From dfeeb066a63b8e35ca584d55e20c6f0093ccd3c6 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 20 Feb 2018 16:11:43 +0000 Subject: [PATCH 001/279] INIT: Initial commit with basic structure Basic structure of a core PRNG and a generator that consumes the core PRNG --- _randomgen/.gitignore | 1 + _randomgen/README.md | 21 ++++++ _randomgen/core_prng/__init__.py | 0 _randomgen/core_prng/common.c | 0 _randomgen/core_prng/common.h | 0 _randomgen/core_prng/common.pxd | 9 +++ _randomgen/core_prng/core_prng.pyx | 115 +++++++++++++++++++++++++++++ _randomgen/core_prng/generator.pyx | 28 +++++++ _randomgen/setup.py | 33 +++++++++ 9 files changed, 207 insertions(+) create mode 100644 _randomgen/.gitignore create mode 100644 _randomgen/README.md create mode 100644 _randomgen/core_prng/__init__.py create mode 100644 _randomgen/core_prng/common.c create mode 100644 _randomgen/core_prng/common.h create mode 100644 _randomgen/core_prng/common.pxd create mode 100644 _randomgen/core_prng/core_prng.pyx create mode 100644 _randomgen/core_prng/generator.pyx create mode 100644 _randomgen/setup.py diff --git a/_randomgen/.gitignore b/_randomgen/.gitignore new file mode 100644 index 000000000000..9f11b755a17d --- /dev/null +++ b/_randomgen/.gitignore @@ -0,0 +1 @@ +.idea/ diff --git a/_randomgen/README.md b/_randomgen/README.md new file mode 100644 index 000000000000..f04d423276d0 --- /dev/null +++ b/_randomgen/README.md @@ -0,0 +1,21 @@ +# Core PRNG + +Experimental Core Pseudo Random Number Generator interface for future +NumPy RandomState evolution. + +## Demo + +Basic POC demonstration + +```bash +python setup.py develop +``` + +```ipython +In [13]: import core_prng.generator + +In [14]: rg = core_prng.generator.RandomGenerator() + +In [15]: rg.random_integer() +Out[15]: 872337561037043212 +``` diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/_randomgen/core_prng/common.c b/_randomgen/core_prng/common.c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/_randomgen/core_prng/common.h b/_randomgen/core_prng/common.h new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd new file mode 100644 index 000000000000..e9949220f9c6 --- /dev/null +++ b/_randomgen/core_prng/common.pxd @@ -0,0 +1,9 @@ +from libc.stdint cimport uint64_t + +ctypedef uint64_t (*random_uint64_anon)(void* st) + +cdef struct anon_func_state: + void *state + void *f + +ctypedef anon_func_state anon_func_state_t diff --git a/_randomgen/core_prng/core_prng.pyx b/_randomgen/core_prng/core_prng.pyx new file mode 100644 index 000000000000..761a150668a5 --- /dev/null +++ b/_randomgen/core_prng/core_prng.pyx @@ -0,0 +1,115 @@ +import numpy as np +cimport numpy as np +from libc.stdint cimport uint64_t +from cpython.pycapsule cimport PyCapsule_New, PyCapsule_IsValid, PyCapsule_GetPointer +from common cimport * + +np.import_array() + +cdef struct state: + uint64_t state + +ctypedef state state_t + +ctypedef uint64_t (*random_uint64)(state* st) + +cdef struct func_state: + state st + random_uint64 f + +ctypedef func_state func_state_t + + +cdef uint64_t _splitmix64(state* st): + cdef uint64_t z + cdef uint64_t c1 = 11400714819323198485 + cdef uint64_t c2 = 13787848793156543929 + cdef uint64_t c3 = 10723151780598845931 + st[0].state += c1 # 0x9E3779B97F4A7C15 + z = st[0].state + z = (z ^ (z >> 30)) * c2 # 0xBF58476D1CE4E5B9 + z = (z ^ (z >> 27)) * c3 # 0x94D049BB133111EB + return z ^ (z >> 31) + +cdef uint64_t _splitmix64_anon(void* st): + return _splitmix64( st) + +cdef class CorePRNG: + cdef state rng_state + cdef func_state rng_func_state + cdef anon_func_state anon_func_state + cdef public object _func_state + cdef public object _anon_func_state + + def __init__(self): + self.rng_state.state = 17013192669731687406 + self.rng_func_state.st = self.rng_state + self.rng_func_state.f = &_splitmix64 + cdef const char *name = "CorePRNG func_state" + self._func_state = PyCapsule_New(&self.rng_func_state, + name, NULL) + self.anon_func_state.state = &self.rng_state + self.anon_func_state.f = &_splitmix64_anon + cdef const char *anon_name = "Anon CorePRNG func_state" + self._anon_func_state = PyCapsule_New(&self.anon_func_state, + anon_name, NULL) + + def random(self): + return _splitmix64(&self.rng_state) + + def get_state(self): + return self.rng_state.state + + def get_state2(self): + return (self.anon_func_state.state)[0] + + def set_state(self, uint64_t value): + self.rng_state.state = value + + @staticmethod + cdef uint64_t c_random(state *st): + return _splitmix64(st) + + @staticmethod + cdef uint64_t c_random_void(void *st): + return _splitmix64( st) + + def random_using_c(self): + return CorePRNG.c_random(&self.rng_state) + + def random_using_c_random_void(self): + return CorePRNG.c_random_void( &self.rng_state) + + def random_using_struct(self): + return self.rng_func_state.f(&self.rng_func_state.st) + +# cdef class RandomGenerator: +# cdef object __core_prng +# cdef func_state rng_func_state +# cdef anon_func_state anon_rng_func_state +# +# def __init__(self, prng=None): +# if prng is None: +# prng = CorePRNG() +# self.__core_prng = prng +# capsule = prng._func_state +# cdef const char *name = "CorePRNG func_state" +# if not PyCapsule_IsValid(capsule, name): +# raise ValueError("Invalid pointer to func_state") +# self.rng_func_state = (PyCapsule_GetPointer(capsule, name))[0] +# +# capsule = prng._anon_func_state +# cdef const char *anon_name = "Anon CorePRNG func_state" +# if not PyCapsule_IsValid(capsule, anon_name): +# raise ValueError("Invalid pointer to anon_func_state") +# self.anon_rng_func_state = (PyCapsule_GetPointer(capsule, anon_name))[0] +# +# def random_integer(self): +# return self.__core_prng.random() +# +# def random_using_struct(self): +# return self.rng_func_state.f(&self.rng_func_state.st) +# +# def random_using_anon_struct(self): +# cdef random_uint64_anon f = self.anon_rng_func_state.f +# return f(self.anon_rng_func_state.state) diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx new file mode 100644 index 000000000000..c003b89e86de --- /dev/null +++ b/_randomgen/core_prng/generator.pyx @@ -0,0 +1,28 @@ +import numpy as np +cimport numpy as np +from libc.stdint cimport uint64_t +from cpython.pycapsule cimport PyCapsule_New, PyCapsule_IsValid, PyCapsule_GetPointer +from common cimport * + +from core_prng.core_prng import CorePRNG + +np.import_array() + +cdef class RandomGenerator: + cdef public object __core_prng + cdef anon_func_state anon_rng_func_state + + def __init__(self, prng=None): + if prng is None: + prng = CorePRNG() + self.__core_prng = prng + + capsule = prng._anon_func_state + cdef const char *anon_name = "Anon CorePRNG func_state" + if not PyCapsule_IsValid(capsule, anon_name): + raise ValueError("Invalid pointer to anon_func_state") + self.anon_rng_func_state = (PyCapsule_GetPointer(capsule, anon_name))[0] + + def random_integer(self): + cdef random_uint64_anon f = self.anon_rng_func_state.f + return f(self.anon_rng_func_state.state) diff --git a/_randomgen/setup.py b/_randomgen/setup.py new file mode 100644 index 000000000000..9cb861f5048e --- /dev/null +++ b/_randomgen/setup.py @@ -0,0 +1,33 @@ +import numpy as np +from Cython.Build import cythonize +from setuptools import setup, find_packages, Distribution +from setuptools.extension import Extension + +extensions = [Extension("core_prng.core_prng", + ["core_prng/core_prng.pyx"], + include_dirs=[np.get_include()]), + Extension("core_prng.generator", + ["core_prng/generator.pyx"], + include_dirs=[np.get_include()])] + +class BinaryDistribution(Distribution): + def is_pure(self): + return False + + +setup( + ext_modules=cythonize(extensions), + name='core_prng', + packages=find_packages(), + package_dir={'core_prng': './core_prng'}, + package_data={'': ['*.c', '*.h', '*.pxi', '*.pyx', '*.pxd']}, + include_package_data=True, + license='NSCA', + author='Kevin Sheppard', + author_email='kevin.k.sheppard@gmail.com', + distclass=BinaryDistribution, + description='Next-gen RandomState supporting multiple PRNGs', + url='https://github.com/bashtage/core-prng', + keywords=['pseudo random numbers', 'PRNG', 'Python'], + zip_safe=False +) From c7c573b41eeb993b48a0f767b9bd3322224e7fc4 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 20 Feb 2018 16:29:07 +0000 Subject: [PATCH 002/279] CLN: Remove unneeded code Remove unnecessary code and add docstrings --- _randomgen/.gitignore | 4 ++ _randomgen/core_prng/core_prng.pyx | 90 ++++++++++-------------------- _randomgen/core_prng/generator.pyx | 17 +++++- 3 files changed, 47 insertions(+), 64 deletions(-) diff --git a/_randomgen/.gitignore b/_randomgen/.gitignore index 9f11b755a17d..fd7f147c8885 100644 --- a/_randomgen/.gitignore +++ b/_randomgen/.gitignore @@ -1 +1,5 @@ .idea/ +build/ +*.egg-info/ +*.pyd +*.html diff --git a/_randomgen/core_prng/core_prng.pyx b/_randomgen/core_prng/core_prng.pyx index 761a150668a5..a43fb9e259db 100644 --- a/_randomgen/core_prng/core_prng.pyx +++ b/_randomgen/core_prng/core_prng.pyx @@ -1,7 +1,7 @@ import numpy as np cimport numpy as np from libc.stdint cimport uint64_t -from cpython.pycapsule cimport PyCapsule_New, PyCapsule_IsValid, PyCapsule_GetPointer +from cpython.pycapsule cimport PyCapsule_New from common cimport * np.import_array() @@ -11,7 +11,7 @@ cdef struct state: ctypedef state state_t -ctypedef uint64_t (*random_uint64)(state* st) +ctypedef uint64_t (*random_uint64)(state_t *st) cdef struct func_state: state st @@ -20,8 +20,9 @@ cdef struct func_state: ctypedef func_state func_state_t -cdef uint64_t _splitmix64(state* st): +cdef uint64_t _splitmix64(state_t *st): cdef uint64_t z + # TODO: Use literals -- PyCharm complains cdef uint64_t c1 = 11400714819323198485 cdef uint64_t c2 = 13787848793156543929 cdef uint64_t c3 = 10723151780598845931 @@ -35,81 +36,46 @@ cdef uint64_t _splitmix64_anon(void* st): return _splitmix64( st) cdef class CorePRNG: + """ + Prototype Core PRNG using directly implemented version of SplitMix64. + + Notes + ----- + Exposes no user-facing API except `get_state` and `set_state`. Designed + for use in a `RandomGenerator` object. + """ cdef state rng_state - cdef func_state rng_func_state cdef anon_func_state anon_func_state - cdef public object _func_state cdef public object _anon_func_state def __init__(self): self.rng_state.state = 17013192669731687406 - self.rng_func_state.st = self.rng_state - self.rng_func_state.f = &_splitmix64 - cdef const char *name = "CorePRNG func_state" - self._func_state = PyCapsule_New(&self.rng_func_state, - name, NULL) + self.anon_func_state.state = &self.rng_state self.anon_func_state.f = &_splitmix64_anon cdef const char *anon_name = "Anon CorePRNG func_state" self._anon_func_state = PyCapsule_New(&self.anon_func_state, anon_name, NULL) - def random(self): + def __random_integer(self): + """ + 64-bit Random Integers from the PRNG + + Returns + ------- + rv : int + Next random value + + Notes + ----- + Testing only + """ return _splitmix64(&self.rng_state) def get_state(self): + """Get PRNG state""" return self.rng_state.state - def get_state2(self): - return (self.anon_func_state.state)[0] - def set_state(self, uint64_t value): + """Set PRNG state""" self.rng_state.state = value - - @staticmethod - cdef uint64_t c_random(state *st): - return _splitmix64(st) - - @staticmethod - cdef uint64_t c_random_void(void *st): - return _splitmix64( st) - - def random_using_c(self): - return CorePRNG.c_random(&self.rng_state) - - def random_using_c_random_void(self): - return CorePRNG.c_random_void( &self.rng_state) - - def random_using_struct(self): - return self.rng_func_state.f(&self.rng_func_state.st) - -# cdef class RandomGenerator: -# cdef object __core_prng -# cdef func_state rng_func_state -# cdef anon_func_state anon_rng_func_state -# -# def __init__(self, prng=None): -# if prng is None: -# prng = CorePRNG() -# self.__core_prng = prng -# capsule = prng._func_state -# cdef const char *name = "CorePRNG func_state" -# if not PyCapsule_IsValid(capsule, name): -# raise ValueError("Invalid pointer to func_state") -# self.rng_func_state = (PyCapsule_GetPointer(capsule, name))[0] -# -# capsule = prng._anon_func_state -# cdef const char *anon_name = "Anon CorePRNG func_state" -# if not PyCapsule_IsValid(capsule, anon_name): -# raise ValueError("Invalid pointer to anon_func_state") -# self.anon_rng_func_state = (PyCapsule_GetPointer(capsule, anon_name))[0] -# -# def random_integer(self): -# return self.__core_prng.random() -# -# def random_using_struct(self): -# return self.rng_func_state.f(&self.rng_func_state.st) -# -# def random_using_anon_struct(self): -# cdef random_uint64_anon f = self.anon_rng_func_state.f -# return f(self.anon_rng_func_state.state) diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index c003b89e86de..da96687cdfe7 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -1,7 +1,6 @@ import numpy as np cimport numpy as np -from libc.stdint cimport uint64_t -from cpython.pycapsule cimport PyCapsule_New, PyCapsule_IsValid, PyCapsule_GetPointer +from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from common cimport * from core_prng.core_prng import CorePRNG @@ -9,6 +8,20 @@ from core_prng.core_prng import CorePRNG np.import_array() cdef class RandomGenerator: + """ + Prototype Random Generator that consumes randoms from a CorePRNG class + + Parameters + ---------- + prng : CorePRNG, optional + Object exposing a PyCapsule containing state and function pointers + + Examples + -------- + >>> from core_prng.generator import RandomGenerator + >>> rg = RandomGenerator() + >>> rg.random_integer() + """ cdef public object __core_prng cdef anon_func_state anon_rng_func_state From a3d45f4403e8f5fea39fc9385f1a882c3be0dfc8 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 22 Feb 2018 10:10:28 +0000 Subject: [PATCH 003/279] ENH: Add support for xoroshiro128 Clean up splitmix64 to use external functions Add xoroshiro128 to show use of additional PRNG --- _randomgen/README.md | 17 ++++- _randomgen/core_prng/common.c | 0 _randomgen/core_prng/common.h | 0 _randomgen/core_prng/generator.pyx | 14 +++- .../{core_prng.pyx => splitmix64.pyx} | 36 +++------ .../core_prng/src/splitmix64/splitmix64.c | 25 +++++++ .../core_prng/src/splitmix64/splitmix64.h | 12 +++ .../src/splitmix64/splitmix64.orig.c | 28 +++++++ .../core_prng/src/xoroshiro128/xoroshiro128.c | 53 +++++++++++++ .../core_prng/src/xoroshiro128/xoroshiro128.h | 23 ++++++ .../src/xoroshiro128/xoroshiro128plus.orig.c | 74 ++++++++++++++++++ _randomgen/core_prng/xoroshiro128.pyx | 75 +++++++++++++++++++ _randomgen/demo.py | 7 ++ _randomgen/setup.py | 19 ++++- 14 files changed, 347 insertions(+), 36 deletions(-) delete mode 100644 _randomgen/core_prng/common.c delete mode 100644 _randomgen/core_prng/common.h rename _randomgen/core_prng/{core_prng.pyx => splitmix64.pyx} (61%) create mode 100644 _randomgen/core_prng/src/splitmix64/splitmix64.c create mode 100644 _randomgen/core_prng/src/splitmix64/splitmix64.h create mode 100644 _randomgen/core_prng/src/splitmix64/splitmix64.orig.c create mode 100644 _randomgen/core_prng/src/xoroshiro128/xoroshiro128.c create mode 100644 _randomgen/core_prng/src/xoroshiro128/xoroshiro128.h create mode 100644 _randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.c create mode 100644 _randomgen/core_prng/xoroshiro128.pyx create mode 100644 _randomgen/demo.py diff --git a/_randomgen/README.md b/_randomgen/README.md index f04d423276d0..0e0bdda72e63 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -12,10 +12,19 @@ python setup.py develop ``` ```ipython -In [13]: import core_prng.generator +In [1]: import core_prng.generator -In [14]: rg = core_prng.generator.RandomGenerator() +# Default generator is Splitmix64 +In [2]: rg = core_prng.generator.RandomGenerator() -In [15]: rg.random_integer() -Out[15]: 872337561037043212 +In [3]: rg.random_integer() +Out[3]: 872337561037043212 + +In [4]: from core_prng.xoroshiro128 import Xoroshiro128 + +# Swap the generator +In [5]: rg = core_prng.generator.RandomGenerator(Xoroshiro128()) + +In [6]: rg.random_integer() +Out[6]: 13370384800127340062 ``` diff --git a/_randomgen/core_prng/common.c b/_randomgen/core_prng/common.c deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/_randomgen/core_prng/common.h b/_randomgen/core_prng/common.h deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index da96687cdfe7..2648f9c0593a 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -3,7 +3,7 @@ cimport numpy as np from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from common cimport * -from core_prng.core_prng import CorePRNG +from core_prng.splitmix64 import SplitMix64 np.import_array() @@ -24,10 +24,12 @@ cdef class RandomGenerator: """ cdef public object __core_prng cdef anon_func_state anon_rng_func_state + cdef random_uint64_anon next_uint64 + cdef void *rng_state def __init__(self, prng=None): if prng is None: - prng = CorePRNG() + prng = SplitMix64() self.__core_prng = prng capsule = prng._anon_func_state @@ -35,7 +37,11 @@ cdef class RandomGenerator: if not PyCapsule_IsValid(capsule, anon_name): raise ValueError("Invalid pointer to anon_func_state") self.anon_rng_func_state = (PyCapsule_GetPointer(capsule, anon_name))[0] + self.next_uint64 = self.anon_rng_func_state.f + self.rng_state = self.anon_rng_func_state.state def random_integer(self): - cdef random_uint64_anon f = self.anon_rng_func_state.f - return f(self.anon_rng_func_state.state) + return self.next_uint64(self.rng_state) + + def random_double(self): + return (self.next_uint64(self.rng_state) >> 11) * (1.0 / 9007199254740992.0) diff --git a/_randomgen/core_prng/core_prng.pyx b/_randomgen/core_prng/splitmix64.pyx similarity index 61% rename from _randomgen/core_prng/core_prng.pyx rename to _randomgen/core_prng/splitmix64.pyx index a43fb9e259db..9b26d233b637 100644 --- a/_randomgen/core_prng/core_prng.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -6,36 +6,22 @@ from common cimport * np.import_array() -cdef struct state: - uint64_t state +cdef extern from "src/splitmix64/splitmix64.h": -ctypedef state state_t + cdef struct s_splitmix64_state: + uint64_t state -ctypedef uint64_t (*random_uint64)(state_t *st) + ctypedef s_splitmix64_state splitmix64_state -cdef struct func_state: - state st - random_uint64 f + cdef uint64_t splitmix64_next(splitmix64_state* state) nogil -ctypedef func_state func_state_t +ctypedef uint64_t (*random_uint64)(splitmix64_state* state) -cdef uint64_t _splitmix64(state_t *st): - cdef uint64_t z - # TODO: Use literals -- PyCharm complains - cdef uint64_t c1 = 11400714819323198485 - cdef uint64_t c2 = 13787848793156543929 - cdef uint64_t c3 = 10723151780598845931 - st[0].state += c1 # 0x9E3779B97F4A7C15 - z = st[0].state - z = (z ^ (z >> 30)) * c2 # 0xBF58476D1CE4E5B9 - z = (z ^ (z >> 27)) * c3 # 0x94D049BB133111EB - return z ^ (z >> 31) +cdef uint64_t _splitmix64_anon(void* st) nogil: + return splitmix64_next(st) -cdef uint64_t _splitmix64_anon(void* st): - return _splitmix64( st) - -cdef class CorePRNG: +cdef class SplitMix64: """ Prototype Core PRNG using directly implemented version of SplitMix64. @@ -44,7 +30,7 @@ cdef class CorePRNG: Exposes no user-facing API except `get_state` and `set_state`. Designed for use in a `RandomGenerator` object. """ - cdef state rng_state + cdef splitmix64_state rng_state cdef anon_func_state anon_func_state cdef public object _anon_func_state @@ -70,7 +56,7 @@ cdef class CorePRNG: ----- Testing only """ - return _splitmix64(&self.rng_state) + return splitmix64_next(&self.rng_state) def get_state(self): """Get PRNG state""" diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.c b/_randomgen/core_prng/src/splitmix64/splitmix64.c new file mode 100644 index 000000000000..fa230a99f05d --- /dev/null +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.c @@ -0,0 +1,25 @@ +/* Written in 2015 by Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . + +Modified 2018 by Kevin Sheppard. Modifications licensed under the NCSA +license. +*/ + +/* This is a fixed-increment version of Java 8's SplittableRandom generator + See http://dx.doi.org/10.1145/2714064.2660195 and + http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html + + It is a very fast generator passing BigCrush, and it can be useful if + for some reason you absolutely want 64 bits of state; otherwise, we + rather suggest to use a xoroshiro128+ (for moderately parallel + computations) or xorshift1024* (for massively parallel computations) + generator. */ + +#include "splitmix64.h" + +extern inline uint64_t splitmix64_next(splitmix64_state *state); diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.h b/_randomgen/core_prng/src/splitmix64/splitmix64.h new file mode 100644 index 000000000000..8ecd72878135 --- /dev/null +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.h @@ -0,0 +1,12 @@ +#include + +typedef struct s_splitmix64_state { + uint64_t state; +} splitmix64_state; + +static inline uint64_t splitmix64_next(splitmix64_state *state) { + uint64_t z = (state->state += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + return z ^ (z >> 31); +} diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.orig.c b/_randomgen/core_prng/src/splitmix64/splitmix64.orig.c new file mode 100644 index 000000000000..d0c1e158fe0c --- /dev/null +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.orig.c @@ -0,0 +1,28 @@ +/* Written in 2015 by Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . */ + +#include + +/* This is a fixed-increment version of Java 8's SplittableRandom generator + See http://dx.doi.org/10.1145/2714064.2660195 and + http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html + + It is a very fast generator passing BigCrush, and it can be useful if + for some reason you absolutely want 64 bits of state; otherwise, we + rather suggest to use a xoroshiro128+ (for moderately parallel + computations) or xorshift1024* (for massively parallel computations) + generator. */ + +uint64_t x; /* The state can be seeded with any value. */ + +uint64_t next() { + uint64_t z = (x += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + return z ^ (z >> 31); +} diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c new file mode 100644 index 000000000000..b346fd50eee7 --- /dev/null +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c @@ -0,0 +1,53 @@ +/* Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . */ + +/* This is the successor to xorshift128+. It is the fastest full-period + generator passing BigCrush without systematic failures, but due to the + relatively short period it is acceptable only for applications with a + mild amount of parallelism; otherwise, use a xorshift1024* generator. + + Beside passing BigCrush, this generator passes the PractRand test suite + up to (and included) 16TB, with the exception of binary rank tests, as + the lowest bit of this generator is an LFSR of degree 128. The next bit + can be described by an LFSR of degree 8256, but in the long run it will + fail linearity tests, too. The other bits needs a much higher degree to + be represented as LFSRs. + + We suggest to use a sign test to extract a random Boolean value, and + right shifts to extract subsets of bits. + + Note that the generator uses a simulated rotate operation, which most C + compilers will turn into a single instruction. In Java, you can use + Long.rotateLeft(). In languages that do not make low-level rotation + instructions accessible xorshift128+ could be faster. + + The state must be seeded so that it is not everywhere zero. If you have + a 64-bit seed, we suggest to seed a splitmix64 generator and use its + output to fill s. */ + +#include "xoroshiro128.h" + +extern inline uint64_t xoroshiro128_next(xoroshiro128_state *state); + +void xoroshiro128_jump(xoroshiro128_state *state) { + static const uint64_t JUMP[] = {0xbeac0467eba5facb, 0xd86b048b86aa9922}; + + uint64_t s0 = 0; + uint64_t s1 = 0; + for (int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for (int b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) { + s0 ^= state->s[0]; + s1 ^= state->s[1]; + } + xoroshiro128_next(state); + } + + state->s[0] = s0; + state->s[1] = s1; +} diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h new file mode 100644 index 000000000000..d6c0eefaf251 --- /dev/null +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h @@ -0,0 +1,23 @@ +#include + +typedef struct s_xoroshiro128_state { + uint64_t s[2]; +} xoroshiro128_state; + +static inline uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + +static inline uint64_t xoroshiro128_next(xoroshiro128_state *state) { + const uint64_t s0 = state->s[0]; + uint64_t s1 = state->s[1]; + const uint64_t result = s0 + s1; + + s1 ^= s0; + state->s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b + state->s[1] = rotl(s1, 36); // c + + return result; +} + +void xoroshiro128_jump(xoroshiro128_state *state); diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.c new file mode 100644 index 000000000000..d55a3b3776ca --- /dev/null +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.c @@ -0,0 +1,74 @@ +/* Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . */ + +#include + +/* This is the successor to xorshift128+. It is the fastest full-period + generator passing BigCrush without systematic failures, but due to the + relatively short period it is acceptable only for applications with a + mild amount of parallelism; otherwise, use a xorshift1024* generator. + + Beside passing BigCrush, this generator passes the PractRand test suite + up to (and included) 16TB, with the exception of binary rank tests, as + the lowest bit of this generator is an LFSR of degree 128. The next bit + can be described by an LFSR of degree 8256, but in the long run it will + fail linearity tests, too. The other bits needs a much higher degree to + be represented as LFSRs. + + We suggest to use a sign test to extract a random Boolean value, and + right shifts to extract subsets of bits. + + Note that the generator uses a simulated rotate operation, which most C + compilers will turn into a single instruction. In Java, you can use + Long.rotateLeft(). In languages that do not make low-level rotation + instructions accessible xorshift128+ could be faster. + + The state must be seeded so that it is not everywhere zero. If you have + a 64-bit seed, we suggest to seed a splitmix64 generator and use its + output to fill s. */ + +uint64_t s[2]; + +static inline uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + +uint64_t next(void) { + const uint64_t s0 = s[0]; + uint64_t s1 = s[1]; + const uint64_t result = s0 + s1; + + s1 ^= s0; + s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b + s[1] = rotl(s1, 36); // c + + return result; +} + + +/* This is the jump function for the generator. It is equivalent + to 2^64 calls to next(); it can be used to generate 2^64 + non-overlapping subsequences for parallel computations. */ + +void jump(void) { + static const uint64_t JUMP[] = { 0xbeac0467eba5facb, 0xd86b048b86aa9922 }; + + uint64_t s0 = 0; + uint64_t s1 = 0; + for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for(int b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) { + s0 ^= s[0]; + s1 ^= s[1]; + } + next(); + } + + s[0] = s0; + s[1] = s1; +} diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx new file mode 100644 index 000000000000..adb94e605691 --- /dev/null +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -0,0 +1,75 @@ +import numpy as np +cimport numpy as np +from libc.stdint cimport uint64_t +from cpython.pycapsule cimport PyCapsule_New +from common cimport * + +np.import_array() + +cdef extern from "src/xoroshiro128/xoroshiro128.h": + + cdef struct s_xoroshiro128_state: + uint64_t s[2] + + ctypedef s_xoroshiro128_state xoroshiro128_state + + cdef uint64_t xoroshiro128_next(xoroshiro128_state* state) nogil + + cdef void xoroshiro128_jump(xoroshiro128_state* state) + + +ctypedef uint64_t (*random_uint64)(xoroshiro128_state* state) + +cdef uint64_t _xoroshiro128_anon(void* st) nogil: + return xoroshiro128_next(st) + +cdef class Xoroshiro128: + """ + Prototype Core PRNG using xoroshiro128 + + Notes + ----- + Exposes no user-facing API except `get_state` and `set_state`. Designed + for use in a `RandomGenerator` object. + """ + cdef xoroshiro128_state rng_state + cdef anon_func_state anon_func_state + cdef public object _anon_func_state + + def __init__(self): + self.rng_state.s[0] = 17013192669731687407 + self.rng_state.s[1] = 14803936204105204271 + + self.anon_func_state.state = &self.rng_state + self.anon_func_state.f = &_xoroshiro128_anon + cdef const char *anon_name = "Anon CorePRNG func_state" + self._anon_func_state = PyCapsule_New(&self.anon_func_state, + anon_name, NULL) + + def __random_integer(self): + """ + 64-bit Random Integers from the PRNG + + Returns + ------- + rv : int + Next random value + + Notes + ----- + Testing only + """ + return xoroshiro128_next(&self.rng_state) + + def get_state(self): + """Get PRNG state""" + return np.array(self.rng_state.s,dtype=np.uint64) + + def set_state(self, value): + """Set PRNG state""" + value = np.asarray(value, dtype=np.uint64) + self.rng_state.s[0] = value[0] + self.rng_state.s[1] = value[1] + + def jump(self): + xoroshiro128_jump(&self.rng_state) diff --git a/_randomgen/demo.py b/_randomgen/demo.py new file mode 100644 index 000000000000..78d2bb4606ff --- /dev/null +++ b/_randomgen/demo.py @@ -0,0 +1,7 @@ +from core_prng.generator import RandomGenerator +from core_prng.splitmix64 import SplitMix64 +from core_prng.xoroshiro128 import Xoroshiro128 + +print(RandomGenerator().random_integer()) +print(RandomGenerator(Xoroshiro128()).random_integer()) +print(RandomGenerator(SplitMix64()).random_integer()) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 9cb861f5048e..96f7c7b49e5e 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -1,15 +1,28 @@ +from os.path import join + import numpy as np from Cython.Build import cythonize from setuptools import setup, find_packages, Distribution from setuptools.extension import Extension -extensions = [Extension("core_prng.core_prng", - ["core_prng/core_prng.pyx"], - include_dirs=[np.get_include()]), +MOD_DIR = './core_prng' + +extensions = [Extension("core_prng.splitmix64", + ["core_prng/splitmix64.pyx", + join(MOD_DIR, 'src', 'splitmix64', 'splitmix64.c')], + include_dirs=[np.get_include(), + join(MOD_DIR, 'src', 'splitmix64')]), + Extension("core_prng.xoroshiro128", + ["core_prng/xoroshiro128.pyx", + join(MOD_DIR, 'src', 'xoroshiro128', + 'xoroshiro128.c')], + include_dirs=[np.get_include(), + join(MOD_DIR, 'src', 'xoroshiro128')]), Extension("core_prng.generator", ["core_prng/generator.pyx"], include_dirs=[np.get_include()])] + class BinaryDistribution(Distribution): def is_pure(self): return False From b8292ab15fb25ae92aa3d7a88b934468fc784025 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 23 Feb 2018 09:40:02 +0000 Subject: [PATCH 004/279] ENH: Add entropy initialization to RNGS Port over random entropy from ng-randomstate --- _randomgen/core_prng/__init__.py | 3 + _randomgen/core_prng/entropy.pyx | 78 +++++++ _randomgen/core_prng/splitmix64.pyx | 25 +- _randomgen/core_prng/src/common/stdint.h | 259 +++++++++++++++++++++ _randomgen/core_prng/src/entropy/entropy.c | 174 ++++++++++++++ _randomgen/core_prng/src/entropy/entropy.h | 43 ++++ _randomgen/core_prng/xoroshiro128.pyx | 11 +- _randomgen/setup.py | 13 +- 8 files changed, 591 insertions(+), 15 deletions(-) create mode 100644 _randomgen/core_prng/entropy.pyx create mode 100644 _randomgen/core_prng/src/common/stdint.h create mode 100644 _randomgen/core_prng/src/entropy/entropy.c create mode 100644 _randomgen/core_prng/src/entropy/entropy.h diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index e69de29bb2d1..8bcc8c6f1365 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -0,0 +1,3 @@ +from .generator import RandomGenerator +from .xoroshiro128 import Xoroshiro128 +from .splitmix64 import SplitMix64 \ No newline at end of file diff --git a/_randomgen/core_prng/entropy.pyx b/_randomgen/core_prng/entropy.pyx new file mode 100644 index 000000000000..0d980fc2ca6d --- /dev/null +++ b/_randomgen/core_prng/entropy.pyx @@ -0,0 +1,78 @@ +cimport numpy as np +import numpy as np + +from libc.stdint cimport uint32_t + +cdef extern from "src/entropy/entropy.h": + cdef bint entropy_getbytes(void* dest, size_t size) + cdef bint entropy_fallback_getbytes(void *dest, size_t size) + +cdef Py_ssize_t compute_numel(size): + cdef Py_ssize_t i, n = 1 + if isinstance(size, tuple): + for i in range(len(size)): + n *= size[i] + else: + n = size + return n + +def random_entropy(size=None, source='system'): + """ + random_entropy(size=None, source='system') + + Read entropy from the system cryptographic provider + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + source : str {'system', 'fallback'} + Source of entropy. 'system' uses system cryptographic pool. + 'fallback' uses a hash of the time and process id. + + Returns + ------- + entropy : scalar or ndarray + Entropy bits in 32-bit unsigned integers + + Notes + ----- + On Unix-like machines, reads from ``/dev/urandom``. On Windows machines + reads from the RSA algorithm provided by the cryptographic service + provider. + + This function reads from the system entropy pool and so samples are + not reproducible. In particular, it does *NOT* make use of a + RandomState, and so ``seed``, ``get_state`` and ``set_state`` have no + effect. + + Raises RuntimeError if the command fails. + """ + cdef bint success = True + cdef Py_ssize_t n = 0 + cdef uint32_t random = 0 + cdef uint32_t [:] randoms + + if source not in ('system', 'fallback'): + raise ValueError('Unknown value in source.') + + if size is None: + if source == 'system': + success = entropy_getbytes(&random, 4) + else: + success = entropy_fallback_getbytes(&random, 4) + else: + n = compute_numel(size) + randoms = np.zeros(n, dtype=np.uint32) + if source == 'system': + success = entropy_getbytes((&randoms[0]), 4 * n) + else: + success = entropy_fallback_getbytes((&randoms[0]), 4 * n) + if not success: + raise RuntimeError('Unable to read from system cryptographic provider') + + if n == 0: + return random + return np.asarray(randoms).reshape(size) \ No newline at end of file diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index 9b26d233b637..e652465bec6d 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -1,25 +1,24 @@ import numpy as np cimport numpy as np -from libc.stdint cimport uint64_t from cpython.pycapsule cimport PyCapsule_New from common cimport * +from core_prng.entropy import random_entropy np.import_array() cdef extern from "src/splitmix64/splitmix64.h": - cdef struct s_splitmix64_state: uint64_t state ctypedef s_splitmix64_state splitmix64_state - cdef uint64_t splitmix64_next(splitmix64_state* state) nogil + cdef uint64_t splitmix64_next(splitmix64_state*state) nogil -ctypedef uint64_t (*random_uint64)(splitmix64_state* state) +ctypedef uint64_t (*random_uint64)(splitmix64_state*state) -cdef uint64_t _splitmix64_anon(void* st) nogil: - return splitmix64_next(st) +cdef uint64_t _splitmix64_anon(void*st) nogil: + return splitmix64_next( st) cdef class SplitMix64: """ @@ -35,12 +34,16 @@ cdef class SplitMix64: cdef public object _anon_func_state def __init__(self): - self.rng_state.state = 17013192669731687406 - - self.anon_func_state.state = &self.rng_state - self.anon_func_state.f = &_splitmix64_anon + try: + state = random_entropy(2) + except RuntimeError: + state = random_entropy(2, 'fallback') + self.rng_state.state = int(state.view(np.uint64)[0]) + + self.anon_func_state.state = &self.rng_state + self.anon_func_state.f = &_splitmix64_anon cdef const char *anon_name = "Anon CorePRNG func_state" - self._anon_func_state = PyCapsule_New(&self.anon_func_state, + self._anon_func_state = PyCapsule_New( &self.anon_func_state, anon_name, NULL) def __random_integer(self): diff --git a/_randomgen/core_prng/src/common/stdint.h b/_randomgen/core_prng/src/common/stdint.h new file mode 100644 index 000000000000..8941d67c8295 --- /dev/null +++ b/_randomgen/core_prng/src/common/stdint.h @@ -0,0 +1,259 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if _MSC_VER >= 1600 // [ +#include +#else // ] _MSC_VER >= 1600 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] \ No newline at end of file diff --git a/_randomgen/core_prng/src/entropy/entropy.c b/_randomgen/core_prng/src/entropy/entropy.c new file mode 100644 index 000000000000..a5d48bd1418e --- /dev/null +++ b/_randomgen/core_prng/src/entropy/entropy.c @@ -0,0 +1,174 @@ +/* + * PCG Random Number Generation for C. + * + * Copyright 2014 Melissa O'Neill + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + +/* This code provides a mechanism for getting external randomness for + * seeding purposes. Usually, it's just a wrapper around reading + * /dev/random. + * + * Alas, because not every system provides /dev/random, we need a fallback. + * We also need to try to test whether or not to use the fallback. + */ + +#include +#include +#include +#include + +#include "entropy.h" +#ifdef _WIN32 +/* Windows */ +#include +#include +#include + +#include +#else +/* Unix */ +#include +#include +#include +#endif + +#ifndef IS_UNIX +#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || \ + (defined(__APPLE__) && defined(__MACH__))) +#define IS_UNIX 1 +#else +#define IS_UNIX 0 +#endif +#endif + +// If HAVE_DEV_RANDOM is set, we use that value, otherwise we guess +#ifndef HAVE_DEV_RANDOM +#define HAVE_DEV_RANDOM IS_UNIX +#endif + +#if HAVE_DEV_RANDOM +#include +#include +#endif + +#if HAVE_DEV_RANDOM +/* entropy_getbytes(dest, size): + * Use /dev/random to get some external entropy for seeding purposes. + * + * Note: + * If reading /dev/random fails (which ought to never happen), it returns + * false, otherwise it returns true. If it fails, you could instead call + * fallback_entropy_getbytes which always succeeds. + */ + +bool entropy_getbytes(void *dest, size_t size) { + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) + return false; + ssize_t sz = read(fd, dest, size); + if ((sz < 0) || ((size_t)sz < size)) + return false; + return close(fd) == 0; +} +#endif + +#ifdef _WIN32 +bool entropy_getbytes(void *dest, size_t size) { + HCRYPTPROV hCryptProv; + BOOL done; + + if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT) || + !hCryptProv) { + return true; + } + done = CryptGenRandom(hCryptProv, (DWORD)size, (unsigned char *)dest); + CryptReleaseContext(hCryptProv, 0); + if (!done) { + return false; + } + + return true; +} +#endif + +/* Thomas Wang 32/64 bits integer hash function */ +uint32_t entropy_hash_32(uint32_t key) { + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + return key; +} + +uint64_t entropy_hash_64(uint64_t key) { + key = (~key) + (key << 21); // key = (key << 21) - key - 1; + key = key ^ (key >> 24); + key = (key + (key << 3)) + (key << 8); // key * 265 + key = key ^ (key >> 14); + key = (key + (key << 2)) + (key << 4); // key * 21 + key = key ^ (key >> 28); + key = key + (key << 31); + return key; +} + +uint32_t entropy_randombytes(void) { + +#ifndef _WIN32 + struct timeval tv; + gettimeofday(&tv, NULL); + return entropy_hash_32(getpid()) ^ entropy_hash_32(tv.tv_sec) ^ + entropy_hash_32(tv.tv_usec) ^ entropy_hash_32(clock()); +#else + uint32_t out = 0; + int64_t counter; + struct _timeb tv; + _ftime(&tv); + out = entropy_hash_32(GetCurrentProcessId()) ^ + entropy_hash_32((uint32_t)tv.time) ^ entropy_hash_32(tv.millitm) ^ + entropy_hash_32(clock()); + if (QueryPerformanceCounter((LARGE_INTEGER *)&counter) != 0) + out ^= entropy_hash_32((uint32_t)(counter & 0xffffffff)); + return out; +#endif +} + +bool entropy_fallback_getbytes(void *dest, size_t size) { + int hashes = (int)size; + uint32_t *hash = malloc(hashes * sizeof(uint32_t)); + // uint32_t hash[hashes]; + int i; + for (i = 0; i < hashes; i++) { + hash[i] = entropy_randombytes(); + } + memcpy(dest, (void *)hash, size); + free(hash); + return true; +} + +void entropy_fill(void *dest, size_t size) { + bool success; + success = entropy_getbytes(dest, size); + if (!success) { + entropy_fallback_getbytes(dest, size); + } +} diff --git a/_randomgen/core_prng/src/entropy/entropy.h b/_randomgen/core_prng/src/entropy/entropy.h new file mode 100644 index 000000000000..0c33edbe4b5e --- /dev/null +++ b/_randomgen/core_prng/src/entropy/entropy.h @@ -0,0 +1,43 @@ +/* + * PCG Random Number Generation for C. + * + * Copyright 2014 Melissa O'Neill + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ +#include +#ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/stdint.h" +typedef int bool; +#define false 0 +#define true 1 +#else +#include +#include +#endif +#else +#include +#include +#endif + +extern void entropy_fill(void *dest, size_t size); + +extern bool entropy_getbytes(void *dest, size_t size); + +extern bool entropy_fallback_getbytes(void *dest, size_t size); diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index adb94e605691..4cd9b2449aab 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -3,7 +3,7 @@ cimport numpy as np from libc.stdint cimport uint64_t from cpython.pycapsule cimport PyCapsule_New from common cimport * - +from core_prng.entropy import random_entropy np.import_array() cdef extern from "src/xoroshiro128/xoroshiro128.h": @@ -37,8 +37,13 @@ cdef class Xoroshiro128: cdef public object _anon_func_state def __init__(self): - self.rng_state.s[0] = 17013192669731687407 - self.rng_state.s[1] = 14803936204105204271 + try: + state = random_entropy(4) + except RuntimeError: + state = random_entropy(4, 'fallback') + state = state.view(np.uint64) + self.rng_state.s[0] = int(state[0]) + self.rng_state.s[1] = int(state[1]) self.anon_func_state.state = &self.rng_state self.anon_func_state.f = &_xoroshiro128_anon diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 96f7c7b49e5e..bd66904cd169 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -1,3 +1,4 @@ +import os from os.path import join import numpy as np @@ -7,7 +8,17 @@ MOD_DIR = './core_prng' -extensions = [Extension("core_prng.splitmix64", +EXTRA_LINK_ARGS = [] +if os.name == 'nt': + EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] + +extensions = [Extension('core_prng.entropy', + sources=[join(MOD_DIR, 'entropy.pyx'), + join(MOD_DIR, 'src', 'entropy', 'entropy.c')], + include_dirs=[np.get_include(), + join(MOD_DIR, 'src', 'entropy')], + extra_link_args=EXTRA_LINK_ARGS), + Extension("core_prng.splitmix64", ["core_prng/splitmix64.pyx", join(MOD_DIR, 'src', 'splitmix64', 'splitmix64.c')], include_dirs=[np.get_include(), From 9360003d1e70b38a0a3f3fc9949d3ba90b79f6b9 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 23 Feb 2018 18:16:40 +0000 Subject: [PATCH 005/279] ENH: Add seeding to generators Allow generators to be seeded on creation --- _randomgen/core_prng/entropy.pxd | 5 ++ _randomgen/core_prng/entropy.pyx | 68 ++++++++++++++++++- _randomgen/core_prng/splitmix64.pyx | 38 +++++++---- .../core_prng/src/splitmix64/splitmix64.c | 2 +- .../core_prng/src/splitmix64/splitmix64.h | 8 +-- _randomgen/core_prng/xoroshiro128.pyx | 22 ++++-- _randomgen/demo.py | 3 + 7 files changed, 117 insertions(+), 29 deletions(-) create mode 100644 _randomgen/core_prng/entropy.pxd diff --git a/_randomgen/core_prng/entropy.pxd b/_randomgen/core_prng/entropy.pxd new file mode 100644 index 000000000000..c0a1a0e871f7 --- /dev/null +++ b/_randomgen/core_prng/entropy.pxd @@ -0,0 +1,5 @@ + +from libc.stdint cimport uint64_t +cimport numpy as np + +cdef np.ndarray seed_by_array(object seed, Py_ssize_t n) \ No newline at end of file diff --git a/_randomgen/core_prng/entropy.pyx b/_randomgen/core_prng/entropy.pyx index 0d980fc2ca6d..f1155c605273 100644 --- a/_randomgen/core_prng/entropy.pyx +++ b/_randomgen/core_prng/entropy.pyx @@ -1,7 +1,14 @@ +import operator + cimport numpy as np import numpy as np -from libc.stdint cimport uint32_t +from libc.stdint cimport uint32_t, uint64_t + +np.import_array() + +cdef extern from "src/splitmix64/splitmix64.h": + cdef uint64_t splitmix64_next(uint64_t *state) nogil cdef extern from "src/entropy/entropy.h": cdef bint entropy_getbytes(void* dest, size_t size) @@ -16,6 +23,65 @@ cdef Py_ssize_t compute_numel(size): n = size return n +cdef np.ndarray seed_by_array(object seed, Py_ssize_t n): + """ + Transforms a seed array into an initiial state + + Parameters + ---------- + seed: array, 1d, uint64 + Array to use. If seed is a scalar, promote to array. + n : int + Number of 64-bit unsiened integers required + + Notes + ----- + Uses splitmix64 to perform the transformation + """ + cdef uint64_t seed_copy = 0 + cdef uint64_t[::1] seed_array + cdef uint64_t[::1] initial_state + cdef Py_ssize_t seed_size, iter_bound + cdef int i, loc = 0 + + try: + if hasattr(seed, 'squeeze'): + seed = seed.squeeze() + idx = operator.index(seed) + if idx > int(2**64 - 1) or idx < 0: + raise ValueError("Seed must be between 0 and 2**64 - 1") + seed = [seed] + seed_array = np.array(seed, dtype=np.uint64) + except TypeError: + exc_msg = "Seed values must be integers between 0 and 2**64 - 1" + obj = np.asarray(seed).astype(np.object).ravel() + if obj.ndim != 1: + raise ValueError('Array-valued seeds must be 1-dimensional') + if ((obj > int(2**64 - 1)) | (obj < 0)).any(): + raise ValueError(exc_msg) + try: + obj_int = obj.astype(np.uint64, casting='unsafe') + except ValueError: + raise ValueError(exc_msg) + if not (obj == obj_int).all(): + raise ValueError(exc_msg) + seed_array = obj_int + + seed_size = seed_array.shape[0] + iter_bound = n if n > seed_size else seed_size + + initial_state = np.empty(n, dtype=np.uint64) + for i in range(iter_bound): + if i < seed_size: + seed_copy ^= seed_array[i] + initial_state[loc] = splitmix64_next(&seed_copy) + loc += 1 + if loc == n: + loc = 0 + + return np.array(initial_state) + + def random_entropy(size=None, source='system'): """ random_entropy(size=None, source='system') diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index e652465bec6d..1a4f3827cae4 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -2,43 +2,51 @@ import numpy as np cimport numpy as np from cpython.pycapsule cimport PyCapsule_New from common cimport * + from core_prng.entropy import random_entropy +from core_prng cimport entropy np.import_array() cdef extern from "src/splitmix64/splitmix64.h": - cdef struct s_splitmix64_state: - uint64_t state - - ctypedef s_splitmix64_state splitmix64_state - cdef uint64_t splitmix64_next(splitmix64_state*state) nogil + cdef uint64_t splitmix64_next(uint64_t *state) nogil -ctypedef uint64_t (*random_uint64)(splitmix64_state*state) +ctypedef uint64_t (*random_uint64)(uint64_t *state) -cdef uint64_t _splitmix64_anon(void*st) nogil: - return splitmix64_next( st) +cdef uint64_t _splitmix64_anon(void *st) nogil: + return splitmix64_next( st) cdef class SplitMix64: """ Prototype Core PRNG using directly implemented version of SplitMix64. + Parameters + ---------- + seed : int, array of int + Integer or array of integers between 0 and 2**64 - 1 + Notes ----- Exposes no user-facing API except `get_state` and `set_state`. Designed for use in a `RandomGenerator` object. """ - cdef splitmix64_state rng_state + cdef uint64_t rng_state cdef anon_func_state anon_func_state cdef public object _anon_func_state - def __init__(self): - try: - state = random_entropy(2) - except RuntimeError: - state = random_entropy(2, 'fallback') - self.rng_state.state = int(state.view(np.uint64)[0]) + def __init__(self, seed=None): + if seed is None: + try: + state = random_entropy(2) + except RuntimeError: + state = random_entropy(2, 'fallback') + state = state.view(np.uint64) + else: + state = entropy.seed_by_array(seed, 1) + + self.rng_state = int(state[0]) self.anon_func_state.state = &self.rng_state self.anon_func_state.f = &_splitmix64_anon diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.c b/_randomgen/core_prng/src/splitmix64/splitmix64.c index fa230a99f05d..1e75f4b9b100 100644 --- a/_randomgen/core_prng/src/splitmix64/splitmix64.c +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.c @@ -22,4 +22,4 @@ license. #include "splitmix64.h" -extern inline uint64_t splitmix64_next(splitmix64_state *state); +extern inline uint64_t splitmix64_next(uint64_t *state); diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.h b/_randomgen/core_prng/src/splitmix64/splitmix64.h index 8ecd72878135..d5d7549d9fad 100644 --- a/_randomgen/core_prng/src/splitmix64/splitmix64.h +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.h @@ -1,11 +1,7 @@ #include -typedef struct s_splitmix64_state { - uint64_t state; -} splitmix64_state; - -static inline uint64_t splitmix64_next(splitmix64_state *state) { - uint64_t z = (state->state += 0x9e3779b97f4a7c15); +static inline uint64_t splitmix64_next(uint64_t *state) { + uint64_t z = (state[0] += 0x9e3779b97f4a7c15); z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; z = (z ^ (z >> 27)) * 0x94d049bb133111eb; return z ^ (z >> 31); diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 4cd9b2449aab..1ae7926acb00 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -4,6 +4,7 @@ from libc.stdint cimport uint64_t from cpython.pycapsule cimport PyCapsule_New from common cimport * from core_prng.entropy import random_entropy +from core_prng cimport entropy np.import_array() cdef extern from "src/xoroshiro128/xoroshiro128.h": @@ -27,6 +28,11 @@ cdef class Xoroshiro128: """ Prototype Core PRNG using xoroshiro128 + Parameters + ---------- + seed : int, array of int + Integer or array of integers between 0 and 2**64 - 1 + Notes ----- Exposes no user-facing API except `get_state` and `set_state`. Designed @@ -36,12 +42,16 @@ cdef class Xoroshiro128: cdef anon_func_state anon_func_state cdef public object _anon_func_state - def __init__(self): - try: - state = random_entropy(4) - except RuntimeError: - state = random_entropy(4, 'fallback') - state = state.view(np.uint64) + def __init__(self, seed=None): + if seed is None: + try: + state = random_entropy(4) + except RuntimeError: + state = random_entropy(4, 'fallback') + state = state.view(np.uint64) + else: + state = entropy.seed_by_array(seed, 2) + self.rng_state.s[0] = int(state[0]) self.rng_state.s[1] = int(state[1]) diff --git a/_randomgen/demo.py b/_randomgen/demo.py index 78d2bb4606ff..f11ad2b2a91c 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -5,3 +5,6 @@ print(RandomGenerator().random_integer()) print(RandomGenerator(Xoroshiro128()).random_integer()) print(RandomGenerator(SplitMix64()).random_integer()) +print(RandomGenerator(SplitMix64()).random_integer()) +print(RandomGenerator(SplitMix64(1)).random_integer()) +print(RandomGenerator(SplitMix64([1.0,2.0])).random_integer()) From f6faacdf31ab1e753a6eda27f36dac0a04b9c68b Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 24 Feb 2018 19:18:38 +0000 Subject: [PATCH 006/279] CLN: Simplify xoroshiro state Simplify xoroshiro state --- _randomgen/core_prng/__init__.py | 4 +- .../core_prng/src/xoroshiro128/xoroshiro128.c | 14 +++---- .../core_prng/src/xoroshiro128/xoroshiro128.h | 16 +++----- _randomgen/core_prng/xoroshiro128.pyx | 40 +++++++++---------- _randomgen/demo.py | 4 +- 5 files changed, 38 insertions(+), 40 deletions(-) diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index 8bcc8c6f1365..d097a9ef158b 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -1,3 +1,5 @@ from .generator import RandomGenerator from .xoroshiro128 import Xoroshiro128 -from .splitmix64 import SplitMix64 \ No newline at end of file +from .splitmix64 import SplitMix64 + +__all__ = ['RandomGenerator', 'SplitMix64', 'Xoroshiro128'] diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c index b346fd50eee7..b9fb5d084309 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c @@ -32,9 +32,9 @@ See . */ #include "xoroshiro128.h" -extern inline uint64_t xoroshiro128_next(xoroshiro128_state *state); +extern inline uint64_t xoroshiro128_next(uint64_t *s); -void xoroshiro128_jump(xoroshiro128_state *state) { +void xoroshiro128_jump(uint64_t *s) { static const uint64_t JUMP[] = {0xbeac0467eba5facb, 0xd86b048b86aa9922}; uint64_t s0 = 0; @@ -42,12 +42,12 @@ void xoroshiro128_jump(xoroshiro128_state *state) { for (int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) for (int b = 0; b < 64; b++) { if (JUMP[i] & UINT64_C(1) << b) { - s0 ^= state->s[0]; - s1 ^= state->s[1]; + s0 ^= s[0]; + s1 ^= s[1]; } - xoroshiro128_next(state); + xoroshiro128_next(s); } - state->s[0] = s0; - state->s[1] = s1; + s[0] = s0; + s[1] = s1; } diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h index d6c0eefaf251..2ececd00e493 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h @@ -1,23 +1,19 @@ #include -typedef struct s_xoroshiro128_state { - uint64_t s[2]; -} xoroshiro128_state; - static inline uint64_t rotl(const uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } -static inline uint64_t xoroshiro128_next(xoroshiro128_state *state) { - const uint64_t s0 = state->s[0]; - uint64_t s1 = state->s[1]; +static inline uint64_t xoroshiro128_next(uint64_t *s) { + const uint64_t s0 = s[0]; + uint64_t s1 = s[1]; const uint64_t result = s0 + s1; s1 ^= s0; - state->s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b - state->s[1] = rotl(s1, 36); // c + s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b + s[1] = rotl(s1, 36); // c return result; } -void xoroshiro128_jump(xoroshiro128_state *state); +void xoroshiro128_jump(uint64_t *s); diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 1ae7926acb00..8baf531c6d9e 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -1,6 +1,7 @@ import numpy as np cimport numpy as np from libc.stdint cimport uint64_t +from libc.stdlib cimport malloc from cpython.pycapsule cimport PyCapsule_New from common cimport * from core_prng.entropy import random_entropy @@ -9,20 +10,13 @@ np.import_array() cdef extern from "src/xoroshiro128/xoroshiro128.h": - cdef struct s_xoroshiro128_state: - uint64_t s[2] + cdef uint64_t xoroshiro128_next(uint64_t *s) nogil + cdef void xoroshiro128_jump(uint64_t *s) - ctypedef s_xoroshiro128_state xoroshiro128_state - - cdef uint64_t xoroshiro128_next(xoroshiro128_state* state) nogil - - cdef void xoroshiro128_jump(xoroshiro128_state* state) - - -ctypedef uint64_t (*random_uint64)(xoroshiro128_state* state) +ctypedef uint64_t (*random_uint64)(uint64_t *s) cdef uint64_t _xoroshiro128_anon(void* st) nogil: - return xoroshiro128_next(st) + return xoroshiro128_next(st) cdef class Xoroshiro128: """ @@ -38,10 +32,11 @@ cdef class Xoroshiro128: Exposes no user-facing API except `get_state` and `set_state`. Designed for use in a `RandomGenerator` object. """ - cdef xoroshiro128_state rng_state + cdef uint64_t *rng_state cdef anon_func_state anon_func_state cdef public object _anon_func_state + def __init__(self, seed=None): if seed is None: try: @@ -51,11 +46,11 @@ cdef class Xoroshiro128: state = state.view(np.uint64) else: state = entropy.seed_by_array(seed, 2) + self.rng_state = malloc(2 * sizeof(uint64_t)) + self.rng_state[0] = int(state[0]) + self.rng_state[1] = int(state[1]) - self.rng_state.s[0] = int(state[0]) - self.rng_state.s[1] = int(state[1]) - - self.anon_func_state.state = &self.rng_state + self.anon_func_state.state = self.rng_state self.anon_func_state.f = &_xoroshiro128_anon cdef const char *anon_name = "Anon CorePRNG func_state" self._anon_func_state = PyCapsule_New(&self.anon_func_state, @@ -74,17 +69,20 @@ cdef class Xoroshiro128: ----- Testing only """ - return xoroshiro128_next(&self.rng_state) + return xoroshiro128_next(self.rng_state) def get_state(self): """Get PRNG state""" - return np.array(self.rng_state.s,dtype=np.uint64) + state = np.empty(2, dtype=np.uint64) + state[0] = self.rng_state[0] + state[1] = self.rng_state[1] + return state def set_state(self, value): """Set PRNG state""" value = np.asarray(value, dtype=np.uint64) - self.rng_state.s[0] = value[0] - self.rng_state.s[1] = value[1] + self.rng_state[0] = value[0] + self.rng_state[1] = value[1] def jump(self): - xoroshiro128_jump(&self.rng_state) + xoroshiro128_jump(self.rng_state) diff --git a/_randomgen/demo.py b/_randomgen/demo.py index f11ad2b2a91c..d034d83c5423 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -4,7 +4,9 @@ print(RandomGenerator().random_integer()) print(RandomGenerator(Xoroshiro128()).random_integer()) +x = Xoroshiro128() +print(x.get_state()) print(RandomGenerator(SplitMix64()).random_integer()) print(RandomGenerator(SplitMix64()).random_integer()) print(RandomGenerator(SplitMix64(1)).random_integer()) -print(RandomGenerator(SplitMix64([1.0,2.0])).random_integer()) +print(RandomGenerator(SplitMix64([1.0, 2.0])).random_integer()) From 4e8597444e2d09ae83f8ef8d0135c25a04855a7c Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 26 Feb 2018 15:19:16 +0000 Subject: [PATCH 007/279] REF: Add additional state Add state to allow 32 bit generation --- _randomgen/core_prng/common.pxd | 14 ++- _randomgen/core_prng/common.pyx | 42 +++++++++ _randomgen/core_prng/generator.pyx | 80 +++++++++++++++- _randomgen/core_prng/splitmix64.pyx | 63 +++++++++---- .../core_prng/src/splitmix64/splitmix64.c | 6 +- .../core_prng/src/splitmix64/splitmix64.h | 21 +++++ .../core_prng/src/xoroshiro128/xoroshiro128.c | 16 ++-- .../core_prng/src/xoroshiro128/xoroshiro128.h | 23 ++++- _randomgen/core_prng/xoroshiro128.pyx | 91 +++++++++++++------ _randomgen/demo.py | 17 +++- _randomgen/setup.py | 6 +- 11 files changed, 319 insertions(+), 60 deletions(-) create mode 100644 _randomgen/core_prng/common.pyx diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index e9949220f9c6..9b867167967e 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -1,9 +1,19 @@ + from libc.stdint cimport uint64_t -ctypedef uint64_t (*random_uint64_anon)(void* st) +ctypedef uint64_t (*random_uint64_anon)(void* st) nogil + +ctypedef double (*random_double_anon)(void* st) nogil cdef struct anon_func_state: void *state - void *f + void *next_uint64 + void *next_uint32 + void *next_double ctypedef anon_func_state anon_func_state_t + +cdef inline double uint64_to_double(uint64_t rnd) nogil: + return (rnd >> 11) * (1.0 / 9007199254740992.0) + +cdef object double_fill(random_double_anon *random_double, void *state, object size, object lock, object out) diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx new file mode 100644 index 000000000000..3fb5dd12971e --- /dev/null +++ b/_randomgen/core_prng/common.pyx @@ -0,0 +1,42 @@ +import numpy as np +cimport numpy as np +from common cimport * + +np.import_array() + +cdef check_output(object out, object dtype, object size): + if out is None: + return + cdef np.ndarray out_array = out + if not (np.PyArray_CHKFLAGS(out_array, np.NPY_CARRAY) or + np.PyArray_CHKFLAGS(out_array, np.NPY_FARRAY)): + raise ValueError('Supplied output array is not contiguous, writable or aligned.') + if out_array.dtype != dtype: + raise TypeError('Supplied output array has the wrong type. ' + 'Expected {0}, got {0}'.format(dtype, out_array.dtype)) + if size is not None: + # TODO: enable this !!! if tuple(size) != out_array.shape: + raise ValueError('size and out cannot be simultaneously used') + + +cdef object double_fill(random_double_anon *random_double, void *state, object size, object lock, object out): + cdef double *out_array_data + cdef np.ndarray out_array + cdef np.npy_intp i, n + + if size is None and out is None: + with lock: + return random_double[0](state) + + if out is not None: + check_output(out, np.double, size) + out_array = out + else: + out_array = np.empty(size, np.double) + + n = np.PyArray_SIZE(out_array) + out_array_data = np.PyArray_DATA(out_array) + with lock, nogil: + for i in range(n): + out_array_data[i] = random_double[0](state) + return out_array diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 2648f9c0593a..7f31ea9be389 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -2,6 +2,10 @@ import numpy as np cimport numpy as np from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from common cimport * +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock from core_prng.splitmix64 import SplitMix64 @@ -25,7 +29,9 @@ cdef class RandomGenerator: cdef public object __core_prng cdef anon_func_state anon_rng_func_state cdef random_uint64_anon next_uint64 + cdef random_double_anon next_double cdef void *rng_state + cdef object lock def __init__(self, prng=None): if prng is None: @@ -37,11 +43,81 @@ cdef class RandomGenerator: if not PyCapsule_IsValid(capsule, anon_name): raise ValueError("Invalid pointer to anon_func_state") self.anon_rng_func_state = (PyCapsule_GetPointer(capsule, anon_name))[0] - self.next_uint64 = self.anon_rng_func_state.f + self.next_uint64 = self.anon_rng_func_state.next_uint64 + self.next_double = self.anon_rng_func_state.next_double self.rng_state = self.anon_rng_func_state.state + self.lock = Lock() + + @property + def state(self): + """Get ot set the underlying PRNG's state""" + return self.__core_prng.state + + @state.setter + def state(self, value): + self.__core_prng.state = value def random_integer(self): return self.next_uint64(self.rng_state) def random_double(self): - return (self.next_uint64(self.rng_state) >> 11) * (1.0 / 9007199254740992.0) + return self.next_double(self.rng_state) + + def random_sample(self, size=None, dtype=np.float64, out=None): + """ + random_sample(size=None, dtype='d', out=None) + + Return random floats in the half-open interval [0.0, 1.0). + + Results are from the "continuous uniform" distribution over the + stated interval. To sample :math:`Unif[a, b), b > a` multiply + the output of `random_sample` by `(b-a)` and add `a`:: + + (b - a) * random_sample() + a + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + dtype : {str, dtype}, optional + Desired dtype of the result, either 'd' (or 'float64') or 'f' + (or 'float32'). All dtypes are determined by their name. The + default value is 'd'. + out : ndarray, optional + Alternative output array in which to place the result. If size is not None, + it must have the same shape as the provided size and must match the type of + the output values. + + Returns + ------- + out : float or ndarray of floats + Array of random floats of shape `size` (unless ``size=None``, in which + case a single float is returned). + + Examples + -------- + >>> np.random.random_sample() + 0.47108547995356098 + >>> type(np.random.random_sample()) + + >>> np.random.random_sample((5,)) + array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) + + Three-by-two array of random numbers from [-5, 0): + + >>> 5 * np.random.random_sample((3, 2)) - 5 + array([[-3.99149989, -0.52338984], + [-2.99091858, -0.79479508], + [-1.23204345, -1.75224494]]) + """ + cdef double temp + key = np.dtype(dtype).name + if key == 'float64': + return double_fill(&self.next_double, self.rng_state, size, self.lock, out) + elif key == 'float32': + raise NotImplementedError + # return float_fill(&self.rng_state, &random_uniform_fill_float, size, self.lock, out) + else: + raise TypeError('Unsupported dtype "%s" for random_sample' % key) diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index 1a4f3827cae4..5bc8dd8d92f3 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -1,22 +1,34 @@ +from libc.stdint cimport uint32_t, uint64_t +from cpython.pycapsule cimport PyCapsule_New + import numpy as np cimport numpy as np -from cpython.pycapsule cimport PyCapsule_New -from common cimport * +from common cimport * from core_prng.entropy import random_entropy from core_prng cimport entropy np.import_array() cdef extern from "src/splitmix64/splitmix64.h": + cdef struct s_splitmix64_state: + uint64_t state + int has_uint32 + uint32_t uinteger + + ctypedef s_splitmix64_state splitmix64_state - cdef uint64_t splitmix64_next(uint64_t *state) nogil + cdef uint64_t splitmix64_next64(splitmix64_state *state) nogil + cdef uint64_t splitmix64_next32(splitmix64_state *state) nogil +cdef uint64_t splitmix64_uint64(void *st) nogil: + return splitmix64_next64( st) -ctypedef uint64_t (*random_uint64)(uint64_t *state) +cdef uint64_t splitmix64_uint32(void *st) nogil: + return splitmix64_next32( st) -cdef uint64_t _splitmix64_anon(void *st) nogil: - return splitmix64_next( st) +cdef double splitmix64_double(void *st) nogil: + return uint64_to_double(splitmix64_uint64( st)) cdef class SplitMix64: """ @@ -32,7 +44,7 @@ cdef class SplitMix64: Exposes no user-facing API except `get_state` and `set_state`. Designed for use in a `RandomGenerator` object. """ - cdef uint64_t rng_state + cdef splitmix64_state rng_state cdef anon_func_state anon_func_state cdef public object _anon_func_state @@ -46,10 +58,13 @@ cdef class SplitMix64: else: state = entropy.seed_by_array(seed, 1) - self.rng_state = int(state[0]) + self.rng_state.state = int(state[0]) + self.rng_state.has_uint32 = 0 self.anon_func_state.state = &self.rng_state - self.anon_func_state.f = &_splitmix64_anon + self.anon_func_state.next_uint64 = &splitmix64_uint64 + self.anon_func_state.next_uint32 = &splitmix64_uint32 + self.anon_func_state.next_double = &splitmix64_double cdef const char *anon_name = "Anon CorePRNG func_state" self._anon_func_state = PyCapsule_New( &self.anon_func_state, anon_name, NULL) @@ -67,12 +82,24 @@ cdef class SplitMix64: ----- Testing only """ - return splitmix64_next(&self.rng_state) - - def get_state(self): - """Get PRNG state""" - return self.rng_state.state - - def set_state(self, uint64_t value): - """Set PRNG state""" - self.rng_state.state = value + return splitmix64_next64(&self.rng_state) + + @property + def state(self): + """Get or set the PRNG state""" + return {'prng': self.__class__.__name__, + 's': self.rng_state.state, + 'has_uint32': self.rng_state.has_uint32, + 'uinteger': self.rng_state.uinteger} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + prng = value.get('prng', '') + if prng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + self.rng_state.state = value['s'] + self.rng_state.has_uint32 = value['has_uint32'] + self.rng_state.uinteger = value['uinteger'] diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.c b/_randomgen/core_prng/src/splitmix64/splitmix64.c index 1e75f4b9b100..77f0693bac65 100644 --- a/_randomgen/core_prng/src/splitmix64/splitmix64.c +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.c @@ -22,4 +22,8 @@ license. #include "splitmix64.h" -extern inline uint64_t splitmix64_next(uint64_t *state); +static inline uint64_t splitmix64_next(uint64_t *state); + +extern inline uint64_t splitmix64_next64(splitmix64_state *state); + +extern inline uint32_t splitmix64_next32(splitmix64_state *state); diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.h b/_randomgen/core_prng/src/splitmix64/splitmix64.h index d5d7549d9fad..6fbaa1657abf 100644 --- a/_randomgen/core_prng/src/splitmix64/splitmix64.h +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.h @@ -1,8 +1,29 @@ #include +typedef struct s_splitmix64_state { + uint64_t state; + int has_uint32; + uint32_t uinteger; +} splitmix64_state; + static inline uint64_t splitmix64_next(uint64_t *state) { uint64_t z = (state[0] += 0x9e3779b97f4a7c15); z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; z = (z ^ (z >> 27)) * 0x94d049bb133111eb; return z ^ (z >> 31); } + +static inline uint64_t splitmix64_next64(splitmix64_state *state) { + return splitmix64_next(&state->state); +} + +static inline uint32_t splitmix64_next32(splitmix64_state *state) { + if (state->has_uint32) { + state->has_uint32 = 0; + return state->uinteger; + } + uint64_t next = splitmix64_next64(state); + state->uinteger = next & 0xffffffff; + state->has_uint32 = 1; + return (uint32_t)(next >> 32); +} diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c index b9fb5d084309..244ca28b20d9 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c @@ -34,7 +34,11 @@ See . */ extern inline uint64_t xoroshiro128_next(uint64_t *s); -void xoroshiro128_jump(uint64_t *s) { +static inline uint64_t xoroshiro128_next64(xoroshiro128_state *state); + +static inline uint64_t xoroshiro128_next32(xoroshiro128_state *state); + +void xoroshiro128_jump(xoroshiro128_state *state) { static const uint64_t JUMP[] = {0xbeac0467eba5facb, 0xd86b048b86aa9922}; uint64_t s0 = 0; @@ -42,12 +46,12 @@ void xoroshiro128_jump(uint64_t *s) { for (int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) for (int b = 0; b < 64; b++) { if (JUMP[i] & UINT64_C(1) << b) { - s0 ^= s[0]; - s1 ^= s[1]; + s0 ^= state->s[0]; + s1 ^= state->s[1]; } - xoroshiro128_next(s); + xoroshiro128_next(&state->s); } - s[0] = s0; - s[1] = s1; + state->s[0] = s0; + state->s[1] = s1; } diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h index 2ececd00e493..f575ef7aada3 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h @@ -1,5 +1,11 @@ #include +typedef struct s_xoroshiro128_state { + uint64_t s[2]; + int has_uint32; + uint32_t uinteger; +} xoroshiro128_state; + static inline uint64_t rotl(const uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } @@ -16,4 +22,19 @@ static inline uint64_t xoroshiro128_next(uint64_t *s) { return result; } -void xoroshiro128_jump(uint64_t *s); +static inline uint64_t xoroshiro128_next64(xoroshiro128_state *state) { + return xoroshiro128_next(&state->s[0]); +} + +static inline uint64_t xoroshiro128_next32(xoroshiro128_state *state) { + if (state->has_uint32) { + state->has_uint32 = 0; + return state->uinteger; + } + uint64_t next = xoroshiro128_next(&state->s[0]); + state->has_uint32 = 1; + state->uinteger = (uint32_t)(next & 0xffffffff); + return (uint32_t)(next >> 32); +} + +void xoroshiro128_jump(xoroshiro128_state *state); diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 8baf531c6d9e..515bb6a1a753 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -1,22 +1,37 @@ import numpy as np cimport numpy as np -from libc.stdint cimport uint64_t +from libc.stdint cimport uint32_t, uint64_t from libc.stdlib cimport malloc from cpython.pycapsule cimport PyCapsule_New from common cimport * from core_prng.entropy import random_entropy from core_prng cimport entropy + np.import_array() cdef extern from "src/xoroshiro128/xoroshiro128.h": + cdef struct s_xoroshiro128_state: + uint64_t s[2] + int has_uint32 + uint32_t uinteger + + ctypedef s_xoroshiro128_state xoroshiro128_state + cdef uint64_t xoroshiro128_next(uint64_t *s) nogil - cdef void xoroshiro128_jump(uint64_t *s) -ctypedef uint64_t (*random_uint64)(uint64_t *s) + cdef uint64_t xoroshiro128_next64(xoroshiro128_state *state) nogil + cdef uint64_t xoroshiro128_next32(xoroshiro128_state *state) nogil + cdef void xoroshiro128_jump(xoroshiro128_state *state) -cdef uint64_t _xoroshiro128_anon(void* st) nogil: - return xoroshiro128_next(st) +cdef uint64_t xoroshiro128_uint64(void* st) nogil: + return xoroshiro128_next64(st) + +cdef uint64_t xoroshiro128_uint32(void *st) nogil: + return xoroshiro128_next32( st) + +cdef double xoroshiro128_double(void* st) nogil: + return uint64_to_double(xoroshiro128_next64(st)) cdef class Xoroshiro128: """ @@ -32,7 +47,7 @@ cdef class Xoroshiro128: Exposes no user-facing API except `get_state` and `set_state`. Designed for use in a `RandomGenerator` object. """ - cdef uint64_t *rng_state + cdef xoroshiro128_state rng_state cdef anon_func_state anon_func_state cdef public object _anon_func_state @@ -46,20 +61,26 @@ cdef class Xoroshiro128: state = state.view(np.uint64) else: state = entropy.seed_by_array(seed, 2) - self.rng_state = malloc(2 * sizeof(uint64_t)) - self.rng_state[0] = int(state[0]) - self.rng_state[1] = int(state[1]) + self.rng_state.s[0] = int(state[0]) + self.rng_state.s[1] = int(state[1]) - self.anon_func_state.state = self.rng_state - self.anon_func_state.f = &_xoroshiro128_anon + self.anon_func_state.state = &self.rng_state + self.anon_func_state.next_uint64 = &xoroshiro128_uint64 + self.anon_func_state.next_uint32 = &xoroshiro128_uint32 + self.anon_func_state.next_double = &xoroshiro128_double cdef const char *anon_name = "Anon CorePRNG func_state" self._anon_func_state = PyCapsule_New(&self.anon_func_state, anon_name, NULL) - def __random_integer(self): + def __random_integer(self, bits=64): """ 64-bit Random Integers from the PRNG + Parameters + ---------- + bits : {32, 64} + Number of random bits to return + Returns ------- rv : int @@ -69,20 +90,36 @@ cdef class Xoroshiro128: ----- Testing only """ - return xoroshiro128_next(self.rng_state) - - def get_state(self): - """Get PRNG state""" - state = np.empty(2, dtype=np.uint64) - state[0] = self.rng_state[0] - state[1] = self.rng_state[1] - return state - - def set_state(self, value): - """Set PRNG state""" - value = np.asarray(value, dtype=np.uint64) - self.rng_state[0] = value[0] - self.rng_state[1] = value[1] + if bits == 64: + return xoroshiro128_next64(&self.rng_state) + elif bits == 32: + return xoroshiro128_next32(&self.rng_state) + else: + raise ValueError('bits must be 32 or 64') def jump(self): - xoroshiro128_jump(self.rng_state) + xoroshiro128_jump(&self.rng_state) + + @property + def state(self): + """Get or set the PRNG state""" + state = np.empty(2, dtype=np.uint64) + state[0] = self.rng_state.s[0] + state[1] = self.rng_state.s[1] + return {'prng': self.__class__.__name__, + 's': state, + 'has_uint32': self.rng_state.has_uint32, + 'uinteger': self.rng_state.uinteger} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + prng = value.get('prng', '') + if prng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + self.rng_state.s[0] = value['s'][0] + self.rng_state.s[1] = value['s'][1] + self.rng_state.has_uint32 = value['has_uint32'] + self.rng_state.uinteger = value['uinteger'] diff --git a/_randomgen/demo.py b/_randomgen/demo.py index d034d83c5423..148c36689230 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -4,9 +4,22 @@ print(RandomGenerator().random_integer()) print(RandomGenerator(Xoroshiro128()).random_integer()) -x = Xoroshiro128() -print(x.get_state()) print(RandomGenerator(SplitMix64()).random_integer()) print(RandomGenerator(SplitMix64()).random_integer()) print(RandomGenerator(SplitMix64(1)).random_integer()) print(RandomGenerator(SplitMix64([1.0, 2.0])).random_integer()) + + +print('\n'*3) +print('Check random_sample') +rg = RandomGenerator() +print(rg.random_sample((3))) +print(rg.random_sample((3,1))) + +print('\n'*3) +print('Check set/get state') +state = rg.state +print(rg.state) +print(rg.random_integer()) +rg.state = state +print(rg.random_integer()) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index bd66904cd169..3d0f1c6edd37 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -31,7 +31,11 @@ join(MOD_DIR, 'src', 'xoroshiro128')]), Extension("core_prng.generator", ["core_prng/generator.pyx"], - include_dirs=[np.get_include()])] + include_dirs=[np.get_include()]), + Extension("core_prng.common", + ["core_prng/common.pyx"], + include_dirs=[np.get_include()]), + ] class BinaryDistribution(Distribution): From 00947ba689ed7214fbce00aa897b4111ba25dd20 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 28 Feb 2018 15:29:20 +0000 Subject: [PATCH 008/279] REF: Reactor filler to take a function --- _randomgen/core_prng/common.pxd | 4 +++- _randomgen/core_prng/common.pyx | 7 ++++--- _randomgen/core_prng/generator.pyx | 11 ++++++++++- _randomgen/core_prng/splitmix64.pyx | 2 +- _randomgen/core_prng/xoroshiro128.pyx | 2 +- _randomgen/demo.py | 1 + _randomgen/setup.py | 3 +++ 7 files changed, 23 insertions(+), 7 deletions(-) diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index 9b867167967e..b3e11a9aa55a 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -5,6 +5,8 @@ ctypedef uint64_t (*random_uint64_anon)(void* st) nogil ctypedef double (*random_double_anon)(void* st) nogil +ctypedef double (*random_0)(void *st) nogil + cdef struct anon_func_state: void *state void *next_uint64 @@ -16,4 +18,4 @@ ctypedef anon_func_state anon_func_state_t cdef inline double uint64_to_double(uint64_t rnd) nogil: return (rnd >> 11) * (1.0 / 9007199254740992.0) -cdef object double_fill(random_double_anon *random_double, void *state, object size, object lock, object out) +cdef object double_fill(void *func, void *state, object size, object lock, object out) diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index 3fb5dd12971e..d7b5da8ddc6f 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -19,14 +19,15 @@ cdef check_output(object out, object dtype, object size): raise ValueError('size and out cannot be simultaneously used') -cdef object double_fill(random_double_anon *random_double, void *state, object size, object lock, object out): +cdef object double_fill(void *func, void *state, object size, object lock, object out): + cdef random_0 random_func = (func) cdef double *out_array_data cdef np.ndarray out_array cdef np.npy_intp i, n if size is None and out is None: with lock: - return random_double[0](state) + return random_func(state) if out is not None: check_output(out, np.double, size) @@ -38,5 +39,5 @@ cdef object double_fill(random_double_anon *random_double, void *state, object s out_array_data = np.PyArray_DATA(out_array) with lock, nogil: for i in range(n): - out_array_data[i] = random_double[0](state) + out_array_data[i] = random_func(state) return out_array diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 7f31ea9be389..636d63a63a02 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -2,6 +2,7 @@ import numpy as np cimport numpy as np from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from common cimport * +cimport common try: from threading import Lock except ImportError: @@ -11,6 +12,14 @@ from core_prng.splitmix64 import SplitMix64 np.import_array() + +cdef double random_double(void *void_state): + cdef anon_func_state_t *anon_state = void_state + cdef random_double_anon random_double_f = anon_state.next_double + cdef void *state = anon_state.state + return random_double_f(state) + + cdef class RandomGenerator: """ Prototype Random Generator that consumes randoms from a CorePRNG class @@ -115,7 +124,7 @@ cdef class RandomGenerator: cdef double temp key = np.dtype(dtype).name if key == 'float64': - return double_fill(&self.next_double, self.rng_state, size, self.lock, out) + return double_fill(&random_double, &self.anon_rng_func_state, size, self.lock, out) elif key == 'float32': raise NotImplementedError # return float_fill(&self.rng_state, &random_uniform_fill_float, size, self.lock, out) diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index 5bc8dd8d92f3..0aeda157a139 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -6,7 +6,7 @@ cimport numpy as np from common cimport * from core_prng.entropy import random_entropy -from core_prng cimport entropy +cimport entropy np.import_array() diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 515bb6a1a753..9f6da5355041 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -5,7 +5,7 @@ from libc.stdlib cimport malloc from cpython.pycapsule cimport PyCapsule_New from common cimport * from core_prng.entropy import random_entropy -from core_prng cimport entropy +cimport entropy np.import_array() diff --git a/_randomgen/demo.py b/_randomgen/demo.py index 148c36689230..4eb414bef6a7 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -13,6 +13,7 @@ print('\n'*3) print('Check random_sample') rg = RandomGenerator() +print(rg.random_sample()) print(rg.random_sample((3))) print(rg.random_sample((3,1))) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 3d0f1c6edd37..a95c0e75de59 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -3,9 +3,12 @@ import numpy as np from Cython.Build import cythonize +import Cython.Compiler.Options from setuptools import setup, find_packages, Distribution from setuptools.extension import Extension +Cython.Compiler.Options.annotate = True + MOD_DIR = './core_prng' EXTRA_LINK_ARGS = [] From fd741d940709d3fd909f0dd3118bde05fc4595b6 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 28 Feb 2018 19:46:02 +0000 Subject: [PATCH 009/279] ENH: Add extra abstraction Abstract various components to allow more flexibility in generating specific distributions --- _randomgen/core_prng/common.pxd | 24 ++++---- _randomgen/core_prng/common.pyx | 25 +++++++- _randomgen/core_prng/generator.pyx | 58 +++++++++++-------- _randomgen/core_prng/splitmix64.pyx | 38 +++++++----- .../src/distributions/distributions.c | 25 ++++++++ .../src/distributions/distributions.h | 33 +++++++++++ _randomgen/core_prng/xoroshiro128.pyx | 16 ++--- _randomgen/demo.py | 18 ++++-- _randomgen/setup.py | 3 +- _randomgen/test.py | 14 +++++ 10 files changed, 190 insertions(+), 64 deletions(-) create mode 100644 _randomgen/core_prng/src/distributions/distributions.c create mode 100644 _randomgen/core_prng/src/distributions/distributions.h create mode 100644 _randomgen/test.py diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index b3e11a9aa55a..8d6df53ba641 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -1,21 +1,25 @@ +from libc.stdint cimport uint32_t, uint64_t -from libc.stdint cimport uint64_t +cdef extern from "src/distributions/distributions.h": + ctypedef double (*prng_double)(void *st) nogil -ctypedef uint64_t (*random_uint64_anon)(void* st) nogil + ctypedef float (*prng_float)(void *st) nogil -ctypedef double (*random_double_anon)(void* st) nogil + ctypedef uint32_t (*prng_uint32)(void *st) nogil -ctypedef double (*random_0)(void *st) nogil + ctypedef uint64_t (*prng_uint64)(void *st) nogil -cdef struct anon_func_state: - void *state - void *next_uint64 - void *next_uint32 - void *next_double + cdef struct prng: + void *state + void *next_uint64 + void *next_uint32 + void *next_double -ctypedef anon_func_state anon_func_state_t + ctypedef prng prng_t cdef inline double uint64_to_double(uint64_t rnd) nogil: return (rnd >> 11) * (1.0 / 9007199254740992.0) cdef object double_fill(void *func, void *state, object size, object lock, object out) + +cdef object float_fill(void *func, void *state, object size, object lock, object out) \ No newline at end of file diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index d7b5da8ddc6f..9dbd5ea08c2c 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -20,7 +20,7 @@ cdef check_output(object out, object dtype, object size): cdef object double_fill(void *func, void *state, object size, object lock, object out): - cdef random_0 random_func = (func) + cdef prng_double random_func = (func) cdef double *out_array_data cdef np.ndarray out_array cdef np.npy_intp i, n @@ -41,3 +41,26 @@ cdef object double_fill(void *func, void *state, object size, object lock, objec for i in range(n): out_array_data[i] = random_func(state) return out_array + +cdef object float_fill(void *func, void *state, object size, object lock, object out): + cdef prng_float random_func = (func) + cdef float *out_array_data + cdef np.ndarray out_array + cdef np.npy_intp i, n + + if size is None and out is None: + with lock: + return random_func(state) + + if out is not None: + check_output(out, np.float32, size) + out_array = out + else: + out_array = np.empty(size, np.float32) + + n = np.PyArray_SIZE(out_array) + out_array_data = np.PyArray_DATA(out_array) + with lock, nogil: + for i in range(n): + out_array_data[i] = random_func(state) + return out_array diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 636d63a63a02..bd213f5bc3ef 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -1,3 +1,4 @@ +from libc.stdint cimport uint64_t, uint32_t import numpy as np cimport numpy as np from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer @@ -12,13 +13,10 @@ from core_prng.splitmix64 import SplitMix64 np.import_array() - -cdef double random_double(void *void_state): - cdef anon_func_state_t *anon_state = void_state - cdef random_double_anon random_double_f = anon_state.next_double - cdef void *state = anon_state.state - return random_double_f(state) - +cdef extern from "src/distributions/distributions.h": + double random_double(void *void_state) nogil + float random_float(void *void_state) nogil + uint32_t random_uint32(void *void_state) nogil cdef class RandomGenerator: """ @@ -36,9 +34,10 @@ cdef class RandomGenerator: >>> rg.random_integer() """ cdef public object __core_prng - cdef anon_func_state anon_rng_func_state - cdef random_uint64_anon next_uint64 - cdef random_double_anon next_double + cdef prng_t *_prng + cdef prng_uint64 next_uint64 + cdef prng_double next_double + cdef prng_uint32 next_uint32 cdef void *rng_state cdef object lock @@ -47,30 +46,42 @@ cdef class RandomGenerator: prng = SplitMix64() self.__core_prng = prng - capsule = prng._anon_func_state - cdef const char *anon_name = "Anon CorePRNG func_state" + capsule = prng._prng_capsule + cdef const char *anon_name = "CorePRNG" if not PyCapsule_IsValid(capsule, anon_name): raise ValueError("Invalid pointer to anon_func_state") - self.anon_rng_func_state = (PyCapsule_GetPointer(capsule, anon_name))[0] - self.next_uint64 = self.anon_rng_func_state.next_uint64 - self.next_double = self.anon_rng_func_state.next_double - self.rng_state = self.anon_rng_func_state.state + self._prng = PyCapsule_GetPointer(capsule, anon_name) + self.next_uint32 = self._prng.next_uint32 + self.next_uint64 = self._prng.next_uint64 + self.next_double = self._prng.next_double + self.rng_state = self._prng.state self.lock = Lock() @property def state(self): - """Get ot set the underlying PRNG's state""" + """Get or set the underlying PRNG's state""" return self.__core_prng.state @state.setter def state(self, value): self.__core_prng.state = value - def random_integer(self): - return self.next_uint64(self.rng_state) + def random_integer(self, bits=64): + if bits==64: + return self.next_uint64(self.rng_state) + elif bits==32: + return random_uint32(self._prng) # self.next_uint32(self.rng_state) + # return self.next_uint32(self.rng_state) + else: + raise ValueError('bits must be 32 or 64') - def random_double(self): - return self.next_double(self.rng_state) + def random_double(self, bits=64): + if bits==64: + return self.next_double(self.rng_state) + elif bits==32: + return random_float(self._prng) + else: + raise ValueError('bits must be 32 or 64') def random_sample(self, size=None, dtype=np.float64, out=None): """ @@ -124,9 +135,8 @@ cdef class RandomGenerator: cdef double temp key = np.dtype(dtype).name if key == 'float64': - return double_fill(&random_double, &self.anon_rng_func_state, size, self.lock, out) + return double_fill(&random_double, self._prng, size, self.lock, out) elif key == 'float32': - raise NotImplementedError - # return float_fill(&self.rng_state, &random_uniform_fill_float, size, self.lock, out) + return float_fill(&random_float, self._prng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for random_sample' % key) diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index 0aeda157a139..d645a1512f46 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -1,6 +1,6 @@ from libc.stdint cimport uint32_t, uint64_t -from cpython.pycapsule cimport PyCapsule_New - +from cpython.pycapsule cimport PyCapsule_New, PyCapsule_GetPointer +from libc.stdlib cimport malloc import numpy as np cimport numpy as np @@ -19,13 +19,14 @@ cdef extern from "src/splitmix64/splitmix64.h": ctypedef s_splitmix64_state splitmix64_state cdef uint64_t splitmix64_next64(splitmix64_state *state) nogil - cdef uint64_t splitmix64_next32(splitmix64_state *state) nogil + cdef uint32_t splitmix64_next32(splitmix64_state *state) nogil cdef uint64_t splitmix64_uint64(void *st) nogil: return splitmix64_next64( st) -cdef uint64_t splitmix64_uint32(void *st) nogil: - return splitmix64_next32( st) +cdef uint32_t splitmix64_uint32(void *st): # nogil: TODO + cdef splitmix64_state *state = st + return splitmix64_next32(state) cdef double splitmix64_double(void *st) nogil: return uint64_to_double(splitmix64_uint64( st)) @@ -44,11 +45,14 @@ cdef class SplitMix64: Exposes no user-facing API except `get_state` and `set_state`. Designed for use in a `RandomGenerator` object. """ - cdef splitmix64_state rng_state - cdef anon_func_state anon_func_state - cdef public object _anon_func_state + cdef splitmix64_state *rng_state + cdef prng_t *_prng + cdef prng_t *_prng2 + cdef public object _prng_capsule def __init__(self, seed=None): + self.rng_state = malloc(sizeof(splitmix64_state)) + self._prng = malloc(sizeof(prng_t)) if seed is None: try: state = random_entropy(2) @@ -60,14 +64,16 @@ cdef class SplitMix64: self.rng_state.state = int(state[0]) self.rng_state.has_uint32 = 0 + self.rng_state.uinteger = 0 + self._prng.state = self.rng_state + self._prng.next_uint64 = &splitmix64_uint64 + self._prng.next_uint32 = &splitmix64_uint32 + self._prng.next_double = &splitmix64_double + cdef const char *anon_name = "CorePRNG" + self._prng_capsule = PyCapsule_New(self._prng, + anon_name, NULL) + self._prng2 = PyCapsule_GetPointer(self._prng_capsule, anon_name) - self.anon_func_state.state = &self.rng_state - self.anon_func_state.next_uint64 = &splitmix64_uint64 - self.anon_func_state.next_uint32 = &splitmix64_uint32 - self.anon_func_state.next_double = &splitmix64_double - cdef const char *anon_name = "Anon CorePRNG func_state" - self._anon_func_state = PyCapsule_New( &self.anon_func_state, - anon_name, NULL) def __random_integer(self): """ @@ -82,7 +88,7 @@ cdef class SplitMix64: ----- Testing only """ - return splitmix64_next64(&self.rng_state) + return splitmix64_next64(self.rng_state) @property def state(self): diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c new file mode 100644 index 000000000000..41613e045727 --- /dev/null +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -0,0 +1,25 @@ +#include "distributions.h" + +uint32_t random_uint32(void *void_state) { + prng_t *prng_state = (prng_t *)void_state; + prng_uint32 next_uint32 = (prng_uint32)prng_state->next_uint32; + return next_uint32(prng_state->state); +} + +float random_float(void *void_state) { + prng_t *prng_state = (prng_t *)void_state; + prng_uint32 next_uint32 = (prng_uint32)(prng_state->next_uint32); + uint32_t next_value = next_uint32(prng_state->state); + return (next_value >> 9) * (1.0f / 8388608.0f); +} + +double random_double(void *void_state) { + prng_t *prng_state = (prng_t *)void_state; + prng_uint64 next_uint64 = (prng_uint64)(prng_state->next_uint64); + uint64_t next_value = next_uint64(prng_state->state); + return (next_value >> 11) * (1.0 / 9007199254740992.0); + // + + //prng_double next_double = (prng_double)prng_state->next_double; + //return next_double(&prng_state->state); +} diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h new file mode 100644 index 000000000000..dbe38492cf06 --- /dev/null +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -0,0 +1,33 @@ +#include +#ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/stdint.h" +typedef int bool; +#define false 0 +#define true 1 +#else +#include +#include +#endif +#else +#include +#include +#endif + +typedef double (*prng_double)(void *st); +typedef float (*prng_float)(void *st); +typedef uint32_t (*prng_uint32)(void *st); +typedef uint64_t (*prng_uint64)(void *st); + +typedef struct prng { + void *state; + void *next_uint64; + void *next_uint32; + void *next_double; +} prng_t; + +float random_float(void *void_state); + +double random_double(void *void_state); + +uint32_t random_uint32(void *void_state); diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 9f6da5355041..b6b724f13372 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -48,8 +48,8 @@ cdef class Xoroshiro128: for use in a `RandomGenerator` object. """ cdef xoroshiro128_state rng_state - cdef anon_func_state anon_func_state - cdef public object _anon_func_state + cdef prng_t _prng + cdef public object _prng_capsule def __init__(self, seed=None): @@ -64,12 +64,12 @@ cdef class Xoroshiro128: self.rng_state.s[0] = int(state[0]) self.rng_state.s[1] = int(state[1]) - self.anon_func_state.state = &self.rng_state - self.anon_func_state.next_uint64 = &xoroshiro128_uint64 - self.anon_func_state.next_uint32 = &xoroshiro128_uint32 - self.anon_func_state.next_double = &xoroshiro128_double - cdef const char *anon_name = "Anon CorePRNG func_state" - self._anon_func_state = PyCapsule_New(&self.anon_func_state, + self._prng.state = &self.rng_state + self._prng.next_uint64 = &xoroshiro128_uint64 + self._prng.next_uint32 = &xoroshiro128_uint32 + self._prng.next_double = &xoroshiro128_double + cdef const char *anon_name = "CorePRNG" + self._prng_capsule = PyCapsule_New(&self._prng, anon_name, NULL) def __random_integer(self, bits=64): diff --git a/_randomgen/demo.py b/_randomgen/demo.py index 4eb414bef6a7..b40a2c42843d 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -9,18 +9,28 @@ print(RandomGenerator(SplitMix64(1)).random_integer()) print(RandomGenerator(SplitMix64([1.0, 2.0])).random_integer()) - -print('\n'*3) +print('\n' * 3) print('Check random_sample') rg = RandomGenerator() +print(rg.state) +print(rg.random_sample()) +print(rg.state) print(rg.random_sample()) print(rg.random_sample((3))) -print(rg.random_sample((3,1))) +print(rg.random_sample((3, 1))) +print(rg.state) +import numpy as np + +a = rg.random_sample((1, 1), dtype=np.float32) +print(a) +print(a.dtype) +print(rg.state) -print('\n'*3) +print('\n' * 3) print('Check set/get state') state = rg.state print(rg.state) print(rg.random_integer()) +print(rg.state) rg.state = state print(rg.random_integer()) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index a95c0e75de59..483299a52958 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -33,7 +33,8 @@ include_dirs=[np.get_include(), join(MOD_DIR, 'src', 'xoroshiro128')]), Extension("core_prng.generator", - ["core_prng/generator.pyx"], + ["core_prng/generator.pyx", + join(MOD_DIR, 'src', 'distributions', 'distributions.c')], include_dirs=[np.get_include()]), Extension("core_prng.common", ["core_prng/common.pyx"], diff --git a/_randomgen/test.py b/_randomgen/test.py new file mode 100644 index 000000000000..38ffa02b05c4 --- /dev/null +++ b/_randomgen/test.py @@ -0,0 +1,14 @@ +import core_prng as c +rg = c.RandomGenerator() +print(rg.state) +rg.random_integer(32) +print(rg.state) +rg.random_integer(32) +print(rg.state) + +rg.random_integer(64) +print(rg.state) +rg.random_integer(32) +print(rg.state) +rg.random_integer(64) +print(rg.state) From 1ae38a390149f1dd15e0d401c9d7e7e1dc099738 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 28 Feb 2018 23:59:34 +0000 Subject: [PATCH 010/279] ENH: Add float from double and std exponential Add float fillng from double Add support for log-based exponential --- _randomgen/core_prng/common.pxd | 6 ++- _randomgen/core_prng/common.pyx | 39 +++++++++----- _randomgen/core_prng/generator.pyx | 52 ++++++++++++++++--- _randomgen/core_prng/splitmix64.pyx | 3 -- .../src/distributions/distributions.c | 13 ++--- .../src/distributions/distributions.h | 4 ++ _randomgen/core_prng/xoroshiro128.pyx | 15 +++--- 7 files changed, 94 insertions(+), 38 deletions(-) diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index 8d6df53ba641..7e29a4190bf6 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -20,6 +20,8 @@ cdef extern from "src/distributions/distributions.h": cdef inline double uint64_to_double(uint64_t rnd) nogil: return (rnd >> 11) * (1.0 / 9007199254740992.0) -cdef object double_fill(void *func, void *state, object size, object lock, object out) +cdef object double_fill(void *func, void *state, object size, object lock) -cdef object float_fill(void *func, void *state, object size, object lock, object out) \ No newline at end of file +cdef object float_fill(void *func, void *state, object size, object lock) + +cdef object float_fill_from_double(void *func, void *state, object size, object lock) \ No newline at end of file diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index 9dbd5ea08c2c..2d09795af180 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -19,21 +19,17 @@ cdef check_output(object out, object dtype, object size): raise ValueError('size and out cannot be simultaneously used') -cdef object double_fill(void *func, void *state, object size, object lock, object out): +cdef object double_fill(void *func, void *state, object size, object lock): cdef prng_double random_func = (func) cdef double *out_array_data cdef np.ndarray out_array cdef np.npy_intp i, n - if size is None and out is None: + if size is None: with lock: return random_func(state) - if out is not None: - check_output(out, np.double, size) - out_array = out - else: - out_array = np.empty(size, np.double) + out_array = np.empty(size, np.double) n = np.PyArray_SIZE(out_array) out_array_data = np.PyArray_DATA(out_array) @@ -42,21 +38,17 @@ cdef object double_fill(void *func, void *state, object size, object lock, objec out_array_data[i] = random_func(state) return out_array -cdef object float_fill(void *func, void *state, object size, object lock, object out): +cdef object float_fill(void *func, void *state, object size, object lock): cdef prng_float random_func = (func) cdef float *out_array_data cdef np.ndarray out_array cdef np.npy_intp i, n - if size is None and out is None: + if size is None: with lock: return random_func(state) - if out is not None: - check_output(out, np.float32, size) - out_array = out - else: - out_array = np.empty(size, np.float32) + out_array = np.empty(size, np.float32) n = np.PyArray_SIZE(out_array) out_array_data = np.PyArray_DATA(out_array) @@ -64,3 +56,22 @@ cdef object float_fill(void *func, void *state, object size, object lock, object for i in range(n): out_array_data[i] = random_func(state) return out_array + +cdef object float_fill_from_double(void *func, void *state, object size, object lock): + cdef prng_double random_func = (func) + cdef float *out_array_data + cdef np.ndarray out_array + cdef np.npy_intp i, n + + if size is None: + with lock: + return random_func(state) + + out_array = np.empty(size, np.float32) + + n = np.PyArray_SIZE(out_array) + out_array_data = np.PyArray_DATA(out_array) + with lock, nogil: + for i in range(n): + out_array_data[i] = random_func(state) + return out_array diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index bd213f5bc3ef..93f44e86dea6 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -17,6 +17,7 @@ cdef extern from "src/distributions/distributions.h": double random_double(void *void_state) nogil float random_float(void *void_state) nogil uint32_t random_uint32(void *void_state) nogil + double random_standard_exponential(void *void_state) nogil cdef class RandomGenerator: """ @@ -83,7 +84,7 @@ cdef class RandomGenerator: else: raise ValueError('bits must be 32 or 64') - def random_sample(self, size=None, dtype=np.float64, out=None): + def random_sample(self, size=None, dtype=np.float64): """ random_sample(size=None, dtype='d', out=None) @@ -105,10 +106,6 @@ cdef class RandomGenerator: Desired dtype of the result, either 'd' (or 'float64') or 'f' (or 'float32'). All dtypes are determined by their name. The default value is 'd'. - out : ndarray, optional - Alternative output array in which to place the result. If size is not None, - it must have the same shape as the provided size and must match the type of - the output values. Returns ------- @@ -135,8 +132,49 @@ cdef class RandomGenerator: cdef double temp key = np.dtype(dtype).name if key == 'float64': - return double_fill(&random_double, self._prng, size, self.lock, out) + return double_fill(&random_double, self._prng, size, self.lock) elif key == 'float32': - return float_fill(&random_float, self._prng, size, self.lock, out) + return float_fill(&random_float, self._prng, size, self.lock) else: raise TypeError('Unsupported dtype "%s" for random_sample' % key) + + + def standard_exponential(self, size=None, dtype=np.float64): + """ + standard_exponential(size=None, dtype='d', method='inv', out=None) + + Draw samples from the standard exponential distribution. + + `standard_exponential` is identical to the exponential distribution + with a scale parameter of 1. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + dtype : dtype, optional + Desired dtype of the result, either 'd' (or 'float64') or 'f' + (or 'float32'). All dtypes are determined by their name. The + default value is 'd'. + + Returns + ------- + out : float or ndarray + Drawn samples. + + Examples + -------- + Output a 3x8000 array: + + >>> n = np.random.standard_exponential((3, 8000)) + """ + key = np.dtype(dtype).name + if key == 'float64': + return double_fill(&random_standard_exponential, self._prng, size, self.lock) + elif key == 'float32': + return float_fill_from_double(&random_standard_exponential, self._prng, size, self.lock) + else: + raise TypeError('Unsupported dtype "%s" for standard_exponential' + % key) diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index d645a1512f46..f953e1c02363 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -47,7 +47,6 @@ cdef class SplitMix64: """ cdef splitmix64_state *rng_state cdef prng_t *_prng - cdef prng_t *_prng2 cdef public object _prng_capsule def __init__(self, seed=None): @@ -72,8 +71,6 @@ cdef class SplitMix64: cdef const char *anon_name = "CorePRNG" self._prng_capsule = PyCapsule_New(self._prng, anon_name, NULL) - self._prng2 = PyCapsule_GetPointer(self._prng_capsule, anon_name) - def __random_integer(self): """ diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 41613e045727..f875b3182d0d 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -15,11 +15,12 @@ float random_float(void *void_state) { double random_double(void *void_state) { prng_t *prng_state = (prng_t *)void_state; - prng_uint64 next_uint64 = (prng_uint64)(prng_state->next_uint64); - uint64_t next_value = next_uint64(prng_state->state); - return (next_value >> 11) * (1.0 / 9007199254740992.0); - // + prng_double next_double = (prng_double)prng_state->next_double; + return next_double(prng_state->state); +} - //prng_double next_double = (prng_double)prng_state->next_double; - //return next_double(&prng_state->state); +double random_standard_exponential(void *void_state) { + prng_t *prng_state = (prng_t *)void_state; + prng_double next_double = (prng_double)prng_state->next_double; + return -log(1.0 - next_double(prng_state->state)); } diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index dbe38492cf06..fa37361cdc09 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -14,6 +14,8 @@ typedef int bool; #include #endif +#include + typedef double (*prng_double)(void *st); typedef float (*prng_float)(void *st); typedef uint32_t (*prng_uint32)(void *st); @@ -31,3 +33,5 @@ float random_float(void *void_state); double random_double(void *void_state); uint32_t random_uint32(void *void_state); + +double random_standard_exponential(void *void_state); \ No newline at end of file diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index b6b724f13372..a44412b997d6 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -47,12 +47,15 @@ cdef class Xoroshiro128: Exposes no user-facing API except `get_state` and `set_state`. Designed for use in a `RandomGenerator` object. """ - cdef xoroshiro128_state rng_state - cdef prng_t _prng + cdef xoroshiro128_state *rng_state + cdef prng_t *_prng cdef public object _prng_capsule def __init__(self, seed=None): + self.rng_state = malloc(sizeof(xoroshiro128_state)) + self._prng = malloc(sizeof(prng_t)) + if seed is None: try: state = random_entropy(4) @@ -64,7 +67,7 @@ cdef class Xoroshiro128: self.rng_state.s[0] = int(state[0]) self.rng_state.s[1] = int(state[1]) - self._prng.state = &self.rng_state + self._prng.state = self.rng_state self._prng.next_uint64 = &xoroshiro128_uint64 self._prng.next_uint32 = &xoroshiro128_uint32 self._prng.next_double = &xoroshiro128_double @@ -91,14 +94,14 @@ cdef class Xoroshiro128: Testing only """ if bits == 64: - return xoroshiro128_next64(&self.rng_state) + return xoroshiro128_next64(self.rng_state) elif bits == 32: - return xoroshiro128_next32(&self.rng_state) + return xoroshiro128_next32(self.rng_state) else: raise ValueError('bits must be 32 or 64') def jump(self): - xoroshiro128_jump(&self.rng_state) + xoroshiro128_jump(self.rng_state) @property def state(self): From 9538cde8f8cbb1e9f52634f892ab017a4cc29933 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 1 Mar 2018 08:47:37 +0000 Subject: [PATCH 011/279] BUG: Fix bug in xoroshiro Fix bug which passes reference to state not state --- _randomgen/.gitattributes | 1 + _randomgen/MANIFEST.in | 2 + _randomgen/core_prng/__init__.py | 4 + _randomgen/core_prng/_version.py | 520 +++++++ _randomgen/core_prng/generator.pyx | 4 + _randomgen/core_prng/splitmix64.pyx | 69 +- _randomgen/core_prng/xoroshiro128.pyx | 71 +- _randomgen/setup.cfg | 7 + _randomgen/setup.py | 4 + _randomgen/versioneer.py | 1822 +++++++++++++++++++++++++ 10 files changed, 2467 insertions(+), 37 deletions(-) create mode 100644 _randomgen/.gitattributes create mode 100644 _randomgen/MANIFEST.in create mode 100644 _randomgen/core_prng/_version.py create mode 100644 _randomgen/setup.cfg create mode 100644 _randomgen/versioneer.py diff --git a/_randomgen/.gitattributes b/_randomgen/.gitattributes new file mode 100644 index 000000000000..c5ff9551eda2 --- /dev/null +++ b/_randomgen/.gitattributes @@ -0,0 +1 @@ +core_prng/_version.py export-subst diff --git a/_randomgen/MANIFEST.in b/_randomgen/MANIFEST.in new file mode 100644 index 000000000000..14d24dca926c --- /dev/null +++ b/_randomgen/MANIFEST.in @@ -0,0 +1,2 @@ +include versioneer.py +include core_prng/_version.py diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index d097a9ef158b..539b3fa4d96a 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -3,3 +3,7 @@ from .splitmix64 import SplitMix64 __all__ = ['RandomGenerator', 'SplitMix64', 'Xoroshiro128'] + +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions diff --git a/_randomgen/core_prng/_version.py b/_randomgen/core_prng/_version.py new file mode 100644 index 000000000000..1041669c74ea --- /dev/null +++ b/_randomgen/core_prng/_version.py @@ -0,0 +1,520 @@ + +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by githubs download-from-tag +# feature). Distribution tarballs (built by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.18 (https://github.com/warner/python-versioneer) + +"""Git implementation of _version.py.""" + +import errno +import os +import re +import subprocess +import sys + + +def get_keywords(): + """Get the keywords needed to look up the version information.""" + # these strings will be replaced by git during git-archive. + # setup.py/versioneer.py will grep for the variable names, so they must + # each be defined on a line of their own. _version.py will just call + # get_keywords(). + git_refnames = "$Format:%d$" + git_full = "$Format:%H$" + git_date = "$Format:%ci$" + keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} + return keywords + + +class VersioneerConfig: + """Container for Versioneer configuration parameters.""" + + +def get_config(): + """Create, populate and return the VersioneerConfig() object.""" + # these strings are filled in when 'setup.py versioneer' creates + # _version.py + cfg = VersioneerConfig() + cfg.VCS = "git" + cfg.style = "pep440" + cfg.tag_prefix = "" + cfg.parentdir_prefix = "core_prng-" + cfg.versionfile_source = "core_prng/_version.py" + cfg.verbose = False + return cfg + + +class NotThisMethod(Exception): + """Exception raised if a method is not valid for the current scenario.""" + + +LONG_VERSION_PY = {} +HANDLERS = {} + + +def register_vcs_handler(vcs, method): # decorator + """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): + """Store f in HANDLERS[vcs][method].""" + if vcs not in HANDLERS: + HANDLERS[vcs] = {} + HANDLERS[vcs][method] = f + return f + return decorate + + +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): + """Call the given command(s).""" + assert isinstance(commands, list) + p = None + for c in commands: + try: + dispcmd = str([c] + args) + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) + break + except EnvironmentError: + e = sys.exc_info()[1] + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %s" % dispcmd) + print(e) + return None, None + else: + if verbose: + print("unable to find command, tried %s" % (commands,)) + return None, None + stdout = p.communicate()[0].strip() + if sys.version_info[0] >= 3: + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % dispcmd) + print("stdout was %s" % stdout) + return None, p.returncode + return stdout, p.returncode + + +def versions_from_parentdir(parentdir_prefix, root, verbose): + """Try to determine the version from the parent directory name. + + Source tarballs conventionally unpack into a directory that includes both + the project name and a version string. We will also support searching up + two directory levels for an appropriately named parent directory + """ + rootdirs = [] + + for i in range(3): + dirname = os.path.basename(root) + if dirname.startswith(parentdir_prefix): + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} + else: + rootdirs.append(root) + root = os.path.dirname(root) # up a level + + if verbose: + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) + raise NotThisMethod("rootdir doesn't start with parentdir_prefix") + + +@register_vcs_handler("git", "get_keywords") +def git_get_keywords(versionfile_abs): + """Extract version information from the given file.""" + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords = {} + try: + f = open(versionfile_abs, "r") + for line in f.readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + if line.strip().startswith("git_date ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["date"] = mo.group(1) + f.close() + except EnvironmentError: + pass + return keywords + + +@register_vcs_handler("git", "keywords") +def git_versions_from_keywords(keywords, tag_prefix, verbose): + """Get version information from git keywords.""" + if not keywords: + raise NotThisMethod("no keywords at all, weird") + date = keywords.get("date") + if date is not None: + # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant + # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 + # -like" string, which we must then edit to make compliant), because + # it's been around since git-1.5.3, and it's too difficult to + # discover which version we're using, or to work around using an + # older one. + date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + raise NotThisMethod("unexpanded keywords, not a git-archive tarball") + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = set([r for r in refs if re.search(r'\d', r)]) + if verbose: + print("discarding '%s', no digits" % ",".join(refs - tags)) + if verbose: + print("likely tags: %s" % ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} + # no suitable tags, so version is "0+unknown", but full hex is still there + if verbose: + print("no suitable tags, using unknown + full revision id") + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} + + +@register_vcs_handler("git", "pieces_from_vcs") +def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): + """Get version from 'git describe' in the root of the source tree. + + This only gets called if the git-archive 'subst' keywords were *not* + expanded, and _version.py hasn't already been rewritten with a short + version string, meaning we're inside a checked out source tree. + """ + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) + if rc != 0: + if verbose: + print("Directory %s not under git control" % root) + raise NotThisMethod("'git rev-parse --git-dir' returned error") + + # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] + # if there isn't one, this yields HEX[-dirty] (no NUM) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) + # --long was added in git-1.5.5 + if describe_out is None: + raise NotThisMethod("'git describe' failed") + describe_out = describe_out.strip() + full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if full_out is None: + raise NotThisMethod("'git rev-parse' failed") + full_out = full_out.strip() + + pieces = {} + pieces["long"] = full_out + pieces["short"] = full_out[:7] # maybe improved later + pieces["error"] = None + + # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] + # TAG might have hyphens. + git_describe = describe_out + + # look for -dirty suffix + dirty = git_describe.endswith("-dirty") + pieces["dirty"] = dirty + if dirty: + git_describe = git_describe[:git_describe.rindex("-dirty")] + + # now we have TAG-NUM-gHEX or HEX + + if "-" in git_describe: + # TAG-NUM-gHEX + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + if not mo: + # unparseable. Maybe git-describe is misbehaving? + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) + return pieces + + # tag + full_tag = mo.group(1) + if not full_tag.startswith(tag_prefix): + if verbose: + fmt = "tag '%s' doesn't start with prefix '%s'" + print(fmt % (full_tag, tag_prefix)) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) + return pieces + pieces["closest-tag"] = full_tag[len(tag_prefix):] + + # distance: number of commits since tag + pieces["distance"] = int(mo.group(2)) + + # commit: short hex revision ID + pieces["short"] = mo.group(3) + + else: + # HEX: no tags + pieces["closest-tag"] = None + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) + pieces["distance"] = int(count_out) # total number of commits + + # commit date: see ISO-8601 comment in git_versions_from_keywords() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() + pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + + return pieces + + +def plus_or_dot(pieces): + """Return a + if we don't already have one, else return a .""" + if "+" in pieces.get("closest-tag", ""): + return "." + return "+" + + +def render_pep440(pieces): + """Build up version string, with post-release "local version identifier". + + Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you + get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty + + Exceptions: + 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += plus_or_dot(pieces) + rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def render_pep440_pre(pieces): + """TAG[.post.devDISTANCE] -- No -dirty. + + Exceptions: + 1: no tags. 0.post.devDISTANCE + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += ".post.dev%d" % pieces["distance"] + else: + # exception #1 + rendered = "0.post.dev%d" % pieces["distance"] + return rendered + + +def render_pep440_post(pieces): + """TAG[.postDISTANCE[.dev0]+gHEX] . + + The ".dev0" means dirty. Note that .dev0 sorts backwards + (a dirty tree will appear "older" than the corresponding clean one), + but you shouldn't be releasing software with -dirty anyways. + + Exceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "g%s" % pieces["short"] + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += "+g%s" % pieces["short"] + return rendered + + +def render_pep440_old(pieces): + """TAG[.postDISTANCE[.dev0]] . + + The ".dev0" means dirty. + + Eexceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + return rendered + + +def render_git_describe(pieces): + """TAG[-DISTANCE-gHEX][-dirty]. + + Like 'git describe --tags --dirty --always'. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render_git_describe_long(pieces): + """TAG-DISTANCE-gHEX[-dirty]. + + Like 'git describe --tags --dirty --always -long'. + The distance/hash is unconditional. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render(pieces, style): + """Render the given version pieces into the requested style.""" + if pieces["error"]: + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} + + if not style or style == "default": + style = "pep440" # the default + + if style == "pep440": + rendered = render_pep440(pieces) + elif style == "pep440-pre": + rendered = render_pep440_pre(pieces) + elif style == "pep440-post": + rendered = render_pep440_post(pieces) + elif style == "pep440-old": + rendered = render_pep440_old(pieces) + elif style == "git-describe": + rendered = render_git_describe(pieces) + elif style == "git-describe-long": + rendered = render_git_describe_long(pieces) + else: + raise ValueError("unknown style '%s'" % style) + + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} + + +def get_versions(): + """Get version information or return default if unable to do so.""" + # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have + # __file__, we can work backwards from there to the root. Some + # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which + # case we can only use expanded keywords. + + cfg = get_config() + verbose = cfg.verbose + + try: + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) + except NotThisMethod: + pass + + try: + root = os.path.realpath(__file__) + # versionfile_source is the relative path from the top of the source + # tree (where the .git directory might live) to this file. Invert + # this to find the root from __file__. + for i in cfg.versionfile_source.split('/'): + root = os.path.dirname(root) + except NameError: + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None} + + try: + pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) + return render(pieces, cfg.style) + except NotThisMethod: + pass + + try: + if cfg.parentdir_prefix: + return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) + except NotThisMethod: + pass + + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", "date": None} diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 93f44e86dea6..69aca7a2e83e 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -68,7 +68,11 @@ cdef class RandomGenerator: self.__core_prng.state = value def random_integer(self, bits=64): + #print("In random_integer") if bits==64: + #print("Calling...") + #print(&self.next_uint64) + #print(&self.rng_state) return self.next_uint64(self.rng_state) elif bits==32: return random_uint32(self._prng) # self.next_uint32(self.rng_state) diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index f953e1c02363..43f11fc18775 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -1,6 +1,7 @@ from libc.stdint cimport uint32_t, uint64_t -from cpython.pycapsule cimport PyCapsule_New, PyCapsule_GetPointer -from libc.stdlib cimport malloc +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + import numpy as np cimport numpy as np @@ -52,25 +53,23 @@ cdef class SplitMix64: def __init__(self, seed=None): self.rng_state = malloc(sizeof(splitmix64_state)) self._prng = malloc(sizeof(prng_t)) - if seed is None: - try: - state = random_entropy(2) - except RuntimeError: - state = random_entropy(2, 'fallback') - state = state.view(np.uint64) - else: - state = entropy.seed_by_array(seed, 1) + self.seed(seed) - self.rng_state.state = int(state[0]) + self._prng.state = self.rng_state + self._prng.next_uint64 = &splitmix64_uint64 + self._prng.next_uint32 = &splitmix64_uint32 + self._prng.next_double = &splitmix64_double + + cdef const char *name = "CorePRNG" + self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + + def __dealloc__(self): + free(self.rng_state) + free(self._prng) + + def _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - self._prng.state = self.rng_state - self._prng.next_uint64 = &splitmix64_uint64 - self._prng.next_uint32 = &splitmix64_uint32 - self._prng.next_double = &splitmix64_double - cdef const char *anon_name = "CorePRNG" - self._prng_capsule = PyCapsule_New(self._prng, - anon_name, NULL) def __random_integer(self): """ @@ -87,6 +86,40 @@ cdef class SplitMix64: """ return splitmix64_next64(self.rng_state) + def seed(self, seed=None): + """ + seed(seed=None, stream=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + + """ + ub = 2 ** 64 + if seed is None: + try: + state = random_entropy(2) + except RuntimeError: + state = random_entropy(2, 'fallback') + state = state.view(np.uint64) + else: + state = entropy.seed_by_array(seed, 1) + self.rng_state.state = int(state[0]) + self._reset_state_variables() + + @property def state(self): """Get or set the PRNG state""" diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index a44412b997d6..0b6a0453ff54 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -1,8 +1,10 @@ -import numpy as np -cimport numpy as np from libc.stdint cimport uint32_t, uint64_t -from libc.stdlib cimport malloc +from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New + +import numpy as np +cimport numpy as np + from common cimport * from core_prng.entropy import random_entropy cimport entropy @@ -24,7 +26,7 @@ cdef extern from "src/xoroshiro128/xoroshiro128.h": cdef uint64_t xoroshiro128_next32(xoroshiro128_state *state) nogil cdef void xoroshiro128_jump(xoroshiro128_state *state) -cdef uint64_t xoroshiro128_uint64(void* st) nogil: +cdef uint64_t xoroshiro128_uint64(void* st):# nogil: return xoroshiro128_next64(st) cdef uint64_t xoroshiro128_uint32(void *st) nogil: @@ -51,29 +53,26 @@ cdef class Xoroshiro128: cdef prng_t *_prng cdef public object _prng_capsule - def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoroshiro128_state)) self._prng = malloc(sizeof(prng_t)) - - if seed is None: - try: - state = random_entropy(4) - except RuntimeError: - state = random_entropy(4, 'fallback') - state = state.view(np.uint64) - else: - state = entropy.seed_by_array(seed, 2) - self.rng_state.s[0] = int(state[0]) - self.rng_state.s[1] = int(state[1]) + self.seed(seed) self._prng.state = self.rng_state self._prng.next_uint64 = &xoroshiro128_uint64 self._prng.next_uint32 = &xoroshiro128_uint32 self._prng.next_double = &xoroshiro128_double - cdef const char *anon_name = "CorePRNG" - self._prng_capsule = PyCapsule_New(&self._prng, - anon_name, NULL) + + cdef const char *name = "CorePRNG" + self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + + def __dealloc__(self): + free(self.rng_state) + free(self._prng) + + def _reset_state_variables(self): + self.rng_state.has_uint32 = 0 + self.rng_state.uinteger = 0 def __random_integer(self, bits=64): """ @@ -100,6 +99,40 @@ cdef class Xoroshiro128: else: raise ValueError('bits must be 32 or 64') + def seed(self, seed=None): + """ + seed(seed=None, stream=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + + """ + ub = 2 ** 64 + if seed is None: + try: + state = random_entropy(4) + except RuntimeError: + state = random_entropy(4, 'fallback') + state = state.view(np.uint64) + else: + state = entropy.seed_by_array(seed, 2) + self.rng_state.s[0] = int(state[0]) + self.rng_state.s[1] = int(state[1]) + self._reset_state_variables() + def jump(self): xoroshiro128_jump(self.rng_state) diff --git a/_randomgen/setup.cfg b/_randomgen/setup.cfg new file mode 100644 index 000000000000..d622db893c08 --- /dev/null +++ b/_randomgen/setup.cfg @@ -0,0 +1,7 @@ +[versioneer] +VCS = git +style = pep440 +versionfile_source = core_prng/_version.py +versionfile_build = core_prng/_version.py +tag_prefix = +parentdir_prefix = core_prng- diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 483299a52958..6aa1aefa7979 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -1,6 +1,8 @@ import os from os.path import join +import versioneer + import numpy as np from Cython.Build import cythonize import Cython.Compiler.Options @@ -48,6 +50,8 @@ def is_pure(self): setup( + version=versioneer.get_version(), + cmdclass=versioneer.get_cmdclass(), ext_modules=cythonize(extensions), name='core_prng', packages=find_packages(), diff --git a/_randomgen/versioneer.py b/_randomgen/versioneer.py new file mode 100644 index 000000000000..64fea1c89272 --- /dev/null +++ b/_randomgen/versioneer.py @@ -0,0 +1,1822 @@ + +# Version: 0.18 + +"""The Versioneer - like a rocketeer, but for versions. + +The Versioneer +============== + +* like a rocketeer, but for versions! +* https://github.com/warner/python-versioneer +* Brian Warner +* License: Public Domain +* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy +* [![Latest Version] +(https://pypip.in/version/versioneer/badge.svg?style=flat) +](https://pypi.python.org/pypi/versioneer/) +* [![Build Status] +(https://travis-ci.org/warner/python-versioneer.png?branch=master) +](https://travis-ci.org/warner/python-versioneer) + +This is a tool for managing a recorded version number in distutils-based +python projects. The goal is to remove the tedious and error-prone "update +the embedded version string" step from your release process. Making a new +release should be as easy as recording a new tag in your version-control +system, and maybe making new tarballs. + + +## Quick Install + +* `pip install versioneer` to somewhere to your $PATH +* add a `[versioneer]` section to your setup.cfg (see below) +* run `versioneer install` in your source tree, commit the results + +## Version Identifiers + +Source trees come from a variety of places: + +* a version-control system checkout (mostly used by developers) +* a nightly tarball, produced by build automation +* a snapshot tarball, produced by a web-based VCS browser, like github's + "tarball from tag" feature +* a release tarball, produced by "setup.py sdist", distributed through PyPI + +Within each source tree, the version identifier (either a string or a number, +this tool is format-agnostic) can come from a variety of places: + +* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows + about recent "tags" and an absolute revision-id +* the name of the directory into which the tarball was unpacked +* an expanded VCS keyword ($Id$, etc) +* a `_version.py` created by some earlier build step + +For released software, the version identifier is closely related to a VCS +tag. Some projects use tag names that include more than just the version +string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool +needs to strip the tag prefix to extract the version identifier. For +unreleased software (between tags), the version identifier should provide +enough information to help developers recreate the same tree, while also +giving them an idea of roughly how old the tree is (after version 1.2, before +version 1.3). Many VCS systems can report a description that captures this, +for example `git describe --tags --dirty --always` reports things like +"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the +0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has +uncommitted changes. + +The version identifier is used for multiple purposes: + +* to allow the module to self-identify its version: `myproject.__version__` +* to choose a name and prefix for a 'setup.py sdist' tarball + +## Theory of Operation + +Versioneer works by adding a special `_version.py` file into your source +tree, where your `__init__.py` can import it. This `_version.py` knows how to +dynamically ask the VCS tool for version information at import time. + +`_version.py` also contains `$Revision$` markers, and the installation +process marks `_version.py` to have this marker rewritten with a tag name +during the `git archive` command. As a result, generated tarballs will +contain enough information to get the proper version. + +To allow `setup.py` to compute a version too, a `versioneer.py` is added to +the top level of your source tree, next to `setup.py` and the `setup.cfg` +that configures it. This overrides several distutils/setuptools commands to +compute the version when invoked, and changes `setup.py build` and `setup.py +sdist` to replace `_version.py` with a small static file that contains just +the generated version data. + +## Installation + +See [INSTALL.md](./INSTALL.md) for detailed installation instructions. + +## Version-String Flavors + +Code which uses Versioneer can learn about its version string at runtime by +importing `_version` from your main `__init__.py` file and running the +`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can +import the top-level `versioneer.py` and run `get_versions()`. + +Both functions return a dictionary with different flavors of version +information: + +* `['version']`: A condensed version string, rendered using the selected + style. This is the most commonly used value for the project's version + string. The default "pep440" style yields strings like `0.11`, + `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section + below for alternative styles. + +* `['full-revisionid']`: detailed revision identifier. For Git, this is the + full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". + +* `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the + commit date in ISO 8601 format. This will be None if the date is not + available. + +* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that + this is only accurate if run in a VCS checkout, otherwise it is likely to + be False or None + +* `['error']`: if the version string could not be computed, this will be set + to a string describing the problem, otherwise it will be None. It may be + useful to throw an exception in setup.py if this is set, to avoid e.g. + creating tarballs with a version string of "unknown". + +Some variants are more useful than others. Including `full-revisionid` in a +bug report should allow developers to reconstruct the exact code being tested +(or indicate the presence of local changes that should be shared with the +developers). `version` is suitable for display in an "about" box or a CLI +`--version` output: it can be easily compared against release notes and lists +of bugs fixed in various releases. + +The installer adds the following text to your `__init__.py` to place a basic +version in `YOURPROJECT.__version__`: + + from ._version import get_versions + __version__ = get_versions()['version'] + del get_versions + +## Styles + +The setup.cfg `style=` configuration controls how the VCS information is +rendered into a version string. + +The default style, "pep440", produces a PEP440-compliant string, equal to the +un-prefixed tag name for actual releases, and containing an additional "local +version" section with more detail for in-between builds. For Git, this is +TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags +--dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the +tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and +that this commit is two revisions ("+2") beyond the "0.11" tag. For released +software (exactly equal to a known tag), the identifier will only contain the +stripped tag, e.g. "0.11". + +Other styles are available. See [details.md](details.md) in the Versioneer +source tree for descriptions. + +## Debugging + +Versioneer tries to avoid fatal errors: if something goes wrong, it will tend +to return a version of "0+unknown". To investigate the problem, run `setup.py +version`, which will run the version-lookup code in a verbose mode, and will +display the full contents of `get_versions()` (including the `error` string, +which may help identify what went wrong). + +## Known Limitations + +Some situations are known to cause problems for Versioneer. This details the +most significant ones. More can be found on Github +[issues page](https://github.com/warner/python-versioneer/issues). + +### Subprojects + +Versioneer has limited support for source trees in which `setup.py` is not in +the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are +two common reasons why `setup.py` might not be in the root: + +* Source trees which contain multiple subprojects, such as + [Buildbot](https://github.com/buildbot/buildbot), which contains both + "master" and "slave" subprojects, each with their own `setup.py`, + `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI + distributions (and upload multiple independently-installable tarballs). +* Source trees whose main purpose is to contain a C library, but which also + provide bindings to Python (and perhaps other langauges) in subdirectories. + +Versioneer will look for `.git` in parent directories, and most operations +should get the right version string. However `pip` and `setuptools` have bugs +and implementation details which frequently cause `pip install .` from a +subproject directory to fail to find a correct version string (so it usually +defaults to `0+unknown`). + +`pip install --editable .` should work correctly. `setup.py install` might +work too. + +Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in +some later version. + +[Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking +this issue. The discussion in +[PR #61](https://github.com/warner/python-versioneer/pull/61) describes the +issue from the Versioneer side in more detail. +[pip PR#3176](https://github.com/pypa/pip/pull/3176) and +[pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve +pip to let Versioneer work correctly. + +Versioneer-0.16 and earlier only looked for a `.git` directory next to the +`setup.cfg`, so subprojects were completely unsupported with those releases. + +### Editable installs with setuptools <= 18.5 + +`setup.py develop` and `pip install --editable .` allow you to install a +project into a virtualenv once, then continue editing the source code (and +test) without re-installing after every change. + +"Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a +convenient way to specify executable scripts that should be installed along +with the python package. + +These both work as expected when using modern setuptools. When using +setuptools-18.5 or earlier, however, certain operations will cause +`pkg_resources.DistributionNotFound` errors when running the entrypoint +script, which must be resolved by re-installing the package. This happens +when the install happens with one version, then the egg_info data is +regenerated while a different version is checked out. Many setup.py commands +cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into +a different virtualenv), so this can be surprising. + +[Bug #83](https://github.com/warner/python-versioneer/issues/83) describes +this one, but upgrading to a newer version of setuptools should probably +resolve it. + +### Unicode version strings + +While Versioneer works (and is continually tested) with both Python 2 and +Python 3, it is not entirely consistent with bytes-vs-unicode distinctions. +Newer releases probably generate unicode version strings on py2. It's not +clear that this is wrong, but it may be surprising for applications when then +write these strings to a network connection or include them in bytes-oriented +APIs like cryptographic checksums. + +[Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates +this question. + + +## Updating Versioneer + +To upgrade your project to a new release of Versioneer, do the following: + +* install the new Versioneer (`pip install -U versioneer` or equivalent) +* edit `setup.cfg`, if necessary, to include any new configuration settings + indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. +* re-run `versioneer install` in your source tree, to replace + `SRC/_version.py` +* commit any changed files + +## Future Directions + +This tool is designed to make it easily extended to other version-control +systems: all VCS-specific components are in separate directories like +src/git/ . The top-level `versioneer.py` script is assembled from these +components by running make-versioneer.py . In the future, make-versioneer.py +will take a VCS name as an argument, and will construct a version of +`versioneer.py` that is specific to the given VCS. It might also take the +configuration arguments that are currently provided manually during +installation by editing setup.py . Alternatively, it might go the other +direction and include code from all supported VCS systems, reducing the +number of intermediate scripts. + + +## License + +To make Versioneer easier to embed, all its code is dedicated to the public +domain. The `_version.py` that it creates is also in the public domain. +Specifically, both are released under the Creative Commons "Public Domain +Dedication" license (CC0-1.0), as described in +https://creativecommons.org/publicdomain/zero/1.0/ . + +""" + +from __future__ import print_function +try: + import configparser +except ImportError: + import ConfigParser as configparser +import errno +import json +import os +import re +import subprocess +import sys + + +class VersioneerConfig: + """Container for Versioneer configuration parameters.""" + + +def get_root(): + """Get the project root directory. + + We require that all commands are run from the project root, i.e. the + directory that contains setup.py, setup.cfg, and versioneer.py . + """ + root = os.path.realpath(os.path.abspath(os.getcwd())) + setup_py = os.path.join(root, "setup.py") + versioneer_py = os.path.join(root, "versioneer.py") + if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): + # allow 'python path/to/setup.py COMMAND' + root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) + setup_py = os.path.join(root, "setup.py") + versioneer_py = os.path.join(root, "versioneer.py") + if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): + err = ("Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND').") + raise VersioneerBadRootError(err) + try: + # Certain runtime workflows (setup.py install/develop in a setuptools + # tree) execute all dependencies in a single python process, so + # "versioneer" may be imported multiple times, and python's shared + # module-import table will cache the first one. So we can't use + # os.path.dirname(__file__), as that will find whichever + # versioneer.py was first imported, even in later projects. + me = os.path.realpath(os.path.abspath(__file__)) + me_dir = os.path.normcase(os.path.splitext(me)[0]) + vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) + if me_dir != vsr_dir: + print("Warning: build in %s is using versioneer.py from %s" + % (os.path.dirname(me), versioneer_py)) + except NameError: + pass + return root + + +def get_config_from_root(root): + """Read the project setup.cfg file to determine Versioneer config.""" + # This might raise EnvironmentError (if setup.cfg is missing), or + # configparser.NoSectionError (if it lacks a [versioneer] section), or + # configparser.NoOptionError (if it lacks "VCS="). See the docstring at + # the top of versioneer.py for instructions on writing your setup.cfg . + setup_cfg = os.path.join(root, "setup.cfg") + parser = configparser.SafeConfigParser() + with open(setup_cfg, "r") as f: + parser.readfp(f) + VCS = parser.get("versioneer", "VCS") # mandatory + + def get(parser, name): + if parser.has_option("versioneer", name): + return parser.get("versioneer", name) + return None + cfg = VersioneerConfig() + cfg.VCS = VCS + cfg.style = get(parser, "style") or "" + cfg.versionfile_source = get(parser, "versionfile_source") + cfg.versionfile_build = get(parser, "versionfile_build") + cfg.tag_prefix = get(parser, "tag_prefix") + if cfg.tag_prefix in ("''", '""'): + cfg.tag_prefix = "" + cfg.parentdir_prefix = get(parser, "parentdir_prefix") + cfg.verbose = get(parser, "verbose") + return cfg + + +class NotThisMethod(Exception): + """Exception raised if a method is not valid for the current scenario.""" + + +# these dictionaries contain VCS-specific tools +LONG_VERSION_PY = {} +HANDLERS = {} + + +def register_vcs_handler(vcs, method): # decorator + """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): + """Store f in HANDLERS[vcs][method].""" + if vcs not in HANDLERS: + HANDLERS[vcs] = {} + HANDLERS[vcs][method] = f + return f + return decorate + + +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): + """Call the given command(s).""" + assert isinstance(commands, list) + p = None + for c in commands: + try: + dispcmd = str([c] + args) + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) + break + except EnvironmentError: + e = sys.exc_info()[1] + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %s" % dispcmd) + print(e) + return None, None + else: + if verbose: + print("unable to find command, tried %s" % (commands,)) + return None, None + stdout = p.communicate()[0].strip() + if sys.version_info[0] >= 3: + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % dispcmd) + print("stdout was %s" % stdout) + return None, p.returncode + return stdout, p.returncode + + +LONG_VERSION_PY['git'] = ''' +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by githubs download-from-tag +# feature). Distribution tarballs (built by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.18 (https://github.com/warner/python-versioneer) + +"""Git implementation of _version.py.""" + +import errno +import os +import re +import subprocess +import sys + + +def get_keywords(): + """Get the keywords needed to look up the version information.""" + # these strings will be replaced by git during git-archive. + # setup.py/versioneer.py will grep for the variable names, so they must + # each be defined on a line of their own. _version.py will just call + # get_keywords(). + git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" + git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" + git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" + keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} + return keywords + + +class VersioneerConfig: + """Container for Versioneer configuration parameters.""" + + +def get_config(): + """Create, populate and return the VersioneerConfig() object.""" + # these strings are filled in when 'setup.py versioneer' creates + # _version.py + cfg = VersioneerConfig() + cfg.VCS = "git" + cfg.style = "%(STYLE)s" + cfg.tag_prefix = "%(TAG_PREFIX)s" + cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" + cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" + cfg.verbose = False + return cfg + + +class NotThisMethod(Exception): + """Exception raised if a method is not valid for the current scenario.""" + + +LONG_VERSION_PY = {} +HANDLERS = {} + + +def register_vcs_handler(vcs, method): # decorator + """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): + """Store f in HANDLERS[vcs][method].""" + if vcs not in HANDLERS: + HANDLERS[vcs] = {} + HANDLERS[vcs][method] = f + return f + return decorate + + +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): + """Call the given command(s).""" + assert isinstance(commands, list) + p = None + for c in commands: + try: + dispcmd = str([c] + args) + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) + break + except EnvironmentError: + e = sys.exc_info()[1] + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %%s" %% dispcmd) + print(e) + return None, None + else: + if verbose: + print("unable to find command, tried %%s" %% (commands,)) + return None, None + stdout = p.communicate()[0].strip() + if sys.version_info[0] >= 3: + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %%s (error)" %% dispcmd) + print("stdout was %%s" %% stdout) + return None, p.returncode + return stdout, p.returncode + + +def versions_from_parentdir(parentdir_prefix, root, verbose): + """Try to determine the version from the parent directory name. + + Source tarballs conventionally unpack into a directory that includes both + the project name and a version string. We will also support searching up + two directory levels for an appropriately named parent directory + """ + rootdirs = [] + + for i in range(3): + dirname = os.path.basename(root) + if dirname.startswith(parentdir_prefix): + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} + else: + rootdirs.append(root) + root = os.path.dirname(root) # up a level + + if verbose: + print("Tried directories %%s but none started with prefix %%s" %% + (str(rootdirs), parentdir_prefix)) + raise NotThisMethod("rootdir doesn't start with parentdir_prefix") + + +@register_vcs_handler("git", "get_keywords") +def git_get_keywords(versionfile_abs): + """Extract version information from the given file.""" + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords = {} + try: + f = open(versionfile_abs, "r") + for line in f.readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + if line.strip().startswith("git_date ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["date"] = mo.group(1) + f.close() + except EnvironmentError: + pass + return keywords + + +@register_vcs_handler("git", "keywords") +def git_versions_from_keywords(keywords, tag_prefix, verbose): + """Get version information from git keywords.""" + if not keywords: + raise NotThisMethod("no keywords at all, weird") + date = keywords.get("date") + if date is not None: + # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant + # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 + # -like" string, which we must then edit to make compliant), because + # it's been around since git-1.5.3, and it's too difficult to + # discover which version we're using, or to work around using an + # older one. + date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + raise NotThisMethod("unexpanded keywords, not a git-archive tarball") + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %%d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = set([r for r in refs if re.search(r'\d', r)]) + if verbose: + print("discarding '%%s', no digits" %% ",".join(refs - tags)) + if verbose: + print("likely tags: %%s" %% ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %%s" %% r) + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} + # no suitable tags, so version is "0+unknown", but full hex is still there + if verbose: + print("no suitable tags, using unknown + full revision id") + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} + + +@register_vcs_handler("git", "pieces_from_vcs") +def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): + """Get version from 'git describe' in the root of the source tree. + + This only gets called if the git-archive 'subst' keywords were *not* + expanded, and _version.py hasn't already been rewritten with a short + version string, meaning we're inside a checked out source tree. + """ + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) + if rc != 0: + if verbose: + print("Directory %%s not under git control" %% root) + raise NotThisMethod("'git rev-parse --git-dir' returned error") + + # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] + # if there isn't one, this yields HEX[-dirty] (no NUM) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%%s*" %% tag_prefix], + cwd=root) + # --long was added in git-1.5.5 + if describe_out is None: + raise NotThisMethod("'git describe' failed") + describe_out = describe_out.strip() + full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if full_out is None: + raise NotThisMethod("'git rev-parse' failed") + full_out = full_out.strip() + + pieces = {} + pieces["long"] = full_out + pieces["short"] = full_out[:7] # maybe improved later + pieces["error"] = None + + # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] + # TAG might have hyphens. + git_describe = describe_out + + # look for -dirty suffix + dirty = git_describe.endswith("-dirty") + pieces["dirty"] = dirty + if dirty: + git_describe = git_describe[:git_describe.rindex("-dirty")] + + # now we have TAG-NUM-gHEX or HEX + + if "-" in git_describe: + # TAG-NUM-gHEX + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + if not mo: + # unparseable. Maybe git-describe is misbehaving? + pieces["error"] = ("unable to parse git-describe output: '%%s'" + %% describe_out) + return pieces + + # tag + full_tag = mo.group(1) + if not full_tag.startswith(tag_prefix): + if verbose: + fmt = "tag '%%s' doesn't start with prefix '%%s'" + print(fmt %% (full_tag, tag_prefix)) + pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" + %% (full_tag, tag_prefix)) + return pieces + pieces["closest-tag"] = full_tag[len(tag_prefix):] + + # distance: number of commits since tag + pieces["distance"] = int(mo.group(2)) + + # commit: short hex revision ID + pieces["short"] = mo.group(3) + + else: + # HEX: no tags + pieces["closest-tag"] = None + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) + pieces["distance"] = int(count_out) # total number of commits + + # commit date: see ISO-8601 comment in git_versions_from_keywords() + date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"], + cwd=root)[0].strip() + pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + + return pieces + + +def plus_or_dot(pieces): + """Return a + if we don't already have one, else return a .""" + if "+" in pieces.get("closest-tag", ""): + return "." + return "+" + + +def render_pep440(pieces): + """Build up version string, with post-release "local version identifier". + + Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you + get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty + + Exceptions: + 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += plus_or_dot(pieces) + rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], + pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def render_pep440_pre(pieces): + """TAG[.post.devDISTANCE] -- No -dirty. + + Exceptions: + 1: no tags. 0.post.devDISTANCE + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += ".post.dev%%d" %% pieces["distance"] + else: + # exception #1 + rendered = "0.post.dev%%d" %% pieces["distance"] + return rendered + + +def render_pep440_post(pieces): + """TAG[.postDISTANCE[.dev0]+gHEX] . + + The ".dev0" means dirty. Note that .dev0 sorts backwards + (a dirty tree will appear "older" than the corresponding clean one), + but you shouldn't be releasing software with -dirty anyways. + + Exceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%%d" %% pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "g%%s" %% pieces["short"] + else: + # exception #1 + rendered = "0.post%%d" %% pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += "+g%%s" %% pieces["short"] + return rendered + + +def render_pep440_old(pieces): + """TAG[.postDISTANCE[.dev0]] . + + The ".dev0" means dirty. + + Eexceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%%d" %% pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + else: + # exception #1 + rendered = "0.post%%d" %% pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + return rendered + + +def render_git_describe(pieces): + """TAG[-DISTANCE-gHEX][-dirty]. + + Like 'git describe --tags --dirty --always'. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render_git_describe_long(pieces): + """TAG-DISTANCE-gHEX[-dirty]. + + Like 'git describe --tags --dirty --always -long'. + The distance/hash is unconditional. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render(pieces, style): + """Render the given version pieces into the requested style.""" + if pieces["error"]: + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} + + if not style or style == "default": + style = "pep440" # the default + + if style == "pep440": + rendered = render_pep440(pieces) + elif style == "pep440-pre": + rendered = render_pep440_pre(pieces) + elif style == "pep440-post": + rendered = render_pep440_post(pieces) + elif style == "pep440-old": + rendered = render_pep440_old(pieces) + elif style == "git-describe": + rendered = render_git_describe(pieces) + elif style == "git-describe-long": + rendered = render_git_describe_long(pieces) + else: + raise ValueError("unknown style '%%s'" %% style) + + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} + + +def get_versions(): + """Get version information or return default if unable to do so.""" + # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have + # __file__, we can work backwards from there to the root. Some + # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which + # case we can only use expanded keywords. + + cfg = get_config() + verbose = cfg.verbose + + try: + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) + except NotThisMethod: + pass + + try: + root = os.path.realpath(__file__) + # versionfile_source is the relative path from the top of the source + # tree (where the .git directory might live) to this file. Invert + # this to find the root from __file__. + for i in cfg.versionfile_source.split('/'): + root = os.path.dirname(root) + except NameError: + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None} + + try: + pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) + return render(pieces, cfg.style) + except NotThisMethod: + pass + + try: + if cfg.parentdir_prefix: + return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) + except NotThisMethod: + pass + + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", "date": None} +''' + + +@register_vcs_handler("git", "get_keywords") +def git_get_keywords(versionfile_abs): + """Extract version information from the given file.""" + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords = {} + try: + f = open(versionfile_abs, "r") + for line in f.readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + if line.strip().startswith("git_date ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["date"] = mo.group(1) + f.close() + except EnvironmentError: + pass + return keywords + + +@register_vcs_handler("git", "keywords") +def git_versions_from_keywords(keywords, tag_prefix, verbose): + """Get version information from git keywords.""" + if not keywords: + raise NotThisMethod("no keywords at all, weird") + date = keywords.get("date") + if date is not None: + # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant + # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 + # -like" string, which we must then edit to make compliant), because + # it's been around since git-1.5.3, and it's too difficult to + # discover which version we're using, or to work around using an + # older one. + date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + raise NotThisMethod("unexpanded keywords, not a git-archive tarball") + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = set([r for r in refs if re.search(r'\d', r)]) + if verbose: + print("discarding '%s', no digits" % ",".join(refs - tags)) + if verbose: + print("likely tags: %s" % ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} + # no suitable tags, so version is "0+unknown", but full hex is still there + if verbose: + print("no suitable tags, using unknown + full revision id") + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} + + +@register_vcs_handler("git", "pieces_from_vcs") +def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): + """Get version from 'git describe' in the root of the source tree. + + This only gets called if the git-archive 'subst' keywords were *not* + expanded, and _version.py hasn't already been rewritten with a short + version string, meaning we're inside a checked out source tree. + """ + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) + if rc != 0: + if verbose: + print("Directory %s not under git control" % root) + raise NotThisMethod("'git rev-parse --git-dir' returned error") + + # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] + # if there isn't one, this yields HEX[-dirty] (no NUM) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) + # --long was added in git-1.5.5 + if describe_out is None: + raise NotThisMethod("'git describe' failed") + describe_out = describe_out.strip() + full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if full_out is None: + raise NotThisMethod("'git rev-parse' failed") + full_out = full_out.strip() + + pieces = {} + pieces["long"] = full_out + pieces["short"] = full_out[:7] # maybe improved later + pieces["error"] = None + + # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] + # TAG might have hyphens. + git_describe = describe_out + + # look for -dirty suffix + dirty = git_describe.endswith("-dirty") + pieces["dirty"] = dirty + if dirty: + git_describe = git_describe[:git_describe.rindex("-dirty")] + + # now we have TAG-NUM-gHEX or HEX + + if "-" in git_describe: + # TAG-NUM-gHEX + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + if not mo: + # unparseable. Maybe git-describe is misbehaving? + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) + return pieces + + # tag + full_tag = mo.group(1) + if not full_tag.startswith(tag_prefix): + if verbose: + fmt = "tag '%s' doesn't start with prefix '%s'" + print(fmt % (full_tag, tag_prefix)) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) + return pieces + pieces["closest-tag"] = full_tag[len(tag_prefix):] + + # distance: number of commits since tag + pieces["distance"] = int(mo.group(2)) + + # commit: short hex revision ID + pieces["short"] = mo.group(3) + + else: + # HEX: no tags + pieces["closest-tag"] = None + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) + pieces["distance"] = int(count_out) # total number of commits + + # commit date: see ISO-8601 comment in git_versions_from_keywords() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() + pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + + return pieces + + +def do_vcs_install(manifest_in, versionfile_source, ipy): + """Git-specific installation logic for Versioneer. + + For Git, this means creating/changing .gitattributes to mark _version.py + for export-subst keyword substitution. + """ + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + files = [manifest_in, versionfile_source] + if ipy: + files.append(ipy) + try: + me = __file__ + if me.endswith(".pyc") or me.endswith(".pyo"): + me = os.path.splitext(me)[0] + ".py" + versioneer_file = os.path.relpath(me) + except NameError: + versioneer_file = "versioneer.py" + files.append(versioneer_file) + present = False + try: + f = open(".gitattributes", "r") + for line in f.readlines(): + if line.strip().startswith(versionfile_source): + if "export-subst" in line.strip().split()[1:]: + present = True + f.close() + except EnvironmentError: + pass + if not present: + f = open(".gitattributes", "a+") + f.write("%s export-subst\n" % versionfile_source) + f.close() + files.append(".gitattributes") + run_command(GITS, ["add", "--"] + files) + + +def versions_from_parentdir(parentdir_prefix, root, verbose): + """Try to determine the version from the parent directory name. + + Source tarballs conventionally unpack into a directory that includes both + the project name and a version string. We will also support searching up + two directory levels for an appropriately named parent directory + """ + rootdirs = [] + + for i in range(3): + dirname = os.path.basename(root) + if dirname.startswith(parentdir_prefix): + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} + else: + rootdirs.append(root) + root = os.path.dirname(root) # up a level + + if verbose: + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) + raise NotThisMethod("rootdir doesn't start with parentdir_prefix") + + +SHORT_VERSION_PY = """ +# This file was generated by 'versioneer.py' (0.18) from +# revision-control system data, or from the parent directory name of an +# unpacked source archive. Distribution tarballs contain a pre-generated copy +# of this file. + +import json + +version_json = ''' +%s +''' # END VERSION_JSON + + +def get_versions(): + return json.loads(version_json) +""" + + +def versions_from_file(filename): + """Try to determine the version from _version.py if present.""" + try: + with open(filename) as f: + contents = f.read() + except EnvironmentError: + raise NotThisMethod("unable to read _version.py") + mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) + if not mo: + mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) + if not mo: + raise NotThisMethod("no version_json in _version.py") + return json.loads(mo.group(1)) + + +def write_to_version_file(filename, versions): + """Write the given version number to the given _version.py file.""" + os.unlink(filename) + contents = json.dumps(versions, sort_keys=True, + indent=1, separators=(",", ": ")) + with open(filename, "w") as f: + f.write(SHORT_VERSION_PY % contents) + + print("set %s to '%s'" % (filename, versions["version"])) + + +def plus_or_dot(pieces): + """Return a + if we don't already have one, else return a .""" + if "+" in pieces.get("closest-tag", ""): + return "." + return "+" + + +def render_pep440(pieces): + """Build up version string, with post-release "local version identifier". + + Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you + get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty + + Exceptions: + 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += plus_or_dot(pieces) + rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def render_pep440_pre(pieces): + """TAG[.post.devDISTANCE] -- No -dirty. + + Exceptions: + 1: no tags. 0.post.devDISTANCE + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += ".post.dev%d" % pieces["distance"] + else: + # exception #1 + rendered = "0.post.dev%d" % pieces["distance"] + return rendered + + +def render_pep440_post(pieces): + """TAG[.postDISTANCE[.dev0]+gHEX] . + + The ".dev0" means dirty. Note that .dev0 sorts backwards + (a dirty tree will appear "older" than the corresponding clean one), + but you shouldn't be releasing software with -dirty anyways. + + Exceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "g%s" % pieces["short"] + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += "+g%s" % pieces["short"] + return rendered + + +def render_pep440_old(pieces): + """TAG[.postDISTANCE[.dev0]] . + + The ".dev0" means dirty. + + Eexceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + return rendered + + +def render_git_describe(pieces): + """TAG[-DISTANCE-gHEX][-dirty]. + + Like 'git describe --tags --dirty --always'. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render_git_describe_long(pieces): + """TAG-DISTANCE-gHEX[-dirty]. + + Like 'git describe --tags --dirty --always -long'. + The distance/hash is unconditional. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render(pieces, style): + """Render the given version pieces into the requested style.""" + if pieces["error"]: + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} + + if not style or style == "default": + style = "pep440" # the default + + if style == "pep440": + rendered = render_pep440(pieces) + elif style == "pep440-pre": + rendered = render_pep440_pre(pieces) + elif style == "pep440-post": + rendered = render_pep440_post(pieces) + elif style == "pep440-old": + rendered = render_pep440_old(pieces) + elif style == "git-describe": + rendered = render_git_describe(pieces) + elif style == "git-describe-long": + rendered = render_git_describe_long(pieces) + else: + raise ValueError("unknown style '%s'" % style) + + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} + + +class VersioneerBadRootError(Exception): + """The project root directory is unknown or missing key files.""" + + +def get_versions(verbose=False): + """Get the project version from whatever source is available. + + Returns dict with two keys: 'version' and 'full'. + """ + if "versioneer" in sys.modules: + # see the discussion in cmdclass.py:get_cmdclass() + del sys.modules["versioneer"] + + root = get_root() + cfg = get_config_from_root(root) + + assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" + handlers = HANDLERS.get(cfg.VCS) + assert handlers, "unrecognized VCS '%s'" % cfg.VCS + verbose = verbose or cfg.verbose + assert cfg.versionfile_source is not None, \ + "please set versioneer.versionfile_source" + assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" + + versionfile_abs = os.path.join(root, cfg.versionfile_source) + + # extract version from first of: _version.py, VCS command (e.g. 'git + # describe'), parentdir. This is meant to work for developers using a + # source checkout, for users of a tarball created by 'setup.py sdist', + # and for users of a tarball/zipball created by 'git archive' or github's + # download-from-tag feature or the equivalent in other VCSes. + + get_keywords_f = handlers.get("get_keywords") + from_keywords_f = handlers.get("keywords") + if get_keywords_f and from_keywords_f: + try: + keywords = get_keywords_f(versionfile_abs) + ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) + if verbose: + print("got version from expanded keyword %s" % ver) + return ver + except NotThisMethod: + pass + + try: + ver = versions_from_file(versionfile_abs) + if verbose: + print("got version from file %s %s" % (versionfile_abs, ver)) + return ver + except NotThisMethod: + pass + + from_vcs_f = handlers.get("pieces_from_vcs") + if from_vcs_f: + try: + pieces = from_vcs_f(cfg.tag_prefix, root, verbose) + ver = render(pieces, cfg.style) + if verbose: + print("got version from VCS %s" % ver) + return ver + except NotThisMethod: + pass + + try: + if cfg.parentdir_prefix: + ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) + if verbose: + print("got version from parentdir %s" % ver) + return ver + except NotThisMethod: + pass + + if verbose: + print("unable to compute version") + + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, "error": "unable to compute version", + "date": None} + + +def get_version(): + """Get the short version string for this project.""" + return get_versions()["version"] + + +def get_cmdclass(): + """Get the custom setuptools/distutils subclasses used by Versioneer.""" + if "versioneer" in sys.modules: + del sys.modules["versioneer"] + # this fixes the "python setup.py develop" case (also 'install' and + # 'easy_install .'), in which subdependencies of the main project are + # built (using setup.py bdist_egg) in the same python process. Assume + # a main project A and a dependency B, which use different versions + # of Versioneer. A's setup.py imports A's Versioneer, leaving it in + # sys.modules by the time B's setup.py is executed, causing B to run + # with the wrong versioneer. Setuptools wraps the sub-dep builds in a + # sandbox that restores sys.modules to it's pre-build state, so the + # parent is protected against the child's "import versioneer". By + # removing ourselves from sys.modules here, before the child build + # happens, we protect the child from the parent's versioneer too. + # Also see https://github.com/warner/python-versioneer/issues/52 + + cmds = {} + + # we add "version" to both distutils and setuptools + from distutils.core import Command + + class cmd_version(Command): + description = "report generated version string" + user_options = [] + boolean_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + vers = get_versions(verbose=True) + print("Version: %s" % vers["version"]) + print(" full-revisionid: %s" % vers.get("full-revisionid")) + print(" dirty: %s" % vers.get("dirty")) + print(" date: %s" % vers.get("date")) + if vers["error"]: + print(" error: %s" % vers["error"]) + cmds["version"] = cmd_version + + # we override "build_py" in both distutils and setuptools + # + # most invocation pathways end up running build_py: + # distutils/build -> build_py + # distutils/install -> distutils/build ->.. + # setuptools/bdist_wheel -> distutils/install ->.. + # setuptools/bdist_egg -> distutils/install_lib -> build_py + # setuptools/install -> bdist_egg ->.. + # setuptools/develop -> ? + # pip install: + # copies source tree to a tempdir before running egg_info/etc + # if .git isn't copied too, 'git describe' will fail + # then does setup.py bdist_wheel, or sometimes setup.py install + # setup.py egg_info -> ? + + # we override different "build_py" commands for both environments + if "setuptools" in sys.modules: + from setuptools.command.build_py import build_py as _build_py + else: + from distutils.command.build_py import build_py as _build_py + + class cmd_build_py(_build_py): + def run(self): + root = get_root() + cfg = get_config_from_root(root) + versions = get_versions() + _build_py.run(self) + # now locate _version.py in the new build/ directory and replace + # it with an updated value + if cfg.versionfile_build: + target_versionfile = os.path.join(self.build_lib, + cfg.versionfile_build) + print("UPDATING %s" % target_versionfile) + write_to_version_file(target_versionfile, versions) + cmds["build_py"] = cmd_build_py + + if "cx_Freeze" in sys.modules: # cx_freeze enabled? + from cx_Freeze.dist import build_exe as _build_exe + # nczeczulin reports that py2exe won't like the pep440-style string + # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. + # setup(console=[{ + # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION + # "product_version": versioneer.get_version(), + # ... + + class cmd_build_exe(_build_exe): + def run(self): + root = get_root() + cfg = get_config_from_root(root) + versions = get_versions() + target_versionfile = cfg.versionfile_source + print("UPDATING %s" % target_versionfile) + write_to_version_file(target_versionfile, versions) + + _build_exe.run(self) + os.unlink(target_versionfile) + with open(cfg.versionfile_source, "w") as f: + LONG = LONG_VERSION_PY[cfg.VCS] + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + cmds["build_exe"] = cmd_build_exe + del cmds["build_py"] + + if 'py2exe' in sys.modules: # py2exe enabled? + try: + from py2exe.distutils_buildexe import py2exe as _py2exe # py3 + except ImportError: + from py2exe.build_exe import py2exe as _py2exe # py2 + + class cmd_py2exe(_py2exe): + def run(self): + root = get_root() + cfg = get_config_from_root(root) + versions = get_versions() + target_versionfile = cfg.versionfile_source + print("UPDATING %s" % target_versionfile) + write_to_version_file(target_versionfile, versions) + + _py2exe.run(self) + os.unlink(target_versionfile) + with open(cfg.versionfile_source, "w") as f: + LONG = LONG_VERSION_PY[cfg.VCS] + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + cmds["py2exe"] = cmd_py2exe + + # we override different "sdist" commands for both environments + if "setuptools" in sys.modules: + from setuptools.command.sdist import sdist as _sdist + else: + from distutils.command.sdist import sdist as _sdist + + class cmd_sdist(_sdist): + def run(self): + versions = get_versions() + self._versioneer_generated_versions = versions + # unless we update this, the command will keep using the old + # version + self.distribution.metadata.version = versions["version"] + return _sdist.run(self) + + def make_release_tree(self, base_dir, files): + root = get_root() + cfg = get_config_from_root(root) + _sdist.make_release_tree(self, base_dir, files) + # now locate _version.py in the new base_dir directory + # (remembering that it may be a hardlink) and replace it with an + # updated value + target_versionfile = os.path.join(base_dir, cfg.versionfile_source) + print("UPDATING %s" % target_versionfile) + write_to_version_file(target_versionfile, + self._versioneer_generated_versions) + cmds["sdist"] = cmd_sdist + + return cmds + + +CONFIG_ERROR = """ +setup.cfg is missing the necessary Versioneer configuration. You need +a section like: + + [versioneer] + VCS = git + style = pep440 + versionfile_source = src/myproject/_version.py + versionfile_build = myproject/_version.py + tag_prefix = + parentdir_prefix = myproject- + +You will also need to edit your setup.py to use the results: + + import versioneer + setup(version=versioneer.get_version(), + cmdclass=versioneer.get_cmdclass(), ...) + +Please read the docstring in ./versioneer.py for configuration instructions, +edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. +""" + +SAMPLE_CONFIG = """ +# See the docstring in versioneer.py for instructions. Note that you must +# re-run 'versioneer.py setup' after changing this section, and commit the +# resulting files. + +[versioneer] +#VCS = git +#style = pep440 +#versionfile_source = +#versionfile_build = +#tag_prefix = +#parentdir_prefix = + +""" + +INIT_PY_SNIPPET = """ +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions +""" + + +def do_setup(): + """Main VCS-independent setup function for installing Versioneer.""" + root = get_root() + try: + cfg = get_config_from_root(root) + except (EnvironmentError, configparser.NoSectionError, + configparser.NoOptionError) as e: + if isinstance(e, (EnvironmentError, configparser.NoSectionError)): + print("Adding sample versioneer config to setup.cfg", + file=sys.stderr) + with open(os.path.join(root, "setup.cfg"), "a") as f: + f.write(SAMPLE_CONFIG) + print(CONFIG_ERROR, file=sys.stderr) + return 1 + + print(" creating %s" % cfg.versionfile_source) + with open(cfg.versionfile_source, "w") as f: + LONG = LONG_VERSION_PY[cfg.VCS] + f.write(LONG % {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), + "__init__.py") + if os.path.exists(ipy): + try: + with open(ipy, "r") as f: + old = f.read() + except EnvironmentError: + old = "" + if INIT_PY_SNIPPET not in old: + print(" appending to %s" % ipy) + with open(ipy, "a") as f: + f.write(INIT_PY_SNIPPET) + else: + print(" %s unmodified" % ipy) + else: + print(" %s doesn't exist, ok" % ipy) + ipy = None + + # Make sure both the top-level "versioneer.py" and versionfile_source + # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so + # they'll be copied into source distributions. Pip won't be able to + # install the package without this. + manifest_in = os.path.join(root, "MANIFEST.in") + simple_includes = set() + try: + with open(manifest_in, "r") as f: + for line in f: + if line.startswith("include "): + for include in line.split()[1:]: + simple_includes.add(include) + except EnvironmentError: + pass + # That doesn't cover everything MANIFEST.in can do + # (http://docs.python.org/2/distutils/sourcedist.html#commands), so + # it might give some false negatives. Appending redundant 'include' + # lines is safe, though. + if "versioneer.py" not in simple_includes: + print(" appending 'versioneer.py' to MANIFEST.in") + with open(manifest_in, "a") as f: + f.write("include versioneer.py\n") + else: + print(" 'versioneer.py' already in MANIFEST.in") + if cfg.versionfile_source not in simple_includes: + print(" appending versionfile_source ('%s') to MANIFEST.in" % + cfg.versionfile_source) + with open(manifest_in, "a") as f: + f.write("include %s\n" % cfg.versionfile_source) + else: + print(" versionfile_source already in MANIFEST.in") + + # Make VCS-specific changes. For git, this means creating/changing + # .gitattributes to mark _version.py for export-subst keyword + # substitution. + do_vcs_install(manifest_in, cfg.versionfile_source, ipy) + return 0 + + +def scan_setup_py(): + """Validate the contents of setup.py against Versioneer's expectations.""" + found = set() + setters = False + errors = 0 + with open("setup.py", "r") as f: + for line in f.readlines(): + if "import versioneer" in line: + found.add("import") + if "versioneer.get_cmdclass()" in line: + found.add("cmdclass") + if "versioneer.get_version()" in line: + found.add("get_version") + if "versioneer.VCS" in line: + setters = True + if "versioneer.versionfile_source" in line: + setters = True + if len(found) != 3: + print("") + print("Your setup.py appears to be missing some important items") + print("(but I might be wrong). Please make sure it has something") + print("roughly like the following:") + print("") + print(" import versioneer") + print(" setup( version=versioneer.get_version(),") + print(" cmdclass=versioneer.get_cmdclass(), ...)") + print("") + errors += 1 + if setters: + print("You should remove lines like 'versioneer.VCS = ' and") + print("'versioneer.versionfile_source = ' . This configuration") + print("now lives in setup.cfg, and should be removed from setup.py") + print("") + errors += 1 + return errors + + +if __name__ == "__main__": + cmd = sys.argv[1] + if cmd == "setup": + errors = do_setup() + errors += scan_setup_py() + if errors: + sys.exit(1) From e3105c004cc84e31866f99a7b843a3868e96b707 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 1 Mar 2018 20:00:12 +0000 Subject: [PATCH 012/279] CLN: Fix warning in entropy Use secure time function to avoid compiler warning --- _randomgen/core_prng/src/entropy/entropy.c | 2 +- _randomgen/core_prng/src/xoroshiro128/xoroshiro128.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/_randomgen/core_prng/src/entropy/entropy.c b/_randomgen/core_prng/src/entropy/entropy.c index a5d48bd1418e..ead4bef835a3 100644 --- a/_randomgen/core_prng/src/entropy/entropy.c +++ b/_randomgen/core_prng/src/entropy/entropy.c @@ -142,7 +142,7 @@ uint32_t entropy_randombytes(void) { uint32_t out = 0; int64_t counter; struct _timeb tv; - _ftime(&tv); + _ftime_s(&tv); out = entropy_hash_32(GetCurrentProcessId()) ^ entropy_hash_32((uint32_t)tv.time) ^ entropy_hash_32(tv.millitm) ^ entropy_hash_32(clock()); diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c index 244ca28b20d9..743b43f5f8c4 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c @@ -49,7 +49,7 @@ void xoroshiro128_jump(xoroshiro128_state *state) { s0 ^= state->s[0]; s1 ^= state->s[1]; } - xoroshiro128_next(&state->s); + xoroshiro128_next(&state->s[0]); } state->s[0] = s0; From 18a1801552a2cda179706fbd3a7bc3e06fc02bef Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 1 Mar 2018 22:45:43 +0000 Subject: [PATCH 013/279] REF: Add types to prng_t Add function types directly to prng_t to simplify use Clean distributionsto use new syntex Remove unused type definitions Rename type definitions to me more meaningful xref #1 --- _randomgen/core_prng/common.pxd | 14 ++++------ _randomgen/core_prng/common.pyx | 6 ++--- _randomgen/core_prng/generator.pyx | 18 +++---------- _randomgen/core_prng/splitmix64.pyx | 6 ++--- .../src/distributions/distributions.c | 26 +++++++------------ .../src/distributions/distributions.h | 20 +++++++------- _randomgen/core_prng/xoroshiro128.pyx | 8 +++--- 7 files changed, 36 insertions(+), 62 deletions(-) diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index 7e29a4190bf6..21bab5df3176 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -1,19 +1,15 @@ from libc.stdint cimport uint32_t, uint64_t cdef extern from "src/distributions/distributions.h": - ctypedef double (*prng_double)(void *st) nogil + ctypedef double (*random_double_0)(void *st) nogil - ctypedef float (*prng_float)(void *st) nogil - - ctypedef uint32_t (*prng_uint32)(void *st) nogil - - ctypedef uint64_t (*prng_uint64)(void *st) nogil + ctypedef float (*random_float_0)(void *st) nogil cdef struct prng: void *state - void *next_uint64 - void *next_uint32 - void *next_double + uint64_t (*next_uint64)(void *st) + uint32_t (*next_uint32)(void *st) + double (*next_double)(void *st) ctypedef prng prng_t diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index 2d09795af180..b6e832c49219 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -20,7 +20,7 @@ cdef check_output(object out, object dtype, object size): cdef object double_fill(void *func, void *state, object size, object lock): - cdef prng_double random_func = (func) + cdef random_double_0 random_func = (func) cdef double *out_array_data cdef np.ndarray out_array cdef np.npy_intp i, n @@ -39,7 +39,7 @@ cdef object double_fill(void *func, void *state, object size, object lock): return out_array cdef object float_fill(void *func, void *state, object size, object lock): - cdef prng_float random_func = (func) + cdef random_float_0 random_func = (func) cdef float *out_array_data cdef np.ndarray out_array cdef np.npy_intp i, n @@ -58,7 +58,7 @@ cdef object float_fill(void *func, void *state, object size, object lock): return out_array cdef object float_fill_from_double(void *func, void *state, object size, object lock): - cdef prng_double random_func = (func) + cdef random_double_0 random_func = (func) cdef float *out_array_data cdef np.ndarray out_array cdef np.npy_intp i, n diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 69aca7a2e83e..cfed7778a0a0 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -36,10 +36,6 @@ cdef class RandomGenerator: """ cdef public object __core_prng cdef prng_t *_prng - cdef prng_uint64 next_uint64 - cdef prng_double next_double - cdef prng_uint32 next_uint32 - cdef void *rng_state cdef object lock def __init__(self, prng=None): @@ -52,10 +48,6 @@ cdef class RandomGenerator: if not PyCapsule_IsValid(capsule, anon_name): raise ValueError("Invalid pointer to anon_func_state") self._prng = PyCapsule_GetPointer(capsule, anon_name) - self.next_uint32 = self._prng.next_uint32 - self.next_uint64 = self._prng.next_uint64 - self.next_double = self._prng.next_double - self.rng_state = self._prng.state self.lock = Lock() @property @@ -70,19 +62,15 @@ cdef class RandomGenerator: def random_integer(self, bits=64): #print("In random_integer") if bits==64: - #print("Calling...") - #print(&self.next_uint64) - #print(&self.rng_state) - return self.next_uint64(self.rng_state) + return self._prng.next_uint64(self._prng.state) elif bits==32: - return random_uint32(self._prng) # self.next_uint32(self.rng_state) - # return self.next_uint32(self.rng_state) + return random_uint32(self._prng) else: raise ValueError('bits must be 32 or 64') def random_double(self, bits=64): if bits==64: - return self.next_double(self.rng_state) + return self._prng.next_double(self._prng.state) elif bits==32: return random_float(self._prng) else: diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index 43f11fc18775..3e83618bcb9e 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -56,9 +56,9 @@ cdef class SplitMix64: self.seed(seed) self._prng.state = self.rng_state - self._prng.next_uint64 = &splitmix64_uint64 - self._prng.next_uint32 = &splitmix64_uint32 - self._prng.next_double = &splitmix64_double + self._prng.next_uint64 = &splitmix64_uint64 + self._prng.next_uint32 = &splitmix64_uint32 + self._prng.next_double = &splitmix64_double cdef const char *name = "CorePRNG" self._prng_capsule = PyCapsule_New(self._prng, name, NULL) diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index f875b3182d0d..d09c49450295 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -1,26 +1,18 @@ #include "distributions.h" -uint32_t random_uint32(void *void_state) { - prng_t *prng_state = (prng_t *)void_state; - prng_uint32 next_uint32 = (prng_uint32)prng_state->next_uint32; - return next_uint32(prng_state->state); +uint32_t random_uint32(prng_t *prng_state) { + return prng_state->next_uint32(prng_state->state); } -float random_float(void *void_state) { - prng_t *prng_state = (prng_t *)void_state; - prng_uint32 next_uint32 = (prng_uint32)(prng_state->next_uint32); - uint32_t next_value = next_uint32(prng_state->state); - return (next_value >> 9) * (1.0f / 8388608.0f); +float random_float(prng_t *prng_state) { + uint32_t next_32 = prng_state->next_uint32(prng_state->state); + return (next_32 >> 9) * (1.0f / 8388608.0f); } -double random_double(void *void_state) { - prng_t *prng_state = (prng_t *)void_state; - prng_double next_double = (prng_double)prng_state->next_double; - return next_double(prng_state->state); +double random_double(prng_t *prng_state) { + return prng_state->next_double(prng_state->state); } -double random_standard_exponential(void *void_state) { - prng_t *prng_state = (prng_t *)void_state; - prng_double next_double = (prng_double)prng_state->next_double; - return -log(1.0 - next_double(prng_state->state)); +double random_standard_exponential(prng_t *prng_state) { + return -log(1.0 - prng_state->next_double(prng_state->state)); } diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index fa37361cdc09..c5ac4d577f3d 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -16,22 +16,20 @@ typedef int bool; #include -typedef double (*prng_double)(void *st); -typedef float (*prng_float)(void *st); -typedef uint32_t (*prng_uint32)(void *st); -typedef uint64_t (*prng_uint64)(void *st); +typedef double (*random_double_0)(void *st); +typedef float (*random_float_0)(void *st); typedef struct prng { void *state; - void *next_uint64; - void *next_uint32; - void *next_double; + uint64_t (*next_uint64)(void *st); + uint32_t (*next_uint32)(void *st); + double (*next_double)(void *st); } prng_t; -float random_float(void *void_state); +float random_float(prng_t *prng_state); -double random_double(void *void_state); +double random_double(prng_t *prng_state); -uint32_t random_uint32(void *void_state); +uint32_t random_uint32(prng_t *prng_state); -double random_standard_exponential(void *void_state); \ No newline at end of file +double random_standard_exponential(prng_t *prng_state); \ No newline at end of file diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 0b6a0453ff54..d97bc06ad602 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -29,7 +29,7 @@ cdef extern from "src/xoroshiro128/xoroshiro128.h": cdef uint64_t xoroshiro128_uint64(void* st):# nogil: return xoroshiro128_next64(st) -cdef uint64_t xoroshiro128_uint32(void *st) nogil: +cdef uint32_t xoroshiro128_uint32(void *st) nogil: return xoroshiro128_next32( st) cdef double xoroshiro128_double(void* st) nogil: @@ -59,9 +59,9 @@ cdef class Xoroshiro128: self.seed(seed) self._prng.state = self.rng_state - self._prng.next_uint64 = &xoroshiro128_uint64 - self._prng.next_uint32 = &xoroshiro128_uint32 - self._prng.next_double = &xoroshiro128_double + self._prng.next_uint64 = &xoroshiro128_uint64 + self._prng.next_uint32 = &xoroshiro128_uint32 + self._prng.next_double = &xoroshiro128_double cdef const char *name = "CorePRNG" self._prng_capsule = PyCapsule_New(self._prng, name, NULL) From 85a7348d3c0dcfeebaf40775f520e882b400113d Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 2 Mar 2018 12:05:41 +0000 Subject: [PATCH 014/279] ENH: Add Threefry generator Add threefry Clean unused definitions from splitmix and xoroshiro --- _randomgen/core_prng/__init__.py | 5 +- .../core_prng/src/splitmix64/splitmix64.c | 2 +- .../core_prng/src/threefry/threefry-orig.c | 86 +++++++++ _randomgen/core_prng/src/threefry/threefry.c | 38 ++++ _randomgen/core_prng/src/threefry/threefry.h | 107 +++++++++++ .../core_prng/src/xoroshiro128/xoroshiro128.c | 6 +- .../core_prng/src/xoroshiro128/xoroshiro128.h | 2 +- _randomgen/core_prng/threefry.pyx | 174 ++++++++++++++++++ _randomgen/core_prng/xoroshiro128.pyx | 2 - _randomgen/demo.py | 10 +- _randomgen/setup.py | 5 + 11 files changed, 425 insertions(+), 12 deletions(-) create mode 100644 _randomgen/core_prng/src/threefry/threefry-orig.c create mode 100644 _randomgen/core_prng/src/threefry/threefry.c create mode 100644 _randomgen/core_prng/src/threefry/threefry.h create mode 100644 _randomgen/core_prng/threefry.pyx diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index 539b3fa4d96a..19890ffb2499 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -1,8 +1,9 @@ from .generator import RandomGenerator -from .xoroshiro128 import Xoroshiro128 from .splitmix64 import SplitMix64 +from .threefry import ThreeFry +from .xoroshiro128 import Xoroshiro128 -__all__ = ['RandomGenerator', 'SplitMix64', 'Xoroshiro128'] +__all__ = ['RandomGenerator', 'SplitMix64', 'Xoroshiro128', 'ThreeFry'] from ._version import get_versions __version__ = get_versions()['version'] diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.c b/_randomgen/core_prng/src/splitmix64/splitmix64.c index 77f0693bac65..79a845982c5f 100644 --- a/_randomgen/core_prng/src/splitmix64/splitmix64.c +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.c @@ -22,7 +22,7 @@ license. #include "splitmix64.h" -static inline uint64_t splitmix64_next(uint64_t *state); +extern inline uint64_t splitmix64_next(uint64_t *state); extern inline uint64_t splitmix64_next64(splitmix64_state *state); diff --git a/_randomgen/core_prng/src/threefry/threefry-orig.c b/_randomgen/core_prng/src/threefry/threefry-orig.c new file mode 100644 index 000000000000..1a5094fa6b6d --- /dev/null +++ b/_randomgen/core_prng/src/threefry/threefry-orig.c @@ -0,0 +1,86 @@ +/* +Copyright (c) 2017, Pierre de Buyl + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include "threefry.h" + +#define N_WORDS 2 +#define KEY_LENGTH 3 +#define C240 0x1BD11BDAA9FC1A22 +#define N_ROUNDS 20 +#define MASK 0xffffffffffffffff +#define DOUBLE_MULT 5.421010862427522e-20 + +static const int ROTATION[] = {16, 42, 12, 31, 16, 32, 24, 21}; + +uint64_t rotl_64(uint64_t x, int d) { + return ((x << d) | (x >> (64-d))); +} + +threefry_t mix(threefry_t x, int R) { + x.c0 += x.c1; + x.c1 = rotl_64(x.c1, R) ^ x.c0; + return x; +} + +threefry_t threefry(threefry_t p, threefry_t k) { + uint64_t K[] = {k.c0, k.c1, C240^k.c0^k.c1}; + int rmod4, rdiv4; + threefry_t x; + x = p; + for (int r=0; rc0++; + return x.c0; +} + +double threefry_double(threefry_t *c, threefry_t *k) { + threefry_t x; + x = threefry(*c, *k); + c->c0++; + return x.c0 * DOUBLE_MULT; +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/threefry/threefry.c b/_randomgen/core_prng/src/threefry/threefry.c new file mode 100644 index 000000000000..3a2f00d13005 --- /dev/null +++ b/_randomgen/core_prng/src/threefry/threefry.c @@ -0,0 +1,38 @@ +/* +Adapted from https://github.com/pdebuyl/threefry + +Copyright (c) 2017, Pierre de Buyl + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "threefry.h" + +extern inline uint64_t threefry_next64(threefry_state *state); + +extern inline uint64_t threefry_next32(threefry_state *state); \ No newline at end of file diff --git a/_randomgen/core_prng/src/threefry/threefry.h b/_randomgen/core_prng/src/threefry/threefry.h new file mode 100644 index 000000000000..302f3c9f1c9d --- /dev/null +++ b/_randomgen/core_prng/src/threefry/threefry.h @@ -0,0 +1,107 @@ +/* +Adapted from https://github.com/pdebuyl/threefry + +Copyright (c) 2017, Pierre de Buyl + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#define N_WORDS 2 +#define KEY_LENGTH 3 +#define C240 0x1BD11BDAA9FC1A22 +#define N_ROUNDS 20 +#define MASK 0xffffffffffffffff +#define DOUBLE_MULT 5.421010862427522e-20 + +typedef struct { + uint64_t c0, c1; +} threefry_t; + +typedef struct s_threefry_state { + threefry_t *c; + threefry_t *k; + int has_uint32; + uint32_t uinteger; +} threefry_state; + +static const int ROTATION[] = {16, 42, 12, 31, 16, 32, 24, 21}; + +static inline uint64_t rotl_64(uint64_t x, int d) { + return ((x << d) | (x >> (64 - d))); +} + +static inline threefry_t mix(threefry_t x, int R) { + x.c0 += x.c1; + x.c1 = rotl_64(x.c1, R) ^ x.c0; + return x; +} + +static inline threefry_t threefry(threefry_t p, threefry_t k) { + const uint64_t K[] = {k.c0, k.c1, C240 ^ k.c0 ^ k.c1}; + int rmod4, rdiv4; + threefry_t x; + x = p; + for (int r = 0; r < N_ROUNDS; r++) { + rmod4 = r % 4; + if (rmod4 == 0) { + rdiv4 = r / 4; + x.c0 += K[rdiv4 % KEY_LENGTH]; + x.c1 += K[(rdiv4 + 1) % KEY_LENGTH] + rdiv4; + } + x = mix(x, ROTATION[r % 8]); + } + x.c0 += K[(N_ROUNDS / 4) % KEY_LENGTH]; + x.c1 += K[(N_ROUNDS / 4 + 1) % KEY_LENGTH] + N_ROUNDS / 4; + return x; +} + +static inline uint64_t threefry_next(threefry_t *c, threefry_t *k) { + threefry_t x; + x = threefry(*c, *k); + c->c0++; + return x.c0; +} + +static inline uint64_t threefry_next64(threefry_state *state) { + return threefry_next(state->c, state->k); +} + +static inline uint64_t threefry_next32(threefry_state *state) { + if (state->has_uint32) { + state->has_uint32 = 0; + return state->uinteger; + } + uint64_t next = threefry_next(state->c, state->k); + ; + state->has_uint32 = 1; + state->uinteger = (uint32_t)(next & 0xffffffff); + return (uint32_t)(next >> 32); +} diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c index 743b43f5f8c4..928e5c523566 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c @@ -32,11 +32,9 @@ See . */ #include "xoroshiro128.h" -extern inline uint64_t xoroshiro128_next(uint64_t *s); +extern inline uint64_t xoroshiro128_next64(xoroshiro128_state *state); -static inline uint64_t xoroshiro128_next64(xoroshiro128_state *state); - -static inline uint64_t xoroshiro128_next32(xoroshiro128_state *state); +extern inline uint32_t xoroshiro128_next32(xoroshiro128_state *state); void xoroshiro128_jump(xoroshiro128_state *state) { static const uint64_t JUMP[] = {0xbeac0467eba5facb, 0xd86b048b86aa9922}; diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h index f575ef7aada3..bc6256aa6267 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h @@ -26,7 +26,7 @@ static inline uint64_t xoroshiro128_next64(xoroshiro128_state *state) { return xoroshiro128_next(&state->s[0]); } -static inline uint64_t xoroshiro128_next32(xoroshiro128_state *state) { +static inline uint32_t xoroshiro128_next32(xoroshiro128_state *state) { if (state->has_uint32) { state->has_uint32 = 0; return state->uinteger; diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx new file mode 100644 index 000000000000..018dfc4165db --- /dev/null +++ b/_randomgen/core_prng/threefry.pyx @@ -0,0 +1,174 @@ +from libc.stdint cimport uint32_t, uint64_t +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + +import numpy as np +cimport numpy as np + +from common cimport * +from core_prng.entropy import random_entropy +cimport entropy + +np.import_array() + +cdef extern from "src/threefry/threefry.h": + + cdef struct s_threefry: + uint64_t c0, c1 + + ctypedef s_threefry threefry_t + + cdef struct s_threefry_state: + threefry_t *c + threefry_t *k + int has_uint32 + uint32_t uinteger + + ctypedef s_threefry_state threefry_state + + cdef uint64_t threefry_next64(threefry_state *state) nogil + cdef uint64_t threefry_next32(threefry_state *state) nogil + + +cdef uint64_t threefry_uint64(void* st):# nogil: + return threefry_next64(st) + +cdef uint32_t threefry_uint32(void *st) nogil: + return threefry_next32( st) + +cdef double threefry_double(void* st) nogil: + return uint64_to_double(threefry_next64(st)) + +cdef class ThreeFry: + """ + Prototype Core PRNG using threefry + + Parameters + ---------- + seed : int, array of int + Integer or array of integers between 0 and 2**64 - 1 + + Notes + ----- + Exposes no user-facing API except `state`. Designed for use in + a `RandomGenerator` object. + """ + cdef threefry_state *rng_state + cdef prng_t *_prng + cdef public object _prng_capsule + + def __init__(self, seed=None): + self.rng_state = malloc(sizeof(threefry_state)) + self.rng_state.c = malloc(sizeof(threefry_t)) + self.rng_state.k = malloc(sizeof(threefry_t)) + self._prng = malloc(sizeof(prng_t)) + self.seed(seed) + + self._prng.state = self.rng_state + self._prng.next_uint64 = &threefry_uint64 + self._prng.next_uint32 = &threefry_uint32 + self._prng.next_double = &threefry_double + + cdef const char *name = "CorePRNG" + self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + + def __dealloc__(self): + free(self.rng_state.c) + free(self.rng_state.k) + free(self.rng_state) + free(self._prng) + + def _reset_state_variables(self): + self.rng_state.has_uint32 = 0 + self.rng_state.uinteger = 0 + + def __random_integer(self, bits=64): + """ + 64-bit Random Integers from the PRNG + + Parameters + ---------- + bits : {32, 64} + Number of random bits to return + + Returns + ------- + rv : int + Next random value + + Notes + ----- + Testing only + """ + if bits == 64: + return threefry_next64(self.rng_state) + elif bits == 32: + return threefry_next32(self.rng_state) + else: + raise ValueError('bits must be 32 or 64') + + def seed(self, seed=None): + """ + seed(seed=None, stream=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + """ + ub = 2 ** 64 + if seed is None: + try: + state = random_entropy(4) + except RuntimeError: + state = random_entropy(4, 'fallback') + state = state.view(np.uint64) + else: + state = entropy.seed_by_array(seed, 2) + # TODO: Need to be able to set the key and counter directly + self.rng_state.c.c0 = 0 + self.rng_state.c.c1 = 0 + self.rng_state.k.c0 = int(state[0]) + self.rng_state.k.c1 = int(state[1]) + self._reset_state_variables() + + @property + def state(self): + """Get or set the PRNG state""" + c = np.empty(2, dtype=np.uint64) + k = np.empty(2, dtype=np.uint64) + c[0] = self.rng_state.c.c0 + c[1] = self.rng_state.c.c1 + k[0] = self.rng_state.k.c0 + k[1] = self.rng_state.k.c1 + state = {'c':c,'k':k} + return {'prng': self.__class__.__name__, + 'state': state, + 'has_uint32': self.rng_state.has_uint32, + 'uinteger': self.rng_state.uinteger} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + prng = value.get('prng', '') + if prng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + self.rng_state.c.c0 = value['state']['c'][0] + self.rng_state.c.c1 = value['state']['c'][1] + self.rng_state.k.c0 = value['state']['k'][0] + self.rng_state.k.c1 = value['state']['k'][1] + self.rng_state.has_uint32 = value['has_uint32'] + self.rng_state.uinteger = value['uinteger'] diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index d97bc06ad602..0cb53f830426 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -20,8 +20,6 @@ cdef extern from "src/xoroshiro128/xoroshiro128.h": ctypedef s_xoroshiro128_state xoroshiro128_state - cdef uint64_t xoroshiro128_next(uint64_t *s) nogil - cdef uint64_t xoroshiro128_next64(xoroshiro128_state *state) nogil cdef uint64_t xoroshiro128_next32(xoroshiro128_state *state) nogil cdef void xoroshiro128_jump(xoroshiro128_state *state) diff --git a/_randomgen/demo.py b/_randomgen/demo.py index b40a2c42843d..25b0ea876bcb 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -1,9 +1,9 @@ from core_prng.generator import RandomGenerator -from core_prng.splitmix64 import SplitMix64 -from core_prng.xoroshiro128 import Xoroshiro128 +from core_prng import SplitMix64, Xoroshiro128, ThreeFry print(RandomGenerator().random_integer()) print(RandomGenerator(Xoroshiro128()).random_integer()) +print(RandomGenerator(ThreeFry()).random_integer()) print(RandomGenerator(SplitMix64()).random_integer()) print(RandomGenerator(SplitMix64()).random_integer()) print(RandomGenerator(SplitMix64(1)).random_integer()) @@ -34,3 +34,9 @@ print(rg.state) rg.state = state print(rg.random_integer()) + +print(RandomGenerator(Xoroshiro128()).state) +rg = RandomGenerator(ThreeFry()) +print(rg.state) +rg.random_integer() +print(rg.state) \ No newline at end of file diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 6aa1aefa7979..0a9a32b7f912 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -28,6 +28,11 @@ join(MOD_DIR, 'src', 'splitmix64', 'splitmix64.c')], include_dirs=[np.get_include(), join(MOD_DIR, 'src', 'splitmix64')]), + Extension("core_prng.threefry", + ["core_prng/threefry.pyx", + join(MOD_DIR, 'src', 'threefry', 'threefry.c')], + include_dirs=[np.get_include(), + join(MOD_DIR, 'src', 'threefry')]), Extension("core_prng.xoroshiro128", ["core_prng/xoroshiro128.pyx", join(MOD_DIR, 'src', 'xoroshiro128', From 8fb764916012b661433150b2cf3fd1077f6e6ad1 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 2 Mar 2018 16:54:06 +0000 Subject: [PATCH 015/279] ENH: Use Random123 threefry Switch to random123 threefry implementation --- _randomgen/core_prng/__init__.py | 4 +- _randomgen/core_prng/entropy.pyx | 4 +- _randomgen/core_prng/mt19937.pyx | 150 +++ _randomgen/core_prng/splitmix64.pyx | 5 +- _randomgen/core_prng/src/mt19937/mt19937.c | 111 +++ _randomgen/core_prng/src/mt19937/mt19937.h | 69 ++ _randomgen/core_prng/src/threefry/threefry.h | 952 +++++++++++++++++-- _randomgen/core_prng/threefry.pyx | 65 +- _randomgen/demo.py | 12 +- _randomgen/setup.py | 5 + 10 files changed, 1265 insertions(+), 112 deletions(-) create mode 100644 _randomgen/core_prng/mt19937.pyx create mode 100644 _randomgen/core_prng/src/mt19937/mt19937.c create mode 100644 _randomgen/core_prng/src/mt19937/mt19937.h diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index 19890ffb2499..8ede7e5f5fe9 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -2,8 +2,10 @@ from .splitmix64 import SplitMix64 from .threefry import ThreeFry from .xoroshiro128 import Xoroshiro128 +from .mt19937 import MT19937 -__all__ = ['RandomGenerator', 'SplitMix64', 'Xoroshiro128', 'ThreeFry'] +__all__ = ['RandomGenerator', 'SplitMix64', 'Xoroshiro128', 'ThreeFry', + 'MT19937'] from ._version import get_versions __version__ = get_versions()['version'] diff --git a/_randomgen/core_prng/entropy.pyx b/_randomgen/core_prng/entropy.pyx index f1155c605273..a4747f36b0fd 100644 --- a/_randomgen/core_prng/entropy.pyx +++ b/_randomgen/core_prng/entropy.pyx @@ -25,14 +25,14 @@ cdef Py_ssize_t compute_numel(size): cdef np.ndarray seed_by_array(object seed, Py_ssize_t n): """ - Transforms a seed array into an initiial state + Transforms a seed array into an initial state Parameters ---------- seed: array, 1d, uint64 Array to use. If seed is a scalar, promote to array. n : int - Number of 64-bit unsiened integers required + Number of 64-bit unsigned integers required Notes ----- diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx new file mode 100644 index 000000000000..e6f59aa2e385 --- /dev/null +++ b/_randomgen/core_prng/mt19937.pyx @@ -0,0 +1,150 @@ +import operator + +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + +import numpy as np +cimport numpy as np + +from common cimport * +from core_prng.entropy import random_entropy + +np.import_array() + +cdef extern from "src/mt19937/mt19937.h": + + cdef struct s_mt19937_state: + uint32_t key[624] + int pos + + ctypedef s_mt19937_state mt19937_state + + cdef uint64_t mt19937_next64(mt19937_state *state) nogil + cdef uint32_t mt19937_next32(mt19937_state *state) nogil + cdef double mt19937_next_double(mt19937_state *state) nogil + cdef void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, int key_length) + cdef void mt19937_seed(mt19937_state *state, uint32_t seed) + +cdef uint64_t mt19937_uint64(void *st) nogil: + return mt19937_next64( st) + +cdef uint32_t mt19937_uint32(void *st) nogil: + return mt19937_next32( st) + +cdef double mt19937_double(void *st) nogil: + return mt19937_next_double( st) + +cdef class MT19937: + """ + Prototype Core PRNG using MT19937 + + Parameters + ---------- + seed : int, array of int + Integer or array of integers between 0 and 2**64 - 1 + + Notes + ----- + Exposes no user-facing API except `state`. Designed for use in a + `RandomGenerator` object. + """ + cdef mt19937_state *rng_state + cdef prng_t *_prng + cdef public object _prng_capsule + + def __init__(self, seed=None): + self.rng_state = malloc(sizeof(mt19937_state)) + self._prng = malloc(sizeof(prng_t)) + self.seed(seed) + + self._prng.state = self.rng_state + self._prng.next_uint64 = &mt19937_uint64 + self._prng.next_uint32 = &mt19937_uint32 + self._prng.next_double = &mt19937_double + + cdef const char *name = "CorePRNG" + self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + + def __dealloc__(self): + free(self.rng_state) + free(self._prng) + + def __random_integer(self): + """ + 64-bit Random Integers from the PRNG + + Returns + ------- + rv : int + Next random value + + Notes + ----- + Testing only + """ + return mt19937_next64(self.rng_state) + + def seed(self, seed=None): + """ + seed(seed=None, stream=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + """ + cdef np.ndarray obj + try: + if seed is None: + try: + seed = random_entropy(1) + except RuntimeError: + seed = random_entropy(1, 'fallback') + mt19937_seed(self.rng_state, seed[0]) + else: + if hasattr(seed, 'squeeze'): + seed = seed.squeeze() + idx = operator.index(seed) + if idx > int(2**32 - 1) or idx < 0: + raise ValueError("Seed must be between 0 and 2**32 - 1") + mt19937_seed(self.rng_state, seed) + except TypeError: + obj = np.asarray(seed).astype(np.int64, casting='safe') + if ((obj > int(2**32 - 1)) | (obj < 0)).any(): + raise ValueError("Seed must be between 0 and 2**32 - 1") + obj = obj.astype(np.uint32, casting='unsafe', order='C') + mt19937_init_by_array(self.rng_state, obj.data, np.PyArray_DIM(obj, 0)) + + @property + def state(self): + """Get or set the PRNG state""" + key = np.zeros(624, dtype=np.uint32) + for i in range(624): + key[i] = self.rng_state.key[i] + + return {'prng': self.__class__.__name__, + 'state': {'key':key, 'pos': self.rng_state.pos}} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + prng = value.get('prng', '') + if prng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + key = value['state']['key'] + for i in range(624): + self.rng_state.key[i] = key[i] + self.rng_state.pos = value['state']['pos'] diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index 3e83618bcb9e..514e9fed9550 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -25,9 +25,8 @@ cdef extern from "src/splitmix64/splitmix64.h": cdef uint64_t splitmix64_uint64(void *st) nogil: return splitmix64_next64( st) -cdef uint32_t splitmix64_uint32(void *st): # nogil: TODO - cdef splitmix64_state *state = st - return splitmix64_next32(state) +cdef uint32_t splitmix64_uint32(void *st) nogil: + return splitmix64_next32( st) cdef double splitmix64_double(void *st) nogil: return uint64_to_double(splitmix64_uint64( st)) diff --git a/_randomgen/core_prng/src/mt19937/mt19937.c b/_randomgen/core_prng/src/mt19937/mt19937.c new file mode 100644 index 000000000000..06ce7a16f4e8 --- /dev/null +++ b/_randomgen/core_prng/src/mt19937/mt19937.c @@ -0,0 +1,111 @@ +#include "mt19937.h" + +extern inline uint32_t mt19937_random(mt19937_state *state); + +void mt19937_seed(mt19937_state *state, uint32_t seed) +{ + int pos; + seed &= 0xffffffffUL; + + /* Knuth's PRNG as used in the Mersenne Twister reference implementation */ + for (pos = 0; pos < RK_STATE_LEN; pos++) { + state->key[pos] = seed; + seed = (1812433253UL * (seed ^ (seed >> 30)) + pos + 1) & 0xffffffffUL; + } + state->pos = RK_STATE_LEN; +} + + +/* initializes mt[RK_STATE_LEN] with a seed */ +static void init_genrand(mt19937_state *state, uint32_t s) +{ + int mti; + uint32_t *mt = state->key; + + mt[0] = s & 0xffffffffUL; + for (mti = 1; mti < RK_STATE_LEN; mti++) { + /* + * See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. + * In the previous versions, MSBs of the seed affect + * only MSBs of the array mt[]. + * 2002/01/09 modified by Makoto Matsumoto + */ + mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); + /* for > 32 bit machines */ + mt[mti] &= 0xffffffffUL; + } + state->pos = mti; + return; +} + + +/* + * initialize by an array with array-length + * init_key is the array for initializing keys + * key_length is its length + */ +void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, int key_length) +{ + /* was signed in the original code. RDH 12/16/2002 */ + int i = 1; + int j = 0; + uint32_t *mt = state->key; + int k; + + init_genrand(state, 19650218UL); + k = (RK_STATE_LEN > key_length ? RK_STATE_LEN : key_length); + for (; k; k--) { + /* non linear */ + mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL)) + + init_key[j] + j; + /* for > 32 bit machines */ + mt[i] &= 0xffffffffUL; + i++; + j++; + if (i >= RK_STATE_LEN) { + mt[0] = mt[RK_STATE_LEN - 1]; + i = 1; + } + if (j >= key_length) { + j = 0; + } + } + for (k = RK_STATE_LEN - 1; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) + - i; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; + if (i >= RK_STATE_LEN) { + mt[0] = mt[RK_STATE_LEN - 1]; + i = 1; + } + } + + mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ +} + +void mt19937_gen(mt19937_state *state) +{ + uint32_t y; + int i; + + for (i = 0; i < N - M; i++) { + y = (state->key[i] & UPPER_MASK) | (state->key[i+1] & LOWER_MASK); + state->key[i] = state->key[i+M] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); + } + for (; i < N - 1; i++) { + y = (state->key[i] & UPPER_MASK) | (state->key[i+1] & LOWER_MASK); + state->key[i] = state->key[i+(M-N)] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); + } + y = (state->key[N - 1] & UPPER_MASK) | (state->key[0] & LOWER_MASK); + state->key[N - 1] = state->key[M - 1] ^ (y >> 1) ^ (-(y & 1) & MATRIX_A); + + state->pos = 0; +} + + +extern inline uint64_t mt19937_next64(mt19937_state *state); + +extern inline uint32_t mt19937_next32(mt19937_state *state); + +extern inline double mt19937_next_double(mt19937_state *state); \ No newline at end of file diff --git a/_randomgen/core_prng/src/mt19937/mt19937.h b/_randomgen/core_prng/src/mt19937/mt19937.h new file mode 100644 index 000000000000..b9617769a622 --- /dev/null +++ b/_randomgen/core_prng/src/mt19937/mt19937.h @@ -0,0 +1,69 @@ +#pragma once +#include +#ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/stdint.h" +#else +#include +#endif +#else +#include +#endif + +#ifdef _WIN32 +#define inline __forceinline +#endif + + +#define RK_STATE_LEN 624 + +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL +#define UPPER_MASK 0x80000000UL +#define LOWER_MASK 0x7fffffffUL + +typedef struct s_mt19937_state +{ + uint32_t key[RK_STATE_LEN]; + int pos; +} mt19937_state; + +extern void mt19937_seed(mt19937_state *state, uint32_t seed); + +extern void mt19937_gen(mt19937_state *state); + +/* Slightly optimized reference implementation of the Mersenne Twister */ +static inline uint32_t mt19937_next(mt19937_state *state) +{ + uint32_t y; + + if (state->pos == RK_STATE_LEN) { + // Move to function to help inlining + mt19937_gen(state); + } + y = state->key[state->pos++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + +extern void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, int key_length); + +static inline uint64_t mt19937_next64(mt19937_state *state) { + return (uint64_t)mt19937_next(state) << 32 | mt19937_next(state); +} + +static inline uint32_t mt19937_next32(mt19937_state *state) { + return mt19937_next(state); +} + +static inline double mt19937_next_double(mt19937_state *state) { + int32_t a = mt19937_next(state) >> 5, b = mt19937_next(state) >> 6; + return (a * 67108864.0 + b) / 9007199254740992.0; +} diff --git a/_randomgen/core_prng/src/threefry/threefry.h b/_randomgen/core_prng/src/threefry/threefry.h index 302f3c9f1c9d..f6a2ca6bf2cc 100644 --- a/_randomgen/core_prng/src/threefry/threefry.h +++ b/_randomgen/core_prng/src/threefry/threefry.h @@ -1,97 +1,894 @@ /* -Adapted from https://github.com/pdebuyl/threefry - -Copyright (c) 2017, Pierre de Buyl - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: +Adapted from random123's threefry.h +*/ -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. +#include +#include -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. +enum r123_enum_threefry64x4 +{ + /* These are the R_256 constants from the Threefish reference sources + with names changed to R_64x4... */ + R_64x4_0_0 = 14, + R_64x4_0_1 = 16, + R_64x4_1_0 = 52, + R_64x4_1_1 = 57, + R_64x4_2_0 = 23, + R_64x4_2_1 = 40, + R_64x4_3_0 = 5, + R_64x4_3_1 = 37, + R_64x4_4_0 = 25, + R_64x4_4_1 = 33, + R_64x4_5_0 = 46, + R_64x4_5_1 = 12, + R_64x4_6_0 = 58, + R_64x4_6_1 = 22, + R_64x4_7_0 = 32, + R_64x4_7_1 = 32 +}; -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. +struct r123array4x64 +{ + uint64_t v[4]; +}; /* r123array4x64 */ -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +typedef struct r123array4x64 threefry4x64_key_t; +typedef struct r123array4x64 threefry4x64_ctr_t; +static __inline _forceinline uint64_t RotL_64(uint64_t x, unsigned int N); +static __inline uint64_t RotL_64(uint64_t x, unsigned int N) +{ + return (x << (N & 63)) | (x >> ((64 - N) & 63)); +} -#include - -#define N_WORDS 2 -#define KEY_LENGTH 3 -#define C240 0x1BD11BDAA9FC1A22 -#define N_ROUNDS 20 -#define MASK 0xffffffffffffffff -#define DOUBLE_MULT 5.421010862427522e-20 -typedef struct { - uint64_t c0, c1; -} threefry_t; +static __inline _forceinline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry4x64_ctr_t in, threefry4x64_key_t k); +static __inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry4x64_ctr_t in, threefry4x64_key_t k) +{ + threefry4x64_ctr_t X; + uint64_t ks[4 + 1]; + int i; + (void)((!!(Nrounds <= 72)) || (_wassert(L"Nrounds<=72", L"c:\\temp\\random123-1.09\\include\\random123\\threefry.h", (unsigned)(728)), 0)); + ks[4] = ((0xA9FC1A22) + (((uint64_t)(0x1BD11BDA)) << 32)); + for (i = 0; i < 4; i++) + { + ks[i] = k.v[i]; + X.v[i] = in.v[i]; + ks[4] ^= k.v[i]; + } + X.v[0] += ks[0]; + X.v[1] += ks[1]; + X.v[2] += ks[2]; + X.v[3] += ks[3]; + if (Nrounds > 0) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 1) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 2) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 3) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 3) + { + X.v[0] += ks[1]; + X.v[1] += ks[2]; + X.v[2] += ks[3]; + X.v[3] += ks[4]; + X.v[4 - 1] += 1; + } + if (Nrounds > 4) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 5) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 6) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 7) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 7) + { + X.v[0] += ks[2]; + X.v[1] += ks[3]; + X.v[2] += ks[4]; + X.v[3] += ks[0]; + X.v[4 - 1] += 2; + } + if (Nrounds > 8) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 9) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 10) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 11) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 11) + { + X.v[0] += ks[3]; + X.v[1] += ks[4]; + X.v[2] += ks[0]; + X.v[3] += ks[1]; + X.v[4 - 1] += 3; + } + if (Nrounds > 12) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 13) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 14) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 15) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 15) + { + X.v[0] += ks[4]; + X.v[1] += ks[0]; + X.v[2] += ks[1]; + X.v[3] += ks[2]; + X.v[4 - 1] += 4; + } + if (Nrounds > 16) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 17) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 18) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 19) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 19) + { + X.v[0] += ks[0]; + X.v[1] += ks[1]; + X.v[2] += ks[2]; + X.v[3] += ks[3]; + X.v[4 - 1] += 5; + } + if (Nrounds > 20) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 21) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 22) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 23) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 23) + { + X.v[0] += ks[1]; + X.v[1] += ks[2]; + X.v[2] += ks[3]; + X.v[3] += ks[4]; + X.v[4 - 1] += 6; + } + if (Nrounds > 24) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 25) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 26) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 27) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 27) + { + X.v[0] += ks[2]; + X.v[1] += ks[3]; + X.v[2] += ks[4]; + X.v[3] += ks[0]; + X.v[4 - 1] += 7; + } + if (Nrounds > 28) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 29) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 30) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 31) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 31) + { + X.v[0] += ks[3]; + X.v[1] += ks[4]; + X.v[2] += ks[0]; + X.v[3] += ks[1]; + X.v[4 - 1] += 8; + } + if (Nrounds > 32) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 33) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 34) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 35) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 35) + { + X.v[0] += ks[4]; + X.v[1] += ks[0]; + X.v[2] += ks[1]; + X.v[3] += ks[2]; + X.v[4 - 1] += 9; + } + if (Nrounds > 36) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 37) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 38) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 39) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 39) + { + X.v[0] += ks[0]; + X.v[1] += ks[1]; + X.v[2] += ks[2]; + X.v[3] += ks[3]; + X.v[4 - 1] += 10; + } + if (Nrounds > 40) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 41) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 42) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 43) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 43) + { + X.v[0] += ks[1]; + X.v[1] += ks[2]; + X.v[2] += ks[3]; + X.v[3] += ks[4]; + X.v[4 - 1] += 11; + } + if (Nrounds > 44) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 45) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 46) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 47) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 47) + { + X.v[0] += ks[2]; + X.v[1] += ks[3]; + X.v[2] += ks[4]; + X.v[3] += ks[0]; + X.v[4 - 1] += 12; + } + if (Nrounds > 48) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 49) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 50) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 51) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 51) + { + X.v[0] += ks[3]; + X.v[1] += ks[4]; + X.v[2] += ks[0]; + X.v[3] += ks[1]; + X.v[4 - 1] += 13; + } + if (Nrounds > 52) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 53) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 54) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 55) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 55) + { + X.v[0] += ks[4]; + X.v[1] += ks[0]; + X.v[2] += ks[1]; + X.v[3] += ks[2]; + X.v[4 - 1] += 14; + } + if (Nrounds > 56) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 57) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 58) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 59) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 59) + { + X.v[0] += ks[0]; + X.v[1] += ks[1]; + X.v[2] += ks[2]; + X.v[3] += ks[3]; + X.v[4 - 1] += 15; + } + if (Nrounds > 60) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 61) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 62) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 63) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 63) + { + X.v[0] += ks[1]; + X.v[1] += ks[2]; + X.v[2] += ks[3]; + X.v[3] += ks[4]; + X.v[4 - 1] += 16; + } + if (Nrounds > 64) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 65) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 66) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 67) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 67) + { + X.v[0] += ks[2]; + X.v[1] += ks[3]; + X.v[2] += ks[4]; + X.v[3] += ks[0]; + X.v[4 - 1] += 17; + } + if (Nrounds > 68) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 69) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 70) + { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 71) + { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 71) + { + X.v[0] += ks[3]; + X.v[1] += ks[4]; + X.v[2] += ks[0]; + X.v[3] += ks[1]; + X.v[4 - 1] += 18; + } + return X; +} +enum r123_enum_threefry4x64 +{ + threefry4x64_rounds = 20 +}; typedef struct s_threefry_state { - threefry_t *c; - threefry_t *k; + threefry4x64_key_t *ctr; + threefry4x64_ctr_t *key; + int buffer_pos; + uint64_t buffer[4]; int has_uint32; uint32_t uinteger; } threefry_state; -static const int ROTATION[] = {16, 42, 12, 31, 16, 32, 24, 21}; -static inline uint64_t rotl_64(uint64_t x, int d) { - return ((x << d) | (x >> (64 - d))); -} - -static inline threefry_t mix(threefry_t x, int R) { - x.c0 += x.c1; - x.c1 = rotl_64(x.c1, R) ^ x.c0; - return x; -} - -static inline threefry_t threefry(threefry_t p, threefry_t k) { - const uint64_t K[] = {k.c0, k.c1, C240 ^ k.c0 ^ k.c1}; - int rmod4, rdiv4; - threefry_t x; - x = p; - for (int r = 0; r < N_ROUNDS; r++) { - rmod4 = r % 4; - if (rmod4 == 0) { - rdiv4 = r / 4; - x.c0 += K[rdiv4 % KEY_LENGTH]; - x.c1 += K[(rdiv4 + 1) % KEY_LENGTH] + rdiv4; - } - x = mix(x, ROTATION[r % 8]); +static inline uint64_t threefry_next(threefry_state *state) { + /* TODO: This 4 should be a constant somewhere */ + if (state->buffer_pos >= 4) { + /* generate 4 new uint64_t */ + int i; + threefry4x64_ctr_t ct; + state->ctr->v[0]++; + ct = threefry4x64_R(threefry4x64_rounds, *state->ctr, *state->key); + for (i=0; i<4; i++){ + state->buffer[i] = ct.v[i]; + } + state->buffer_pos = 0; } - x.c0 += K[(N_ROUNDS / 4) % KEY_LENGTH]; - x.c1 += K[(N_ROUNDS / 4 + 1) % KEY_LENGTH] + N_ROUNDS / 4; - return x; -} - -static inline uint64_t threefry_next(threefry_t *c, threefry_t *k) { - threefry_t x; - x = threefry(*c, *k); - c->c0++; - return x.c0; + uint64_t out = state->buffer[state->buffer_pos]; + state->buffer_pos++; + return out; } static inline uint64_t threefry_next64(threefry_state *state) { - return threefry_next(state->c, state->k); + return threefry_next(state); } static inline uint64_t threefry_next32(threefry_state *state) { @@ -99,9 +896,10 @@ static inline uint64_t threefry_next32(threefry_state *state) { state->has_uint32 = 0; return state->uinteger; } - uint64_t next = threefry_next(state->c, state->k); - ; + uint64_t next = threefry_next(state); + state->has_uint32 = 1; state->uinteger = (uint32_t)(next & 0xffffffff); + return (uint32_t)(next >> 32); } diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index 018dfc4165db..961c09f59de5 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -13,14 +13,19 @@ np.import_array() cdef extern from "src/threefry/threefry.h": - cdef struct s_threefry: - uint64_t c0, c1 + cdef struct s_r123array4x64: + uint64_t v[4] - ctypedef s_threefry threefry_t + ctypedef s_r123array4x64 r123array4x64 + + ctypedef r123array4x64 threefry4x64_key_t + ctypedef r123array4x64 threefry4x64_ctr_t cdef struct s_threefry_state: - threefry_t *c - threefry_t *k + threefry4x64_key_t *ctr; + threefry4x64_ctr_t *key; + int buffer_pos; + uint64_t buffer[4]; int has_uint32 uint32_t uinteger @@ -30,7 +35,7 @@ cdef extern from "src/threefry/threefry.h": cdef uint64_t threefry_next32(threefry_state *state) nogil -cdef uint64_t threefry_uint64(void* st):# nogil: +cdef uint64_t threefry_uint64(void* st) nogil: return threefry_next64(st) cdef uint32_t threefry_uint32(void *st) nogil: @@ -59,8 +64,8 @@ cdef class ThreeFry: def __init__(self, seed=None): self.rng_state = malloc(sizeof(threefry_state)) - self.rng_state.c = malloc(sizeof(threefry_t)) - self.rng_state.k = malloc(sizeof(threefry_t)) + self.rng_state.ctr = malloc(sizeof(threefry4x64_ctr_t)) + self.rng_state.key = malloc(sizeof(threefry4x64_key_t)) self._prng = malloc(sizeof(prng_t)) self.seed(seed) @@ -73,14 +78,17 @@ cdef class ThreeFry: self._prng_capsule = PyCapsule_New(self._prng, name, NULL) def __dealloc__(self): - free(self.rng_state.c) - free(self.rng_state.k) + free(self.rng_state.ctr) + free(self.rng_state.key) free(self.rng_state) free(self._prng) def _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 + self.rng_state.buffer_pos = 4 + for i in range(4): + self.rng_state.buffer[i] = 0 def __random_integer(self, bits=64): """ @@ -130,31 +138,33 @@ cdef class ThreeFry: ub = 2 ** 64 if seed is None: try: - state = random_entropy(4) + state = random_entropy(8) except RuntimeError: - state = random_entropy(4, 'fallback') + state = random_entropy(8, 'fallback') state = state.view(np.uint64) else: state = entropy.seed_by_array(seed, 2) # TODO: Need to be able to set the key and counter directly - self.rng_state.c.c0 = 0 - self.rng_state.c.c1 = 0 - self.rng_state.k.c0 = int(state[0]) - self.rng_state.k.c1 = int(state[1]) + for i in range(4): + self.rng_state.ctr.v[i] = 0 + self.rng_state.key.v[i] = state[i] self._reset_state_variables() @property def state(self): """Get or set the PRNG state""" - c = np.empty(2, dtype=np.uint64) - k = np.empty(2, dtype=np.uint64) - c[0] = self.rng_state.c.c0 - c[1] = self.rng_state.c.c1 - k[0] = self.rng_state.k.c0 - k[1] = self.rng_state.k.c1 - state = {'c':c,'k':k} + ctr = np.empty(4, dtype=np.uint64) + key = np.empty(4, dtype=np.uint64) + buffer = np.empty(4, dtype=np.uint64) + for i in range(4): + ctr[i] = self.rng_state.ctr.v[i] + key[i] = self.rng_state.key.v[i] + buffer[i] = self.rng_state.buffer[i] + state = {'ctr':ctr,'k':key} return {'prng': self.__class__.__name__, 'state': state, + 'buffer': buffer, + 'buffer_pos': self.rng_state.buffer_pos, 'has_uint32': self.rng_state.has_uint32, 'uinteger': self.rng_state.uinteger} @@ -166,9 +176,10 @@ cdef class ThreeFry: if prng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) - self.rng_state.c.c0 = value['state']['c'][0] - self.rng_state.c.c1 = value['state']['c'][1] - self.rng_state.k.c0 = value['state']['k'][0] - self.rng_state.k.c1 = value['state']['k'][1] + for i in range(4): + self.rng_state.ctr.v[i] = value['state']['ctr'][i] + self.rng_state.key.v[i] = value['state']['key'][i] + self.rng_state.buffer[i] = value['state']['buffer'][i] self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] + self.rng_state.buffer_pos = value['buffer_pos'] diff --git a/_randomgen/demo.py b/_randomgen/demo.py index 25b0ea876bcb..7fe81af01c25 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -1,5 +1,6 @@ from core_prng.generator import RandomGenerator -from core_prng import SplitMix64, Xoroshiro128, ThreeFry + +from core_prng import SplitMix64, Xoroshiro128, ThreeFry, MT19937 print(RandomGenerator().random_integer()) print(RandomGenerator(Xoroshiro128()).random_integer()) @@ -39,4 +40,11 @@ rg = RandomGenerator(ThreeFry()) print(rg.state) rg.random_integer() -print(rg.state) \ No newline at end of file +print(rg.state) +rg = RandomGenerator(MT19937()) +state = rg.state +print(state) +rg.state = state +print(rg.random_integer()) +print(rg.random_integer(32)) +print(rg.random_sample()) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 0a9a32b7f912..3e06920e8844 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -23,6 +23,11 @@ include_dirs=[np.get_include(), join(MOD_DIR, 'src', 'entropy')], extra_link_args=EXTRA_LINK_ARGS), + Extension("core_prng.mt19937", + ["core_prng/mt19937.pyx", + join(MOD_DIR, 'src', 'mt19937', 'mt19937.c')], + include_dirs=[np.get_include(), + join(MOD_DIR, 'src', 'mt19937')]), Extension("core_prng.splitmix64", ["core_prng/splitmix64.pyx", join(MOD_DIR, 'src', 'splitmix64', 'splitmix64.c')], From 142c8d56e37313a43ab807e0682afd6c82e778b0 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 2 Mar 2018 17:10:18 +0000 Subject: [PATCH 016/279] CLN: Remove unnecessary code from threefry Remove higher iterations from threefre --- _randomgen/core_prng/src/threefry/threefry.h | 574 +------------------ 1 file changed, 5 insertions(+), 569 deletions(-) diff --git a/_randomgen/core_prng/src/threefry/threefry.h b/_randomgen/core_prng/src/threefry/threefry.h index f6a2ca6bf2cc..5e0a720ffe1b 100644 --- a/_randomgen/core_prng/src/threefry/threefry.h +++ b/_randomgen/core_prng/src/threefry/threefry.h @@ -3,7 +3,6 @@ Adapted from random123's threefry.h */ #include -#include enum r123_enum_threefry64x4 { @@ -35,20 +34,19 @@ struct r123array4x64 typedef struct r123array4x64 threefry4x64_key_t; typedef struct r123array4x64 threefry4x64_ctr_t; -static __inline _forceinline uint64_t RotL_64(uint64_t x, unsigned int N); -static __inline uint64_t RotL_64(uint64_t x, unsigned int N) +static inline uint64_t RotL_64(uint64_t x, unsigned int N); +static inline uint64_t RotL_64(uint64_t x, unsigned int N) { return (x << (N & 63)) | (x >> ((64 - N) & 63)); } -static __inline _forceinline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry4x64_ctr_t in, threefry4x64_key_t k); -static __inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry4x64_ctr_t in, threefry4x64_key_t k) +static inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry4x64_ctr_t in, threefry4x64_key_t k); +static inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry4x64_ctr_t in, threefry4x64_key_t k) { threefry4x64_ctr_t X; uint64_t ks[4 + 1]; int i; - (void)((!!(Nrounds <= 72)) || (_wassert(L"Nrounds<=72", L"c:\\temp\\random123-1.09\\include\\random123\\threefry.h", (unsigned)(728)), 0)); ks[4] = ((0xA9FC1A22) + (((uint64_t)(0x1BD11BDA)) << 32)); for (i = 0; i < 4; i++) { @@ -280,6 +278,7 @@ static __inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry X.v[3] += ks[3]; X.v[4 - 1] += 5; } + /* Maximum of 20 rounds */ if (Nrounds > 20) { X.v[0] += X.v[1]; @@ -289,569 +288,6 @@ static __inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry X.v[3] = RotL_64(X.v[3], R_64x4_4_1); X.v[3] ^= X.v[2]; } - if (Nrounds > 21) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_5_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_5_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 22) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_6_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_6_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 23) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_7_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_7_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 23) - { - X.v[0] += ks[1]; - X.v[1] += ks[2]; - X.v[2] += ks[3]; - X.v[3] += ks[4]; - X.v[4 - 1] += 6; - } - if (Nrounds > 24) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_0_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_0_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 25) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_1_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_1_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 26) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_2_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_2_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 27) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_3_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_3_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 27) - { - X.v[0] += ks[2]; - X.v[1] += ks[3]; - X.v[2] += ks[4]; - X.v[3] += ks[0]; - X.v[4 - 1] += 7; - } - if (Nrounds > 28) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_4_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_4_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 29) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_5_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_5_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 30) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_6_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_6_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 31) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_7_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_7_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 31) - { - X.v[0] += ks[3]; - X.v[1] += ks[4]; - X.v[2] += ks[0]; - X.v[3] += ks[1]; - X.v[4 - 1] += 8; - } - if (Nrounds > 32) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_0_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_0_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 33) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_1_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_1_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 34) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_2_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_2_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 35) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_3_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_3_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 35) - { - X.v[0] += ks[4]; - X.v[1] += ks[0]; - X.v[2] += ks[1]; - X.v[3] += ks[2]; - X.v[4 - 1] += 9; - } - if (Nrounds > 36) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_4_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_4_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 37) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_5_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_5_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 38) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_6_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_6_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 39) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_7_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_7_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 39) - { - X.v[0] += ks[0]; - X.v[1] += ks[1]; - X.v[2] += ks[2]; - X.v[3] += ks[3]; - X.v[4 - 1] += 10; - } - if (Nrounds > 40) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_0_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_0_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 41) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_1_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_1_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 42) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_2_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_2_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 43) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_3_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_3_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 43) - { - X.v[0] += ks[1]; - X.v[1] += ks[2]; - X.v[2] += ks[3]; - X.v[3] += ks[4]; - X.v[4 - 1] += 11; - } - if (Nrounds > 44) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_4_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_4_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 45) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_5_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_5_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 46) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_6_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_6_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 47) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_7_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_7_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 47) - { - X.v[0] += ks[2]; - X.v[1] += ks[3]; - X.v[2] += ks[4]; - X.v[3] += ks[0]; - X.v[4 - 1] += 12; - } - if (Nrounds > 48) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_0_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_0_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 49) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_1_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_1_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 50) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_2_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_2_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 51) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_3_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_3_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 51) - { - X.v[0] += ks[3]; - X.v[1] += ks[4]; - X.v[2] += ks[0]; - X.v[3] += ks[1]; - X.v[4 - 1] += 13; - } - if (Nrounds > 52) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_4_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_4_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 53) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_5_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_5_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 54) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_6_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_6_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 55) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_7_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_7_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 55) - { - X.v[0] += ks[4]; - X.v[1] += ks[0]; - X.v[2] += ks[1]; - X.v[3] += ks[2]; - X.v[4 - 1] += 14; - } - if (Nrounds > 56) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_0_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_0_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 57) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_1_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_1_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 58) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_2_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_2_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 59) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_3_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_3_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 59) - { - X.v[0] += ks[0]; - X.v[1] += ks[1]; - X.v[2] += ks[2]; - X.v[3] += ks[3]; - X.v[4 - 1] += 15; - } - if (Nrounds > 60) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_4_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_4_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 61) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_5_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_5_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 62) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_6_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_6_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 63) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_7_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_7_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 63) - { - X.v[0] += ks[1]; - X.v[1] += ks[2]; - X.v[2] += ks[3]; - X.v[3] += ks[4]; - X.v[4 - 1] += 16; - } - if (Nrounds > 64) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_0_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_0_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 65) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_1_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_1_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 66) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_2_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_2_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 67) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_3_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_3_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 67) - { - X.v[0] += ks[2]; - X.v[1] += ks[3]; - X.v[2] += ks[4]; - X.v[3] += ks[0]; - X.v[4 - 1] += 17; - } - if (Nrounds > 68) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_4_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_4_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 69) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_5_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_5_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 70) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_6_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_6_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 71) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_7_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_7_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 71) - { - X.v[0] += ks[3]; - X.v[1] += ks[4]; - X.v[2] += ks[0]; - X.v[3] += ks[1]; - X.v[4 - 1] += 18; - } return X; } enum r123_enum_threefry4x64 From a2452fd1a3bdafa02e38cd8fca1a0eeb7ec21eb1 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 3 Mar 2018 11:26:08 +0000 Subject: [PATCH 017/279] ENH: Add pickle support Add pickle support for RandomGenerator Add pickle support for other core PRNGs --- _randomgen/core_prng/__init__.py | 4 +- _randomgen/core_prng/generator.pyx | 13 ++++++ _randomgen/core_prng/mt19937.pyx | 13 ++++++ _randomgen/core_prng/pickle.py | 62 +++++++++++++++++++++++++++ _randomgen/core_prng/splitmix64.pyx | 14 ++++++ _randomgen/core_prng/threefry.pyx | 14 ++++++ _randomgen/core_prng/xoroshiro128.pyx | 13 ++++++ 7 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 _randomgen/core_prng/pickle.py diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index 8ede7e5f5fe9..6fa8bf8c40c7 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -1,12 +1,14 @@ from .generator import RandomGenerator +from .mt19937 import MT19937 from .splitmix64 import SplitMix64 from .threefry import ThreeFry from .xoroshiro128 import Xoroshiro128 -from .mt19937 import MT19937 __all__ = ['RandomGenerator', 'SplitMix64', 'Xoroshiro128', 'ThreeFry', 'MT19937'] from ._version import get_versions + __version__ = get_versions()['version'] del get_versions + diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index cfed7778a0a0..115ae9b2e3f5 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -10,6 +10,7 @@ except ImportError: from dummy_threading import Lock from core_prng.splitmix64 import SplitMix64 +import core_prng.pickle np.import_array() @@ -50,6 +51,18 @@ cdef class RandomGenerator: self._prng = PyCapsule_GetPointer(capsule, anon_name) self.lock = Lock() + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__generator_ctor, + (self.state['prng'],), + self.state) + @property def state(self): """Get or set the underlying PRNG's state""" diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index e6f59aa2e385..2a9be05100eb 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -7,6 +7,7 @@ import numpy as np cimport numpy as np from common cimport * +import core_prng.pickle from core_prng.entropy import random_entropy np.import_array() @@ -69,6 +70,18 @@ cdef class MT19937: free(self.rng_state) free(self._prng) + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__prng_ctor, + (self.state['prng'],), + self.state) + def __random_integer(self): """ 64-bit Random Integers from the PRNG diff --git a/_randomgen/core_prng/pickle.py b/_randomgen/core_prng/pickle.py new file mode 100644 index 000000000000..e3fede9210b4 --- /dev/null +++ b/_randomgen/core_prng/pickle.py @@ -0,0 +1,62 @@ +from .generator import RandomGenerator +from .mt19937 import MT19937 +from .splitmix64 import SplitMix64 +from .threefry import ThreeFry +from .xoroshiro128 import Xoroshiro128 + +PRNGS = {'SplitMix64': SplitMix64, + 'ThreeFry': ThreeFry, + 'MT19937': MT19937, + 'Xoroshiro128': Xoroshiro128} + + +def __generator_ctor(prng_name='mt19937'): + """ + Pickling helper function that returns a mod_name.RandomState object + + Parameters + ---------- + prng_name: str + String containing the core PRNG + + Returns + ------- + rg: RandomGenerator + RandomGenerator using the named core PRNG + """ + try: + prng_name = prng_name.decode('ascii') + except AttributeError: + pass + if prng_name in PRNGS: + prng = PRNGS[prng_name] + else: + raise ValueError(str(prng_name) + ' is not a known PRNG module.') + + return RandomGenerator(prng()) + + +def __prng_ctor(prng_name='mt19937'): + """ + Pickling helper function that returns a mod_name.RandomState object + + Parameters + ---------- + prng_name: str + String containing the core PRNG + + Returns + ------- + prng: CorePRNG + Core PRNG instance + """ + try: + prng_name = prng_name.decode('ascii') + except AttributeError: + pass + if prng_name in PRNGS: + prng = PRNGS[prng_name] + else: + raise ValueError(str(prng_name) + ' is not a known PRNG module.') + + return prng() diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index 514e9fed9550..a80fe826aa07 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -7,6 +7,7 @@ cimport numpy as np from common cimport * from core_prng.entropy import random_entropy +import core_prng.pickle cimport entropy np.import_array() @@ -66,6 +67,19 @@ cdef class SplitMix64: free(self.rng_state) free(self._prng) + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__prng_ctor, + (self.state['prng'],), + self.state) + + def _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index 961c09f59de5..ae73cd36fe41 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -7,6 +7,7 @@ cimport numpy as np from common cimport * from core_prng.entropy import random_entropy +import core_prng.pickle cimport entropy np.import_array() @@ -77,6 +78,19 @@ cdef class ThreeFry: cdef const char *name = "CorePRNG" self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__prng_ctor, + (self.state['prng'],), + self.state) + + def __dealloc__(self): free(self.rng_state.ctr) free(self.rng_state.key) diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 0cb53f830426..fc24db07d202 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -7,6 +7,7 @@ cimport numpy as np from common cimport * from core_prng.entropy import random_entropy +import core_prng.pickle cimport entropy np.import_array() @@ -64,6 +65,18 @@ cdef class Xoroshiro128: cdef const char *name = "CorePRNG" self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__prng_ctor, + (self.state['prng'],), + self.state) + def __dealloc__(self): free(self.rng_state) free(self._prng) From 30cee9ba744400ee3c9002e49138a2c93ac2e677 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 3 Mar 2018 11:56:14 +0000 Subject: [PATCH 018/279] DOC: Add list of TODOs List contains major next steps --- _randomgen/TODO.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 _randomgen/TODO.md diff --git a/_randomgen/TODO.md b/_randomgen/TODO.md new file mode 100644 index 000000000000..a2e48fabc766 --- /dev/null +++ b/_randomgen/TODO.md @@ -0,0 +1,20 @@ +# TODO +0. Use inheritance to simplify CorePRNG structure. The natural base is + xoroshiro128. +1. Add PCG64 +2. Add dSFMT +3. Add xorshift2014 +4. Augment state to include has_gauss and gauss +5. Augment state to have binomial structure +6. Port over 0 parameter distributions + * standard exponential float + * standard exponential ziggurat + * standard exponential ziggurat float + * standard normal + * standard normal float + * standard normal ziggurat + * standard normal ziggurat float + * standard gamma + * standard gamma float +7. Remove SplitMix64 as an external generator +8. Restore ability to use `out` in core distributions From 259829ab2d69874880d53f09586a7bd32517852c Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 3 Mar 2018 13:06:58 +0000 Subject: [PATCH 019/279] BIG: Fix setting state in threee fry --- _randomgen/TODO.md | 2 ++ _randomgen/core_prng/threefry.pyx | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/_randomgen/TODO.md b/_randomgen/TODO.md index a2e48fabc766..dc093f4dca4d 100644 --- a/_randomgen/TODO.md +++ b/_randomgen/TODO.md @@ -18,3 +18,5 @@ * standard gamma float 7. Remove SplitMix64 as an external generator 8. Restore ability to use `out` in core distributions +9. Add correct carry for ThreeFry to allow full set of counters. Important when implmenting jump + diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index ae73cd36fe41..3279c23016a9 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -90,7 +90,6 @@ cdef class ThreeFry: (self.state['prng'],), self.state) - def __dealloc__(self): free(self.rng_state.ctr) free(self.rng_state.key) @@ -174,7 +173,7 @@ cdef class ThreeFry: ctr[i] = self.rng_state.ctr.v[i] key[i] = self.rng_state.key.v[i] buffer[i] = self.rng_state.buffer[i] - state = {'ctr':ctr,'k':key} + state = {'ctr':ctr,'key':key} return {'prng': self.__class__.__name__, 'state': state, 'buffer': buffer, @@ -193,7 +192,7 @@ cdef class ThreeFry: for i in range(4): self.rng_state.ctr.v[i] = value['state']['ctr'][i] self.rng_state.key.v[i] = value['state']['key'][i] - self.rng_state.buffer[i] = value['state']['buffer'][i] + self.rng_state.buffer[i] = value['buffer'][i] self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] self.rng_state.buffer_pos = value['buffer_pos'] From c080eaaec257e33a2d64726c4cac5b6ed104ace8 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 3 Mar 2018 21:51:23 +0000 Subject: [PATCH 020/279] ENH: Add jump and advance to threefry Add jump (2**128) and advance (arbitrary) to threefry --- _randomgen/TODO.md | 3 +- _randomgen/core_prng/mt19937.pyx | 12 +- _randomgen/core_prng/splitmix64.pyx | 6 +- _randomgen/core_prng/src/threefry/threefry.c | 26 +- _randomgen/core_prng/src/threefry/threefry.h | 559 +++++++++---------- _randomgen/core_prng/threefry.pyx | 28 +- _randomgen/core_prng/xoroshiro128.pyx | 8 +- 7 files changed, 333 insertions(+), 309 deletions(-) diff --git a/_randomgen/TODO.md b/_randomgen/TODO.md index dc093f4dca4d..5ba92ab4ef75 100644 --- a/_randomgen/TODO.md +++ b/_randomgen/TODO.md @@ -18,5 +18,6 @@ * standard gamma float 7. Remove SplitMix64 as an external generator 8. Restore ability to use `out` in core distributions -9. Add correct carry for ThreeFry to allow full set of counters. Important when implmenting jump +## Done +9. Add correct carry for ThreeFry to allow full set of counters. Important when implemeting jump diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index 2a9be05100eb..6c2f4c5786e2 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -14,17 +14,17 @@ np.import_array() cdef extern from "src/mt19937/mt19937.h": - cdef struct s_mt19937_state: + struct s_mt19937_state: uint32_t key[624] int pos ctypedef s_mt19937_state mt19937_state - cdef uint64_t mt19937_next64(mt19937_state *state) nogil - cdef uint32_t mt19937_next32(mt19937_state *state) nogil - cdef double mt19937_next_double(mt19937_state *state) nogil - cdef void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, int key_length) - cdef void mt19937_seed(mt19937_state *state, uint32_t seed) + uint64_t mt19937_next64(mt19937_state *state) nogil + uint32_t mt19937_next32(mt19937_state *state) nogil + double mt19937_next_double(mt19937_state *state) nogil + void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, int key_length) + void mt19937_seed(mt19937_state *state, uint32_t seed) cdef uint64_t mt19937_uint64(void *st) nogil: return mt19937_next64( st) diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index a80fe826aa07..515f68884bb8 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -13,15 +13,15 @@ cimport entropy np.import_array() cdef extern from "src/splitmix64/splitmix64.h": - cdef struct s_splitmix64_state: + struct s_splitmix64_state: uint64_t state int has_uint32 uint32_t uinteger ctypedef s_splitmix64_state splitmix64_state - cdef uint64_t splitmix64_next64(splitmix64_state *state) nogil - cdef uint32_t splitmix64_next32(splitmix64_state *state) nogil + uint64_t splitmix64_next64(splitmix64_state *state) nogil + uint32_t splitmix64_next32(splitmix64_state *state) nogil cdef uint64_t splitmix64_uint64(void *st) nogil: return splitmix64_next64( st) diff --git a/_randomgen/core_prng/src/threefry/threefry.c b/_randomgen/core_prng/src/threefry/threefry.c index 3a2f00d13005..069ac5356d9a 100644 --- a/_randomgen/core_prng/src/threefry/threefry.c +++ b/_randomgen/core_prng/src/threefry/threefry.c @@ -35,4 +35,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern inline uint64_t threefry_next64(threefry_state *state); -extern inline uint64_t threefry_next32(threefry_state *state); \ No newline at end of file +extern inline uint64_t threefry_next32(threefry_state *state); + +extern void threefry_jump(threefry_state *state) { + /* Advances state as-if 2^128 draws were made */ + state->ctr->v[2]++; + if (state->ctr->v[2] == 0) { + state->ctr->v[3]++; + } +} + +extern void threefry_advance(uint64_t *step, threefry_state *state) { + int i, carry = 0; + uint64_t v_orig; + for (i = 0; i < 4; i++) { + if (carry == 1) { + state->ctr->v[i]++; + carry = state->ctr->v[i] == 0 ? 1 : 0; + } + v_orig = state->ctr->v[i]; + state->ctr->v[i] += step[i]; + if (state->ctr->v[i] < v_orig && carry == 0) { + carry = 1; + } + } +} diff --git a/_randomgen/core_prng/src/threefry/threefry.h b/_randomgen/core_prng/src/threefry/threefry.h index 5e0a720ffe1b..35a3be53f576 100644 --- a/_randomgen/core_prng/src/threefry/threefry.h +++ b/_randomgen/core_prng/src/threefry/threefry.h @@ -4,296 +4,265 @@ Adapted from random123's threefry.h #include -enum r123_enum_threefry64x4 -{ - /* These are the R_256 constants from the Threefish reference sources - with names changed to R_64x4... */ - R_64x4_0_0 = 14, - R_64x4_0_1 = 16, - R_64x4_1_0 = 52, - R_64x4_1_1 = 57, - R_64x4_2_0 = 23, - R_64x4_2_1 = 40, - R_64x4_3_0 = 5, - R_64x4_3_1 = 37, - R_64x4_4_0 = 25, - R_64x4_4_1 = 33, - R_64x4_5_0 = 46, - R_64x4_5_1 = 12, - R_64x4_6_0 = 58, - R_64x4_6_1 = 22, - R_64x4_7_0 = 32, - R_64x4_7_1 = 32 +enum r123_enum_threefry64x4 { + /* These are the R_256 constants from the Threefish reference sources + with names changed to R_64x4... */ + R_64x4_0_0 = 14, + R_64x4_0_1 = 16, + R_64x4_1_0 = 52, + R_64x4_1_1 = 57, + R_64x4_2_0 = 23, + R_64x4_2_1 = 40, + R_64x4_3_0 = 5, + R_64x4_3_1 = 37, + R_64x4_4_0 = 25, + R_64x4_4_1 = 33, + R_64x4_5_0 = 46, + R_64x4_5_1 = 12, + R_64x4_6_0 = 58, + R_64x4_6_1 = 22, + R_64x4_7_0 = 32, + R_64x4_7_1 = 32 }; -struct r123array4x64 -{ - uint64_t v[4]; +struct r123array4x64 { + uint64_t v[4]; }; /* r123array4x64 */ typedef struct r123array4x64 threefry4x64_key_t; typedef struct r123array4x64 threefry4x64_ctr_t; static inline uint64_t RotL_64(uint64_t x, unsigned int N); -static inline uint64_t RotL_64(uint64_t x, unsigned int N) -{ - return (x << (N & 63)) | (x >> ((64 - N) & 63)); +static inline uint64_t RotL_64(uint64_t x, unsigned int N) { + return (x << (N & 63)) | (x >> ((64 - N) & 63)); } - -static inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry4x64_ctr_t in, threefry4x64_key_t k); -static inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry4x64_ctr_t in, threefry4x64_key_t k) -{ - threefry4x64_ctr_t X; - uint64_t ks[4 + 1]; - int i; - ks[4] = ((0xA9FC1A22) + (((uint64_t)(0x1BD11BDA)) << 32)); - for (i = 0; i < 4; i++) - { - ks[i] = k.v[i]; - X.v[i] = in.v[i]; - ks[4] ^= k.v[i]; - } +static inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, + threefry4x64_ctr_t in, + threefry4x64_key_t k); +static inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, + threefry4x64_ctr_t in, + threefry4x64_key_t k) { + threefry4x64_ctr_t X; + uint64_t ks[4 + 1]; + int i; + ks[4] = ((0xA9FC1A22) + (((uint64_t)(0x1BD11BDA)) << 32)); + for (i = 0; i < 4; i++) { + ks[i] = k.v[i]; + X.v[i] = in.v[i]; + ks[4] ^= k.v[i]; + } + X.v[0] += ks[0]; + X.v[1] += ks[1]; + X.v[2] += ks[2]; + X.v[3] += ks[3]; + if (Nrounds > 0) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 1) { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 2) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 3) { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 3) { + X.v[0] += ks[1]; + X.v[1] += ks[2]; + X.v[2] += ks[3]; + X.v[3] += ks[4]; + X.v[4 - 1] += 1; + } + if (Nrounds > 4) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 5) { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 6) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 7) { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 7) { + X.v[0] += ks[2]; + X.v[1] += ks[3]; + X.v[2] += ks[4]; + X.v[3] += ks[0]; + X.v[4 - 1] += 2; + } + if (Nrounds > 8) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 9) { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 10) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 11) { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 11) { + X.v[0] += ks[3]; + X.v[1] += ks[4]; + X.v[2] += ks[0]; + X.v[3] += ks[1]; + X.v[4 - 1] += 3; + } + if (Nrounds > 12) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 13) { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 14) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 15) { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 15) { + X.v[0] += ks[4]; + X.v[1] += ks[0]; + X.v[2] += ks[1]; + X.v[3] += ks[2]; + X.v[4 - 1] += 4; + } + if (Nrounds > 16) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 17) { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 18) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 19) { + X.v[0] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 19) { X.v[0] += ks[0]; X.v[1] += ks[1]; X.v[2] += ks[2]; X.v[3] += ks[3]; - if (Nrounds > 0) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_0_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_0_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 1) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_1_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_1_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 2) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_2_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_2_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 3) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_3_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_3_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 3) - { - X.v[0] += ks[1]; - X.v[1] += ks[2]; - X.v[2] += ks[3]; - X.v[3] += ks[4]; - X.v[4 - 1] += 1; - } - if (Nrounds > 4) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_4_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_4_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 5) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_5_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_5_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 6) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_6_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_6_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 7) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_7_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_7_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 7) - { - X.v[0] += ks[2]; - X.v[1] += ks[3]; - X.v[2] += ks[4]; - X.v[3] += ks[0]; - X.v[4 - 1] += 2; - } - if (Nrounds > 8) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_0_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_0_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 9) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_1_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_1_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 10) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_2_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_2_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 11) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_3_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_3_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 11) - { - X.v[0] += ks[3]; - X.v[1] += ks[4]; - X.v[2] += ks[0]; - X.v[3] += ks[1]; - X.v[4 - 1] += 3; - } - if (Nrounds > 12) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_4_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_4_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 13) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_5_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_5_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 14) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_6_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_6_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 15) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_7_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_7_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 15) - { - X.v[0] += ks[4]; - X.v[1] += ks[0]; - X.v[2] += ks[1]; - X.v[3] += ks[2]; - X.v[4 - 1] += 4; - } - if (Nrounds > 16) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_0_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_0_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 17) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_1_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_1_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 18) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_2_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_2_1); - X.v[3] ^= X.v[2]; - } - if (Nrounds > 19) - { - X.v[0] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_3_0); - X.v[3] ^= X.v[0]; - X.v[2] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_3_1); - X.v[1] ^= X.v[2]; - } - if (Nrounds > 19) - { - X.v[0] += ks[0]; - X.v[1] += ks[1]; - X.v[2] += ks[2]; - X.v[3] += ks[3]; - X.v[4 - 1] += 5; - } - /* Maximum of 20 rounds */ - if (Nrounds > 20) - { - X.v[0] += X.v[1]; - X.v[1] = RotL_64(X.v[1], R_64x4_4_0); - X.v[1] ^= X.v[0]; - X.v[2] += X.v[3]; - X.v[3] = RotL_64(X.v[3], R_64x4_4_1); - X.v[3] ^= X.v[2]; - } - return X; + X.v[4 - 1] += 5; + } + /* Maximum of 20 rounds */ + if (Nrounds > 20) { + X.v[0] += X.v[1]; + X.v[1] = RotL_64(X.v[1], R_64x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_64(X.v[3], R_64x4_4_1); + X.v[3] ^= X.v[2]; + } + return X; } -enum r123_enum_threefry4x64 -{ - threefry4x64_rounds = 20 -}; +enum r123_enum_threefry4x64 { threefry4x64_rounds = 20 }; typedef struct s_threefry_state { threefry4x64_key_t *ctr; @@ -304,23 +273,33 @@ typedef struct s_threefry_state { uint32_t uinteger; } threefry_state; - static inline uint64_t threefry_next(threefry_state *state) { /* TODO: This 4 should be a constant somewhere */ - if (state->buffer_pos >= 4) { - /* generate 4 new uint64_t */ - int i; - threefry4x64_ctr_t ct; - state->ctr->v[0]++; - ct = threefry4x64_R(threefry4x64_rounds, *state->ctr, *state->key); - for (i=0; i<4; i++){ - state->buffer[i] = ct.v[i]; + if (state->buffer_pos < 4) { + uint64_t out = state->buffer[state->buffer_pos]; + state->buffer_pos++; + return out; + } + /* generate 4 new uint64_t */ + int i; + threefry4x64_ctr_t ct; + state->ctr->v[0]++; + /* Handle carry */ + if (state->ctr->v[0] == 0) { + state->ctr->v[1]++; + if (state->ctr->v[1] == 0) { + state->ctr->v[2]++; + if (state->ctr->v[2] == 0) { + state->ctr->v[3]++; + } } - state->buffer_pos = 0; } - uint64_t out = state->buffer[state->buffer_pos]; - state->buffer_pos++; - return out; + ct = threefry4x64_R(threefry4x64_rounds, *state->ctr, *state->key); + for (i = 0; i < 4; i++) { + state->buffer[i] = ct.v[i]; + } + state->buffer_pos = 1; + return state->buffer[0]; } static inline uint64_t threefry_next64(threefry_state *state) { @@ -339,3 +318,7 @@ static inline uint64_t threefry_next32(threefry_state *state) { return (uint32_t)(next >> 32); } + +extern void threefry_jump(threefry_state *state); + +extern void threefry_advance(uint64_t *step, threefry_state *state); diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index 3279c23016a9..ede7e7caefbb 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -1,4 +1,3 @@ -from libc.stdint cimport uint32_t, uint64_t from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New @@ -13,8 +12,7 @@ cimport entropy np.import_array() cdef extern from "src/threefry/threefry.h": - - cdef struct s_r123array4x64: + struct s_r123array4x64: uint64_t v[4] ctypedef s_r123array4x64 r123array4x64 @@ -22,7 +20,7 @@ cdef extern from "src/threefry/threefry.h": ctypedef r123array4x64 threefry4x64_key_t ctypedef r123array4x64 threefry4x64_ctr_t - cdef struct s_threefry_state: + struct s_threefry_state: threefry4x64_key_t *ctr; threefry4x64_ctr_t *key; int buffer_pos; @@ -32,8 +30,10 @@ cdef extern from "src/threefry/threefry.h": ctypedef s_threefry_state threefry_state - cdef uint64_t threefry_next64(threefry_state *state) nogil - cdef uint64_t threefry_next32(threefry_state *state) nogil + uint64_t threefry_next64(threefry_state *state) nogil + uint64_t threefry_next32(threefry_state *state) nogil + void threefry_jump(threefry_state *state) + void threefry_advance(uint64_t *step, threefry_state *state) cdef uint64_t threefry_uint64(void* st) nogil: @@ -196,3 +196,19 @@ cdef class ThreeFry: self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] self.rng_state.buffer_pos = value['buffer_pos'] + + def jump(self): + """Jump the state as-if 2**128 draws have been made""" + threefry_jump(self.rng_state) + + def advance(self, step): + """Advance the state as-if a specific number of draws have been made""" + cdef np.ndarray step_a = np.zeros(4,dtype=np.uint64) + if step >= 2**256 or step < 0: + raise ValueError('step must be between 0 and 2**256-1') + loc = 0 + while step > 0: + step_a[loc] = step % 2**64 + step >>= 64 + loc += 1 + threefry_advance(step_a.data, self.rng_state) diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index fc24db07d202..69ce93c31f84 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -14,16 +14,16 @@ np.import_array() cdef extern from "src/xoroshiro128/xoroshiro128.h": - cdef struct s_xoroshiro128_state: + struct s_xoroshiro128_state: uint64_t s[2] int has_uint32 uint32_t uinteger ctypedef s_xoroshiro128_state xoroshiro128_state - cdef uint64_t xoroshiro128_next64(xoroshiro128_state *state) nogil - cdef uint64_t xoroshiro128_next32(xoroshiro128_state *state) nogil - cdef void xoroshiro128_jump(xoroshiro128_state *state) + uint64_t xoroshiro128_next64(xoroshiro128_state *state) nogil + uint64_t xoroshiro128_next32(xoroshiro128_state *state) nogil + void xoroshiro128_jump(xoroshiro128_state *state) cdef uint64_t xoroshiro128_uint64(void* st):# nogil: return xoroshiro128_next64(st) From b42f38d8c1fabb4a8c31230f4bb15a77e3b1c488 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 4 Mar 2018 21:36:13 +0000 Subject: [PATCH 021/279] ENH: Add PCG64 Add PCG64 generator --- _randomgen/TODO.md | 27 +- _randomgen/core_prng/__init__.py | 7 +- _randomgen/core_prng/common.pxd | 12 +- _randomgen/core_prng/generator.pyx | 106 +- _randomgen/core_prng/pcg64.pyx | 188 +++ .../src/distributions/distributions.c | 110 +- .../src/distributions/distributions.h | 15 +- .../core_prng/src/distributions/ziggurat.h | 276 ++++ .../src/distributions/ziggurat_constants.h | 1196 +++++++++++++++++ _randomgen/core_prng/src/pcg64/pcg64.c | 92 ++ _randomgen/core_prng/src/pcg64/pcg64.h | 237 ++++ .../core_prng/src/xorshift1024/xorshift1024.c | 31 + .../core_prng/src/xorshift1024/xorshift1024.h | 33 + .../src/xorshift1024/xorshift2014.orig.c | 69 + _randomgen/core_prng/xorshift1024.pyx | 174 +++ _randomgen/demo.py | 7 +- _randomgen/setup.py | 13 + 17 files changed, 2557 insertions(+), 36 deletions(-) create mode 100644 _randomgen/core_prng/pcg64.pyx create mode 100644 _randomgen/core_prng/src/distributions/ziggurat.h create mode 100644 _randomgen/core_prng/src/distributions/ziggurat_constants.h create mode 100644 _randomgen/core_prng/src/pcg64/pcg64.c create mode 100644 _randomgen/core_prng/src/pcg64/pcg64.h create mode 100644 _randomgen/core_prng/src/xorshift1024/xorshift1024.c create mode 100644 _randomgen/core_prng/src/xorshift1024/xorshift1024.h create mode 100644 _randomgen/core_prng/src/xorshift1024/xorshift2014.orig.c create mode 100644 _randomgen/core_prng/xorshift1024.pyx diff --git a/_randomgen/TODO.md b/_randomgen/TODO.md index 5ba92ab4ef75..fac0a525c94d 100644 --- a/_randomgen/TODO.md +++ b/_randomgen/TODO.md @@ -1,23 +1,28 @@ # TODO -0. Use inheritance to simplify CorePRNG structure. The natural base is - xoroshiro128. -1. Add PCG64 2. Add dSFMT -3. Add xorshift2014 -4. Augment state to include has_gauss and gauss 5. Augment state to have binomial structure 6. Port over 0 parameter distributions - * standard exponential float - * standard exponential ziggurat * standard exponential ziggurat float - * standard normal - * standard normal float * standard normal ziggurat * standard normal ziggurat float - * standard gamma - * standard gamma float 7. Remove SplitMix64 as an external generator 8. Restore ability to use `out` in core distributions +10. Seed/Inc for PCG64 +11. Advance/Jump for PCG64 +12. Key/Counter for ThreeFry ## Done +1. Add PCG64 +3. Add xorshift2014 +4. Augment state to include has_gauss and gauss +6. Port over 0 parameter distributions + * standard exponential ziggurat + * standard exponential float + * standard normal + * standard normal float + * standard gamma - Not implement: This is a 1 param + * standard gamma float - Not implement: This is a 1 param + 9. Add correct carry for ThreeFry to allow full set of counters. Important when implemeting jump +0. NOT IMPLEMENTABLE due to limits on inheritance in Cython: Use inheritance to simplify CorePRNG structure. The natural base is + xoroshiro128. diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index 6fa8bf8c40c7..c6123e023d03 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -1,14 +1,15 @@ from .generator import RandomGenerator from .mt19937 import MT19937 +from .pcg64 import PCG64 from .splitmix64 import SplitMix64 from .threefry import ThreeFry from .xoroshiro128 import Xoroshiro128 +from .xorshift1024 import XorShift1024 -__all__ = ['RandomGenerator', 'SplitMix64', 'Xoroshiro128', 'ThreeFry', - 'MT19937'] +__all__ = ['RandomGenerator', 'SplitMix64', 'PCG64', 'Xoroshiro128', + 'ThreeFry', 'MT19937', 'XorShift1024'] from ._version import get_versions __version__ = get_versions()['version'] del get_versions - diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index 21bab5df3176..b761cc037658 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -6,10 +6,14 @@ cdef extern from "src/distributions/distributions.h": ctypedef float (*random_float_0)(void *st) nogil cdef struct prng: - void *state - uint64_t (*next_uint64)(void *st) - uint32_t (*next_uint32)(void *st) - double (*next_double)(void *st) + void *state + uint64_t (*next_uint64)(void *st) + uint32_t (*next_uint32)(void *st) + double (*next_double)(void *st) + int has_gauss + double gauss + int has_gauss_f + float gauss_f ctypedef prng prng_t diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 115ae9b2e3f5..29b364270ade 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -1,9 +1,14 @@ -from libc.stdint cimport uint64_t, uint32_t import numpy as np cimport numpy as np from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from common cimport * -cimport common + +cimport numpy as np +import numpy as np +from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer + +from common cimport * + try: from threading import Lock except ImportError: @@ -15,10 +20,13 @@ import core_prng.pickle np.import_array() cdef extern from "src/distributions/distributions.h": - double random_double(void *void_state) nogil - float random_float(void *void_state) nogil - uint32_t random_uint32(void *void_state) nogil - double random_standard_exponential(void *void_state) nogil + double random_double(prng_t *prng_state) nogil + float random_float(prng_t *prng_state) nogil + uint32_t random_uint32(prng_t *prng_state) nogil + double random_standard_exponential(prng_t *prng_state) nogil + float random_standard_exponential_float(prng_t *prng_state) nogil + double random_gauss(prng_t *prng_state) + float random_gauss_float(prng_t *prng_state) cdef class RandomGenerator: """ @@ -48,8 +56,11 @@ cdef class RandomGenerator: cdef const char *anon_name = "CorePRNG" if not PyCapsule_IsValid(capsule, anon_name): raise ValueError("Invalid pointer to anon_func_state") - self._prng = PyCapsule_GetPointer(capsule, anon_name) + self._prng = PyCapsule_GetPointer(capsule, anon_name) self.lock = Lock() + with self.lock: + self._prng.has_gauss = 0 + self._prng.has_gauss_f = 0 # Pickling support: def __getstate__(self): @@ -66,25 +77,34 @@ cdef class RandomGenerator: @property def state(self): """Get or set the underlying PRNG's state""" - return self.__core_prng.state + state = self.__core_prng.state + state['has_gauss'] = self._prng.has_gauss + state['has_gauss_f'] = self._prng.has_gauss_f + state['gauss'] = self._prng.gauss + state['gauss_f'] = self._prng.gauss_f + return state @state.setter def state(self, value): + self._prng.has_gauss = value['has_gauss'] + self._prng.has_gauss_f = value['has_gauss_f'] + self._prng.gauss = value['gauss'] + self._prng.gauss_f = value['gauss_f'] self.__core_prng.state = value def random_integer(self, bits=64): #print("In random_integer") - if bits==64: + if bits == 64: return self._prng.next_uint64(self._prng.state) - elif bits==32: + elif bits == 32: return random_uint32(self._prng) else: raise ValueError('bits must be 32 or 64') def random_double(self, bits=64): - if bits==64: + if bits == 64: return self._prng.next_double(self._prng.state) - elif bits==32: + elif bits == 32: return random_float(self._prng) else: raise ValueError('bits must be 32 or 64') @@ -143,7 +163,6 @@ cdef class RandomGenerator: else: raise TypeError('Unsupported dtype "%s" for random_sample' % key) - def standard_exponential(self, size=None, dtype=np.float64): """ standard_exponential(size=None, dtype='d', method='inv', out=None) @@ -179,7 +198,66 @@ cdef class RandomGenerator: if key == 'float64': return double_fill(&random_standard_exponential, self._prng, size, self.lock) elif key == 'float32': - return float_fill_from_double(&random_standard_exponential, self._prng, size, self.lock) + return float_fill(&random_standard_exponential_float, self._prng, size, self.lock) else: raise TypeError('Unsupported dtype "%s" for standard_exponential' % key) + + # Complicated, continuous distributions: + def standard_normal(self, size=None, dtype=np.float64, method='bm'): + """ + standard_normal(size=None, dtype='d', method='bm', out=None) + + Draw samples from a standard Normal distribution (mean=0, stdev=1). + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + dtype : {str, dtype}, optional + Desired dtype of the result, either 'd' (or 'float64') or 'f' + (or 'float32'). All dtypes are determined by their name. The + default value is 'd'. + method : str, optional + Either 'bm' or 'zig'. 'bm' uses the default Box-Muller transformations + method. 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. + out : ndarray, optional + Alternative output array in which to place the result. If size is not None, + it must have the same shape as the provided size and must match the type of + the output values. + + Returns + ------- + out : float or ndarray + Drawn samples. + + Examples + -------- + >>> s = np.random.standard_normal(8000) + >>> s + array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random + -0.38672696, -0.4685006 ]) #random + >>> s.shape + (8000,) + >>> s = np.random.standard_normal(size=(3, 4, 2)) + >>> s.shape + (3, 4, 2) + + """ + key = np.dtype(dtype).name + if key == 'float64': + if method == u'zig': + raise NotImplementedError + #return double_fill(&self.rng_state, &random_gauss_zig_double_fill, size, self.lock, out) + else: + return double_fill(&random_gauss, self._prng, size, self.lock) + elif key == 'float32': + if method == u'zig': + raise NotImplementedError + #return float_fill(&self.rng_state, &random_gauss_zig_float_fill, size, self.lock, out) + else: + return float_fill(&random_gauss_float, self._prng, size, self.lock) + else: + raise TypeError('Unsupported dtype "%s" for standard_normal' % key) diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx new file mode 100644 index 000000000000..543202b1293e --- /dev/null +++ b/_randomgen/core_prng/pcg64.pyx @@ -0,0 +1,188 @@ +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + +import numpy as np +cimport numpy as np + +from common cimport * +from core_prng.entropy import random_entropy +import core_prng.pickle +cimport entropy + +np.import_array() + +cdef extern from "src/pcg64/pcg64.h": + + ctypedef struct pcg128_t: + uint64_t high + uint64_t low + + cdef struct pcg_state_setseq_128: + pcg128_t state + pcg128_t inc + + ctypedef pcg_state_setseq_128 pcg64_random_t + + struct s_pcg64_state: + pcg64_random_t *pcg_state + int has_uint32 + uint32_t uinteger + + ctypedef s_pcg64_state pcg64_state + + uint64_t pcg64_next64(pcg64_state *state) nogil + uint64_t pcg64_next32(pcg64_state *state) nogil + void pcg64_jump(pcg64_state *state) + + +cdef uint64_t pcg64_uint64(void* st):# nogil: + return pcg64_next64(st) + +cdef uint32_t pcg64_uint32(void *st) nogil: + return pcg64_next32( st) + +cdef double pcg64_double(void* st) nogil: + return uint64_to_double(pcg64_next64(st)) + +cdef class PCG64: + """ + Prototype Core PRNG using pcg64 + + Parameters + ---------- + seed : int, array of int + Integer or array of integers between 0 and 2**64 - 1 + + Notes + ----- + Exposes no user-facing API except `get_state` and `set_state`. Designed + for use in a `RandomGenerator` object. + """ + cdef pcg64_state *rng_state + cdef prng_t *_prng + cdef public object _prng_capsule + + def __init__(self, seed=None): + self.rng_state = malloc(sizeof(pcg64_state)) + self.rng_state.pcg_state = malloc(sizeof(pcg64_random_t)) + self._prng = malloc(sizeof(prng_t)) + self.seed(seed) + + self._prng.state = self.rng_state + self._prng.next_uint64 = &pcg64_uint64 + self._prng.next_uint32 = &pcg64_uint32 + self._prng.next_double = &pcg64_double + + self.rng_state.pcg_state.inc.high = 0 + self.rng_state.pcg_state.inc.low = 1 + + cdef const char *name = "CorePRNG" + self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__prng_ctor, + (self.state['prng'],), + self.state) + + def __dealloc__(self): + free(self.rng_state) + free(self._prng) + + def _reset_state_variables(self): + self.rng_state.has_uint32 = 0 + self.rng_state.uinteger = 0 + + def __random_integer(self, bits=64): + """ + 64-bit Random Integers from the PRNG + + Parameters + ---------- + bits : {32, 64} + Number of random bits to return + + Returns + ------- + rv : int + Next random value + + Notes + ----- + Testing only + """ + if bits == 64: + return self._prng.next_uint64(self._prng.state) + elif bits == 32: + return self._prng.next_uint32(self._prng.state) + else: + raise ValueError('bits must be 32 or 64') + + def seed(self, seed=None): + """ + seed(seed=None, stream=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + + """ + ub = 2 ** 64 + if seed is None: + try: + state = random_entropy(4) + except RuntimeError: + state = random_entropy(4, 'fallback') + state = state.view(np.uint64) + else: + state = entropy.seed_by_array(seed, 2) + self.rng_state.pcg_state.state.high = int(state[0]) + self.rng_state.pcg_state.state.low = int(state[1]) + self._reset_state_variables() + + @property + def state(self): + """Get or set the PRNG state""" + state = 2 **64 * self.rng_state.pcg_state.state.high + state += self.rng_state.pcg_state.state.low + inc = 2 **64 * self.rng_state.pcg_state.inc.high + inc += self.rng_state.pcg_state.inc.low + + return {'prng': self.__class__.__name__, + 'state': {'state': state, 'inc':inc}, + 'has_uint32': self.rng_state.has_uint32, + 'uinteger': self.rng_state.uinteger} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + prng = value.get('prng', '') + if prng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + + self.rng_state.pcg_state.state.high = value['state']['state'] // 2 ** 64 + self.rng_state.pcg_state.state.low = value['state']['state'] % 2 ** 64 + self.rng_state.pcg_state.inc.high = value['state']['inc'] // 2 ** 64 + self.rng_state.pcg_state.inc.low = value['state']['inc'] % 2 ** 64 + self.rng_state.has_uint32 = value['has_uint32'] + self.rng_state.uinteger = value['uinteger'] diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index d09c49450295..6c19ad020581 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -1,12 +1,18 @@ #include "distributions.h" +#include "ziggurat.h" +#include "ziggurat_constants.h" + +static NPY_INLINE float uint32_to_float(prng_t *prng_state) +{ + return (prng_state->next_uint32(prng_state->state) >> 9) * (1.0f / 8388608.0f); +} uint32_t random_uint32(prng_t *prng_state) { return prng_state->next_uint32(prng_state->state); } float random_float(prng_t *prng_state) { - uint32_t next_32 = prng_state->next_uint32(prng_state->state); - return (next_32 >> 9) * (1.0f / 8388608.0f); + return uint32_to_float(prng_state); } double random_double(prng_t *prng_state) { @@ -16,3 +22,103 @@ double random_double(prng_t *prng_state) { double random_standard_exponential(prng_t *prng_state) { return -log(1.0 - prng_state->next_double(prng_state->state)); } + +float random_standard_exponential_float(prng_t *prng_state) { + return -logf(1.0f - uint32_to_float(prng_state)); +} + +double random_gauss(prng_t *prng_state) +{ + if (prng_state->has_gauss) + { + const double temp = prng_state->gauss; + prng_state->has_gauss = false; + return temp; + } + else + { + double f, x1, x2, r2; + + do + { + x1 = 2.0 * prng_state->next_double(prng_state->state) - 1.0; + x2 = 2.0 * prng_state->next_double(prng_state->state) - 1.0; + r2 = x1 * x1 + x2 * x2; + } while (r2 >= 1.0 || r2 == 0.0); + + /* Box-Muller transform */ + f = sqrt(-2.0 * log(r2) / r2); + /* Keep for next call */ + prng_state->gauss = f * x1; + prng_state->has_gauss = true; + return f * x2; + } +} + +float random_gauss_float(prng_t *prng_state) +{ + if (prng_state->has_gauss_f) + { + const float temp = prng_state->gauss_f; + prng_state->has_gauss_f = false; + return temp; + } + else + { + float f, x1, x2, r2; + + do + { + x1 = 2.0f * uint32_to_float(prng_state) - 1.0f; + x2 = 2.0f * uint32_to_float(prng_state) - 1.0f; + r2 = x1 * x1 + x2 * x2; + } while (r2 >= 1.0 || r2 == 0.0); + + /* Box-Muller transform */ + f = sqrtf(-2.0f * logf(r2) / r2); + /* Keep for next call */ + prng_state->gauss_f = f * x1; + prng_state->has_gauss_f = true; + return f * x2; + } +} + +double standard_exponential_zig_double(prng_t *prng_state); + +static double standard_exponential_zig_double_unlikely(prng_t *prng_state, uint8_t idx, double x) +{ + if (idx == 0) + { + return ziggurat_exp_r - log(random_double(prng_state)); + } + else if ((fe_double[idx - 1] - fe_double[idx]) * random_double(prng_state) + fe_double[idx] < exp(-x)) + { + return x; + } + else + { + return standard_exponential_zig_double(prng_state); + } +} + +double standard_exponential_zig_double(prng_t *prng_state) +{ + uint64_t ri; + uint8_t idx; + double x; + ri = prng_state->next_uint64(prng_state->state); + ri >>= 3; + idx = ri & 0xFF; + ri >>= 8; + x = ri * we_double[idx]; + if (ri < ke_double[idx]) + { + return x; // 98.9% of the time we return here 1st try + } + return standard_exponential_zig_double_unlikely(prng_state, idx, x); +} + +double random_standard_exponential_zig_double(prng_t *prng_state) +{ + return standard_exponential_zig_double(prng_state); +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index c5ac4d577f3d..7c029fe60e02 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -15,6 +15,7 @@ typedef int bool; #endif #include +#include "numpy/npy_common.h" typedef double (*random_double_0)(void *st); typedef float (*random_float_0)(void *st); @@ -24,6 +25,10 @@ typedef struct prng { uint64_t (*next_uint64)(void *st); uint32_t (*next_uint32)(void *st); double (*next_double)(void *st); + int has_gauss; + double gauss; + int has_gauss_f; + float gauss_f; } prng_t; float random_float(prng_t *prng_state); @@ -32,4 +37,12 @@ double random_double(prng_t *prng_state); uint32_t random_uint32(prng_t *prng_state); -double random_standard_exponential(prng_t *prng_state); \ No newline at end of file +double random_standard_exponential(prng_t *prng_state); + +float random_standard_exponential_float(prng_t *prng_state); + +double random_gauss(prng_t *prng_state); + +float random_gauss_float(prng_t *prng_state); + +double random_standard_exponential_zig_double(prng_t *prng_state); \ No newline at end of file diff --git a/_randomgen/core_prng/src/distributions/ziggurat.h b/_randomgen/core_prng/src/distributions/ziggurat.h new file mode 100644 index 000000000000..7808c0e68fea --- /dev/null +++ b/_randomgen/core_prng/src/distributions/ziggurat.h @@ -0,0 +1,276 @@ +/* + * Constants from Julia's Ziggurat implementation + */ + +static const uint64_t ki[] = { + 0x0007799ec012f7b2, 0x0000000000000000, 0x0006045f4c7de363, + 0x0006d1aa7d5ec0a5, 0x000728fb3f60f777, 0x0007592af4e9fbc0, + 0x000777a5c0bf655d, 0x00078ca3857d2256, 0x00079bf6b0ffe58b, + 0x0007a7a34ab092ad, 0x0007b0d2f20dd1cb, 0x0007b83d3aa9cb52, + 0x0007be597614224d, 0x0007c3788631abe9, 0x0007c7d32bc192ee, + 0x0007cb9263a6e86d, 0x0007ced483edfa84, 0x0007d1b07ac0fd39, + 0x0007d437ef2da5fc, 0x0007d678b069aa6e, 0x0007d87db38c5c87, + 0x0007da4fc6a9ba62, 0x0007dbf611b37f3b, 0x0007dd7674d0f286, + 0x0007ded5ce8205f6, 0x0007e018307fb62b, 0x0007e141081bd124, + 0x0007e2533d712de8, 0x0007e3514bbd7718, 0x0007e43d54944b52, + 0x0007e5192f25ef42, 0x0007e5e67481118d, 0x0007e6a6897c1ce2, + 0x0007e75aa6c7f64c, 0x0007e803df8ee498, 0x0007e8a326eb6272, + 0x0007e93954717a28, 0x0007e9c727f8648f, 0x0007ea4d4cc85a3c, + 0x0007eacc5c4907a9, 0x0007eb44e0474cf6, 0x0007ebb754e47419, + 0x0007ec242a3d8474, 0x0007ec8bc5d69645, 0x0007ecee83d3d6e9, + 0x0007ed4cb8082f45, 0x0007eda6aee0170f, 0x0007edfcae2dfe68, + 0x0007ee4ef5dccd3e, 0x0007ee9dc08c394e, 0x0007eee9441a17c7, + 0x0007ef31b21b4fb1, 0x0007ef773846a8a7, 0x0007efba00d35a17, + 0x0007effa32ccf69f, 0x0007f037f25e1278, 0x0007f0736112d12c, + 0x0007f0ac9e145c25, 0x0007f0e3c65e1fcc, 0x0007f118f4ed8e54, + 0x0007f14c42ed0dc8, 0x0007f17dc7daa0c3, 0x0007f1ad99aac6a5, + 0x0007f1dbcce80015, 0x0007f20874cf56bf, 0x0007f233a36a3b9a, + 0x0007f25d69a604ad, 0x0007f285d7694a92, 0x0007f2acfba75e3b, + 0x0007f2d2e4720909, 0x0007f2f79f09c344, 0x0007f31b37ec883b, + 0x0007f33dbae36abc, 0x0007f35f330f08d5, 0x0007f37faaf2fa79, + 0x0007f39f2c805380, 0x0007f3bdc11f4f1c, 0x0007f3db71b83850, + 0x0007f3f846bba121, 0x0007f4144829f846, 0x0007f42f7d9a8b9d, + 0x0007f449ee420432, 0x0007f463a0f8675e, 0x0007f47c9c3ea77b, + 0x0007f494e643cd8e, 0x0007f4ac84e9c475, 0x0007f4c37dc9cd50, + 0x0007f4d9d638a432, 0x0007f4ef934a5b6a, 0x0007f504b9d5f33d, + 0x0007f5194e78b352, 0x0007f52d55994a96, 0x0007f540d36aba0c, + 0x0007f553cbef0e77, 0x0007f56642f9ec8f, 0x0007f5783c32f31e, + 0x0007f589bb17f609, 0x0007f59ac2ff1525, 0x0007f5ab5718b15a, + 0x0007f5bb7a71427c, 0x0007f5cb2ff31009, 0x0007f5da7a67cebe, + 0x0007f5e95c7a24e7, 0x0007f5f7d8b7171e, 0x0007f605f18f5ef4, + 0x0007f613a958ad0a, 0x0007f621024ed7e9, 0x0007f62dfe94f8cb, + 0x0007f63aa036777a, 0x0007f646e928065a, 0x0007f652db488f88, + 0x0007f65e786213ff, 0x0007f669c22a7d8a, 0x0007f674ba446459, + 0x0007f67f623fc8db, 0x0007f689bb9ac294, 0x0007f693c7c22481, + 0x0007f69d881217a6, 0x0007f6a6fdd6ac36, 0x0007f6b02a4c61ee, + 0x0007f6b90ea0a7f4, 0x0007f6c1abf254c0, 0x0007f6ca03521664, + 0x0007f6d215c2db82, 0x0007f6d9e43a3559, 0x0007f6e16fa0b329, + 0x0007f6e8b8d23729, 0x0007f6efc09e4569, 0x0007f6f687c84cbf, + 0x0007f6fd0f07ea09, 0x0007f703570925e2, 0x0007f709606cad03, + 0x0007f70f2bc8036f, 0x0007f714b9a5b292, 0x0007f71a0a85725d, + 0x0007f71f1edc4d9e, 0x0007f723f714c179, 0x0007f728938ed843, + 0x0007f72cf4a03fa0, 0x0007f7311a945a16, 0x0007f73505ac4bf8, + 0x0007f738b61f03bd, 0x0007f73c2c193dc0, 0x0007f73f67bd835c, + 0x0007f74269242559, 0x0007f745305b31a1, 0x0007f747bd666428, + 0x0007f74a103f12ed, 0x0007f74c28d414f5, 0x0007f74e0709a42d, + 0x0007f74faab939f9, 0x0007f75113b16657, 0x0007f75241b5a155, + 0x0007f753347e16b8, 0x0007f753ebb76b7c, 0x0007f75467027d05, + 0x0007f754a5f4199d, 0x0007f754a814b207, 0x0007f7546ce003ae, + 0x0007f753f3c4bb29, 0x0007f7533c240e92, 0x0007f75245514f41, + 0x0007f7510e91726c, 0x0007f74f971a9012, 0x0007f74dde135797, + 0x0007f74be2927971, 0x0007f749a39e051c, 0x0007f747202aba8a, + 0x0007f744571b4e3c, 0x0007f741473f9efe, 0x0007f73def53dc43, + 0x0007f73a4dff9bff, 0x0007f73661d4deaf, 0x0007f732294f003f, + 0x0007f72da2d19444, 0x0007f728cca72bda, 0x0007f723a5000367, + 0x0007f71e29f09627, 0x0007f7185970156b, 0x0007f7123156c102, + 0x0007f70baf5c1e2c, 0x0007f704d1150a23, 0x0007f6fd93f1a4e5, + 0x0007f6f5f53b10b6, 0x0007f6edf211023e, 0x0007f6e587671ce9, + 0x0007f6dcb2021679, 0x0007f6d36e749c64, 0x0007f6c9b91bf4c6, + 0x0007f6bf8e1c541b, 0x0007f6b4e95ce015, 0x0007f6a9c68356ff, + 0x0007f69e20ef5211, 0x0007f691f3b517eb, 0x0007f6853997f321, + 0x0007f677ed03ff19, 0x0007f66a08075bdc, 0x0007f65b844ab75a, + 0x0007f64c5b091860, 0x0007f63c8506d4bc, 0x0007f62bfa8798fe, + 0x0007f61ab34364b0, 0x0007f608a65a599a, 0x0007f5f5ca4737e8, + 0x0007f5e214d05b48, 0x0007f5cd7af7066e, 0x0007f5b7f0e4c2a1, + 0x0007f5a169d68fcf, 0x0007f589d80596a5, 0x0007f5712c8d0174, + 0x0007f557574c912b, 0x0007f53c46c77193, 0x0007f51fe7feb9f2, + 0x0007f5022646ecfb, 0x0007f4e2eb17ab1d, 0x0007f4c21dd4a3d1, + 0x0007f49fa38ea394, 0x0007f47b5ebb62eb, 0x0007f4552ee27473, + 0x0007f42cf03d58f5, 0x0007f4027b48549f, 0x0007f3d5a44119df, + 0x0007f3a63a8fb552, 0x0007f37408155100, 0x0007f33ed05b55ec, + 0x0007f3064f9c183e, 0x0007f2ca399c7ba1, 0x0007f28a384bb940, + 0x0007f245ea1b7a2b, 0x0007f1fcdffe8f1b, 0x0007f1ae9af758cd, + 0x0007f15a8917f27e, 0x0007f10001ccaaab, 0x0007f09e413c418a, + 0x0007f034627733d7, 0x0007efc15815b8d5, 0x0007ef43e2bf7f55, + 0x0007eeba84e31dfe, 0x0007ee237294df89, 0x0007ed7c7c170141, + 0x0007ecc2f0d95d3a, 0x0007ebf377a46782, 0x0007eb09d6deb285, + 0x0007ea00a4f17808, 0x0007e8d0d3da63d6, 0x0007e771023b0fcf, + 0x0007e5d46c2f08d8, 0x0007e3e937669691, 0x0007e195978f1176, + 0x0007deb2c0e05c1c, 0x0007db0362002a19, 0x0007d6202c151439, + 0x0007cf4b8f00a2cb, 0x0007c4fd24520efd, 0x0007b362fbf81816, + 0x00078d2d25998e24}; + +static const double wi[] = { + 1.7367254121602630e-15, 9.5586603514556339e-17, 1.2708704834810623e-16, + 1.4909740962495474e-16, 1.6658733631586268e-16, 1.8136120810119029e-16, + 1.9429720153135588e-16, 2.0589500628482093e-16, 2.1646860576895422e-16, + 2.2622940392218116e-16, 2.3532718914045892e-16, 2.4387234557428771e-16, + 2.5194879829274225e-16, 2.5962199772528103e-16, 2.6694407473648285e-16, + 2.7395729685142446e-16, 2.8069646002484804e-16, 2.8719058904113930e-16, + 2.9346417484728883e-16, 2.9953809336782113e-16, 3.0543030007192440e-16, + 3.1115636338921572e-16, 3.1672988018581815e-16, 3.2216280350549905e-16, + 3.2746570407939751e-16, 3.3264798116841710e-16, 3.3771803417353232e-16, + 3.4268340353119356e-16, 3.4755088731729758e-16, 3.5232663846002031e-16, + 3.5701624633953494e-16, 3.6162480571598339e-16, 3.6615697529653540e-16, + 3.7061702777236077e-16, 3.7500889278747798e-16, 3.7933619401549554e-16, + 3.8360228129677279e-16, 3.8781025861250247e-16, 3.9196300853257678e-16, + 3.9606321366256378e-16, 4.0011337552546690e-16, 4.0411583124143332e-16, + 4.0807276830960448e-16, 4.1198623774807442e-16, 4.1585816580828064e-16, + 4.1969036444740733e-16, 4.2348454071520708e-16, 4.2724230518899761e-16, + 4.3096517957162941e-16, 4.3465460355128760e-16, 4.3831194100854571e-16, + 4.4193848564470665e-16, 4.4553546609579137e-16, 4.4910405058828750e-16, + 4.5264535118571397e-16, 4.5616042766900381e-16, 4.5965029108849407e-16, + 4.6311590702081647e-16, 4.6655819856008752e-16, 4.6997804906941950e-16, + 4.7337630471583237e-16, 4.7675377680908526e-16, 4.8011124396270155e-16, + 4.8344945409350080e-16, 4.8676912627422087e-16, 4.9007095245229938e-16, + 4.9335559904654139e-16, 4.9662370843221783e-16, 4.9987590032409088e-16, + 5.0311277306593187e-16, 5.0633490483427195e-16, 5.0954285476338923e-16, + 5.1273716399787966e-16, 5.1591835667857364e-16, 5.1908694086703434e-16, + 5.2224340941340417e-16, 5.2538824077194543e-16, 5.2852189976823820e-16, + 5.3164483832166176e-16, 5.3475749612647295e-16, 5.3786030129452348e-16, + 5.4095367096239933e-16, 5.4403801186554671e-16, 5.4711372088173611e-16, + 5.5018118554603362e-16, 5.5324078453927836e-16, 5.5629288815190902e-16, + 5.5933785872484621e-16, 5.6237605106900435e-16, 5.6540781286489604e-16, + 5.6843348504368141e-16, 5.7145340215092040e-16, 5.7446789269419609e-16, + 5.7747727947569648e-16, 5.8048187991076857e-16, 5.8348200633338921e-16, + 5.8647796628943653e-16, 5.8947006281858718e-16, 5.9245859472561339e-16, + 5.9544385684180598e-16, 5.9842614027720281e-16, 6.0140573266426640e-16, + 6.0438291839361250e-16, 6.0735797884236057e-16, 6.1033119259564394e-16, + 6.1330283566179110e-16, 6.1627318168165963e-16, 6.1924250213258470e-16, + 6.2221106652737879e-16, 6.2517914260879998e-16, 6.2814699653988953e-16, + 6.3111489309056042e-16, 6.3408309582080600e-16, 6.3705186726088149e-16, + 6.4002146908880247e-16, 6.4299216230548961e-16, 6.4596420740788321e-16, + 6.4893786456033965e-16, 6.5191339376461587e-16, 6.5489105502874154e-16, + 6.5787110853507413e-16, 6.6085381480782587e-16, 6.6383943488035057e-16, + 6.6682823046247459e-16, 6.6982046410815579e-16, 6.7281639938375311e-16, + 6.7581630103719006e-16, 6.7882043516829803e-16, 6.8182906940062540e-16, + 6.8484247305500383e-16, 6.8786091732516637e-16, 6.9088467545571690e-16, + 6.9391402292275690e-16, 6.9694923761748294e-16, 6.9999060003307640e-16, + 7.0303839345521508e-16, 7.0609290415654822e-16, 7.0915442159548734e-16, + 7.1222323861967788e-16, 7.1529965167453030e-16, 7.1838396101720629e-16, + 7.2147647093647067e-16, 7.2457748997883870e-16, 7.2768733118146927e-16, + 7.3080631231227429e-16, 7.3393475611774048e-16, 7.3707299057898310e-16, + 7.4022134917657997e-16, 7.4338017116476479e-16, 7.4654980185558890e-16, + 7.4973059291369793e-16, 7.5292290266240584e-16, 7.5612709640179217e-16, + 7.5934354673958895e-16, 7.6257263393567558e-16, 7.6581474626104873e-16, + 7.6907028037219191e-16, 7.7233964170182985e-16, 7.7562324486711744e-16, + 7.7892151409638524e-16, 7.8223488367564108e-16, 7.8556379841610841e-16, + 7.8890871414417552e-16, 7.9227009821522709e-16, 7.9564843005293662e-16, + 7.9904420171571300e-16, 8.0245791849212591e-16, 8.0589009952726568e-16, + 8.0934127848215009e-16, 8.1281200422845008e-16, 8.1630284158098775e-16, + 8.1981437207065329e-16, 8.2334719476060504e-16, 8.2690192710884700e-16, + 8.3047920588053737e-16, 8.3407968811366288e-16, 8.3770405214202216e-16, + 8.4135299867980282e-16, 8.4502725197240968e-16, 8.4872756101861549e-16, + 8.5245470086955962e-16, 8.5620947401062333e-16, 8.5999271183276646e-16, + 8.6380527620052589e-16, 8.6764806112455816e-16, 8.7152199454736980e-16, + 8.7542804025171749e-16, 8.7936719990210427e-16, 8.8334051523084080e-16, + 8.8734907038131345e-16, 8.9139399442240861e-16, 8.9547646404950677e-16, + 8.9959770648910994e-16, 9.0375900262601175e-16, 9.0796169037400680e-16, + 9.1220716831348461e-16, 9.1649689962191353e-16, 9.2083241632623076e-16, + 9.2521532390956933e-16, 9.2964730630864167e-16, 9.3413013134252651e-16, + 9.3866565661866598e-16, 9.4325583596767065e-16, 9.4790272646517382e-16, + 9.5260849610662787e-16, 9.5737543220974496e-16, 9.6220595062948384e-16, + 9.6710260588230542e-16, 9.7206810229016259e-16, 9.7710530627072088e-16, + 9.8221725991905411e-16, 9.8740719604806711e-16, 9.9267855488079765e-16, + 9.9803500261836449e-16, 1.0034804521436181e-15, 1.0090190861637457e-15, + 1.0146553831467086e-15, 1.0203941464683124e-15, 1.0262405372613567e-15, + 1.0322001115486456e-15, 1.0382788623515399e-15, 1.0444832676000471e-15, + 1.0508203448355195e-15, 1.0572977139009890e-15, 1.0639236690676801e-15, + 1.0707072623632994e-15, 1.0776584002668106e-15, 1.0847879564403425e-15, + 1.0921079038149563e-15, 1.0996314701785628e-15, 1.1073733224935752e-15, + 1.1153497865853155e-15, 1.1235791107110833e-15, 1.1320817840164846e-15, + 1.1408809242582780e-15, 1.1500027537839792e-15, 1.1594771891449189e-15, + 1.1693385786910960e-15, 1.1796266352955801e-15, 1.1903876299282890e-15, + 1.2016759392543819e-15, 1.2135560818666897e-15, 1.2261054417450561e-15, + 1.2394179789163251e-15, 1.2536093926602567e-15, 1.2688244814255010e-15, + 1.2852479319096109e-15, 1.3031206634689985e-15, 1.3227655770195326e-15, + 1.3446300925011171e-15, 1.3693606835128518e-15, 1.3979436672775240e-15, + 1.4319989869661328e-15, 1.4744848603597596e-15, 1.5317872741611144e-15, + 1.6227698675312968e-15}; + +static const double fi[] = { + 1.0000000000000000e+00, 9.7710170126767082e-01, 9.5987909180010600e-01, + 9.4519895344229909e-01, 9.3206007595922991e-01, 9.1999150503934646e-01, + 9.0872644005213032e-01, 8.9809592189834297e-01, 8.8798466075583282e-01, + 8.7830965580891684e-01, 8.6900868803685649e-01, 8.6003362119633109e-01, + 8.5134625845867751e-01, 8.4291565311220373e-01, 8.3471629298688299e-01, + 8.2672683394622093e-01, 8.1892919160370192e-01, 8.1130787431265572e-01, + 8.0384948317096383e-01, 7.9654233042295841e-01, 7.8937614356602404e-01, + 7.8234183265480195e-01, 7.7543130498118662e-01, 7.6863731579848571e-01, + 7.6195334683679483e-01, 7.5537350650709567e-01, 7.4889244721915638e-01, + 7.4250529634015061e-01, 7.3620759812686210e-01, 7.2999526456147568e-01, + 7.2386453346862967e-01, 7.1781193263072152e-01, 7.1183424887824798e-01, + 7.0592850133275376e-01, 7.0009191813651117e-01, 6.9432191612611627e-01, + 6.8861608300467136e-01, 6.8297216164499430e-01, 6.7738803621877308e-01, + 6.7186171989708166e-01, 6.6639134390874977e-01, 6.6097514777666277e-01, + 6.5561147057969693e-01, 6.5029874311081637e-01, 6.4503548082082196e-01, + 6.3982027745305614e-01, 6.3465179928762327e-01, 6.2952877992483625e-01, + 6.2445001554702606e-01, 6.1941436060583399e-01, 6.1442072388891344e-01, + 6.0946806492577310e-01, 6.0455539069746733e-01, 5.9968175261912482e-01, + 5.9484624376798689e-01, 5.9004799633282545e-01, 5.8528617926337090e-01, + 5.8055999610079034e-01, 5.7586868297235316e-01, 5.7121150673525267e-01, + 5.6658776325616389e-01, 5.6199677581452390e-01, 5.5743789361876550e-01, + 5.5291049042583185e-01, 5.4841396325526537e-01, 5.4394773119002582e-01, + 5.3951123425695158e-01, 5.3510393238045717e-01, 5.3072530440366150e-01, + 5.2637484717168403e-01, 5.2205207467232140e-01, 5.1775651722975591e-01, + 5.1348772074732651e-01, 5.0924524599574761e-01, 5.0502866794346790e-01, + 5.0083757512614835e-01, 4.9667156905248933e-01, 4.9253026364386815e-01, + 4.8841328470545758e-01, 4.8432026942668288e-01, 4.8025086590904642e-01, + 4.7620473271950547e-01, 4.7218153846772976e-01, 4.6818096140569321e-01, + 4.6420268904817391e-01, 4.6024641781284248e-01, 4.5631185267871610e-01, + 4.5239870686184824e-01, 4.4850670150720273e-01, 4.4463556539573912e-01, + 4.4078503466580377e-01, 4.3695485254798533e-01, 4.3314476911265209e-01, + 4.2935454102944126e-01, 4.2558393133802180e-01, 4.2183270922949573e-01, + 4.1810064983784795e-01, 4.1438753404089090e-01, 4.1069314827018799e-01, + 4.0701728432947315e-01, 4.0335973922111429e-01, 3.9972031498019700e-01, + 3.9609881851583223e-01, 3.9249506145931540e-01, 3.8890886001878855e-01, + 3.8534003484007706e-01, 3.8178841087339344e-01, 3.7825381724561896e-01, + 3.7473608713789086e-01, 3.7123505766823922e-01, 3.6775056977903225e-01, + 3.6428246812900372e-01, 3.6083060098964775e-01, 3.5739482014578022e-01, + 3.5397498080007656e-01, 3.5057094148140588e-01, 3.4718256395679348e-01, + 3.4380971314685055e-01, 3.4045225704452164e-01, 3.3711006663700588e-01, + 3.3378301583071823e-01, 3.3047098137916342e-01, 3.2717384281360129e-01, + 3.2389148237639104e-01, 3.2062378495690530e-01, 3.1737063802991350e-01, + 3.1413193159633707e-01, 3.1090755812628634e-01, 3.0769741250429189e-01, + 3.0450139197664983e-01, 3.0131939610080288e-01, 2.9815132669668531e-01, + 2.9499708779996164e-01, 2.9185658561709499e-01, 2.8872972848218270e-01, + 2.8561642681550159e-01, 2.8251659308370741e-01, 2.7943014176163772e-01, + 2.7635698929566810e-01, 2.7329705406857691e-01, 2.7025025636587519e-01, + 2.6721651834356114e-01, 2.6419576399726080e-01, 2.6118791913272082e-01, + 2.5819291133761890e-01, 2.5521066995466168e-01, 2.5224112605594190e-01, + 2.4928421241852824e-01, 2.4633986350126363e-01, 2.4340801542275012e-01, + 2.4048860594050039e-01, 2.3758157443123795e-01, 2.3468686187232990e-01, + 2.3180441082433859e-01, 2.2893416541468023e-01, 2.2607607132238020e-01, + 2.2323007576391746e-01, 2.2039612748015194e-01, 2.1757417672433113e-01, + 2.1476417525117358e-01, 2.1196607630703015e-01, 2.0917983462112499e-01, + 2.0640540639788071e-01, 2.0364274931033485e-01, 2.0089182249465656e-01, + 1.9815258654577511e-01, 1.9542500351413428e-01, 1.9270903690358912e-01, + 1.9000465167046496e-01, 1.8731181422380025e-01, 1.8463049242679927e-01, + 1.8196065559952254e-01, 1.7930227452284767e-01, 1.7665532144373500e-01, + 1.7401977008183875e-01, 1.7139559563750595e-01, 1.6878277480121151e-01, + 1.6618128576448205e-01, 1.6359110823236570e-01, 1.6101222343751107e-01, + 1.5844461415592431e-01, 1.5588826472447920e-01, 1.5334316106026283e-01, + 1.5080929068184568e-01, 1.4828664273257453e-01, 1.4577520800599403e-01, + 1.4327497897351341e-01, 1.4078594981444470e-01, 1.3830811644855071e-01, + 1.3584147657125373e-01, 1.3338602969166913e-01, 1.3094177717364430e-01, + 1.2850872227999952e-01, 1.2608687022018586e-01, 1.2367622820159654e-01, + 1.2127680548479021e-01, 1.1888861344290998e-01, 1.1651166562561080e-01, + 1.1414597782783835e-01, 1.1179156816383801e-01, 1.0944845714681163e-01, + 1.0711666777468364e-01, 1.0479622562248690e-01, 1.0248715894193508e-01, + 1.0018949876880981e-01, 9.7903279038862284e-02, 9.5628536713008819e-02, + 9.3365311912690860e-02, 9.1113648066373634e-02, 8.8873592068275789e-02, + 8.6645194450557961e-02, 8.4428509570353374e-02, 8.2223595813202863e-02, + 8.0030515814663056e-02, 7.7849336702096039e-02, 7.5680130358927067e-02, + 7.3522973713981268e-02, 7.1377949058890375e-02, 6.9245144397006769e-02, + 6.7124653827788497e-02, 6.5016577971242842e-02, 6.2921024437758113e-02, + 6.0838108349539864e-02, 5.8767952920933758e-02, 5.6710690106202902e-02, + 5.4666461324888914e-02, 5.2635418276792176e-02, 5.0617723860947761e-02, + 4.8613553215868521e-02, 4.6623094901930368e-02, 4.4646552251294443e-02, + 4.2684144916474431e-02, 4.0736110655940933e-02, 3.8802707404526113e-02, + 3.6884215688567284e-02, 3.4980941461716084e-02, 3.3093219458578522e-02, + 3.1221417191920245e-02, 2.9365939758133314e-02, 2.7527235669603082e-02, + 2.5705804008548896e-02, 2.3902203305795882e-02, 2.2117062707308864e-02, + 2.0351096230044517e-02, 1.8605121275724643e-02, 1.6880083152543166e-02, + 1.5177088307935325e-02, 1.3497450601739880e-02, 1.1842757857907888e-02, + 1.0214971439701471e-02, 8.6165827693987316e-03, 7.0508754713732268e-03, + 5.5224032992509968e-03, 4.0379725933630305e-03, 2.6090727461021627e-03, + 1.2602859304985975e-03}; + +static const double ziggurat_nor_r = 3.6541528853610087963519472518; +static const double ziggurat_nor_inv_r = + 0.27366123732975827203338247596; // 1.0 / ziggurat_nor_r; +static const double ziggurat_exp_r = 7.6971174701310497140446280481; + +static const float ziggurat_nor_r_f = 3.6541528853610087963519472518f; +static const float ziggurat_nor_inv_r_f = 0.27366123732975827203338247596f; +static const float ziggurat_exp_r_f = 7.6971174701310497140446280481f; diff --git a/_randomgen/core_prng/src/distributions/ziggurat_constants.h b/_randomgen/core_prng/src/distributions/ziggurat_constants.h new file mode 100644 index 000000000000..17eccec0fb72 --- /dev/null +++ b/_randomgen/core_prng/src/distributions/ziggurat_constants.h @@ -0,0 +1,1196 @@ +static const uint64_t ki_double[] = { + 0x000EF33D8025EF6AULL, 0x0000000000000000ULL, 0x000C08BE98FBC6A8ULL, + 0x000DA354FABD8142ULL, 0x000E51F67EC1EEEAULL, 0x000EB255E9D3F77EULL, + 0x000EEF4B817ECAB9ULL, 0x000F19470AFA44AAULL, 0x000F37ED61FFCB18ULL, + 0x000F4F469561255CULL, 0x000F61A5E41BA396ULL, 0x000F707A755396A4ULL, + 0x000F7CB2EC28449AULL, 0x000F86F10C6357D3ULL, 0x000F8FA6578325DEULL, + 0x000F9724C74DD0DAULL, 0x000F9DA907DBF509ULL, 0x000FA360F581FA74ULL, + 0x000FA86FDE5B4BF8ULL, 0x000FACF160D354DCULL, 0x000FB0FB6718B90FULL, + 0x000FB49F8D5374C6ULL, 0x000FB7EC2366FE77ULL, 0x000FBAECE9A1E50EULL, + 0x000FBDAB9D040BEDULL, 0x000FC03060FF6C57ULL, 0x000FC2821037A248ULL, + 0x000FC4A67AE25BD1ULL, 0x000FC6A2977AEE31ULL, 0x000FC87AA92896A4ULL, + 0x000FCA325E4BDE85ULL, 0x000FCBCCE902231AULL, 0x000FCD4D12F839C4ULL, + 0x000FCEB54D8FEC99ULL, 0x000FD007BF1DC930ULL, 0x000FD1464DD6C4E6ULL, + 0x000FD272A8E2F450ULL, 0x000FD38E4FF0C91EULL, 0x000FD49A9990B478ULL, + 0x000FD598B8920F53ULL, 0x000FD689C08E99ECULL, 0x000FD76EA9C8E832ULL, + 0x000FD848547B08E8ULL, 0x000FD9178BAD2C8CULL, 0x000FD9DD07A7ADD2ULL, + 0x000FDA9970105E8CULL, 0x000FDB4D5DC02E20ULL, 0x000FDBF95C5BFCD0ULL, + 0x000FDC9DEBB99A7DULL, 0x000FDD3B8118729DULL, 0x000FDDD288342F90ULL, + 0x000FDE6364369F64ULL, 0x000FDEEE708D514EULL, 0x000FDF7401A6B42EULL, + 0x000FDFF46599ED40ULL, 0x000FE06FE4BC24F2ULL, 0x000FE0E6C225A258ULL, + 0x000FE1593C28B84CULL, 0x000FE1C78CBC3F99ULL, 0x000FE231E9DB1CAAULL, + 0x000FE29885DA1B91ULL, 0x000FE2FB8FB54186ULL, 0x000FE35B33558D4AULL, + 0x000FE3B799D0002AULL, 0x000FE410E99EAD7FULL, 0x000FE46746D47734ULL, + 0x000FE4BAD34C095CULL, 0x000FE50BAED29524ULL, 0x000FE559F74EBC78ULL, + 0x000FE5A5C8E41212ULL, 0x000FE5EF3E138689ULL, 0x000FE6366FD91078ULL, + 0x000FE67B75C6D578ULL, 0x000FE6BE661E11AAULL, 0x000FE6FF55E5F4F2ULL, + 0x000FE73E5900A702ULL, 0x000FE77B823E9E39ULL, 0x000FE7B6E37070A2ULL, + 0x000FE7F08D774243ULL, 0x000FE8289053F08CULL, 0x000FE85EFB35173AULL, + 0x000FE893DC840864ULL, 0x000FE8C741F0CEBCULL, 0x000FE8F9387D4EF6ULL, + 0x000FE929CC879B1DULL, 0x000FE95909D388EAULL, 0x000FE986FB939AA2ULL, + 0x000FE9B3AC714866ULL, 0x000FE9DF2694B6D5ULL, 0x000FEA0973ABE67CULL, + 0x000FEA329CF166A4ULL, 0x000FEA5AAB32952CULL, 0x000FEA81A6D5741AULL, + 0x000FEAA797DE1CF0ULL, 0x000FEACC85F3D920ULL, 0x000FEAF07865E63CULL, + 0x000FEB13762FEC13ULL, 0x000FEB3585FE2A4AULL, 0x000FEB56AE3162B4ULL, + 0x000FEB76F4E284FAULL, 0x000FEB965FE62014ULL, 0x000FEBB4F4CF9D7CULL, + 0x000FEBD2B8F449D0ULL, 0x000FEBEFB16E2E3EULL, 0x000FEC0BE31EBDE8ULL, + 0x000FEC2752B15A15ULL, 0x000FEC42049DAFD3ULL, 0x000FEC5BFD29F196ULL, + 0x000FEC75406CEEF4ULL, 0x000FEC8DD2500CB4ULL, 0x000FECA5B6911F12ULL, + 0x000FECBCF0C427FEULL, 0x000FECD38454FB15ULL, 0x000FECE97488C8B3ULL, + 0x000FECFEC47F91B7ULL, 0x000FED1377358528ULL, 0x000FED278F844903ULL, + 0x000FED3B10242F4CULL, 0x000FED4DFBAD586EULL, 0x000FED605498C3DDULL, + 0x000FED721D414FE8ULL, 0x000FED8357E4A982ULL, 0x000FED9406A42CC8ULL, + 0x000FEDA42B85B704ULL, 0x000FEDB3C8746AB4ULL, 0x000FEDC2DF416652ULL, + 0x000FEDD171A46E52ULL, 0x000FEDDF813C8AD3ULL, 0x000FEDED0F909980ULL, + 0x000FEDFA1E0FD414ULL, 0x000FEE06AE124BC4ULL, 0x000FEE12C0D95A06ULL, + 0x000FEE1E579006E0ULL, 0x000FEE29734B6524ULL, 0x000FEE34150AE4BCULL, + 0x000FEE3E3DB89B3CULL, 0x000FEE47EE2982F4ULL, 0x000FEE51271DB086ULL, + 0x000FEE59E9407F41ULL, 0x000FEE623528B42EULL, 0x000FEE6A0B5897F1ULL, + 0x000FEE716C3E077AULL, 0x000FEE7858327B82ULL, 0x000FEE7ECF7B06BAULL, + 0x000FEE84D2484AB2ULL, 0x000FEE8A60B66343ULL, 0x000FEE8F7ACCC851ULL, + 0x000FEE94207E25DAULL, 0x000FEE9851A829EAULL, 0x000FEE9C0E13485CULL, + 0x000FEE9F557273F4ULL, 0x000FEEA22762CCAEULL, 0x000FEEA4836B42ACULL, + 0x000FEEA668FC2D71ULL, 0x000FEEA7D76ED6FAULL, 0x000FEEA8CE04FA0AULL, + 0x000FEEA94BE8333BULL, 0x000FEEA950296410ULL, 0x000FEEA8D9C0075EULL, + 0x000FEEA7E7897654ULL, 0x000FEEA678481D24ULL, 0x000FEEA48AA29E83ULL, + 0x000FEEA21D22E4DAULL, 0x000FEE9F2E352024ULL, 0x000FEE9BBC26AF2EULL, + 0x000FEE97C524F2E4ULL, 0x000FEE93473C0A3AULL, 0x000FEE8E40557516ULL, + 0x000FEE88AE369C7AULL, 0x000FEE828E7F3DFDULL, 0x000FEE7BDEA7B888ULL, + 0x000FEE749BFF37FFULL, 0x000FEE6CC3A9BD5EULL, 0x000FEE64529E007EULL, + 0x000FEE5B45A32888ULL, 0x000FEE51994E57B6ULL, 0x000FEE474A0006CFULL, + 0x000FEE3C53E12C50ULL, 0x000FEE30B2E02AD8ULL, 0x000FEE2462AD8205ULL, + 0x000FEE175EB83C5AULL, 0x000FEE09A22A1447ULL, 0x000FEDFB27E349CCULL, + 0x000FEDEBEA76216CULL, 0x000FEDDBE422047EULL, 0x000FEDCB0ECE39D3ULL, + 0x000FEDB964042CF4ULL, 0x000FEDA6DCE938C9ULL, 0x000FED937237E98DULL, + 0x000FED7F1C38A836ULL, 0x000FED69D2B9C02BULL, 0x000FED538D06AE00ULL, + 0x000FED3C41DEA422ULL, 0x000FED23E76A2FD8ULL, 0x000FED0A732FE644ULL, + 0x000FECEFDA07FE34ULL, 0x000FECD4100EB7B8ULL, 0x000FECB708956EB4ULL, + 0x000FEC98B61230C1ULL, 0x000FEC790A0DA978ULL, 0x000FEC57F50F31FEULL, + 0x000FEC356686C962ULL, 0x000FEC114CB4B335ULL, 0x000FEBEB948E6FD0ULL, + 0x000FEBC429A0B692ULL, 0x000FEB9AF5EE0CDCULL, 0x000FEB6FE1C98542ULL, + 0x000FEB42D3AD1F9EULL, 0x000FEB13B00B2D4BULL, 0x000FEAE2591A02E9ULL, + 0x000FEAAEAE992257ULL, 0x000FEA788D8EE326ULL, 0x000FEA3FCFFD73E5ULL, + 0x000FEA044C8DD9F6ULL, 0x000FE9C5D62F563BULL, 0x000FE9843BA947A4ULL, + 0x000FE93F471D4728ULL, 0x000FE8F6BD76C5D6ULL, 0x000FE8AA5DC4E8E6ULL, + 0x000FE859E07AB1EAULL, 0x000FE804F690A940ULL, 0x000FE7AB488233C0ULL, + 0x000FE74C751F6AA5ULL, 0x000FE6E8102AA202ULL, 0x000FE67DA0B6ABD8ULL, + 0x000FE60C9F38307EULL, 0x000FE5947338F742ULL, 0x000FE51470977280ULL, + 0x000FE48BD436F458ULL, 0x000FE3F9BFFD1E37ULL, 0x000FE35D35EEB19CULL, + 0x000FE2B5122FE4FEULL, 0x000FE20003995557ULL, 0x000FE13C82788314ULL, + 0x000FE068C4EE67B0ULL, 0x000FDF82B02B71AAULL, 0x000FDE87C57EFEAAULL, + 0x000FDD7509C63BFDULL, 0x000FDC46E529BF13ULL, 0x000FDAF8F82E0282ULL, + 0x000FD985E1B2BA75ULL, 0x000FD7E6EF48CF04ULL, 0x000FD613ADBD650BULL, + 0x000FD40149E2F012ULL, 0x000FD1A1A7B4C7ACULL, 0x000FCEE204761F9EULL, + 0x000FCBA8D85E11B2ULL, 0x000FC7D26ECD2D22ULL, 0x000FC32B2F1E22EDULL, + 0x000FBD6581C0B83AULL, 0x000FB606C4005434ULL, 0x000FAC40582A2874ULL, + 0x000F9E971E014598ULL, 0x000F89FA48A41DFCULL, 0x000F66C5F7F0302CULL, + 0x000F1A5A4B331C4AULL}; + +static const double wi_double[] = { + 8.68362706080130616677e-16, 4.77933017572773682428e-17, + 6.35435241740526230246e-17, 7.45487048124769627714e-17, + 8.32936681579309972857e-17, 9.06806040505948228243e-17, + 9.71486007656776183958e-17, 1.02947503142410192108e-16, + 1.08234302884476839838e-16, 1.13114701961090307945e-16, + 1.17663594570229211411e-16, 1.21936172787143633280e-16, + 1.25974399146370927864e-16, 1.29810998862640315416e-16, + 1.33472037368241227547e-16, 1.36978648425712032797e-16, + 1.40348230012423820659e-16, 1.43595294520569430270e-16, + 1.46732087423644219083e-16, 1.49769046683910367425e-16, + 1.52715150035961979750e-16, 1.55578181694607639484e-16, + 1.58364940092908853989e-16, 1.61081401752749279325e-16, + 1.63732852039698532012e-16, 1.66323990584208352778e-16, + 1.68859017086765964015e-16, 1.71341701765596607184e-16, + 1.73775443658648593310e-16, 1.76163319230009959832e-16, + 1.78508123169767272927e-16, 1.80812402857991522674e-16, + 1.83078487648267501776e-16, 1.85308513886180189386e-16, + 1.87504446393738816849e-16, 1.89668097007747596212e-16, + 1.91801140648386198029e-16, 1.93905129306251037069e-16, + 1.95981504266288244037e-16, 1.98031606831281739736e-16, + 2.00056687762733300198e-16, 2.02057915620716538808e-16, + 2.04036384154802118313e-16, 2.05993118874037063144e-16, + 2.07929082904140197311e-16, 2.09845182223703516690e-16, + 2.11742270357603418769e-16, 2.13621152594498681022e-16, + 2.15482589785814580926e-16, 2.17327301775643674990e-16, + 2.19155970504272708519e-16, 2.20969242822353175995e-16, + 2.22767733047895534948e-16, 2.24552025294143552381e-16, + 2.26322675592856786566e-16, 2.28080213834501706782e-16, + 2.29825145544246839061e-16, 2.31557953510408037008e-16, + 2.33279099280043561128e-16, 2.34989024534709550938e-16, + 2.36688152357916037468e-16, 2.38376888404542434981e-16, + 2.40055621981350627349e-16, 2.41724727046750252175e-16, + 2.43384563137110286400e-16, 2.45035476226149539878e-16, + 2.46677799523270498158e-16, 2.48311854216108767769e-16, + 2.49937950162045242375e-16, 2.51556386532965786439e-16, + 2.53167452417135826983e-16, 2.54771427381694417303e-16, + 2.56368581998939683749e-16, 2.57959178339286723500e-16, + 2.59543470433517070146e-16, 2.61121704706701939097e-16, + 2.62694120385972564623e-16, 2.64260949884118951286e-16, + 2.65822419160830680292e-16, 2.67378748063236329361e-16, + 2.68930150647261591777e-16, 2.70476835481199518794e-16, + 2.72019005932773206655e-16, 2.73556860440867908686e-16, + 2.75090592773016664571e-16, 2.76620392269639032183e-16, + 2.78146444075954410103e-16, 2.79668929362423005309e-16, + 2.81188025534502074329e-16, 2.82703906432447923059e-16, + 2.84216742521840606520e-16, 2.85726701075460149289e-16, + 2.87233946347097994381e-16, 2.88738639737848191815e-16, + 2.90240939955384233230e-16, 2.91741003166694553259e-16, + 2.93238983144718163965e-16, 2.94735031409293489611e-16, + 2.96229297362806647792e-16, 2.97721928420902891115e-16, + 2.99213070138601307081e-16, 3.00702866332133102993e-16, + 3.02191459196806151971e-16, 3.03678989421180184427e-16, + 3.05165596297821922381e-16, 3.06651417830895451744e-16, + 3.08136590840829717032e-16, 3.09621251066292253306e-16, + 3.11105533263689296831e-16, 3.12589571304399892784e-16, + 3.14073498269944617203e-16, 3.15557446545280064031e-16, + 3.17041547910402852545e-16, 3.18525933630440648871e-16, + 3.20010734544401137886e-16, 3.21496081152744704901e-16, + 3.22982103703941557538e-16, 3.24468932280169778077e-16, + 3.25956696882307838340e-16, 3.27445527514370671802e-16, + 3.28935554267536967851e-16, 3.30426907403912838589e-16, + 3.31919717440175233652e-16, 3.33414115231237245918e-16, + 3.34910232054077845412e-16, 3.36408199691876507948e-16, + 3.37908150518594979994e-16, 3.39410217584148914282e-16, + 3.40914534700312603713e-16, 3.42421236527501816058e-16, + 3.43930458662583133920e-16, 3.45442337727858401604e-16, + 3.46957011461378353333e-16, 3.48474618808741370700e-16, + 3.49995300016538099813e-16, 3.51519196727607440975e-16, + 3.53046452078274009054e-16, 3.54577210797743572160e-16, + 3.56111619309838843415e-16, 3.57649825837265051035e-16, + 3.59191980508602994994e-16, 3.60738235468235137839e-16, + 3.62288744989419151904e-16, 3.63843665590734438546e-16, + 3.65403156156136995766e-16, 3.66967378058870090021e-16, + 3.68536495289491401456e-16, 3.70110674588289834952e-16, + 3.71690085582382297792e-16, 3.73274900927794352614e-16, + 3.74865296456848868882e-16, 3.76461451331202869131e-16, + 3.78063548200896037651e-16, 3.79671773369794425924e-16, + 3.81286316967837738238e-16, 3.82907373130524317507e-16, + 3.84535140186095955858e-16, 3.86169820850914927119e-16, + 3.87811622433558721164e-16, 3.89460757048192620674e-16, + 3.91117441837820542060e-16, 3.92781899208054153270e-16, + 3.94454357072087711446e-16, 3.96135049107613542983e-16, + 3.97824215026468259474e-16, 3.99522100857856502444e-16, + 4.01228959246062907451e-16, 4.02945049763632792393e-16, + 4.04670639241074995115e-16, 4.06406002114225038723e-16, + 4.08151420790493873480e-16, 4.09907186035326643447e-16, + 4.11673597380302570170e-16, 4.13450963554423599878e-16, + 4.15239602940268833891e-16, 4.17039844056831587498e-16, + 4.18852026071011229572e-16, 4.20676499339901510978e-16, + 4.22513625986204937320e-16, 4.24363780509307796137e-16, + 4.26227350434779809917e-16, 4.28104737005311666397e-16, + 4.29996355916383230161e-16, 4.31902638100262944617e-16, + 4.33824030562279080411e-16, 4.35760997273684900553e-16, + 4.37714020125858747008e-16, 4.39683599951052137423e-16, + 4.41670257615420348435e-16, 4.43674535190656726604e-16, + 4.45696997211204306674e-16, 4.47738232024753387312e-16, + 4.49798853244554968009e-16, 4.51879501313005876278e-16, + 4.53980845187003400947e-16, 4.56103584156742206384e-16, + 4.58248449810956667052e-16, 4.60416208163115281428e-16, + 4.62607661954784567754e-16, 4.64823653154320737780e-16, + 4.67065065671263059081e-16, 4.69332828309332890697e-16, + 4.71627917983835129766e-16, 4.73951363232586715165e-16, + 4.76304248053313737663e-16, 4.78687716104872284247e-16, + 4.81102975314741720538e-16, 4.83551302941152515162e-16, + 4.86034051145081195402e-16, 4.88552653135360343280e-16, + 4.91108629959526955862e-16, 4.93703598024033454728e-16, + 4.96339277440398725619e-16, 4.99017501309182245754e-16, + 5.01740226071808946011e-16, 5.04509543081872748637e-16, + 5.07327691573354207058e-16, 5.10197073234156184149e-16, + 5.13120268630678373200e-16, 5.16100055774322824569e-16, + 5.19139431175769859873e-16, 5.22241633800023428760e-16, + 5.25410172417759732697e-16, 5.28648856950494511482e-16, + 5.31961834533840037535e-16, 5.35353631181649688145e-16, + 5.38829200133405320160e-16, 5.42393978220171234073e-16, + 5.46053951907478041166e-16, 5.49815735089281410703e-16, + 5.53686661246787600374e-16, 5.57674893292657647836e-16, + 5.61789555355541665830e-16, 5.66040892008242216739e-16, + 5.70440462129138908417e-16, 5.75001376891989523684e-16, + 5.79738594572459365014e-16, 5.84669289345547900201e-16, + 5.89813317647789942685e-16, 5.95193814964144415532e-16, + 6.00837969627190832234e-16, 6.06778040933344851394e-16, + 6.13052720872528159123e-16, 6.19708989458162555387e-16, + 6.26804696330128439415e-16, 6.34412240712750598627e-16, + 6.42623965954805540945e-16, 6.51560331734499356881e-16, + 6.61382788509766415145e-16, 6.72315046250558662913e-16, + 6.84680341756425875856e-16, 6.98971833638761995415e-16, + 7.15999493483066421560e-16, 7.37242430179879890722e-16, + 7.65893637080557275482e-16, 8.11384933765648418565e-16}; + +static const double fi_double[] = { + 1.00000000000000000000e+00, 9.77101701267671596263e-01, + 9.59879091800106665211e-01, 9.45198953442299649730e-01, + 9.32060075959230460718e-01, 9.19991505039347012840e-01, + 9.08726440052130879366e-01, 8.98095921898343418910e-01, + 8.87984660755833377088e-01, 8.78309655808917399966e-01, + 8.69008688036857046555e-01, 8.60033621196331532488e-01, + 8.51346258458677951353e-01, 8.42915653112204177333e-01, + 8.34716292986883434679e-01, 8.26726833946221373317e-01, + 8.18929191603702366642e-01, 8.11307874312656274185e-01, + 8.03849483170964274059e-01, 7.96542330422958966274e-01, + 7.89376143566024590648e-01, 7.82341832654802504798e-01, + 7.75431304981187174974e-01, 7.68637315798486264740e-01, + 7.61953346836795386565e-01, 7.55373506507096115214e-01, + 7.48892447219156820459e-01, 7.42505296340151055290e-01, + 7.36207598126862650112e-01, 7.29995264561476231435e-01, + 7.23864533468630222401e-01, 7.17811932630721960535e-01, + 7.11834248878248421200e-01, 7.05928501332754310127e-01, + 7.00091918136511615067e-01, 6.94321916126116711609e-01, + 6.88616083004671808432e-01, 6.82972161644994857355e-01, + 6.77388036218773526009e-01, 6.71861719897082099173e-01, + 6.66391343908750100056e-01, 6.60975147776663107813e-01, + 6.55611470579697264149e-01, 6.50298743110816701574e-01, + 6.45035480820822293424e-01, 6.39820277453056585060e-01, + 6.34651799287623608059e-01, 6.29528779924836690007e-01, + 6.24450015547026504592e-01, 6.19414360605834324325e-01, + 6.14420723888913888899e-01, 6.09468064925773433949e-01, + 6.04555390697467776029e-01, 5.99681752619125263415e-01, + 5.94846243767987448159e-01, 5.90047996332826008015e-01, + 5.85286179263371453274e-01, 5.80559996100790898232e-01, + 5.75868682972353718164e-01, 5.71211506735253227163e-01, + 5.66587763256164445025e-01, 5.61996775814524340831e-01, + 5.57437893618765945014e-01, 5.52910490425832290562e-01, + 5.48413963255265812791e-01, 5.43947731190026262382e-01, + 5.39511234256952132426e-01, 5.35103932380457614215e-01, + 5.30725304403662057062e-01, 5.26374847171684479008e-01, + 5.22052074672321841931e-01, 5.17756517229756352272e-01, + 5.13487720747326958914e-01, 5.09245245995747941592e-01, + 5.05028667943468123624e-01, 5.00837575126148681903e-01, + 4.96671569052489714213e-01, 4.92530263643868537748e-01, + 4.88413284705458028423e-01, 4.84320269426683325253e-01, + 4.80250865909046753544e-01, 4.76204732719505863248e-01, + 4.72181538467730199660e-01, 4.68180961405693596422e-01, + 4.64202689048174355069e-01, 4.60246417812842867345e-01, + 4.56311852678716434184e-01, 4.52398706861848520777e-01, + 4.48506701507203064949e-01, 4.44635565395739396077e-01, + 4.40785034665803987508e-01, 4.36954852547985550526e-01, + 4.33144769112652261445e-01, 4.29354541029441427735e-01, + 4.25583931338021970170e-01, 4.21832709229495894654e-01, + 4.18100649837848226120e-01, 4.14387534040891125642e-01, + 4.10693148270188157500e-01, 4.07017284329473372217e-01, + 4.03359739221114510510e-01, 3.99720314980197222177e-01, + 3.96098818515832451492e-01, 3.92495061459315619512e-01, + 3.88908860018788715696e-01, 3.85340034840077283462e-01, + 3.81788410873393657674e-01, 3.78253817245619183840e-01, + 3.74736087137891138443e-01, 3.71235057668239498696e-01, + 3.67750569779032587814e-01, 3.64282468129004055601e-01, + 3.60830600989648031529e-01, 3.57394820145780500731e-01, + 3.53974980800076777232e-01, 3.50570941481406106455e-01, + 3.47182563956793643900e-01, 3.43809713146850715049e-01, + 3.40452257044521866547e-01, 3.37110066637006045021e-01, + 3.33783015830718454708e-01, 3.30470981379163586400e-01, + 3.27173842813601400970e-01, 3.23891482376391093290e-01, + 3.20623784956905355514e-01, 3.17370638029913609834e-01, + 3.14131931596337177215e-01, 3.10907558126286509559e-01, + 3.07697412504292056035e-01, 3.04501391976649993243e-01, + 3.01319396100803049698e-01, 2.98151326696685481377e-01, + 2.94997087799961810184e-01, 2.91856585617095209972e-01, + 2.88729728482182923521e-01, 2.85616426815501756042e-01, + 2.82516593083707578948e-01, 2.79430141761637940157e-01, + 2.76356989295668320494e-01, 2.73297054068577072172e-01, + 2.70250256365875463072e-01, 2.67216518343561471038e-01, + 2.64195763997261190426e-01, 2.61187919132721213522e-01, + 2.58192911337619235290e-01, 2.55210669954661961700e-01, + 2.52241126055942177508e-01, 2.49284212418528522415e-01, + 2.46339863501263828249e-01, 2.43408015422750312329e-01, + 2.40488605940500588254e-01, 2.37581574431238090606e-01, + 2.34686861872330010392e-01, 2.31804410824338724684e-01, + 2.28934165414680340644e-01, 2.26076071322380278694e-01, + 2.23230075763917484855e-01, 2.20396127480151998723e-01, + 2.17574176724331130872e-01, 2.14764175251173583536e-01, + 2.11966076307030182324e-01, 2.09179834621125076977e-01, + 2.06405406397880797353e-01, 2.03642749310334908452e-01, + 2.00891822494656591136e-01, 1.98152586545775138971e-01, + 1.95425003514134304483e-01, 1.92709036903589175926e-01, + 1.90004651670464985713e-01, 1.87311814223800304768e-01, + 1.84630492426799269756e-01, 1.81960655599522513892e-01, + 1.79302274522847582272e-01, 1.76655321443734858455e-01, + 1.74019770081838553999e-01, 1.71395595637505754327e-01, + 1.68782774801211288285e-01, 1.66181285764481906364e-01, + 1.63591108232365584074e-01, 1.61012223437511009516e-01, + 1.58444614155924284882e-01, 1.55888264724479197465e-01, + 1.53343161060262855866e-01, 1.50809290681845675763e-01, + 1.48286642732574552861e-01, 1.45775208005994028060e-01, + 1.43274978973513461566e-01, 1.40785949814444699690e-01, + 1.38308116448550733057e-01, 1.35841476571253755301e-01, + 1.33386029691669155683e-01, 1.30941777173644358090e-01, + 1.28508722279999570981e-01, 1.26086870220185887081e-01, + 1.23676228201596571932e-01, 1.21276805484790306533e-01, + 1.18888613442910059947e-01, 1.16511665625610869035e-01, + 1.14145977827838487895e-01, 1.11791568163838089811e-01, + 1.09448457146811797824e-01, 1.07116667774683801961e-01, + 1.04796225622487068629e-01, 1.02487158941935246892e-01, + 1.00189498768810017482e-01, 9.79032790388624646338e-02, + 9.56285367130089991594e-02, 9.33653119126910124859e-02, + 9.11136480663737591268e-02, 8.88735920682758862021e-02, + 8.66451944505580717859e-02, 8.44285095703534715916e-02, + 8.22235958132029043366e-02, 8.00305158146630696292e-02, + 7.78493367020961224423e-02, 7.56801303589271778804e-02, + 7.35229737139813238622e-02, 7.13779490588904025339e-02, + 6.92451443970067553879e-02, 6.71246538277884968737e-02, + 6.50165779712428976156e-02, 6.29210244377581412456e-02, + 6.08381083495398780614e-02, 5.87679529209337372930e-02, + 5.67106901062029017391e-02, 5.46664613248889208474e-02, + 5.26354182767921896513e-02, 5.06177238609477817000e-02, + 4.86135532158685421122e-02, 4.66230949019303814174e-02, + 4.46465522512944634759e-02, 4.26841449164744590750e-02, + 4.07361106559409394401e-02, 3.88027074045261474722e-02, + 3.68842156885673053135e-02, 3.49809414617161251737e-02, + 3.30932194585785779961e-02, 3.12214171919203004046e-02, + 2.93659397581333588001e-02, 2.75272356696031131329e-02, + 2.57058040085489103443e-02, 2.39022033057958785407e-02, + 2.21170627073088502113e-02, 2.03510962300445102935e-02, + 1.86051212757246224594e-02, 1.68800831525431419000e-02, + 1.51770883079353092332e-02, 1.34974506017398673818e-02, + 1.18427578579078790488e-02, 1.02149714397014590439e-02, + 8.61658276939872638800e-03, 7.05087547137322242369e-03, + 5.52240329925099155545e-03, 4.03797259336302356153e-03, + 2.60907274610215926189e-03, 1.26028593049859797236e-03}; + +static const uint32_t ki_float[] = { + 0x007799ECUL, 0x00000000UL, 0x006045F5UL, 0x006D1AA8UL, 0x00728FB4UL, + 0x007592AFUL, 0x00777A5CUL, 0x0078CA38UL, 0x0079BF6BUL, 0x007A7A35UL, + 0x007B0D2FUL, 0x007B83D4UL, 0x007BE597UL, 0x007C3788UL, 0x007C7D33UL, + 0x007CB926UL, 0x007CED48UL, 0x007D1B08UL, 0x007D437FUL, 0x007D678BUL, + 0x007D87DBUL, 0x007DA4FCUL, 0x007DBF61UL, 0x007DD767UL, 0x007DED5DUL, + 0x007E0183UL, 0x007E1411UL, 0x007E2534UL, 0x007E3515UL, 0x007E43D5UL, + 0x007E5193UL, 0x007E5E67UL, 0x007E6A69UL, 0x007E75AAUL, 0x007E803EUL, + 0x007E8A32UL, 0x007E9395UL, 0x007E9C72UL, 0x007EA4D5UL, 0x007EACC6UL, + 0x007EB44EUL, 0x007EBB75UL, 0x007EC243UL, 0x007EC8BCUL, 0x007ECEE8UL, + 0x007ED4CCUL, 0x007EDA6BUL, 0x007EDFCBUL, 0x007EE4EFUL, 0x007EE9DCUL, + 0x007EEE94UL, 0x007EF31BUL, 0x007EF774UL, 0x007EFBA0UL, 0x007EFFA3UL, + 0x007F037FUL, 0x007F0736UL, 0x007F0ACAUL, 0x007F0E3CUL, 0x007F118FUL, + 0x007F14C4UL, 0x007F17DCUL, 0x007F1ADAUL, 0x007F1DBDUL, 0x007F2087UL, + 0x007F233AUL, 0x007F25D7UL, 0x007F285DUL, 0x007F2AD0UL, 0x007F2D2EUL, + 0x007F2F7AUL, 0x007F31B3UL, 0x007F33DCUL, 0x007F35F3UL, 0x007F37FBUL, + 0x007F39F3UL, 0x007F3BDCUL, 0x007F3DB7UL, 0x007F3F84UL, 0x007F4145UL, + 0x007F42F8UL, 0x007F449FUL, 0x007F463AUL, 0x007F47CAUL, 0x007F494EUL, + 0x007F4AC8UL, 0x007F4C38UL, 0x007F4D9DUL, 0x007F4EF9UL, 0x007F504CUL, + 0x007F5195UL, 0x007F52D5UL, 0x007F540DUL, 0x007F553DUL, 0x007F5664UL, + 0x007F5784UL, 0x007F589CUL, 0x007F59ACUL, 0x007F5AB5UL, 0x007F5BB8UL, + 0x007F5CB3UL, 0x007F5DA8UL, 0x007F5E96UL, 0x007F5F7EUL, 0x007F605FUL, + 0x007F613BUL, 0x007F6210UL, 0x007F62E0UL, 0x007F63AAUL, 0x007F646FUL, + 0x007F652EUL, 0x007F65E8UL, 0x007F669CUL, 0x007F674CUL, 0x007F67F6UL, + 0x007F689CUL, 0x007F693CUL, 0x007F69D9UL, 0x007F6A70UL, 0x007F6B03UL, + 0x007F6B91UL, 0x007F6C1BUL, 0x007F6CA0UL, 0x007F6D21UL, 0x007F6D9EUL, + 0x007F6E17UL, 0x007F6E8CUL, 0x007F6EFCUL, 0x007F6F68UL, 0x007F6FD1UL, + 0x007F7035UL, 0x007F7096UL, 0x007F70F3UL, 0x007F714CUL, 0x007F71A1UL, + 0x007F71F2UL, 0x007F723FUL, 0x007F7289UL, 0x007F72CFUL, 0x007F7312UL, + 0x007F7350UL, 0x007F738BUL, 0x007F73C3UL, 0x007F73F6UL, 0x007F7427UL, + 0x007F7453UL, 0x007F747CUL, 0x007F74A1UL, 0x007F74C3UL, 0x007F74E0UL, + 0x007F74FBUL, 0x007F7511UL, 0x007F7524UL, 0x007F7533UL, 0x007F753FUL, + 0x007F7546UL, 0x007F754AUL, 0x007F754BUL, 0x007F7547UL, 0x007F753FUL, + 0x007F7534UL, 0x007F7524UL, 0x007F7511UL, 0x007F74F9UL, 0x007F74DEUL, + 0x007F74BEUL, 0x007F749AUL, 0x007F7472UL, 0x007F7445UL, 0x007F7414UL, + 0x007F73DFUL, 0x007F73A5UL, 0x007F7366UL, 0x007F7323UL, 0x007F72DAUL, + 0x007F728DUL, 0x007F723AUL, 0x007F71E3UL, 0x007F7186UL, 0x007F7123UL, + 0x007F70BBUL, 0x007F704DUL, 0x007F6FD9UL, 0x007F6F5FUL, 0x007F6EDFUL, + 0x007F6E58UL, 0x007F6DCBUL, 0x007F6D37UL, 0x007F6C9CUL, 0x007F6BF9UL, + 0x007F6B4FUL, 0x007F6A9CUL, 0x007F69E2UL, 0x007F691FUL, 0x007F6854UL, + 0x007F677FUL, 0x007F66A1UL, 0x007F65B8UL, 0x007F64C6UL, 0x007F63C8UL, + 0x007F62C0UL, 0x007F61ABUL, 0x007F608AUL, 0x007F5F5DUL, 0x007F5E21UL, + 0x007F5CD8UL, 0x007F5B7FUL, 0x007F5A17UL, 0x007F589EUL, 0x007F5713UL, + 0x007F5575UL, 0x007F53C4UL, 0x007F51FEUL, 0x007F5022UL, 0x007F4E2FUL, + 0x007F4C22UL, 0x007F49FAUL, 0x007F47B6UL, 0x007F4553UL, 0x007F42CFUL, + 0x007F4028UL, 0x007F3D5AUL, 0x007F3A64UL, 0x007F3741UL, 0x007F33EDUL, + 0x007F3065UL, 0x007F2CA4UL, 0x007F28A4UL, 0x007F245FUL, 0x007F1FCEUL, + 0x007F1AEAUL, 0x007F15A9UL, 0x007F1000UL, 0x007F09E4UL, 0x007F0346UL, + 0x007EFC16UL, 0x007EF43EUL, 0x007EEBA8UL, 0x007EE237UL, 0x007ED7C8UL, + 0x007ECC2FUL, 0x007EBF37UL, 0x007EB09DUL, 0x007EA00AUL, 0x007E8D0DUL, + 0x007E7710UL, 0x007E5D47UL, 0x007E3E93UL, 0x007E1959UL, 0x007DEB2CUL, + 0x007DB036UL, 0x007D6203UL, 0x007CF4B9UL, 0x007C4FD2UL, 0x007B3630UL, + 0x0078D2D2UL}; + +static const float wi_float[] = { + 4.66198677960027669255e-07f, 2.56588335019207033255e-08f, + 3.41146697750176784592e-08f, 4.00230311410932959821e-08f, + 4.47179475877737745459e-08f, 4.86837785973537366722e-08f, + 5.21562578925932412861e-08f, 5.52695199001886257153e-08f, + 5.81078488992733116465e-08f, 6.07279932024587421409e-08f, + 6.31701613261172047795e-08f, 6.54639842900233842742e-08f, + 6.76319905583641815324e-08f, 6.96917493470166688656e-08f, + 7.16572544283857476692e-08f, 7.35398519048393832969e-08f, + 7.53488822443557479279e-08f, 7.70921367281667127885e-08f, + 7.87761895947956022626e-08f, 8.04066446825615346857e-08f, + 8.19883218760237408659e-08f, 8.35254002936857088917e-08f, + 8.50215298165053411740e-08f, 8.64799190652369040985e-08f, + 8.79034055989140110861e-08f, 8.92945125124233511541e-08f, + 9.06554945027956262312e-08f, 9.19883756905278607229e-08f, + 9.32949809202232869780e-08f, 9.45769618559625849039e-08f, + 9.58358188855612866442e-08f, 9.70729196232813152662e-08f, + 9.82895146313061088986e-08f, 9.94867508514382224721e-08f, + 1.00665683139461669691e-07f, 1.01827284217853923044e-07f, + 1.02972453302539369464e-07f, 1.04102023612124921572e-07f, + 1.05216768930574060431e-07f, 1.06317409364335657741e-07f, + 1.07404616410877866490e-07f, 1.08479017436113134283e-07f, + 1.09541199642370962438e-07f, 1.10591713595628691212e-07f, + 1.11631076370069356306e-07f, 1.12659774359245895023e-07f, + 1.13678265795837113569e-07f, 1.14686983015899673063e-07f, + 1.15686334498432158725e-07f, 1.16676706706789039179e-07f, + 1.17658465754873988919e-07f, 1.18631958917986203582e-07f, + 1.19597516005596215528e-07f, 1.20555450611113917226e-07f, + 1.21506061251817163689e-07f, 1.22449632410483948386e-07f, + 1.23386435488872536840e-07f, 1.24316729681986364321e-07f, + 1.25240762781015530062e-07f, 1.26158771911939892267e-07f, + 1.27070984215989333455e-07f, 1.27977617477468922011e-07f, + 1.28878880703854958297e-07f, 1.29774974662539874521e-07f, + 1.30666092378141980504e-07f, 1.31552419593887221722e-07f, + 1.32434135200211397569e-07f, 1.33311411633413359243e-07f, + 1.34184415246907777059e-07f, 1.35053306657377859830e-07f, + 1.35918241067904315860e-07f, 1.36779368569952053923e-07f, + 1.37636834425917531047e-07f, 1.38490779333783508675e-07f, + 1.39341339675287344817e-07f, 1.40188647748881762555e-07f, + 1.41032831988654882776e-07f, 1.41874017170273235693e-07f, + 1.42712324604921442006e-07f, 1.43547872322127921816e-07f, + 1.44380775242292721080e-07f, 1.45211145339665544509e-07f, + 1.46039091796461362146e-07f, 1.46864721148745476208e-07f, + 1.47688137424670065700e-07f, 1.48509442275598857119e-07f, + 1.49328735100614641423e-07f, 1.50146113164867617390e-07f, + 1.50961671712187416111e-07f, 1.51775504072350982845e-07f, + 1.52587701763369746341e-07f, 1.53398354589133671168e-07f, + 1.54207550732725568797e-07f, 1.55015376845697999657e-07f, + 1.55821918133584372604e-07f, 1.56627258437898192833e-07f, + 1.57431480314857468671e-07f, 1.58234665111056041043e-07f, + 1.59036893036289199880e-07f, 1.59838243233728855017e-07f, + 1.60638793847630850137e-07f, 1.61438622088746393909e-07f, + 1.62237804297600106296e-07f, 1.63036416005787357730e-07f, + 1.63834531995435479082e-07f, 1.64632226356965902954e-07f, + 1.65429572545287097020e-07f, 1.66226643434541294491e-07f, + 1.67023511371523209274e-07f, 1.67820248227882200051e-07f, + 1.68616925451215588827e-07f, 1.69413614115155757272e-07f, + 1.70210384968549673733e-07f, 1.71007308483826142122e-07f, + 1.71804454904642543391e-07f, 1.72601894292900061024e-07f, + 1.73399696575213681990e-07f, 1.74197931588920988271e-07f, + 1.74996669127712165834e-07f, 1.75795978986961275677e-07f, + 1.76595931008838063924e-07f, 1.77396595127278238022e-07f, + 1.78198041412889183130e-07f, 1.79000340117867431104e-07f, + 1.79803561721004406185e-07f, 1.80607776972855859813e-07f, + 1.81413056941151359868e-07f, 1.82219473056520464354e-07f, + 1.83027097158612474240e-07f, 1.83836001542687613069e-07f, + 1.84646259006759307383e-07f, 1.85457942899367347876e-07f, + 1.86271127168064649331e-07f, 1.87085886408701333260e-07f, + 1.87902295915592424729e-07f, 1.88720431732658022414e-07f, + 1.89540370705627262627e-07f, 1.90362190535400839128e-07f, + 1.91185969832669990437e-07f, 1.92011788173893651535e-07f, + 1.92839726158739913768e-07f, 1.93669865469102145482e-07f, + 1.94502288929804890433e-07f, 1.95337080571120616772e-07f, + 1.96174325693223683314e-07f, 1.97014110932714374919e-07f, + 1.97856524331352952716e-07f, 1.98701655407150388211e-07f, + 1.99549595227971635348e-07f, 2.00400436487814600236e-07f, + 2.01254273585938820883e-07f, 2.02111202709026498408e-07f, + 2.02971321916571014951e-07f, 2.03834731229698846698e-07f, + 2.04701532723644121196e-07f, 2.05571830624108885378e-07f, + 2.06445731407757185541e-07f, 2.07323343907107312957e-07f, + 2.08204779420104330037e-07f, 2.09090151824673600213e-07f, + 2.09979577698577670508e-07f, 2.10873176444920111011e-07f, + 2.11771070423665379388e-07f, 2.12673385089569268965e-07f, + 2.13580249136944118603e-07f, 2.14491794651713402832e-07f, + 2.15408157271244625533e-07f, 2.16329476352486921685e-07f, + 2.17255895148978920488e-07f, 2.18187560997337924713e-07f, + 2.19124625513888206785e-07f, 2.20067244802139479285e-07f, + 2.21015579671883851683e-07f, 2.21969795870742159701e-07f, + 2.22930064329060010376e-07f, 2.23896561419128954210e-07f, + 2.24869469229791575583e-07f, 2.25848975857580322189e-07f, + 2.26835275715640744118e-07f, 2.27828569861799901001e-07f, + 2.28829066347263833069e-07f, 2.29836980587561823183e-07f, + 2.30852535757505260518e-07f, 2.31875963212094114516e-07f, + 2.32907502935486642699e-07f, 2.33947404020352726160e-07f, + 2.34995925180156140289e-07f, 2.36053335297164516378e-07f, + 2.37119914009265667728e-07f, 2.38195952338983970691e-07f, + 2.39281753368440712742e-07f, 2.40377632964396957621e-07f, + 2.41483920557958384709e-07f, 2.42600959984018662258e-07f, + 2.43729110386077326413e-07f, 2.44868747192698939290e-07f, + 2.46020263172594533433e-07f, 2.47184069576113545901e-07f, + 2.48360597371852893654e-07f, 2.49550298588131851232e-07f, + 2.50753647770270890721e-07f, 2.51971143565970967140e-07f, + 2.53203310452642767375e-07f, 2.54450700622322097890e-07f, + 2.55713896041856770961e-07f, 2.56993510708419870887e-07f, + 2.58290193123138874550e-07f, 2.59604629008804833146e-07f, + 2.60937544301314385690e-07f, 2.62289708448800566945e-07f, + 2.63661938057441759882e-07f, 2.65055100928844238758e-07f, + 2.66470120540847889467e-07f, 2.67907981031821866252e-07f, + 2.69369732758258246335e-07f, 2.70856498507068313229e-07f, + 2.72369480457841388042e-07f, 2.73909968006952220135e-07f, + 2.75479346585437289399e-07f, 2.77079107626811561009e-07f, + 2.78710859870496796972e-07f, 2.80376342222588603820e-07f, + 2.82077438439999912690e-07f, 2.83816193958769527230e-07f, + 2.85594835255375795814e-07f, 2.87415792215003905739e-07f, + 2.89281724087851835900e-07f, 2.91195549750371467233e-07f, + 2.93160483161771875581e-07f, 2.95180075129332912389e-07f, + 2.97258262785797916083e-07f, 2.99399428561531794298e-07f, + 3.01608470935804138388e-07f, 3.03890889921758510417e-07f, + 3.06252891144972267537e-07f, 3.08701513613258141075e-07f, + 3.11244787989714509378e-07f, 3.13891934589336184321e-07f, + 3.16653613755314681314e-07f, 3.19542246256559459667e-07f, + 3.22572428717978242099e-07f, 3.25761480217458181578e-07f, + 3.29130173358915628534e-07f, 3.32703730345002116955e-07f, + 3.36513208964639108346e-07f, 3.40597478255417943913e-07f, + 3.45006114675213401550e-07f, 3.49803789521323211592e-07f, + 3.55077180848341416206e-07f, 3.60946392031859609868e-07f, + 3.67584959507244041831e-07f, 3.75257645787954431030e-07f, + 3.84399301057791926300e-07f, 3.95804015855768440983e-07f, + 4.11186015434435801956e-07f, 4.35608969373823260746e-07f}; + +static const float fi_float[] = { + 1.00000000000000000000e+00f, 9.77101701267671596263e-01f, + 9.59879091800106665211e-01f, 9.45198953442299649730e-01f, + 9.32060075959230460718e-01f, 9.19991505039347012840e-01f, + 9.08726440052130879366e-01f, 8.98095921898343418910e-01f, + 8.87984660755833377088e-01f, 8.78309655808917399966e-01f, + 8.69008688036857046555e-01f, 8.60033621196331532488e-01f, + 8.51346258458677951353e-01f, 8.42915653112204177333e-01f, + 8.34716292986883434679e-01f, 8.26726833946221373317e-01f, + 8.18929191603702366642e-01f, 8.11307874312656274185e-01f, + 8.03849483170964274059e-01f, 7.96542330422958966274e-01f, + 7.89376143566024590648e-01f, 7.82341832654802504798e-01f, + 7.75431304981187174974e-01f, 7.68637315798486264740e-01f, + 7.61953346836795386565e-01f, 7.55373506507096115214e-01f, + 7.48892447219156820459e-01f, 7.42505296340151055290e-01f, + 7.36207598126862650112e-01f, 7.29995264561476231435e-01f, + 7.23864533468630222401e-01f, 7.17811932630721960535e-01f, + 7.11834248878248421200e-01f, 7.05928501332754310127e-01f, + 7.00091918136511615067e-01f, 6.94321916126116711609e-01f, + 6.88616083004671808432e-01f, 6.82972161644994857355e-01f, + 6.77388036218773526009e-01f, 6.71861719897082099173e-01f, + 6.66391343908750100056e-01f, 6.60975147776663107813e-01f, + 6.55611470579697264149e-01f, 6.50298743110816701574e-01f, + 6.45035480820822293424e-01f, 6.39820277453056585060e-01f, + 6.34651799287623608059e-01f, 6.29528779924836690007e-01f, + 6.24450015547026504592e-01f, 6.19414360605834324325e-01f, + 6.14420723888913888899e-01f, 6.09468064925773433949e-01f, + 6.04555390697467776029e-01f, 5.99681752619125263415e-01f, + 5.94846243767987448159e-01f, 5.90047996332826008015e-01f, + 5.85286179263371453274e-01f, 5.80559996100790898232e-01f, + 5.75868682972353718164e-01f, 5.71211506735253227163e-01f, + 5.66587763256164445025e-01f, 5.61996775814524340831e-01f, + 5.57437893618765945014e-01f, 5.52910490425832290562e-01f, + 5.48413963255265812791e-01f, 5.43947731190026262382e-01f, + 5.39511234256952132426e-01f, 5.35103932380457614215e-01f, + 5.30725304403662057062e-01f, 5.26374847171684479008e-01f, + 5.22052074672321841931e-01f, 5.17756517229756352272e-01f, + 5.13487720747326958914e-01f, 5.09245245995747941592e-01f, + 5.05028667943468123624e-01f, 5.00837575126148681903e-01f, + 4.96671569052489714213e-01f, 4.92530263643868537748e-01f, + 4.88413284705458028423e-01f, 4.84320269426683325253e-01f, + 4.80250865909046753544e-01f, 4.76204732719505863248e-01f, + 4.72181538467730199660e-01f, 4.68180961405693596422e-01f, + 4.64202689048174355069e-01f, 4.60246417812842867345e-01f, + 4.56311852678716434184e-01f, 4.52398706861848520777e-01f, + 4.48506701507203064949e-01f, 4.44635565395739396077e-01f, + 4.40785034665803987508e-01f, 4.36954852547985550526e-01f, + 4.33144769112652261445e-01f, 4.29354541029441427735e-01f, + 4.25583931338021970170e-01f, 4.21832709229495894654e-01f, + 4.18100649837848226120e-01f, 4.14387534040891125642e-01f, + 4.10693148270188157500e-01f, 4.07017284329473372217e-01f, + 4.03359739221114510510e-01f, 3.99720314980197222177e-01f, + 3.96098818515832451492e-01f, 3.92495061459315619512e-01f, + 3.88908860018788715696e-01f, 3.85340034840077283462e-01f, + 3.81788410873393657674e-01f, 3.78253817245619183840e-01f, + 3.74736087137891138443e-01f, 3.71235057668239498696e-01f, + 3.67750569779032587814e-01f, 3.64282468129004055601e-01f, + 3.60830600989648031529e-01f, 3.57394820145780500731e-01f, + 3.53974980800076777232e-01f, 3.50570941481406106455e-01f, + 3.47182563956793643900e-01f, 3.43809713146850715049e-01f, + 3.40452257044521866547e-01f, 3.37110066637006045021e-01f, + 3.33783015830718454708e-01f, 3.30470981379163586400e-01f, + 3.27173842813601400970e-01f, 3.23891482376391093290e-01f, + 3.20623784956905355514e-01f, 3.17370638029913609834e-01f, + 3.14131931596337177215e-01f, 3.10907558126286509559e-01f, + 3.07697412504292056035e-01f, 3.04501391976649993243e-01f, + 3.01319396100803049698e-01f, 2.98151326696685481377e-01f, + 2.94997087799961810184e-01f, 2.91856585617095209972e-01f, + 2.88729728482182923521e-01f, 2.85616426815501756042e-01f, + 2.82516593083707578948e-01f, 2.79430141761637940157e-01f, + 2.76356989295668320494e-01f, 2.73297054068577072172e-01f, + 2.70250256365875463072e-01f, 2.67216518343561471038e-01f, + 2.64195763997261190426e-01f, 2.61187919132721213522e-01f, + 2.58192911337619235290e-01f, 2.55210669954661961700e-01f, + 2.52241126055942177508e-01f, 2.49284212418528522415e-01f, + 2.46339863501263828249e-01f, 2.43408015422750312329e-01f, + 2.40488605940500588254e-01f, 2.37581574431238090606e-01f, + 2.34686861872330010392e-01f, 2.31804410824338724684e-01f, + 2.28934165414680340644e-01f, 2.26076071322380278694e-01f, + 2.23230075763917484855e-01f, 2.20396127480151998723e-01f, + 2.17574176724331130872e-01f, 2.14764175251173583536e-01f, + 2.11966076307030182324e-01f, 2.09179834621125076977e-01f, + 2.06405406397880797353e-01f, 2.03642749310334908452e-01f, + 2.00891822494656591136e-01f, 1.98152586545775138971e-01f, + 1.95425003514134304483e-01f, 1.92709036903589175926e-01f, + 1.90004651670464985713e-01f, 1.87311814223800304768e-01f, + 1.84630492426799269756e-01f, 1.81960655599522513892e-01f, + 1.79302274522847582272e-01f, 1.76655321443734858455e-01f, + 1.74019770081838553999e-01f, 1.71395595637505754327e-01f, + 1.68782774801211288285e-01f, 1.66181285764481906364e-01f, + 1.63591108232365584074e-01f, 1.61012223437511009516e-01f, + 1.58444614155924284882e-01f, 1.55888264724479197465e-01f, + 1.53343161060262855866e-01f, 1.50809290681845675763e-01f, + 1.48286642732574552861e-01f, 1.45775208005994028060e-01f, + 1.43274978973513461566e-01f, 1.40785949814444699690e-01f, + 1.38308116448550733057e-01f, 1.35841476571253755301e-01f, + 1.33386029691669155683e-01f, 1.30941777173644358090e-01f, + 1.28508722279999570981e-01f, 1.26086870220185887081e-01f, + 1.23676228201596571932e-01f, 1.21276805484790306533e-01f, + 1.18888613442910059947e-01f, 1.16511665625610869035e-01f, + 1.14145977827838487895e-01f, 1.11791568163838089811e-01f, + 1.09448457146811797824e-01f, 1.07116667774683801961e-01f, + 1.04796225622487068629e-01f, 1.02487158941935246892e-01f, + 1.00189498768810017482e-01f, 9.79032790388624646338e-02f, + 9.56285367130089991594e-02f, 9.33653119126910124859e-02f, + 9.11136480663737591268e-02f, 8.88735920682758862021e-02f, + 8.66451944505580717859e-02f, 8.44285095703534715916e-02f, + 8.22235958132029043366e-02f, 8.00305158146630696292e-02f, + 7.78493367020961224423e-02f, 7.56801303589271778804e-02f, + 7.35229737139813238622e-02f, 7.13779490588904025339e-02f, + 6.92451443970067553879e-02f, 6.71246538277884968737e-02f, + 6.50165779712428976156e-02f, 6.29210244377581412456e-02f, + 6.08381083495398780614e-02f, 5.87679529209337372930e-02f, + 5.67106901062029017391e-02f, 5.46664613248889208474e-02f, + 5.26354182767921896513e-02f, 5.06177238609477817000e-02f, + 4.86135532158685421122e-02f, 4.66230949019303814174e-02f, + 4.46465522512944634759e-02f, 4.26841449164744590750e-02f, + 4.07361106559409394401e-02f, 3.88027074045261474722e-02f, + 3.68842156885673053135e-02f, 3.49809414617161251737e-02f, + 3.30932194585785779961e-02f, 3.12214171919203004046e-02f, + 2.93659397581333588001e-02f, 2.75272356696031131329e-02f, + 2.57058040085489103443e-02f, 2.39022033057958785407e-02f, + 2.21170627073088502113e-02f, 2.03510962300445102935e-02f, + 1.86051212757246224594e-02f, 1.68800831525431419000e-02f, + 1.51770883079353092332e-02f, 1.34974506017398673818e-02f, + 1.18427578579078790488e-02f, 1.02149714397014590439e-02f, + 8.61658276939872638800e-03f, 7.05087547137322242369e-03f, + 5.52240329925099155545e-03f, 4.03797259336302356153e-03f, + 2.60907274610215926189e-03f, 1.26028593049859797236e-03f}; + +static const uint64_t ke_double[] = { + 0x001C5214272497C6, 0x0000000000000000, 0x00137D5BD79C317E, + 0x00186EF58E3F3C10, 0x001A9BB7320EB0AE, 0x001BD127F719447C, + 0x001C951D0F88651A, 0x001D1BFE2D5C3972, 0x001D7E5BD56B18B2, + 0x001DC934DD172C70, 0x001E0409DFAC9DC8, 0x001E337B71D47836, + 0x001E5A8B177CB7A2, 0x001E7B42096F046C, 0x001E970DAF08AE3E, + 0x001EAEF5B14EF09E, 0x001EC3BD07B46556, 0x001ED5F6F08799CE, + 0x001EE614AE6E5688, 0x001EF46ECA361CD0, 0x001F014B76DDD4A4, + 0x001F0CE313A796B6, 0x001F176369F1F77A, 0x001F20F20C452570, + 0x001F29AE1951A874, 0x001F31B18FB95532, 0x001F39125157C106, + 0x001F3FE2EB6E694C, 0x001F463332D788FA, 0x001F4C10BF1D3A0E, + 0x001F51874C5C3322, 0x001F56A109C3ECC0, 0x001F5B66D9099996, + 0x001F5FE08210D08C, 0x001F6414DD445772, 0x001F6809F6859678, + 0x001F6BC52A2B02E6, 0x001F6F4B3D32E4F4, 0x001F72A07190F13A, + 0x001F75C8974D09D6, 0x001F78C71B045CC0, 0x001F7B9F12413FF4, + 0x001F7E5346079F8A, 0x001F80E63BE21138, 0x001F835A3DAD9162, + 0x001F85B16056B912, 0x001F87ED89B24262, 0x001F8A10759374FA, + 0x001F8C1BBA3D39AC, 0x001F8E10CC45D04A, 0x001F8FF102013E16, + 0x001F91BD968358E0, 0x001F9377AC47AFD8, 0x001F95204F8B64DA, + 0x001F96B878633892, 0x001F98410C968892, 0x001F99BAE146BA80, + 0x001F9B26BC697F00, 0x001F9C85561B717A, 0x001F9DD759CFD802, + 0x001F9F1D6761A1CE, 0x001FA058140936C0, 0x001FA187EB3A3338, + 0x001FA2AD6F6BC4FC, 0x001FA3C91ACE0682, 0x001FA4DB5FEE6AA2, + 0x001FA5E4AA4D097C, 0x001FA6E55EE46782, 0x001FA7DDDCA51EC4, + 0x001FA8CE7CE6A874, 0x001FA9B793CE5FEE, 0x001FAA9970ADB858, + 0x001FAB745E588232, 0x001FAC48A3740584, 0x001FAD1682BF9FE8, + 0x001FADDE3B5782C0, 0x001FAEA008F21D6C, 0x001FAF5C2418B07E, + 0x001FB012C25B7A12, 0x001FB0C41681DFF4, 0x001FB17050B6F1FA, + 0x001FB2179EB2963A, 0x001FB2BA2BDFA84A, 0x001FB358217F4E18, + 0x001FB3F1A6C9BE0C, 0x001FB486E10CACD6, 0x001FB517F3C793FC, + 0x001FB5A500C5FDAA, 0x001FB62E2837FE58, 0x001FB6B388C9010A, + 0x001FB7353FB50798, 0x001FB7B368DC7DA8, 0x001FB82E1ED6BA08, + 0x001FB8A57B0347F6, 0x001FB919959A0F74, 0x001FB98A85BA7204, + 0x001FB9F861796F26, 0x001FBA633DEEE286, 0x001FBACB2F41EC16, + 0x001FBB3048B49144, 0x001FBB929CAEA4E2, 0x001FBBF23CC8029E, + 0x001FBC4F39D22994, 0x001FBCA9A3E140D4, 0x001FBD018A548F9E, + 0x001FBD56FBDE729C, 0x001FBDAA068BD66A, 0x001FBDFAB7CB3F40, + 0x001FBE491C7364DE, 0x001FBE9540C9695E, 0x001FBEDF3086B128, + 0x001FBF26F6DE6174, 0x001FBF6C9E828AE2, 0x001FBFB031A904C4, + 0x001FBFF1BA0FFDB0, 0x001FC03141024588, 0x001FC06ECF5B54B2, + 0x001FC0AA6D8B1426, 0x001FC0E42399698A, 0x001FC11BF9298A64, + 0x001FC151F57D1942, 0x001FC1861F770F4A, 0x001FC1B87D9E74B4, + 0x001FC1E91620EA42, 0x001FC217EED505DE, 0x001FC2450D3C83FE, + 0x001FC27076864FC2, 0x001FC29A2F90630E, 0x001FC2C23CE98046, + 0x001FC2E8A2D2C6B4, 0x001FC30D654122EC, 0x001FC33087DE9C0E, + 0x001FC3520E0B7EC6, 0x001FC371FADF66F8, 0x001FC390512A2886, + 0x001FC3AD137497FA, 0x001FC3C844013348, 0x001FC3E1E4CCAB40, + 0x001FC3F9F78E4DA8, 0x001FC4107DB85060, 0x001FC4257877FD68, + 0x001FC438E8B5BFC6, 0x001FC44ACF15112A, 0x001FC45B2BF447E8, + 0x001FC469FF6C4504, 0x001FC477495001B2, 0x001FC483092BFBB8, + 0x001FC48D3E457FF6, 0x001FC495E799D21A, 0x001FC49D03DD30B0, + 0x001FC4A29179B432, 0x001FC4A68E8E07FC, 0x001FC4A8F8EBFB8C, + 0x001FC4A9CE16EA9E, 0x001FC4A90B41FA34, 0x001FC4A6AD4E28A0, + 0x001FC4A2B0C82E74, 0x001FC49D11E62DE2, 0x001FC495CC852DF4, + 0x001FC48CDC265EC0, 0x001FC4823BEC237A, 0x001FC475E696DEE6, + 0x001FC467D6817E82, 0x001FC458059DC036, 0x001FC4466D702E20, + 0x001FC433070BCB98, 0x001FC41DCB0D6E0E, 0x001FC406B196BBF6, + 0x001FC3EDB248CB62, 0x001FC3D2C43E593C, 0x001FC3B5DE0591B4, + 0x001FC396F599614C, 0x001FC376005A4592, 0x001FC352F3069370, + 0x001FC32DC1B22818, 0x001FC3065FBD7888, 0x001FC2DCBFCBF262, + 0x001FC2B0D3B99F9E, 0x001FC2828C8FFCF0, 0x001FC251DA79F164, + 0x001FC21EACB6D39E, 0x001FC1E8F18C6756, 0x001FC1B09637BB3C, + 0x001FC17586DCCD10, 0x001FC137AE74D6B6, 0x001FC0F6F6BB2414, + 0x001FC0B348184DA4, 0x001FC06C898BAFF0, 0x001FC022A092F364, + 0x001FBFD5710F72B8, 0x001FBF84DD29488E, 0x001FBF30C52FC60A, + 0x001FBED907770CC6, 0x001FBE7D80327DDA, 0x001FBE1E094BA614, + 0x001FBDBA7A354408, 0x001FBD52A7B9F826, 0x001FBCE663C6201A, + 0x001FBC757D2C4DE4, 0x001FBBFFBF63B7AA, 0x001FBB84F23FE6A2, + 0x001FBB04D9A0D18C, 0x001FBA7F351A70AC, 0x001FB9F3BF92B618, + 0x001FB9622ED4ABFC, 0x001FB8CA33174A16, 0x001FB82B76765B54, + 0x001FB7859C5B895C, 0x001FB6D840D55594, 0x001FB622F7D96942, + 0x001FB5654C6F37E0, 0x001FB49EBFBF69D2, 0x001FB3CEC803E746, + 0x001FB2F4CF539C3E, 0x001FB21032442852, 0x001FB1203E5A9604, + 0x001FB0243042E1C2, 0x001FAF1B31C479A6, 0x001FAE045767E104, + 0x001FACDE9DBF2D72, 0x001FABA8E640060A, 0x001FAA61F399FF28, + 0x001FA908656F66A2, 0x001FA79AB3508D3C, 0x001FA61726D1F214, + 0x001FA47BD48BEA00, 0x001FA2C693C5C094, 0x001FA0F4F47DF314, + 0x001F9F04336BBE0A, 0x001F9CF12B79F9BC, 0x001F9AB84415ABC4, + 0x001F98555B782FB8, 0x001F95C3ABD03F78, 0x001F92FDA9CEF1F2, + 0x001F8FFCDA9AE41C, 0x001F8CB99E7385F8, 0x001F892AEC479606, + 0x001F8545F904DB8E, 0x001F80FDC336039A, 0x001F7C427839E926, + 0x001F7700A3582ACC, 0x001F71200F1A241C, 0x001F6A8234B7352A, + 0x001F630000A8E266, 0x001F5A66904FE3C4, 0x001F50724ECE1172, + 0x001F44C7665C6FDA, 0x001F36E5A38A59A2, 0x001F26143450340A, + 0x001F113E047B0414, 0x001EF6AEFA57CBE6, 0x001ED38CA188151E, + 0x001EA2A61E122DB0, 0x001E5961C78B267C, 0x001DDDF62BAC0BB0, + 0x001CDB4DD9E4E8C0}; + +static const double we_double[] = { + 9.655740063209182975e-16, 7.089014243955414331e-18, + 1.163941249669122378e-17, 1.524391512353216015e-17, + 1.833284885723743916e-17, 2.108965109464486630e-17, + 2.361128077843138196e-17, 2.595595772310893952e-17, + 2.816173554197752338e-17, 3.025504130321382330e-17, + 3.225508254836375280e-17, 3.417632340185027033e-17, + 3.602996978734452488e-17, 3.782490776869649048e-17, + 3.956832198097553231e-17, 4.126611778175946428e-17, + 4.292321808442525631e-17, 4.454377743282371417e-17, + 4.613133981483185932e-17, 4.768895725264635940e-17, + 4.921928043727962847e-17, 5.072462904503147014e-17, + 5.220704702792671737e-17, 5.366834661718192181e-17, + 5.511014372835094717e-17, 5.653388673239667134e-17, + 5.794088004852766616e-17, 5.933230365208943081e-17, + 6.070922932847179572e-17, 6.207263431163193485e-17, + 6.342341280303076511e-17, 6.476238575956142121e-17, + 6.609030925769405241e-17, 6.740788167872722244e-17, + 6.871574991183812442e-17, 7.001451473403929616e-17, + 7.130473549660643409e-17, 7.258693422414648352e-17, + 7.386159921381791997e-17, 7.512918820723728089e-17, + 7.639013119550825792e-17, 7.764483290797848102e-17, + 7.889367502729790548e-17, 8.013701816675454434e-17, + 8.137520364041762206e-17, 8.260855505210038174e-17, + 8.383737972539139383e-17, 8.506196999385323132e-17, + 8.628260436784112996e-17, 8.749954859216182511e-17, + 8.871305660690252281e-17, 8.992337142215357066e-17, + 9.113072591597909173e-17, 9.233534356381788123e-17, + 9.353743910649128938e-17, 9.473721916312949566e-17, + 9.593488279457997317e-17, 9.713062202221521206e-17, + 9.832462230649511362e-17, 9.951706298915071878e-17, + 1.007081177024294931e-16, 1.018979547484694078e-16, + 1.030867374515421954e-16, 1.042746244856188556e-16, + 1.054617701794576406e-16, 1.066483248011914702e-16, + 1.078344348241948498e-16, 1.090202431758350473e-16, + 1.102058894705578110e-16, 1.113915102286197502e-16, + 1.125772390816567488e-16, 1.137632069661684705e-16, + 1.149495423059009298e-16, 1.161363711840218308e-16, + 1.173238175059045788e-16, 1.185120031532669434e-16, + 1.197010481303465158e-16, 1.208910707027385520e-16, + 1.220821875294706151e-16, 1.232745137888415193e-16, + 1.244681632985112523e-16, 1.256632486302898513e-16, + 1.268598812200397542e-16, 1.280581714730749379e-16, + 1.292582288654119552e-16, 1.304601620412028847e-16, + 1.316640789066572582e-16, 1.328700867207380889e-16, + 1.340782921828999433e-16, 1.352888015181175458e-16, + 1.365017205594397770e-16, 1.377171548282880964e-16, + 1.389352096127063919e-16, 1.401559900437571538e-16, + 1.413796011702485188e-16, 1.426061480319665444e-16, + 1.438357357315790180e-16, 1.450684695053687684e-16, + 1.463044547929475721e-16, 1.475437973060951633e-16, + 1.487866030968626066e-16, 1.500329786250736949e-16, + 1.512830308253539427e-16, 1.525368671738125550e-16, + 1.537945957544996933e-16, 1.550563253257577148e-16, + 1.563221653865837505e-16, 1.575922262431176140e-16, + 1.588666190753684151e-16, 1.601454560042916733e-16, + 1.614288501593278662e-16, 1.627169157465130500e-16, + 1.640097681172717950e-16, 1.653075238380036909e-16, + 1.666103007605742067e-16, 1.679182180938228863e-16, + 1.692313964762022267e-16, 1.705499580496629830e-16, + 1.718740265349031656e-16, 1.732037273081008369e-16, + 1.745391874792533975e-16, 1.758805359722491379e-16, + 1.772279036068006489e-16, 1.785814231823732619e-16, + 1.799412295642463721e-16, 1.813074597718501559e-16, + 1.826802530695252266e-16, 1.840597510598587828e-16, + 1.854460977797569461e-16, 1.868394397994192684e-16, + 1.882399263243892051e-16, 1.896477093008616722e-16, + 1.910629435244376536e-16, 1.924857867525243818e-16, + 1.939163998205899420e-16, 1.953549467624909132e-16, + 1.968015949351037382e-16, 1.982565151475019047e-16, + 1.997198817949342081e-16, 2.011918729978734671e-16, + 2.026726707464198289e-16, 2.041624610503588774e-16, + 2.056614340951917875e-16, 2.071697844044737034e-16, + 2.086877110088159721e-16, 2.102154176219292789e-16, + 2.117531128241075913e-16, 2.133010102535779087e-16, + 2.148593288061663316e-16, 2.164282928437604723e-16, + 2.180081324120784027e-16, 2.195990834682870728e-16, + 2.212013881190495942e-16, 2.228152948696180545e-16, + 2.244410588846308588e-16, 2.260789422613173739e-16, + 2.277292143158621037e-16, 2.293921518837311354e-16, + 2.310680396348213318e-16, 2.327571704043534613e-16, + 2.344598455404957859e-16, 2.361763752697773994e-16, + 2.379070790814276700e-16, 2.396522861318623520e-16, + 2.414123356706293277e-16, 2.431875774892255956e-16, + 2.449783723943070217e-16, 2.467850927069288738e-16, + 2.486081227895851719e-16, 2.504478596029557040e-16, + 2.523047132944217013e-16, 2.541791078205812227e-16, + 2.560714816061770759e-16, 2.579822882420530896e-16, + 2.599119972249746917e-16, 2.618610947423924219e-16, + 2.638300845054942823e-16, 2.658194886341845120e-16, + 2.678298485979525166e-16, 2.698617262169488933e-16, + 2.719157047279818500e-16, 2.739923899205814823e-16, + 2.760924113487617126e-16, 2.782164236246436081e-16, + 2.803651078006983464e-16, 2.825391728480253184e-16, + 2.847393572388174091e-16, 2.869664306419817679e-16, + 2.892211957417995598e-16, 2.915044901905293183e-16, + 2.938171887070028633e-16, 2.961602053345465687e-16, + 2.985344958730045276e-16, 3.009410605012618141e-16, + 3.033809466085003416e-16, 3.058552518544860874e-16, + 3.083651274815310004e-16, 3.109117819034266344e-16, + 3.134964845996663118e-16, 3.161205703467105734e-16, + 3.187854438219713117e-16, 3.214925846206797361e-16, + 3.242435527309451638e-16, 3.270399945182240440e-16, + 3.298836492772283149e-16, 3.327763564171671408e-16, + 3.357200633553244075e-16, 3.387168342045505162e-16, + 3.417688593525636996e-16, 3.448784660453423890e-16, + 3.480481301037442286e-16, 3.512804889222979418e-16, + 3.545783559224791863e-16, 3.579447366604276541e-16, + 3.613828468219060593e-16, 3.648961323764542545e-16, + 3.684882922095621322e-16, 3.721633036080207290e-16, + 3.759254510416256532e-16, 3.797793587668874387e-16, + 3.837300278789213687e-16, 3.877828785607895292e-16, + 3.919437984311428867e-16, 3.962191980786774996e-16, + 4.006160751056541688e-16, 4.051420882956573177e-16, + 4.098056438903062509e-16, 4.146159964290904582e-16, + 4.195833672073398926e-16, 4.247190841824385048e-16, + 4.300357481667470702e-16, 4.355474314693952008e-16, + 4.412699169036069903e-16, 4.472209874259932285e-16, + 4.534207798565834480e-16, 4.598922204905932469e-16, + 4.666615664711475780e-16, 4.737590853262492027e-16, + 4.812199172829237933e-16, 4.890851827392209900e-16, + 4.974034236191939753e-16, 5.062325072144159699e-16, + 5.156421828878082953e-16, 5.257175802022274839e-16, + 5.365640977112021618e-16, 5.483144034258703912e-16, + 5.611387454675159622e-16, 5.752606481503331688e-16, + 5.909817641652102998e-16, 6.087231416180907671e-16, + 6.290979034877557049e-16, 6.530492053564040799e-16, + 6.821393079028928626e-16, 7.192444966089361564e-16, + 7.706095350032096755e-16, 8.545517038584027421e-16}; + +static const double fe_double[] = { + 1.000000000000000000e+00, 9.381436808621747003e-01, + 9.004699299257464817e-01, 8.717043323812035949e-01, + 8.477855006239896074e-01, 8.269932966430503241e-01, + 8.084216515230083777e-01, 7.915276369724956185e-01, + 7.759568520401155522e-01, 7.614633888498962833e-01, + 7.478686219851951034e-01, 7.350380924314234843e-01, + 7.228676595935720206e-01, 7.112747608050760117e-01, + 7.001926550827881623e-01, 6.895664961170779872e-01, + 6.793505722647653622e-01, 6.695063167319247333e-01, + 6.600008410789997004e-01, 6.508058334145710999e-01, + 6.418967164272660897e-01, 6.332519942143660652e-01, + 6.248527387036659775e-01, 6.166821809152076561e-01, + 6.087253820796220127e-01, 6.009689663652322267e-01, + 5.934009016917334289e-01, 5.860103184772680329e-01, + 5.787873586028450257e-01, 5.717230486648258170e-01, + 5.648091929124001709e-01, 5.580382822625874484e-01, + 5.514034165406412891e-01, 5.448982376724396115e-01, + 5.385168720028619127e-01, 5.322538802630433219e-01, + 5.261042139836197284e-01, 5.200631773682335979e-01, + 5.141263938147485613e-01, 5.082897764106428795e-01, + 5.025495018413477233e-01, 4.969019872415495476e-01, + 4.913438695940325340e-01, 4.858719873418849144e-01, + 4.804833639304542103e-01, 4.751751930373773747e-01, + 4.699448252839599771e-01, 4.647897562504261781e-01, + 4.597076156421376902e-01, 4.546961574746155033e-01, + 4.497532511627549967e-01, 4.448768734145485126e-01, + 4.400651008423538957e-01, 4.353161032156365740e-01, + 4.306281372884588343e-01, 4.259995411430343437e-01, + 4.214287289976165751e-01, 4.169141864330028757e-01, + 4.124544659971611793e-01, 4.080481831520323954e-01, + 4.036940125305302773e-01, 3.993906844752310725e-01, + 3.951369818332901573e-01, 3.909317369847971069e-01, + 3.867738290841376547e-01, 3.826621814960098344e-01, + 3.785957594095807899e-01, 3.745735676159021588e-01, + 3.705946484351460013e-01, 3.666580797815141568e-01, + 3.627629733548177748e-01, 3.589084729487497794e-01, + 3.550937528667874599e-01, 3.513180164374833381e-01, + 3.475804946216369817e-01, 3.438804447045024082e-01, + 3.402171490667800224e-01, 3.365899140286776059e-01, + 3.329980687618089852e-01, 3.294409642641363267e-01, + 3.259179723935561879e-01, 3.224284849560891675e-01, + 3.189719128449572394e-01, 3.155476852271289490e-01, + 3.121552487741795501e-01, 3.087940669345601852e-01, + 3.054636192445902565e-01, 3.021634006756935276e-01, + 2.988929210155817917e-01, 2.956517042812611962e-01, + 2.924392881618925744e-01, 2.892552234896777485e-01, + 2.860990737370768255e-01, 2.829704145387807457e-01, + 2.798688332369729248e-01, 2.767939284485173568e-01, + 2.737453096528029706e-01, 2.707225967990600224e-01, + 2.677254199320447947e-01, 2.647534188350622042e-01, + 2.618062426893629779e-01, 2.588835497490162285e-01, + 2.559850070304153791e-01, 2.531102900156294577e-01, + 2.502590823688622956e-01, 2.474310756653276266e-01, + 2.446259691318921070e-01, 2.418434693988772144e-01, + 2.390832902624491774e-01, 2.363451524570596429e-01, + 2.336287834374333461e-01, 2.309339171696274118e-01, + 2.282602939307167011e-01, 2.256076601166840667e-01, + 2.229757680581201940e-01, 2.203643758433594946e-01, + 2.177732471487005272e-01, 2.152021510753786837e-01, + 2.126508619929782795e-01, 2.101191593889882581e-01, + 2.076068277242220372e-01, 2.051136562938377095e-01, + 2.026394390937090173e-01, 2.001839746919112650e-01, + 1.977470661050988732e-01, 1.953285206795632167e-01, + 1.929281499767713515e-01, 1.905457696631953912e-01, + 1.881811994042543179e-01, 1.858342627621971110e-01, + 1.835047870977674633e-01, 1.811926034754962889e-01, + 1.788975465724783054e-01, 1.766194545904948843e-01, + 1.743581691713534942e-01, 1.721135353153200598e-01, + 1.698854013025276610e-01, 1.676736186172501919e-01, + 1.654780418749360049e-01, 1.632985287519018169e-01, + 1.611349399175920349e-01, 1.589871389693142123e-01, + 1.568549923693652315e-01, 1.547383693844680830e-01, + 1.526371420274428570e-01, 1.505511850010398944e-01, + 1.484803756438667910e-01, 1.464245938783449441e-01, + 1.443837221606347754e-01, 1.423576454324722018e-01, + 1.403462510748624548e-01, 1.383494288635802039e-01, + 1.363670709264288572e-01, 1.343990717022136294e-01, + 1.324453279013875218e-01, 1.305057384683307731e-01, + 1.285802045452281717e-01, 1.266686294375106714e-01, + 1.247709185808309612e-01, 1.228869795095451356e-01, + 1.210167218266748335e-01, 1.191600571753276827e-01, + 1.173168992115555670e-01, 1.154871635786335338e-01, + 1.136707678827443141e-01, 1.118676316700562973e-01, + 1.100776764051853845e-01, 1.083008254510337970e-01, + 1.065370040500016602e-01, 1.047861393065701724e-01, + 1.030481601712577161e-01, 1.013229974259536315e-01, + 9.961058367063713170e-02, 9.791085331149219917e-02, + 9.622374255043279756e-02, 9.454918937605585882e-02, + 9.288713355604354127e-02, 9.123751663104015530e-02, + 8.960028191003285847e-02, 8.797537446727021759e-02, + 8.636274114075691288e-02, 8.476233053236811865e-02, + 8.317409300963238272e-02, 8.159798070923741931e-02, + 8.003394754231990538e-02, 7.848194920160642130e-02, + 7.694194317048050347e-02, 7.541388873405840965e-02, + 7.389774699236474620e-02, 7.239348087570873780e-02, + 7.090105516237182881e-02, 6.942043649872875477e-02, + 6.795159342193660135e-02, 6.649449638533977414e-02, + 6.504911778675374900e-02, 6.361543199980733421e-02, + 6.219341540854099459e-02, 6.078304644547963265e-02, + 5.938430563342026597e-02, 5.799717563120065922e-02, + 5.662164128374287675e-02, 5.525768967669703741e-02, + 5.390531019604608703e-02, 5.256449459307169225e-02, + 5.123523705512628146e-02, 4.991753428270637172e-02, + 4.861138557337949667e-02, 4.731679291318154762e-02, + 4.603376107617516977e-02, 4.476229773294328196e-02, + 4.350241356888818328e-02, 4.225412241331623353e-02, + 4.101744138041481941e-02, 3.979239102337412542e-02, + 3.857899550307485742e-02, 3.737728277295936097e-02, + 3.618728478193142251e-02, 3.500903769739741045e-02, + 3.384258215087432992e-02, 3.268796350895953468e-02, + 3.154523217289360859e-02, 3.041444391046660423e-02, + 2.929566022463739317e-02, 2.818894876397863569e-02, + 2.709438378095579969e-02, 2.601204664513421735e-02, + 2.494202641973178314e-02, 2.388442051155817078e-02, + 2.283933540638524023e-02, 2.180688750428358066e-02, + 2.078720407257811723e-02, 1.978042433800974303e-02, + 1.878670074469603046e-02, 1.780620041091136169e-02, + 1.683910682603994777e-02, 1.588562183997316302e-02, + 1.494596801169114850e-02, 1.402039140318193759e-02, + 1.310916493125499106e-02, 1.221259242625538123e-02, + 1.133101359783459695e-02, 1.046481018102997894e-02, + 9.614413642502209895e-03, 8.780314985808975251e-03, + 7.963077438017040002e-03, 7.163353183634983863e-03, + 6.381905937319179087e-03, 5.619642207205483020e-03, + 4.877655983542392333e-03, 4.157295120833795314e-03, + 3.460264777836904049e-03, 2.788798793574076128e-03, + 2.145967743718906265e-03, 1.536299780301572356e-03, + 9.672692823271745359e-04, 4.541343538414967652e-04}; + +static const uint32_t ke_float[] = { + 0x00714851UL, 0x00000000UL, 0x004DF56FUL, 0x0061BBD6UL, 0x006A6EDDUL, + 0x006F44A0UL, 0x00725474UL, 0x00746FF9UL, 0x0075F96FUL, 0x007724D3UL, + 0x00781027UL, 0x0078CDEEUL, 0x00796A2CUL, 0x0079ED08UL, 0x007A5C37UL, + 0x007ABBD7UL, 0x007B0EF4UL, 0x007B57DCUL, 0x007B9853UL, 0x007BD1BBUL, + 0x007C052EUL, 0x007C338CUL, 0x007C5D8EUL, 0x007C83C8UL, 0x007CA6B8UL, + 0x007CC6C6UL, 0x007CE449UL, 0x007CFF8CUL, 0x007D18CDUL, 0x007D3043UL, + 0x007D461DUL, 0x007D5A84UL, 0x007D6D9BUL, 0x007D7F82UL, 0x007D9053UL, + 0x007DA028UL, 0x007DAF15UL, 0x007DBD2DUL, 0x007DCA82UL, 0x007DD722UL, + 0x007DE31CUL, 0x007DEE7CUL, 0x007DF94DUL, 0x007E0399UL, 0x007E0D69UL, + 0x007E16C6UL, 0x007E1FB6UL, 0x007E2842UL, 0x007E306FUL, 0x007E3843UL, + 0x007E3FC4UL, 0x007E46F6UL, 0x007E4DDFUL, 0x007E5481UL, 0x007E5AE2UL, + 0x007E6104UL, 0x007E66ECUL, 0x007E6C9BUL, 0x007E7215UL, 0x007E775DUL, + 0x007E7C76UL, 0x007E8160UL, 0x007E8620UL, 0x007E8AB6UL, 0x007E8F24UL, + 0x007E936DUL, 0x007E9793UL, 0x007E9B95UL, 0x007E9F77UL, 0x007EA33AUL, + 0x007EA6DEUL, 0x007EAA66UL, 0x007EADD1UL, 0x007EB123UL, 0x007EB45AUL, + 0x007EB779UL, 0x007EBA80UL, 0x007EBD71UL, 0x007EC04BUL, 0x007EC310UL, + 0x007EC5C1UL, 0x007EC85EUL, 0x007ECAE9UL, 0x007ECD61UL, 0x007ECFC7UL, + 0x007ED21CUL, 0x007ED460UL, 0x007ED694UL, 0x007ED8B9UL, 0x007EDACEUL, + 0x007EDCD5UL, 0x007EDECEUL, 0x007EE0B8UL, 0x007EE296UL, 0x007EE466UL, + 0x007EE62AUL, 0x007EE7E2UL, 0x007EE98DUL, 0x007EEB2DUL, 0x007EECC1UL, + 0x007EEE4AUL, 0x007EEFC9UL, 0x007EF13DUL, 0x007EF2A7UL, 0x007EF406UL, + 0x007EF55CUL, 0x007EF6A8UL, 0x007EF7EBUL, 0x007EF924UL, 0x007EFA55UL, + 0x007EFB7DUL, 0x007EFC9CUL, 0x007EFDB2UL, 0x007EFEC1UL, 0x007EFFC7UL, + 0x007F00C5UL, 0x007F01BBUL, 0x007F02AAUL, 0x007F0391UL, 0x007F0470UL, + 0x007F0548UL, 0x007F0618UL, 0x007F06E2UL, 0x007F07A4UL, 0x007F0860UL, + 0x007F0914UL, 0x007F09C2UL, 0x007F0A69UL, 0x007F0B09UL, 0x007F0BA3UL, + 0x007F0C36UL, 0x007F0CC2UL, 0x007F0D48UL, 0x007F0DC8UL, 0x007F0E41UL, + 0x007F0EB4UL, 0x007F0F21UL, 0x007F0F88UL, 0x007F0FE8UL, 0x007F1042UL, + 0x007F1096UL, 0x007F10E4UL, 0x007F112BUL, 0x007F116DUL, 0x007F11A8UL, + 0x007F11DDUL, 0x007F120CUL, 0x007F1235UL, 0x007F1258UL, 0x007F1274UL, + 0x007F128AUL, 0x007F129AUL, 0x007F12A4UL, 0x007F12A7UL, 0x007F12A4UL, + 0x007F129BUL, 0x007F128BUL, 0x007F1274UL, 0x007F1257UL, 0x007F1233UL, + 0x007F1209UL, 0x007F11D8UL, 0x007F119FUL, 0x007F1160UL, 0x007F111AUL, + 0x007F10CCUL, 0x007F1077UL, 0x007F101BUL, 0x007F0FB7UL, 0x007F0F4BUL, + 0x007F0ED7UL, 0x007F0E5CUL, 0x007F0DD8UL, 0x007F0D4CUL, 0x007F0CB7UL, + 0x007F0C19UL, 0x007F0B73UL, 0x007F0AC3UL, 0x007F0A0AUL, 0x007F0947UL, + 0x007F087BUL, 0x007F07A4UL, 0x007F06C2UL, 0x007F05D6UL, 0x007F04DFUL, + 0x007F03DCUL, 0x007F02CDUL, 0x007F01B2UL, 0x007F008BUL, 0x007EFF56UL, + 0x007EFE13UL, 0x007EFCC3UL, 0x007EFB64UL, 0x007EF9F6UL, 0x007EF878UL, + 0x007EF6EAUL, 0x007EF54BUL, 0x007EF39AUL, 0x007EF1D6UL, 0x007EEFFFUL, + 0x007EEE14UL, 0x007EEC13UL, 0x007EE9FDUL, 0x007EE7CFUL, 0x007EE589UL, + 0x007EE329UL, 0x007EE0AEUL, 0x007EDE16UL, 0x007EDB61UL, 0x007ED88CUL, + 0x007ED595UL, 0x007ED27BUL, 0x007ECF3BUL, 0x007ECBD3UL, 0x007EC841UL, + 0x007EC481UL, 0x007EC091UL, 0x007EBC6DUL, 0x007EB811UL, 0x007EB37AUL, + 0x007EAEA4UL, 0x007EA988UL, 0x007EA422UL, 0x007E9E6BUL, 0x007E985DUL, + 0x007E91EFUL, 0x007E8B1AUL, 0x007E83D4UL, 0x007E7C11UL, 0x007E73C5UL, + 0x007E6AE1UL, 0x007E6155UL, 0x007E570FUL, 0x007E4BF7UL, 0x007E3FF3UL, + 0x007E32E6UL, 0x007E24ACUL, 0x007E1518UL, 0x007E03F7UL, 0x007DF10AUL, + 0x007DDC03UL, 0x007DC480UL, 0x007DAA09UL, 0x007D8C00UL, 0x007D699AUL, + 0x007D41C9UL, 0x007D131EUL, 0x007CDB97UL, 0x007C9851UL, 0x007C44F8UL, + 0x007BDABCUL, 0x007B4E33UL, 0x007A8A98UL, 0x00796587UL, 0x007777D9UL, + 0x00736D37UL, +}; +static const float we_float[] = { + 1.03677719e-06F, 7.61177108e-09F, 1.24977240e-08F, 1.63680292e-08F, + 1.96847466e-08F, 2.26448404e-08F, 2.53524197e-08F, 2.78699974e-08F, + 3.02384333e-08F, 3.24861032e-08F, 3.46336312e-08F, 3.66965478e-08F, + 3.86868855e-08F, 4.06141855e-08F, 4.24861622e-08F, 4.43091566e-08F, + 4.60884545e-08F, 4.78285168e-08F, 4.95331490e-08F, 5.12056279e-08F, + 5.28488000e-08F, 5.44651557e-08F, 5.60568899e-08F, 5.76259484e-08F, + 5.91740662e-08F, 6.07027987e-08F, 6.22135462e-08F, 6.37075759e-08F, + 6.51860386e-08F, 6.66499836e-08F, 6.81003709e-08F, 6.95380822e-08F, + 7.09639292e-08F, 7.23786618e-08F, 7.37829746e-08F, 7.51775128e-08F, + 7.65628768e-08F, 7.79396272e-08F, 7.93082883e-08F, 8.06693516e-08F, + 8.20232788e-08F, 8.33705045e-08F, 8.47114385e-08F, 8.60464681e-08F, + 8.73759596e-08F, 8.87002606e-08F, 9.00197010e-08F, 9.13345948e-08F, + 9.26452410e-08F, 9.39519249e-08F, 9.52549192e-08F, 9.65544849e-08F, + 9.78508719e-08F, 9.91443202e-08F, 1.00435060e-07F, 1.01723315e-07F, + 1.03009296e-07F, 1.04293211e-07F, 1.05575259e-07F, 1.06855633e-07F, + 1.08134518e-07F, 1.09412096e-07F, 1.10688542e-07F, 1.11964025e-07F, + 1.13238713e-07F, 1.14512767e-07F, 1.15786343e-07F, 1.17059595e-07F, + 1.18332673e-07F, 1.19605723e-07F, 1.20878890e-07F, 1.22152313e-07F, + 1.23426131e-07F, 1.24700479e-07F, 1.25975490e-07F, 1.27251294e-07F, + 1.28528022e-07F, 1.29805799e-07F, 1.31084751e-07F, 1.32365001e-07F, + 1.33646673e-07F, 1.34929886e-07F, 1.36214760e-07F, 1.37501415e-07F, + 1.38789966e-07F, 1.40080532e-07F, 1.41373228e-07F, 1.42668169e-07F, + 1.43965470e-07F, 1.45265245e-07F, 1.46567606e-07F, 1.47872669e-07F, + 1.49180545e-07F, 1.50491348e-07F, 1.51805191e-07F, 1.53122186e-07F, + 1.54442445e-07F, 1.55766083e-07F, 1.57093212e-07F, 1.58423946e-07F, + 1.59758399e-07F, 1.61096684e-07F, 1.62438917e-07F, 1.63785214e-07F, + 1.65135690e-07F, 1.66490462e-07F, 1.67849647e-07F, 1.69213364e-07F, + 1.70581733e-07F, 1.71954874e-07F, 1.73332908e-07F, 1.74715958e-07F, + 1.76104148e-07F, 1.77497602e-07F, 1.78896448e-07F, 1.80300814e-07F, + 1.81710828e-07F, 1.83126623e-07F, 1.84548331e-07F, 1.85976086e-07F, + 1.87410026e-07F, 1.88850288e-07F, 1.90297012e-07F, 1.91750343e-07F, + 1.93210424e-07F, 1.94677403e-07F, 1.96151428e-07F, 1.97632653e-07F, + 1.99121231e-07F, 2.00617321e-07F, 2.02121082e-07F, 2.03632677e-07F, + 2.05152273e-07F, 2.06680040e-07F, 2.08216149e-07F, 2.09760777e-07F, + 2.11314104e-07F, 2.12876312e-07F, 2.14447590e-07F, 2.16028129e-07F, + 2.17618123e-07F, 2.19217773e-07F, 2.20827283e-07F, 2.22446862e-07F, + 2.24076723e-07F, 2.25717086e-07F, 2.27368174e-07F, 2.29030216e-07F, + 2.30703448e-07F, 2.32388110e-07F, 2.34084450e-07F, 2.35792720e-07F, + 2.37513182e-07F, 2.39246101e-07F, 2.40991752e-07F, 2.42750416e-07F, + 2.44522382e-07F, 2.46307948e-07F, 2.48107418e-07F, 2.49921109e-07F, + 2.51749342e-07F, 2.53592452e-07F, 2.55450781e-07F, 2.57324683e-07F, + 2.59214522e-07F, 2.61120673e-07F, 2.63043524e-07F, 2.64983476e-07F, + 2.66940939e-07F, 2.68916342e-07F, 2.70910123e-07F, 2.72922739e-07F, + 2.74954660e-07F, 2.77006373e-07F, 2.79078382e-07F, 2.81171210e-07F, + 2.83285396e-07F, 2.85421503e-07F, 2.87580110e-07F, 2.89761822e-07F, + 2.91967265e-07F, 2.94197089e-07F, 2.96451969e-07F, 2.98732610e-07F, + 3.01039742e-07F, 3.03374127e-07F, 3.05736557e-07F, 3.08127859e-07F, + 3.10548894e-07F, 3.13000563e-07F, 3.15483804e-07F, 3.17999599e-07F, + 3.20548974e-07F, 3.23133003e-07F, 3.25752811e-07F, 3.28409576e-07F, + 3.31104534e-07F, 3.33838984e-07F, 3.36614287e-07F, 3.39431878e-07F, + 3.42293264e-07F, 3.45200034e-07F, 3.48153864e-07F, 3.51156520e-07F, + 3.54209871e-07F, 3.57315892e-07F, 3.60476673e-07F, 3.63694431e-07F, + 3.66971518e-07F, 3.70310433e-07F, 3.73713834e-07F, 3.77184553e-07F, + 3.80725611e-07F, 3.84340234e-07F, 3.88031877e-07F, 3.91804239e-07F, + 3.95661291e-07F, 3.99607304e-07F, 4.03646879e-07F, 4.07784981e-07F, + 4.12026980e-07F, 4.16378695e-07F, 4.20846449e-07F, 4.25437124e-07F, + 4.30158235e-07F, 4.35018005e-07F, 4.40025460e-07F, 4.45190536e-07F, + 4.50524210e-07F, 4.56038644e-07F, 4.61747369e-07F, 4.67665494e-07F, + 4.73809965e-07F, 4.80199879e-07F, 4.86856855e-07F, 4.93805512e-07F, + 5.01074042e-07F, 5.08694944e-07F, 5.16705952e-07F, 5.25151216e-07F, + 5.34082859e-07F, 5.43563016e-07F, 5.53666578e-07F, 5.64484953e-07F, + 5.76131313e-07F, 5.88748108e-07F, 6.02518140e-07F, 6.17681418e-07F, + 6.34561837e-07F, 6.53611496e-07F, 6.75488730e-07F, 7.01206245e-07F, + 7.32441505e-07F, 7.72282898e-07F, 8.27435688e-07F, 9.17567905e-07F, +}; +static const float fe_float[] = { + 1.00000000e+00F, 9.38143681e-01F, 9.00469930e-01F, 8.71704332e-01F, + 8.47785501e-01F, 8.26993297e-01F, 8.08421652e-01F, 7.91527637e-01F, + 7.75956852e-01F, 7.61463389e-01F, 7.47868622e-01F, 7.35038092e-01F, + 7.22867660e-01F, 7.11274761e-01F, 7.00192655e-01F, 6.89566496e-01F, + 6.79350572e-01F, 6.69506317e-01F, 6.60000841e-01F, 6.50805833e-01F, + 6.41896716e-01F, 6.33251994e-01F, 6.24852739e-01F, 6.16682181e-01F, + 6.08725382e-01F, 6.00968966e-01F, 5.93400902e-01F, 5.86010318e-01F, + 5.78787359e-01F, 5.71723049e-01F, 5.64809193e-01F, 5.58038282e-01F, + 5.51403417e-01F, 5.44898238e-01F, 5.38516872e-01F, 5.32253880e-01F, + 5.26104214e-01F, 5.20063177e-01F, 5.14126394e-01F, 5.08289776e-01F, + 5.02549502e-01F, 4.96901987e-01F, 4.91343870e-01F, 4.85871987e-01F, + 4.80483364e-01F, 4.75175193e-01F, 4.69944825e-01F, 4.64789756e-01F, + 4.59707616e-01F, 4.54696157e-01F, 4.49753251e-01F, 4.44876873e-01F, + 4.40065101e-01F, 4.35316103e-01F, 4.30628137e-01F, 4.25999541e-01F, + 4.21428729e-01F, 4.16914186e-01F, 4.12454466e-01F, 4.08048183e-01F, + 4.03694013e-01F, 3.99390684e-01F, 3.95136982e-01F, 3.90931737e-01F, + 3.86773829e-01F, 3.82662181e-01F, 3.78595759e-01F, 3.74573568e-01F, + 3.70594648e-01F, 3.66658080e-01F, 3.62762973e-01F, 3.58908473e-01F, + 3.55093753e-01F, 3.51318016e-01F, 3.47580495e-01F, 3.43880445e-01F, + 3.40217149e-01F, 3.36589914e-01F, 3.32998069e-01F, 3.29440964e-01F, + 3.25917972e-01F, 3.22428485e-01F, 3.18971913e-01F, 3.15547685e-01F, + 3.12155249e-01F, 3.08794067e-01F, 3.05463619e-01F, 3.02163401e-01F, + 2.98892921e-01F, 2.95651704e-01F, 2.92439288e-01F, 2.89255223e-01F, + 2.86099074e-01F, 2.82970415e-01F, 2.79868833e-01F, 2.76793928e-01F, + 2.73745310e-01F, 2.70722597e-01F, 2.67725420e-01F, 2.64753419e-01F, + 2.61806243e-01F, 2.58883550e-01F, 2.55985007e-01F, 2.53110290e-01F, + 2.50259082e-01F, 2.47431076e-01F, 2.44625969e-01F, 2.41843469e-01F, + 2.39083290e-01F, 2.36345152e-01F, 2.33628783e-01F, 2.30933917e-01F, + 2.28260294e-01F, 2.25607660e-01F, 2.22975768e-01F, 2.20364376e-01F, + 2.17773247e-01F, 2.15202151e-01F, 2.12650862e-01F, 2.10119159e-01F, + 2.07606828e-01F, 2.05113656e-01F, 2.02639439e-01F, 2.00183975e-01F, + 1.97747066e-01F, 1.95328521e-01F, 1.92928150e-01F, 1.90545770e-01F, + 1.88181199e-01F, 1.85834263e-01F, 1.83504787e-01F, 1.81192603e-01F, + 1.78897547e-01F, 1.76619455e-01F, 1.74358169e-01F, 1.72113535e-01F, + 1.69885401e-01F, 1.67673619e-01F, 1.65478042e-01F, 1.63298529e-01F, + 1.61134940e-01F, 1.58987139e-01F, 1.56854992e-01F, 1.54738369e-01F, + 1.52637142e-01F, 1.50551185e-01F, 1.48480376e-01F, 1.46424594e-01F, + 1.44383722e-01F, 1.42357645e-01F, 1.40346251e-01F, 1.38349429e-01F, + 1.36367071e-01F, 1.34399072e-01F, 1.32445328e-01F, 1.30505738e-01F, + 1.28580205e-01F, 1.26668629e-01F, 1.24770919e-01F, 1.22886980e-01F, + 1.21016722e-01F, 1.19160057e-01F, 1.17316899e-01F, 1.15487164e-01F, + 1.13670768e-01F, 1.11867632e-01F, 1.10077676e-01F, 1.08300825e-01F, + 1.06537004e-01F, 1.04786139e-01F, 1.03048160e-01F, 1.01322997e-01F, + 9.96105837e-02F, 9.79108533e-02F, 9.62237426e-02F, 9.45491894e-02F, + 9.28871336e-02F, 9.12375166e-02F, 8.96002819e-02F, 8.79753745e-02F, + 8.63627411e-02F, 8.47623305e-02F, 8.31740930e-02F, 8.15979807e-02F, + 8.00339475e-02F, 7.84819492e-02F, 7.69419432e-02F, 7.54138887e-02F, + 7.38977470e-02F, 7.23934809e-02F, 7.09010552e-02F, 6.94204365e-02F, + 6.79515934e-02F, 6.64944964e-02F, 6.50491178e-02F, 6.36154320e-02F, + 6.21934154e-02F, 6.07830464e-02F, 5.93843056e-02F, 5.79971756e-02F, + 5.66216413e-02F, 5.52576897e-02F, 5.39053102e-02F, 5.25644946e-02F, + 5.12352371e-02F, 4.99175343e-02F, 4.86113856e-02F, 4.73167929e-02F, + 4.60337611e-02F, 4.47622977e-02F, 4.35024136e-02F, 4.22541224e-02F, + 4.10174414e-02F, 3.97923910e-02F, 3.85789955e-02F, 3.73772828e-02F, + 3.61872848e-02F, 3.50090377e-02F, 3.38425822e-02F, 3.26879635e-02F, + 3.15452322e-02F, 3.04144439e-02F, 2.92956602e-02F, 2.81889488e-02F, + 2.70943838e-02F, 2.60120466e-02F, 2.49420264e-02F, 2.38844205e-02F, + 2.28393354e-02F, 2.18068875e-02F, 2.07872041e-02F, 1.97804243e-02F, + 1.87867007e-02F, 1.78062004e-02F, 1.68391068e-02F, 1.58856218e-02F, + 1.49459680e-02F, 1.40203914e-02F, 1.31091649e-02F, 1.22125924e-02F, + 1.13310136e-02F, 1.04648102e-02F, 9.61441364e-03F, 8.78031499e-03F, + 7.96307744e-03F, 7.16335318e-03F, 6.38190594e-03F, 5.61964221e-03F, + 4.87765598e-03F, 4.15729512e-03F, 3.46026478e-03F, 2.78879879e-03F, + 2.14596774e-03F, 1.53629978e-03F, 9.67269282e-04F, 4.54134354e-04F, +}; diff --git a/_randomgen/core_prng/src/pcg64/pcg64.c b/_randomgen/core_prng/src/pcg64/pcg64.c new file mode 100644 index 000000000000..ba8ce4124cfd --- /dev/null +++ b/_randomgen/core_prng/src/pcg64/pcg64.c @@ -0,0 +1,92 @@ +/* + * PCG64 Random Number Generation for C. + * + * Copyright 2014 Melissa O'Neill + * Copyright 2015 Robert Kern + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + +#include "pcg64.h" + +extern inline void pcg_setseq_128_step_r(pcg_state_setseq_128* rng); +extern inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state); +extern inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128* rng, + pcg128_t initstate, pcg128_t initseq); +extern inline uint64_t +pcg_setseq_128_xsl_rr_64_random_r(pcg_state_setseq_128* rng); +extern inline uint64_t +pcg_setseq_128_xsl_rr_64_boundedrand_r(pcg_state_setseq_128* rng, + uint64_t bound); +extern inline void pcg_setseq_128_advance_r(pcg_state_setseq_128* rng, pcg128_t delta); + +/* Multi-step advance functions (jump-ahead, jump-back) +* +* The method used here is based on Brown, "Random Number Generation +* with Arbitrary Stride,", Transactions of the American Nuclear +* Society (Nov. 1994). The algorithm is very similar to fast +* exponentiation. +* +* Even though delta is an unsigned integer, we can pass a +* signed integer to go backwards, it just goes "the long way round". +*/ + +#ifndef PCG_EMULATED_128BIT_MATH + +pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult, + pcg128_t cur_plus) +{ + pcg128_t acc_mult = 1u; + pcg128_t acc_plus = 0u; + while (delta > 0) { + if (delta & 1) { + acc_mult *= cur_mult; + acc_plus = acc_plus * cur_mult + cur_plus; + } + cur_plus = (cur_mult + 1) * cur_plus; + cur_mult *= cur_mult; + delta /= 2; + } + return acc_mult * state + acc_plus; +} + +#else + +pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult, + pcg128_t cur_plus) +{ + pcg128_t acc_mult = PCG_128BIT_CONSTANT(0u, 1u); + pcg128_t acc_plus = PCG_128BIT_CONSTANT(0u, 0u); + while ((delta.high > 0) || (delta.low > 0)) { + if (delta.low & 1) { + acc_mult = _pcg128_mult(acc_mult, cur_mult); + acc_plus = _pcg128_add(_pcg128_mult(acc_plus, cur_mult), cur_plus); + } + cur_plus = _pcg128_mult(_pcg128_add(cur_mult, PCG_128BIT_CONSTANT(0u, 1u)), cur_plus); + cur_mult = _pcg128_mult(cur_mult, cur_mult); + delta.low >>= 1; + delta.low += delta.high & 1; + delta.high >>= 1; + } + return _pcg128_add(_pcg128_mult(acc_mult, state), acc_plus); +} + +#endif + +extern inline uint64_t pcg64_next64(pcg64_state *state); +extern inline uint32_t pcg64_next32(pcg64_state *state); \ No newline at end of file diff --git a/_randomgen/core_prng/src/pcg64/pcg64.h b/_randomgen/core_prng/src/pcg64/pcg64.h new file mode 100644 index 000000000000..441ebe87d56e --- /dev/null +++ b/_randomgen/core_prng/src/pcg64/pcg64.h @@ -0,0 +1,237 @@ +/* + * PCG64 Random Number Generation for C. + * + * Copyright 2014 Melissa O'Neill + * Copyright 2015 Robert Kern + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + +#ifndef PCG64_H_INCLUDED +#define PCG64_H_INCLUDED 1 + +#ifdef _WIN32 +#ifndef _INTTYPES +#include "../common/stdint.h" +#endif +#define inline __forceinline +#else +#include +#endif + + +#if __GNUC_GNU_INLINE__ && !defined(__cplusplus) +#error Nonstandard GNU inlining semantics. Compile with -std=c99 or better. +#endif + +#if __cplusplus +extern "C" { +#endif + +#if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH) + typedef __uint128_t pcg128_t; +#define PCG_128BIT_CONSTANT(high,low) \ + (((pcg128_t)(high) << 64) + low) +#else + typedef struct { + uint64_t high; + uint64_t low; + } pcg128_t; + + inline pcg128_t PCG_128BIT_CONSTANT(uint64_t high, uint64_t low) { + pcg128_t result; + result.high = high; + result.low = low; + return result; + } + +#define PCG_EMULATED_128BIT_MATH 1 +#endif + + typedef struct { + pcg128_t state; + } pcg_state_128; + + typedef struct { + pcg128_t state; + pcg128_t inc; + } pcg_state_setseq_128; + +#define PCG_DEFAULT_MULTIPLIER_128 \ + PCG_128BIT_CONSTANT(2549297995355413924ULL,4865540595714422341ULL) +#define PCG_DEFAULT_INCREMENT_128 \ + PCG_128BIT_CONSTANT(6364136223846793005ULL,1442695040888963407ULL) +#define PCG_STATE_SETSEQ_128_INITIALIZER \ + { PCG_128BIT_CONSTANT(0x979c9a98d8462005ULL, 0x7d3e9cb6cfe0549bULL), \ + PCG_128BIT_CONSTANT(0x0000000000000001ULL, 0xda3e39cb94b95bdbULL) } + + inline uint64_t pcg_rotr_64(uint64_t value, unsigned int rot) + { + return (value >> rot) | (value << ((- rot) & 63)); + } + +#ifdef PCG_EMULATED_128BIT_MATH + + inline pcg128_t _pcg128_add(pcg128_t a, pcg128_t b) { + pcg128_t result; + + result.low = a.low + b.low; + result.high = a.high + b.high + (result.low < b.low); + return result; + } + + inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t* z1, uint64_t* z0) { + uint64_t x0, x1, y0, y1; + uint64_t w0, w1, w2, t; + /* Lower 64 bits are straightforward clock-arithmetic. */ + *z0 = x * y; + + x0 = x & 0xFFFFFFFFULL; + x1 = x >> 32; + y0 = y & 0xFFFFFFFFULL; + y1 = y >> 32; + w0 = x0 * y0; + t = x1 * y0 + (w0 >> 32); + w1 = t & 0xFFFFFFFFULL; + w2 = t >> 32; + w1 += x0 * y1; + *z1 = x1 * y1 + w2 + (w1 >> 32); + } + + inline pcg128_t _pcg128_mult(pcg128_t a, pcg128_t b) { + uint64_t h1; + pcg128_t result; + + h1 = a.high * b.low + a.low * b.high; + _pcg_mult64(a.low, b.low, &(result.high), &(result.low)); + result.high += h1; + return result; + } + + inline void pcg_setseq_128_step_r(pcg_state_setseq_128* rng) + { + rng->state = _pcg128_add(_pcg128_mult(rng->state, PCG_DEFAULT_MULTIPLIER_128), rng->inc); + } + + inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) + { + return pcg_rotr_64(state.high ^ state.low, + state.high >> 58u); + } + + inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128* rng, + pcg128_t initstate, pcg128_t initseq) + { + rng->state = PCG_128BIT_CONSTANT(0ULL, 0ULL); + rng->inc.high = initseq.high << 1u; + rng->inc.high |= initseq.low & 0x800000000000ULL; + rng->inc.low = (initseq.low << 1u) | 1u; + pcg_setseq_128_step_r(rng); + rng->state = _pcg128_add(rng->state, initstate); + pcg_setseq_128_step_r(rng); + } + +#else /* PCG_EMULATED_128BIT_MATH */ + + inline void pcg_setseq_128_step_r(pcg_state_setseq_128* rng) + { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + rng->inc; + } + + inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) + { + return pcg_rotr_64(((uint64_t)(state >> 64u)) ^ (uint64_t)state, + state >> 122u); + } + + inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128* rng, + pcg128_t initstate, pcg128_t initseq) + { + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_128_step_r(rng); + rng->state += initstate; + pcg_setseq_128_step_r(rng); + } + +#endif /* PCG_EMULATED_128BIT_MATH */ + + + inline uint64_t + pcg_setseq_128_xsl_rr_64_random_r(pcg_state_setseq_128* rng) + { + pcg_setseq_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); + } + + inline uint64_t + pcg_setseq_128_xsl_rr_64_boundedrand_r(pcg_state_setseq_128* rng, + uint64_t bound) + { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } + } + + extern pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult, + pcg128_t cur_plus); + + inline void pcg_setseq_128_advance_r(pcg_state_setseq_128* rng, pcg128_t delta) + { + rng->state = pcg_advance_lcg_128(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_128, rng->inc); + } + + typedef pcg_state_setseq_128 pcg64_random_t; +#define pcg64_random_r pcg_setseq_128_xsl_rr_64_random_r +#define pcg64_boundedrand_r pcg_setseq_128_xsl_rr_64_boundedrand_r +#define pcg64_srandom_r pcg_setseq_128_srandom_r +#define pcg64_advance_r pcg_setseq_128_advance_r +#define PCG64_INITIALIZER PCG_STATE_SETSEQ_128_INITIALIZER + +#if __cplusplus +} +#endif + +#endif /* PCG64_H_INCLUDED */ + + +typedef struct s_pcg64_state { + pcg64_random_t *pcg_state; + int has_uint32; + uint32_t uinteger; +} pcg64_state; + + +static inline uint64_t pcg64_next64(pcg64_state *state) { + return pcg64_random_r(state->pcg_state); +} + +static inline uint32_t pcg64_next32(pcg64_state *state) { + if (state->has_uint32) { + state->has_uint32 = 0; + return state->uinteger; + } + uint64_t next = pcg64_random_r(state->pcg_state); + state->has_uint32 = 1; + state->uinteger = (uint32_t)(next & 0xffffffff); + return (uint32_t)(next >> 32); +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.c b/_randomgen/core_prng/src/xorshift1024/xorshift1024.c new file mode 100644 index 000000000000..a7d1fe0fa9aa --- /dev/null +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024.c @@ -0,0 +1,31 @@ +#include "xorshift1024.h" + +/* This is the jump function for the generator. It is equivalent + to 2^512 calls to next(); it can be used to generate 2^512 + non-overlapping subsequences for parallel computations. */ + +extern inline uint64_t xorshift1024_next(xorshift1024_state *state); +extern inline uint64_t xorshift1024_next64(xorshift1024_state *state); +extern inline uint32_t xorshift1024_next32(xorshift1024_state *state); + +void xorshift1024_jump(xorshift1024_state *state) { + static const uint64_t JUMP[] = { + 0x84242f96eca9c41d, 0xa3c65b8776f96855, 0x5b34a39f070b5837, + 0x4489affce4f31a1e, 0x2ffeeb0a48316f40, 0xdc2d9891fe68c022, + 0x3659132bb12fea70, 0xaac17d8efa43cab8, 0xc4cb815590989b13, + 0x5ee975283d71c93b, 0x691548c86c1bd540, 0x7910c41d10a1e6a5, + 0x0b5fc64563b3e2a8, 0x047f7684e9fc949d, 0xb99181f2d8f685ca, + 0x284600e3f30e38c3}; + + uint64_t t[16] = {0}; + for (int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for (int b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) + for (int j = 0; j < 16; j++) + t[j] ^= state->s[(j + state->p) & 15]; + xorshift1024_next(state); + } + + for (int j = 0; j < 16; j++) + state->s[(j + state->p) & 15] = t[j]; +} diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.h b/_randomgen/core_prng/src/xorshift1024/xorshift1024.h new file mode 100644 index 000000000000..141010d9d5e9 --- /dev/null +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024.h @@ -0,0 +1,33 @@ +#include + +typedef struct s_xorshift1024_state { + uint64_t s[16]; + int p; + int has_uint32; + uint32_t uinteger; +} xorshift1024_state; + +static inline uint64_t xorshift1024_next(xorshift1024_state *state) { + const uint64_t s0 = state->s[state->p]; + uint64_t s1 = state->s[state->p = ((state->p) + 1) & 15]; + s1 ^= s1 << 31; // a + state->s[state->p] = s1 ^ s0 ^ (s1 >> 11) ^ (s0 >> 30); // b,c + return state->s[state->p] * 0x9e3779b97f4a7c13; +} + +static inline uint64_t xorshift1024_next64(xorshift1024_state *state) { + return xorshift1024_next(state); +} + +static inline uint32_t xorshift1024_next32(xorshift1024_state *state) { + if (state->has_uint32) { + state->has_uint32 = 0; + return state->uinteger; + } + uint64_t next = xorshift1024_next(state); + state->has_uint32 = 1; + state->uinteger = (uint32_t)(next & 0xffffffff); + return (uint32_t)(next >> 32); +} + +void xorshift1024_jump(xorshift1024_state *state); \ No newline at end of file diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift2014.orig.c b/_randomgen/core_prng/src/xorshift1024/xorshift2014.orig.c new file mode 100644 index 000000000000..ed1cf8d6ef77 --- /dev/null +++ b/_randomgen/core_prng/src/xorshift1024/xorshift2014.orig.c @@ -0,0 +1,69 @@ +/* Written in 2017 by Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . */ + +#include +#include + +/* NOTE: as of 2017-10-08, this generator has a different multiplier (a + fixed-point representation of the golden ratio), which eliminates + linear dependencies from one of the lowest bits. The previous + multiplier was 1181783497276652981 (M_8 in the paper). If you need to + tell apart the two generators, you can refer to this generator as + xorshift1024*φ and to the previous one as xorshift1024*M_8. + + This is a fast, high-quality generator. If 1024 bits of state are too + much, try a xoroshiro128+ generator. + + Note that the two lowest bits of this generator are LFSRs of degree + 1024, and thus will fail binary rank tests. The other bits needs a much + higher degree to be represented as LFSRs. + + We suggest to use a sign test to extract a random Boolean value, and + right shifts to extract subsets of bits. + + The state must be seeded so that it is not everywhere zero. If you have + a 64-bit seed, we suggest to seed a splitmix64 generator and use its + output to fill s. */ + +uint64_t s[16]; +int p; + +uint64_t next(void) { + const uint64_t s0 = s[p]; + uint64_t s1 = s[p = (p + 1) & 15]; + s1 ^= s1 << 31; // a + s[p] = s1 ^ s0 ^ (s1 >> 11) ^ (s0 >> 30); // b,c + return s[p] * 0x9e3779b97f4a7c13; +} + + +/* This is the jump function for the generator. It is equivalent + to 2^512 calls to next(); it can be used to generate 2^512 + non-overlapping subsequences for parallel computations. */ + +void jump(void) { + static const uint64_t JUMP[] = { 0x84242f96eca9c41d, + 0xa3c65b8776f96855, 0x5b34a39f070b5837, 0x4489affce4f31a1e, + 0x2ffeeb0a48316f40, 0xdc2d9891fe68c022, 0x3659132bb12fea70, + 0xaac17d8efa43cab8, 0xc4cb815590989b13, 0x5ee975283d71c93b, + 0x691548c86c1bd540, 0x7910c41d10a1e6a5, 0x0b5fc64563b3e2a8, + 0x047f7684e9fc949d, 0xb99181f2d8f685ca, 0x284600e3f30e38c3 + }; + + uint64_t t[16] = { 0 }; + for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for(int b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) + for(int j = 0; j < 16; j++) + t[j] ^= s[(j + p) & 15]; + next(); + } + + for(int j = 0; j < 16; j++) + s[(j + p) & 15] = t[j]; +} \ No newline at end of file diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx new file mode 100644 index 000000000000..22892058ede0 --- /dev/null +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -0,0 +1,174 @@ +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + +import numpy as np +cimport numpy as np + +from common cimport * +from core_prng.entropy import random_entropy +import core_prng.pickle +cimport entropy + +np.import_array() + +cdef extern from "src/xorshift1024/xorshift1024.h": + + struct s_xorshift1024_state: + uint64_t s[16] + int p + int has_uint32 + uint32_t uinteger + + ctypedef s_xorshift1024_state xorshift1024_state + + uint64_t xorshift1024_next64(xorshift1024_state *state) nogil + uint64_t xorshift1024_next32(xorshift1024_state *state) nogil + void xorshift1024_jump(xorshift1024_state *state) + +cdef uint64_t xorshift1024_uint64(void* st):# nogil: + return xorshift1024_next64(st) + +cdef uint32_t xorshift1024_uint32(void *st) nogil: + return xorshift1024_next32( st) + +cdef double xorshift1024_double(void* st) nogil: + return uint64_to_double(xorshift1024_next64(st)) + +cdef class XorShift1024: + """ + Prototype Core PRNG using xorshift1024 + + Parameters + ---------- + seed : int, array of int + Integer or array of integers between 0 and 2**64 - 1 + + Notes + ----- + Exposes no user-facing API except `get_state` and `set_state`. Designed + for use in a `RandomGenerator` object. + """ + cdef xorshift1024_state *rng_state + cdef prng_t *_prng + cdef public object _prng_capsule + + def __init__(self, seed=None): + self.rng_state = malloc(sizeof(xorshift1024_state)) + self._prng = malloc(sizeof(prng_t)) + self.seed(seed) + + self._prng.state = self.rng_state + self._prng.next_uint64 = &xorshift1024_uint64 + self._prng.next_uint32 = &xorshift1024_uint32 + self._prng.next_double = &xorshift1024_double + + cdef const char *name = "CorePRNG" + self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__prng_ctor, + (self.state['prng'],), + self.state) + + def __dealloc__(self): + free(self.rng_state) + free(self._prng) + + def _reset_state_variables(self): + self.rng_state.has_uint32 = 0 + self.rng_state.uinteger = 0 + + def __random_integer(self, bits=64): + """ + 64-bit Random Integers from the PRNG + + Parameters + ---------- + bits : {32, 64} + Number of random bits to return + + Returns + ------- + rv : int + Next random value + + Notes + ----- + Testing only + """ + if bits == 64: + return xorshift1024_next64(self.rng_state) + elif bits == 32: + return xorshift1024_next32(self.rng_state) + else: + raise ValueError('bits must be 32 or 64') + + def seed(self, seed=None): + """ + seed(seed=None, stream=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + + """ + ub = 2 ** 64 + if seed is None: + try: + state = random_entropy(32) + except RuntimeError: + state = random_entropy(4, 'fallback') + state = state.view(np.uint64) + else: + state = entropy.seed_by_array(seed, 16) + for i in range(16): + self.rng_state.s[i] = int(state[i]) + self.rng_state.p = 0 + self._reset_state_variables() + + def jump(self): + xorshift1024_jump(self.rng_state) + + @property + def state(self): + """Get or set the PRNG state""" + s = np.empty(16, dtype=np.uint64) + for i in range(16): + s[i] = self.rng_state.s[i] + return {'prng': self.__class__.__name__, + 'state': {'s':s,'p':self.rng_state.p}, + 'has_uint32': self.rng_state.has_uint32, + 'uinteger': self.rng_state.uinteger} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + prng = value.get('prng', '') + if prng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + for i in range(16): + self.rng_state.s[i] = value['state']['s'][i] + self.rng_state.p = value['state']['p'] + self.rng_state.has_uint32 = value['has_uint32'] + self.rng_state.uinteger = value['uinteger'] diff --git a/_randomgen/demo.py b/_randomgen/demo.py index 7fe81af01c25..b15f59830114 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -1,6 +1,6 @@ from core_prng.generator import RandomGenerator -from core_prng import SplitMix64, Xoroshiro128, ThreeFry, MT19937 +from core_prng import SplitMix64, Xoroshiro128, ThreeFry, MT19937, XorShift1024 print(RandomGenerator().random_integer()) print(RandomGenerator(Xoroshiro128()).random_integer()) @@ -48,3 +48,8 @@ print(rg.random_integer()) print(rg.random_integer(32)) print(rg.random_sample()) + +rg = RandomGenerator(XorShift1024()) +state = rg.state +print(state) +rg.state = state diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 3e06920e8844..babb7bbbbd85 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -28,6 +28,13 @@ join(MOD_DIR, 'src', 'mt19937', 'mt19937.c')], include_dirs=[np.get_include(), join(MOD_DIR, 'src', 'mt19937')]), + Extension("core_prng.pcg64", + ["core_prng/pcg64.pyx", + join(MOD_DIR, 'src', 'pcg64', + 'pcg64.c')], + include_dirs=[np.get_include(), + join(MOD_DIR, 'src', 'pcg64')]), + Extension("core_prng.splitmix64", ["core_prng/splitmix64.pyx", join(MOD_DIR, 'src', 'splitmix64', 'splitmix64.c')], @@ -44,6 +51,12 @@ 'xoroshiro128.c')], include_dirs=[np.get_include(), join(MOD_DIR, 'src', 'xoroshiro128')]), + Extension("core_prng.xorshift1024", + ["core_prng/xorshift1024.pyx", + join(MOD_DIR, 'src', 'xorshift1024', + 'xorshift1024.c')], + include_dirs=[np.get_include(), + join(MOD_DIR, 'src', 'xorshift1024')]), Extension("core_prng.generator", ["core_prng/generator.pyx", join(MOD_DIR, 'src', 'distributions', 'distributions.c')], From 12c59970f891906e8dd9e290141d0a9077ca6724 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 4 Mar 2018 23:29:00 +0000 Subject: [PATCH 022/279] ENH: Add advance and jump to PCG64 Add advance and jump Clean other PRNGs --- _randomgen/TODO.md | 8 +++--- _randomgen/core_prng/common.pxd | 22 ++++++++++++++++ _randomgen/core_prng/generator.pyx | 1 + _randomgen/core_prng/mt19937.pyx | 16 ++++++++++-- _randomgen/core_prng/pcg64.pyx | 26 ++++++++++++++----- _randomgen/core_prng/splitmix64.pyx | 16 ++++++++++-- .../core_prng/src/distributions/binomial.h | 0 .../src/distributions/distributions.h | 22 ++++++++++++++++ _randomgen/core_prng/src/pcg64/pcg64.c | 15 ++++++++++- _randomgen/core_prng/src/pcg64/pcg64.h | 8 +++++- _randomgen/core_prng/threefry.pyx | 7 +++-- _randomgen/core_prng/xoroshiro128.pyx | 3 +++ _randomgen/core_prng/xorshift1024.pyx | 7 +++-- _randomgen/demo.py | 10 +++++-- 14 files changed, 139 insertions(+), 22 deletions(-) create mode 100644 _randomgen/core_prng/src/distributions/binomial.h diff --git a/_randomgen/TODO.md b/_randomgen/TODO.md index fac0a525c94d..b374e3a753ff 100644 --- a/_randomgen/TODO.md +++ b/_randomgen/TODO.md @@ -1,20 +1,19 @@ # TODO 2. Add dSFMT -5. Augment state to have binomial structure 6. Port over 0 parameter distributions * standard exponential ziggurat float * standard normal ziggurat * standard normal ziggurat float 7. Remove SplitMix64 as an external generator 8. Restore ability to use `out` in core distributions -10. Seed/Inc for PCG64 -11. Advance/Jump for PCG64 12. Key/Counter for ThreeFry +13. Simplify state ## Done 1. Add PCG64 3. Add xorshift2014 4. Augment state to include has_gauss and gauss +5. Augment state to have binomial structure 6. Port over 0 parameter distributions * standard exponential ziggurat * standard exponential float @@ -22,7 +21,8 @@ * standard normal float * standard gamma - Not implement: This is a 1 param * standard gamma float - Not implement: This is a 1 param - 9. Add correct carry for ThreeFry to allow full set of counters. Important when implemeting jump +10. Seed/Inc for PCG64 +11. Advance/Jump for PCG64 0. NOT IMPLEMENTABLE due to limits on inheritance in Cython: Use inheritance to simplify CorePRNG structure. The natural base is xoroshiro128. diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index b761cc037658..c8b469cc52bc 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -5,6 +5,27 @@ cdef extern from "src/distributions/distributions.h": ctypedef float (*random_float_0)(void *st) nogil + cdef struct s_binomial_t: + int has_binomial; + double psave; + long nsave; + double r; + double q; + double fm; + long m; + double p1; + double xm; + double xl; + double xr; + double c; + double laml; + double lamr; + double p2; + double p3; + double p4; + + ctypedef s_binomial_t binomial_t + cdef struct prng: void *state uint64_t (*next_uint64)(void *st) @@ -14,6 +35,7 @@ cdef extern from "src/distributions/distributions.h": double gauss int has_gauss_f float gauss_f + binomial_t *binomial ctypedef prng prng_t diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 29b364270ade..671fc9080330 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -2,6 +2,7 @@ import numpy as np cimport numpy as np from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from common cimport * +from libc.stdlib cimport malloc, free cimport numpy as np import numpy as np diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index 6c2f4c5786e2..0cbf3e133733 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -56,6 +56,7 @@ cdef class MT19937: def __init__(self, seed=None): self.rng_state = malloc(sizeof(mt19937_state)) self._prng = malloc(sizeof(prng_t)) + self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed) self._prng.state = self.rng_state @@ -68,6 +69,7 @@ cdef class MT19937: def __dealloc__(self): free(self.rng_state) + free(self._prng.binomial) free(self._prng) # Pickling support: @@ -82,10 +84,15 @@ cdef class MT19937: (self.state['prng'],), self.state) - def __random_integer(self): + def __random_integer(self, bits=64): """ 64-bit Random Integers from the PRNG + Parameters + ---------- + bits : {32, 64} + Number of random bits to return + Returns ------- rv : int @@ -95,7 +102,12 @@ cdef class MT19937: ----- Testing only """ - return mt19937_next64(self.rng_state) + if bits == 64: + return self._prng.next_uint64(self._prng.state) + elif bits == 32: + return self._prng.next_uint32(self._prng.state) + else: + raise ValueError('bits must be 32 or 64') def seed(self, seed=None): """ diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index 543202b1293e..08d52351bd66 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -33,6 +33,7 @@ cdef extern from "src/pcg64/pcg64.h": uint64_t pcg64_next64(pcg64_state *state) nogil uint64_t pcg64_next32(pcg64_state *state) nogil void pcg64_jump(pcg64_state *state) + void pcg64_advance(pcg64_state *state, uint64_t *step) cdef uint64_t pcg64_uint64(void* st):# nogil: @@ -62,20 +63,18 @@ cdef class PCG64: cdef prng_t *_prng cdef public object _prng_capsule - def __init__(self, seed=None): + def __init__(self, seed=None, inc=1): self.rng_state = malloc(sizeof(pcg64_state)) self.rng_state.pcg_state = malloc(sizeof(pcg64_random_t)) self._prng = malloc(sizeof(prng_t)) - self.seed(seed) + self._prng.binomial = malloc(sizeof(binomial_t)) + self.seed(seed, inc) self._prng.state = self.rng_state self._prng.next_uint64 = &pcg64_uint64 self._prng.next_uint32 = &pcg64_uint32 self._prng.next_double = &pcg64_double - self.rng_state.pcg_state.inc.high = 0 - self.rng_state.pcg_state.inc.low = 1 - cdef const char *name = "CorePRNG" self._prng_capsule = PyCapsule_New(self._prng, name, NULL) @@ -93,6 +92,7 @@ cdef class PCG64: def __dealloc__(self): free(self.rng_state) + free(self._prng.binomial) free(self._prng) def _reset_state_variables(self): @@ -124,7 +124,7 @@ cdef class PCG64: else: raise ValueError('bits must be 32 or 64') - def seed(self, seed=None): + def seed(self, seed=None, inc=1): """ seed(seed=None, stream=None) @@ -138,6 +138,8 @@ cdef class PCG64: ---------- seed : int, optional Seed for ``RandomState``. + inc : int, optional + Increment to use for PCG stream Raises ------ @@ -156,6 +158,8 @@ cdef class PCG64: state = entropy.seed_by_array(seed, 2) self.rng_state.pcg_state.state.high = int(state[0]) self.rng_state.pcg_state.state.low = int(state[1]) + self.rng_state.pcg_state.inc.high = inc // 2**64 + self.rng_state.pcg_state.inc.low = inc % 2**64 self._reset_state_variables() @property @@ -186,3 +190,13 @@ cdef class PCG64: self.rng_state.pcg_state.inc.low = value['state']['inc'] % 2 ** 64 self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] + + def advance(self, step): + cdef np.ndarray delta = np.empty(2,dtype=np.uint64) + delta[0] = step // 2**64 + delta[1] = step % 2**64 + pcg64_advance(self.rng_state, delta.data) + return self + + def jump(self): + return self.advance(2**64) diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index 515f68884bb8..4ca39c7bbcc3 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -53,6 +53,7 @@ cdef class SplitMix64: def __init__(self, seed=None): self.rng_state = malloc(sizeof(splitmix64_state)) self._prng = malloc(sizeof(prng_t)) + self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed) self._prng.state = self.rng_state @@ -65,6 +66,7 @@ cdef class SplitMix64: def __dealloc__(self): free(self.rng_state) + free(self._prng.binomial) free(self._prng) # Pickling support: @@ -84,10 +86,15 @@ cdef class SplitMix64: self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - def __random_integer(self): + def __random_integer(self, bits=64): """ 64-bit Random Integers from the PRNG + Parameters + ---------- + bits : {32, 64} + Number of random bits to return + Returns ------- rv : int @@ -97,7 +104,12 @@ cdef class SplitMix64: ----- Testing only """ - return splitmix64_next64(self.rng_state) + if bits == 64: + return self._prng.next_uint64(self._prng.state) + elif bits == 32: + return self._prng.next_uint32(self._prng.state) + else: + raise ValueError('bits must be 32 or 64') def seed(self, seed=None): """ diff --git a/_randomgen/core_prng/src/distributions/binomial.h b/_randomgen/core_prng/src/distributions/binomial.h new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index 7c029fe60e02..757029074285 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -20,6 +20,27 @@ typedef int bool; typedef double (*random_double_0)(void *st); typedef float (*random_float_0)(void *st); +typedef struct s_binomial_t +{ + int has_binomial; /* !=0: following parameters initialized for binomial */ + double psave; + long nsave; + double r; + double q; + double fm; + long m; + double p1; + double xm; + double xl; + double xr; + double c; + double laml; + double lamr; + double p2; + double p3; + double p4; +} binomial_t; + typedef struct prng { void *state; uint64_t (*next_uint64)(void *st); @@ -29,6 +50,7 @@ typedef struct prng { double gauss; int has_gauss_f; float gauss_f; + binomial_t *binomial; } prng_t; float random_float(prng_t *prng_state); diff --git a/_randomgen/core_prng/src/pcg64/pcg64.c b/_randomgen/core_prng/src/pcg64/pcg64.c index ba8ce4124cfd..8f29947e0047 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.c +++ b/_randomgen/core_prng/src/pcg64/pcg64.c @@ -89,4 +89,17 @@ pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult, #endif extern inline uint64_t pcg64_next64(pcg64_state *state); -extern inline uint32_t pcg64_next32(pcg64_state *state); \ No newline at end of file +extern inline uint32_t pcg64_next32(pcg64_state *state); + +#if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH) +extern void pcg64_advance(pcg64_state *state, pcg128_t step) { + pcg64_advance_r(state->pcg_state, step); +} +#else +extern void pcg64_advance(pcg64_state *state, uint64_t *step) { + pcg128_t delta; + delta.high = step[0]; + delta.low = step[1]; + pcg64_advance_r(state->pcg_state, delta); +} +#endif \ No newline at end of file diff --git a/_randomgen/core_prng/src/pcg64/pcg64.h b/_randomgen/core_prng/src/pcg64/pcg64.h index 441ebe87d56e..acb6417b86ed 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.h +++ b/_randomgen/core_prng/src/pcg64/pcg64.h @@ -234,4 +234,10 @@ static inline uint32_t pcg64_next32(pcg64_state *state) { state->has_uint32 = 1; state->uinteger = (uint32_t)(next & 0xffffffff); return (uint32_t)(next >> 32); -} \ No newline at end of file +} + +#if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH) +void pcg64_advance(pcg64_state *state, pcg128_t step); +#else +void pcg64_advance(pcg64_state *state, uint64_t *step); +#endif \ No newline at end of file diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index ede7e7caefbb..010fe39f8007 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -68,6 +68,7 @@ cdef class ThreeFry: self.rng_state.ctr = malloc(sizeof(threefry4x64_ctr_t)) self.rng_state.key = malloc(sizeof(threefry4x64_key_t)) self._prng = malloc(sizeof(prng_t)) + self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed) self._prng.state = self.rng_state @@ -94,6 +95,7 @@ cdef class ThreeFry: free(self.rng_state.ctr) free(self.rng_state.key) free(self.rng_state) + free(self._prng.binomial) free(self._prng) def _reset_state_variables(self): @@ -122,9 +124,9 @@ cdef class ThreeFry: Testing only """ if bits == 64: - return threefry_next64(self.rng_state) + return self._prng.next_uint64(self._prng.state) elif bits == 32: - return threefry_next32(self.rng_state) + return self._prng.next_uint32(self._prng.state) else: raise ValueError('bits must be 32 or 64') @@ -200,6 +202,7 @@ cdef class ThreeFry: def jump(self): """Jump the state as-if 2**128 draws have been made""" threefry_jump(self.rng_state) + return self def advance(self, step): """Advance the state as-if a specific number of draws have been made""" diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 69ce93c31f84..38d46b1d7eb8 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -55,6 +55,7 @@ cdef class Xoroshiro128: def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoroshiro128_state)) self._prng = malloc(sizeof(prng_t)) + self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed) self._prng.state = self.rng_state @@ -79,6 +80,7 @@ cdef class Xoroshiro128: def __dealloc__(self): free(self.rng_state) + free(self._prng.binomial) free(self._prng) def _reset_state_variables(self): @@ -146,6 +148,7 @@ cdef class Xoroshiro128: def jump(self): xoroshiro128_jump(self.rng_state) + return self @property def state(self): diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index 22892058ede0..0ca23b0a3e98 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -55,6 +55,7 @@ cdef class XorShift1024: def __init__(self, seed=None): self.rng_state = malloc(sizeof(xorshift1024_state)) self._prng = malloc(sizeof(prng_t)) + self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed) self._prng.state = self.rng_state @@ -79,6 +80,7 @@ cdef class XorShift1024: def __dealloc__(self): free(self.rng_state) + free(self._prng.binomial) free(self._prng) def _reset_state_variables(self): @@ -104,9 +106,9 @@ cdef class XorShift1024: Testing only """ if bits == 64: - return xorshift1024_next64(self.rng_state) + return self._prng.next_uint64(self._prng.state) elif bits == 32: - return xorshift1024_next32(self.rng_state) + return self._prng.next_uint32(self._prng.state) else: raise ValueError('bits must be 32 or 64') @@ -147,6 +149,7 @@ cdef class XorShift1024: def jump(self): xorshift1024_jump(self.rng_state) + return self @property def state(self): diff --git a/_randomgen/demo.py b/_randomgen/demo.py index b15f59830114..47353f9ae6da 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -1,8 +1,8 @@ from core_prng.generator import RandomGenerator -from core_prng import SplitMix64, Xoroshiro128, ThreeFry, MT19937, XorShift1024 +from core_prng import SplitMix64, Xoroshiro128, ThreeFry, MT19937, XorShift1024, PCG64 -print(RandomGenerator().random_integer()) +print(RandomGenerator().random_integer(32)) print(RandomGenerator(Xoroshiro128()).random_integer()) print(RandomGenerator(ThreeFry()).random_integer()) print(RandomGenerator(SplitMix64()).random_integer()) @@ -22,6 +22,7 @@ print(rg.state) import numpy as np + a = rg.random_sample((1, 1), dtype=np.float32) print(a) print(a.dtype) @@ -53,3 +54,8 @@ state = rg.state print(state) rg.state = state + +rg = RandomGenerator(PCG64()) +state = rg.state +print(state) +rg.state = state From 3beb59459929d108a9e36b9753a3cb13bd2ec183 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Mar 2018 10:21:18 +0000 Subject: [PATCH 023/279] ENH: Add Philox Add philox as a core PRNG --- _randomgen/core_prng/__init__.py | 1 + _randomgen/core_prng/mt19937.pyx | 5 + _randomgen/core_prng/pcg64.pyx | 6 + _randomgen/core_prng/philox.pyx | 232 +++++++++++++++++++++++ _randomgen/core_prng/splitmix64.pyx | 6 + _randomgen/core_prng/src/philox/philox.c | 29 +++ _randomgen/core_prng/src/philox/philox.h | 183 ++++++++++++++++++ _randomgen/core_prng/threefry.pyx | 11 +- _randomgen/core_prng/xoroshiro128.pyx | 5 + _randomgen/core_prng/xorshift1024.pyx | 5 + _randomgen/demo.py | 10 +- _randomgen/papers/random123sc11.pdf | Bin 0 -> 280039 bytes _randomgen/setup.py | 5 + 13 files changed, 492 insertions(+), 6 deletions(-) create mode 100644 _randomgen/core_prng/philox.pyx create mode 100644 _randomgen/core_prng/src/philox/philox.c create mode 100644 _randomgen/core_prng/src/philox/philox.h create mode 100644 _randomgen/papers/random123sc11.pdf diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index c6123e023d03..1e528323b1d4 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -5,6 +5,7 @@ from .threefry import ThreeFry from .xoroshiro128 import Xoroshiro128 from .xorshift1024 import XorShift1024 +from .philox import Philox __all__ = ['RandomGenerator', 'SplitMix64', 'PCG64', 'Xoroshiro128', 'ThreeFry', 'MT19937', 'XorShift1024'] diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index 0cbf3e133733..9e6b936efb5a 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -109,6 +109,11 @@ cdef class MT19937: else: raise ValueError('bits must be 32 or 64') + def _benchmark(self, Py_ssize_t cnt): + cdef Py_ssize_t i + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + def seed(self, seed=None): """ seed(seed=None, stream=None) diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index 08d52351bd66..4a3dcfc4b514 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -124,6 +124,12 @@ cdef class PCG64: else: raise ValueError('bits must be 32 or 64') + def _benchmark(self, Py_ssize_t cnt): + cdef Py_ssize_t i + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + + def seed(self, seed=None, inc=1): """ seed(seed=None, stream=None) diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx new file mode 100644 index 000000000000..111d702be680 --- /dev/null +++ b/_randomgen/core_prng/philox.pyx @@ -0,0 +1,232 @@ +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + +import numpy as np +cimport numpy as np + +from common cimport * +from core_prng.entropy import random_entropy +import core_prng.pickle +cimport entropy + +np.import_array() + +cdef extern from "src/philox/philox.h": + struct s_r123array2x64: + uint64_t v[2] + + struct s_r123array4x64: + uint64_t v[4] + + ctypedef s_r123array4x64 r123array4x64 + ctypedef s_r123array2x64 r123array2x64 + + ctypedef r123array4x64 philox4x64_ctr_t; + ctypedef r123array2x64 philox4x64_key_t; + + struct s_philox_state: + philox4x64_ctr_t *ctr; + philox4x64_key_t *key; + int buffer_pos; + uint64_t buffer[4]; + int has_uint32 + uint32_t uinteger + + ctypedef s_philox_state philox_state + + uint64_t philox_next64(philox_state *state) nogil + uint64_t philox_next32(philox_state *state) nogil + void philox_jump(philox_state *state) + void philox_advance(uint64_t *step, philox_state *state) + + +cdef uint64_t philox_uint64(void*st) nogil: + return philox_next64( st) + +cdef uint32_t philox_uint32(void *st) nogil: + return philox_next32( st) + +cdef double philox_double(void*st) nogil: + return uint64_to_double(philox_next64( st)) + +cdef class Philox: + """ + Prototype Core PRNG using philox + + Parameters + ---------- + seed : int, array of int + Integer or array of integers between 0 and 2**64 - 1 + + Notes + ----- + Exposes no user-facing API except `state`. Designed for use in + a `RandomGenerator` object. + """ + cdef philox_state *rng_state + cdef prng_t *_prng + cdef public object _prng_capsule + + def __init__(self, seed=None): + self.rng_state = malloc(sizeof(philox_state)) + self.rng_state.ctr = malloc( + sizeof(philox4x64_ctr_t)) + self.rng_state.key = malloc( + sizeof(philox4x64_key_t)) + self._prng = malloc(sizeof(prng_t)) + self._prng.binomial = malloc(sizeof(binomial_t)) + self.seed(seed) + + self._prng.state = self.rng_state + self._prng.next_uint64 = &philox_uint64 + self._prng.next_uint32 = &philox_uint32 + self._prng.next_double = &philox_double + + cdef const char *name = "CorePRNG" + self._prng_capsule = PyCapsule_New( self._prng, name, NULL) + + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__prng_ctor, + (self.state['prng'],), + self.state) + + def __dealloc__(self): + free(self.rng_state.ctr) + free(self.rng_state.key) + free(self.rng_state) + free(self._prng.binomial) + free(self._prng) + + def _reset_state_variables(self): + self.rng_state.has_uint32 = 0 + self.rng_state.uinteger = 0 + self.rng_state.buffer_pos = 4 + for i in range(4): + self.rng_state.buffer[i] = 0 + + def __random_integer(self, bits=64): + """ + 64-bit Random Integers from the PRNG + + Parameters + ---------- + bits : {32, 64} + Number of random bits to return + + Returns + ------- + rv : int + Next random value + + Notes + ----- + Testing only + """ + if bits == 64: + return self._prng.next_uint64(self._prng.state) + elif bits == 32: + return self._prng.next_uint32(self._prng.state) + else: + raise ValueError('bits must be 32 or 64') + + def _benchmark(self, Py_ssize_t cnt): + cdef Py_ssize_t i + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + + def seed(self, seed=None): + """ + seed(seed=None, stream=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + """ + ub = 2 ** 64 + if seed is None: + try: + state = random_entropy(4) + except RuntimeError: + state = random_entropy(4, 'fallback') + state = state.view(np.uint64) + else: + state = entropy.seed_by_array(seed, 2) + # TODO: Need to be able to set the key and counter directly + for i in range(4): + self.rng_state.ctr.v[i] = 0 + self.rng_state.key.v[0] = state[0] + self.rng_state.key.v[1] = state[1] + self._reset_state_variables() + + @property + def state(self): + """Get or set the PRNG state""" + ctr = np.empty(4, dtype=np.uint64) + key = np.empty(2, dtype=np.uint64) + buffer = np.empty(4, dtype=np.uint64) + for i in range(4): + ctr[i] = self.rng_state.ctr.v[i] + buffer[i] = self.rng_state.buffer[i] + if i < 2: + key[i] = self.rng_state.key.v[i] + + state = {'ctr': ctr, 'key': key} + return {'prng': self.__class__.__name__, + 'state': state, + 'buffer': buffer, + 'buffer_pos': self.rng_state.buffer_pos, + 'has_uint32': self.rng_state.has_uint32, + 'uinteger': self.rng_state.uinteger} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + prng = value.get('prng', '') + if prng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + for i in range(4): + self.rng_state.ctr.v[i] = value['state']['ctr'][i] + self.rng_state.buffer[i] = value['buffer'][i] + if i < 2: + self.rng_state.key.v[i] = value['state']['key'][i] + self.rng_state.has_uint32 = value['has_uint32'] + self.rng_state.uinteger = value['uinteger'] + self.rng_state.buffer_pos = value['buffer_pos'] + + def jump(self): + """Jump the state as-if 2**128 draws have been made""" + philox_jump(self.rng_state) + return self + + def advance(self, step): + """Advance the state as-if a specific number of draws have been made""" + cdef np.ndarray step_a = np.zeros(4, dtype=np.uint64) + if step >= 2 ** 256 or step < 0: + raise ValueError('step must be between 0 and 2**256-1') + loc = 0 + while step > 0: + step_a[loc] = step % 2 ** 64 + step >>= 64 + loc += 1 + philox_advance( step_a.data, self.rng_state) diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx index 4ca39c7bbcc3..fbc41544cd2f 100644 --- a/_randomgen/core_prng/splitmix64.pyx +++ b/_randomgen/core_prng/splitmix64.pyx @@ -111,6 +111,12 @@ cdef class SplitMix64: else: raise ValueError('bits must be 32 or 64') + def _benchmark(self, Py_ssize_t cnt): + cdef Py_ssize_t i + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + + def seed(self, seed=None): """ seed(seed=None, stream=None) diff --git a/_randomgen/core_prng/src/philox/philox.c b/_randomgen/core_prng/src/philox/philox.c new file mode 100644 index 000000000000..06eaa3400ebb --- /dev/null +++ b/_randomgen/core_prng/src/philox/philox.c @@ -0,0 +1,29 @@ +#include "philox.h" + +extern inline uint64_t philox_next64(philox_state *state); + +extern inline uint64_t philox_next32(philox_state *state); + +extern void philox_jump(philox_state *state) { + /* Advances state as-if 2^128 draws were made */ + state->ctr->v[2]++; + if (state->ctr->v[2] == 0) { + state->ctr->v[3]++; + } +} + +extern void philox_advance(uint64_t *step, philox_state *state) { + int i, carry = 0; + uint64_t v_orig; + for (i = 0; i < 4; i++) { + if (carry == 1) { + state->ctr->v[i]++; + carry = state->ctr->v[i] == 0 ? 1 : 0; + } + v_orig = state->ctr->v[i]; + state->ctr->v[i] += step[i]; + if (state->ctr->v[i] < v_orig && carry == 0) { + carry = 1; + } + } +} diff --git a/_randomgen/core_prng/src/philox/philox.h b/_randomgen/core_prng/src/philox/philox.h new file mode 100644 index 000000000000..1c6baf3075e5 --- /dev/null +++ b/_randomgen/core_prng/src/philox/philox.h @@ -0,0 +1,183 @@ +#include + +struct r123array2x64 { + uint64_t v[2]; +}; +struct r123array4x64 { + uint64_t v[4]; +}; + +enum r123_enum_philox4x64 { philox4x64_rounds = 10 }; +typedef struct r123array4x64 philox4x64_ctr_t; +typedef struct r123array2x64 philox4x64_key_t; +typedef struct r123array2x64 philox4x64_ukey_t; + +static __inline struct r123array2x64 +_philox4x64bumpkey(struct r123array2x64 key) { + key.v[0] += (0x9E3779B97F4A7C15ULL); + key.v[1] += (0xBB67AE8584CAA73BULL); + return key; +} + +#ifdef _WIN32 +/* TODO: This isn't correct for many platforms */ +#include +#pragma intrinsic(_umul128) + +static __inline uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { + return _umul128(a, b, hip); +} +#else +static inline uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { + __uint128_t product = ((__uint128_t)a) * ((__uint128_t)b); + *hip = product >> 64; + return (uint64_t)product; +} +#endif + +// static __inline _forceinline struct r123array4x64 _philox4x64round(struct +// r123array4x64 ctr, struct r123array2x64 key); + +static __inline _forceinline struct r123array4x64 +_philox4x64round(struct r123array4x64 ctr, struct r123array2x64 key) { + uint64_t hi0; + uint64_t hi1; + uint64_t lo0 = mulhilo64((0xD2E7470EE14C6C93ULL), ctr.v[0], &hi0); + uint64_t lo1 = mulhilo64((0xCA5A826395121157ULL), ctr.v[2], &hi1); + struct r123array4x64 out = { + {hi1 ^ ctr.v[1] ^ key.v[0], lo1, hi0 ^ ctr.v[3] ^ key.v[1], lo0}}; + return out; +} + +static __inline philox4x64_key_t philox4x64keyinit(philox4x64_ukey_t uk) { + return uk; +} +// static __inline _forceinline philox4x64_ctr_t philox4x64_R(unsigned int R, +// philox4x64_ctr_t ctr, philox4x64_key_t key); + +static __inline _forceinline philox4x64_ctr_t +philox4x64_R(unsigned int R, philox4x64_ctr_t ctr, philox4x64_key_t key) { + if (R > 0) { + ctr = _philox4x64round(ctr, key); + } + if (R > 1) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 2) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 3) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 4) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 5) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 6) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 7) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 8) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 9) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 10) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 11) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 12) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 13) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 14) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + if (R > 15) { + key = _philox4x64bumpkey(key); + ctr = _philox4x64round(ctr, key); + } + return ctr; +} + +typedef struct s_philox_state { + philox4x64_ctr_t *ctr; + philox4x64_key_t *key; + int buffer_pos; + uint64_t buffer[4]; + int has_uint32; + uint32_t uinteger; +} philox_state; + +static inline uint64_t philox_next(philox_state *state) { + /* TODO: This 4 should be a constant somewhere */ + if (state->buffer_pos < 4) { + uint64_t out = state->buffer[state->buffer_pos]; + state->buffer_pos++; + return out; + } + /* generate 4 new uint64_t */ + int i; + philox4x64_ctr_t ct; + state->ctr->v[0]++; + /* Handle carry */ + if (state->ctr->v[0] == 0) { + state->ctr->v[1]++; + if (state->ctr->v[1] == 0) { + state->ctr->v[2]++; + if (state->ctr->v[2] == 0) { + state->ctr->v[3]++; + } + } + } + ct = philox4x64_R(philox4x64_rounds, *state->ctr, *state->key); + for (i = 0; i < 4; i++) { + state->buffer[i] = ct.v[i]; + } + state->buffer_pos = 1; + return state->buffer[0]; +} + +static inline uint64_t philox_next64(philox_state *state) { + return philox_next(state); +} + +static inline uint64_t philox_next32(philox_state *state) { + if (state->has_uint32) { + state->has_uint32 = 0; + return state->uinteger; + } + uint64_t next = philox_next(state); + + state->has_uint32 = 1; + state->uinteger = (uint32_t)(next & 0xffffffff); + + return (uint32_t)(next >> 32); +} + +extern void philox_jump(philox_state *state); + +extern void philox_advance(uint64_t *step, philox_state *state); diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index 010fe39f8007..3c669a439ca2 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -21,8 +21,8 @@ cdef extern from "src/threefry/threefry.h": ctypedef r123array4x64 threefry4x64_ctr_t struct s_threefry_state: - threefry4x64_key_t *ctr; - threefry4x64_ctr_t *key; + threefry4x64_ctr_t *ctr; + threefry4x64_key_t *key; int buffer_pos; uint64_t buffer[4]; int has_uint32 @@ -130,6 +130,11 @@ cdef class ThreeFry: else: raise ValueError('bits must be 32 or 64') + def _benchmark(self, Py_ssize_t cnt): + cdef Py_ssize_t i + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + def seed(self, seed=None): """ seed(seed=None, stream=None) @@ -158,7 +163,7 @@ cdef class ThreeFry: state = random_entropy(8, 'fallback') state = state.view(np.uint64) else: - state = entropy.seed_by_array(seed, 2) + state = entropy.seed_by_array(seed, 4) # TODO: Need to be able to set the key and counter directly for i in range(4): self.rng_state.ctr.v[i] = 0 diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 38d46b1d7eb8..0c1f90998d9d 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -112,6 +112,11 @@ cdef class Xoroshiro128: else: raise ValueError('bits must be 32 or 64') + def _benchmark(self, Py_ssize_t cnt): + cdef Py_ssize_t i + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + def seed(self, seed=None): """ seed(seed=None, stream=None) diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index 0ca23b0a3e98..b7b6fc42349f 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -112,6 +112,11 @@ cdef class XorShift1024: else: raise ValueError('bits must be 32 or 64') + def _benchmark(self, Py_ssize_t cnt): + cdef Py_ssize_t i + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + def seed(self, seed=None): """ seed(seed=None, stream=None) diff --git a/_randomgen/demo.py b/_randomgen/demo.py index 47353f9ae6da..5ab97f01fb63 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -1,7 +1,7 @@ +from core_prng import SplitMix64, Xoroshiro128, ThreeFry, MT19937, \ + XorShift1024, PCG64, Philox from core_prng.generator import RandomGenerator -from core_prng import SplitMix64, Xoroshiro128, ThreeFry, MT19937, XorShift1024, PCG64 - print(RandomGenerator().random_integer(32)) print(RandomGenerator(Xoroshiro128()).random_integer()) print(RandomGenerator(ThreeFry()).random_integer()) @@ -22,7 +22,6 @@ print(rg.state) import numpy as np - a = rg.random_sample((1, 1), dtype=np.float32) print(a) print(a.dtype) @@ -59,3 +58,8 @@ state = rg.state print(state) rg.state = state + +rg = RandomGenerator(Philox()) +state = rg.state +print(state) +rg.state = state diff --git a/_randomgen/papers/random123sc11.pdf b/_randomgen/papers/random123sc11.pdf new file mode 100644 index 0000000000000000000000000000000000000000..360459924069b54c0c6ab01409d6ccd0d13d6a02 GIT binary patch literal 280039 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%0AvI7VN6Q;@oF<` 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

20`c50&Iy94^Wyv^r}!uU;$V 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൚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 S9s<&0uvj`lK}9Vky8i)Ig%*JT literal 0 HcmV?d00001 diff --git a/_randomgen/setup.py b/_randomgen/setup.py index babb7bbbbd85..46cbe56eb7ca 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -28,6 +28,11 @@ join(MOD_DIR, 'src', 'mt19937', 'mt19937.c')], include_dirs=[np.get_include(), join(MOD_DIR, 'src', 'mt19937')]), + Extension("core_prng.philox", + ["core_prng/philox.pyx", + join(MOD_DIR, 'src', 'philox', 'philox.c')], + include_dirs=[np.get_include(), + join(MOD_DIR, 'src', 'philox')]), Extension("core_prng.pcg64", ["core_prng/pcg64.pyx", join(MOD_DIR, 'src', 'pcg64', From 4a35374dbe7a5997d23d54dafca2e398b4dd1868 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Mar 2018 10:27:38 +0000 Subject: [PATCH 024/279] CLN: Remove splitmix64 as a visible PRNG Retain splitmix64 for internal use Default is now xoroshiro128 --- _randomgen/TODO.md | 2 +- _randomgen/core_prng/__init__.py | 7 +- _randomgen/core_prng/generator.pyx | 4 +- _randomgen/core_prng/pickle.py | 10 +- _randomgen/core_prng/splitmix64.pyx | 172 -------------------------- _randomgen/core_prng/xorshift1024.pyx | 2 +- _randomgen/demo.py | 10 +- _randomgen/setup.py | 6 - 8 files changed, 17 insertions(+), 196 deletions(-) delete mode 100644 _randomgen/core_prng/splitmix64.pyx diff --git a/_randomgen/TODO.md b/_randomgen/TODO.md index b374e3a753ff..2be06b8ec4bf 100644 --- a/_randomgen/TODO.md +++ b/_randomgen/TODO.md @@ -4,7 +4,6 @@ * standard exponential ziggurat float * standard normal ziggurat * standard normal ziggurat float -7. Remove SplitMix64 as an external generator 8. Restore ability to use `out` in core distributions 12. Key/Counter for ThreeFry 13. Simplify state @@ -21,6 +20,7 @@ * standard normal float * standard gamma - Not implement: This is a 1 param * standard gamma float - Not implement: This is a 1 param +7. Remove SplitMix64 as an external generator 9. Add correct carry for ThreeFry to allow full set of counters. Important when implemeting jump 10. Seed/Inc for PCG64 11. Advance/Jump for PCG64 diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index 1e528323b1d4..7f554c4d3f97 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -1,14 +1,13 @@ from .generator import RandomGenerator from .mt19937 import MT19937 from .pcg64 import PCG64 -from .splitmix64 import SplitMix64 from .threefry import ThreeFry from .xoroshiro128 import Xoroshiro128 -from .xorshift1024 import XorShift1024 +from .xorshift1024 import Xorshift1024 from .philox import Philox -__all__ = ['RandomGenerator', 'SplitMix64', 'PCG64', 'Xoroshiro128', - 'ThreeFry', 'MT19937', 'XorShift1024'] +__all__ = ['RandomGenerator', 'PCG64', 'Xoroshiro128', + 'ThreeFry', 'MT19937', 'Xorshift1024'] from ._version import get_versions diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 671fc9080330..1447e44783d1 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -15,7 +15,7 @@ try: except ImportError: from dummy_threading import Lock -from core_prng.splitmix64 import SplitMix64 +from core_prng.xoroshiro128 import Xoroshiro128 import core_prng.pickle np.import_array() @@ -50,7 +50,7 @@ cdef class RandomGenerator: def __init__(self, prng=None): if prng is None: - prng = SplitMix64() + prng = Xoroshiro128() self.__core_prng = prng capsule = prng._prng_capsule diff --git a/_randomgen/core_prng/pickle.py b/_randomgen/core_prng/pickle.py index e3fede9210b4..d4e5a1f71d63 100644 --- a/_randomgen/core_prng/pickle.py +++ b/_randomgen/core_prng/pickle.py @@ -1,12 +1,16 @@ from .generator import RandomGenerator from .mt19937 import MT19937 -from .splitmix64 import SplitMix64 +from .pcg64 import PCG64 +from .philox import Philox from .threefry import ThreeFry from .xoroshiro128 import Xoroshiro128 +from .xorshift1024 import Xorshift1024 -PRNGS = {'SplitMix64': SplitMix64, +PRNGS = {'MT19937': MT19937, + 'PCG64': PCG64, + 'Philox': Philox, 'ThreeFry': ThreeFry, - 'MT19937': MT19937, + 'Xorshift1024': Xorshift1024, 'Xoroshiro128': Xoroshiro128} diff --git a/_randomgen/core_prng/splitmix64.pyx b/_randomgen/core_prng/splitmix64.pyx deleted file mode 100644 index fbc41544cd2f..000000000000 --- a/_randomgen/core_prng/splitmix64.pyx +++ /dev/null @@ -1,172 +0,0 @@ -from libc.stdint cimport uint32_t, uint64_t -from libc.stdlib cimport malloc, free -from cpython.pycapsule cimport PyCapsule_New - -import numpy as np -cimport numpy as np - -from common cimport * -from core_prng.entropy import random_entropy -import core_prng.pickle -cimport entropy - -np.import_array() - -cdef extern from "src/splitmix64/splitmix64.h": - struct s_splitmix64_state: - uint64_t state - int has_uint32 - uint32_t uinteger - - ctypedef s_splitmix64_state splitmix64_state - - uint64_t splitmix64_next64(splitmix64_state *state) nogil - uint32_t splitmix64_next32(splitmix64_state *state) nogil - -cdef uint64_t splitmix64_uint64(void *st) nogil: - return splitmix64_next64( st) - -cdef uint32_t splitmix64_uint32(void *st) nogil: - return splitmix64_next32( st) - -cdef double splitmix64_double(void *st) nogil: - return uint64_to_double(splitmix64_uint64( st)) - -cdef class SplitMix64: - """ - Prototype Core PRNG using directly implemented version of SplitMix64. - - Parameters - ---------- - seed : int, array of int - Integer or array of integers between 0 and 2**64 - 1 - - Notes - ----- - Exposes no user-facing API except `get_state` and `set_state`. Designed - for use in a `RandomGenerator` object. - """ - cdef splitmix64_state *rng_state - cdef prng_t *_prng - cdef public object _prng_capsule - - def __init__(self, seed=None): - self.rng_state = malloc(sizeof(splitmix64_state)) - self._prng = malloc(sizeof(prng_t)) - self._prng.binomial = malloc(sizeof(binomial_t)) - self.seed(seed) - - self._prng.state = self.rng_state - self._prng.next_uint64 = &splitmix64_uint64 - self._prng.next_uint32 = &splitmix64_uint32 - self._prng.next_double = &splitmix64_double - - cdef const char *name = "CorePRNG" - self._prng_capsule = PyCapsule_New(self._prng, name, NULL) - - def __dealloc__(self): - free(self.rng_state) - free(self._prng.binomial) - free(self._prng) - - # Pickling support: - def __getstate__(self): - return self.state - - def __setstate__(self, state): - self.state = state - - def __reduce__(self): - return (core_prng.pickle.__prng_ctor, - (self.state['prng'],), - self.state) - - - def _reset_state_variables(self): - self.rng_state.has_uint32 = 0 - self.rng_state.uinteger = 0 - - def __random_integer(self, bits=64): - """ - 64-bit Random Integers from the PRNG - - Parameters - ---------- - bits : {32, 64} - Number of random bits to return - - Returns - ------- - rv : int - Next random value - - Notes - ----- - Testing only - """ - if bits == 64: - return self._prng.next_uint64(self._prng.state) - elif bits == 32: - return self._prng.next_uint32(self._prng.state) - else: - raise ValueError('bits must be 32 or 64') - - def _benchmark(self, Py_ssize_t cnt): - cdef Py_ssize_t i - for i in range(cnt): - self._prng.next_uint64(self._prng.state) - - - def seed(self, seed=None): - """ - seed(seed=None, stream=None) - - Seed the generator. - - This method is called when ``RandomState`` is initialized. It can be - called again to re-seed the generator. For details, see - ``RandomState``. - - Parameters - ---------- - seed : int, optional - Seed for ``RandomState``. - - Raises - ------ - ValueError - If seed values are out of range for the PRNG. - - """ - ub = 2 ** 64 - if seed is None: - try: - state = random_entropy(2) - except RuntimeError: - state = random_entropy(2, 'fallback') - state = state.view(np.uint64) - else: - state = entropy.seed_by_array(seed, 1) - self.rng_state.state = int(state[0]) - self._reset_state_variables() - - - @property - def state(self): - """Get or set the PRNG state""" - return {'prng': self.__class__.__name__, - 's': self.rng_state.state, - 'has_uint32': self.rng_state.has_uint32, - 'uinteger': self.rng_state.uinteger} - - @state.setter - def state(self, value): - if not isinstance(value, dict): - raise TypeError('state must be a dict') - prng = value.get('prng', '') - if prng != self.__class__.__name__: - raise ValueError('state must be for a {0} ' - 'PRNG'.format(self.__class__.__name__)) - self.rng_state.state = value['s'] - self.rng_state.has_uint32 = value['has_uint32'] - self.rng_state.uinteger = value['uinteger'] diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index b7b6fc42349f..f693d5a7e208 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -34,7 +34,7 @@ cdef uint32_t xorshift1024_uint32(void *st) nogil: cdef double xorshift1024_double(void* st) nogil: return uint64_to_double(xorshift1024_next64(st)) -cdef class XorShift1024: +cdef class Xorshift1024: """ Prototype Core PRNG using xorshift1024 diff --git a/_randomgen/demo.py b/_randomgen/demo.py index 5ab97f01fb63..0acf66da49b2 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -1,14 +1,10 @@ -from core_prng import SplitMix64, Xoroshiro128, ThreeFry, MT19937, \ - XorShift1024, PCG64, Philox +from core_prng import Xoroshiro128, ThreeFry, MT19937, \ + Xorshift1024, PCG64, Philox from core_prng.generator import RandomGenerator print(RandomGenerator().random_integer(32)) print(RandomGenerator(Xoroshiro128()).random_integer()) print(RandomGenerator(ThreeFry()).random_integer()) -print(RandomGenerator(SplitMix64()).random_integer()) -print(RandomGenerator(SplitMix64()).random_integer()) -print(RandomGenerator(SplitMix64(1)).random_integer()) -print(RandomGenerator(SplitMix64([1.0, 2.0])).random_integer()) print('\n' * 3) print('Check random_sample') @@ -49,7 +45,7 @@ print(rg.random_integer(32)) print(rg.random_sample()) -rg = RandomGenerator(XorShift1024()) +rg = RandomGenerator(Xorshift1024()) state = rg.state print(state) rg.state = state diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 46cbe56eb7ca..fcda70ad0d0c 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -39,12 +39,6 @@ 'pcg64.c')], include_dirs=[np.get_include(), join(MOD_DIR, 'src', 'pcg64')]), - - Extension("core_prng.splitmix64", - ["core_prng/splitmix64.pyx", - join(MOD_DIR, 'src', 'splitmix64', 'splitmix64.c')], - include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'splitmix64')]), Extension("core_prng.threefry", ["core_prng/threefry.pyx", join(MOD_DIR, 'src', 'threefry', 'threefry.c')], From ef7637dcda994919f69b107813380b41b970d9ef Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Mar 2018 12:21:08 +0000 Subject: [PATCH 025/279] BUG: Fix bugs which prevented building on Linux Fix definitions in PCG Fix inlining in Philox --- _randomgen/core_prng/pcg64.pyx | 55 +++-- _randomgen/core_prng/src/pcg64/pcg64.c | 103 ++++---- _randomgen/core_prng/src/pcg64/pcg64.h | 285 +++++++++++------------ _randomgen/core_prng/src/philox/philox.h | 12 +- _randomgen/setup.py | 6 +- 5 files changed, 241 insertions(+), 220 deletions(-) diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index 4a3dcfc4b514..49b9b9d02fe9 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -11,11 +11,28 @@ cimport entropy np.import_array() +DEF PCG_EMULATED_MATH=0 + +IF PCG_EMULATED_MATH: + cdef extern from "src/pcg64/pcg64.h": + + ctypedef struct pcg128_t: + uint64_t high + uint64_t low +ELSE: + cdef extern from "inttypes.h": + ctypedef unsigned long long __uint128_t + + cdef extern from "src/pcg64/pcg64.h": + ctypedef __uint128_t pcg128_t + cdef extern from "src/pcg64/pcg64.h": ctypedef struct pcg128_t: uint64_t high - uint64_t low + uint64_t low + +cdef extern from "src/pcg64/pcg64.h": cdef struct pcg_state_setseq_128: pcg128_t state @@ -162,19 +179,27 @@ cdef class PCG64: state = state.view(np.uint64) else: state = entropy.seed_by_array(seed, 2) - self.rng_state.pcg_state.state.high = int(state[0]) - self.rng_state.pcg_state.state.low = int(state[1]) - self.rng_state.pcg_state.inc.high = inc // 2**64 - self.rng_state.pcg_state.inc.low = inc % 2**64 + IF PCG_EMULATED_MATH: + self.rng_state.pcg_state.state.high = int(state[0]) + self.rng_state.pcg_state.state.low = int(state[1]) + self.rng_state.pcg_state.inc.high = inc // 2**64 + self.rng_state.pcg_state.inc.low = inc % 2**64 + ELSE: + self.rng_state.pcg_state.state = state[0] * 2**64 + state[1] + self.rng_state.pcg_state.inc = inc self._reset_state_variables() @property def state(self): """Get or set the PRNG state""" - state = 2 **64 * self.rng_state.pcg_state.state.high - state += self.rng_state.pcg_state.state.low - inc = 2 **64 * self.rng_state.pcg_state.inc.high - inc += self.rng_state.pcg_state.inc.low + IF PCG_EMULATED_MATH: + state = 2 **64 * self.rng_state.pcg_state.state.high + state += self.rng_state.pcg_state.state.low + inc = 2 **64 * self.rng_state.pcg_state.inc.high + inc += self.rng_state.pcg_state.inc.low + ELSE: + state = self.rng_state.pcg_state.state + inc = self.rng_state.pcg_state.inc return {'prng': self.__class__.__name__, 'state': {'state': state, 'inc':inc}, @@ -189,11 +214,15 @@ cdef class PCG64: if prng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) + IF PCG_EMULATED_MATH: + self.rng_state.pcg_state.state.high = value['state']['state'] // 2 ** 64 + self.rng_state.pcg_state.state.low = value['state']['state'] % 2 ** 64 + self.rng_state.pcg_state.inc.high = value['state']['inc'] // 2 ** 64 + self.rng_state.pcg_state.inc.low = value['state']['inc'] % 2 ** 64 + ELSE: + self.rng_state.pcg_state.state = value['state']['state'] + self.rng_state.pcg_state.inc = value['state']['inc'] - self.rng_state.pcg_state.state.high = value['state']['state'] // 2 ** 64 - self.rng_state.pcg_state.state.low = value['state']['state'] % 2 ** 64 - self.rng_state.pcg_state.inc.high = value['state']['inc'] // 2 ** 64 - self.rng_state.pcg_state.inc.low = value['state']['inc'] % 2 ** 64 self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] diff --git a/_randomgen/core_prng/src/pcg64/pcg64.c b/_randomgen/core_prng/src/pcg64/pcg64.c index 8f29947e0047..f51099f3f314 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.c +++ b/_randomgen/core_prng/src/pcg64/pcg64.c @@ -24,66 +24,67 @@ #include "pcg64.h" -extern inline void pcg_setseq_128_step_r(pcg_state_setseq_128* rng); +extern inline void pcg_setseq_128_step_r(pcg_state_setseq_128 *rng); extern inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state); -extern inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128* rng, - pcg128_t initstate, pcg128_t initseq); +extern inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng, + pcg128_t initstate, + pcg128_t initseq); extern inline uint64_t -pcg_setseq_128_xsl_rr_64_random_r(pcg_state_setseq_128* rng); +pcg_setseq_128_xsl_rr_64_random_r(pcg_state_setseq_128 *rng); extern inline uint64_t -pcg_setseq_128_xsl_rr_64_boundedrand_r(pcg_state_setseq_128* rng, +pcg_setseq_128_xsl_rr_64_boundedrand_r(pcg_state_setseq_128 *rng, uint64_t bound); -extern inline void pcg_setseq_128_advance_r(pcg_state_setseq_128* rng, pcg128_t delta); +extern inline void pcg_setseq_128_advance_r(pcg_state_setseq_128 *rng, + pcg128_t delta); /* Multi-step advance functions (jump-ahead, jump-back) -* -* The method used here is based on Brown, "Random Number Generation -* with Arbitrary Stride,", Transactions of the American Nuclear -* Society (Nov. 1994). The algorithm is very similar to fast -* exponentiation. -* -* Even though delta is an unsigned integer, we can pass a -* signed integer to go backwards, it just goes "the long way round". -*/ + * + * The method used here is based on Brown, "Random Number Generation + * with Arbitrary Stride,", Transactions of the American Nuclear + * Society (Nov. 1994). The algorithm is very similar to fast + * exponentiation. + * + * Even though delta is an unsigned integer, we can pass a + * signed integer to go backwards, it just goes "the long way round". + */ #ifndef PCG_EMULATED_128BIT_MATH pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult, - pcg128_t cur_plus) -{ - pcg128_t acc_mult = 1u; - pcg128_t acc_plus = 0u; - while (delta > 0) { - if (delta & 1) { - acc_mult *= cur_mult; - acc_plus = acc_plus * cur_mult + cur_plus; - } - cur_plus = (cur_mult + 1) * cur_plus; - cur_mult *= cur_mult; - delta /= 2; + pcg128_t cur_plus) { + pcg128_t acc_mult = 1u; + pcg128_t acc_plus = 0u; + while (delta > 0) { + if (delta & 1) { + acc_mult *= cur_mult; + acc_plus = acc_plus * cur_mult + cur_plus; } - return acc_mult * state + acc_plus; + cur_plus = (cur_mult + 1) * cur_plus; + cur_mult *= cur_mult; + delta /= 2; + } + return acc_mult * state + acc_plus; } #else pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult, - pcg128_t cur_plus) -{ - pcg128_t acc_mult = PCG_128BIT_CONSTANT(0u, 1u); - pcg128_t acc_plus = PCG_128BIT_CONSTANT(0u, 0u); - while ((delta.high > 0) || (delta.low > 0)) { - if (delta.low & 1) { - acc_mult = _pcg128_mult(acc_mult, cur_mult); - acc_plus = _pcg128_add(_pcg128_mult(acc_plus, cur_mult), cur_plus); - } - cur_plus = _pcg128_mult(_pcg128_add(cur_mult, PCG_128BIT_CONSTANT(0u, 1u)), cur_plus); - cur_mult = _pcg128_mult(cur_mult, cur_mult); - delta.low >>= 1; - delta.low += delta.high & 1; - delta.high >>= 1; + pcg128_t cur_plus) { + pcg128_t acc_mult = PCG_128BIT_CONSTANT(0u, 1u); + pcg128_t acc_plus = PCG_128BIT_CONSTANT(0u, 0u); + while ((delta.high > 0) || (delta.low > 0)) { + if (delta.low & 1) { + acc_mult = _pcg128_mult(acc_mult, cur_mult); + acc_plus = _pcg128_add(_pcg128_mult(acc_plus, cur_mult), cur_plus); } - return _pcg128_add(_pcg128_mult(acc_mult, state), acc_plus); + cur_plus = _pcg128_mult(_pcg128_add(cur_mult, PCG_128BIT_CONSTANT(0u, 1u)), + cur_plus); + cur_mult = _pcg128_mult(cur_mult, cur_mult); + delta.low >>= 1; + delta.low += delta.high & 1; + delta.high >>= 1; + } + return _pcg128_add(_pcg128_mult(acc_mult, state), acc_plus); } #endif @@ -91,15 +92,13 @@ pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult, extern inline uint64_t pcg64_next64(pcg64_state *state); extern inline uint32_t pcg64_next32(pcg64_state *state); +extern void pcg64_advance(pcg64_state *state, uint64_t *step) { + pcg128_t delta; #if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH) -extern void pcg64_advance(pcg64_state *state, pcg128_t step) { - pcg64_advance_r(state->pcg_state, step); -} + delta = (((pcg128_t)step[0]) << 64) | step[1]; #else -extern void pcg64_advance(pcg64_state *state, uint64_t *step) { - pcg128_t delta; - delta.high = step[0]; - delta.low = step[1]; - pcg64_advance_r(state->pcg_state, delta); + delta.high = step[0]; + delta.low = step[1]; +#endif + pcg64_advance_r(state->pcg_state, delta); } -#endif \ No newline at end of file diff --git a/_randomgen/core_prng/src/pcg64/pcg64.h b/_randomgen/core_prng/src/pcg64/pcg64.h index acb6417b86ed..244eeb8cff49 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.h +++ b/_randomgen/core_prng/src/pcg64/pcg64.h @@ -34,8 +34,7 @@ #include #endif - -#if __GNUC_GNU_INLINE__ && !defined(__cplusplus) +#if __GNUC_GNU_INLINE__ && !defined(__cplusplus) #error Nonstandard GNU inlining semantics. Compile with -std=c99 or better. #endif @@ -44,168 +43,158 @@ extern "C" { #endif #if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH) - typedef __uint128_t pcg128_t; -#define PCG_128BIT_CONSTANT(high,low) \ - (((pcg128_t)(high) << 64) + low) +typedef __uint128_t pcg128_t; +#define PCG_128BIT_CONSTANT(high, low) (((pcg128_t)(high) << 64) + low) #else - typedef struct { - uint64_t high; - uint64_t low; - } pcg128_t; - - inline pcg128_t PCG_128BIT_CONSTANT(uint64_t high, uint64_t low) { - pcg128_t result; - result.high = high; - result.low = low; - return result; - } +typedef struct { + uint64_t high; + uint64_t low; +} pcg128_t; + +inline pcg128_t PCG_128BIT_CONSTANT(uint64_t high, uint64_t low) { + pcg128_t result; + result.high = high; + result.low = low; + return result; +} #define PCG_EMULATED_128BIT_MATH 1 #endif - typedef struct { - pcg128_t state; - } pcg_state_128; +typedef struct { + pcg128_t state; +} pcg_state_128; - typedef struct { - pcg128_t state; - pcg128_t inc; - } pcg_state_setseq_128; +typedef struct { + pcg128_t state; + pcg128_t inc; +} pcg_state_setseq_128; -#define PCG_DEFAULT_MULTIPLIER_128 \ - PCG_128BIT_CONSTANT(2549297995355413924ULL,4865540595714422341ULL) -#define PCG_DEFAULT_INCREMENT_128 \ - PCG_128BIT_CONSTANT(6364136223846793005ULL,1442695040888963407ULL) +#define PCG_DEFAULT_MULTIPLIER_128 \ + PCG_128BIT_CONSTANT(2549297995355413924ULL, 4865540595714422341ULL) +#define PCG_DEFAULT_INCREMENT_128 \ + PCG_128BIT_CONSTANT(6364136223846793005ULL, 1442695040888963407ULL) #define PCG_STATE_SETSEQ_128_INITIALIZER \ - { PCG_128BIT_CONSTANT(0x979c9a98d8462005ULL, 0x7d3e9cb6cfe0549bULL), \ - PCG_128BIT_CONSTANT(0x0000000000000001ULL, 0xda3e39cb94b95bdbULL) } + { \ + PCG_128BIT_CONSTANT(0x979c9a98d8462005ULL, 0x7d3e9cb6cfe0549bULL), \ + PCG_128BIT_CONSTANT(0x0000000000000001ULL, 0xda3e39cb94b95bdbULL) \ + } - inline uint64_t pcg_rotr_64(uint64_t value, unsigned int rot) - { - return (value >> rot) | (value << ((- rot) & 63)); - } +inline uint64_t pcg_rotr_64(uint64_t value, unsigned int rot) { + return (value >> rot) | (value << ((-rot) & 63)); +} #ifdef PCG_EMULATED_128BIT_MATH - inline pcg128_t _pcg128_add(pcg128_t a, pcg128_t b) { - pcg128_t result; - - result.low = a.low + b.low; - result.high = a.high + b.high + (result.low < b.low); - return result; - } - - inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t* z1, uint64_t* z0) { - uint64_t x0, x1, y0, y1; - uint64_t w0, w1, w2, t; - /* Lower 64 bits are straightforward clock-arithmetic. */ - *z0 = x * y; - - x0 = x & 0xFFFFFFFFULL; - x1 = x >> 32; - y0 = y & 0xFFFFFFFFULL; - y1 = y >> 32; - w0 = x0 * y0; - t = x1 * y0 + (w0 >> 32); - w1 = t & 0xFFFFFFFFULL; - w2 = t >> 32; - w1 += x0 * y1; - *z1 = x1 * y1 + w2 + (w1 >> 32); - } - - inline pcg128_t _pcg128_mult(pcg128_t a, pcg128_t b) { - uint64_t h1; - pcg128_t result; - - h1 = a.high * b.low + a.low * b.high; - _pcg_mult64(a.low, b.low, &(result.high), &(result.low)); - result.high += h1; - return result; - } - - inline void pcg_setseq_128_step_r(pcg_state_setseq_128* rng) - { - rng->state = _pcg128_add(_pcg128_mult(rng->state, PCG_DEFAULT_MULTIPLIER_128), rng->inc); - } - - inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) - { - return pcg_rotr_64(state.high ^ state.low, - state.high >> 58u); - } - - inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128* rng, - pcg128_t initstate, pcg128_t initseq) - { - rng->state = PCG_128BIT_CONSTANT(0ULL, 0ULL); - rng->inc.high = initseq.high << 1u; - rng->inc.high |= initseq.low & 0x800000000000ULL; - rng->inc.low = (initseq.low << 1u) | 1u; - pcg_setseq_128_step_r(rng); - rng->state = _pcg128_add(rng->state, initstate); - pcg_setseq_128_step_r(rng); - } +inline pcg128_t _pcg128_add(pcg128_t a, pcg128_t b) { + pcg128_t result; + + result.low = a.low + b.low; + result.high = a.high + b.high + (result.low < b.low); + return result; +} + +inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t *z1, uint64_t *z0) { + uint64_t x0, x1, y0, y1; + uint64_t w0, w1, w2, t; + /* Lower 64 bits are straightforward clock-arithmetic. */ + *z0 = x * y; + + x0 = x & 0xFFFFFFFFULL; + x1 = x >> 32; + y0 = y & 0xFFFFFFFFULL; + y1 = y >> 32; + w0 = x0 * y0; + t = x1 * y0 + (w0 >> 32); + w1 = t & 0xFFFFFFFFULL; + w2 = t >> 32; + w1 += x0 * y1; + *z1 = x1 * y1 + w2 + (w1 >> 32); +} + +inline pcg128_t _pcg128_mult(pcg128_t a, pcg128_t b) { + uint64_t h1; + pcg128_t result; + + h1 = a.high * b.low + a.low * b.high; + _pcg_mult64(a.low, b.low, &(result.high), &(result.low)); + result.high += h1; + return result; +} + +inline void pcg_setseq_128_step_r(pcg_state_setseq_128 *rng) { + rng->state = _pcg128_add(_pcg128_mult(rng->state, PCG_DEFAULT_MULTIPLIER_128), + rng->inc); +} + +inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) { + return pcg_rotr_64(state.high ^ state.low, state.high >> 58u); +} + +inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng, + pcg128_t initstate, pcg128_t initseq) { + rng->state = PCG_128BIT_CONSTANT(0ULL, 0ULL); + rng->inc.high = initseq.high << 1u; + rng->inc.high |= initseq.low & 0x800000000000ULL; + rng->inc.low = (initseq.low << 1u) | 1u; + pcg_setseq_128_step_r(rng); + rng->state = _pcg128_add(rng->state, initstate); + pcg_setseq_128_step_r(rng); +} #else /* PCG_EMULATED_128BIT_MATH */ - inline void pcg_setseq_128_step_r(pcg_state_setseq_128* rng) - { - rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + rng->inc; - } - - inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) - { - return pcg_rotr_64(((uint64_t)(state >> 64u)) ^ (uint64_t)state, - state >> 122u); - } - - inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128* rng, - pcg128_t initstate, pcg128_t initseq) - { - rng->state = 0U; - rng->inc = (initseq << 1u) | 1u; - pcg_setseq_128_step_r(rng); - rng->state += initstate; - pcg_setseq_128_step_r(rng); - } +inline void pcg_setseq_128_step_r(pcg_state_setseq_128 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + rng->inc; +} + +inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) { + return pcg_rotr_64(((uint64_t)(state >> 64u)) ^ (uint64_t)state, + state >> 122u); +} + +inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng, + pcg128_t initstate, pcg128_t initseq) { + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_128_step_r(rng); + rng->state += initstate; + pcg_setseq_128_step_r(rng); +} #endif /* PCG_EMULATED_128BIT_MATH */ +inline uint64_t pcg_setseq_128_xsl_rr_64_random_r(pcg_state_setseq_128 *rng) { + pcg_setseq_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} + +inline uint64_t +pcg_setseq_128_xsl_rr_64_boundedrand_r(pcg_state_setseq_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +extern pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, + pcg128_t cur_mult, pcg128_t cur_plus); + +inline void pcg_setseq_128_advance_r(pcg_state_setseq_128 *rng, + pcg128_t delta) { + rng->state = pcg_advance_lcg_128(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_128, rng->inc); +} - inline uint64_t - pcg_setseq_128_xsl_rr_64_random_r(pcg_state_setseq_128* rng) - { - pcg_setseq_128_step_r(rng); - return pcg_output_xsl_rr_128_64(rng->state); - } - - inline uint64_t - pcg_setseq_128_xsl_rr_64_boundedrand_r(pcg_state_setseq_128* rng, - uint64_t bound) - { - uint64_t threshold = -bound % bound; - for (;;) { - uint64_t r = pcg_setseq_128_xsl_rr_64_random_r(rng); - if (r >= threshold) - return r % bound; - } - } - - extern pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult, - pcg128_t cur_plus); - - inline void pcg_setseq_128_advance_r(pcg_state_setseq_128* rng, pcg128_t delta) - { - rng->state = pcg_advance_lcg_128(rng->state, delta, - PCG_DEFAULT_MULTIPLIER_128, rng->inc); - } - - typedef pcg_state_setseq_128 pcg64_random_t; -#define pcg64_random_r pcg_setseq_128_xsl_rr_64_random_r -#define pcg64_boundedrand_r pcg_setseq_128_xsl_rr_64_boundedrand_r -#define pcg64_srandom_r pcg_setseq_128_srandom_r -#define pcg64_advance_r pcg_setseq_128_advance_r -#define PCG64_INITIALIZER PCG_STATE_SETSEQ_128_INITIALIZER +typedef pcg_state_setseq_128 pcg64_random_t; +#define pcg64_random_r pcg_setseq_128_xsl_rr_64_random_r +#define pcg64_boundedrand_r pcg_setseq_128_xsl_rr_64_boundedrand_r +#define pcg64_srandom_r pcg_setseq_128_srandom_r +#define pcg64_advance_r pcg_setseq_128_advance_r +#define PCG64_INITIALIZER PCG_STATE_SETSEQ_128_INITIALIZER #if __cplusplus } @@ -213,14 +202,12 @@ extern "C" { #endif /* PCG64_H_INCLUDED */ - typedef struct s_pcg64_state { pcg64_random_t *pcg_state; int has_uint32; uint32_t uinteger; } pcg64_state; - static inline uint64_t pcg64_next64(pcg64_state *state) { return pcg64_random_r(state->pcg_state); } @@ -236,8 +223,4 @@ static inline uint32_t pcg64_next32(pcg64_state *state) { return (uint32_t)(next >> 32); } -#if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH) -void pcg64_advance(pcg64_state *state, pcg128_t step); -#else void pcg64_advance(pcg64_state *state, uint64_t *step); -#endif \ No newline at end of file diff --git a/_randomgen/core_prng/src/philox/philox.h b/_randomgen/core_prng/src/philox/philox.h index 1c6baf3075e5..3121d5cbdc2e 100644 --- a/_randomgen/core_prng/src/philox/philox.h +++ b/_randomgen/core_prng/src/philox/philox.h @@ -1,5 +1,11 @@ #include +#ifdef _WIN32 +#define INLINE __inline _forceinline +#else +#define INLINE inline +#endif + struct r123array2x64 { uint64_t v[2]; }; @@ -38,7 +44,7 @@ static inline uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { // static __inline _forceinline struct r123array4x64 _philox4x64round(struct // r123array4x64 ctr, struct r123array2x64 key); -static __inline _forceinline struct r123array4x64 +static INLINE struct r123array4x64 _philox4x64round(struct r123array4x64 ctr, struct r123array2x64 key) { uint64_t hi0; uint64_t hi1; @@ -49,13 +55,13 @@ _philox4x64round(struct r123array4x64 ctr, struct r123array2x64 key) { return out; } -static __inline philox4x64_key_t philox4x64keyinit(philox4x64_ukey_t uk) { +static INLINE philox4x64_key_t philox4x64keyinit(philox4x64_ukey_t uk) { return uk; } // static __inline _forceinline philox4x64_ctr_t philox4x64_R(unsigned int R, // philox4x64_ctr_t ctr, philox4x64_key_t key); -static __inline _forceinline philox4x64_ctr_t +static INLINE philox4x64_ctr_t philox4x64_R(unsigned int R, philox4x64_ctr_t ctr, philox4x64_key_t key) { if (R > 0) { ctr = _philox4x64round(ctr, key); diff --git a/_randomgen/setup.py b/_randomgen/setup.py index fcda70ad0d0c..cb51f83792bc 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -13,9 +13,12 @@ MOD_DIR = './core_prng' + +PCG_EMULATED_MATH = False EXTRA_LINK_ARGS = [] if os.name == 'nt': EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] + PCG_EMULATED_MATH = True extensions = [Extension('core_prng.entropy', sources=[join(MOD_DIR, 'entropy.pyx'), @@ -38,7 +41,8 @@ join(MOD_DIR, 'src', 'pcg64', 'pcg64.c')], include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'pcg64')]), + join(MOD_DIR, 'src', 'pcg64')], + cython_compile_time_env={'PCG_EMULATED_MATH':PCG_EMULATED_MATH}), Extension("core_prng.threefry", ["core_prng/threefry.pyx", join(MOD_DIR, 'src', 'threefry', 'threefry.c')], From 6d29ef128ab7beaaa56f520320a21798f035c1cc Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Mar 2018 13:17:24 +0000 Subject: [PATCH 026/279] BUG: Fix comditional compilation for PCG Remove hard coded flag for PCG --- _randomgen/core_prng/pcg64.pyx | 10 +++--- _randomgen/demo.py | 17 ++++++++++ _randomgen/setup.py | 61 +++++++++++++++++++++++++--------- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index 49b9b9d02fe9..f728e2bbecc0 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -11,9 +11,7 @@ cimport entropy np.import_array() -DEF PCG_EMULATED_MATH=0 - -IF PCG_EMULATED_MATH: +IF PCG_EMULATED_MATH==1: cdef extern from "src/pcg64/pcg64.h": ctypedef struct pcg128_t: @@ -179,7 +177,7 @@ cdef class PCG64: state = state.view(np.uint64) else: state = entropy.seed_by_array(seed, 2) - IF PCG_EMULATED_MATH: + IF PCG_EMULATED_MATH==1: self.rng_state.pcg_state.state.high = int(state[0]) self.rng_state.pcg_state.state.low = int(state[1]) self.rng_state.pcg_state.inc.high = inc // 2**64 @@ -192,7 +190,7 @@ cdef class PCG64: @property def state(self): """Get or set the PRNG state""" - IF PCG_EMULATED_MATH: + IF PCG_EMULATED_MATH==1: state = 2 **64 * self.rng_state.pcg_state.state.high state += self.rng_state.pcg_state.state.low inc = 2 **64 * self.rng_state.pcg_state.inc.high @@ -214,7 +212,7 @@ cdef class PCG64: if prng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) - IF PCG_EMULATED_MATH: + IF PCG_EMULATED_MATH==1: self.rng_state.pcg_state.state.high = value['state']['state'] // 2 ** 64 self.rng_state.pcg_state.state.low = value['state']['state'] % 2 ** 64 self.rng_state.pcg_state.inc.high = value['state']['inc'] // 2 ** 64 diff --git a/_randomgen/demo.py b/_randomgen/demo.py index 0acf66da49b2..b1956831c156 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -1,3 +1,5 @@ +import timeit + from core_prng import Xoroshiro128, ThreeFry, MT19937, \ Xorshift1024, PCG64, Philox from core_prng.generator import RandomGenerator @@ -59,3 +61,18 @@ state = rg.state print(state) rg.state = state + +PRNGS = [MT19937, PCG64, Philox, ThreeFry, Xoroshiro128, Xorshift1024] + +setup = """ +from core_prng import {module} +m = {module}() +m._benchmark(701) +""" +for p in PRNGS: + module = p.__name__ + print(module) + t = timeit.timeit("m._benchmark(10000000)", setup.format(module=module), + number=10) + print('{:0.2f} ms'.format(1000 * t / 10)) + print('{:,} randoms per second'.format(int(10000000 / (t/10)))) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index cb51f83792bc..663c0056c7e0 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -1,11 +1,10 @@ import os from os.path import join -import versioneer - +import Cython.Compiler.Options import numpy as np +import versioneer from Cython.Build import cythonize -import Cython.Compiler.Options from setuptools import setup, find_packages, Distribution from setuptools.extension import Extension @@ -13,60 +12,91 @@ MOD_DIR = './core_prng' - +DEBUG = False PCG_EMULATED_MATH = False + +EXTRA_COMPILE_ARGS = [] EXTRA_LINK_ARGS = [] if os.name == 'nt': EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] PCG_EMULATED_MATH = True + if DEBUG: + EXTRA_LINK_ARGS += ['-debug'] + EXTRA_COMPILE_ARGS = ["-Zi", "/Od"] extensions = [Extension('core_prng.entropy', sources=[join(MOD_DIR, 'entropy.pyx'), join(MOD_DIR, 'src', 'entropy', 'entropy.c')], include_dirs=[np.get_include(), join(MOD_DIR, 'src', 'entropy')], - extra_link_args=EXTRA_LINK_ARGS), + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("core_prng.mt19937", ["core_prng/mt19937.pyx", join(MOD_DIR, 'src', 'mt19937', 'mt19937.c')], include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'mt19937')]), + join(MOD_DIR, 'src', 'mt19937')], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("core_prng.philox", ["core_prng/philox.pyx", join(MOD_DIR, 'src', 'philox', 'philox.c')], include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'philox')]), + join(MOD_DIR, 'src', 'philox')], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("core_prng.pcg64", ["core_prng/pcg64.pyx", join(MOD_DIR, 'src', 'pcg64', 'pcg64.c')], include_dirs=[np.get_include(), join(MOD_DIR, 'src', 'pcg64')], - cython_compile_time_env={'PCG_EMULATED_MATH':PCG_EMULATED_MATH}), + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("core_prng.threefry", ["core_prng/threefry.pyx", join(MOD_DIR, 'src', 'threefry', 'threefry.c')], include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'threefry')]), + join(MOD_DIR, 'src', 'threefry')], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("core_prng.xoroshiro128", ["core_prng/xoroshiro128.pyx", join(MOD_DIR, 'src', 'xoroshiro128', 'xoroshiro128.c')], include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'xoroshiro128')]), + join(MOD_DIR, 'src', 'xoroshiro128')], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("core_prng.xorshift1024", ["core_prng/xorshift1024.pyx", join(MOD_DIR, 'src', 'xorshift1024', 'xorshift1024.c')], include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'xorshift1024')]), + join(MOD_DIR, 'src', 'xorshift1024')], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("core_prng.generator", ["core_prng/generator.pyx", - join(MOD_DIR, 'src', 'distributions', 'distributions.c')], - include_dirs=[np.get_include()]), + join(MOD_DIR, 'src', 'distributions', + 'distributions.c')], + include_dirs=[np.get_include()], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("core_prng.common", ["core_prng/common.pyx"], - include_dirs=[np.get_include()]), + include_dirs=[np.get_include()], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), ] @@ -78,7 +108,8 @@ def is_pure(self): setup( version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass(), - ext_modules=cythonize(extensions), + ext_modules=cythonize(extensions, compile_time_env={ + "PCG_EMULATED_MATH": PCG_EMULATED_MATH}), name='core_prng', packages=find_packages(), package_dir={'core_prng': './core_prng'}, From 3cd0cefc2ddcd5ded52eb80044feedfec7e5ec19 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Mar 2018 15:34:31 +0000 Subject: [PATCH 027/279] ENH: Add dSFMT Add support for dSFMT --- _randomgen/core_prng/__init__.py | 5 +- _randomgen/core_prng/dsfmt.pyx | 233 ++++++ .../core_prng/src/dsfmt/128-bit-jump.poly.txt | 2 + .../core_prng/src/dsfmt/96-bit-jump.poly.txt | 2 + _randomgen/core_prng/src/dsfmt/LICENSE.txt | 32 + _randomgen/core_prng/src/dsfmt/calc-jump.cpp | 81 +++ .../core_prng/src/dsfmt/dSFMT-calc-jump.hpp | 106 +++ _randomgen/core_prng/src/dsfmt/dSFMT-common.h | 115 +++ _randomgen/core_prng/src/dsfmt/dSFMT-params.h | 87 +++ .../core_prng/src/dsfmt/dSFMT-params19937.h | 40 ++ .../core_prng/src/dsfmt/dSFMT-test-gen.c | 53 ++ _randomgen/core_prng/src/dsfmt/dsfmt-jump.c | 184 +++++ _randomgen/core_prng/src/dsfmt/dsfmt-jump.h | 29 + _randomgen/core_prng/src/dsfmt/dsfmt.c | 639 +++++++++++++++++ _randomgen/core_prng/src/dsfmt/dsfmt.h | 678 ++++++++++++++++++ _randomgen/demo.py | 10 +- _randomgen/setup.py | 24 + 17 files changed, 2316 insertions(+), 4 deletions(-) create mode 100644 _randomgen/core_prng/dsfmt.pyx create mode 100644 _randomgen/core_prng/src/dsfmt/128-bit-jump.poly.txt create mode 100644 _randomgen/core_prng/src/dsfmt/96-bit-jump.poly.txt create mode 100644 _randomgen/core_prng/src/dsfmt/LICENSE.txt create mode 100644 _randomgen/core_prng/src/dsfmt/calc-jump.cpp create mode 100644 _randomgen/core_prng/src/dsfmt/dSFMT-calc-jump.hpp create mode 100644 _randomgen/core_prng/src/dsfmt/dSFMT-common.h create mode 100644 _randomgen/core_prng/src/dsfmt/dSFMT-params.h create mode 100644 _randomgen/core_prng/src/dsfmt/dSFMT-params19937.h create mode 100644 _randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c create mode 100644 _randomgen/core_prng/src/dsfmt/dsfmt-jump.c create mode 100644 _randomgen/core_prng/src/dsfmt/dsfmt-jump.h create mode 100644 _randomgen/core_prng/src/dsfmt/dsfmt.c create mode 100644 _randomgen/core_prng/src/dsfmt/dsfmt.h diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index 7f554c4d3f97..2d8d0ae6f2e4 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -1,12 +1,13 @@ +from .dsfmt import DSFMT from .generator import RandomGenerator from .mt19937 import MT19937 from .pcg64 import PCG64 +from .philox import Philox from .threefry import ThreeFry from .xoroshiro128 import Xoroshiro128 from .xorshift1024 import Xorshift1024 -from .philox import Philox -__all__ = ['RandomGenerator', 'PCG64', 'Xoroshiro128', +__all__ = ['RandomGenerator', 'DSFMT', 'PCG64', 'Xoroshiro128', 'ThreeFry', 'MT19937', 'Xorshift1024'] from ._version import get_versions diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx new file mode 100644 index 000000000000..3930c3d7f592 --- /dev/null +++ b/_randomgen/core_prng/dsfmt.pyx @@ -0,0 +1,233 @@ +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + +import numpy as np +cimport numpy as np + +from common cimport * +from core_prng.entropy import random_entropy +import core_prng.pickle +cimport entropy + +np.import_array() + +DEF DSFMT_MEXP = 19937 +DEF DSFMT_N = 191 # ((DSFMT_MEXP - 128) / 104 + 1) +DEF DSFMT_N_PLUS_1 = 192 # DSFMT_N + 1 +DEF DSFMT_N64 = DSFMT_N * 2 + +cdef extern from "src/dsfmt/dSFMT.h": + + union W128_T: + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; + + ctypedef W128_T w128_t; + + struct DSFMT_T: + w128_t status[DSFMT_N_PLUS_1]; + int idx; + + ctypedef DSFMT_T dsfmt_t; + + struct s_dsfmt_state: + dsfmt_t *state + int has_uint32 + uint32_t uinteger + + double *buffered_uniforms + int buffer_loc + + ctypedef s_dsfmt_state dsfmt_state + + double dsfmt_next_double(dsfmt_state *state) nogil + uint64_t dsfmt_next64(dsfmt_state *state) nogil + uint64_t dsfmt_next32(dsfmt_state *state) nogil + + void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) + void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) + # void dsfmt_jump(dsfmt_state *state) + +cdef uint64_t dsfmt_uint64(void* st):# nogil: + return dsfmt_next64(st) + +cdef uint32_t dsfmt_uint32(void *st) nogil: + return dsfmt_next32( st) + +cdef double dsfmt_double(void* st) nogil: + return dsfmt_next_double(st) + +cdef class DSFMT: + """ + Prototype Core PRNG using dsfmt + + Parameters + ---------- + seed : int, array of int + Integer or array of integers between 0 and 2**64 - 1 + + Notes + ----- + Exposes no user-facing API except `state`. Designed for use in a + `RandomGenerator` object. + """ + cdef dsfmt_state *rng_state + cdef prng_t *_prng + cdef public object _prng_capsule + + def __init__(self, seed=None): + self.rng_state = malloc(sizeof(dsfmt_state)) + self.rng_state.state = malloc(sizeof(dsfmt_t)) + self.rng_state.buffered_uniforms = malloc(DSFMT_N64 * sizeof(double)) + self.rng_state.buffer_loc = DSFMT_N64 + self._prng = malloc(sizeof(prng_t)) + self._prng.binomial = malloc(sizeof(binomial_t)) + self.seed(seed) + self._prng.state = self.rng_state + self._prng.next_uint64 = &dsfmt_uint64 + self._prng.next_uint32 = &dsfmt_uint32 + self._prng.next_double = &dsfmt_double + cdef const char *name = "CorePRNG" + self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__prng_ctor, + (self.state['prng'],), + self.state) + + def __dealloc__(self): + free(self.rng_state.state) + free(self.rng_state.buffered_uniforms) + free(self.rng_state) + free(self._prng.binomial) + free(self._prng) + + def _reset_state_variables(self): + pass + + def __random_integer(self, bits=64): + """ + 64-bit Random Integers from the PRNG + + Parameters + ---------- + bits : {32, 64} + Number of random bits to return + + Returns + ------- + rv : int + Next random value + + Notes + ----- + Testing only + """ + if bits == 64: + return dsfmt_next64(self.rng_state) + elif bits == 32: + return dsfmt_next32(self.rng_state) + else: + raise ValueError('bits must be 32 or 64') + + def _benchmark(self, Py_ssize_t cnt): + cdef Py_ssize_t i + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + + def seed(self, seed=None): + """ + seed(seed=None, stream=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + + """ + cdef np.ndarray init_key + ub = 2 ** 32 + if seed is None: + try: + state = random_entropy(1) + except RuntimeError: + state = random_entropy(1, 'fallback') + seed = state[0] + if np.isscalar(seed): + # TODO: This isn't correct, but works now + seed = int(seed) + if seed < 0 or seed > ub: + raise ValueError('seed must be an unsigned 32-bit integer') + dsfmt_init_gen_rand(self.rng_state.state, seed) + else: + # TODO: This also need to be impeoved to be more careful + init_key = np.asarray(seed, dtype=np.uint32).ravel() + dsfmt_init_by_array(self.rng_state.state, + init_key.data, + init_key.shape[0]) + + self._reset_state_variables() + +# def jump(self): +# dsfmt_jump(self.rng_state) +# return self + + @property + def state(self): + """Get or set the PRNG state""" + cdef Py_ssize_t i, j, loc = 0 + cdef uint64_t[::1] state + cdef double[::1] buffered_uniforms + + state = np.empty(2 *DSFMT_N_PLUS_1, dtype=np.uint64) + for i in range(DSFMT_N_PLUS_1): + for j in range(2): + state[loc] = self.rng_state.state.status[i].u[j] + loc += 1 + buffered_uniforms = np.empty(DSFMT_N64,dtype=np.double) + for i in range(DSFMT_N64): + buffered_uniforms[i] = self.rng_state.buffered_uniforms[i] + return {'prng': self.__class__.__name__, + 'state': {'state':np.asarray(state), + 'idx':self.rng_state.state.idx}, + 'buffer_loc': self.rng_state.buffer_loc, + 'buffered_uniforms':np.asarray(buffered_uniforms)} + + @state.setter + def state(self, value): + cdef Py_ssize_t i, j, loc = 0 + if not isinstance(value, dict): + raise TypeError('state must be a dict') + prng = value.get('prng', '') + if prng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + state = value['state']['state'] + for i in range(DSFMT_N_PLUS_1): + for j in range(2): + self.rng_state.state.status[i].u[j] = state[loc] + loc += 1 + self.rng_state.state.idx = value['state']['idx'] + buffered_uniforms = value['buffered_uniforms'] + for i in range(DSFMT_N64): + self.rng_state.buffered_uniforms[i] = buffered_uniforms[i] + self.rng_state.buffer_loc = value['buffer_loc'] \ No newline at end of file diff --git a/_randomgen/core_prng/src/dsfmt/128-bit-jump.poly.txt b/_randomgen/core_prng/src/dsfmt/128-bit-jump.poly.txt new file mode 100644 index 000000000000..fea1318fb706 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/128-bit-jump.poly.txt @@ -0,0 +1,2 @@ +jump polynomial: +f4dfa6c62049d0776e0bf6f1e953f3aa38abb113df86be024eab3773ad5f2b82ead936022e656dff7e562691c59dd5f7d2566b78d9669002503c4ddb1888a49f32333f515e6c60c4ecd221078ec6f26f0a90f4875067ca1f399a99775037adf905566e2c7e6b42131420f8f04f112c92621c9b1502f2a8aefad6c667904af62f0d55e02d396902d3b89450103c5ce5fe0408d97cbb864861b49e4e42048ff3310b48faac55095a7f422eea4aade752f947f947c6be0a0c665bdea099246ab9eff658ea8ca468bf49d0227748367878de06d7bd86ea6708fcac6e252f5f00f04309b2aac3036b64afb39d990427c6c9f03477cc7e935c43c0e61bc161db8eb15516eee8cb377ecbc1849207990fb6778721b29bfe0d89bfda1b3772fa5b0b1f7ec3daf36052032285898c6f6396f55010c31f8201b7e2e51d94f920bfe57684c5415cc342cb39a0045d9793d13cf8646096daeb8bb9bfc20a90de8f2426da8733267a9b9674f32154e8f84a9932223a2ca3c787d0b66df6675febbdfcba2f9cef09c621c57e11098b3289c77397aaae8b104642ffe0c4b75598efbc53745984d68b4d6656cae299ae2be55217a9a02b009ca7be32f47fbe434bce4914a34d0c9b0085bede9b8a99319c34660d66f0124b5a7714c4bf3cbfec3ee43ed817087168bad80133bebaeeb68cf7929a24d1bb3de831a8340d220906ab04159cf94b21d5ee813bd7c80f10f01b43052af530917513b169254c25d6fcfe6cb420d6ce92f54886ef6eaf9a5ba35e893ff593834d05ddf28899e42d729c7df3d21ef036020789739366f0c11ec52ff92a0bfd8ba69508e27b20fabb8217bd36b90e5aa918159ac87913bc7b46c04e366c23c92807fbe9c6a407e6a4db0b4fc23c3b6c706b5ca058fe8c190f849f18d16d6b48b5ed760eb202fd566291a799420b9654e08b8118bcbfead8e9dd2fdb9b053e9bdfb665285c78718f726d0b3d6c37e116428ec9ac9db2637259e4e8d6402bbada46c6bdb03985e19a82e9b4e57de1b025a3cb1f850beae7e8da9941655825bce0e89d536b6ee9064865b1a85c185e9fc9cb7f435de13d44773c00eed442a286e4ab807e3cab4dc3441d1b7d2af693812ae8b39652bb8c835fc895d13d6da93541afeadeee450475c29f3b2dfa8ef1c1e2547463b2cc2f0ff7a42ac4dd35e25c4fa030d2d2766fbe9f2d04c1304671747bace2f7dd55142bfa60f8cbc968bfc3d7a342152dc684a0fb5a32c0962a62b5220ac0f72add9d8b84d6cc76b97d03245e01fc8da3414a49bb4075d3488f29b56dc42ba69e3b58529448c943ecfd98b3784a39d0b8609a8fb945e757f4569f53bd2cf80f7f638acf5b67fe9c560a3b7b0cf7e0398f31aa8b03cf9c62b24296b6d8596b694469a02686c38daa16a1ef86e012d61a2f7de1693a5c00b3685175caec3c67146477eba54830f1d546cb18a553779aa46adb4f2010e33f3def847c7d89b51a8462b227605f6c920fd558a6daf64bc98682e508ae960c0c571870e603ba1fce0c13d53176f353fd319959e13db93eae1359f06e3dd4767c04f824cf34ec7bf8f60161ba1a615db82852eca9e3869afa711ab9a090660b0dc6cfbea310dda77e02310fbaeacd2636f975838c2dbcdbe9ac2cd85cee28f5e3f0c73abf62f9fa02cd79a7606b7ba855db68a07848b057c3aaf38f1a70086e14616f6f88305a1f9ce6b41378a620d4db3e0e7e1d421590dccaeff86212e232eeb5eb8a8d33a8c9b25ae88f3a7bd5032b4efa68f8af3186a02ffcbf5456f12beccace94c81c360cc4a0dcc642b59f991eec68c59af78139ca60b96d6a18e9535f8995e89bd2cf6a0aef3acffd33d1c0c1b79b66414a91d9f65b2b4ec65844b96f725d2b4b0c309f3eb9d714e9dd939bbdfd85ce8fb43679aeab13f6c29549949503c9466dbd337c4cdde46d6eacd15f21f4d8fdeaa627a47884c88a9c85f0b731d271a8ea7cb9e04a4a149c23c10f56b3a0476dc77a999d6e4f813e4b0f805e2a693e2ae4ae0ecc423c9ba5d17b42e691abf83784a582f2b1fd85d1e0a27ba38a500963568b2450363d2c5e3f7b8ba3e5b56e4e9f745a3a710bf2ae233c303068c532ce78ff031e6ab28b705dd94d7db4500909edb5626b8c9bd5ff4f0b4741388f0b91563ee516934c013e901572cba005ac5c535f4f107903be9af7b2793dfb61b5070facbe71eefe1b5600f975c8c38c3a2350d78beadfecb78e981164ae8bc866e732972d3ceef4aac68e15861f9b881d9b51b4edece150bc124b07645defb4202ef5d0e0962db98cae6ed459561c93c74c20bd64362e4f4fffc389a6cd80514604ff22eecc10c9cbc7981d19a8102b24146354c463107c9dc070e29e70df3578022acf72289ef071ab9f9402a544d0399f1b1e5f206b6d46d445f6d612a490e72918e00c853eda8493bef511149e80c9ab56e8b4b8cba3987249f77d060e61760e5792ac321c987c03c2606e9393a7970212992cdbd16448078d5039d4c2c3199714f53278f4f7b1d2e514cf95bdfc078b8bb0db659cb2c3f5cc02890ea84f05d414c88d2db9e9f8455659b9fa6254405317245fa070d6970cafb4dadb2522b490a5c8e02fe973a8cdbfbfbdbfb01535099ffba3d3896bc4d1189fc570c3e6fdc6469265b8da912772e75dd62ab71be507f700d56cac5e68fd6b57ec166168ab5258a69625c142a5b1b3519f94be1bde5e51d3bd8ea0c12d5af2fe4615b1b7bd4a96628a4fabc65925ff09718f63bbebaad98f89bd9543a27b3ff3b5d8bfa89f941a5eb8cc005ccd4a705190e1c9dc6a9f4264e5ee658520a4438e92de854bffc39f8dc7dfbb5de4f14ba63ea16a37d14a7b4610f95b6cffd55e4679b29cedbdf20e7bd16da822fad910c359ee3a68e48aae6e769b0e291d5d3aa3e2ca9d8d23abe8a1d5349f4991e9300852cc0befb20c2fc0d169306b260763344024f8092cbcc24c6807363e9fc548a30d5faab3a94b2af0782a2942be80c45d8b0587efd587394ef33c33022436e285806ddffdd32fe36345c3c38ed8d680abeb7a028b44ee6f94d060a14c7019bb6af1f1b5f0a562957d19826d8cc216f9b908c989ccd5415e3525dfe9422ffb5b50b7cc3083dc325544751e5683535d7439d3da2b0bb73bea551dd99e04e0e793804f4774eb6b1daf781d9caa5128274e599e847862fe309027813d3e4eda0bbeb7201856a5c5d8370e44dabff0bb229c723ba0a6bcf29c44536147de11b7835991018100105bd4329217f7386903fe8e7363cd7b3e893244e245e0a187467664c05b0be1fd429722b9b9a5e3198147fad72776e8a63aab9054fa9d259af0198d088d71d132e6068676a8e9ebb0f616b51ee34aac39c2c2221c71124017270d75ff4a048363c389e04e9b440ad2032a381ac2cfc54f409caa791e65ee4f5d6cd035008f219b88a803a7382ae447bf65a3df2176b25b3b7b67dabe34decd9a1384dc7a003916ca8fbcb29b3ad6fd8eac5bbbaa3bdfa6c6a3ad9427c4f3ed79fea26e14c8ce5fa3b4f82c5f7b6d2125916753a7b92ce9b46d45 diff --git a/_randomgen/core_prng/src/dsfmt/96-bit-jump.poly.txt b/_randomgen/core_prng/src/dsfmt/96-bit-jump.poly.txt new file mode 100644 index 000000000000..15c68d155af4 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/96-bit-jump.poly.txt @@ -0,0 +1,2 @@ +jump polynomial: +288da521f7244e5f62bf26692bdd1fcdfd38a850addb02d98bd358367cb78c71348f3e163522e0e30e4feb90aa210dd793c94d151fa89aa319911aa42b511ea568a503d595c6d9bcd37317a37ef5679700a5b67f29df72451770fc1eb8c97427cdd9825c23f32dcd5c4fb117a4f5982a3bee8f16595d021165cd9688db342e360e222c9855c8306fd7b5fc82e62e3b1765e7f3319da9da66c325b030bd6175876efc70636306cd2de31a299ca20e9eb1d5063bcbff0ba282aff4737a5b1585cd940ae9cd45fda222308341e0d5588e81b42c4e0574deeb2d80b84c00cb3f8a7ae6278462e1994b83a25b33aa0dc74d5d3d057dabfd6a8a82d7dfb6bb66a223bc46dca2b5fb1885e6ab80fddcd6578b32c21c4a9d761cb9798800c921d56ee356c491454e15956e68ef566c1706fcdfb6a6828ec1fb93db455525828e8741a371c14959658b99bbd358a162230ee451a8432df279e4ba0d3a493954359a5390b16475540578270b168054fefb1e20948d4d20c88005ed09e671b6a94b8ea929f72e7b2f85af4098a92d742b64964ea6b7773b2c20b22a0ff35bd9367c3160b549411230e15a987f361e04daac49d2fe4c7c9371d84bf270d8f33a62680b2ee014bf5be691aa0d82e66e885eaa832a241aff8a09c435ac2b0698bc3865c5125d498a4ffadd31d5f2c6aee6496fdc6c13055b53e7f65a683ef539b6e8ea6e21429a11ff74ccef09ee83eac1b5ddaf1b77fed786fd20e8cbb3e8877b7f80a24fef31a9f8d8108099c50abc886f7ab20c4396bf51af1b806003185eaf2061f55036e26f498b92aabadfb6b5bed2d116b32ae387a692058e6160a9508dc44c971454d9a357ba115278861be0aeaa0926d773c5d4563e37dffcfed8bbf44b79e384650b7eff30aae73154a2ef130cee1eaf32d944e5472ae217789c03276deb8290c73dd5cde0b6dce9b28cbb73776e3e52260768f37a38db3d1c26c3c065b641c7a825edc155d947118d8b6ff8c8818440088724261ca83fa866aa4159fbffac8c28c8a7ca5f1e2fde74b4908c8215cbde20190bdf0de1d5a05a2c116a66eeadcafd643098e74ec3e82b3658c0c4fd7c7797d567b8db3d6b67ca262d713dbf45cc80b89f279be0991f276a4501d2ea6222026caa7e6fbcf4d02fdf65d8f439f88cfb1121d1b0f4dd670d146b93e099a32869448d837e347229745e5c30f1521b0c477b2062c9c8f631dcd29664eec7f28bdcac2a1ca2deabbbc89b21824ba92a61eeb4c5dd62b20c346134d842bcfc189f0e2244bfb8596c38c88d5bd4447fcd30890a4acf71801a6bcf5d806073b9ca730db53e160a79516333748708dd5e5be37d75e90e64d14ddf5ccc9390ae67cbba39916ce9b3b6b1d19378e4bd36ef0c9e62570394051cc273122e0790e381b20e083beca6e88bc2fa8bde22c89689b4b710c775cd9065158b48bf855fc3a3e80693908046ea1da9c558f024ea5ea69d65f40317fc3c8bab7606bf7edf17fcaeb706756c4de38319a51fc24c80a2baccef40f4354f5147fb91c9b1b91011d146da7eeb426d25de17d7e39ee53735ef28b64d5e6e5444676f679a8e4e91314377c7606531b90dc1cd8cf2d929ed9137fdc0d6b6db62e764ef200a439d742b51425b818231ed799a53768119466cc42296ce36f52507411709cd9d622c1f899291db27104589a5e4509d9818cef983d6a13ce1247184c4551c38bd319aa068cd9c0b96f9e08b4a7bd7852c129d4126676cbcb30ae029b0e2cec3c58c110fecae7967fca0752874e2fcc077084dd4d87b4dee632b621f35cb9f22639ab4de86089c56cabb1aa8a4fedbc5d8673cca12b4479dca5dc6f3048bb654fd59c464b033960177a4d6c2ee38b124d193cd5da3cbc5aa5ebdf7197f5d3f3008f01effb599b6d238044f2ee204bf372685256813278ca7a7d145445f5d5eb5490d99ee89d587fe446e1600d7daf9553b7d709bd796c59757e2f7c26cb71990a51ffc49120f358ef4927729b7e8c2cf9ad35a8017667625a39e2d12c8b0dd5de3d3797d9167ac9302a122e0f066a2552a7278a632b043089a1f5a127ce0bc8e688c545f20bca467fd58d9f9b8234f2be7a28152ab4d39ba8d6c4471d574571aa1a4a3aca16f46ac74e664899cf24502334aec637a9c392ba1618340080bfaed493abaa2f684ffb2bc1da86d804305772e30893f67235d5ce8180ef60490e46f131465d249a39df1aaed30621169c0f7db0b6a6adcab975ec00ca68b2fc06f443cfb8933b326f106670e0e528f22ff96d06b2a6d917258d29a87cf637f37c3661b42462c11c73c1cd0a6774e4e10157b02c0cfd9148ad8a23775653db3dec41fd6d1d5eb54a3e5e144a489a18412f21eb96a72b6751482882d636a1cd0057ea48d1a985472b0c301c4a5b24b0152bdc50a47126a01a1d0665270cdbf2ed852e0f61515bad6e58973329d269bf057ffa52331dde4700b926f635cdf49234f4aaabbabca5386526568fc3a80b1d8a9e1566e21bf889546379289263d978e95de390c4bbdb5a813535b7186f661f5c283400adb3bcf9365d45abb6088b729a98789265f1e8e684e2b2c15b4ce53230abc5e5bf6895827c95842e0849fc7fe56b7c65f075baded0f2e172c8e1088219615b8697ff4a3c6f5f708e498e6c7312680f214a877061511d3b85087545fc26708d039e977a0157b95ceba40497cc2dd1b1b1394eb98f651d701dfbc3583c159da8bae76a25db213211d6191d83c5d7a3d4b2320b8a305b5d90e04d6e3de161fff5dae7e3d4f6c9e1cf55cb5ac1677d9cfd560db2209be2b9566a267aad9cf4b9e03c221ba5b0f02cabb50cef19180ba329691d114da670d7b85e36c0b6b7d81613bd31350dfe225050861e90043ac2334478f52584a1a8809f76d40af36da02549c54da164487f0b7f823cff797db1c90f2f1c431eca97fc8bcdfb44c30cd1643c893d5e33aa56cbc0a0c38f5c8f6bb37483d13b85b659ac51ce05311bba19c97772e81c2315a009e80f591c82445d493dc3b5fb12c52e8c50c6260200b0d77092bf19aabce491b2c511fca2a4ebd99b446e55f453314297723894f0b223868ef80f5964468afa3a5e6aa41f2128e6de893bba2cbde9bea91ba97bda18a01905ce8d2e85e6011cc0550f5ae9121361fdec1ec97a6e6892a68732a69147476d54babaa564b883baad7100eb1092a1aa28a29f67e6b53deab511e53eada87cfe1bb6e3c6a215fd8d729840a5b5ac452cfd8acb9be7818d2c806c3e0cedd0847ddf9a5906bf1a0fa4da44ccea829a1a5350d5db0241a221b97e5cd5ba15e58b402529317c854fbcda86a562d4ee44a34193513647af0a3bc9f90ababc1dbbfd9aba8d3dcc39463473ca6bc0e1dc736ba712eef42dee80e31e7d8abe23f98e91ab875d0553bc24be9cb1d9484812c0b038cb177ad52064328e17f8ca7c8737902d964017e3aaae66161270dac21de42a6f60d10d89c1556916a249a130752bb7c7783b93a59d9f5456745ecc512f497b5a31be2678b9587628cb45dae2f5f6bde7ea4500c1ba961e2 diff --git a/_randomgen/core_prng/src/dsfmt/LICENSE.txt b/_randomgen/core_prng/src/dsfmt/LICENSE.txt new file mode 100644 index 000000000000..4570c4603b21 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/LICENSE.txt @@ -0,0 +1,32 @@ +Copyright (c) 2007, 2008, 2009 Mutsuo Saito, Makoto Matsumoto +and Hiroshima University. +Copyright (c) 2011, 2002 Mutsuo Saito, Makoto Matsumoto, Hiroshima +University and The University of Tokyo. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the Hiroshima University nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/_randomgen/core_prng/src/dsfmt/calc-jump.cpp b/_randomgen/core_prng/src/dsfmt/calc-jump.cpp new file mode 100644 index 000000000000..495b2797c782 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/calc-jump.cpp @@ -0,0 +1,81 @@ +/** + * @file calc-jump.cpp + * + * @brief calc jump function. + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (The University of Tokyo) + * + * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, + * Hiroshima University and The University of Tokyo. + * All rights reserved. + * + * The 3-clause BSD License is applied to this software, see + * LICENSE.txt + * + * Compile: + * g++ calc-jump.cpp -o calc-jump -lntl + * + * Compute polynomial for 2^128 steps: + * ./calc-jump 340282366920938463463374607431768211456 poly.19937.txt + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dSFMT-calc-jump.hpp" + +using namespace NTL; +using namespace std; +using namespace dsfmt; + +static void read_file(GF2X& lcmpoly, long line_no, const string& file); + +int main(int argc, char * argv[]) { + if (argc <= 2) { + cout << argv[0] << " jump-step poly-file" << endl; + cout << " jump-step: a number between zero and 2^{DSFMT_MEXP}-1.\n" + << " large decimal number is allowed." << endl; + cout << " poly-file: one of poly.{MEXP}.txt " + << "file" << endl; + return -1; + } + string step_string = argv[1]; + string filename = argv[2]; + long no = 0; + GF2X lcmpoly; + read_file(lcmpoly, no, filename); + ZZ step; + stringstream ss(step_string); + ss >> step; + string jump_str; + calc_jump(jump_str, step, lcmpoly); + cout << "jump polynomial:" << endl; + cout << jump_str << endl; + return 0; +} + + +static void read_file(GF2X& lcmpoly, long line_no, const string& file) +{ + ifstream ifs(file.c_str()); + string line; + for (int i = 0; i < line_no; i++) { + ifs >> line; + ifs >> line; + } + if (ifs) { + ifs >> line; + line = ""; + ifs >> line; + } + stringtopoly(lcmpoly, line); +} diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-calc-jump.hpp b/_randomgen/core_prng/src/dsfmt/dSFMT-calc-jump.hpp new file mode 100644 index 000000000000..b960826be43c --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-calc-jump.hpp @@ -0,0 +1,106 @@ +#pragma once +#ifndef DSFMT_CALC_JUMP_HPP +#define DSFMT_CALC_JUMP_HPP +/** + * @file dSFMT-calc-jump.hpp + * + * @brief functions for calculating jump polynomial. + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (The University of Tokyo) + * + * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, + * Hiroshima University and The University of Tokyo. + * All rights reserved. + * + * The 3-clause BSD License is applied to this software, see + * LICENSE.txt + */ +#include +#include +#include +#include + +namespace dsfmt { +/** + * converts polynomial to string for convenient use in C language. + * @param x output string + * @param polynomial input polynomial + */ + static inline void polytostring(std::string& x, NTL::GF2X& polynomial) + { + using namespace NTL; + using namespace std; + + long degree = deg(polynomial); + int buff; + stringstream ss; + for (int i = 0; i <= degree; i+=4) { + buff = 0; + for (int j = 0; j < 4; j++) { + if (IsOne(coeff(polynomial, i + j))) { + buff |= 1 << j; + } else { + buff &= (0x0f ^ (1 << j)); + } + } + ss << hex << buff; + } + ss << flush; + x = ss.str(); + } + +/** + * converts string to polynomial + * @param str string + * @param poly output polynomial + */ + static inline void stringtopoly(NTL::GF2X& poly, std::string& str) + { + using namespace NTL; + using namespace std; + + stringstream ss(str); + char c; + long p = 0; + clear(poly); + while(ss) { + ss >> c; + if (!ss) { + break; + } + if (c >= 'a') { + c = c - 'a' + 10; + } else { + c = c - '0'; + } + for (int j = 0; j < 4; j++) { + if (c & (1 << j)) { + SetCoeff(poly, p, 1); + } else { + SetCoeff(poly, p, 0); + } + p++; + } + } + } + +/** + * calculate the jump polynomial. + * SFMT generates 4 32-bit integers from one internal state. + * @param jump_str output string which represents jump polynomial. + * @param step jump step of internal state + * @param characteristic polynomial + */ + static inline void calc_jump(std::string& jump_str, + NTL::ZZ& step, + NTL::GF2X& characteristic) + { + using namespace NTL; + using namespace std; + GF2X jump; + PowerXMod(jump, step, characteristic); + polytostring(jump_str, jump); + } +} +#endif diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-common.h b/_randomgen/core_prng/src/dsfmt/dSFMT-common.h new file mode 100644 index 000000000000..30c26c08bed5 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-common.h @@ -0,0 +1,115 @@ +#pragma once +/** + * @file dSFMT-common.h + * + * @brief SIMD oriented Fast Mersenne Twister(SFMT) pseudorandom + * number generator with jump function. This file includes common functions + * used in random number generation and jump. + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (The University of Tokyo) + * + * Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima + * University. + * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima + * University and The University of Tokyo. + * All rights reserved. + * + * The 3-clause BSD License is applied to this software, see + * LICENSE.txt + */ +#ifndef DSFMT_COMMON_H +#define DSFMT_COMMON_H + +#include "dSFMT.h" + +#if defined(HAVE_SSE2) +# include +union X128I_T { + uint64_t u[2]; + __m128i i128; +}; +union X128D_T { + double d[2]; + __m128d d128; +}; +/** mask data for sse2 */ +static const union X128I_T sse2_param_mask = {{DSFMT_MSK1, DSFMT_MSK2}}; +#endif + +#if defined(HAVE_ALTIVEC) +inline static void do_recursion(w128_t *r, w128_t *a, w128_t * b, + w128_t *lung) { + const vector unsigned char sl1 = ALTI_SL1; + const vector unsigned char sl1_perm = ALTI_SL1_PERM; + const vector unsigned int sl1_msk = ALTI_SL1_MSK; + const vector unsigned char sr1 = ALTI_SR; + const vector unsigned char sr1_perm = ALTI_SR_PERM; + const vector unsigned int sr1_msk = ALTI_SR_MSK; + const vector unsigned char perm = ALTI_PERM; + const vector unsigned int msk1 = ALTI_MSK; + vector unsigned int w, x, y, z; + + z = a->s; + w = lung->s; + x = vec_perm(w, (vector unsigned int)perm, perm); + y = vec_perm(z, (vector unsigned int)sl1_perm, sl1_perm); + y = vec_sll(y, sl1); + y = vec_and(y, sl1_msk); + w = vec_xor(x, b->s); + w = vec_xor(w, y); + x = vec_perm(w, (vector unsigned int)sr1_perm, sr1_perm); + x = vec_srl(x, sr1); + x = vec_and(x, sr1_msk); + y = vec_and(w, msk1); + z = vec_xor(z, y); + r->s = vec_xor(z, x); + lung->s = w; +} +#elif defined(HAVE_SSE2) +/** + * This function represents the recursion formula. + * @param r output 128-bit + * @param a a 128-bit part of the internal state array + * @param b a 128-bit part of the internal state array + * @param d a 128-bit part of the internal state array (I/O) + */ +inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *u) { + __m128i v, w, x, y, z; + + x = a->si; + z = _mm_slli_epi64(x, DSFMT_SL1); + y = _mm_shuffle_epi32(u->si, SSE2_SHUFF); + z = _mm_xor_si128(z, b->si); + y = _mm_xor_si128(y, z); + + v = _mm_srli_epi64(y, DSFMT_SR); + w = _mm_and_si128(y, sse2_param_mask.i128); + v = _mm_xor_si128(v, x); + v = _mm_xor_si128(v, w); + r->si = v; + u->si = y; +} +#else +/** + * This function represents the recursion formula. + * @param r output 128-bit + * @param a a 128-bit part of the internal state array + * @param b a 128-bit part of the internal state array + * @param lung a 128-bit part of the internal state array (I/O) + */ +inline static void do_recursion(w128_t *r, w128_t *a, w128_t * b, + w128_t *lung) { + uint64_t t0, t1, L0, L1; + + t0 = a->u[0]; + t1 = a->u[1]; + L0 = lung->u[0]; + L1 = lung->u[1]; + lung->u[0] = (t0 << DSFMT_SL1) ^ (L1 >> 32) ^ (L1 << 32) ^ b->u[0]; + lung->u[1] = (t1 << DSFMT_SL1) ^ (L0 >> 32) ^ (L0 << 32) ^ b->u[1]; + r->u[0] = (lung->u[0] >> DSFMT_SR) ^ (lung->u[0] & DSFMT_MSK1) ^ t0; + r->u[1] = (lung->u[1] >> DSFMT_SR) ^ (lung->u[1] & DSFMT_MSK2) ^ t1; +} +#endif +#endif diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-params.h b/_randomgen/core_prng/src/dsfmt/dSFMT-params.h new file mode 100644 index 000000000000..aa0247800488 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-params.h @@ -0,0 +1,87 @@ +#ifndef DSFMT_PARAMS_H +#define DSFMT_PARAMS_H + +#include "dSFMT.h" + +/*---------------------- + the parameters of DSFMT + following definitions are in dSFMT-paramsXXXX.h file. + ----------------------*/ +/** the pick up position of the array. +#define DSFMT_POS1 122 +*/ + +/** the parameter of shift left as four 32-bit registers. +#define DSFMT_SL1 18 + */ + +/** the parameter of shift right as four 32-bit registers. +#define DSFMT_SR1 12 +*/ + +/** A bitmask, used in the recursion. These parameters are introduced + * to break symmetry of SIMD. +#define DSFMT_MSK1 (uint64_t)0xdfffffefULL +#define DSFMT_MSK2 (uint64_t)0xddfecb7fULL +*/ + +/** These definitions are part of a 128-bit period certification vector. +#define DSFMT_PCV1 UINT64_C(0x00000001) +#define DSFMT_PCV2 UINT64_C(0x00000000) +*/ + +#define DSFMT_LOW_MASK UINT64_C(0x000FFFFFFFFFFFFF) +#define DSFMT_HIGH_CONST UINT64_C(0x3FF0000000000000) +#define DSFMT_SR 12 + +/* for sse2 */ +#if defined(HAVE_SSE2) + #define SSE2_SHUFF 0x1b +#elif defined(HAVE_ALTIVEC) + #if defined(__APPLE__) /* For OSX */ + #define ALTI_SR (vector unsigned char)(4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4) + #define ALTI_SR_PERM \ + (vector unsigned char)(15,0,1,2,3,4,5,6,15,8,9,10,11,12,13,14) + #define ALTI_SR_MSK \ + (vector unsigned int)(0x000fffffU,0xffffffffU,0x000fffffU,0xffffffffU) + #define ALTI_PERM \ + (vector unsigned char)(12,13,14,15,8,9,10,11,4,5,6,7,0,1,2,3) + #else + #define ALTI_SR {4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4} + #define ALTI_SR_PERM {15,0,1,2,3,4,5,6,15,8,9,10,11,12,13,14} + #define ALTI_SR_MSK {0x000fffffU,0xffffffffU,0x000fffffU,0xffffffffU} + #define ALTI_PERM {12,13,14,15,8,9,10,11,4,5,6,7,0,1,2,3} + #endif +#endif + +#if DSFMT_MEXP == 521 + #include "dSFMT-params521.h" +#elif DSFMT_MEXP == 1279 + #include "dSFMT-params1279.h" +#elif DSFMT_MEXP == 2203 + #include "dSFMT-params2203.h" +#elif DSFMT_MEXP == 4253 + #include "dSFMT-params4253.h" +#elif DSFMT_MEXP == 11213 + #include "dSFMT-params11213.h" +#elif DSFMT_MEXP == 19937 + #include "dSFMT-params19937.h" +#elif DSFMT_MEXP == 44497 + #include "dSFMT-params44497.h" +#elif DSFMT_MEXP == 86243 + #include "dSFMT-params86243.h" +#elif DSFMT_MEXP == 132049 + #include "dSFMT-params132049.h" +#elif DSFMT_MEXP == 216091 + #include "dSFMT-params216091.h" +#else +#ifdef __GNUC__ + #error "DSFMT_MEXP is not valid." + #undef DSFMT_MEXP +#else + #undef DSFMT_MEXP +#endif + +#endif + +#endif /* DSFMT_PARAMS_H */ diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-params19937.h b/_randomgen/core_prng/src/dsfmt/dSFMT-params19937.h new file mode 100644 index 000000000000..a600b0dbcc2d --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-params19937.h @@ -0,0 +1,40 @@ +#ifndef DSFMT_PARAMS19937_H +#define DSFMT_PARAMS19937_H + +/* #define DSFMT_N 191 */ +/* #define DSFMT_MAXDEGREE 19992 */ +#define DSFMT_POS1 117 +#define DSFMT_SL1 19 +#define DSFMT_MSK1 UINT64_C(0x000ffafffffffb3f) +#define DSFMT_MSK2 UINT64_C(0x000ffdfffc90fffd) +#define DSFMT_MSK32_1 0x000ffaffU +#define DSFMT_MSK32_2 0xfffffb3fU +#define DSFMT_MSK32_3 0x000ffdffU +#define DSFMT_MSK32_4 0xfc90fffdU +#define DSFMT_FIX1 UINT64_C(0x90014964b32f4329) +#define DSFMT_FIX2 UINT64_C(0x3b8d12ac548a7c7a) +#define DSFMT_PCV1 UINT64_C(0x3d84e1ac0dc82880) +#define DSFMT_PCV2 UINT64_C(0x0000000000000001) +#define DSFMT_IDSTR "dSFMT2-19937:117-19:ffafffffffb3f-ffdfffc90fffd" + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned char)(3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3) + #define ALTI_SL1_PERM \ + (vector unsigned char)(2,3,4,5,6,7,30,30,10,11,12,13,14,15,0,1) + #define ALTI_SL1_MSK \ + (vector unsigned int)(0xffffffffU,0xfff80000U,0xffffffffU,0xfff80000U) + #define ALTI_MSK (vector unsigned int)(DSFMT_MSK32_1, \ + DSFMT_MSK32_2, DSFMT_MSK32_3, DSFMT_MSK32_4) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3} + #define ALTI_SL1_PERM \ + {2,3,4,5,6,7,30,30,10,11,12,13,14,15,0,1} + #define ALTI_SL1_MSK \ + {0xffffffffU,0xfff80000U,0xffffffffU,0xfff80000U} + #define ALTI_MSK \ + {DSFMT_MSK32_1, DSFMT_MSK32_2, DSFMT_MSK32_3, DSFMT_MSK32_4} +#endif + +#endif /* DSFMT_PARAMS19937_H */ diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c b/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c new file mode 100644 index 000000000000..9103f6d5030d --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c @@ -0,0 +1,53 @@ +/* +* +* gcc dSFMT-test-gen.c dSFMT.c -DHAVE_SSE2 -DDSFMT_MEXP=19937 -o dSFMT +*/ +#include +#include +#include "dSFMT.h" + +int main(void) +{ + int i; + double d; + uint64_t *temp; + uint32_t seed = 1UL; + dsfmt_t state; + dsfmt_init_gen_rand(&state, seed); + double out[1000]; + dsfmt_fill_array_close1_open2(&state, out, 1000); + + FILE *fp; + fp = fopen("dSFMT-testset-1.csv", "w"); + if(fp == NULL){ + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, %" PRIu32 "\n", seed); + for (i=0; i < 1000; i++) + { + d = out[i]; + temp = (uint64_t *)&d; + fprintf(fp, "%d, %" PRIu64 "\n", i, *temp); + printf("%d, %" PRIu64 "\n", i, *temp); + } + fclose(fp); + + seed = 123456789UL; + dsfmt_init_gen_rand(&state, seed); + dsfmt_fill_array_close1_open2(&state, out, 1000); + fp = fopen("dSFMT-testset-2.csv", "w"); + if(fp == NULL){ + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, %" PRIu32 "\n", seed); + for (i=0; i < 1000; i++) + { + d = out[i]; + temp = (uint64_t *)&d; + fprintf(fp, "%d, %" PRIu64 "\n", i, *temp); + printf("%d, %" PRIu64 "\n", i, *temp); + } + fclose(fp); +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/dsfmt/dsfmt-jump.c b/_randomgen/core_prng/src/dsfmt/dsfmt-jump.c new file mode 100644 index 000000000000..1832bb8853b7 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dsfmt-jump.c @@ -0,0 +1,184 @@ +/** + * @file dSFMT-jump.c + * + * @brief do jump using jump polynomial. + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (The University of Tokyo) + * + * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, + * Hiroshima University and The University of Tokyo. + * All rights reserved. + * + * The 3-clause BSD License is applied to this software, see + * LICENSE.txt + */ + +#include +#include +#include +#include +#include "dSFMT-params.h" +#include "dSFMT.h" +#include "dSFMT-jump.h" +#include "dSFMT-common.h" + +#if defined(__cplusplus) +extern "C" { +#endif + + struct FIX_T { + int mexp; + uint64_t fix[4]; + }; + + struct FIX_T fix_table[] = { + {521, {UINT64_C(0x3fff56977f035125), + UINT64_C(0x3ff553857b015035), + UINT64_C(0x4034434434434434), + UINT64_C(0x0140151151351371)}}, + {1279, {UINT64_C(0x3ff87befce70e89f), + UINT64_C(0x3ff5f6afa3c60868), + UINT64_C(0xa4ca4caccaccacdb), + UINT64_C(0x40444444444c44c4)}}, + {4253, {UINT64_C(0x3ff85a66da51a81a), + UINT64_C(0x3ff4f4aeab9688eb), + UINT64_C(0x20524524534d34d3), + UINT64_C(0xc9cc9cc9cc9ccdcf)}}, + {216091, {UINT64_C(0x3ff096d54a871071), + UINT64_C(0x3ffafa9bfbd5d55d), + UINT64_C(0x0470470470573573), + UINT64_C(0x0250250251259259)}}, + {0} + }; + + inline static void next_state(dsfmt_t * dsfmt); + +#if defined(HAVE_SSE2) +/** + * add internal state of src to dest as F2-vector. + * @param dest destination state + * @param src source state + */ + inline static void add(dsfmt_t *dest, dsfmt_t *src) { + int dp = dest->idx / 2; + int sp = src->idx / 2; + int diff = (sp - dp + DSFMT_N) % DSFMT_N; + int p; + int i; + for (i = 0; i < DSFMT_N - diff; i++) { + p = i + diff; + dest->status[i].si + = _mm_xor_si128(dest->status[i].si, src->status[p].si); + } + for (i = DSFMT_N - diff; i < DSFMT_N; i++) { + p = i + diff - DSFMT_N; + dest->status[i].si + = _mm_xor_si128(dest->status[i].si, src->status[p].si); + } + dest->status[DSFMT_N].si + = _mm_xor_si128(dest->status[DSFMT_N].si, + src->status[DSFMT_N].si); + } +#else + inline static void add(dsfmt_t *dest, dsfmt_t *src) { + int dp = dest->idx / 2; + int sp = src->idx / 2; + int diff = (sp - dp + DSFMT_N) % DSFMT_N; + int p; + int i; + for (i = 0; i < DSFMT_N - diff; i++) { + p = i + diff; + dest->status[i].u[0] ^= src->status[p].u[0]; + dest->status[i].u[1] ^= src->status[p].u[1]; + } + for (; i < DSFMT_N; i++) { + p = i + diff - DSFMT_N; + dest->status[i].u[0] ^= src->status[p].u[0]; + dest->status[i].u[1] ^= src->status[p].u[1]; + } + dest->status[DSFMT_N].u[0] ^= src->status[DSFMT_N].u[0]; + dest->status[DSFMT_N].u[1] ^= src->status[DSFMT_N].u[1]; + } +#endif + +/** + * calculate next state + * @param dsfmt dSFMT internal state + */ + inline static void next_state(dsfmt_t * dsfmt) { + int idx = (dsfmt->idx / 2) % DSFMT_N; + w128_t * lung; + w128_t * pstate = &dsfmt->status[0]; + + lung = &pstate[DSFMT_N]; + do_recursion(&pstate[idx], + &pstate[idx], + &pstate[(idx + DSFMT_POS1) % DSFMT_N], + lung); + dsfmt->idx = (dsfmt->idx + 2) % DSFMT_N64; + } + + inline static void add_fix(dsfmt_t * dsfmt) { + int i; + int index = -1; + for (i = 0; fix_table[i].mexp != 0; i++) { + if (fix_table[i].mexp == DSFMT_MEXP) { + index = i; + } + if (fix_table[i].mexp > DSFMT_MEXP) { + break; + } + } + if (index < 0) { + return; + } + for (i = 0; i < DSFMT_N; i++) { + dsfmt->status[i].u[0] ^= fix_table[index].fix[0]; + dsfmt->status[i].u[1] ^= fix_table[index].fix[1]; + } + dsfmt->status[DSFMT_N].u[0] ^= fix_table[index].fix[2]; + dsfmt->status[DSFMT_N].u[1] ^= fix_table[index].fix[3]; + } + +/** + * jump ahead using jump_string + * @param dsfmt dSFMT internal state input and output. + * @param jump_string string which represents jump polynomial. + */ + void dSFMT_jump(dsfmt_t * dsfmt, const char * jump_string) { + dsfmt_t work; + int index = dsfmt->idx; + int bits; + int i; + int j; + memset(&work, 0, sizeof(dsfmt_t)); + add_fix(dsfmt); + dsfmt->idx = DSFMT_N64; + + for (i = 0; jump_string[i] != '\0'; i++) { + bits = jump_string[i]; + assert(isxdigit(bits)); + bits = tolower(bits); + if (bits >= 'a' && bits <= 'f') { + bits = bits - 'a' + 10; + } else { + bits = bits - '0'; + } + bits = bits & 0x0f; + for (j = 0; j < 4; j++) { + if ((bits & 1) != 0) { + add(&work, dsfmt); + } + next_state(dsfmt); + bits = bits >> 1; + } + } + *dsfmt = work; + add_fix(dsfmt); + dsfmt->idx = index; + } + +#if defined(__cplusplus) +} +#endif diff --git a/_randomgen/core_prng/src/dsfmt/dsfmt-jump.h b/_randomgen/core_prng/src/dsfmt/dsfmt-jump.h new file mode 100644 index 000000000000..2979f3269bc3 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dsfmt-jump.h @@ -0,0 +1,29 @@ +#pragma once +#ifndef DSFMT_JUMP_H +#define DSFMT_JUMP_H +/** + * @file SFMT-jump.h + * + * @brief jump header file. + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (The University of Tokyo) + * + * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, + * Hiroshima University and The University of Tokyo. + * All rights reserved. + * + * The 3-clause BSD License is applied to this software, see + * LICENSE.txt + */ +#if defined(__cplusplus) +extern "C" { +#endif + +#include "dSFMT.h" +void dSFMT_jump(dsfmt_t * dsfmt, const char * jump_str); + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/_randomgen/core_prng/src/dsfmt/dsfmt.c b/_randomgen/core_prng/src/dsfmt/dsfmt.c new file mode 100644 index 000000000000..3ce156699175 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dsfmt.c @@ -0,0 +1,639 @@ +/** + * @file dSFMT.c + * @brief double precision SIMD-oriented Fast Mersenne Twister (dSFMT) + * based on IEEE 754 format. + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (Hiroshima University) + * + * Copyright (C) 2007,2008 Mutsuo Saito, Makoto Matsumoto and Hiroshima + * University. All rights reserved. + * + * The new BSD License is applied to this software, see LICENSE.txt + */ +#include +#include +#include +#include "dSFMT-params.h" +#include "dSFMT-common.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/** dsfmt internal state vector */ +dsfmt_t dsfmt_global_data; +/** dsfmt mexp for check */ +static const int dsfmt_mexp = DSFMT_MEXP; + +/*---------------- + STATIC FUNCTIONS + ----------------*/ +inline static uint32_t ini_func1(uint32_t x); +inline static uint32_t ini_func2(uint32_t x); +inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, + int size); +inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, + int size); +inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, + int size); +inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, + int size); +inline static int idxof(int i); +static void initial_mask(dsfmt_t *dsfmt); +static void period_certification(dsfmt_t *dsfmt); + +#if defined(HAVE_SSE2) +/** 1 in 64bit for sse2 */ +static const union X128I_T sse2_int_one = {{1, 1}}; +/** 2.0 double for sse2 */ +static const union X128D_T sse2_double_two = {{2.0, 2.0}}; +/** -1.0 double for sse2 */ +static const union X128D_T sse2_double_m_one = {{-1.0, -1.0}}; +#endif + +/** + * This function simulate a 32-bit array index overlapped to 64-bit + * array of LITTLE ENDIAN in BIG ENDIAN machine. + */ +#if defined(DSFMT_BIG_ENDIAN) +inline static int idxof(int i) { + return i ^ 1; +} +#else +inline static int idxof(int i) { + return i; +} +#endif + +#if defined(HAVE_SSE2) +/** + * This function converts the double precision floating point numbers which + * distribute uniformly in the range [1, 2) to those which distribute uniformly + * in the range [0, 1). + * @param w 128bit stracture of double precision floating point numbers (I/O) + */ +inline static void convert_c0o1(w128_t *w) { + w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); +} + +/** + * This function converts the double precision floating point numbers which + * distribute uniformly in the range [1, 2) to those which distribute uniformly + * in the range (0, 1]. + * @param w 128bit stracture of double precision floating point numbers (I/O) + */ +inline static void convert_o0c1(w128_t *w) { + w->sd = _mm_sub_pd(sse2_double_two.d128, w->sd); +} + +/** + * This function converts the double precision floating point numbers which + * distribute uniformly in the range [1, 2) to those which distribute uniformly + * in the range (0, 1). + * @param w 128bit stracture of double precision floating point numbers (I/O) + */ +inline static void convert_o0o1(w128_t *w) { + w->si = _mm_or_si128(w->si, sse2_int_one.i128); + w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); +} +#else /* standard C and altivec */ +/** + * This function converts the double precision floating point numbers which + * distribute uniformly in the range [1, 2) to those which distribute uniformly + * in the range [0, 1). + * @param w 128bit stracture of double precision floating point numbers (I/O) + */ +inline static void convert_c0o1(w128_t *w) { + w->d[0] -= 1.0; + w->d[1] -= 1.0; +} + +/** + * This function converts the double precision floating point numbers which + * distribute uniformly in the range [1, 2) to those which distribute uniformly + * in the range (0, 1]. + * @param w 128bit stracture of double precision floating point numbers (I/O) + */ +inline static void convert_o0c1(w128_t *w) { + w->d[0] = 2.0 - w->d[0]; + w->d[1] = 2.0 - w->d[1]; +} + +/** + * This function converts the double precision floating point numbers which + * distribute uniformly in the range [1, 2) to those which distribute uniformly + * in the range (0, 1). + * @param w 128bit stracture of double precision floating point numbers (I/O) + */ +inline static void convert_o0o1(w128_t *w) { + w->u[0] |= 1; + w->u[1] |= 1; + w->d[0] -= 1.0; + w->d[1] -= 1.0; +} +#endif + +/** + * This function fills the user-specified array with double precision + * floating point pseudorandom numbers of the IEEE 754 format. + * @param dsfmt dsfmt state vector. + * @param array an 128-bit array to be filled by pseudorandom numbers. + * @param size number of 128-bit pseudorandom numbers to be generated. + */ +inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], + &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + } + dsfmt->status[DSFMT_N] = lung; +} + +/** + * This function fills the user-specified array with double precision + * floating point pseudorandom numbers of the IEEE 754 format. + * @param dsfmt dsfmt state vector. + * @param array an 128-bit array to be filled by pseudorandom numbers. + * @param size number of 128-bit pseudorandom numbers to be generated. + */ +inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], + &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_c0o1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_c0o1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_c0o1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; +} + +/** + * This function fills the user-specified array with double precision + * floating point pseudorandom numbers of the IEEE 754 format. + * @param dsfmt dsfmt state vector. + * @param array an 128-bit array to be filled by pseudorandom numbers. + * @param size number of 128-bit pseudorandom numbers to be generated. + */ +inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], + &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_o0o1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_o0o1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_o0o1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; +} + +/** + * This function fills the user-specified array with double precision + * floating point pseudorandom numbers of the IEEE 754 format. + * @param dsfmt dsfmt state vector. + * @param array an 128-bit array to be filled by pseudorandom numbers. + * @param size number of 128-bit pseudorandom numbers to be generated. + */ +inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], + &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_o0c1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_o0c1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_o0c1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; +} + +/** + * This function represents a function used in the initialization + * by init_by_array + * @param x 32-bit integer + * @return 32-bit integer + */ +static uint32_t ini_func1(uint32_t x) { + return (x ^ (x >> 27)) * (uint32_t)1664525UL; +} + +/** + * This function represents a function used in the initialization + * by init_by_array + * @param x 32-bit integer + * @return 32-bit integer + */ +static uint32_t ini_func2(uint32_t x) { + return (x ^ (x >> 27)) * (uint32_t)1566083941UL; +} + +/** + * This function initializes the internal state array to fit the IEEE + * 754 format. + * @param dsfmt dsfmt state vector. + */ +static void initial_mask(dsfmt_t *dsfmt) { + int i; + uint64_t *psfmt; + + psfmt = &dsfmt->status[0].u[0]; + for (i = 0; i < DSFMT_N * 2; i++) { + psfmt[i] = (psfmt[i] & DSFMT_LOW_MASK) | DSFMT_HIGH_CONST; + } +} + +/** + * This function certificate the period of 2^{SFMT_MEXP}-1. + * @param dsfmt dsfmt state vector. + */ +static void period_certification(dsfmt_t *dsfmt) { + uint64_t pcv[2] = {DSFMT_PCV1, DSFMT_PCV2}; + uint64_t tmp[2]; + uint64_t inner; + int i; +#if (DSFMT_PCV2 & 1) != 1 + int j; + uint64_t work; +#endif + + tmp[0] = (dsfmt->status[DSFMT_N].u[0] ^ DSFMT_FIX1); + tmp[1] = (dsfmt->status[DSFMT_N].u[1] ^ DSFMT_FIX2); + + inner = tmp[0] & pcv[0]; + inner ^= tmp[1] & pcv[1]; + for (i = 32; i > 0; i >>= 1) { + inner ^= inner >> i; + } + inner &= 1; + /* check OK */ + if (inner == 1) { + return; + } + /* check NG, and modification */ +#if (DSFMT_PCV2 & 1) == 1 + dsfmt->status[DSFMT_N].u[1] ^= 1; +#else + for (i = 1; i >= 0; i--) { + work = 1; + for (j = 0; j < 64; j++) { + if ((work & pcv[i]) != 0) { + dsfmt->status[DSFMT_N].u[i] ^= work; + return; + } + work = work << 1; + } + } +#endif + return; +} + +/*---------------- + PUBLIC FUNCTIONS + ----------------*/ +/** + * This function returns the identification string. The string shows + * the Mersenne exponent, and all parameters of this generator. + * @return id string. + */ +const char *dsfmt_get_idstring(void) { + return DSFMT_IDSTR; +} + +/** + * This function returns the minimum size of array used for \b + * fill_array functions. + * @return minimum size of array used for fill_array functions. + */ +int dsfmt_get_min_array_size(void) { + return DSFMT_N64; +} + +/** + * This function fills the internal state array with double precision + * floating point pseudorandom numbers of the IEEE 754 format. + * @param dsfmt dsfmt state vector. + */ +void dsfmt_gen_rand_all(dsfmt_t *dsfmt) { + int i; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&dsfmt->status[0], &dsfmt->status[0], + &dsfmt->status[DSFMT_POS1], &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&dsfmt->status[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&dsfmt->status[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1 - DSFMT_N], &lung); + } + dsfmt->status[DSFMT_N] = lung; +} + +/** + * This function generates double precision floating point + * pseudorandom numbers which distribute in the range [1, 2) to the + * specified array[] by one call. The number of pseudorandom numbers + * is specified by the argument \b size, which must be at least (SFMT_MEXP + * / 128) * 2 and a multiple of two. The function + * get_min_array_size() returns this minimum size. The generation by + * this function is much faster than the following fill_array_xxx functions. + * + * For initialization, init_gen_rand() or init_by_array() must be called + * before the first call of this function. This function can not be + * used after calling genrand_xxx functions, without initialization. + * + * @param dsfmt dsfmt state vector. + * @param array an array where pseudorandom numbers are filled + * by this function. The pointer to the array must be "aligned" + * (namely, must be a multiple of 16) in the SIMD version, since it + * refers to the address of a 128-bit integer. In the standard C + * version, the pointer is arbitrary. + * + * @param size the number of 64-bit pseudorandom integers to be + * generated. size must be a multiple of 2, and greater than or equal + * to (SFMT_MEXP / 128) * 2. + * + * @note \b memalign or \b posix_memalign is available to get aligned + * memory. Mac OSX doesn't have these functions, but \b malloc of OSX + * returns the pointer to the aligned memory block. + */ +void dsfmt_fill_array_close1_open2(dsfmt_t *dsfmt, double array[], int size) { + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_c1o2(dsfmt, (w128_t *)array, size / 2); +} + +/** + * This function generates double precision floating point + * pseudorandom numbers which distribute in the range (0, 1] to the + * specified array[] by one call. This function is the same as + * fill_array_close1_open2() except the distribution range. + * + * @param dsfmt dsfmt state vector. + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa fill_array_close1_open2() + */ +void dsfmt_fill_array_open_close(dsfmt_t *dsfmt, double array[], int size) { + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_o0c1(dsfmt, (w128_t *)array, size / 2); +} + +/** + * This function generates double precision floating point + * pseudorandom numbers which distribute in the range [0, 1) to the + * specified array[] by one call. This function is the same as + * fill_array_close1_open2() except the distribution range. + * + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param dsfmt dsfmt state vector. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa fill_array_close1_open2() + */ +void dsfmt_fill_array_close_open(dsfmt_t *dsfmt, double array[], int size) { + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_c0o1(dsfmt, (w128_t *)array, size / 2); +} + +/** + * This function generates double precision floating point + * pseudorandom numbers which distribute in the range (0, 1) to the + * specified array[] by one call. This function is the same as + * fill_array_close1_open2() except the distribution range. + * + * @param dsfmt dsfmt state vector. + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa fill_array_close1_open2() + */ +void dsfmt_fill_array_open_open(dsfmt_t *dsfmt, double array[], int size) { + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_o0o1(dsfmt, (w128_t *)array, size / 2); +} + +#if defined(__INTEL_COMPILER) +# pragma warning(disable:981) +#endif +/** + * This function initializes the internal state array with a 32-bit + * integer seed. + * @param dsfmt dsfmt state vector. + * @param seed a 32-bit integer used as the seed. + * @param mexp caller's mersenne expornent + */ +void dsfmt_chk_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed, int mexp) { + int i; + uint32_t *psfmt; + + /* make sure caller program is compiled with the same MEXP */ + if (mexp != dsfmt_mexp) { + fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); + exit(1); + } + psfmt = &dsfmt->status[0].u32[0]; + psfmt[idxof(0)] = seed; + for (i = 1; i < (DSFMT_N + 1) * 4; i++) { + psfmt[idxof(i)] = 1812433253UL + * (psfmt[idxof(i - 1)] ^ (psfmt[idxof(i - 1)] >> 30)) + i; + } + initial_mask(dsfmt); + period_certification(dsfmt); + dsfmt->idx = DSFMT_N64; +} + +/** + * This function initializes the internal state array, + * with an array of 32-bit integers used as the seeds + * @param dsfmt dsfmt state vector. + * @param init_key the array of 32-bit integers, used as a seed. + * @param key_length the length of init_key. + * @param mexp caller's mersenne expornent + */ +void dsfmt_chk_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], + int key_length, int mexp) { + int i, j, count; + uint32_t r; + uint32_t *psfmt32; + int lag; + int mid; + int size = (DSFMT_N + 1) * 4; /* pulmonary */ + + /* make sure caller program is compiled with the same MEXP */ + if (mexp != dsfmt_mexp) { + fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); + exit(1); + } + if (size >= 623) { + lag = 11; + } else if (size >= 68) { + lag = 7; + } else if (size >= 39) { + lag = 5; + } else { + lag = 3; + } + mid = (size - lag) / 2; + + psfmt32 = &dsfmt->status[0].u32[0]; + memset(dsfmt->status, 0x8b, sizeof(dsfmt->status)); + if (key_length + 1 > size) { + count = key_length + 1; + } else { + count = size; + } + r = ini_func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid % size)] + ^ psfmt32[idxof((size - 1) % size)]); + psfmt32[idxof(mid % size)] += r; + r += key_length; + psfmt32[idxof((mid + lag) % size)] += r; + psfmt32[idxof(0)] = r; + count--; + for (i = 1, j = 0; (j < count) && (j < key_length); j++) { + r = ini_func1(psfmt32[idxof(i)] + ^ psfmt32[idxof((i + mid) % size)] + ^ psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] += r; + r += init_key[j] + i; + psfmt32[idxof((i + mid + lag) % size)] += r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + for (; j < count; j++) { + r = ini_func1(psfmt32[idxof(i)] + ^ psfmt32[idxof((i + mid) % size)] + ^ psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] += r; + r += i; + psfmt32[idxof((i + mid + lag) % size)] += r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + for (j = 0; j < size; j++) { + r = ini_func2(psfmt32[idxof(i)] + + psfmt32[idxof((i + mid) % size)] + + psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] ^= r; + r -= i; + psfmt32[idxof((i + mid + lag) % size)] ^= r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + initial_mask(dsfmt); + period_certification(dsfmt); + dsfmt->idx = DSFMT_N64; +} +#if defined(__INTEL_COMPILER) +# pragma warning(default:981) +#endif + +#if defined(__cplusplus) +} +#endif + +extern inline double dsfmt_next_double(dsfmt_state *state); + +extern inline uint64_t dsfmt_next64(dsfmt_state *state); + +extern inline uint32_t dsfmt_next32(dsfmt_state *state); \ No newline at end of file diff --git a/_randomgen/core_prng/src/dsfmt/dsfmt.h b/_randomgen/core_prng/src/dsfmt/dsfmt.h new file mode 100644 index 000000000000..52b6b3aedcc2 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dsfmt.h @@ -0,0 +1,678 @@ +#pragma once +/** + * @file dSFMT.h + * + * @brief double precision SIMD oriented Fast Mersenne Twister(dSFMT) + * pseudorandom number generator based on IEEE 754 format. + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (Hiroshima University) + * + * Copyright (C) 2007, 2008 Mutsuo Saito, Makoto Matsumoto and + * Hiroshima University. All rights reserved. + * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, + * Hiroshima University and The University of Tokyo. + * All rights reserved. + * + * The new BSD License is applied to this software. + * see LICENSE.txt + * + * @note We assume that your system has inttypes.h. If your system + * doesn't have inttypes.h, you have to typedef uint32_t and uint64_t, + * and you have to define PRIu64 and PRIx64 in this file as follows: + * @verbatim + typedef unsigned int uint32_t + typedef unsigned long long uint64_t + #define PRIu64 "llu" + #define PRIx64 "llx" +@endverbatim + * uint32_t must be exactly 32-bit unsigned integer type (no more, no + * less), and uint64_t must be exactly 64-bit unsigned integer type. + * PRIu64 and PRIx64 are used for printf function to print 64-bit + * unsigned int and 64-bit unsigned int in hexadecimal format. + */ + +#ifndef DSFMT_H +#define DSFMT_H +#if defined(__cplusplus) +extern "C" { +#endif + +#include +#include + +#if !defined(DSFMT_MEXP) +#ifdef __GNUC__ + #warning "DSFMT_MEXP is not defined. I assume DSFMT_MEXP is 19937." +#endif + #define DSFMT_MEXP 19937 +#endif +/*----------------- + BASIC DEFINITIONS + -----------------*/ +/* Mersenne Exponent. The period of the sequence + * is a multiple of 2^DSFMT_MEXP-1. + * #define DSFMT_MEXP 19937 */ +/** DSFMT generator has an internal state array of 128-bit integers, + * and N is its size. */ +#define DSFMT_N ((DSFMT_MEXP - 128) / 104 + 1) +/** N32 is the size of internal state array when regarded as an array + * of 32-bit integers.*/ +#define DSFMT_N32 (DSFMT_N * 4) +/** N64 is the size of internal state array when regarded as an array + * of 64-bit integers.*/ +#define DSFMT_N64 (DSFMT_N * 2) + +#if !defined(DSFMT_BIG_ENDIAN) +# if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) +# if __BYTE_ORDER == __BIG_ENDIAN +# define DSFMT_BIG_ENDIAN 1 +# endif +# elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) +# if _BYTE_ORDER == _BIG_ENDIAN +# define DSFMT_BIG_ENDIAN 1 +# endif +# elif defined(__BYTE_ORDER__) && defined(__BIG_ENDIAN__) +# if __BYTE_ORDER__ == __BIG_ENDIAN__ +# define DSFMT_BIG_ENDIAN 1 +# endif +# elif defined(BYTE_ORDER) && defined(BIG_ENDIAN) +# if BYTE_ORDER == BIG_ENDIAN +# define DSFMT_BIG_ENDIAN 1 +# endif +# elif defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) \ + || defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) +# define DSFMT_BIG_ENDIAN 1 +# endif +#endif + +#if defined(DSFMT_BIG_ENDIAN) && defined(__amd64) +# undef DSFMT_BIG_ENDIAN +#endif + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# include +#elif defined(_MSC_VER) || defined(__BORLANDC__) +# if !defined(DSFMT_UINT32_DEFINED) && !defined(SFMT_UINT32_DEFINED) +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +# ifndef UINT64_C +# define UINT64_C(v) (v ## ui64) +# endif +# define DSFMT_UINT32_DEFINED +# if !defined(inline) && !defined(__cplusplus) +# define inline __forceinline +# endif +# endif +#else +# include +# if !defined(inline) && !defined(__cplusplus) +# if defined(__GNUC__) +# define inline __forceinline__ +# else +# define inline +# endif +# endif +#endif + +#ifndef PRIu64 +# if defined(_MSC_VER) || defined(__BORLANDC__) +# define PRIu64 "I64u" +# define PRIx64 "I64x" +# else +# define PRIu64 "llu" +# define PRIx64 "llx" +# endif +#endif + +#ifndef UINT64_C +# define UINT64_C(v) (v ## ULL) +#endif + +/*------------------------------------------ + 128-bit SIMD like data type for standard C + ------------------------------------------*/ +#if defined(HAVE_ALTIVEC) +# if !defined(__APPLE__) +# include +# endif +/** 128-bit data structure */ +union W128_T { + vector unsigned int s; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; +}; + +#elif defined(HAVE_SSE2) +# include + +/** 128-bit data structure */ +union W128_T { + __m128i si; + __m128d sd; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; +}; +#else /* standard C */ +/** 128-bit data structure */ +union W128_T { + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; +}; +#endif + +/** 128-bit data type */ +typedef union W128_T w128_t; + +/** the 128-bit internal state array */ +struct DSFMT_T { + w128_t status[DSFMT_N + 1]; + int idx; +}; +typedef struct DSFMT_T dsfmt_t; + +/** dsfmt internal state vector */ +extern dsfmt_t dsfmt_global_data; +/** dsfmt mexp for check */ +extern const int dsfmt_global_mexp; + +void dsfmt_gen_rand_all(dsfmt_t *dsfmt); +void dsfmt_fill_array_open_close(dsfmt_t *dsfmt, double array[], int size); +void dsfmt_fill_array_close_open(dsfmt_t *dsfmt, double array[], int size); +void dsfmt_fill_array_open_open(dsfmt_t *dsfmt, double array[], int size); +void dsfmt_fill_array_close1_open2(dsfmt_t *dsfmt, double array[], int size); +void dsfmt_chk_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed, int mexp); +void dsfmt_chk_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], + int key_length, int mexp); +const char *dsfmt_get_idstring(void); +int dsfmt_get_min_array_size(void); + +#if defined(__GNUC__) +# define DSFMT_PRE_INLINE inline static +# define DSFMT_PST_INLINE __attribute__((always_inline)) +#elif defined(_MSC_VER) && _MSC_VER >= 1200 +# define DSFMT_PRE_INLINE __forceinline static +# define DSFMT_PST_INLINE +#else +# define DSFMT_PRE_INLINE inline static +# define DSFMT_PST_INLINE +#endif +DSFMT_PRE_INLINE uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_genrand_close_open(dsfmt_t *dsfmt) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_genrand_open_close(dsfmt_t *dsfmt) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_genrand_open_open(dsfmt_t *dsfmt) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE uint32_t dsfmt_gv_genrand_uint32(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_gv_genrand_close1_open2(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_gv_genrand_close_open(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_gv_genrand_open_close(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_gv_genrand_open_open(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_close(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close_open(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_open(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close1_open2(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_init_gen_rand(uint32_t seed) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_init_by_array(uint32_t init_key[], + int key_length) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], + int key_length) DSFMT_PST_INLINE; + +/** + * This function generates and returns unsigned 32-bit integer. + * This is slower than SFMT, only for convenience usage. + * dsfmt_init_gen_rand() or dsfmt_init_by_array() must be called + * before this function. + * @param dsfmt dsfmt internal state date + * @return double precision floating point pseudorandom number + */ +inline static uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) { + uint32_t r; + uint64_t *psfmt64 = &dsfmt->status[0].u[0]; + + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r = psfmt64[dsfmt->idx++] & 0xffffffffU; + return r; +} + +/** + * This function generates and returns double precision pseudorandom + * number which distributes uniformly in the range [1, 2). This is + * the primitive and faster than generating numbers in other ranges. + * dsfmt_init_gen_rand() or dsfmt_init_by_array() must be called + * before this function. + * @param dsfmt dsfmt internal state date + * @return double precision floating point pseudorandom number + */ +inline static double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) { + double r; + double *psfmt64 = &dsfmt->status[0].d[0]; + + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r = psfmt64[dsfmt->idx++]; + return r; +} + +/** + * This function generates and returns unsigned 32-bit integer. + * This is slower than SFMT, only for convenience usage. + * dsfmt_gv_init_gen_rand() or dsfmt_gv_init_by_array() must be called + * before this function. This function uses \b global variables. + * @return double precision floating point pseudorandom number + */ +inline static uint32_t dsfmt_gv_genrand_uint32(void) { + return dsfmt_genrand_uint32(&dsfmt_global_data); +} + +/** + * This function generates and returns double precision pseudorandom + * number which distributes uniformly in the range [1, 2). + * dsfmt_gv_init_gen_rand() or dsfmt_gv_init_by_array() must be called + * before this function. This function uses \b global variables. + * @return double precision floating point pseudorandom number + */ +inline static double dsfmt_gv_genrand_close1_open2(void) { + return dsfmt_genrand_close1_open2(&dsfmt_global_data); +} + +/** + * This function generates and returns double precision pseudorandom + * number which distributes uniformly in the range [0, 1). + * dsfmt_init_gen_rand() or dsfmt_init_by_array() must be called + * before this function. + * @param dsfmt dsfmt internal state date + * @return double precision floating point pseudorandom number + */ +inline static double dsfmt_genrand_close_open(dsfmt_t *dsfmt) { + return dsfmt_genrand_close1_open2(dsfmt) - 1.0; +} + +/** + * This function generates and returns double precision pseudorandom + * number which distributes uniformly in the range [0, 1). + * dsfmt_gv_init_gen_rand() or dsfmt_gv_init_by_array() must be called + * before this function. This function uses \b global variables. + * @return double precision floating point pseudorandom number + */ +inline static double dsfmt_gv_genrand_close_open(void) { + return dsfmt_gv_genrand_close1_open2() - 1.0; +} + +/** + * This function generates and returns double precision pseudorandom + * number which distributes uniformly in the range (0, 1]. + * dsfmt_init_gen_rand() or dsfmt_init_by_array() must be called + * before this function. + * @param dsfmt dsfmt internal state date + * @return double precision floating point pseudorandom number + */ +inline static double dsfmt_genrand_open_close(dsfmt_t *dsfmt) { + return 2.0 - dsfmt_genrand_close1_open2(dsfmt); +} + +/** + * This function generates and returns double precision pseudorandom + * number which distributes uniformly in the range (0, 1]. + * dsfmt_gv_init_gen_rand() or dsfmt_gv_init_by_array() must be called + * before this function. This function uses \b global variables. + * @return double precision floating point pseudorandom number + */ +inline static double dsfmt_gv_genrand_open_close(void) { + return 2.0 - dsfmt_gv_genrand_close1_open2(); +} + +/** + * This function generates and returns double precision pseudorandom + * number which distributes uniformly in the range (0, 1). + * dsfmt_init_gen_rand() or dsfmt_init_by_array() must be called + * before this function. + * @param dsfmt dsfmt internal state date + * @return double precision floating point pseudorandom number + */ +inline static double dsfmt_genrand_open_open(dsfmt_t *dsfmt) { + double *dsfmt64 = &dsfmt->status[0].d[0]; + union { + double d; + uint64_t u; + } r; + + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r.d = dsfmt64[dsfmt->idx++]; + r.u |= 1; + return r.d - 1.0; +} + +/** + * This function generates and returns double precision pseudorandom + * number which distributes uniformly in the range (0, 1). + * dsfmt_gv_init_gen_rand() or dsfmt_gv_init_by_array() must be called + * before this function. This function uses \b global variables. + * @return double precision floating point pseudorandom number + */ +inline static double dsfmt_gv_genrand_open_open(void) { + return dsfmt_genrand_open_open(&dsfmt_global_data); +} + +/** + * This function generates double precision floating point + * pseudorandom numbers which distribute in the range [1, 2) to the + * specified array[] by one call. This function is the same as + * dsfmt_fill_array_close1_open2() except that this function uses + * \b global variables. + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa dsfmt_fill_array_close1_open2() + */ +inline static void dsfmt_gv_fill_array_close1_open2(double array[], int size) { + dsfmt_fill_array_close1_open2(&dsfmt_global_data, array, size); +} + +/** + * This function generates double precision floating point + * pseudorandom numbers which distribute in the range (0, 1] to the + * specified array[] by one call. This function is the same as + * dsfmt_gv_fill_array_close1_open2() except the distribution range. + * This function uses \b global variables. + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa dsfmt_fill_array_close1_open2() and \sa + * dsfmt_gv_fill_array_close1_open2() + */ +inline static void dsfmt_gv_fill_array_open_close(double array[], int size) { + dsfmt_fill_array_open_close(&dsfmt_global_data, array, size); +} + +/** + * This function generates double precision floating point + * pseudorandom numbers which distribute in the range [0, 1) to the + * specified array[] by one call. This function is the same as + * dsfmt_gv_fill_array_close1_open2() except the distribution range. + * This function uses \b global variables. + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa dsfmt_fill_array_close1_open2() \sa + * dsfmt_gv_fill_array_close1_open2() + */ +inline static void dsfmt_gv_fill_array_close_open(double array[], int size) { + dsfmt_fill_array_close_open(&dsfmt_global_data, array, size); +} + +/** + * This function generates double precision floating point + * pseudorandom numbers which distribute in the range (0, 1) to the + * specified array[] by one call. This function is the same as + * dsfmt_gv_fill_array_close1_open2() except the distribution range. + * This function uses \b global variables. + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa dsfmt_fill_array_close1_open2() \sa + * dsfmt_gv_fill_array_close1_open2() + */ +inline static void dsfmt_gv_fill_array_open_open(double array[], int size) { + dsfmt_fill_array_open_open(&dsfmt_global_data, array, size); +} + +/** + * This function initializes the internal state array with a 32-bit + * integer seed. + * @param dsfmt dsfmt state vector. + * @param seed a 32-bit integer used as the seed. + */ +inline static void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) { + dsfmt_chk_init_gen_rand(dsfmt, seed, DSFMT_MEXP); +} + +/** + * This function initializes the internal state array with a 32-bit + * integer seed. This function uses \b global variables. + * @param seed a 32-bit integer used as the seed. + * see also \sa dsfmt_init_gen_rand() + */ +inline static void dsfmt_gv_init_gen_rand(uint32_t seed) { + dsfmt_init_gen_rand(&dsfmt_global_data, seed); +} + +/** + * This function initializes the internal state array, + * with an array of 32-bit integers used as the seeds. + * @param dsfmt dsfmt state vector + * @param init_key the array of 32-bit integers, used as a seed. + * @param key_length the length of init_key. + */ +inline static void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], + int key_length) { + dsfmt_chk_init_by_array(dsfmt, init_key, key_length, DSFMT_MEXP); +} + +/** + * This function initializes the internal state array, + * with an array of 32-bit integers used as the seeds. + * This function uses \b global variables. + * @param init_key the array of 32-bit integers, used as a seed. + * @param key_length the length of init_key. + * see also \sa dsfmt_init_by_array() + */ +inline static void dsfmt_gv_init_by_array(uint32_t init_key[], int key_length) { + dsfmt_init_by_array(&dsfmt_global_data, init_key, key_length); +} + +#if !defined(DSFMT_DO_NOT_USE_OLD_NAMES) +DSFMT_PRE_INLINE const char *get_idstring(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE int get_min_array_size(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void init_gen_rand(uint32_t seed) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void init_by_array(uint32_t init_key[], int key_length) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double genrand_close1_open2(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double genrand_close_open(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double genrand_open_close(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double genrand_open_open(void) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_open_close(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_close_open(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_open_open(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_close1_open2(double array[], int size) + DSFMT_PST_INLINE; + +/** + * This function is just the same as dsfmt_get_idstring(). + * @return id string. + * see also \sa dsfmt_get_idstring() + */ +inline static const char *get_idstring(void) { + return dsfmt_get_idstring(); +} + +/** + * This function is just the same as dsfmt_get_min_array_size(). + * @return minimum size of array used for fill_array functions. + * see also \sa dsfmt_get_min_array_size() + */ +inline static int get_min_array_size(void) { + return dsfmt_get_min_array_size(); +} + +/** + * This function is just the same as dsfmt_gv_init_gen_rand(). + * @param seed a 32-bit integer used as the seed. + * see also \sa dsfmt_gv_init_gen_rand(), \sa dsfmt_init_gen_rand(). + */ +inline static void init_gen_rand(uint32_t seed) { + dsfmt_gv_init_gen_rand(seed); +} + +/** + * This function is just the same as dsfmt_gv_init_by_array(). + * @param init_key the array of 32-bit integers, used as a seed. + * @param key_length the length of init_key. + * see also \sa dsfmt_gv_init_by_array(), \sa dsfmt_init_by_array(). + */ +inline static void init_by_array(uint32_t init_key[], int key_length) { + dsfmt_gv_init_by_array(init_key, key_length); +} + +/** + * This function is just the same as dsfmt_gv_genrand_close1_open2(). + * @return double precision floating point number. + * see also \sa dsfmt_genrand_close1_open2() \sa + * dsfmt_gv_genrand_close1_open2() + */ +inline static double genrand_close1_open2(void) { + return dsfmt_gv_genrand_close1_open2(); +} + +/** + * This function is just the same as dsfmt_gv_genrand_close_open(). + * @return double precision floating point number. + * see also \sa dsfmt_genrand_close_open() \sa + * dsfmt_gv_genrand_close_open() + */ +inline static double genrand_close_open(void) { + return dsfmt_gv_genrand_close_open(); +} + +/** + * This function is just the same as dsfmt_gv_genrand_open_close(). + * @return double precision floating point number. + * see also \sa dsfmt_genrand_open_close() \sa + * dsfmt_gv_genrand_open_close() + */ +inline static double genrand_open_close(void) { + return dsfmt_gv_genrand_open_close(); +} + +/** + * This function is just the same as dsfmt_gv_genrand_open_open(). + * @return double precision floating point number. + * see also \sa dsfmt_genrand_open_open() \sa + * dsfmt_gv_genrand_open_open() + */ +inline static double genrand_open_open(void) { + return dsfmt_gv_genrand_open_open(); +} + +/** + * This function is juset the same as dsfmt_gv_fill_array_open_close(). + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa dsfmt_gv_fill_array_open_close(), \sa + * dsfmt_fill_array_close1_open2(), \sa + * dsfmt_gv_fill_array_close1_open2() + */ +inline static void fill_array_open_close(double array[], int size) { + dsfmt_gv_fill_array_open_close(array, size); +} + +/** + * This function is juset the same as dsfmt_gv_fill_array_close_open(). + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa dsfmt_gv_fill_array_close_open(), \sa + * dsfmt_fill_array_close1_open2(), \sa + * dsfmt_gv_fill_array_close1_open2() + */ +inline static void fill_array_close_open(double array[], int size) { + dsfmt_gv_fill_array_close_open(array, size); +} + +/** + * This function is juset the same as dsfmt_gv_fill_array_open_open(). + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa dsfmt_gv_fill_array_open_open(), \sa + * dsfmt_fill_array_close1_open2(), \sa + * dsfmt_gv_fill_array_close1_open2() + */ +inline static void fill_array_open_open(double array[], int size) { + dsfmt_gv_fill_array_open_open(array, size); +} + +/** + * This function is juset the same as dsfmt_gv_fill_array_close1_open2(). + * @param array an array where pseudorandom numbers are filled + * by this function. + * @param size the number of pseudorandom numbers to be generated. + * see also \sa dsfmt_fill_array_close1_open2(), \sa + * dsfmt_gv_fill_array_close1_open2() + */ +inline static void fill_array_close1_open2(double array[], int size) { + dsfmt_gv_fill_array_close1_open2(array, size); +} +#endif /* DSFMT_DO_NOT_USE_OLD_NAMES */ + +#if defined(__cplusplus) +} +#endif + +#endif /* DSFMT_H */ + + +typedef struct s_dsfmt_state { + dsfmt_t *state; + int has_uint32; + uint32_t uinteger; + + double *buffered_uniforms; + int buffer_loc; +} dsfmt_state; + +static inline double dsfmt_next_double(dsfmt_state *state) { + if (state->buffer_loc < DSFMT_N64) { + double out = state->buffered_uniforms[state->buffer_loc]; + state->buffer_loc++; + return out; + } + dsfmt_fill_array_close_open(state->state, state->buffered_uniforms, DSFMT_N64); + state->buffer_loc = 1; + return state->buffered_uniforms[0]; +} + +static inline uint64_t dsfmt_next64(dsfmt_state *state) { + /* Discard bottom 16 bits */ + double d = dsfmt_next_double(state); + uint64_t out; + uint64_t *tmp; + tmp = (uint64_t *)&d; + out = (*tmp >> 16) << 32; + d = dsfmt_next_double(state); + tmp = (uint64_t *)&d; + out |= (*tmp >> 16) & 0xffffffff; + return out; +} + + +static inline uint32_t dsfmt_next32(dsfmt_state *state) { + /* Discard bottom 16 bits */ + double d = dsfmt_next_double(state); + uint64_t *out = (uint64_t *)&d; + return (uint32_t)((*out >> 16) & 0xffffffff); +} diff --git a/_randomgen/demo.py b/_randomgen/demo.py index b1956831c156..29f440505330 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -1,7 +1,7 @@ import timeit from core_prng import Xoroshiro128, ThreeFry, MT19937, \ - Xorshift1024, PCG64, Philox + Xorshift1024, PCG64, Philox, DSFMT from core_prng.generator import RandomGenerator print(RandomGenerator().random_integer(32)) @@ -62,7 +62,13 @@ print(state) rg.state = state -PRNGS = [MT19937, PCG64, Philox, ThreeFry, Xoroshiro128, Xorshift1024] +rg = RandomGenerator(DSFMT()) +state = rg.state +print(state) +rg.state = state + + +PRNGS = [MT19937, PCG64, Philox, ThreeFry, Xoroshiro128, Xorshift1024, DSFMT] setup = """ from core_prng import {module} diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 663c0056c7e0..d1dc482b882f 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -1,3 +1,5 @@ +import struct +import sys import os from os.path import join @@ -10,6 +12,8 @@ Cython.Compiler.Options.annotate = True + +USE_SSE2 = True if not '--no-sse2' in sys.argv else False MOD_DIR = './core_prng' DEBUG = False @@ -24,6 +28,17 @@ EXTRA_LINK_ARGS += ['-debug'] EXTRA_COMPILE_ARGS = ["-Zi", "/Od"] +if USE_SSE2: + if os.name == 'nt': + EXTRA_COMPILE_ARGS += ['/wd4146', '/GL'] + if struct.calcsize('P') < 8: + EXTRA_COMPILE_ARGS += ['/arch:SSE2'] + else: + EXTRA_COMPILE_ARGS += ['-msse2'] +DSFMT_DEFS = [('DSFMT_MEXP', '19937')] +if USE_SSE2: + DSFMT_DEFS += [('HAVE_SSE2', '1')] + extensions = [Extension('core_prng.entropy', sources=[join(MOD_DIR, 'entropy.pyx'), join(MOD_DIR, 'src', 'entropy', 'entropy.c')], @@ -32,6 +47,15 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), + Extension("core_prng.dsfmt", + ["core_prng/dsfmt.pyx", + join(MOD_DIR, 'src', 'dsfmt', 'dSFMT.c')], + include_dirs=[np.get_include(), + join(MOD_DIR, 'src', 'dsfmt')], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + define_macros=DSFMT_DEFS, + ), Extension("core_prng.mt19937", ["core_prng/mt19937.pyx", join(MOD_DIR, 'src', 'mt19937', 'mt19937.c')], From dd2a11361e43f3b2893d23d79df5213f0d3fbb33 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Mar 2018 15:44:41 +0000 Subject: [PATCH 028/279] BUG: Fix names in dsfmt Fix case issues in dsfmt --- _randomgen/core_prng/src/dsfmt/{dsfmt-jump.c => dSFMT-jump.c} | 0 _randomgen/core_prng/src/dsfmt/{dsfmt-jump.h => dSFMT-jump.h} | 0 _randomgen/core_prng/src/dsfmt/{dsfmt.c => dSFMT.c} | 0 _randomgen/core_prng/src/dsfmt/{dsfmt.h => dSFMT.h} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename _randomgen/core_prng/src/dsfmt/{dsfmt-jump.c => dSFMT-jump.c} (100%) rename _randomgen/core_prng/src/dsfmt/{dsfmt-jump.h => dSFMT-jump.h} (100%) rename _randomgen/core_prng/src/dsfmt/{dsfmt.c => dSFMT.c} (100%) rename _randomgen/core_prng/src/dsfmt/{dsfmt.h => dSFMT.h} (100%) diff --git a/_randomgen/core_prng/src/dsfmt/dsfmt-jump.c b/_randomgen/core_prng/src/dsfmt/dSFMT-jump.c similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dsfmt-jump.c rename to _randomgen/core_prng/src/dsfmt/dSFMT-jump.c diff --git a/_randomgen/core_prng/src/dsfmt/dsfmt-jump.h b/_randomgen/core_prng/src/dsfmt/dSFMT-jump.h similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dsfmt-jump.h rename to _randomgen/core_prng/src/dsfmt/dSFMT-jump.h diff --git a/_randomgen/core_prng/src/dsfmt/dsfmt.c b/_randomgen/core_prng/src/dsfmt/dSFMT.c similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dsfmt.c rename to _randomgen/core_prng/src/dsfmt/dSFMT.c diff --git a/_randomgen/core_prng/src/dsfmt/dsfmt.h b/_randomgen/core_prng/src/dsfmt/dSFMT.h similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dsfmt.h rename to _randomgen/core_prng/src/dsfmt/dSFMT.h From fb68ef2acbf84d0787d0cb883107c1f6be197c62 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Mar 2018 15:51:45 +0000 Subject: [PATCH 029/279] CLN: Fix seeding in dsfmt Fix seeding to respect constraints --- _randomgen/core_prng/dsfmt.pyx | 46 ++++++++++++++++++++++ _randomgen/core_prng/src/mt19937/mt19937.c | 2 - 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index 3930c3d7f592..e43d05a75af9 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -1,3 +1,4 @@ +import operator from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New @@ -143,6 +144,51 @@ cdef class DSFMT: for i in range(cnt): self._prng.next_uint64(self._prng.state) + + def seed(self, seed=None): + """ + seed(seed=None, stream=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + """ + cdef np.ndarray obj + try: + if seed is None: + try: + seed = random_entropy(1) + except RuntimeError: + seed = random_entropy(1, 'fallback') + dsfmt_init_gen_rand(self.rng_state.state, seed) + else: + if hasattr(seed, 'squeeze'): + seed = seed.squeeze() + idx = operator.index(seed) + if idx > int(2**32 - 1) or idx < 0: + raise ValueError("Seed must be between 0 and 2**32 - 1") + dsfmt_init_gen_rand(self.rng_state.state, seed) + except TypeError: + obj = np.asarray(seed).astype(np.int64, casting='safe').ravel() + if ((obj > int(2**32 - 1)) | (obj < 0)).any(): + raise ValueError("Seed must be between 0 and 2**32 - 1") + obj = obj.astype(np.uint32, casting='unsafe', order='C') + dsfmt_init_by_array(self.rng_state.state, + obj.data, + np.PyArray_DIM(obj, 0)) + def seed(self, seed=None): """ seed(seed=None, stream=None) diff --git a/_randomgen/core_prng/src/mt19937/mt19937.c b/_randomgen/core_prng/src/mt19937/mt19937.c index 06ce7a16f4e8..699efd21d08a 100644 --- a/_randomgen/core_prng/src/mt19937/mt19937.c +++ b/_randomgen/core_prng/src/mt19937/mt19937.c @@ -1,7 +1,5 @@ #include "mt19937.h" -extern inline uint32_t mt19937_random(mt19937_state *state); - void mt19937_seed(mt19937_state *state, uint32_t seed) { int pos; From 263d67b01cce8b6d947ba5648b45d4996bcac655 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Mar 2018 18:03:32 +0000 Subject: [PATCH 030/279] ENH: Add out, ziggurat for exponential Add out to fill existing arrays Add ziggurat for exponential --- _randomgen/TODO.md | 10 +-- _randomgen/core_prng/common.pxd | 10 ++- _randomgen/core_prng/common.pyx | 46 +++++++++-- _randomgen/core_prng/generator.pyx | 57 +++++++++----- _randomgen/core_prng/philox.pyx | 76 +++++++++++-------- .../src/distributions/distributions.c | 42 +++++++++- .../src/distributions/distributions.h | 4 +- _randomgen/core_prng/threefry.pyx | 74 +++++++++++------- 8 files changed, 224 insertions(+), 95 deletions(-) diff --git a/_randomgen/TODO.md b/_randomgen/TODO.md index 2be06b8ec4bf..93d6ca0536b4 100644 --- a/_randomgen/TODO.md +++ b/_randomgen/TODO.md @@ -1,28 +1,28 @@ # TODO -2. Add dSFMT 6. Port over 0 parameter distributions - * standard exponential ziggurat float * standard normal ziggurat * standard normal ziggurat float -8. Restore ability to use `out` in core distributions -12. Key/Counter for ThreeFry 13. Simplify state ## Done 1. Add PCG64 +2. Add dSFMT 3. Add xorshift2014 4. Augment state to include has_gauss and gauss 5. Augment state to have binomial structure 6. Port over 0 parameter distributions * standard exponential ziggurat + * standard exponential ziggurat float * standard exponential float * standard normal * standard normal float * standard gamma - Not implement: This is a 1 param * standard gamma float - Not implement: This is a 1 param 7. Remove SplitMix64 as an external generator +8. Restore ability to use `out` in core distributions 9. Add correct carry for ThreeFry to allow full set of counters. Important when implemeting jump 10. Seed/Inc for PCG64 11. Advance/Jump for PCG64 -0. NOT IMPLEMENTABLE due to limits on inheritance in Cython: Use inheritance to simplify CorePRNG structure. The natural base is +12. Key/Counter for ThreeFry +0. **NOT IMPLEMENTABLE** due to limits on inheritance in Cython: Use inheritance to simplify CorePRNG structure. The natural base is xoroshiro128. diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index c8b469cc52bc..c8b15b77d409 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -1,4 +1,6 @@ from libc.stdint cimport uint32_t, uint64_t +import numpy as np +cimport numpy as np cdef extern from "src/distributions/distributions.h": ctypedef double (*random_double_0)(void *st) nogil @@ -42,8 +44,10 @@ cdef extern from "src/distributions/distributions.h": cdef inline double uint64_to_double(uint64_t rnd) nogil: return (rnd >> 11) * (1.0 / 9007199254740992.0) -cdef object double_fill(void *func, void *state, object size, object lock) +cdef object double_fill(void *func, void *state, object size, object lock, object out) -cdef object float_fill(void *func, void *state, object size, object lock) +cdef object float_fill(void *func, void *state, object size, object lock, object out) -cdef object float_fill_from_double(void *func, void *state, object size, object lock) \ No newline at end of file +cdef object float_fill_from_double(void *func, void *state, object size, object lock, object out) + +cdef np.ndarray int_to_array(object value, object name, object bits) \ No newline at end of file diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index b6e832c49219..0d18a8fc8664 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -4,6 +4,27 @@ from common cimport * np.import_array() +cdef np.ndarray int_to_array(object value, object name, object bits): + len = bits // 64 + value = np.asarray(value) + if value.shape == (): + value = int(value) + upper = int(2)**int(bits) + if value < 0 or value >= upper: + raise ValueError('{name} must be positive and ' + 'less than 2**{bits}.'.format(name=name, bits=bits)) + out = np.empty(len, dtype=np.uint64) + for i in range(len): + out[i] = value % 2**64 + value >>= 64 + else: + out = value.astype(np.uint64) + if out.shape != (len,): + raise ValueError('{name} must have {len} elements when using ' + 'array form'.format(name=name, len=len)) + return out + + cdef check_output(object out, object dtype, object size): if out is None: return @@ -19,7 +40,7 @@ cdef check_output(object out, object dtype, object size): raise ValueError('size and out cannot be simultaneously used') -cdef object double_fill(void *func, void *state, object size, object lock): +cdef object double_fill(void *func, void *state, object size, object lock, object out): cdef random_double_0 random_func = (func) cdef double *out_array_data cdef np.ndarray out_array @@ -29,7 +50,11 @@ cdef object double_fill(void *func, void *state, object size, object lock): with lock: return random_func(state) - out_array = np.empty(size, np.double) + if out is not None: + check_output(out, np.float64, size) + out_array = out + else: + out_array = np.empty(size, np.double) n = np.PyArray_SIZE(out_array) out_array_data = np.PyArray_DATA(out_array) @@ -38,7 +63,7 @@ cdef object double_fill(void *func, void *state, object size, object lock): out_array_data[i] = random_func(state) return out_array -cdef object float_fill(void *func, void *state, object size, object lock): +cdef object float_fill(void *func, void *state, object size, object lock, object out): cdef random_float_0 random_func = (func) cdef float *out_array_data cdef np.ndarray out_array @@ -48,7 +73,11 @@ cdef object float_fill(void *func, void *state, object size, object lock): with lock: return random_func(state) - out_array = np.empty(size, np.float32) + if out is not None: + check_output(out, np.float32, size) + out_array = out + else: + out_array = np.empty(size, np.float32) n = np.PyArray_SIZE(out_array) out_array_data = np.PyArray_DATA(out_array) @@ -57,7 +86,7 @@ cdef object float_fill(void *func, void *state, object size, object lock): out_array_data[i] = random_func(state) return out_array -cdef object float_fill_from_double(void *func, void *state, object size, object lock): +cdef object float_fill_from_double(void *func, void *state, object size, object lock, object out): cdef random_double_0 random_func = (func) cdef float *out_array_data cdef np.ndarray out_array @@ -67,7 +96,11 @@ cdef object float_fill_from_double(void *func, void *state, object size, object with lock: return random_func(state) - out_array = np.empty(size, np.float32) + if out is not None: + check_output(out, np.float32, size) + out_array = out + else: + out_array = np.empty(size, np.float32) n = np.PyArray_SIZE(out_array) out_array_data = np.PyArray_DATA(out_array) @@ -75,3 +108,4 @@ cdef object float_fill_from_double(void *func, void *state, object size, object for i in range(n): out_array_data[i] = random_func(state) return out_array + diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 1447e44783d1..ab9a57b5ad02 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -22,12 +22,14 @@ np.import_array() cdef extern from "src/distributions/distributions.h": double random_double(prng_t *prng_state) nogil - float random_float(prng_t *prng_state) nogil - uint32_t random_uint32(prng_t *prng_state) nogil + double random_standard_exponential_zig_double(prng_t *prng_state) nogil + double random_gauss(prng_t *prng_state) nogil double random_standard_exponential(prng_t *prng_state) nogil + float random_standard_exponential_float(prng_t *prng_state) nogil - double random_gauss(prng_t *prng_state) - float random_gauss_float(prng_t *prng_state) + float random_float(prng_t *prng_state) nogil + float random_gauss_float(prng_t *prng_state) nogil + float random_standard_exponential_zig_float(prng_t *prng_state) nogil cdef class RandomGenerator: """ @@ -98,7 +100,7 @@ cdef class RandomGenerator: if bits == 64: return self._prng.next_uint64(self._prng.state) elif bits == 32: - return random_uint32(self._prng) + return self._prng.next_uint32(self._prng.state) else: raise ValueError('bits must be 32 or 64') @@ -110,7 +112,7 @@ cdef class RandomGenerator: else: raise ValueError('bits must be 32 or 64') - def random_sample(self, size=None, dtype=np.float64): + def random_sample(self, size=None, dtype=np.float64, out=None): """ random_sample(size=None, dtype='d', out=None) @@ -132,6 +134,10 @@ cdef class RandomGenerator: Desired dtype of the result, either 'd' (or 'float64') or 'f' (or 'float32'). All dtypes are determined by their name. The default value is 'd'. + out : ndarray, optional + Alternative output array in which to place the result. If size is not None, + it must have the same shape as the provided size and must match the type of + the output values. Returns ------- @@ -158,15 +164,15 @@ cdef class RandomGenerator: cdef double temp key = np.dtype(dtype).name if key == 'float64': - return double_fill(&random_double, self._prng, size, self.lock) + return double_fill(&random_double, self._prng, size, self.lock, out) elif key == 'float32': - return float_fill(&random_float, self._prng, size, self.lock) + return float_fill(&random_float, self._prng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for random_sample' % key) - def standard_exponential(self, size=None, dtype=np.float64): + def standard_exponential(self, size=None, dtype=np.float64, method=u'zig', out=None): """ - standard_exponential(size=None, dtype='d', method='inv', out=None) + standard_exponential(size=None, dtype='d', method='zig', out=None) Draw samples from the standard exponential distribution. @@ -183,6 +189,13 @@ cdef class RandomGenerator: Desired dtype of the result, either 'd' (or 'float64') or 'f' (or 'float32'). All dtypes are determined by their name. The default value is 'd'. + method : str, optional + Either 'inv' or 'zig'. 'inv' uses the default inverse CDF method. + 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. + out : ndarray, optional + Alternative output array in which to place the result. If size is not None, + it must have the same shape as the provided size and must match the type of + the output values. Returns ------- @@ -197,17 +210,23 @@ cdef class RandomGenerator: """ key = np.dtype(dtype).name if key == 'float64': - return double_fill(&random_standard_exponential, self._prng, size, self.lock) + if method == u'zig': + return double_fill(&random_standard_exponential_zig_double, self._prng, size, self.lock, out) + else: + return double_fill(&random_standard_exponential, self._prng, size, self.lock, out) elif key == 'float32': - return float_fill(&random_standard_exponential_float, self._prng, size, self.lock) + if method == u'zig': + return float_fill(&random_standard_exponential_zig_float, self._prng, size, self.lock, out) + else: + return float_fill(&random_standard_exponential_float, self._prng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for standard_exponential' % key) # Complicated, continuous distributions: - def standard_normal(self, size=None, dtype=np.float64, method='bm'): + def standard_normal(self, size=None, dtype=np.float64, method=u'zig', out=None): """ - standard_normal(size=None, dtype='d', method='bm', out=None) + standard_normal(size=None, dtype='d', method='zig', out=None) Draw samples from a standard Normal distribution (mean=0, stdev=1). @@ -222,7 +241,7 @@ cdef class RandomGenerator: (or 'float32'). All dtypes are determined by their name. The default value is 'd'. method : str, optional - Either 'bm' or 'zig'. 'bm' uses the default Box-Muller transformations + Either 'bm' or 'zig'. 'bm' uses the Box-Muller transformations method. 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. out : ndarray, optional Alternative output array in which to place the result. If size is not None, @@ -251,14 +270,14 @@ cdef class RandomGenerator: if key == 'float64': if method == u'zig': raise NotImplementedError - #return double_fill(&self.rng_state, &random_gauss_zig_double_fill, size, self.lock, out) + #return double_fill(&random_gauss_zig_double, self._prng, size, self.lock, out) else: - return double_fill(&random_gauss, self._prng, size, self.lock) + return double_fill(&random_gauss, self._prng, size, self.lock, out) elif key == 'float32': if method == u'zig': raise NotImplementedError - #return float_fill(&self.rng_state, &random_gauss_zig_float_fill, size, self.lock, out) + #return float_fill(&random_gauss_zig_float, self._prng, size, self.lock, out) else: - return float_fill(&random_gauss_float, self._prng, size, self.lock) + return float_fill(&random_gauss_float, self._prng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for standard_normal' % key) diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx index 111d702be680..474bc752ebf0 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/core_prng/philox.pyx @@ -2,7 +2,6 @@ from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New import numpy as np -cimport numpy as np from common cimport * from core_prng.entropy import random_entropy @@ -11,7 +10,7 @@ cimport entropy np.import_array() -cdef extern from "src/philox/philox.h": +cdef extern from 'src/philox/philox.h': struct s_r123array2x64: uint64_t v[2] @@ -67,7 +66,7 @@ cdef class Philox: cdef prng_t *_prng cdef public object _prng_capsule - def __init__(self, seed=None): + def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(philox_state)) self.rng_state.ctr = malloc( sizeof(philox4x64_ctr_t)) @@ -75,14 +74,14 @@ cdef class Philox: sizeof(philox4x64_key_t)) self._prng = malloc(sizeof(prng_t)) self._prng.binomial = malloc(sizeof(binomial_t)) - self.seed(seed) + self.seed(seed, counter, key) self._prng.state = self.rng_state self._prng.next_uint64 = &philox_uint64 self._prng.next_uint32 = &philox_uint32 self._prng.next_double = &philox_double - cdef const char *name = "CorePRNG" + cdef const char *name = 'CorePRNG' self._prng_capsule = PyCapsule_New( self._prng, name, NULL) # Pickling support: @@ -141,9 +140,9 @@ cdef class Philox: for i in range(cnt): self._prng.next_uint64(self._prng.state) - def seed(self, seed=None): + def seed(self, seed=None, counter=None, key=None): """ - seed(seed=None, stream=None) + seed(seed=None, counter=None, key=None) Seed the generator. @@ -155,26 +154,46 @@ cdef class Philox: ---------- seed : int, optional Seed for ``RandomState``. + counter : {int array}, optional + Positive integer less than 2**256 containing the counter position + or a 4 element array of uint64 containing the counter + key : {int, array}, options + Positive integer less than 2**128 containing the key + or a 2 element array of uint64 containing the key Raises ------ ValueError - If seed values are out of range for the PRNG. + If values are out of range for the PRNG. + + Notes + ----- + The two representation of the counter and key are related through + array[i] = (value // 2**(64*i)) % 2**64. """ - ub = 2 ** 64 - if seed is None: - try: - state = random_entropy(4) - except RuntimeError: - state = random_entropy(4, 'fallback') - state = state.view(np.uint64) + if seed is not None and key is not None: + raise ValueError('seed and key cannot be both used') + ub = 2 ** 64 + if key is None: + if seed is None: + try: + state = random_entropy(4) + except RuntimeError: + state = random_entropy(4, 'fallback') + state = state.view(np.uint64) + else: + state = entropy.seed_by_array(seed, 2) + for i in range(2): + self.rng_state.key.v[i] = state[i] else: - state = entropy.seed_by_array(seed, 2) - # TODO: Need to be able to set the key and counter directly + key = int_to_array(key, 'key', 128) + for i in range(2): + self.rng_state.key.v[i] = key[i] + counter = 0 if counter is None else counter + counter = int_to_array(counter, 'counter', 256) for i in range(4): - self.rng_state.ctr.v[i] = 0 - self.rng_state.key.v[0] = state[0] - self.rng_state.key.v[1] = state[1] + self.rng_state.ctr.v[i] = counter[i] + self._reset_state_variables() @property @@ -189,7 +208,7 @@ cdef class Philox: if i < 2: key[i] = self.rng_state.key.v[i] - state = {'ctr': ctr, 'key': key} + state = {'counter': ctr, 'key': key} return {'prng': self.__class__.__name__, 'state': state, 'buffer': buffer, @@ -206,7 +225,7 @@ cdef class Philox: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) for i in range(4): - self.rng_state.ctr.v[i] = value['state']['ctr'][i] + self.rng_state.ctr.v[i] = value['state']['counter'][i] self.rng_state.buffer[i] = value['buffer'][i] if i < 2: self.rng_state.key.v[i] = value['state']['key'][i] @@ -216,17 +235,12 @@ cdef class Philox: def jump(self): """Jump the state as-if 2**128 draws have been made""" - philox_jump(self.rng_state) - return self + return self.advance(2**128) def advance(self, step): """Advance the state as-if a specific number of draws have been made""" - cdef np.ndarray step_a = np.zeros(4, dtype=np.uint64) - if step >= 2 ** 256 or step < 0: - raise ValueError('step must be between 0 and 2**256-1') + cdef np.ndarray step_a + step_a = int_to_array(step, 'step', 256) loc = 0 - while step > 0: - step_a[loc] = step % 2 ** 64 - step >>= 64 - loc += 1 philox_advance( step_a.data, self.rng_state) + return self diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 6c19ad020581..7a348d5325e3 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -121,4 +121,44 @@ double standard_exponential_zig_double(prng_t *prng_state) double random_standard_exponential_zig_double(prng_t *prng_state) { return standard_exponential_zig_double(prng_state); -} \ No newline at end of file +} + +static NPY_INLINE float standard_exponential_zig_float(prng_t *prng_state); + +static float standard_exponential_zig_float_unlikely(prng_t *prng_state, uint8_t idx, float x) +{ + if (idx == 0) + { + return ziggurat_exp_r_f - logf(random_float(prng_state)); + } + else if ((fe_float[idx - 1] - fe_float[idx]) * random_float(prng_state) + fe_float[idx] < expf(-x)) + { + return x; + } + else + { + return standard_exponential_zig_float(prng_state); + } +} + +static NPY_INLINE float standard_exponential_zig_float(prng_t *prng_state) +{ + uint32_t ri; + uint8_t idx; + float x; + ri = prng_state->next_uint32(prng_state->state); + ri >>= 1; + idx = ri & 0xFF; + ri >>= 8; + x = ri * we_float[idx]; + if (ri < ke_float[idx]) + { + return x; // 98.9% of the time we return here 1st try + } + return standard_exponential_zig_float_unlikely(prng_state, idx, x); +} + +float random_standard_exponential_zig_float(prng_t *prng_state) +{ + return standard_exponential_zig_float(prng_state); +} diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index 757029074285..028557ae3d62 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -67,4 +67,6 @@ double random_gauss(prng_t *prng_state); float random_gauss_float(prng_t *prng_state); -double random_standard_exponential_zig_double(prng_t *prng_state); \ No newline at end of file +double random_standard_exponential_zig_double(prng_t *prng_state); + +float random_standard_exponential_zig_float(prng_t *prng_state); \ No newline at end of file diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index 3c669a439ca2..dfcc6e41da9d 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -2,7 +2,6 @@ from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New import numpy as np -cimport numpy as np from common cimport * from core_prng.entropy import random_entropy @@ -11,7 +10,7 @@ cimport entropy np.import_array() -cdef extern from "src/threefry/threefry.h": +cdef extern from 'src/threefry/threefry.h': struct s_r123array4x64: uint64_t v[4] @@ -63,20 +62,20 @@ cdef class ThreeFry: cdef prng_t *_prng cdef public object _prng_capsule - def __init__(self, seed=None): + def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(threefry_state)) self.rng_state.ctr = malloc(sizeof(threefry4x64_ctr_t)) self.rng_state.key = malloc(sizeof(threefry4x64_key_t)) self._prng = malloc(sizeof(prng_t)) self._prng.binomial = malloc(sizeof(binomial_t)) - self.seed(seed) + self.seed(seed, counter, key) self._prng.state = self.rng_state self._prng.next_uint64 = &threefry_uint64 self._prng.next_uint32 = &threefry_uint32 self._prng.next_double = &threefry_double - cdef const char *name = "CorePRNG" + cdef const char *name = 'CorePRNG' self._prng_capsule = PyCapsule_New(self._prng, name, NULL) # Pickling support: @@ -135,9 +134,9 @@ cdef class ThreeFry: for i in range(cnt): self._prng.next_uint64(self._prng.state) - def seed(self, seed=None): + def seed(self, seed=None, counter=None, key=None): """ - seed(seed=None, stream=None) + seed(seed=None, counter=None, key=None) Seed the generator. @@ -149,25 +148,47 @@ cdef class ThreeFry: ---------- seed : int, optional Seed for ``RandomState``. + counter : {int array}, optional + Positive integer less than 2**256 containing the counter position + or a 4 element array of uint64 containing the counter + key : {int, array}, options + Positive integer less than 2**256 containing the key + or a 4 element array of uint64 containing the key Raises ------ ValueError - If seed values are out of range for the PRNG. + If values are out of range for the PRNG. + + Notes + ----- + The two representation of the counter and key are related through + array[i] = (value // 2**(64*i)) % 2**64. """ + if seed is not None and key is not None: + raise ValueError('seed and key cannot be both used') ub = 2 ** 64 - if seed is None: - try: - state = random_entropy(8) - except RuntimeError: - state = random_entropy(8, 'fallback') - state = state.view(np.uint64) + if key is None: + if seed is None: + try: + state = random_entropy(8) + except RuntimeError: + state = random_entropy(8, 'fallback') + state = state.view(np.uint64) + else: + state = entropy.seed_by_array(seed, 4) + for i in range(4): + self.rng_state.key.v[i] = state[i] else: - state = entropy.seed_by_array(seed, 4) - # TODO: Need to be able to set the key and counter directly + key = int_to_array(key, 'key', 256) + for i in range(4): + self.rng_state.key.v[i] = key[i] + + counter = 0 if counter is None else counter + counter = int_to_array(counter, 'counter', 256) for i in range(4): - self.rng_state.ctr.v[i] = 0 - self.rng_state.key.v[i] = state[i] + self.rng_state.ctr.v[i] = counter[i] + self._reset_state_variables() @property @@ -180,7 +201,7 @@ cdef class ThreeFry: ctr[i] = self.rng_state.ctr.v[i] key[i] = self.rng_state.key.v[i] buffer[i] = self.rng_state.buffer[i] - state = {'ctr':ctr,'key':key} + state = {'counter':ctr,'key':key} return {'prng': self.__class__.__name__, 'state': state, 'buffer': buffer, @@ -197,7 +218,7 @@ cdef class ThreeFry: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) for i in range(4): - self.rng_state.ctr.v[i] = value['state']['ctr'][i] + self.rng_state.ctr.v[i] = value['state']['counter'][i] self.rng_state.key.v[i] = value['state']['key'][i] self.rng_state.buffer[i] = value['buffer'][i] self.rng_state.has_uint32 = value['has_uint32'] @@ -206,17 +227,12 @@ cdef class ThreeFry: def jump(self): """Jump the state as-if 2**128 draws have been made""" - threefry_jump(self.rng_state) - return self + return self.advance(2**128) def advance(self, step): """Advance the state as-if a specific number of draws have been made""" - cdef np.ndarray step_a = np.zeros(4,dtype=np.uint64) - if step >= 2**256 or step < 0: - raise ValueError('step must be between 0 and 2**256-1') + cdef np.ndarray step_a + step_a = int_to_array(step, 'step', 256) loc = 0 - while step > 0: - step_a[loc] = step % 2**64 - step >>= 64 - loc += 1 threefry_advance(step_a.data, self.rng_state) + return self From 4be9914e4c31ec0a55113d7472ad80b6f054c267 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Mar 2018 20:13:05 +0000 Subject: [PATCH 031/279] REF: Refactor distributions Simplify naming schame Add ziggurate gauss --- _randomgen/TODO.md | 5 +- _randomgen/core_prng/generator.pyx | 36 ++--- .../src/distributions/distributions.c | 131 ++++++++++++++---- .../src/distributions/distributions.h | 19 ++- _randomgen/setup.py | 9 +- 5 files changed, 136 insertions(+), 64 deletions(-) diff --git a/_randomgen/TODO.md b/_randomgen/TODO.md index 93d6ca0536b4..ed2697d9e826 100644 --- a/_randomgen/TODO.md +++ b/_randomgen/TODO.md @@ -1,7 +1,4 @@ # TODO -6. Port over 0 parameter distributions - * standard normal ziggurat - * standard normal ziggurat float 13. Simplify state ## Done @@ -11,6 +8,8 @@ 4. Augment state to include has_gauss and gauss 5. Augment state to have binomial structure 6. Port over 0 parameter distributions + * standard normal ziggurat + * standard normal ziggurat float * standard exponential ziggurat * standard exponential ziggurat float * standard exponential float diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index ab9a57b5ad02..44a717f67fbd 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -21,15 +21,17 @@ import core_prng.pickle np.import_array() cdef extern from "src/distributions/distributions.h": - double random_double(prng_t *prng_state) nogil - double random_standard_exponential_zig_double(prng_t *prng_state) nogil - double random_gauss(prng_t *prng_state) nogil + double random_sample(prng_t *prng_state) nogil double random_standard_exponential(prng_t *prng_state) nogil + double random_standard_exponential_zig(prng_t *prng_state) nogil + double random_gauss(prng_t *prng_state) nogil + double random_gauss_zig(prng_t* prng_state) nogil - float random_standard_exponential_float(prng_t *prng_state) nogil - float random_float(prng_t *prng_state) nogil - float random_gauss_float(prng_t *prng_state) nogil - float random_standard_exponential_zig_float(prng_t *prng_state) nogil + float random_sample_f(prng_t *prng_state) nogil + float random_standard_exponential_f(prng_t *prng_state) nogil + float random_standard_exponential_zig_f(prng_t *prng_state) nogil + float random_gauss_f(prng_t *prng_state) nogil + float random_gauss_zig_f(prng_t* prng_state) nogil cdef class RandomGenerator: """ @@ -108,7 +110,7 @@ cdef class RandomGenerator: if bits == 64: return self._prng.next_double(self._prng.state) elif bits == 32: - return random_float(self._prng) + return random_sample_f(self._prng) else: raise ValueError('bits must be 32 or 64') @@ -164,9 +166,9 @@ cdef class RandomGenerator: cdef double temp key = np.dtype(dtype).name if key == 'float64': - return double_fill(&random_double, self._prng, size, self.lock, out) + return double_fill(&random_sample, self._prng, size, self.lock, out) elif key == 'float32': - return float_fill(&random_float, self._prng, size, self.lock, out) + return float_fill(&random_sample_f, self._prng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for random_sample' % key) @@ -211,14 +213,14 @@ cdef class RandomGenerator: key = np.dtype(dtype).name if key == 'float64': if method == u'zig': - return double_fill(&random_standard_exponential_zig_double, self._prng, size, self.lock, out) + return double_fill(&random_standard_exponential_zig, self._prng, size, self.lock, out) else: return double_fill(&random_standard_exponential, self._prng, size, self.lock, out) elif key == 'float32': if method == u'zig': - return float_fill(&random_standard_exponential_zig_float, self._prng, size, self.lock, out) + return float_fill(&random_standard_exponential_zig_f, self._prng, size, self.lock, out) else: - return float_fill(&random_standard_exponential_float, self._prng, size, self.lock, out) + return float_fill(&random_standard_exponential_f, self._prng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for standard_exponential' % key) @@ -269,15 +271,13 @@ cdef class RandomGenerator: key = np.dtype(dtype).name if key == 'float64': if method == u'zig': - raise NotImplementedError - #return double_fill(&random_gauss_zig_double, self._prng, size, self.lock, out) + return double_fill(&random_gauss_zig, self._prng, size, self.lock, out) else: return double_fill(&random_gauss, self._prng, size, self.lock, out) elif key == 'float32': if method == u'zig': - raise NotImplementedError - #return float_fill(&random_gauss_zig_float, self._prng, size, self.lock, out) + return float_fill(&random_gauss_zig_f, self._prng, size, self.lock, out) else: - return float_fill(&random_gauss_float, self._prng, size, self.lock, out) + return float_fill(&random_gauss_f, self._prng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for standard_normal' % key) diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 7a348d5325e3..aebbbfca1973 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -2,8 +2,7 @@ #include "ziggurat.h" #include "ziggurat_constants.h" -static NPY_INLINE float uint32_to_float(prng_t *prng_state) -{ +static NPY_INLINE float next_float(prng_t *prng_state){ return (prng_state->next_uint32(prng_state->state) >> 9) * (1.0f / 8388608.0f); } @@ -11,11 +10,11 @@ uint32_t random_uint32(prng_t *prng_state) { return prng_state->next_uint32(prng_state->state); } -float random_float(prng_t *prng_state) { - return uint32_to_float(prng_state); +float random_sample_f(prng_t *prng_state) { + return next_float(prng_state); } -double random_double(prng_t *prng_state) { +double random_sample(prng_t *prng_state) { return prng_state->next_double(prng_state->state); } @@ -23,8 +22,8 @@ double random_standard_exponential(prng_t *prng_state) { return -log(1.0 - prng_state->next_double(prng_state->state)); } -float random_standard_exponential_float(prng_t *prng_state) { - return -logf(1.0f - uint32_to_float(prng_state)); +float random_standard_exponential_f(prng_t *prng_state) { + return -logf(1.0f - next_float(prng_state)); } double random_gauss(prng_t *prng_state) @@ -55,7 +54,7 @@ double random_gauss(prng_t *prng_state) } } -float random_gauss_float(prng_t *prng_state) +float random_gauss_f(prng_t *prng_state) { if (prng_state->has_gauss_f) { @@ -69,8 +68,8 @@ float random_gauss_float(prng_t *prng_state) do { - x1 = 2.0f * uint32_to_float(prng_state) - 1.0f; - x2 = 2.0f * uint32_to_float(prng_state) - 1.0f; + x1 = 2.0f * next_float(prng_state) - 1.0f; + x2 = 2.0f * next_float(prng_state) - 1.0f; r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); @@ -83,25 +82,25 @@ float random_gauss_float(prng_t *prng_state) } } -double standard_exponential_zig_double(prng_t *prng_state); +double standard_exponential_zig(prng_t *prng_state); -static double standard_exponential_zig_double_unlikely(prng_t *prng_state, uint8_t idx, double x) +static double standard_exponential_zig_unlikely(prng_t *prng_state, uint8_t idx, double x) { if (idx == 0) { - return ziggurat_exp_r - log(random_double(prng_state)); + return ziggurat_exp_r - log(prng_state->next_double(prng_state->state)); } - else if ((fe_double[idx - 1] - fe_double[idx]) * random_double(prng_state) + fe_double[idx] < exp(-x)) + else if ((fe_double[idx - 1] - fe_double[idx]) * prng_state->next_double(prng_state->state) + fe_double[idx] < exp(-x)) { return x; } else { - return standard_exponential_zig_double(prng_state); + return standard_exponential_zig(prng_state); } } -double standard_exponential_zig_double(prng_t *prng_state) +double standard_exponential_zig(prng_t *prng_state) { uint64_t ri; uint8_t idx; @@ -115,33 +114,33 @@ double standard_exponential_zig_double(prng_t *prng_state) { return x; // 98.9% of the time we return here 1st try } - return standard_exponential_zig_double_unlikely(prng_state, idx, x); + return standard_exponential_zig_unlikely(prng_state, idx, x); } -double random_standard_exponential_zig_double(prng_t *prng_state) +double random_standard_exponential_zig(prng_t *prng_state) { - return standard_exponential_zig_double(prng_state); + return standard_exponential_zig(prng_state); } -static NPY_INLINE float standard_exponential_zig_float(prng_t *prng_state); +static NPY_INLINE float standard_exponential_zig_f(prng_t *prng_state); -static float standard_exponential_zig_float_unlikely(prng_t *prng_state, uint8_t idx, float x) +static float standard_exponential_zig_unlikely_f(prng_t *prng_state, uint8_t idx, float x) { if (idx == 0) { - return ziggurat_exp_r_f - logf(random_float(prng_state)); + return ziggurat_exp_r_f - logf(next_float(prng_state)); } - else if ((fe_float[idx - 1] - fe_float[idx]) * random_float(prng_state) + fe_float[idx] < expf(-x)) + else if ((fe_float[idx - 1] - fe_float[idx]) * next_float(prng_state) + fe_float[idx] < expf(-x)) { return x; } else { - return standard_exponential_zig_float(prng_state); + return standard_exponential_zig_f(prng_state); } } -static NPY_INLINE float standard_exponential_zig_float(prng_t *prng_state) +static NPY_INLINE float standard_exponential_zig_f(prng_t *prng_state) { uint32_t ri; uint8_t idx; @@ -155,10 +154,86 @@ static NPY_INLINE float standard_exponential_zig_float(prng_t *prng_state) { return x; // 98.9% of the time we return here 1st try } - return standard_exponential_zig_float_unlikely(prng_state, idx, x); + return standard_exponential_zig_unlikely_f(prng_state, idx, x); } -float random_standard_exponential_zig_float(prng_t *prng_state) +float random_standard_exponential_zig_f(prng_t *prng_state) { - return standard_exponential_zig_float(prng_state); + return standard_exponential_zig_f(prng_state); } + + +double random_gauss_zig(prng_t* prng_state) +{ + uint64_t r; + int sign; + int64_t rabs; + int idx; + double x, xx, yy; + for (;;) + { + /* r = e3n52sb8 */ + r = prng_state->next_uint64(prng_state->state); + idx = r & 0xff; + r >>= 8; + sign = r & 0x1; + rabs = (int64_t)((r >> 1) & 0x000fffffffffffff); + x = rabs * wi_double[idx]; + if (sign & 0x1) + x = -x; + if (rabs < ki_double[idx]) + return x; // # 99.3% of the time return here + if (idx == 0) + { + for (;;) + { + xx = -ziggurat_nor_inv_r * log(prng_state->next_double(prng_state->state)); + yy = -log(prng_state->next_double(prng_state->state)); + if (yy + yy > xx * xx) + return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r + xx) : ziggurat_nor_r + xx; + } + } + else + { + if (((fi_double[idx - 1] - fi_double[idx]) * prng_state->next_double(prng_state->state) + fi_double[idx]) < exp(-0.5 * x * x)) + return x; + } + } +} + +float random_gauss_zig_f(prng_t* prng_state) +{ + uint32_t r; + int sign; + int32_t rabs; + int idx; + float x, xx, yy; + for (;;) + { + /* r = n23sb8 */ + r = prng_state->next_uint32(prng_state->state); + idx = r & 0xff; + sign = (r >> 8) & 0x1; + rabs = (int32_t)((r >> 9) & 0x0007fffff); + x = rabs * wi_float[idx]; + if (sign & 0x1) + x = -x; + if (rabs < ki_float[idx]) + return x; // # 99.3% of the time return here + if (idx == 0) + { + for (;;) + { + xx = -ziggurat_nor_inv_r_f * logf(next_float(prng_state)); + yy = -logf(next_float(prng_state)); + if (yy + yy > xx * xx) + return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r_f + xx) : ziggurat_nor_r_f + xx; + } + } + else + { + if (((fi_float[idx - 1] - fi_float[idx]) * next_float(prng_state) + fi_float[idx]) < exp(-0.5 * x * x)) + return x; + } + } +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index 028557ae3d62..4cd72e9d2320 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -53,20 +53,17 @@ typedef struct prng { binomial_t *binomial; } prng_t; -float random_float(prng_t *prng_state); - -double random_double(prng_t *prng_state); +float random_sample_f(prng_t *prng_state); +double random_sample(prng_t *prng_state); uint32_t random_uint32(prng_t *prng_state); double random_standard_exponential(prng_t *prng_state); - -float random_standard_exponential_float(prng_t *prng_state); +float random_standard_exponential_f(prng_t *prng_state); +double random_standard_exponential_zig(prng_t *prng_state); +float random_standard_exponential_zig_f(prng_t *prng_state); double random_gauss(prng_t *prng_state); - -float random_gauss_float(prng_t *prng_state); - -double random_standard_exponential_zig_double(prng_t *prng_state); - -float random_standard_exponential_zig_float(prng_t *prng_state); \ No newline at end of file +float random_gauss_f(prng_t *prng_state); +double random_gauss_zig(prng_t* prng_state); +float random_gauss_zig_f(prng_t* prng_state); \ No newline at end of file diff --git a/_randomgen/setup.py b/_randomgen/setup.py index d1dc482b882f..cb633f359ac7 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -1,17 +1,17 @@ +import os import struct import sys -import os from os.path import join import Cython.Compiler.Options import numpy as np -import versioneer from Cython.Build import cythonize from setuptools import setup, find_packages, Distribution from setuptools.extension import Extension -Cython.Compiler.Options.annotate = True +import versioneer +Cython.Compiler.Options.annotate = True USE_SSE2 = True if not '--no-sse2' in sys.argv else False MOD_DIR = './core_prng' @@ -21,12 +21,13 @@ EXTRA_COMPILE_ARGS = [] EXTRA_LINK_ARGS = [] +EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else ['-std=c99'] if os.name == 'nt': EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] PCG_EMULATED_MATH = True if DEBUG: EXTRA_LINK_ARGS += ['-debug'] - EXTRA_COMPILE_ARGS = ["-Zi", "/Od"] + EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] if USE_SSE2: if os.name == 'nt': From 8de44088925157f24746b41de50ffc0b4e25ffd2 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Mar 2018 23:24:29 +0000 Subject: [PATCH 032/279] ENH: Add std gamma Add standard gamma Add array fillers --- _randomgen/core_prng/common.pxd | 68 +- _randomgen/core_prng/common.pyx | 667 +++++++++++++++++- _randomgen/core_prng/generator.pyx | 110 +++ .../src/distributions/distributions.c | 248 ++++++- .../src/distributions/distributions.h | 66 +- 5 files changed, 1116 insertions(+), 43 deletions(-) diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index c8b15b77d409..38c66814775b 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -1,11 +1,25 @@ -from libc.stdint cimport uint32_t, uint64_t +from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t +from cpython cimport PyInt_AsLong, PyFloat_AsDouble + import numpy as np cimport numpy as np -cdef extern from "src/distributions/distributions.h": - ctypedef double (*random_double_0)(void *st) nogil +cdef double POISSON_LAM_MAX +cdef uint64_t MAXSIZE - ctypedef float (*random_float_0)(void *st) nogil +cdef enum ConstraintType: + CONS_NONE + CONS_NON_NEGATIVE + CONS_POSITIVE + CONS_BOUNDED_0_1 + CONS_BOUNDED_0_1_NOTNAN + CONS_GT_1 + CONS_GTE_1 + CONS_POISSON + +ctypedef ConstraintType constraint_type + +cdef extern from "src/distributions/distributions.h": cdef struct s_binomial_t: int has_binomial; @@ -41,13 +55,51 @@ cdef extern from "src/distributions/distributions.h": ctypedef prng prng_t +ctypedef double (*random_double_0)(prng_t *state) nogil +ctypedef double (*random_double_1)(prng_t *state, double a) nogil +ctypedef double (*random_double_2)(prng_t *state, double a, double b) nogil +ctypedef double (*random_double_3)(prng_t *state, double a, double b, double c) nogil + +ctypedef float (*random_float_0)(prng_t *state) nogil +ctypedef float (*random_float_1)(prng_t *state, float a) nogil + +ctypedef long (*random_uint_0)(prng_t *state) nogil +ctypedef long (*random_uint_d)(prng_t *state, double a) nogil +ctypedef long (*random_uint_dd)(prng_t *state, double a, double b) nogil +ctypedef long (*random_uint_di)(prng_t *state, double a, uint64_t b) nogil +ctypedef long (*random_uint_i)(prng_t *state, long a) nogil +ctypedef long (*random_uint_iii)(prng_t *state, long a, long b, long c) nogil + +ctypedef uint32_t (*random_uint_0_32)(prng_t *state) nogil +ctypedef uint32_t (*random_uint_1_i_32)(prng_t *state, uint32_t a) nogil + +ctypedef int32_t (*random_int_2_i_32)(prng_t *state, int32_t a, int32_t b) nogil +ctypedef int64_t (*random_int_2_i)(prng_t *state, int64_t a, int64_t b) nogil + + cdef inline double uint64_to_double(uint64_t rnd) nogil: return (rnd >> 11) * (1.0 / 9007199254740992.0) -cdef object double_fill(void *func, void *state, object size, object lock, object out) +cdef object double_fill(void *func, prng_t *state, object size, object lock, object out) + +cdef object float_fill(void *func, prng_t *state, object size, object lock, object out) + +cdef object float_fill_from_double(void *func, prng_t *state, object size, object lock, object out) + +cdef np.ndarray int_to_array(object value, object name, object bits) -cdef object float_fill(void *func, void *state, object size, object lock, object out) +cdef object cont(void *func, prng_t *state, object size, object lock, int narg, + object a, object a_name, constraint_type a_constraint, + object b, object b_name, constraint_type b_constraint, + object c, object c_name, constraint_type c_constraint, + object out) -cdef object float_fill_from_double(void *func, void *state, object size, object lock, object out) +cdef object disc(void *func, prng_t *state, object size, object lock, + int narg_double, int narg_long, + object a, object a_name, constraint_type a_constraint, + object b, object b_name, constraint_type b_constraint, + object c, object c_name, constraint_type c_constraint) -cdef np.ndarray int_to_array(object value, object name, object bits) \ No newline at end of file +cdef object cont_f(void *func, prng_t *state, object size, object lock, + object a, object a_name, constraint_type a_constraint, + object out) diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index 0d18a8fc8664..811824985663 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -1,3 +1,4 @@ +import sys import numpy as np cimport numpy as np from common cimport * @@ -40,7 +41,7 @@ cdef check_output(object out, object dtype, object size): raise ValueError('size and out cannot be simultaneously used') -cdef object double_fill(void *func, void *state, object size, object lock, object out): +cdef object double_fill(void *func, prng_t *state, object size, object lock, object out): cdef random_double_0 random_func = (func) cdef double *out_array_data cdef np.ndarray out_array @@ -63,7 +64,7 @@ cdef object double_fill(void *func, void *state, object size, object lock, objec out_array_data[i] = random_func(state) return out_array -cdef object float_fill(void *func, void *state, object size, object lock, object out): +cdef object float_fill(void *func, prng_t *state, object size, object lock, object out): cdef random_float_0 random_func = (func) cdef float *out_array_data cdef np.ndarray out_array @@ -86,7 +87,7 @@ cdef object float_fill(void *func, void *state, object size, object lock, object out_array_data[i] = random_func(state) return out_array -cdef object float_fill_from_double(void *func, void *state, object size, object lock, object out): +cdef object float_fill_from_double(void *func, prng_t *state, object size, object lock, object out): cdef random_double_0 random_func = (func) cdef float *out_array_data cdef np.ndarray out_array @@ -109,3 +110,663 @@ cdef object float_fill_from_double(void *func, void *state, object size, object out_array_data[i] = random_func(state) return out_array + +cdef double POISSON_LAM_MAX = np.iinfo('l').max - np.sqrt(np.iinfo('l').max)*10 + +cdef uint64_t MAXSIZE = sys.maxsize + +cdef int check_array_constraint(np.ndarray val, object name, constraint_type cons) except -1: + if cons == CONS_NON_NEGATIVE: + if np.any(np.signbit(val)): + raise ValueError(name + " < 0") + elif cons == CONS_POSITIVE: + if np.any(np.less_equal(val, 0)): + raise ValueError(name + " <= 0") + elif cons == CONS_BOUNDED_0_1 or cons == CONS_BOUNDED_0_1_NOTNAN: + if np.any(np.less(val, 0)) or np.any(np.greater(val, 1)): + raise ValueError(name + " <= 0 or " + name + " >= 1") + if cons == CONS_BOUNDED_0_1_NOTNAN: + if np.any(np.isnan(val)): + raise ValueError(name + ' contains NaNs') + elif cons == CONS_GT_1: + if np.any(np.less_equal(val, 1)): + raise ValueError(name + " <= 1") + elif cons == CONS_GTE_1: + if np.any(np.less(val, 1)): + raise ValueError(name + " < 1") + elif cons == CONS_POISSON: + if np.any(np.greater(val, POISSON_LAM_MAX)): + raise ValueError(name + " value too large") + if np.any(np.less(val, 0.0)): + raise ValueError(name + " < 0") + + return 0 + + + +cdef int check_constraint(double val, object name, constraint_type cons) except -1: + if cons == CONS_NON_NEGATIVE: + if np.signbit(val): + raise ValueError(name + " < 0") + elif cons == CONS_POSITIVE: + if val <= 0: + raise ValueError(name + " <= 0") + elif cons == CONS_BOUNDED_0_1 or cons == CONS_BOUNDED_0_1_NOTNAN: + if val < 0 or val > 1: + raise ValueError(name + " <= 0 or " + name + " >= 1") + if cons == CONS_BOUNDED_0_1_NOTNAN: + if np.isnan(val): + raise ValueError(name + ' contains NaNs') + elif cons == CONS_GT_1: + if val <= 1: + raise ValueError(name + " <= 1") + elif cons == CONS_GTE_1: + if val < 1: + raise ValueError(name + " < 1") + elif cons == CONS_POISSON: + if val < 0: + raise ValueError(name + " < 0") + elif val > POISSON_LAM_MAX: + raise ValueError(name + " value too large") + + return 0 + +cdef object cont_broadcast_1(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint, + object out): + + cdef np.ndarray randoms + cdef double a_val + cdef double *randoms_data + cdef np.broadcast it + cdef random_double_1 f = (func) + cdef np.npy_intp i, n + + if a_constraint != CONS_NONE: + check_array_constraint(a_arr, a_name, a_constraint) + + if size is not None and out is None: + randoms = np.empty(size, np.double) + elif out is None: + randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_DOUBLE) + else: + randoms = out + + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + it = np.PyArray_MultiIterNew2(randoms, a_arr) + + with lock, nogil: + for i in range(n): + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + randoms_data[i] = f(state, a_val) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + +cdef object cont_broadcast_2(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint, + np.ndarray b_arr, object b_name, constraint_type b_constraint): + cdef np.ndarray randoms + cdef double a_val, b_val + cdef double *randoms_data + cdef np.broadcast it + cdef random_double_2 f = (func) + cdef np.npy_intp i, n + + if a_constraint != CONS_NONE: + check_array_constraint(a_arr, a_name, a_constraint) + + if b_constraint != CONS_NONE: + check_array_constraint(b_arr, b_name, b_constraint) + + if size is not None: + randoms = np.empty(size, np.double) + else: + it = np.PyArray_MultiIterNew2(a_arr, b_arr) + randoms = np.empty(it.shape, np.double) + # randoms = np.PyArray_SimpleNew(it.nd, np.PyArray_DIMS(it), np.NPY_DOUBLE) + + + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr) + with lock, nogil: + for i in range(n): + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + b_val = (np.PyArray_MultiIter_DATA(it, 2))[0] + randoms_data[i] = f(state, a_val, b_val) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + +cdef object cont_broadcast_3(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint, + np.ndarray b_arr, object b_name, constraint_type b_constraint, + np.ndarray c_arr, object c_name, constraint_type c_constraint): + cdef np.ndarray randoms + cdef double a_val, b_val, c_val + cdef double *randoms_data + cdef np.broadcast it + cdef random_double_3 f = (func) + cdef np.npy_intp i, n + + if a_constraint != CONS_NONE: + check_array_constraint(a_arr, a_name, a_constraint) + + if b_constraint != CONS_NONE: + check_array_constraint(b_arr, b_name, b_constraint) + + if c_constraint != CONS_NONE: + check_array_constraint(c_arr, c_name, c_constraint) + + if size is not None: + randoms = np.empty(size, np.double) + else: + it = np.PyArray_MultiIterNew3(a_arr, b_arr, c_arr) + #randoms = np.PyArray_SimpleNew(it.nd, np.PyArray_DIMS(it), np.NPY_DOUBLE) + randoms = np.empty(it.shape, np.double) + + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + it = np.PyArray_MultiIterNew4(randoms, a_arr, b_arr, c_arr) + with lock, nogil: + for i in range(n): + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + b_val = (np.PyArray_MultiIter_DATA(it, 2))[0] + c_val = (np.PyArray_MultiIter_DATA(it, 3))[0] + randoms_data[i] = f(state, a_val, b_val, c_val) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + +cdef object cont(void *func, prng_t *state, object size, object lock, int narg, + object a, object a_name, constraint_type a_constraint, + object b, object b_name, constraint_type b_constraint, + object c, object c_name, constraint_type c_constraint, + object out): + + cdef np.ndarray a_arr, b_arr, c_arr + cdef double _a = 0.0, _b = 0.0, _c = 0.0 + cdef bint is_scalar = True + check_output(out, np.float64, size) + if narg > 0: + a_arr = np.PyArray_FROM_OTF(a, np.NPY_DOUBLE, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(a_arr) == 0 + if narg > 1: + b_arr = np.PyArray_FROM_OTF(b, np.NPY_DOUBLE, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0 + if narg == 3: + c_arr = np.PyArray_FROM_OTF(c, np.NPY_DOUBLE, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(c_arr) == 0 + + if not is_scalar: + if narg == 1: + return cont_broadcast_1(func, state, size, lock, + a_arr, a_name, a_constraint, + out) + elif narg == 2: + return cont_broadcast_2(func, state, size, lock, + a_arr, a_name, a_constraint, + b_arr, b_name, b_constraint) + else: + return cont_broadcast_3(func, state, size, lock, + a_arr, a_name, a_constraint, + b_arr, b_name, b_constraint, + c_arr, c_name, c_constraint) + + if narg > 0: + _a = PyFloat_AsDouble(a) + if a_constraint != CONS_NONE and is_scalar: + check_constraint(_a, a_name, a_constraint) + if narg > 1: + _b = PyFloat_AsDouble(b) + if b_constraint != CONS_NONE: + check_constraint(_b, b_name, b_constraint) + if narg == 3: + _c = PyFloat_AsDouble(c) + if c_constraint != CONS_NONE and is_scalar: + check_constraint(_c, c_name, c_constraint) + + if size is None and out is None: + with lock: + if narg == 0: + return (func)(state) + elif narg == 1: + return (func)(state, _a) + elif narg == 2: + return (func)(state, _a, _b) + elif narg == 3: + return (func)(state, _a, _b, _c) + + cdef np.npy_intp i, n + cdef np.ndarray randoms + if out is None: + randoms = np.empty(size) + else: + randoms = out + n = np.PyArray_SIZE(randoms) + + cdef double *randoms_data = np.PyArray_DATA(randoms) + cdef random_double_0 f0; + cdef random_double_1 f1; + cdef random_double_2 f2; + cdef random_double_3 f3; + + with lock, nogil: + if narg == 0: + f0 = (func) + for i in range(n): + randoms_data[i] = f0(state) + elif narg == 1: + f1 = (func) + for i in range(n): + randoms_data[i] = f1(state, _a) + elif narg == 2: + f2 = (func) + for i in range(n): + randoms_data[i] = f2(state, _a, _b) + elif narg == 3: + f3 = (func) + for i in range(n): + randoms_data[i] = f3(state, _a, _b, _c) + + if out is None: + return randoms + else: + return out + +cdef object discrete_broadcast_d(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint): + + cdef np.ndarray randoms + cdef long *randoms_data + cdef np.broadcast it + cdef random_uint_d f = (func) + cdef np.npy_intp i, n + + if a_constraint != CONS_NONE: + check_array_constraint(a_arr, a_name, a_constraint) + + if size is not None: + randoms = np.empty(size, np.int) + else: + #randoms = np.empty(np.shape(a_arr), np.double) + randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_LONG) + + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + it = np.PyArray_MultiIterNew2(randoms, a_arr) + with lock, nogil: + for i in range(n): + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + randoms_data[i] = f(state, a_val) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + +cdef object discrete_broadcast_dd(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint, + np.ndarray b_arr, object b_name, constraint_type b_constraint): + cdef np.ndarray randoms + cdef long *randoms_data + cdef np.broadcast it + cdef random_uint_dd f = (func) + cdef np.npy_intp i, n + + if a_constraint != CONS_NONE: + check_array_constraint(a_arr, a_name, a_constraint) + if b_constraint != CONS_NONE: + check_array_constraint(b_arr, b_name, b_constraint) + + if size is not None: + randoms = np.empty(size, np.int) + else: + it = np.PyArray_MultiIterNew2(a_arr, b_arr) + randoms = np.empty(it.shape, np.int) + # randoms = np.PyArray_SimpleNew(it.nd, np.PyArray_DIMS(it), np.NPY_LONG) + + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr) + with lock, nogil: + for i in range(n): + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + b_val = (np.PyArray_MultiIter_DATA(it, 2))[0] + randoms_data[i] = f(state, a_val, b_val) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + +cdef object discrete_broadcast_di(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint, + np.ndarray b_arr, object b_name, constraint_type b_constraint): + cdef np.ndarray randoms + cdef long *randoms_data + cdef np.broadcast it + cdef random_uint_di f = (func) + cdef np.npy_intp i, n + + + if a_constraint != CONS_NONE: + check_array_constraint(a_arr, a_name, a_constraint) + + if b_constraint != CONS_NONE: + check_array_constraint(b_arr, b_name, b_constraint) + + if size is not None: + randoms = np.empty(size, np.int) + else: + it = np.PyArray_MultiIterNew2(a_arr, b_arr) + randoms = np.empty(it.shape, np.int) + + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr) + with lock, nogil: + for i in range(n): + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + b_val = (np.PyArray_MultiIter_DATA(it, 2))[0] + (np.PyArray_MultiIter_DATA(it, 0))[0] = f(state, a_val, b_val) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + +cdef object discrete_broadcast_iii(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint, + np.ndarray b_arr, object b_name, constraint_type b_constraint, + np.ndarray c_arr, object c_name, constraint_type c_constraint): + cdef np.ndarray randoms + cdef long *randoms_data + cdef np.broadcast it + cdef random_uint_iii f = (func) + cdef np.npy_intp i, n + + if a_constraint != CONS_NONE: + check_array_constraint(a_arr, a_name, a_constraint) + + if b_constraint != CONS_NONE: + check_array_constraint(b_arr, b_name, b_constraint) + + if c_constraint != CONS_NONE: + check_array_constraint(c_arr, c_name, c_constraint) + + if size is not None: + randoms = np.empty(size, np.int) + else: + it = np.PyArray_MultiIterNew3(a_arr, b_arr, c_arr) + randoms = np.empty(it.shape, np.int) + + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + it = np.PyArray_MultiIterNew4(randoms, a_arr, b_arr, c_arr) + with lock, nogil: + for i in range(n): + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + b_val = (np.PyArray_MultiIter_DATA(it, 2))[0] + c_val = (np.PyArray_MultiIter_DATA(it, 3))[0] + randoms_data[i] = f(state, a_val, b_val, c_val) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + +cdef object discrete_broadcast_i(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint): + cdef np.ndarray randoms + cdef long *randoms_data + cdef np.broadcast it + cdef random_uint_i f = (func) + cdef np.npy_intp i, n + + if a_constraint != CONS_NONE: + check_array_constraint(a_arr, a_name, a_constraint) + + if size is not None: + randoms = np.empty(size, np.int) + else: + randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_LONG) + + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + it = np.PyArray_MultiIterNew2(randoms, a_arr) + with lock, nogil: + for i in range(n): + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + randoms_data[i] = f(state, a_val) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + +# Needs double , double-double , double-long, long , long-long-long +cdef object disc(void *func, prng_t *state, object size, object lock, + int narg_double, int narg_long, + object a, object a_name, constraint_type a_constraint, + object b, object b_name, constraint_type b_constraint, + object c, object c_name, constraint_type c_constraint): + + cdef double _da = 0, _db = 0 + cdef long _ia = 0, _ib = 0 , _ic = 0 + cdef bint is_scalar = True + if narg_double > 0: + a_arr = np.PyArray_FROM_OTF(a, np.NPY_DOUBLE, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(a_arr) == 0 + if narg_double > 1: + b_arr = np.PyArray_FROM_OTF(b, np.NPY_DOUBLE, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0 + elif narg_long == 1: + b_arr = np.PyArray_FROM_OTF(b, np.NPY_LONG, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0 + else: + if narg_long > 0: + a_arr = np.PyArray_FROM_OTF(a, np.NPY_LONG, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(a_arr) == 0 + if narg_long > 1: + b_arr = np.PyArray_FROM_OTF(b, np.NPY_LONG, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0 + if narg_long > 2 : + c_arr = np.PyArray_FROM_OTF(c, np.NPY_LONG, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(c_arr) == 0 + + if not is_scalar: + if narg_long == 0: + if narg_double == 1: + return discrete_broadcast_d(func, state, size, lock, + a_arr, a_name, a_constraint) + elif narg_double == 2: + return discrete_broadcast_dd(func, state, size, lock, + a_arr, a_name, a_constraint, + b_arr, b_name, b_constraint) + elif narg_long == 1: + if narg_double == 0: + return discrete_broadcast_i(func, state, size, lock, + a_arr, a_name, a_constraint) + elif narg_double == 1: + return discrete_broadcast_di(func, state, size, lock, + a_arr, a_name, a_constraint, + b_arr, b_name, b_constraint) + else: + raise NotImplementedError("No vector path available") + + + if narg_double > 0: + _da = PyFloat_AsDouble(a) + if a_constraint != CONS_NONE and is_scalar: + check_constraint(_da, a_name, a_constraint) + + if narg_double > 1: + _db = PyFloat_AsDouble(b) + if b_constraint != CONS_NONE and is_scalar: + check_constraint(_db, b_name, b_constraint) + elif narg_long == 1: + _ib = PyInt_AsLong(b) + if b_constraint != CONS_NONE and is_scalar: + check_constraint(_ib, b_name, b_constraint) + else: + if narg_long > 0: + _ia = PyInt_AsLong(a) + if a_constraint != CONS_NONE and is_scalar: + check_constraint(_ia, a_name, a_constraint) + if narg_long > 1: + _ib = PyInt_AsLong(b) + if b_constraint != CONS_NONE and is_scalar: + check_constraint(_ib, b_name, b_constraint) + if narg_long > 2 : + _ic = PyInt_AsLong(c) + if c_constraint != CONS_NONE and is_scalar: + check_constraint(_ic, c_name, c_constraint) + + if size is None: + with lock: + if narg_long == 0: + if narg_double == 0: + return (func)(state) + elif narg_double == 1: + return (func)(state, _da) + elif narg_double == 2: + return (func)(state, _da, _db) + elif narg_long == 1: + if narg_double == 0: + return (func)(state, _ia) + if narg_double == 1: + return (func)(state, _da, _ib) + else: + return (func)(state, _ia, _ib, _ic) + + cdef np.npy_intp i, n + cdef np.ndarray randoms = np.empty(size, np.int) + cdef np.int_t *randoms_data + cdef random_uint_0 f0; + cdef random_uint_d fd; + cdef random_uint_dd fdd; + cdef random_uint_di fdi; + cdef random_uint_i fi; + cdef random_uint_iii fiii; + + n = np.PyArray_SIZE(randoms) + randoms_data = np.PyArray_DATA(randoms) + + with lock, nogil: + if narg_long == 0: + if narg_double == 0: + f0 = (func) + for i in range(n): + randoms_data[i] = f0(state) + elif narg_double == 1: + fd = (func) + for i in range(n): + randoms_data[i] = fd(state, _da) + elif narg_double == 2: + fdd = (func) + for i in range(n): + randoms_data[i] = fdd(state, _da, _db) + elif narg_long == 1: + if narg_double == 0: + fi = (func) + for i in range(n): + randoms_data[i] = fi(state, _ia) + if narg_double == 1: + fdi = (func) + for i in range(n): + randoms_data[i] = fdi(state, _da, _ib) + else: + fiii = (func) + for i in range(n): + randoms_data[i] = fiii(state, _ia, _ib, _ic) + + return randoms + + +cdef object cont_broadcast_1_f(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint, + object out): + + cdef np.ndarray randoms + cdef float a_val + cdef float *randoms_data + cdef np.broadcast it + cdef random_float_1 f = (func) + cdef np.npy_intp i, n + + if a_constraint != CONS_NONE: + check_array_constraint(a_arr, a_name, a_constraint) + + if size is not None and out is None: + randoms = np.empty(size, np.float32) + elif out is None: + randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), + np.PyArray_DIMS(a_arr), + np.NPY_FLOAT32) + else: + randoms = out + + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + it = np.PyArray_MultiIterNew2(randoms, a_arr) + + with lock, nogil: + for i in range(n): + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + randoms_data[i] = f(state, a_val) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + +cdef object cont_f(void *func, prng_t *state, object size, object lock, + object a, object a_name, constraint_type a_constraint, + object out): + + cdef np.ndarray a_arr, b_arr, c_arr + cdef float _a + cdef bint is_scalar = True + cdef int requirements = np.NPY_ALIGNED | np.NPY_FORCECAST + check_output(out, np.float32, size) + a_arr = np.PyArray_FROMANY(a, np.NPY_FLOAT32, 0, 0, requirements) + # a_arr = np.PyArray_FROM_OTF(a, np.NPY_FLOAT32, np.NPY_ALIGNED) + is_scalar = np.PyArray_NDIM(a_arr) == 0 + + if not is_scalar: + return cont_broadcast_1_f(func, state, size, lock, a_arr, a_name, a_constraint, out) + + _a = PyFloat_AsDouble(a) + if a_constraint != CONS_NONE: + check_constraint(_a, a_name, a_constraint) + + if size is None and out is None: + with lock: + return (func)(state, _a) + + cdef np.npy_intp i, n + cdef np.ndarray randoms + if out is None: + randoms = np.empty(size, np.float32) + else: + randoms = out + n = np.PyArray_SIZE(randoms) + + cdef float *randoms_data = np.PyArray_DATA(randoms) + cdef random_float_1 f1 = func; + + with lock, nogil: + for i in range(n): + randoms_data[i] = f1(state, _a) + + if out is None: + return randoms + else: + return out \ No newline at end of file diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 44a717f67fbd..c48afd199aa4 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -26,12 +26,16 @@ cdef extern from "src/distributions/distributions.h": double random_standard_exponential_zig(prng_t *prng_state) nogil double random_gauss(prng_t *prng_state) nogil double random_gauss_zig(prng_t* prng_state) nogil + double random_standard_gamma(prng_t *prng_state, double shape) nogil + double random_standard_gamma_zig(prng_t *prng_state, double shape) nogil float random_sample_f(prng_t *prng_state) nogil float random_standard_exponential_f(prng_t *prng_state) nogil float random_standard_exponential_zig_f(prng_t *prng_state) nogil float random_gauss_f(prng_t *prng_state) nogil float random_gauss_zig_f(prng_t* prng_state) nogil + float random_standard_gamma_f(prng_t *prng_state, float shape) nogil + float random_standard_gamma_zig_f(prng_t *prng_state, float shape) nogil cdef class RandomGenerator: """ @@ -281,3 +285,109 @@ cdef class RandomGenerator: return float_fill(&random_gauss_f, self._prng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for standard_normal' % key) + + + def standard_gamma(self, shape, size=None, dtype=np.float64, method='zig', + out=None): + """ + standard_gamma(shape, size=None, dtype='d', method='inv', out=None) + + Draw samples from a standard Gamma distribution. + + Samples are drawn from a Gamma distribution with specified parameters, + shape (sometimes designated "k") and scale=1. + + Parameters + ---------- + shape : float or array_like of floats + Parameter, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``shape`` is a scalar. Otherwise, + ``np.array(shape).size`` samples are drawn. + dtype : {str, dtype}, optional + Desired dtype of the result, either 'd' (or 'float64') or 'f' + (or 'float32'). All dtypes are determined by their name. The + default value is 'd'. + method : str, optional + Either 'inv' or 'zig'. 'inv' uses the default inverse CDF method. + 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. + out : ndarray, optional + Alternative output array in which to place the result. If size is + not None, it must have the same shape as the provided size and + must match the type of the output values. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized standard gamma distribution. + + See Also + -------- + scipy.stats.gamma : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gamma distribution is + + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. + + References + ---------- + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + http://en.wikipedia.org/wiki/Gamma_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> shape, scale = 2., 1. # mean and width + >>> s = np.random.standard_gamma(shape, 1000000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ + ... (sps.gamma(shape) * scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') + >>> plt.show() + """ + cdef void *func + if method != u'zig' and method != u'inv': + raise ValueError("method must be either 'inv' or 'zig'") + key = np.dtype(dtype).name + if key == 'float64': + if method == 'inv': + func = &random_standard_gamma + else: + func = &random_standard_gamma_zig + return cont(func, self._prng, size, self.lock, 1, + shape, 'shape', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, + out) + if key == 'float32': + if method == 'inv': + func = &random_standard_gamma_f + else: + func = &random_standard_gamma_zig_f + return cont_f(func, self._prng, size, self.lock, + shape, 'shape', CONS_NON_NEGATIVE, + out) + else: + raise TypeError('Unsupported dtype "%s" for standard_gamma' % key) diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index aebbbfca1973..14cc85da0830 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -236,4 +236,250 @@ float random_gauss_zig_f(prng_t* prng_state) return x; } } -} \ No newline at end of file +} + +static NPY_INLINE double standard_gamma(prng_t* prng_state, double shape) +{ + double b, c; + double U, V, X, Y; + + if (shape == 1.0) + { + return random_standard_exponential(prng_state); + } + else if (shape < 1.0) + { + for (;;) + { + U = prng_state->next_double(prng_state->state); + V = random_standard_exponential(prng_state); + if (U <= 1.0 - shape) + { + X = pow(U, 1. / shape); + if (X <= V) + { + return X; + } + } + else + { + Y = -log((1 - U) / shape); + X = pow(1.0 - shape + shape * Y, 1. / shape); + if (X <= (V + Y)) + { + return X; + } + } + } + } + else + { + b = shape - 1. / 3.; + c = 1. / sqrt(9 * b); + for (;;) + { + do + { + X = random_gauss(prng_state); + V = 1.0 + c * X; + } while (V <= 0.0); + + V = V * V * V; + U = random_sample(prng_state); + if (U < 1.0 - 0.0331 * (X * X) * (X * X)) + return (b * V); + if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) + return (b * V); + } + } +} + +static NPY_INLINE float standard_gamma_float(prng_t *prng_state, float shape) +{ + float b, c; + float U, V, X, Y; + + if (shape == 1.0f) + { + return random_standard_exponential_f(prng_state); + } + else if (shape < 1.0f) + { + for (;;) + { + U = random_sample_f(prng_state); + V = random_standard_exponential_f(prng_state); + if (U <= 1.0f - shape) + { + X = powf(U, 1.0f / shape); + if (X <= V) + { + return X; + } + } + else + { + Y = -logf((1.0f - U) / shape); + X = powf(1.0f - shape + shape * Y, 1.0f / shape); + if (X <= (V + Y)) + { + return X; + } + } + } + } + else + { + b = shape - 1.0f / 3.0f; + c = 1.0f / sqrtf(9.0f * b); + for (;;) + { + do + { + X = random_gauss_f(prng_state); + V = 1.0f + c * X; + } while (V <= 0.0f); + + V = V * V * V; + U = random_sample_f(prng_state); + if (U < 1.0f - 0.0331f * (X * X) * (X * X)) + return (b * V); + if (logf(U) < 0.5f * X * X + b * (1.0f - V + logf(V))) + return (b * V); + } + } +} + + +double random_standard_gamma(prng_t* prng_state, double shape) +{ + return standard_gamma(prng_state, shape); +} + +float random_standard_gamma_f(prng_t* prng_state, float shape) +{ + return standard_gamma_float(prng_state, shape); +} + + +static NPY_INLINE double standard_gamma_zig(prng_t *prng_state, double shape) +{ + double b, c; + double U, V, X, Y; + + if (shape == 1.0) + { + return random_standard_exponential_zig(prng_state); + } + else if (shape < 1.0) + { + for (;;) + { + U = random_sample(prng_state); + V = random_standard_exponential_zig(prng_state); + if (U <= 1.0 - shape) + { + X = pow(U, 1. / shape); + if (X <= V) + { + return X; + } + } + else + { + Y = -log((1 - U) / shape); + X = pow(1.0 - shape + shape * Y, 1. / shape); + if (X <= (V + Y)) + { + return X; + } + } + } + } + else + { + b = shape - 1. / 3.; + c = 1. / sqrt(9 * b); + for (;;) + { + do + { + X = random_gauss_zig(prng_state); + V = 1.0 + c * X; + } while (V <= 0.0); + + V = V * V * V; + U = random_sample(prng_state); + if (U < 1.0 - 0.0331 * (X * X) * (X * X)) + return (b * V); + if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) + return (b * V); + } + } +} + +static NPY_INLINE float standard_gamma_zig_f(prng_t *prng_state, float shape) +{ + float b, c; + float U, V, X, Y; + + if (shape == 1.0f) + { + return random_standard_exponential_zig_f(prng_state); + } + else if (shape < 1.0f) + { + for (;;) + { + U = random_sample_f(prng_state); + V = random_standard_exponential_zig_f(prng_state); + if (U <= 1.0f - shape) + { + X = powf(U, 1.0f / shape); + if (X <= V) + { + return X; + } + } + else + { + Y = -logf((1.0f - U) / shape); + X = powf(1.0f - shape + shape * Y, 1.0f / shape); + if (X <= (V + Y)) + { + return X; + } + } + } + } + else + { + b = shape - 1.0f / 3.0f; + c = 1.0f / sqrtf(9.0f * b); + for (;;) + { + do + { + X = random_gauss_zig_f(prng_state); + V = 1.0f + c * X; + } while (V <= 0.0f); + + V = V * V * V; + U = random_sample_f(prng_state); + if (U < 1.0f - 0.0331f * (X * X) * (X * X)) + return (b * V); + if (logf(U) < 0.5f * X * X + b * (1.0f - V + logf(V))) + return (b * V); + } + } +} + +double random_standard_gamma_zig(prng_t *prng_state, double shape) +{ + return standard_gamma_zig(prng_state, shape); +} + +float random_standard_gamma_zig_f(prng_t *prng_state, float shape) +{ + return standard_gamma_zig_f(prng_state, shape); +} diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index 4cd72e9d2320..3672060eab3b 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -14,31 +14,30 @@ typedef int bool; #include #endif -#include #include "numpy/npy_common.h" +#include typedef double (*random_double_0)(void *st); typedef float (*random_float_0)(void *st); -typedef struct s_binomial_t -{ - int has_binomial; /* !=0: following parameters initialized for binomial */ - double psave; - long nsave; - double r; - double q; - double fm; - long m; - double p1; - double xm; - double xl; - double xr; - double c; - double laml; - double lamr; - double p2; - double p3; - double p4; +typedef struct s_binomial_t { + int has_binomial; /* !=0: following parameters initialized for binomial */ + double psave; + long nsave; + double r; + double q; + double fm; + long m; + double p1; + double xm; + double xl; + double xr; + double c; + double laml; + double lamr; + double p2; + double p3; + double p4; } binomial_t; typedef struct prng { @@ -53,17 +52,22 @@ typedef struct prng { binomial_t *binomial; } prng_t; -float random_sample_f(prng_t *prng_state); -double random_sample(prng_t *prng_state); +extern float random_sample_f(prng_t *prng_state); +extern double random_sample(prng_t *prng_state); + +extern uint32_t random_uint32(prng_t *prng_state); -uint32_t random_uint32(prng_t *prng_state); +extern double random_standard_exponential(prng_t *prng_state); +extern float random_standard_exponential_f(prng_t *prng_state); +extern double random_standard_exponential_zig(prng_t *prng_state); +extern float random_standard_exponential_zig_f(prng_t *prng_state); -double random_standard_exponential(prng_t *prng_state); -float random_standard_exponential_f(prng_t *prng_state); -double random_standard_exponential_zig(prng_t *prng_state); -float random_standard_exponential_zig_f(prng_t *prng_state); +extern double random_gauss(prng_t *prng_state); +extern float random_gauss_f(prng_t *prng_state); +extern double random_gauss_zig(prng_t *prng_state); +extern float random_gauss_zig_f(prng_t *prng_state); -double random_gauss(prng_t *prng_state); -float random_gauss_f(prng_t *prng_state); -double random_gauss_zig(prng_t* prng_state); -float random_gauss_zig_f(prng_t* prng_state); \ No newline at end of file +extern double random_standard_gamma(prng_t *prng_state, double shape); +extern float random_standard_gamma_f(prng_t *prng_state, float shape); +extern double random_standard_gamma_zig(prng_t *prng_state, double shape); +extern float random_standard_gamma_zig_f(prng_t *prng_state, float shape); From 647866f5163d18e14560161aa506add1a7869a08 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 6 Mar 2018 09:32:13 +0000 Subject: [PATCH 033/279] CLN: Clean random123 generators Simplify these generators a small amount Define constants nhance the demo/benchmark --- _randomgen/core_prng/dsfmt.pyx | 13 +++++-- _randomgen/core_prng/mt19937.pyx | 12 ++++-- _randomgen/core_prng/pcg64.pyx | 12 ++++-- _randomgen/core_prng/philox.pyx | 29 ++++++++++----- _randomgen/core_prng/src/philox/philox.c | 4 +- _randomgen/core_prng/src/philox/philox.h | 39 +++++++++++--------- _randomgen/core_prng/src/threefry/threefry.h | 27 +++++++++----- _randomgen/core_prng/threefry.pyx | 24 ++++++++---- _randomgen/core_prng/xoroshiro128.pyx | 12 ++++-- _randomgen/core_prng/xorshift1024.pyx | 12 ++++-- _randomgen/demo.py | 23 +++++++++++- 11 files changed, 143 insertions(+), 64 deletions(-) diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index e43d05a75af9..68663e4b0d10 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -139,11 +139,16 @@ cdef class DSFMT: else: raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt): + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i - for i in range(cnt): - self._prng.next_uint64(self._prng.state) - + if method==u'uint64': + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + elif method==u'double': + for i in range(cnt): + self._prng.next_double(self._prng.state) + else: + raise ValueError('Unknown method') def seed(self, seed=None): """ diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index 9e6b936efb5a..a5b836699697 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -109,10 +109,16 @@ cdef class MT19937: else: raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt): + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i - for i in range(cnt): - self._prng.next_uint64(self._prng.state) + if method==u'uint64': + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + elif method==u'double': + for i in range(cnt): + self._prng.next_double(self._prng.state) + else: + raise ValueError('Unknown method') def seed(self, seed=None): """ diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index f728e2bbecc0..3e447ae3a92a 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -139,10 +139,16 @@ cdef class PCG64: else: raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt): + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i - for i in range(cnt): - self._prng.next_uint64(self._prng.state) + if method==u'uint64': + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + elif method==u'double': + for i in range(cnt): + self._prng.next_double(self._prng.state) + else: + raise ValueError('Unknown method') def seed(self, seed=None, inc=1): diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx index 474bc752ebf0..f0dcc3a7d1ea 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/core_prng/philox.pyx @@ -10,6 +10,8 @@ cimport entropy np.import_array() +DEF PHILOX_BUFFER_SIZE=4 + cdef extern from 'src/philox/philox.h': struct s_r123array2x64: uint64_t v[2] @@ -27,7 +29,7 @@ cdef extern from 'src/philox/philox.h': philox4x64_ctr_t *ctr; philox4x64_key_t *key; int buffer_pos; - uint64_t buffer[4]; + uint64_t buffer[PHILOX_BUFFER_SIZE]; int has_uint32 uint32_t uinteger @@ -106,8 +108,8 @@ cdef class Philox: def _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - self.rng_state.buffer_pos = 4 - for i in range(4): + self.rng_state.buffer_pos = PHILOX_BUFFER_SIZE + for i in range(PHILOX_BUFFER_SIZE): self.rng_state.buffer[i] = 0 def __random_integer(self, bits=64): @@ -135,10 +137,16 @@ cdef class Philox: else: raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt): + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i - for i in range(cnt): - self._prng.next_uint64(self._prng.state) + if method==u'uint64': + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + elif method==u'double': + for i in range(cnt): + self._prng.next_double(self._prng.state) + else: + raise ValueError('Unknown method') def seed(self, seed=None, counter=None, key=None): """ @@ -201,12 +209,13 @@ cdef class Philox: """Get or set the PRNG state""" ctr = np.empty(4, dtype=np.uint64) key = np.empty(2, dtype=np.uint64) - buffer = np.empty(4, dtype=np.uint64) + buffer = np.empty(PHILOX_BUFFER_SIZE, dtype=np.uint64) for i in range(4): ctr[i] = self.rng_state.ctr.v[i] - buffer[i] = self.rng_state.buffer[i] if i < 2: key[i] = self.rng_state.key.v[i] + for i in range(PHILOX_BUFFER_SIZE): + buffer[i] = self.rng_state.buffer[i] state = {'counter': ctr, 'key': key} return {'prng': self.__class__.__name__, @@ -226,9 +235,11 @@ cdef class Philox: 'PRNG'.format(self.__class__.__name__)) for i in range(4): self.rng_state.ctr.v[i] = value['state']['counter'][i] - self.rng_state.buffer[i] = value['buffer'][i] if i < 2: self.rng_state.key.v[i] = value['state']['key'][i] + for i in range(PHILOX_BUFFER_SIZE): + self.rng_state.buffer[i] = value['buffer'][i] + self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] self.rng_state.buffer_pos = value['buffer_pos'] diff --git a/_randomgen/core_prng/src/philox/philox.c b/_randomgen/core_prng/src/philox/philox.c index 06eaa3400ebb..ea401e3690d8 100644 --- a/_randomgen/core_prng/src/philox/philox.c +++ b/_randomgen/core_prng/src/philox/philox.c @@ -1,8 +1,8 @@ #include "philox.h" -extern inline uint64_t philox_next64(philox_state *state); +extern INLINE uint64_t philox_next64(philox_state *state); -extern inline uint64_t philox_next32(philox_state *state); +extern INLINE uint64_t philox_next32(philox_state *state); extern void philox_jump(philox_state *state) { /* Advances state as-if 2^128 draws were made */ diff --git a/_randomgen/core_prng/src/philox/philox.h b/_randomgen/core_prng/src/philox/philox.h index 3121d5cbdc2e..477ba17accb6 100644 --- a/_randomgen/core_prng/src/philox/philox.h +++ b/_randomgen/core_prng/src/philox/philox.h @@ -1,11 +1,13 @@ #include #ifdef _WIN32 -#define INLINE __inline _forceinline +#define INLINE __inline __forceinline #else #define INLINE inline #endif +#define PHILOX_BUFFER_SIZE 4UL + struct r123array2x64 { uint64_t v[2]; }; @@ -18,7 +20,7 @@ typedef struct r123array4x64 philox4x64_ctr_t; typedef struct r123array2x64 philox4x64_key_t; typedef struct r123array2x64 philox4x64_ukey_t; -static __inline struct r123array2x64 +static INLINE struct r123array2x64 _philox4x64bumpkey(struct r123array2x64 key) { key.v[0] += (0x9E3779B97F4A7C15ULL); key.v[1] += (0xBB67AE8584CAA73BULL); @@ -30,22 +32,22 @@ _philox4x64bumpkey(struct r123array2x64 key) { #include #pragma intrinsic(_umul128) -static __inline uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { +static INLINE uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { return _umul128(a, b, hip); } #else -static inline uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { +static INLINE uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { __uint128_t product = ((__uint128_t)a) * ((__uint128_t)b); *hip = product >> 64; return (uint64_t)product; } #endif -// static __inline _forceinline struct r123array4x64 _philox4x64round(struct -// r123array4x64 ctr, struct r123array2x64 key); +static INLINE struct r123array4x64 _philox4x64round(struct r123array4x64 ctr, + struct r123array2x64 key); -static INLINE struct r123array4x64 -_philox4x64round(struct r123array4x64 ctr, struct r123array2x64 key) { +static INLINE struct r123array4x64 _philox4x64round(struct r123array4x64 ctr, + struct r123array2x64 key) { uint64_t hi0; uint64_t hi1; uint64_t lo0 = mulhilo64((0xD2E7470EE14C6C93ULL), ctr.v[0], &hi0); @@ -58,11 +60,13 @@ _philox4x64round(struct r123array4x64 ctr, struct r123array2x64 key) { static INLINE philox4x64_key_t philox4x64keyinit(philox4x64_ukey_t uk) { return uk; } -// static __inline _forceinline philox4x64_ctr_t philox4x64_R(unsigned int R, -// philox4x64_ctr_t ctr, philox4x64_key_t key); +static INLINE philox4x64_ctr_t philox4x64_R(unsigned int R, + philox4x64_ctr_t ctr, + philox4x64_key_t key); -static INLINE philox4x64_ctr_t -philox4x64_R(unsigned int R, philox4x64_ctr_t ctr, philox4x64_key_t key) { +static INLINE philox4x64_ctr_t philox4x64_R(unsigned int R, + philox4x64_ctr_t ctr, + philox4x64_key_t key) { if (R > 0) { ctr = _philox4x64round(ctr, key); } @@ -133,14 +137,13 @@ typedef struct s_philox_state { philox4x64_ctr_t *ctr; philox4x64_key_t *key; int buffer_pos; - uint64_t buffer[4]; + uint64_t buffer[PHILOX_BUFFER_SIZE]; int has_uint32; uint32_t uinteger; } philox_state; -static inline uint64_t philox_next(philox_state *state) { - /* TODO: This 4 should be a constant somewhere */ - if (state->buffer_pos < 4) { +static INLINE uint64_t philox_next(philox_state *state) { + if (state->buffer_pos < PHILOX_BUFFER_SIZE) { uint64_t out = state->buffer[state->buffer_pos]; state->buffer_pos++; return out; @@ -167,11 +170,11 @@ static inline uint64_t philox_next(philox_state *state) { return state->buffer[0]; } -static inline uint64_t philox_next64(philox_state *state) { +static INLINE uint64_t philox_next64(philox_state *state) { return philox_next(state); } -static inline uint64_t philox_next32(philox_state *state) { +static INLINE uint64_t philox_next32(philox_state *state) { if (state->has_uint32) { state->has_uint32 = 0; return state->uinteger; diff --git a/_randomgen/core_prng/src/threefry/threefry.h b/_randomgen/core_prng/src/threefry/threefry.h index 35a3be53f576..5fa9a716b5a2 100644 --- a/_randomgen/core_prng/src/threefry/threefry.h +++ b/_randomgen/core_prng/src/threefry/threefry.h @@ -4,6 +4,14 @@ Adapted from random123's threefry.h #include +#ifdef _WIN32 +#define INLINE __inline __forceinline +#else +#define INLINE inline +#endif + +#define THREEFRY_BUFFER_SIZE 4UL + enum r123_enum_threefry64x4 { /* These are the R_256 constants from the Threefish reference sources with names changed to R_64x4... */ @@ -32,15 +40,15 @@ struct r123array4x64 { typedef struct r123array4x64 threefry4x64_key_t; typedef struct r123array4x64 threefry4x64_ctr_t; -static inline uint64_t RotL_64(uint64_t x, unsigned int N); -static inline uint64_t RotL_64(uint64_t x, unsigned int N) { +static INLINE uint64_t RotL_64(uint64_t x, unsigned int N); +static INLINE uint64_t RotL_64(uint64_t x, unsigned int N) { return (x << (N & 63)) | (x >> ((64 - N) & 63)); } -static inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, +static INLINE threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry4x64_ctr_t in, threefry4x64_key_t k); -static inline threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, +static INLINE threefry4x64_ctr_t threefry4x64_R(unsigned int Nrounds, threefry4x64_ctr_t in, threefry4x64_key_t k) { threefry4x64_ctr_t X; @@ -268,14 +276,13 @@ typedef struct s_threefry_state { threefry4x64_key_t *ctr; threefry4x64_ctr_t *key; int buffer_pos; - uint64_t buffer[4]; + uint64_t buffer[THREEFRY_BUFFER_SIZE]; int has_uint32; uint32_t uinteger; } threefry_state; -static inline uint64_t threefry_next(threefry_state *state) { - /* TODO: This 4 should be a constant somewhere */ - if (state->buffer_pos < 4) { +static INLINE uint64_t threefry_next(threefry_state *state) { + if (state->buffer_pos < THREEFRY_BUFFER_SIZE) { uint64_t out = state->buffer[state->buffer_pos]; state->buffer_pos++; return out; @@ -302,11 +309,11 @@ static inline uint64_t threefry_next(threefry_state *state) { return state->buffer[0]; } -static inline uint64_t threefry_next64(threefry_state *state) { +static INLINE uint64_t threefry_next64(threefry_state *state) { return threefry_next(state); } -static inline uint64_t threefry_next32(threefry_state *state) { +static INLINE uint64_t threefry_next32(threefry_state *state) { if (state->has_uint32) { state->has_uint32 = 0; return state->uinteger; diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index dfcc6e41da9d..db83379eb9c5 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -10,6 +10,8 @@ cimport entropy np.import_array() +DEF THREEFRY_BUFFER_SIZE=4 + cdef extern from 'src/threefry/threefry.h': struct s_r123array4x64: uint64_t v[4] @@ -23,7 +25,7 @@ cdef extern from 'src/threefry/threefry.h': threefry4x64_ctr_t *ctr; threefry4x64_key_t *key; int buffer_pos; - uint64_t buffer[4]; + uint64_t buffer[THREEFRY_BUFFER_SIZE]; int has_uint32 uint32_t uinteger @@ -100,8 +102,8 @@ cdef class ThreeFry: def _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - self.rng_state.buffer_pos = 4 - for i in range(4): + self.rng_state.buffer_pos = THREEFRY_BUFFER_SIZE + for i in range(THREEFRY_BUFFER_SIZE): self.rng_state.buffer[i] = 0 def __random_integer(self, bits=64): @@ -129,10 +131,16 @@ cdef class ThreeFry: else: raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt): + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i - for i in range(cnt): - self._prng.next_uint64(self._prng.state) + if method==u'uint64': + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + elif method==u'double': + for i in range(cnt): + self._prng.next_double(self._prng.state) + else: + raise ValueError('Unknown method') def seed(self, seed=None, counter=None, key=None): """ @@ -196,10 +204,11 @@ cdef class ThreeFry: """Get or set the PRNG state""" ctr = np.empty(4, dtype=np.uint64) key = np.empty(4, dtype=np.uint64) - buffer = np.empty(4, dtype=np.uint64) + buffer = np.empty(THREEFRY_BUFFER_SIZE, dtype=np.uint64) for i in range(4): ctr[i] = self.rng_state.ctr.v[i] key[i] = self.rng_state.key.v[i] + for i in range(THREEFRY_BUFFER_SIZE): buffer[i] = self.rng_state.buffer[i] state = {'counter':ctr,'key':key} return {'prng': self.__class__.__name__, @@ -220,6 +229,7 @@ cdef class ThreeFry: for i in range(4): self.rng_state.ctr.v[i] = value['state']['counter'][i] self.rng_state.key.v[i] = value['state']['key'][i] + for i in range(THREEFRY_BUFFER_SIZE): self.rng_state.buffer[i] = value['buffer'][i] self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 0c1f90998d9d..820ae0476e49 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -112,10 +112,16 @@ cdef class Xoroshiro128: else: raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt): + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i - for i in range(cnt): - self._prng.next_uint64(self._prng.state) + if method==u'uint64': + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + elif method==u'double': + for i in range(cnt): + self._prng.next_double(self._prng.state) + else: + raise ValueError('Unknown method') def seed(self, seed=None): """ diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index f693d5a7e208..6c0585369479 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -112,10 +112,16 @@ cdef class Xorshift1024: else: raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt): + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i - for i in range(cnt): - self._prng.next_uint64(self._prng.state) + if method==u'uint64': + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + elif method==u'double': + for i in range(cnt): + self._prng.next_double(self._prng.state) + else: + raise ValueError('Unknown method') def seed(self, seed=None): """ diff --git a/_randomgen/demo.py b/_randomgen/demo.py index 29f440505330..30b0984221d2 100644 --- a/_randomgen/demo.py +++ b/_randomgen/demo.py @@ -75,10 +75,29 @@ m = {module}() m._benchmark(701) """ +import pandas as pd +res = [] for p in PRNGS: module = p.__name__ print(module) t = timeit.timeit("m._benchmark(10000000)", setup.format(module=module), number=10) - print('{:0.2f} ms'.format(1000 * t / 10)) - print('{:,} randoms per second'.format(int(10000000 / (t/10)))) + res.append(pd.Series({'module': module, 'ms': 1000 * + t / 10, 'rps': int(10000000 / (t/10))})) + #print('{:0.2f} ms'.format()) + # print('{:,} randoms per second'.format())) +res = pd.DataFrame(res) +print(res.set_index('module').sort_values('ms')) + +res = [] +for p in PRNGS: + module = p.__name__ + print(module) + t = timeit.timeit("m._benchmark(10000000, 'double')", setup.format(module=module), + number=10) + res.append(pd.Series({'module': module, 'ms': 1000 * + t / 10, 'rps': int(10000000 / (t/10))})) + #print('{:0.2f} ms'.format()) + # print('{:,} randoms per second'.format())) +res = pd.DataFrame(res) +print(res.set_index('module').sort_values('ms')) From ca3955844f03c532ce1fbf14f0be758b45337082 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 6 Mar 2018 12:00:48 +0000 Subject: [PATCH 034/279] TST: Add test code for philox Add test and benchmark code for Philox --- .../core_prng/src/philox/philox-benchmark.c | 33 +++++++++ .../src/philox/philox-test-data-gen.c | 74 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 _randomgen/core_prng/src/philox/philox-benchmark.c create mode 100644 _randomgen/core_prng/src/philox/philox-test-data-gen.c diff --git a/_randomgen/core_prng/src/philox/philox-benchmark.c b/_randomgen/core_prng/src/philox/philox-benchmark.c new file mode 100644 index 000000000000..db265df0a275 --- /dev/null +++ b/_randomgen/core_prng/src/philox/philox-benchmark.c @@ -0,0 +1,33 @@ +/* + * Simple benchamrk command + * + * cl philox-benchmark.c /Ox /GL + * Measure-Command { .\philox-benchmark.exe } + * + * gcc philox-benchmark.c -O3 -o philox-benchmark + * time ./philox-benchmark + * + * Requres the Random123 directory containins header files to be located in the + * same directory (not included). + */ +#include "Random123/philox.h" +#include +#include + +#define N 1000000000 + +int main() { + philox4x64_ctr_t ctr = {{0, 0, 0, 0}}; + philox4x64_key_t key = {{0, 0xDEADBEAF}}; + philox4x64_ctr_t out; + uint64_t sum = 0; + int i, j; + for (i = 0; i < N / 4UL; i++) { + ctr.v[0]++; + out = philox4x64_R(philox4x64_rounds, ctr, key); + for (j = 0; j < 4; j++) { + sum += out.v[j]; + } + } + printf("%" PRIu64 "\n", sum); +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/philox/philox-test-data-gen.c b/_randomgen/core_prng/src/philox/philox-test-data-gen.c new file mode 100644 index 000000000000..8f7ecf381640 --- /dev/null +++ b/_randomgen/core_prng/src/philox/philox-test-data-gen.c @@ -0,0 +1,74 @@ +/* + * Generate testing csv files + * + * cl philox-test-data-gen.c /Ox + * philox-test-data-gen.exe + * + * gcc philox-test-data-gen.c -o philox-test-data-gen + * ./philox-test-data-gen + * + * Requres the Random123 directory containins header files to be located in the + * same directory (not included). + * + */ + +#include "Random123/philox.h" +#include +#include + +#define N 1000 + +int main() { + philox4x64_ctr_t ctr = {{0, 0, 0, 0}}; + philox4x64_key_t key = {{0, 0xDEADBEAF}}; + philox4x64_ctr_t out; + uint64_t store[N]; + int i, j; + for (i = 0; i < N / 4UL; i++) { + ctr.v[0]++; + out = philox4x64_R(philox4x64_rounds, ctr, key); + for (j = 0; j < 4; j++) { + store[i * 4 + j] = out.v[j]; + } + } + + FILE *fp; + fp = fopen("philox-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "key: %" PRIu64 ", %" PRIu64 "\n", key.v[0], key.v[1]); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, %" PRIu64 "\n", i, store[i]); + if (i == 999) { + printf("%d, %" PRIu64 "\n", i, store[i]); + } + } + fclose(fp); + + ctr.v[0] = 0; + key.v[0] = 0xDEADBEAF; + key.v[1] = 0xFBADBEEF; + for (i = 0; i < N / 4UL; i++) { + ctr.v[0]++; + out = philox4x64_R(philox4x64_rounds, ctr, key); + for (j = 0; j < 4; j++) { + store[i * 4 + j] = out.v[j]; + } + } + + fp = fopen("philox-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "key: %" PRIu64 ", %" PRIu64 "\n", key.v[0], key.v[1]); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, %" PRIu64 "\n", i, store[i]); + if (i == 999) { + printf("%d, %" PRIu64 "\n", i, store[i]); + } + } + fclose(fp); +} \ No newline at end of file From a2bc5b0fbc643785c1a7f4f9c1d774052d0004a7 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 6 Mar 2018 12:25:19 +0000 Subject: [PATCH 035/279] TST: Add test generation for threefry Add test generation and benchmark Fix benchmark for philox --- .../core_prng/src/philox/philox-benchmark.c | 4 +- .../src/philox/philox-test-data-gen.c | 2 +- .../src/threefry/threefry-benchmark.c | 34 ++++++++ .../src/threefry/threefry-test-data-gen.c | 77 +++++++++++++++++++ 4 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 _randomgen/core_prng/src/threefry/threefry-benchmark.c create mode 100644 _randomgen/core_prng/src/threefry/threefry-test-data-gen.c diff --git a/_randomgen/core_prng/src/philox/philox-benchmark.c b/_randomgen/core_prng/src/philox/philox-benchmark.c index db265df0a275..03ab8bde0eac 100644 --- a/_randomgen/core_prng/src/philox/philox-benchmark.c +++ b/_randomgen/core_prng/src/philox/philox-benchmark.c @@ -1,13 +1,13 @@ /* * Simple benchamrk command * - * cl philox-benchmark.c /Ox /GL + * cl philox-benchmark.c /Ox * Measure-Command { .\philox-benchmark.exe } * * gcc philox-benchmark.c -O3 -o philox-benchmark * time ./philox-benchmark * - * Requres the Random123 directory containins header files to be located in the + * Requres the Random123 directory containing header files to be located in the * same directory (not included). */ #include "Random123/philox.h" diff --git a/_randomgen/core_prng/src/philox/philox-test-data-gen.c b/_randomgen/core_prng/src/philox/philox-test-data-gen.c index 8f7ecf381640..f50389a4c8aa 100644 --- a/_randomgen/core_prng/src/philox/philox-test-data-gen.c +++ b/_randomgen/core_prng/src/philox/philox-test-data-gen.c @@ -7,7 +7,7 @@ * gcc philox-test-data-gen.c -o philox-test-data-gen * ./philox-test-data-gen * - * Requres the Random123 directory containins header files to be located in the + * Requres the Random123 directory containing header files to be located in the * same directory (not included). * */ diff --git a/_randomgen/core_prng/src/threefry/threefry-benchmark.c b/_randomgen/core_prng/src/threefry/threefry-benchmark.c new file mode 100644 index 000000000000..cc6548bed6e2 --- /dev/null +++ b/_randomgen/core_prng/src/threefry/threefry-benchmark.c @@ -0,0 +1,34 @@ +/* + * Simple benchamrk command + * + * cl threefry-benchmark.c /Ox + * Measure-Command { .\threefry-benchmark.exe } + * + * gcc threefry-benchmark.c -O3 -o threefry-benchmark + * time ./threefry-benchmark + * + * Requres the Random123 directory containing header files to be located in the + * same directory (not included). + */ +#include "Random123/threefry.h" +#include +#include + +#define N 1000000000 + +int main() { + + threefry4x64_key_t ctr = {{0, 0, 0, 0}}; + threefry4x64_ctr_t key = {{0xDEADBEAF, 0, 0, 0}}; + threefry4x64_ctr_t out; + uint64_t sum = 0; + int i, j; + for (i = 0; i < N / 4UL; i++) { + ctr.v[0]++; + out = threefry4x64_R(threefry4x64_rounds, ctr, key); + for (j = 0; j < 4; j++) { + sum += out.v[j]; + } + } + printf("%" PRIu64 "\n", sum); +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c b/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c new file mode 100644 index 000000000000..4f49914e151c --- /dev/null +++ b/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c @@ -0,0 +1,77 @@ +/* + * Generate testing csv files + * + * cl threefry-test-data-gen.c /Ox + * threefry-test-data-gen.exe + * + * gcc threefry-test-data-gen.c -o philox-test-data-gen + * ./threefry-test-data-gen + * + * Requres the Random123 directory containing header files to be located in the + * same directory (not included). + * + */ + +#include "Random123/threefry.h" +#include +#include + +#define N 1000 + +int main() { + threefry4x64_key_t ctr = {{0, 0, 0, 0}}; + threefry4x64_ctr_t key = {{0xDEADBEAF, 0, 0, 0}}; + threefry4x64_ctr_t out; + uint64_t store[N]; + int i, j; + for (i = 0; i < N / 4UL; i++) { + ctr.v[0]++; + out = threefry4x64_R(threefry4x64_rounds, ctr, key); + for (j = 0; j < 4; j++) { + store[i * 4 + j] = out.v[j]; + } + } + + FILE *fp; + fp = fopen("threefry-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "key, %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 "\n", + key.v[0], key.v[1], key.v[2], key.v[3]); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, %" PRIu64 "\n", i, store[i]); + if (i == 999) { + printf("%d, %" PRIu64 "\n", i, store[i]); + } + } + fclose(fp); + + ctr.v[0] = 0; + key.v[0] = 0; + key.v[1] = 0; + key.v[2] = 0xFBADBEEF; + key.v[3] = 0xDEADBEAF; + for (i = 0; i < N / 4UL; i++) { + ctr.v[0]++; + out = threefry4x64_R(threefry4x64_rounds, ctr, key); + for (j = 0; j < 4; j++) { + store[i * 4 + j] = out.v[j]; + } + } + + fp = fopen("philox-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "key: %" PRIu64 ", %" PRIu64 "\n", key.v[0], key.v[1]); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, %" PRIu64 "\n", i, store[i]); + if (i == 999) { + printf("%d, %" PRIu64 "\n", i, store[i]); + } + } + fclose(fp); +} \ No newline at end of file From 0338539bb32570a4395d981d8a4ee23977647695 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 6 Mar 2018 12:51:47 +0000 Subject: [PATCH 036/279] ENH: Improve benchmark Improve benchmarks --- .../core_prng/src/philox/philox-benchmark.c | 2 +- .../src/philox/philox-test-data-gen.c | 12 ++++++------ .../src/threefry/threefry-benchmark.c | 2 +- .../src/threefry/threefry-test-data-gen.c | 19 +++++++++++-------- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/_randomgen/core_prng/src/philox/philox-benchmark.c b/_randomgen/core_prng/src/philox/philox-benchmark.c index 03ab8bde0eac..d80563e5e4b2 100644 --- a/_randomgen/core_prng/src/philox/philox-benchmark.c +++ b/_randomgen/core_prng/src/philox/philox-benchmark.c @@ -29,5 +29,5 @@ int main() { sum += out.v[j]; } } - printf("%" PRIu64 "\n", sum); + printf("0x%" PRIx64 "\n", sum); } \ No newline at end of file diff --git a/_randomgen/core_prng/src/philox/philox-test-data-gen.c b/_randomgen/core_prng/src/philox/philox-test-data-gen.c index f50389a4c8aa..fd717b959794 100644 --- a/_randomgen/core_prng/src/philox/philox-test-data-gen.c +++ b/_randomgen/core_prng/src/philox/philox-test-data-gen.c @@ -38,11 +38,11 @@ int main() { printf("Couldn't open file\n"); return -1; } - fprintf(fp, "key: %" PRIu64 ", %" PRIu64 "\n", key.v[0], key.v[1]); + fprintf(fp, "key, 0x%" PRIx64 ", 0x%" PRIx64 "\n", key.v[0], key.v[1]); for (i = 0; i < N; i++) { - fprintf(fp, "%d, %" PRIu64 "\n", i, store[i]); + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); if (i == 999) { - printf("%d, %" PRIu64 "\n", i, store[i]); + printf("%d, 0x%" PRIx64 "\n", i, store[i]); } } fclose(fp); @@ -63,11 +63,11 @@ int main() { printf("Couldn't open file\n"); return -1; } - fprintf(fp, "key: %" PRIu64 ", %" PRIu64 "\n", key.v[0], key.v[1]); + fprintf(fp, "key, 0x%" PRIx64 ", 0x%" PRIx64 "\n", key.v[0], key.v[1]); for (i = 0; i < N; i++) { - fprintf(fp, "%d, %" PRIu64 "\n", i, store[i]); + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); if (i == 999) { - printf("%d, %" PRIu64 "\n", i, store[i]); + printf("%d, 0x%" PRIx64 "\n", i, store[i]); } } fclose(fp); diff --git a/_randomgen/core_prng/src/threefry/threefry-benchmark.c b/_randomgen/core_prng/src/threefry/threefry-benchmark.c index cc6548bed6e2..e5f923551a54 100644 --- a/_randomgen/core_prng/src/threefry/threefry-benchmark.c +++ b/_randomgen/core_prng/src/threefry/threefry-benchmark.c @@ -30,5 +30,5 @@ int main() { sum += out.v[j]; } } - printf("%" PRIu64 "\n", sum); + printf("0x%" PRIx64 "\n", sum); } \ No newline at end of file diff --git a/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c b/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c index 4f49914e151c..2fa09eed31f3 100644 --- a/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c +++ b/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c @@ -4,7 +4,7 @@ * cl threefry-test-data-gen.c /Ox * threefry-test-data-gen.exe * - * gcc threefry-test-data-gen.c -o philox-test-data-gen + * gcc threefry-test-data-gen.c -o threefry-test-data-gen * ./threefry-test-data-gen * * Requres the Random123 directory containing header files to be located in the @@ -38,12 +38,13 @@ int main() { printf("Couldn't open file\n"); return -1; } - fprintf(fp, "key, %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 "\n", + fprintf(fp, + "key, 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 "\n", key.v[0], key.v[1], key.v[2], key.v[3]); for (i = 0; i < N; i++) { - fprintf(fp, "%d, %" PRIu64 "\n", i, store[i]); + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); if (i == 999) { - printf("%d, %" PRIu64 "\n", i, store[i]); + printf("%d, 0x%" PRIx64 "\n", i, store[i]); } } fclose(fp); @@ -61,16 +62,18 @@ int main() { } } - fp = fopen("philox-testset-2.csv", "w"); + fp = fopen("threefry-testset-2.csv", "w"); if (fp == NULL) { printf("Couldn't open file\n"); return -1; } - fprintf(fp, "key: %" PRIu64 ", %" PRIu64 "\n", key.v[0], key.v[1]); + fprintf(fp, + "key, 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 "\n", + key.v[0], key.v[1], key.v[2], key.v[3]); for (i = 0; i < N; i++) { - fprintf(fp, "%d, %" PRIu64 "\n", i, store[i]); + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); if (i == 999) { - printf("%d, %" PRIu64 "\n", i, store[i]); + printf("%d, 0x%" PRIx64 "\n", i, store[i]); } } fclose(fp); From 9225df4fe31fbd89e55012a1f0daa94af932d1ea Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 6 Mar 2018 18:06:36 +0000 Subject: [PATCH 037/279] TST: Add test data gen and benchmarks for xoroshirt and xorshirt Add test data gen Add benchamrks --- _randomgen/.gitignore | 5 ++ .../src/xoroshiro128/xoroshiro128-benchmark.c | 28 +++++++ .../xoroshiro128/xoroshiro128-test-data-gen.c | 72 ++++++++++++++++++ .../src/xoroshiro128/xoroshiro128plus.orig.h | 5 ++ .../src/xorshift1024/xorshift1024-benchmark.c | 29 ++++++++ .../xorshift1024/xorshift1024-test-data-gen.c | 74 +++++++++++++++++++ .../src/xorshift1024/xorshift1024.orig.h | 7 ++ 7 files changed, 220 insertions(+) create mode 100644 _randomgen/core_prng/src/xoroshiro128/xoroshiro128-benchmark.c create mode 100644 _randomgen/core_prng/src/xoroshiro128/xoroshiro128-test-data-gen.c create mode 100644 _randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.h create mode 100644 _randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c create mode 100644 _randomgen/core_prng/src/xorshift1024/xorshift1024-test-data-gen.c create mode 100644 _randomgen/core_prng/src/xorshift1024/xorshift1024.orig.h diff --git a/_randomgen/.gitignore b/_randomgen/.gitignore index fd7f147c8885..6fef7580ddca 100644 --- a/_randomgen/.gitignore +++ b/_randomgen/.gitignore @@ -2,4 +2,9 @@ build/ *.egg-info/ *.pyd +*.pyc *.html +*.obj +*.exe +**/Random123 +settings.json diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-benchmark.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-benchmark.c new file mode 100644 index 000000000000..f23411cf8d5e --- /dev/null +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-benchmark.c @@ -0,0 +1,28 @@ +/* + * cl xoroshiro128-benchmark.c xoroshiro128plus.orig.c \ + * ../splitmix64/splitmix64.c /Ox + * Measure-Command { .\xoroshiro128-benchmark.exe } + * + * gcc -O3 xoroshiro128-benchmark.c xoroshiro128plus.orig.c \ + * ../splitmix64/splitmix64.c -o xoroshiro128-benchmark time + * ./xoroshiro128-benchmark + * + */ +#include "../splitmix64/splitmix64.h" +#include "xoroshiro128plus.orig.h" +#include +#include + +#define N 1000000000 + +int main() { + uint64_t sum = 0; + uint64_t seed = 0xDEADBEAF; + s[0] = splitmix64_next(&seed); + s[1] = splitmix64_next(&seed); + int i; + for (i = 0; i < N; i++) { + sum += next(); + } + printf("0x%" PRIx64 "\n", sum); +} diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-test-data-gen.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-test-data-gen.c new file mode 100644 index 000000000000..d49c87ce2109 --- /dev/null +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-test-data-gen.c @@ -0,0 +1,72 @@ +/* + * Generate testing csv files + * + * cl xoroshiro128-test-data-gen.c xoroshiro128plus.orig.c / + * ../splitmix64/splitmix64.c /Ox + * xoroshiro128-test-data-gen.exe * + * + * gcc xoroshiro128-test-data-gen.c xoroshiro128plus.orig.c / + * ../splitmix64/splitmix64.c -o xoroshiro128-test-data-gen + * ./xoroshiro128-test-data-gen + * + * Requres the Random123 directory containing header files to be located in the + * same directory (not included). + * + */ + +#include "../splitmix64/splitmix64.h" +#include "xoroshiro128plus.orig.h" +#include +#include + +#define N 1000 + +int main() { + uint64_t sum = 0; + uint64_t state, seed = 0xDEADBEAF; + state = seed; + int i; + for (i = 0; i < 2; i++) { + s[i] = splitmix64_next(&state); + } + uint64_t store[N]; + for (i = 0; i < N; i++) { + store[i] = next(); + } + + FILE *fp; + fp = fopen("xoroshiro128-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); + + seed = state = 0; + for (i = 0; i < 2; i++) { + s[i] = splitmix64_next(&state); + } + for (i = 0; i < N; i++) { + store[i] = next(); + } + fp = fopen("xoroshiro128-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.h b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.h new file mode 100644 index 000000000000..20c96fe04dec --- /dev/null +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.h @@ -0,0 +1,5 @@ +#include + +uint64_t s[2]; +uint64_t next(void); +void jump(void); diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c b/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c new file mode 100644 index 000000000000..1640c0177467 --- /dev/null +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c @@ -0,0 +1,29 @@ +/* + * cl xorshift1024-benchmark.c xorshift2014.orig.c ../splitmix64/splitmix64.c + * /Ox Measure-Command { .\xorshift1024-benchmark.exe } + * + * gcc -O3 xorshift1024-benchmark.c xorshift2014.orig.c / + * ../splitmix64/splitmix64.c -o xorshift1024-benchmark time + * ./xoroshiro128-benchmark + * + */ +#include "../splitmix64/splitmix64.h" +#include "xorshift1024.orig.h" +#include +#include + +#define N 1000000000 + +int main() { + uint64_t sum = 0; + uint64_t seed = 0xDEADBEAF; + int i; + for (i = 0; i < 16; i++) { + s[i] = splitmix64_next(&seed); + } + p = 0; + for (i = 0; i < N; i++) { + sum += next(); + } + printf("0x%" PRIx64 "\n", sum); +} diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024-test-data-gen.c b/_randomgen/core_prng/src/xorshift1024/xorshift1024-test-data-gen.c new file mode 100644 index 000000000000..aa0ebca33085 --- /dev/null +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024-test-data-gen.c @@ -0,0 +1,74 @@ +/* + * Generate testing csv files + * + * cl xorshift1024-test-data-gen.c xorshift1024.orig.c / + * ../splitmix64/splitmix64.c /Ox + * xorshift1024-test-data-gen.exe * + * + * gcc xorshift1024-test-data-gen.c xorshift1024.orig.c / + * ../splitmix64/splitmix64.c -o xorshift1024-test-data-gen + * ./xorshift1024-test-data-gen + * + * Requres the Random123 directory containing header files to be located in the + * same directory (not included). + * + */ + +#include "../splitmix64/splitmix64.h" +#include "xorshift1024.orig.h" +#include +#include + +#define N 1000 + +int main() { + uint64_t sum = 0; + uint64_t state, seed = 0xDEADBEAF; + state = seed; + int i; + for (i = 0; i < 16; i++) { + s[i] = splitmix64_next(&state); + } + p = 0; + uint64_t store[N]; + for (i = 0; i < N; i++) { + store[i] = next(); + } + + FILE *fp; + fp = fopen("xorshift1024-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); + + seed = state = 0; + for (i = 0; i < 16; i++) { + s[i] = splitmix64_next(&state); + } + p = 0; + for (i = 0; i < N; i++) { + store[i] = next(); + } + fp = fopen("xorshift1024-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.orig.h b/_randomgen/core_prng/src/xorshift1024/xorshift1024.orig.h new file mode 100644 index 000000000000..9b7597967677 --- /dev/null +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024.orig.h @@ -0,0 +1,7 @@ +#include +#include + +uint64_t s[16]; +int p; +uint64_t next(void); +void jump(void); From 21088ccd20c0627f00b25d3708f8713c877d3d3e Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 6 Mar 2018 19:02:56 +0000 Subject: [PATCH 038/279] TST: Add benchmarks and test data generators Add benchmarks for mt19937 and dsfmt Add test data generator for mt19937 --- .../core_prng/src/dsfmt/dsfmt-benchmark.c | 35 ++ .../core_prng/src/mt19937/mt19937-benchmark.c | 23 + .../src/mt19937/mt19937-test-data-gen.c | 66 ++ _randomgen/core_prng/src/mt19937/randomkit.c | 580 ++++++++++++++++++ _randomgen/core_prng/src/mt19937/randomkit.h | 223 +++++++ .../src/xorshift1024/xorshift1024-benchmark.c | 6 +- 6 files changed, 931 insertions(+), 2 deletions(-) create mode 100644 _randomgen/core_prng/src/dsfmt/dsfmt-benchmark.c create mode 100644 _randomgen/core_prng/src/mt19937/mt19937-benchmark.c create mode 100644 _randomgen/core_prng/src/mt19937/mt19937-test-data-gen.c create mode 100644 _randomgen/core_prng/src/mt19937/randomkit.c create mode 100644 _randomgen/core_prng/src/mt19937/randomkit.h diff --git a/_randomgen/core_prng/src/dsfmt/dsfmt-benchmark.c b/_randomgen/core_prng/src/dsfmt/dsfmt-benchmark.c new file mode 100644 index 000000000000..47eae7e1c286 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dsfmt-benchmark.c @@ -0,0 +1,35 @@ +/* + * + * cl dsfmt-benchmark.c dSFMT.c /Ox -DHAVE_SSE2 + * Measure-Command { .\dsfmt-benchmark.exe } + * + * + */ +#include "dSFMT.h" +#include + +#define N 1000000000 + +int main() { + int i, j; + uint32_t seed = 0xDEADBEAF; + uint64_t total = 0, sum = 0; + dsfmt_t state; + double buffer[DSFMT_N64]; + + uint64_t out; + uint64_t *tmp; + dsfmt_init_gen_rand(&state, seed); + for (i = 0; i < N / (DSFMT_N64 / 2); i++) { + dsfmt_fill_array_close_open(&state, &buffer[0], DSFMT_N64); + for (j = 0; j < DSFMT_N64; j += 2) { + tmp = (uint64_t *)&buffer[j]; + out = (*tmp >> 16) << 32; + tmp = (uint64_t *)&buffer[j + 1]; + out |= (*tmp >> 16) & 0xffffffff; + sum += out; + total++; + } + } + printf("0x%" PRIx64 ", total: %" PRIu64 "\n", sum, total); +} diff --git a/_randomgen/core_prng/src/mt19937/mt19937-benchmark.c b/_randomgen/core_prng/src/mt19937/mt19937-benchmark.c new file mode 100644 index 000000000000..8f6ce20ac40f --- /dev/null +++ b/_randomgen/core_prng/src/mt19937/mt19937-benchmark.c @@ -0,0 +1,23 @@ +/* + * cl mt19937-benchmark.c mt19937.c /Ox + * Measure-Command { .\mt19937-benchmark.exe } + * + * gcc mt19937-benchmark.c mt19937.c -O3 -o mt19937-benchmark + * time ./mt19937-benchmark + */ +#include "mt19937.h" +#include + +#define N 1000000000 + +int main() { + int i; + uint32_t seed = 0x0; + uint64_t sum; + mt19937_state state; + mt19937_seed(&state, seed); + for (i = 0; i < N; i++) { + sum += mt19937_next64(&state); + } + printf("0x%" PRIx64 "\n", sum); +} diff --git a/_randomgen/core_prng/src/mt19937/mt19937-test-data-gen.c b/_randomgen/core_prng/src/mt19937/mt19937-test-data-gen.c new file mode 100644 index 000000000000..ef98be160b55 --- /dev/null +++ b/_randomgen/core_prng/src/mt19937/mt19937-test-data-gen.c @@ -0,0 +1,66 @@ +/* + * Generate testing csv files + * + * cl mt19937-test-data-gen.c randomkit.c + * -IC:\Anaconda\Lib\site-packages\numpy\core\include -IC:\Anaconda\include + * Advapi32.lib Kernel32.lib C:\Anaconda\libs\python36.lib -DRK_NO_WINCRYPT=1 + * + */ +#include "randomkit.h" +#include +#include + +#define N 1000 + +int main() { + uint64_t sum = 0; + uint64_t temp; + uint32_t seed = 0xDEADBEAF; + int i; + rk_state state; + rk_seed(seed, &state); + uint64_t store[N]; + for (i = 0; i < N; i++) { + temp = 0; + temp = (uint64_t)rk_random(&state) << 32; + temp |= rk_random(&state); + store[i] = temp; + } + + FILE *fp; + fp = fopen("mt19937-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx32 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); + + seed = 0; + rk_seed(seed, &state); + for (i = 0; i < N; i++) { + temp = 0; + temp = (uint64_t)rk_random(&state) << 32; + temp |= rk_random(&state); + store[i] = temp; + } + fp = fopen("mt19937-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx32 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); +} diff --git a/_randomgen/core_prng/src/mt19937/randomkit.c b/_randomgen/core_prng/src/mt19937/randomkit.c new file mode 100644 index 000000000000..17f10a288f39 --- /dev/null +++ b/_randomgen/core_prng/src/mt19937/randomkit.c @@ -0,0 +1,580 @@ +/* Random kit 1.3 */ + +/* + * Copyright (c) 2003-2005, Jean-Sebastien Roy (js@jeannot.org) + * + * The rk_random and rk_seed functions algorithms and the original design of + * the Mersenne Twister RNG: + * + * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Original algorithm for the implementation of rk_interval function from + * Richard J. Wagner's implementation of the Mersenne Twister RNG, optimised by + * Magnus Jonsson. + * + * Constants used in the rk_double implementation by Isaku Wada. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* static char const rcsid[] = + "@(#) $Jeannot: randomkit.c,v 1.28 2005/07/21 22:14:09 js Exp $"; */ + +#ifdef _WIN32 +/* + * Windows + * XXX: we have to use this ugly defined(__GNUC__) because it is not easy to + * detect the compiler used in distutils itself + */ +#if (defined(__GNUC__) && defined(NPY_NEEDS_MINGW_TIME_WORKAROUND)) + +/* + * FIXME: ideally, we should set this to the real version of MSVCRT. We need + * something higher than 0x601 to enable _ftime64 and co + */ +#define __MSVCRT_VERSION__ 0x0700 +#include +#include + + +/* + * mingw msvcr lib import wrongly export _ftime, which does not exist in the + * actual msvc runtime for version >= 8; we make it an alias to _ftime64, which + * is available in those versions of the runtime + */ +#define _FTIME(x) _ftime64((x)) +#else +#include +#include + +#define _FTIME(x) _ftime((x)) +#endif + +#ifndef RK_NO_WINCRYPT +/* Windows crypto */ +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif +#include +#include + +#endif + +/* + * Do not move this include. randomkit.h must be included + * after windows timeb.h is included. + */ +#include "randomkit.h" + +#else +/* Unix */ +#include "randomkit.h" +#include +#include +#include + +#endif + +#include +#include +#include +#include +#include +#include +#include + + +#ifndef RK_DEV_URANDOM +#define RK_DEV_URANDOM "/dev/urandom" +#endif + +#ifndef RK_DEV_RANDOM +#define RK_DEV_RANDOM "/dev/random" +#endif + +char *rk_strerror[RK_ERR_MAX] = {"no error", "random device unvavailable"}; + +/* static functions */ +static unsigned long rk_hash(unsigned long key); + +void rk_seed(unsigned long seed, rk_state *state) { + int pos; + seed &= 0xffffffffUL; + + /* Knuth's PRNG as used in the Mersenne Twister reference implementation */ + for (pos = 0; pos < RK_STATE_LEN; pos++) { + state->key[pos] = seed; + seed = (1812433253UL * (seed ^ (seed >> 30)) + pos + 1) & 0xffffffffUL; + } + state->pos = RK_STATE_LEN; + state->gauss = 0; + state->has_gauss = 0; + state->has_binomial = 0; +} + +/* Thomas Wang 32 bits integer hash function */ +unsigned long rk_hash(unsigned long key) { + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + return key; +} + +rk_error rk_randomseed(rk_state *state) { +#ifndef _WIN32 + struct timeval tv; +#else + struct _timeb tv; +#endif + int i; + + if (rk_devfill(state->key, sizeof(state->key), 0) == RK_NOERR) { + /* ensures non-zero key */ + state->key[0] |= 0x80000000UL; + state->pos = RK_STATE_LEN; + state->gauss = 0; + state->has_gauss = 0; + state->has_binomial = 0; + + for (i = 0; i < 624; i++) { + state->key[i] &= 0xffffffffUL; + } + return RK_NOERR; + } + +#ifndef _WIN32 + gettimeofday(&tv, NULL); + rk_seed(rk_hash(getpid()) ^ rk_hash(tv.tv_sec) ^ rk_hash(tv.tv_usec) ^ + rk_hash(clock()), + state); +#else + _FTIME(&tv); + rk_seed(rk_hash(tv.time) ^ rk_hash(tv.millitm) ^ rk_hash(clock()), state); +#endif + + return RK_ENODEV; +} + +/* Magic Mersenne Twister constants */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL +#define UPPER_MASK 0x80000000UL +#define LOWER_MASK 0x7fffffffUL + +/* + * Slightly optimised reference implementation of the Mersenne Twister + * Note that regardless of the precision of long, only 32 bit random + * integers are produced + */ +unsigned long rk_random(rk_state *state) { + unsigned long y; + + if (state->pos == RK_STATE_LEN) { + int i; + + for (i = 0; i < N - M; i++) { + y = (state->key[i] & UPPER_MASK) | (state->key[i + 1] & LOWER_MASK); + state->key[i] = state->key[i + M] ^ (y >> 1) ^ (-(y & 1) & MATRIX_A); + } + for (; i < N - 1; i++) { + y = (state->key[i] & UPPER_MASK) | (state->key[i + 1] & LOWER_MASK); + state->key[i] = + state->key[i + (M - N)] ^ (y >> 1) ^ (-(y & 1) & MATRIX_A); + } + y = (state->key[N - 1] & UPPER_MASK) | (state->key[0] & LOWER_MASK); + state->key[N - 1] = state->key[M - 1] ^ (y >> 1) ^ (-(y & 1) & MATRIX_A); + + state->pos = 0; + } + y = state->key[state->pos++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + +/* + * Returns an unsigned 64 bit random integer. + */ +NPY_INLINE static npy_uint64 rk_uint64(rk_state *state) { + npy_uint64 upper = (npy_uint64)rk_random(state) << 32; + npy_uint64 lower = (npy_uint64)rk_random(state); + return upper | lower; +} + +/* + * Returns an unsigned 32 bit random integer. + */ +NPY_INLINE static npy_uint32 rk_uint32(rk_state *state) { + return (npy_uint32)rk_random(state); +} + +/* + * Fills an array with cnt random npy_uint64 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void rk_random_uint64(npy_uint64 off, npy_uint64 rng, npy_intp cnt, + npy_uint64 *out, rk_state *state) { + npy_uint64 val, mask = rng; + npy_intp i; + + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; + mask |= mask >> 32; + + for (i = 0; i < cnt; i++) { + if (rng <= 0xffffffffUL) { + while ((val = (rk_uint32(state) & mask)) > rng) + ; + } else { + while ((val = (rk_uint64(state) & mask)) > rng) + ; + } + out[i] = off + val; + } +} + +/* + * Fills an array with cnt random npy_uint32 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void rk_random_uint32(npy_uint32 off, npy_uint32 rng, npy_intp cnt, + npy_uint32 *out, rk_state *state) { + npy_uint32 val, mask = rng; + npy_intp i; + + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; + + for (i = 0; i < cnt; i++) { + while ((val = (rk_uint32(state) & mask)) > rng) + ; + out[i] = off + val; + } +} + +/* + * Fills an array with cnt random npy_uint16 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void rk_random_uint16(npy_uint16 off, npy_uint16 rng, npy_intp cnt, + npy_uint16 *out, rk_state *state) { + npy_uint16 val, mask = rng; + npy_intp i; + npy_uint32 buf; + int bcnt = 0; + + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + + for (i = 0; i < cnt; i++) { + do { + if (!bcnt) { + buf = rk_uint32(state); + bcnt = 1; + } else { + buf >>= 16; + bcnt--; + } + val = (npy_uint16)buf & mask; + } while (val > rng); + out[i] = off + val; + } +} + +/* + * Fills an array with cnt random npy_uint8 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void rk_random_uint8(npy_uint8 off, npy_uint8 rng, npy_intp cnt, npy_uint8 *out, + rk_state *state) { + npy_uint8 val, mask = rng; + npy_intp i; + npy_uint32 buf; + int bcnt = 0; + + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + + for (i = 0; i < cnt; i++) { + do { + if (!bcnt) { + buf = rk_uint32(state); + bcnt = 3; + } else { + buf >>= 8; + bcnt--; + } + val = (npy_uint8)buf & mask; + } while (val > rng); + out[i] = off + val; + } +} + +/* + * Fills an array with cnt random npy_bool between off and off + rng + * inclusive. + */ +void rk_random_bool(npy_bool off, npy_bool rng, npy_intp cnt, npy_bool *out, + rk_state *state) { + npy_intp i; + npy_uint32 buf; + int bcnt = 0; + + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + /* If we reach here rng and mask are one and off is zero */ + assert(rng == 1 && off == 0); + for (i = 0; i < cnt; i++) { + if (!bcnt) { + buf = rk_uint32(state); + bcnt = 31; + } else { + buf >>= 1; + bcnt--; + } + out[i] = (buf & 0x00000001) != 0; + } +} + +long rk_long(rk_state *state) { return rk_ulong(state) >> 1; } + +unsigned long rk_ulong(rk_state *state) { +#if ULONG_MAX <= 0xffffffffUL + return rk_random(state); +#else + return (rk_random(state) << 32) | (rk_random(state)); +#endif +} + +unsigned long rk_interval(unsigned long max, rk_state *state) { + unsigned long mask = max, value; + + if (max == 0) { + return 0; + } + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; +#if ULONG_MAX > 0xffffffffUL + mask |= mask >> 32; +#endif + + /* Search a random value in [0..mask] <= max */ +#if ULONG_MAX > 0xffffffffUL + if (max <= 0xffffffffUL) { + while ((value = (rk_random(state) & mask)) > max) + ; + } else { + while ((value = (rk_ulong(state) & mask)) > max) + ; + } +#else + while ((value = (rk_ulong(state) & mask)) > max) + ; +#endif + return value; +} + +double rk_double(rk_state *state) { + /* shifts : 67108864 = 0x4000000, 9007199254740992 = 0x20000000000000 */ + long a = rk_random(state) >> 5, b = rk_random(state) >> 6; + return (a * 67108864.0 + b) / 9007199254740992.0; +} + +void rk_fill(void *buffer, size_t size, rk_state *state) { + unsigned long r; + unsigned char *buf = buffer; + + for (; size >= 4; size -= 4) { + r = rk_random(state); + *(buf++) = r & 0xFF; + *(buf++) = (r >> 8) & 0xFF; + *(buf++) = (r >> 16) & 0xFF; + *(buf++) = (r >> 24) & 0xFF; + } + + if (!size) { + return; + } + r = rk_random(state); + for (; size; r >>= 8, size--) { + *(buf++) = (unsigned char)(r & 0xFF); + } +} + +rk_error rk_devfill(void *buffer, size_t size, int strong) { +#ifndef _WIN32 + FILE *rfile; + int done; + + if (strong) { + rfile = fopen(RK_DEV_RANDOM, "rb"); + } else { + rfile = fopen(RK_DEV_URANDOM, "rb"); + } + if (rfile == NULL) { + return RK_ENODEV; + } + done = fread(buffer, size, 1, rfile); + fclose(rfile); + if (done) { + return RK_NOERR; + } +#else + +#ifndef RK_NO_WINCRYPT + HCRYPTPROV hCryptProv; + BOOL done; + + if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT) || + !hCryptProv) { + return RK_ENODEV; + } + done = CryptGenRandom(hCryptProv, size, (unsigned char *)buffer); + CryptReleaseContext(hCryptProv, 0); + if (done) { + return RK_NOERR; + } +#endif + +#endif + return RK_ENODEV; +} + +rk_error rk_altfill(void *buffer, size_t size, int strong, rk_state *state) { + rk_error err; + + err = rk_devfill(buffer, size, strong); + if (err) { + rk_fill(buffer, size, state); + } + return err; +} + +double rk_gauss(rk_state *state) { + if (state->has_gauss) { + const double tmp = state->gauss; + state->gauss = 0; + state->has_gauss = 0; + return tmp; + } else { + double f, x1, x2, r2; + + do { + x1 = 2.0 * rk_double(state) - 1.0; + x2 = 2.0 * rk_double(state) - 1.0; + r2 = x1 * x1 + x2 * x2; + } while (r2 >= 1.0 || r2 == 0.0); + + /* Box-Muller transform */ + f = sqrt(-2.0 * log(r2) / r2); + /* Keep for next call */ + state->gauss = f * x1; + state->has_gauss = 1; + return f * x2; + } +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/mt19937/randomkit.h b/_randomgen/core_prng/src/mt19937/randomkit.h new file mode 100644 index 000000000000..f57f50ae360e --- /dev/null +++ b/_randomgen/core_prng/src/mt19937/randomkit.h @@ -0,0 +1,223 @@ +/* Random kit 1.3 */ + +/* + * Copyright (c) 2003-2005, Jean-Sebastien Roy (js@jeannot.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* @(#) $Jeannot: randomkit.h,v 1.24 2005/07/21 22:14:09 js Exp $ */ + +/* + * Typical use: + * + * { + * rk_state state; + * unsigned long seed = 1, random_value; + * + * rk_seed(seed, &state); // Initialize the RNG + * ... + * random_value = rk_random(&state); // Generate random values in [0..RK_MAX] + * } + * + * Instead of rk_seed, you can use rk_randomseed which will get a random seed + * from /dev/urandom (or the clock, if /dev/urandom is unavailable): + * + * { + * rk_state state; + * unsigned long random_value; + * + * rk_randomseed(&state); // Initialize the RNG with a random seed + * ... + * random_value = rk_random(&state); // Generate random values in [0..RK_MAX] + * } + */ + +/* + * Useful macro: + * RK_DEV_RANDOM: the device used for random seeding. + * defaults to "/dev/urandom" + */ + +#ifndef _RANDOMKIT_ +#define _RANDOMKIT_ + +#include +#include + +#define RK_STATE_LEN 624 + +typedef struct rk_state_ { + unsigned long key[RK_STATE_LEN]; + int pos; + int has_gauss; /* !=0: gauss contains a gaussian deviate */ + double gauss; + + /* The rk_state structure has been extended to store the following + * information for the binomial generator. If the input values of n or p + * are different than nsave and psave, then the other parameters will be + * recomputed. RTK 2005-09-02 */ + + int has_binomial; /* !=0: following parameters initialized for + binomial */ + double psave; + long nsave; + double r; + double q; + double fm; + long m; + double p1; + double xm; + double xl; + double xr; + double c; + double laml; + double lamr; + double p2; + double p3; + double p4; + +} rk_state; + +typedef enum { + RK_NOERR = 0, /* no error */ + RK_ENODEV = 1, /* no RK_DEV_RANDOM device */ + RK_ERR_MAX = 2 +} rk_error; + +/* error strings */ +extern char *rk_strerror[RK_ERR_MAX]; + +/* Maximum generated random value */ +#define RK_MAX 0xFFFFFFFFUL + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Initialize the RNG state using the given seed. + */ +extern void rk_seed(unsigned long seed, rk_state *state); + +/* + * Initialize the RNG state using a random seed. + * Uses /dev/random or, when unavailable, the clock (see randomkit.c). + * Returns RK_NOERR when no errors occurs. + * Returns RK_ENODEV when the use of RK_DEV_RANDOM failed (for example because + * there is no such device). In this case, the RNG was initialized using the + * clock. + */ +extern rk_error rk_randomseed(rk_state *state); + +/* + * Returns a random unsigned long between 0 and RK_MAX inclusive + */ +extern unsigned long rk_random(rk_state *state); + +/* + * Returns a random long between 0 and LONG_MAX inclusive + */ +extern long rk_long(rk_state *state); + +/* + * Returns a random unsigned long between 0 and ULONG_MAX inclusive + */ +extern unsigned long rk_ulong(rk_state *state); + +/* + * Returns a random unsigned long between 0 and max inclusive. + */ +extern unsigned long rk_interval(unsigned long max, rk_state *state); + +/* + * Fills an array with cnt random npy_uint64 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +extern void rk_random_uint64(npy_uint64 off, npy_uint64 rng, npy_intp cnt, + npy_uint64 *out, rk_state *state); + +/* + * Fills an array with cnt random npy_uint32 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +extern void rk_random_uint32(npy_uint32 off, npy_uint32 rng, npy_intp cnt, + npy_uint32 *out, rk_state *state); + +/* + * Fills an array with cnt random npy_uint16 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +extern void rk_random_uint16(npy_uint16 off, npy_uint16 rng, npy_intp cnt, + npy_uint16 *out, rk_state *state); + +/* + * Fills an array with cnt random npy_uint8 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +extern void rk_random_uint8(npy_uint8 off, npy_uint8 rng, npy_intp cnt, + npy_uint8 *out, rk_state *state); + +/* + * Fills an array with cnt random npy_bool between off and off + rng + * inclusive. It is assumed tha npy_bool as the same size as npy_uint8. + */ +extern void rk_random_bool(npy_bool off, npy_bool rng, npy_intp cnt, + npy_bool *out, rk_state *state); + +/* + * Returns a random double between 0.0 and 1.0, 1.0 excluded. + */ +extern double rk_double(rk_state *state); + +/* + * fill the buffer with size random bytes + */ +extern void rk_fill(void *buffer, size_t size, rk_state *state); + +/* + * fill the buffer with randombytes from the random device + * Returns RK_ENODEV if the device is unavailable, or RK_NOERR if it is + * On Unix, if strong is defined, RK_DEV_RANDOM is used. If not, RK_DEV_URANDOM + * is used instead. This parameter has no effect on Windows. + * Warning: on most unixes RK_DEV_RANDOM will wait for enough entropy to answer + * which can take a very long time on quiet systems. + */ +extern rk_error rk_devfill(void *buffer, size_t size, int strong); + +/* + * fill the buffer using rk_devfill if the random device is available and using + * rk_fill if it is not + * parameters have the same meaning as rk_fill and rk_devfill + * Returns RK_ENODEV if the device is unavailable, or RK_NOERR if it is + */ +extern rk_error rk_altfill(void *buffer, size_t size, int strong, + rk_state *state); + +/* + * return a random gaussian deviate with variance unity and zero mean. + */ +extern double rk_gauss(rk_state *state); + +#ifdef __cplusplus +} +#endif + +#endif /* _RANDOMKIT_ */ \ No newline at end of file diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c b/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c index 1640c0177467..b4229d2f770e 100644 --- a/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c @@ -1,6 +1,8 @@ /* - * cl xorshift1024-benchmark.c xorshift2014.orig.c ../splitmix64/splitmix64.c - * /Ox Measure-Command { .\xorshift1024-benchmark.exe } + * cl xorshift1024-benchmark.c xorshift2014.orig.c + * ../splitmix64/splitmix64.c /Ox + * + * Measure-Command { .\xorshift1024-benchmark.exe } * * gcc -O3 xorshift1024-benchmark.c xorshift2014.orig.c / * ../splitmix64/splitmix64.c -o xorshift1024-benchmark time From 301af3da7a6211c02da937a8c8b639c7b6f97868 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 6 Mar 2018 22:55:58 +0000 Subject: [PATCH 039/279] TST: Add pcg64 test and benchmark Add test and benchmark for pcg64 --- .../core_prng/src/pcg64/pcg64-benchmark.c | 30 + .../core_prng/src/pcg64/pcg64-test-data-gen.c | 73 + _randomgen/core_prng/src/pcg64/pcg64.orig.h | 2025 +++++++++++++++++ 3 files changed, 2128 insertions(+) create mode 100644 _randomgen/core_prng/src/pcg64/pcg64-benchmark.c create mode 100644 _randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c create mode 100644 _randomgen/core_prng/src/pcg64/pcg64.orig.h diff --git a/_randomgen/core_prng/src/pcg64/pcg64-benchmark.c b/_randomgen/core_prng/src/pcg64/pcg64-benchmark.c new file mode 100644 index 000000000000..38a75e38a4f7 --- /dev/null +++ b/_randomgen/core_prng/src/pcg64/pcg64-benchmark.c @@ -0,0 +1,30 @@ +/* + * cl pcg64-benchmark.c pcg64.c ../splitmix64/splitmix64.c /Ox + * Measure-Command { .\xoroshiro128-benchmark.exe } + * + * gcc pcg64-benchmark.c pcg64.c ../splitmix64/splitmix64.c -O3 -o + * pcg64-benchmark + * time ./pcg64-benchmark + */ +#include "../splitmix64/splitmix64.h" +#include "pcg64.h" +#include +#include + +#define N 1000000000 + +int main() { + pcg64_random_t rng; + uint64_t sum = 0; + uint64_t seed = 0xDEADBEAF; + int i; + rng.state.high = splitmix64_next(&seed); + rng.state.low = splitmix64_next(&seed); + rng.inc.high = 0; + rng.inc.low = 1; + + for (i = 0; i < N; i++) { + sum += pcg64_random_r(&rng); + } + printf("0x%" PRIx64 "\n", sum); +} diff --git a/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c b/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c new file mode 100644 index 000000000000..1671b42ae8ef --- /dev/null +++ b/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c @@ -0,0 +1,73 @@ +/* + * Generate testing csv files + * + * GCC only + * + * gcc xoroshiro128-test-data-gen.c xoroshiro128plus.orig.c / + * ../splitmix64/splitmix64.c -o xoroshiro128-test-data-gen + * ./xoroshiro128-test-data-gen + * + */ + +#include "../splitmix64/splitmix64.h" +#include "pcg64.orig.h" +#include +#include + +#define N 1000 + +typedef uint64_t __uint128_t; + +int main() { + pcg64_random_t c; + uint64_t state, seed = 0xDEADBEAF; + state = seed; + __uint128_t temp; + rng.state = (__uint128_t)splitmix64_next(&state) << 64; + rng.state |= splitmix64_next(&state); + rng.inc = (__uint128_t)1; + int i; + uint64_t store[N]; + for (i = 0; i < N; i++) { + store[i] = pcg64_random_r(&rng); + ; + } + + FILE *fp; + fp = fopen("pcg64-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); + + uint64_t state, seed = 0; + state = seed; + rng.state = + (__uint128_t)splitmix64_next(&state) << 64 | splitmix64_next(&state); + rng.inc = (__uint128_t)1; + for (i = 0; i < N; i++) { + store[i] = pcg64_random_r(&rng); + ; + } + fp = fopen("xoroshiro128-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/pcg64/pcg64.orig.h b/_randomgen/core_prng/src/pcg64/pcg64.orig.h new file mode 100644 index 000000000000..645025acb01e --- /dev/null +++ b/_randomgen/core_prng/src/pcg64/pcg64.orig.h @@ -0,0 +1,2025 @@ +/* + * PCG Random Number Generation for C. + * + * Copyright 2014 Melissa O'Neill + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + +/* + * This code is derived from the canonical C++ PCG implementation, which + * has many additional features and is preferable if you can use C++ in + * your project. + * + * Much of the derivation was performed mechanically. In particular, the + * output functions were generated by compiling the C++ output functions + * into LLVM bitcode and then transforming that using the LLVM C backend + * (from https://github.com/draperlaboratory/llvm-cbe), and then + * postprocessing and hand editing the output. + * + * Much of the remaining code was generated by C-preprocessor metaprogramming. + */ + +#ifndef PCG_VARIANTS_H_INCLUDED +#define PCG_VARIANTS_H_INCLUDED 1 + +#include + +#if __SIZEOF_INT128__ +typedef __uint128_t pcg128_t; +#define PCG_128BIT_CONSTANT(high, low) ((((pcg128_t)high) << 64) + low) +#define PCG_HAS_128BIT_OPS 1 +#endif + +#if __GNUC_GNU_INLINE__ && !defined(__cplusplus) +#error Nonstandard GNU inlining semantics. Compile with -std=c99 or better. +// We could instead use macros PCG_INLINE and PCG_EXTERN_INLINE +// but better to just reject ancient C code. +#endif + +#if __cplusplus +extern "C" { +#endif + +/* + * Rotate helper functions. + */ + +inline uint8_t pcg_rotr_8(uint8_t value, unsigned int rot) { +/* Unfortunately, clang is kinda pathetic when it comes to properly + * recognizing idiomatic rotate code, so for clang we actually provide + * assembler directives (enabled with PCG_USE_INLINE_ASM). Boo, hiss. + */ +#if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) + asm("rorb %%cl, %0" : "=r"(value) : "0"(value), "c"(rot)); + return value; +#else + return (value >> rot) | (value << ((-rot) & 7)); +#endif +} + +inline uint16_t pcg_rotr_16(uint16_t value, unsigned int rot) { +#if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) + asm("rorw %%cl, %0" : "=r"(value) : "0"(value), "c"(rot)); + return value; +#else + return (value >> rot) | (value << ((-rot) & 15)); +#endif +} + +inline uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) { +#if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) + asm("rorl %%cl, %0" : "=r"(value) : "0"(value), "c"(rot)); + return value; +#else + return (value >> rot) | (value << ((-rot) & 31)); +#endif +} + +inline uint64_t pcg_rotr_64(uint64_t value, unsigned int rot) { +#if 0 && PCG_USE_INLINE_ASM && __clang__ && __x86_64__ + // For whatever reason, clang actually *does* generate rotq by + // itself, so we don't need this code. + asm ("rorq %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +#else + return (value >> rot) | (value << ((-rot) & 63)); +#endif +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_rotr_128(pcg128_t value, unsigned int rot) { + return (value >> rot) | (value << ((-rot) & 127)); +} +#endif + +/* + * Output functions. These are the core of the PCG generation scheme. + */ + +// XSH RS + +inline uint8_t pcg_output_xsh_rs_16_8(uint16_t state) { + return (uint8_t)(((state >> 7u) ^ state) >> ((state >> 14u) + 3u)); +} + +inline uint16_t pcg_output_xsh_rs_32_16(uint32_t state) { + return (uint16_t)(((state >> 11u) ^ state) >> ((state >> 30u) + 11u)); +} + +inline uint32_t pcg_output_xsh_rs_64_32(uint64_t state) { + + return (uint32_t)(((state >> 22u) ^ state) >> ((state >> 61u) + 22u)); +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_output_xsh_rs_128_64(pcg128_t state) { + return (uint64_t)(((state >> 43u) ^ state) >> ((state >> 124u) + 45u)); +} +#endif + +// XSH RR + +inline uint8_t pcg_output_xsh_rr_16_8(uint16_t state) { + return pcg_rotr_8(((state >> 5u) ^ state) >> 5u, state >> 13u); +} + +inline uint16_t pcg_output_xsh_rr_32_16(uint32_t state) { + return pcg_rotr_16(((state >> 10u) ^ state) >> 12u, state >> 28u); +} + +inline uint32_t pcg_output_xsh_rr_64_32(uint64_t state) { + return pcg_rotr_32(((state >> 18u) ^ state) >> 27u, state >> 59u); +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_output_xsh_rr_128_64(pcg128_t state) { + return pcg_rotr_64(((state >> 29u) ^ state) >> 58u, state >> 122u); +} +#endif + +// RXS M XS + +inline uint8_t pcg_output_rxs_m_xs_8_8(uint8_t state) { + uint8_t word = ((state >> ((state >> 6u) + 2u)) ^ state) * 217u; + return (word >> 6u) ^ word; +} + +inline uint16_t pcg_output_rxs_m_xs_16_16(uint16_t state) { + uint16_t word = ((state >> ((state >> 13u) + 3u)) ^ state) * 62169u; + return (word >> 11u) ^ word; +} + +inline uint32_t pcg_output_rxs_m_xs_32_32(uint32_t state) { + uint32_t word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +inline uint64_t pcg_output_rxs_m_xs_64_64(uint64_t state) { + uint64_t word = + ((state >> ((state >> 59u) + 5u)) ^ state) * 12605985483714917081ull; + return (word >> 43u) ^ word; +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_output_rxs_m_xs_128_128(pcg128_t state) { + pcg128_t word = + ((state >> ((state >> 122u) + 6u)) ^ state) * + (PCG_128BIT_CONSTANT(17766728186571221404ULL, 12605985483714917081ULL)); + // 327738287884841127335028083622016905945 + return (word >> 86u) ^ word; +} +#endif + +// XSL RR (only defined for >= 64 bits) + +inline uint32_t pcg_output_xsl_rr_64_32(uint64_t state) { + return pcg_rotr_32(((uint32_t)(state >> 32u)) ^ (uint32_t)state, + state >> 59u); +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) { + return pcg_rotr_64(((uint64_t)(state >> 64u)) ^ (uint64_t)state, + state >> 122u); +} +#endif + +// XSL RR RR (only defined for >= 64 bits) + +inline uint64_t pcg_output_xsl_rr_rr_64_64(uint64_t state) { + uint32_t rot1 = (uint32_t)(state >> 59u); + uint32_t high = (uint32_t)(state >> 32u); + uint32_t low = (uint32_t)state; + uint32_t xored = high ^ low; + uint32_t newlow = pcg_rotr_32(xored, rot1); + uint32_t newhigh = pcg_rotr_32(high, newlow & 31u); + return (((uint64_t)newhigh) << 32u) | newlow; +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_output_xsl_rr_rr_128_128(pcg128_t state) { + uint32_t rot1 = (uint32_t)(state >> 122u); + uint64_t high = (uint64_t)(state >> 64u); + uint64_t low = (uint64_t)state; + uint64_t xored = high ^ low; + uint64_t newlow = pcg_rotr_64(xored, rot1); + uint64_t newhigh = pcg_rotr_64(high, newlow & 63u); + return (((pcg128_t)newhigh) << 64u) | newlow; +} +#endif + +#define PCG_DEFAULT_MULTIPLIER_8 141U +#define PCG_DEFAULT_MULTIPLIER_16 12829U +#define PCG_DEFAULT_MULTIPLIER_32 747796405U +#define PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL + +#define PCG_DEFAULT_INCREMENT_8 77U +#define PCG_DEFAULT_INCREMENT_16 47989U +#define PCG_DEFAULT_INCREMENT_32 2891336453U +#define PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL + +#if PCG_HAS_128BIT_OPS +#define PCG_DEFAULT_MULTIPLIER_128 \ + PCG_128BIT_CONSTANT(2549297995355413924ULL, 4865540595714422341ULL) +#define PCG_DEFAULT_INCREMENT_128 \ + PCG_128BIT_CONSTANT(6364136223846793005ULL, 1442695040888963407ULL) +#endif + +/* + * Static initialization constants (if you can't call srandom for some + * bizarre reason). + */ + +#define PCG_STATE_ONESEQ_8_INITIALIZER \ + { 0xd7U } +#define PCG_STATE_ONESEQ_16_INITIALIZER \ + { 0x20dfU } +#define PCG_STATE_ONESEQ_32_INITIALIZER \ + { 0x46b56677U } +#define PCG_STATE_ONESEQ_64_INITIALIZER \ + { 0x4d595df4d0f33173ULL } +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_ONESEQ_128_INITIALIZER \ + { PCG_128BIT_CONSTANT(0xb8dc10e158a92392ULL, 0x98046df007ec0a53ULL) } +#endif + +#define PCG_STATE_UNIQUE_8_INITIALIZER PCG_STATE_ONESEQ_8_INITIALIZER +#define PCG_STATE_UNIQUE_16_INITIALIZER PCG_STATE_ONESEQ_16_INITIALIZER +#define PCG_STATE_UNIQUE_32_INITIALIZER PCG_STATE_ONESEQ_32_INITIALIZER +#define PCG_STATE_UNIQUE_64_INITIALIZER PCG_STATE_ONESEQ_64_INITIALIZER +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_UNIQUE_128_INITIALIZER PCG_STATE_ONESEQ_128_INITIALIZER +#endif + +#define PCG_STATE_MCG_8_INITIALIZER \ + { 0xe5U } +#define PCG_STATE_MCG_16_INITIALIZER \ + { 0xa5e5U } +#define PCG_STATE_MCG_32_INITIALIZER \ + { 0xd15ea5e5U } +#define PCG_STATE_MCG_64_INITIALIZER \ + { 0xcafef00dd15ea5e5ULL } +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_MCG_128_INITIALIZER \ + { PCG_128BIT_CONSTANT(0x0000000000000000ULL, 0xcafef00dd15ea5e5ULL) } +#endif + +#define PCG_STATE_SETSEQ_8_INITIALIZER \ + { 0x9bU, 0xdbU } +#define PCG_STATE_SETSEQ_16_INITIALIZER \ + { 0xe39bU, 0x5bdbU } +#define PCG_STATE_SETSEQ_32_INITIALIZER \ + { 0xec02d89bU, 0x94b95bdbU } +#define PCG_STATE_SETSEQ_64_INITIALIZER \ + { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL } +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_SETSEQ_128_INITIALIZER \ + { \ + PCG_128BIT_CONSTANT(0x979c9a98d8462005ULL, 0x7d3e9cb6cfe0549bULL) \ + , PCG_128BIT_CONSTANT(0x0000000000000001ULL, 0xda3e39cb94b95bdbULL) \ + } +#endif + +/* Representations for the oneseq, mcg, and unique variants */ + +struct pcg_state_8 { + uint8_t state; +}; + +struct pcg_state_16 { + uint16_t state; +}; + +struct pcg_state_32 { + uint32_t state; +}; + +struct pcg_state_64 { + uint64_t state; +}; + +#if PCG_HAS_128BIT_OPS +struct pcg_state_128 { + pcg128_t state; +}; +#endif + +/* Representations setseq variants */ + +struct pcg_state_setseq_8 { + uint8_t state; + uint8_t inc; +}; + +struct pcg_state_setseq_16 { + uint16_t state; + uint16_t inc; +}; + +struct pcg_state_setseq_32 { + uint32_t state; + uint32_t inc; +}; + +struct pcg_state_setseq_64 { + uint64_t state; + uint64_t inc; +}; + +#if PCG_HAS_128BIT_OPS +struct pcg_state_setseq_128 { + pcg128_t state; + pcg128_t inc; +}; +#endif + +/* Multi-step advance functions (jump-ahead, jump-back) */ + +extern uint8_t pcg_advance_lcg_8(uint8_t state, uint8_t delta, uint8_t cur_mult, + uint8_t cur_plus); +extern uint16_t pcg_advance_lcg_16(uint16_t state, uint16_t delta, + uint16_t cur_mult, uint16_t cur_plus); +extern uint32_t pcg_advance_lcg_32(uint32_t state, uint32_t delta, + uint32_t cur_mult, uint32_t cur_plus); +extern uint64_t pcg_advance_lcg_64(uint64_t state, uint64_t delta, + uint64_t cur_mult, uint64_t cur_plus); + +#if PCG_HAS_128BIT_OPS +extern pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, + pcg128_t cur_mult, pcg128_t cur_plus); +#endif + +/* Functions to advance the underlying LCG, one version for each size and + * each style. These functions are considered semi-private. There is rarely + * a good reason to call them directly. + */ + +inline void pcg_oneseq_8_step_r(struct pcg_state_8 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8 + PCG_DEFAULT_INCREMENT_8; +} + +inline void pcg_oneseq_8_advance_r(struct pcg_state_8 *rng, uint8_t delta) { + rng->state = pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, + PCG_DEFAULT_INCREMENT_8); +} + +inline void pcg_mcg_8_step_r(struct pcg_state_8 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8; +} + +inline void pcg_mcg_8_advance_r(struct pcg_state_8 *rng, uint8_t delta) { + rng->state = + pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, 0u); +} + +inline void pcg_unique_8_step_r(struct pcg_state_8 *rng) { + rng->state = + rng->state * PCG_DEFAULT_MULTIPLIER_8 + (uint8_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_8_advance_r(struct pcg_state_8 *rng, uint8_t delta) { + rng->state = pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, + (uint8_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_8_step_r(struct pcg_state_setseq_8 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8 + rng->inc; +} + +inline void pcg_setseq_8_advance_r(struct pcg_state_setseq_8 *rng, + uint8_t delta) { + rng->state = + pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, rng->inc); +} + +inline void pcg_oneseq_16_step_r(struct pcg_state_16 *rng) { + rng->state = + rng->state * PCG_DEFAULT_MULTIPLIER_16 + PCG_DEFAULT_INCREMENT_16; +} + +inline void pcg_oneseq_16_advance_r(struct pcg_state_16 *rng, uint16_t delta) { + rng->state = pcg_advance_lcg_16(rng->state, delta, PCG_DEFAULT_MULTIPLIER_16, + PCG_DEFAULT_INCREMENT_16); +} + +inline void pcg_mcg_16_step_r(struct pcg_state_16 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_16; +} + +inline void pcg_mcg_16_advance_r(struct pcg_state_16 *rng, uint16_t delta) { + rng->state = + pcg_advance_lcg_16(rng->state, delta, PCG_DEFAULT_MULTIPLIER_16, 0u); +} + +inline void pcg_unique_16_step_r(struct pcg_state_16 *rng) { + rng->state = + rng->state * PCG_DEFAULT_MULTIPLIER_16 + (uint16_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_16_advance_r(struct pcg_state_16 *rng, uint16_t delta) { + rng->state = pcg_advance_lcg_16(rng->state, delta, PCG_DEFAULT_MULTIPLIER_16, + (uint16_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_16_step_r(struct pcg_state_setseq_16 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_16 + rng->inc; +} + +inline void pcg_setseq_16_advance_r(struct pcg_state_setseq_16 *rng, + uint16_t delta) { + rng->state = pcg_advance_lcg_16(rng->state, delta, PCG_DEFAULT_MULTIPLIER_16, + rng->inc); +} + +inline void pcg_oneseq_32_step_r(struct pcg_state_32 *rng) { + rng->state = + rng->state * PCG_DEFAULT_MULTIPLIER_32 + PCG_DEFAULT_INCREMENT_32; +} + +inline void pcg_oneseq_32_advance_r(struct pcg_state_32 *rng, uint32_t delta) { + rng->state = pcg_advance_lcg_32(rng->state, delta, PCG_DEFAULT_MULTIPLIER_32, + PCG_DEFAULT_INCREMENT_32); +} + +inline void pcg_mcg_32_step_r(struct pcg_state_32 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_32; +} + +inline void pcg_mcg_32_advance_r(struct pcg_state_32 *rng, uint32_t delta) { + rng->state = + pcg_advance_lcg_32(rng->state, delta, PCG_DEFAULT_MULTIPLIER_32, 0u); +} + +inline void pcg_unique_32_step_r(struct pcg_state_32 *rng) { + rng->state = + rng->state * PCG_DEFAULT_MULTIPLIER_32 + (uint32_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_32_advance_r(struct pcg_state_32 *rng, uint32_t delta) { + rng->state = pcg_advance_lcg_32(rng->state, delta, PCG_DEFAULT_MULTIPLIER_32, + (uint32_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_32_step_r(struct pcg_state_setseq_32 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_32 + rng->inc; +} + +inline void pcg_setseq_32_advance_r(struct pcg_state_setseq_32 *rng, + uint32_t delta) { + rng->state = pcg_advance_lcg_32(rng->state, delta, PCG_DEFAULT_MULTIPLIER_32, + rng->inc); +} + +inline void pcg_oneseq_64_step_r(struct pcg_state_64 *rng) { + rng->state = + rng->state * PCG_DEFAULT_MULTIPLIER_64 + PCG_DEFAULT_INCREMENT_64; +} + +inline void pcg_oneseq_64_advance_r(struct pcg_state_64 *rng, uint64_t delta) { + rng->state = pcg_advance_lcg_64(rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, + PCG_DEFAULT_INCREMENT_64); +} + +inline void pcg_mcg_64_step_r(struct pcg_state_64 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64; +} + +inline void pcg_mcg_64_advance_r(struct pcg_state_64 *rng, uint64_t delta) { + rng->state = + pcg_advance_lcg_64(rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, 0u); +} + +inline void pcg_unique_64_step_r(struct pcg_state_64 *rng) { + rng->state = + rng->state * PCG_DEFAULT_MULTIPLIER_64 + (uint64_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_64_advance_r(struct pcg_state_64 *rng, uint64_t delta) { + rng->state = pcg_advance_lcg_64(rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, + (uint64_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_64_step_r(struct pcg_state_setseq_64 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64 + rng->inc; +} + +inline void pcg_setseq_64_advance_r(struct pcg_state_setseq_64 *rng, + uint64_t delta) { + rng->state = pcg_advance_lcg_64(rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, + rng->inc); +} + +#if PCG_HAS_128BIT_OPS +inline void pcg_oneseq_128_step_r(struct pcg_state_128 *rng) { + rng->state = + rng->state * PCG_DEFAULT_MULTIPLIER_128 + PCG_DEFAULT_INCREMENT_128; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_oneseq_128_advance_r(struct pcg_state_128 *rng, + pcg128_t delta) { + rng->state = pcg_advance_lcg_128( + rng->state, delta, PCG_DEFAULT_MULTIPLIER_128, PCG_DEFAULT_INCREMENT_128); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_mcg_128_step_r(struct pcg_state_128 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_mcg_128_advance_r(struct pcg_state_128 *rng, pcg128_t delta) { + rng->state = + pcg_advance_lcg_128(rng->state, delta, PCG_DEFAULT_MULTIPLIER_128, 0u); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_unique_128_step_r(struct pcg_state_128 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + + (pcg128_t)(((intptr_t)rng) | 1u); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_unique_128_advance_r(struct pcg_state_128 *rng, + pcg128_t delta) { + rng->state = + pcg_advance_lcg_128(rng->state, delta, PCG_DEFAULT_MULTIPLIER_128, + (pcg128_t)(((intptr_t)rng) | 1u)); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_setseq_128_step_r(struct pcg_state_setseq_128 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + rng->inc; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_setseq_128_advance_r(struct pcg_state_setseq_128 *rng, + pcg128_t delta) { + rng->state = pcg_advance_lcg_128(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_128, rng->inc); +} +#endif + +/* Functions to seed the RNG state, one version for each size and each + * style. Unlike the step functions, regular users can and should call + * these functions. + */ + +inline void pcg_oneseq_8_srandom_r(struct pcg_state_8 *rng, uint8_t initstate) { + rng->state = 0U; + pcg_oneseq_8_step_r(rng); + rng->state += initstate; + pcg_oneseq_8_step_r(rng); +} + +inline void pcg_mcg_8_srandom_r(struct pcg_state_8 *rng, uint8_t initstate) { + rng->state = initstate | 1u; +} + +inline void pcg_unique_8_srandom_r(struct pcg_state_8 *rng, uint8_t initstate) { + rng->state = 0U; + pcg_unique_8_step_r(rng); + rng->state += initstate; + pcg_unique_8_step_r(rng); +} + +inline void pcg_setseq_8_srandom_r(struct pcg_state_setseq_8 *rng, + uint8_t initstate, uint8_t initseq) { + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_8_step_r(rng); + rng->state += initstate; + pcg_setseq_8_step_r(rng); +} + +inline void pcg_oneseq_16_srandom_r(struct pcg_state_16 *rng, + uint16_t initstate) { + rng->state = 0U; + pcg_oneseq_16_step_r(rng); + rng->state += initstate; + pcg_oneseq_16_step_r(rng); +} + +inline void pcg_mcg_16_srandom_r(struct pcg_state_16 *rng, uint16_t initstate) { + rng->state = initstate | 1u; +} + +inline void pcg_unique_16_srandom_r(struct pcg_state_16 *rng, + uint16_t initstate) { + rng->state = 0U; + pcg_unique_16_step_r(rng); + rng->state += initstate; + pcg_unique_16_step_r(rng); +} + +inline void pcg_setseq_16_srandom_r(struct pcg_state_setseq_16 *rng, + uint16_t initstate, uint16_t initseq) { + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_16_step_r(rng); + rng->state += initstate; + pcg_setseq_16_step_r(rng); +} + +inline void pcg_oneseq_32_srandom_r(struct pcg_state_32 *rng, + uint32_t initstate) { + rng->state = 0U; + pcg_oneseq_32_step_r(rng); + rng->state += initstate; + pcg_oneseq_32_step_r(rng); +} + +inline void pcg_mcg_32_srandom_r(struct pcg_state_32 *rng, uint32_t initstate) { + rng->state = initstate | 1u; +} + +inline void pcg_unique_32_srandom_r(struct pcg_state_32 *rng, + uint32_t initstate) { + rng->state = 0U; + pcg_unique_32_step_r(rng); + rng->state += initstate; + pcg_unique_32_step_r(rng); +} + +inline void pcg_setseq_32_srandom_r(struct pcg_state_setseq_32 *rng, + uint32_t initstate, uint32_t initseq) { + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_32_step_r(rng); + rng->state += initstate; + pcg_setseq_32_step_r(rng); +} + +inline void pcg_oneseq_64_srandom_r(struct pcg_state_64 *rng, + uint64_t initstate) { + rng->state = 0U; + pcg_oneseq_64_step_r(rng); + rng->state += initstate; + pcg_oneseq_64_step_r(rng); +} + +inline void pcg_mcg_64_srandom_r(struct pcg_state_64 *rng, uint64_t initstate) { + rng->state = initstate | 1u; +} + +inline void pcg_unique_64_srandom_r(struct pcg_state_64 *rng, + uint64_t initstate) { + rng->state = 0U; + pcg_unique_64_step_r(rng); + rng->state += initstate; + pcg_unique_64_step_r(rng); +} + +inline void pcg_setseq_64_srandom_r(struct pcg_state_setseq_64 *rng, + uint64_t initstate, uint64_t initseq) { + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_64_step_r(rng); + rng->state += initstate; + pcg_setseq_64_step_r(rng); +} + +#if PCG_HAS_128BIT_OPS +inline void pcg_oneseq_128_srandom_r(struct pcg_state_128 *rng, + pcg128_t initstate) { + rng->state = 0U; + pcg_oneseq_128_step_r(rng); + rng->state += initstate; + pcg_oneseq_128_step_r(rng); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_mcg_128_srandom_r(struct pcg_state_128 *rng, + pcg128_t initstate) { + rng->state = initstate | 1u; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_unique_128_srandom_r(struct pcg_state_128 *rng, + pcg128_t initstate) { + rng->state = 0U; + pcg_unique_128_step_r(rng); + rng->state += initstate; + pcg_unique_128_step_r(rng); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_setseq_128_srandom_r(struct pcg_state_setseq_128 *rng, + pcg128_t initstate, pcg128_t initseq) { + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_128_step_r(rng); + rng->state += initstate; + pcg_setseq_128_step_r(rng); +} +#endif + +/* Now, finally we create each of the individual generators. We provide + * a random_r function that provides a random number of the appropriate + * type (using the full range of the type) and a boundedrand_r version + * that provides + * + * Implementation notes for boundedrand_r: + * + * To avoid bias, we need to make the range of the RNG a multiple of + * bound, which we do by dropping output less than a threshold. + * Let's consider a 32-bit case... A naive scheme to calculate the + * threshold would be to do + * + * uint32_t threshold = 0x100000000ull % bound; + * + * but 64-bit div/mod is slower than 32-bit div/mod (especially on + * 32-bit platforms). In essence, we do + * + * uint32_t threshold = (0x100000000ull-bound) % bound; + * + * because this version will calculate the same modulus, but the LHS + * value is less than 2^32. + * + * (Note that using modulo is only wise for good RNGs, poorer RNGs + * such as raw LCGs do better using a technique based on division.) + * Empricical tests show that division is preferable to modulus for + * reducting the range of an RNG. It's faster, and sometimes it can + * even be statistically prefereable. + */ + +/* Generation functions for XSH RS */ + +inline uint8_t pcg_oneseq_16_xsh_rs_8_random_r(struct pcg_state_16 *rng) { + uint16_t oldstate = rng->state; + pcg_oneseq_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t pcg_oneseq_16_xsh_rs_8_boundedrand_r(struct pcg_state_16 *rng, + uint8_t bound) { + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_oneseq_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_oneseq_32_xsh_rs_16_random_r(struct pcg_state_32 *rng) { + uint32_t oldstate = rng->state; + pcg_oneseq_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t pcg_oneseq_32_xsh_rs_16_boundedrand_r(struct pcg_state_32 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_oneseq_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_oneseq_64_xsh_rs_32_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t pcg_oneseq_64_xsh_rs_32_boundedrand_r(struct pcg_state_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_xsh_rs_64_random_r(struct pcg_state_128 *rng) { + pcg_oneseq_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_oneseq_128_xsh_rs_64_boundedrand_r(struct pcg_state_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_unique_16_xsh_rs_8_random_r(struct pcg_state_16 *rng) { + uint16_t oldstate = rng->state; + pcg_unique_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t pcg_unique_16_xsh_rs_8_boundedrand_r(struct pcg_state_16 *rng, + uint8_t bound) { + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_unique_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_unique_32_xsh_rs_16_random_r(struct pcg_state_32 *rng) { + uint32_t oldstate = rng->state; + pcg_unique_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t pcg_unique_32_xsh_rs_16_boundedrand_r(struct pcg_state_32 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_unique_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_unique_64_xsh_rs_32_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t pcg_unique_64_xsh_rs_32_boundedrand_r(struct pcg_state_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_xsh_rs_64_random_r(struct pcg_state_128 *rng) { + pcg_unique_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_unique_128_xsh_rs_64_boundedrand_r(struct pcg_state_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t +pcg_setseq_16_xsh_rs_8_random_r(struct pcg_state_setseq_16 *rng) { + uint16_t oldstate = rng->state; + pcg_setseq_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t +pcg_setseq_16_xsh_rs_8_boundedrand_r(struct pcg_state_setseq_16 *rng, + uint8_t bound) { + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_setseq_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t +pcg_setseq_32_xsh_rs_16_random_r(struct pcg_state_setseq_32 *rng) { + uint32_t oldstate = rng->state; + pcg_setseq_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t +pcg_setseq_32_xsh_rs_16_boundedrand_r(struct pcg_state_setseq_32 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_setseq_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t +pcg_setseq_64_xsh_rs_32_random_r(struct pcg_state_setseq_64 *rng) { + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t +pcg_setseq_64_xsh_rs_32_boundedrand_r(struct pcg_state_setseq_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rs_64_random_r(struct pcg_state_setseq_128 *rng) { + pcg_setseq_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rs_64_boundedrand_r(struct pcg_state_setseq_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_mcg_16_xsh_rs_8_random_r(struct pcg_state_16 *rng) { + uint16_t oldstate = rng->state; + pcg_mcg_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t pcg_mcg_16_xsh_rs_8_boundedrand_r(struct pcg_state_16 *rng, + uint8_t bound) { + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_mcg_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_mcg_32_xsh_rs_16_random_r(struct pcg_state_32 *rng) { + uint32_t oldstate = rng->state; + pcg_mcg_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t pcg_mcg_32_xsh_rs_16_boundedrand_r(struct pcg_state_32 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_mcg_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_mcg_64_xsh_rs_32_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_mcg_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t pcg_mcg_64_xsh_rs_32_boundedrand_r(struct pcg_state_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_mcg_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rs_64_random_r(struct pcg_state_128 *rng) { + pcg_mcg_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rs_64_boundedrand_r(struct pcg_state_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_mcg_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for XSH RR */ + +inline uint8_t pcg_oneseq_16_xsh_rr_8_random_r(struct pcg_state_16 *rng) { + uint16_t oldstate = rng->state; + pcg_oneseq_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t pcg_oneseq_16_xsh_rr_8_boundedrand_r(struct pcg_state_16 *rng, + uint8_t bound) { + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_oneseq_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_oneseq_32_xsh_rr_16_random_r(struct pcg_state_32 *rng) { + uint32_t oldstate = rng->state; + pcg_oneseq_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t pcg_oneseq_32_xsh_rr_16_boundedrand_r(struct pcg_state_32 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_oneseq_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_oneseq_64_xsh_rr_32_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t pcg_oneseq_64_xsh_rr_32_boundedrand_r(struct pcg_state_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_xsh_rr_64_random_r(struct pcg_state_128 *rng) { + pcg_oneseq_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_oneseq_128_xsh_rr_64_boundedrand_r(struct pcg_state_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_unique_16_xsh_rr_8_random_r(struct pcg_state_16 *rng) { + uint16_t oldstate = rng->state; + pcg_unique_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t pcg_unique_16_xsh_rr_8_boundedrand_r(struct pcg_state_16 *rng, + uint8_t bound) { + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_unique_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_unique_32_xsh_rr_16_random_r(struct pcg_state_32 *rng) { + uint32_t oldstate = rng->state; + pcg_unique_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t pcg_unique_32_xsh_rr_16_boundedrand_r(struct pcg_state_32 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_unique_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_unique_64_xsh_rr_32_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t pcg_unique_64_xsh_rr_32_boundedrand_r(struct pcg_state_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_xsh_rr_64_random_r(struct pcg_state_128 *rng) { + pcg_unique_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_unique_128_xsh_rr_64_boundedrand_r(struct pcg_state_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t +pcg_setseq_16_xsh_rr_8_random_r(struct pcg_state_setseq_16 *rng) { + uint16_t oldstate = rng->state; + pcg_setseq_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t +pcg_setseq_16_xsh_rr_8_boundedrand_r(struct pcg_state_setseq_16 *rng, + uint8_t bound) { + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_setseq_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t +pcg_setseq_32_xsh_rr_16_random_r(struct pcg_state_setseq_32 *rng) { + uint32_t oldstate = rng->state; + pcg_setseq_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t +pcg_setseq_32_xsh_rr_16_boundedrand_r(struct pcg_state_setseq_32 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_setseq_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t +pcg_setseq_64_xsh_rr_32_random_r(struct pcg_state_setseq_64 *rng) { + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t +pcg_setseq_64_xsh_rr_32_boundedrand_r(struct pcg_state_setseq_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rr_64_random_r(struct pcg_state_setseq_128 *rng) { + pcg_setseq_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rr_64_boundedrand_r(struct pcg_state_setseq_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_mcg_16_xsh_rr_8_random_r(struct pcg_state_16 *rng) { + uint16_t oldstate = rng->state; + pcg_mcg_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t pcg_mcg_16_xsh_rr_8_boundedrand_r(struct pcg_state_16 *rng, + uint8_t bound) { + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_mcg_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_mcg_32_xsh_rr_16_random_r(struct pcg_state_32 *rng) { + uint32_t oldstate = rng->state; + pcg_mcg_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t pcg_mcg_32_xsh_rr_16_boundedrand_r(struct pcg_state_32 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_mcg_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_mcg_64_xsh_rr_32_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_mcg_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t pcg_mcg_64_xsh_rr_32_boundedrand_r(struct pcg_state_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_mcg_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rr_64_random_r(struct pcg_state_128 *rng) { + pcg_mcg_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rr_64_boundedrand_r(struct pcg_state_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_mcg_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for RXS M XS (no MCG versions because they + * don't make sense when you want to use the entire state) + */ + +inline uint8_t pcg_oneseq_8_rxs_m_xs_8_random_r(struct pcg_state_8 *rng) { + uint8_t oldstate = rng->state; + pcg_oneseq_8_step_r(rng); + return pcg_output_rxs_m_xs_8_8(oldstate); +} + +inline uint8_t pcg_oneseq_8_rxs_m_xs_8_boundedrand_r(struct pcg_state_8 *rng, + uint8_t bound) { + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_oneseq_8_rxs_m_xs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_oneseq_16_rxs_m_xs_16_random_r(struct pcg_state_16 *rng) { + uint16_t oldstate = rng->state; + pcg_oneseq_16_step_r(rng); + return pcg_output_rxs_m_xs_16_16(oldstate); +} + +inline uint16_t +pcg_oneseq_16_rxs_m_xs_16_boundedrand_r(struct pcg_state_16 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_oneseq_16_rxs_m_xs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_oneseq_32_rxs_m_xs_32_random_r(struct pcg_state_32 *rng) { + uint32_t oldstate = rng->state; + pcg_oneseq_32_step_r(rng); + return pcg_output_rxs_m_xs_32_32(oldstate); +} + +inline uint32_t +pcg_oneseq_32_rxs_m_xs_32_boundedrand_r(struct pcg_state_32 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_32_rxs_m_xs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint64_t pcg_oneseq_64_rxs_m_xs_64_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_rxs_m_xs_64_64(oldstate); +} + +inline uint64_t +pcg_oneseq_64_rxs_m_xs_64_boundedrand_r(struct pcg_state_64 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_64_rxs_m_xs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_oneseq_128_rxs_m_xs_128_random_r(struct pcg_state_128 *rng) { + pcg_oneseq_128_step_r(rng); + return pcg_output_rxs_m_xs_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_oneseq_128_rxs_m_xs_128_boundedrand_r(struct pcg_state_128 *rng, + pcg128_t bound) { + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_oneseq_128_rxs_m_xs_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint16_t pcg_unique_16_rxs_m_xs_16_random_r(struct pcg_state_16 *rng) { + uint16_t oldstate = rng->state; + pcg_unique_16_step_r(rng); + return pcg_output_rxs_m_xs_16_16(oldstate); +} + +inline uint16_t +pcg_unique_16_rxs_m_xs_16_boundedrand_r(struct pcg_state_16 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_unique_16_rxs_m_xs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_unique_32_rxs_m_xs_32_random_r(struct pcg_state_32 *rng) { + uint32_t oldstate = rng->state; + pcg_unique_32_step_r(rng); + return pcg_output_rxs_m_xs_32_32(oldstate); +} + +inline uint32_t +pcg_unique_32_rxs_m_xs_32_boundedrand_r(struct pcg_state_32 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_32_rxs_m_xs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint64_t pcg_unique_64_rxs_m_xs_64_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_rxs_m_xs_64_64(oldstate); +} + +inline uint64_t +pcg_unique_64_rxs_m_xs_64_boundedrand_r(struct pcg_state_64 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_64_rxs_m_xs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_unique_128_rxs_m_xs_128_random_r(struct pcg_state_128 *rng) { + pcg_unique_128_step_r(rng); + return pcg_output_rxs_m_xs_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_unique_128_rxs_m_xs_128_boundedrand_r(struct pcg_state_128 *rng, + pcg128_t bound) { + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_unique_128_rxs_m_xs_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t +pcg_setseq_8_rxs_m_xs_8_random_r(struct pcg_state_setseq_8 *rng) { + uint8_t oldstate = rng->state; + pcg_setseq_8_step_r(rng); + return pcg_output_rxs_m_xs_8_8(oldstate); +} + +inline uint8_t +pcg_setseq_8_rxs_m_xs_8_boundedrand_r(struct pcg_state_setseq_8 *rng, + uint8_t bound) { + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_setseq_8_rxs_m_xs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t +pcg_setseq_16_rxs_m_xs_16_random_r(struct pcg_state_setseq_16 *rng) { + uint16_t oldstate = rng->state; + pcg_setseq_16_step_r(rng); + return pcg_output_rxs_m_xs_16_16(oldstate); +} + +inline uint16_t +pcg_setseq_16_rxs_m_xs_16_boundedrand_r(struct pcg_state_setseq_16 *rng, + uint16_t bound) { + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_setseq_16_rxs_m_xs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t +pcg_setseq_32_rxs_m_xs_32_random_r(struct pcg_state_setseq_32 *rng) { + uint32_t oldstate = rng->state; + pcg_setseq_32_step_r(rng); + return pcg_output_rxs_m_xs_32_32(oldstate); +} + +inline uint32_t +pcg_setseq_32_rxs_m_xs_32_boundedrand_r(struct pcg_state_setseq_32 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_32_rxs_m_xs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint64_t +pcg_setseq_64_rxs_m_xs_64_random_r(struct pcg_state_setseq_64 *rng) { + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_rxs_m_xs_64_64(oldstate); +} + +inline uint64_t +pcg_setseq_64_rxs_m_xs_64_boundedrand_r(struct pcg_state_setseq_64 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_64_rxs_m_xs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_rxs_m_xs_128_random_r(struct pcg_state_setseq_128 *rng) { + pcg_setseq_128_step_r(rng); + return pcg_output_rxs_m_xs_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_rxs_m_xs_128_boundedrand_r(struct pcg_state_setseq_128 *rng, + pcg128_t bound) { + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_setseq_128_rxs_m_xs_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for XSL RR (only defined for "large" types) */ + +inline uint32_t pcg_oneseq_64_xsl_rr_32_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t pcg_oneseq_64_xsl_rr_32_boundedrand_r(struct pcg_state_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_xsl_rr_64_random_r(struct pcg_state_128 *rng) { + pcg_oneseq_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_oneseq_128_xsl_rr_64_boundedrand_r(struct pcg_state_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint32_t pcg_unique_64_xsl_rr_32_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t pcg_unique_64_xsl_rr_32_boundedrand_r(struct pcg_state_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_xsl_rr_64_random_r(struct pcg_state_128 *rng) { + pcg_unique_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_unique_128_xsl_rr_64_boundedrand_r(struct pcg_state_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint32_t +pcg_setseq_64_xsl_rr_32_random_r(struct pcg_state_setseq_64 *rng) { + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t +pcg_setseq_64_xsl_rr_32_boundedrand_r(struct pcg_state_setseq_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsl_rr_64_random_r(struct pcg_state_setseq_128 *rng) { + pcg_setseq_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsl_rr_64_boundedrand_r(struct pcg_state_setseq_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint32_t pcg_mcg_64_xsl_rr_32_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_mcg_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t pcg_mcg_64_xsl_rr_32_boundedrand_r(struct pcg_state_64 *rng, + uint32_t bound) { + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_mcg_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsl_rr_64_random_r(struct pcg_state_128 *rng) { + pcg_mcg_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsl_rr_64_boundedrand_r(struct pcg_state_128 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_mcg_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for XSL RR RR (only defined for "large" types) */ + +inline uint64_t pcg_oneseq_64_xsl_rr_rr_64_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsl_rr_rr_64_64(oldstate); +} + +inline uint64_t +pcg_oneseq_64_xsl_rr_rr_64_boundedrand_r(struct pcg_state_64 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_64_xsl_rr_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_oneseq_128_xsl_rr_rr_128_random_r(struct pcg_state_128 *rng) { + pcg_oneseq_128_step_r(rng); + return pcg_output_xsl_rr_rr_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_oneseq_128_xsl_rr_rr_128_boundedrand_r(struct pcg_state_128 *rng, + pcg128_t bound) { + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_oneseq_128_xsl_rr_rr_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint64_t pcg_unique_64_xsl_rr_rr_64_random_r(struct pcg_state_64 *rng) { + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsl_rr_rr_64_64(oldstate); +} + +inline uint64_t +pcg_unique_64_xsl_rr_rr_64_boundedrand_r(struct pcg_state_64 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_64_xsl_rr_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_unique_128_xsl_rr_rr_128_random_r(struct pcg_state_128 *rng) { + pcg_unique_128_step_r(rng); + return pcg_output_xsl_rr_rr_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_unique_128_xsl_rr_rr_128_boundedrand_r(struct pcg_state_128 *rng, + pcg128_t bound) { + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_unique_128_xsl_rr_rr_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint64_t +pcg_setseq_64_xsl_rr_rr_64_random_r(struct pcg_state_setseq_64 *rng) { + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsl_rr_rr_64_64(oldstate); +} + +inline uint64_t +pcg_setseq_64_xsl_rr_rr_64_boundedrand_r(struct pcg_state_setseq_64 *rng, + uint64_t bound) { + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_64_xsl_rr_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_xsl_rr_rr_128_random_r(struct pcg_state_setseq_128 *rng) { + pcg_setseq_128_step_r(rng); + return pcg_output_xsl_rr_rr_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_xsl_rr_rr_128_boundedrand_r(struct pcg_state_setseq_128 *rng, + pcg128_t bound) { + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_setseq_128_xsl_rr_rr_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +//// Typedefs +typedef struct pcg_state_setseq_64 pcg32_random_t; +typedef struct pcg_state_64 pcg32s_random_t; +typedef struct pcg_state_64 pcg32u_random_t; +typedef struct pcg_state_64 pcg32f_random_t; +//// random_r +#define pcg32_random_r pcg_setseq_64_xsh_rr_32_random_r +#define pcg32s_random_r pcg_oneseq_64_xsh_rr_32_random_r +#define pcg32u_random_r pcg_unique_64_xsh_rr_32_random_r +#define pcg32f_random_r pcg_mcg_64_xsh_rs_32_random_r +//// boundedrand_r +#define pcg32_boundedrand_r pcg_setseq_64_xsh_rr_32_boundedrand_r +#define pcg32s_boundedrand_r pcg_oneseq_64_xsh_rr_32_boundedrand_r +#define pcg32u_boundedrand_r pcg_unique_64_xsh_rr_32_boundedrand_r +#define pcg32f_boundedrand_r pcg_mcg_64_xsh_rs_32_boundedrand_r +//// srandom_r +#define pcg32_srandom_r pcg_setseq_64_srandom_r +#define pcg32s_srandom_r pcg_oneseq_64_srandom_r +#define pcg32u_srandom_r pcg_unique_64_srandom_r +#define pcg32f_srandom_r pcg_mcg_64_srandom_r +//// advance_r +#define pcg32_advance_r pcg_setseq_64_advance_r +#define pcg32s_advance_r pcg_oneseq_64_advance_r +#define pcg32u_advance_r pcg_unique_64_advance_r +#define pcg32f_advance_r pcg_mcg_64_advance_r + +#if PCG_HAS_128BIT_OPS +//// Typedefs +typedef struct pcg_state_setseq_128 pcg64_random_t; +typedef struct pcg_state_128 pcg64s_random_t; +typedef struct pcg_state_128 pcg64u_random_t; +typedef struct pcg_state_128 pcg64f_random_t; +//// random_r +#define pcg64_random_r pcg_setseq_128_xsl_rr_64_random_r +#define pcg64s_random_r pcg_oneseq_128_xsl_rr_64_random_r +#define pcg64u_random_r pcg_unique_128_xsl_rr_64_random_r +#define pcg64f_random_r pcg_mcg_128_xsl_rr_64_random_r +//// boundedrand_r +#define pcg64_boundedrand_r pcg_setseq_128_xsl_rr_64_boundedrand_r +#define pcg64s_boundedrand_r pcg_oneseq_128_xsl_rr_64_boundedrand_r +#define pcg64u_boundedrand_r pcg_unique_128_xsl_rr_64_boundedrand_r +#define pcg64f_boundedrand_r pcg_mcg_128_xsl_rr_64_boundedrand_r +//// srandom_r +#define pcg64_srandom_r pcg_setseq_128_srandom_r +#define pcg64s_srandom_r pcg_oneseq_128_srandom_r +#define pcg64u_srandom_r pcg_unique_128_srandom_r +#define pcg64f_srandom_r pcg_mcg_128_srandom_r +//// advance_r +#define pcg64_advance_r pcg_setseq_128_advance_r +#define pcg64s_advance_r pcg_oneseq_128_advance_r +#define pcg64u_advance_r pcg_unique_128_advance_r +#define pcg64f_advance_r pcg_mcg_128_advance_r +#endif + +//// Typedefs +typedef struct pcg_state_8 pcg8si_random_t; +typedef struct pcg_state_16 pcg16si_random_t; +typedef struct pcg_state_32 pcg32si_random_t; +typedef struct pcg_state_64 pcg64si_random_t; +//// random_r +#define pcg8si_random_r pcg_oneseq_8_rxs_m_xs_8_random_r +#define pcg16si_random_r pcg_oneseq_16_rxs_m_xs_16_random_r +#define pcg32si_random_r pcg_oneseq_32_rxs_m_xs_32_random_r +#define pcg64si_random_r pcg_oneseq_64_rxs_m_xs_64_random_r +//// boundedrand_r +#define pcg8si_boundedrand_r pcg_oneseq_8_rxs_m_xs_8_boundedrand_r +#define pcg16si_boundedrand_r pcg_oneseq_16_rxs_m_xs_16_boundedrand_r +#define pcg32si_boundedrand_r pcg_oneseq_32_rxs_m_xs_32_boundedrand_r +#define pcg64si_boundedrand_r pcg_oneseq_64_rxs_m_xs_64_boundedrand_r +//// srandom_r +#define pcg8si_srandom_r pcg_oneseq_8_srandom_r +#define pcg16si_srandom_r pcg_oneseq_16_srandom_r +#define pcg32si_srandom_r pcg_oneseq_32_srandom_r +#define pcg64si_srandom_r pcg_oneseq_64_srandom_r +//// advance_r +#define pcg8si_advance_r pcg_oneseq_8_advance_r +#define pcg16si_advance_r pcg_oneseq_16_advance_r +#define pcg32si_advance_r pcg_oneseq_32_advance_r +#define pcg64si_advance_r pcg_oneseq_64_advance_r + +#if PCG_HAS_128BIT_OPS +typedef struct pcg_state_128 pcg128si_random_t; +#define pcg128si_random_r pcg_oneseq_128_rxs_m_xs_128_random_r +#define pcg128si_boundedrand_r pcg_oneseq_128_rxs_m_xs_128_boundedrand_r +#define pcg128si_srandom_r pcg_oneseq_128_srandom_r +#define pcg128si_advance_r pcg_oneseq_128_advance_r +#endif + +//// Typedefs +typedef struct pcg_state_setseq_8 pcg8i_random_t; +typedef struct pcg_state_setseq_16 pcg16i_random_t; +typedef struct pcg_state_setseq_32 pcg32i_random_t; +typedef struct pcg_state_setseq_64 pcg64i_random_t; +//// random_r +#define pcg8i_random_r pcg_setseq_8_rxs_m_xs_8_random_r +#define pcg16i_random_r pcg_setseq_16_rxs_m_xs_16_random_r +#define pcg32i_random_r pcg_setseq_32_rxs_m_xs_32_random_r +#define pcg64i_random_r pcg_setseq_64_rxs_m_xs_64_random_r +//// boundedrand_r +#define pcg8i_boundedrand_r pcg_setseq_8_rxs_m_xs_8_boundedrand_r +#define pcg16i_boundedrand_r pcg_setseq_16_rxs_m_xs_16_boundedrand_r +#define pcg32i_boundedrand_r pcg_setseq_32_rxs_m_xs_32_boundedrand_r +#define pcg64i_boundedrand_r pcg_setseq_64_rxs_m_xs_64_boundedrand_r +//// srandom_r +#define pcg8i_srandom_r pcg_setseq_8_srandom_r +#define pcg16i_srandom_r pcg_setseq_16_srandom_r +#define pcg32i_srandom_r pcg_setseq_32_srandom_r +#define pcg64i_srandom_r pcg_setseq_64_srandom_r +//// advance_r +#define pcg8i_advance_r pcg_setseq_8_advance_r +#define pcg16i_advance_r pcg_setseq_16_advance_r +#define pcg32i_advance_r pcg_setseq_32_advance_r +#define pcg64i_advance_r pcg_setseq_64_advance_r + +#if PCG_HAS_128BIT_OPS +typedef struct pcg_state_setseq_128 pcg128i_random_t; +#define pcg128i_random_r pcg_setseq_128_rxs_m_xs_128_random_r +#define pcg128i_boundedrand_r pcg_setseq_128_rxs_m_xs_128_boundedrand_r +#define pcg128i_srandom_r pcg_setseq_128_srandom_r +#define pcg128i_advance_r pcg_setseq_128_advance_r +#endif + +extern uint32_t pcg32_random(); +extern uint32_t pcg32_boundedrand(uint32_t bound); +extern void pcg32_srandom(uint64_t seed, uint64_t seq); +extern void pcg32_advance(uint64_t delta); + +#if PCG_HAS_128BIT_OPS +extern uint64_t pcg64_random(); +extern uint64_t pcg64_boundedrand(uint64_t bound); +extern void pcg64_srandom(pcg128_t seed, pcg128_t seq); +extern void pcg64_advance(pcg128_t delta); +#endif + +/* + * Static initialization constants (if you can't call srandom for some + * bizarre reason). + */ + +#define PCG32_INITIALIZER PCG_STATE_SETSEQ_64_INITIALIZER +#define PCG32U_INITIALIZER PCG_STATE_UNIQUE_64_INITIALIZER +#define PCG32S_INITIALIZER PCG_STATE_ONESEQ_64_INITIALIZER +#define PCG32F_INITIALIZER PCG_STATE_MCG_64_INITIALIZER + +#if PCG_HAS_128BIT_OPS +#define PCG64_INITIALIZER PCG_STATE_SETSEQ_128_INITIALIZER +#define PCG64U_INITIALIZER PCG_STATE_UNIQUE_128_INITIALIZER +#define PCG64S_INITIALIZER PCG_STATE_ONESEQ_128_INITIALIZER +#define PCG64F_INITIALIZER PCG_STATE_MCG_128_INITIALIZER +#endif + +#define PCG8SI_INITIALIZER PCG_STATE_ONESEQ_8_INITIALIZER +#define PCG16SI_INITIALIZER PCG_STATE_ONESEQ_16_INITIALIZER +#define PCG32SI_INITIALIZER PCG_STATE_ONESEQ_32_INITIALIZER +#define PCG64SI_INITIALIZER PCG_STATE_ONESEQ_64_INITIALIZER +#if PCG_HAS_128BIT_OPS +#define PCG128SI_INITIALIZER PCG_STATE_ONESEQ_128_INITIALIZER +#endif + +#define PCG8I_INITIALIZER PCG_STATE_SETSEQ_8_INITIALIZER +#define PCG16I_INITIALIZER PCG_STATE_SETSEQ_16_INITIALIZER +#define PCG32I_INITIALIZER PCG_STATE_SETSEQ_32_INITIALIZER +#define PCG64I_INITIALIZER PCG_STATE_SETSEQ_64_INITIALIZER +#if PCG_HAS_128BIT_OPS +#define PCG128I_INITIALIZER PCG_STATE_SETSEQ_128_INITIALIZER +#endif + +#if __cplusplus +} +#endif + +#endif // PCG_VARIANTS_H_INCLUDED From 681d5d5c494757b8ac4c9adb8975e15f2cc6703c Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 6 Mar 2018 23:53:25 +0000 Subject: [PATCH 040/279] CLN: Clean up benchmarks Add internal timer --- _randomgen/.gitignore | 1 + .../{dsfmt-benchmark.c => dSFMT-benchmark.c} | 16 ++++++++++----- .../core_prng/src/mt19937/mt19937-benchmark.c | 16 +++++++++++---- .../core_prng/src/pcg64/pcg64-benchmark.c | 20 +++++++++++++++---- .../core_prng/src/pcg64/pcg64-test-data-gen.c | 18 +++++------------ _randomgen/core_prng/src/pcg64/pcg64.h | 2 +- _randomgen/core_prng/src/pcg64/pcg64.orig.c | 6 ++++++ .../core_prng/src/philox/philox-benchmark.c | 13 ++++++++---- .../src/threefry/threefry-benchmark.c | 14 ++++++++----- .../src/xoroshiro128/xoroshiro128-benchmark.c | 15 +++++++++----- .../src/xorshift1024/xorshift1024-benchmark.c | 16 +++++++++------ 11 files changed, 90 insertions(+), 47 deletions(-) rename _randomgen/core_prng/src/dsfmt/{dsfmt-benchmark.c => dSFMT-benchmark.c} (59%) create mode 100644 _randomgen/core_prng/src/pcg64/pcg64.orig.c diff --git a/_randomgen/.gitignore b/_randomgen/.gitignore index 6fef7580ddca..613fc1bf498c 100644 --- a/_randomgen/.gitignore +++ b/_randomgen/.gitignore @@ -8,3 +8,4 @@ build/ *.exe **/Random123 settings.json +*.so diff --git a/_randomgen/core_prng/src/dsfmt/dsfmt-benchmark.c b/_randomgen/core_prng/src/dsfmt/dSFMT-benchmark.c similarity index 59% rename from _randomgen/core_prng/src/dsfmt/dsfmt-benchmark.c rename to _randomgen/core_prng/src/dsfmt/dSFMT-benchmark.c index 47eae7e1c286..d311179fc2bd 100644 --- a/_randomgen/core_prng/src/dsfmt/dsfmt-benchmark.c +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-benchmark.c @@ -1,25 +1,27 @@ /* * * cl dsfmt-benchmark.c dSFMT.c /Ox -DHAVE_SSE2 - * Measure-Command { .\dsfmt-benchmark.exe } - * * + * gcc dSFMT-benchmark.c dSFMT.c -O3 -DHAVE_SSE2 -DDSFMT_MEXP=19937 -o + * dSFMT-benchmark */ #include "dSFMT.h" #include +#include #define N 1000000000 int main() { int i, j; uint32_t seed = 0xDEADBEAF; - uint64_t total = 0, sum = 0; + uint64_t count = 0, sum = 0; dsfmt_t state; double buffer[DSFMT_N64]; uint64_t out; uint64_t *tmp; dsfmt_init_gen_rand(&state, seed); + clock_t begin = clock(); for (i = 0; i < N / (DSFMT_N64 / 2); i++) { dsfmt_fill_array_close_open(&state, &buffer[0], DSFMT_N64); for (j = 0; j < DSFMT_N64; j += 2) { @@ -28,8 +30,12 @@ int main() { tmp = (uint64_t *)&buffer[j + 1]; out |= (*tmp >> 16) & 0xffffffff; sum += out; - total++; + count++; } } - printf("0x%" PRIx64 ", total: %" PRIu64 "\n", sum, total); + clock_t end = clock(); + double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; + printf("0x%" PRIx64 "\ncount: %" PRIu64 "\n", sum, count); + printf("%" PRIu64 " randoms per second\n", + (uint64_t)(N / time_spent) / 1000000 * 1000000); } diff --git a/_randomgen/core_prng/src/mt19937/mt19937-benchmark.c b/_randomgen/core_prng/src/mt19937/mt19937-benchmark.c index 8f6ce20ac40f..039f8030af65 100644 --- a/_randomgen/core_prng/src/mt19937/mt19937-benchmark.c +++ b/_randomgen/core_prng/src/mt19937/mt19937-benchmark.c @@ -7,17 +7,25 @@ */ #include "mt19937.h" #include +#include +#include -#define N 1000000000 +#define Q 1000000000 int main() { int i; uint32_t seed = 0x0; - uint64_t sum; + uint64_t sum = 0, count = 0; mt19937_state state; mt19937_seed(&state, seed); - for (i = 0; i < N; i++) { + clock_t begin = clock(); + for (i = 0; i < Q; i++) { sum += mt19937_next64(&state); + count++; } - printf("0x%" PRIx64 "\n", sum); + clock_t end = clock(); + double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; + printf("0x%" PRIx64 "\ncount: %" PRIu64 "\n", sum, count); + printf("%" PRIu64 " randoms per second\n", + (uint64_t)(Q / time_spent) / 1000000 * 1000000); } diff --git a/_randomgen/core_prng/src/pcg64/pcg64-benchmark.c b/_randomgen/core_prng/src/pcg64/pcg64-benchmark.c index 38a75e38a4f7..76f3ec78c300 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64-benchmark.c +++ b/_randomgen/core_prng/src/pcg64/pcg64-benchmark.c @@ -3,28 +3,40 @@ * Measure-Command { .\xoroshiro128-benchmark.exe } * * gcc pcg64-benchmark.c pcg64.c ../splitmix64/splitmix64.c -O3 -o - * pcg64-benchmark + * pcg64-benchmark * time ./pcg64-benchmark */ #include "../splitmix64/splitmix64.h" #include "pcg64.h" #include #include +#include #define N 1000000000 int main() { pcg64_random_t rng; - uint64_t sum = 0; + uint64_t sum = 0, count = 0; uint64_t seed = 0xDEADBEAF; int i; +#if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH) + rng.state = (__uint128_t)splitmix64_next(&seed) << 64; + rng.state |= splitmix64_next(&seed); + rng.inc = (__uint128_t)1; +#else rng.state.high = splitmix64_next(&seed); rng.state.low = splitmix64_next(&seed); rng.inc.high = 0; rng.inc.low = 1; - +#endif + clock_t begin = clock(); for (i = 0; i < N; i++) { sum += pcg64_random_r(&rng); + count++; } - printf("0x%" PRIx64 "\n", sum); + clock_t end = clock(); + double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; + printf("0x%" PRIx64 "\ncount: %" PRIu64 "\n", sum, count); + printf("%" PRIu64 " randoms per second\n", + (uint64_t)(N / time_spent) / 1000000 * 1000000); } diff --git a/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c b/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c index 1671b42ae8ef..d97632d759a0 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c +++ b/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c @@ -3,23 +3,18 @@ * * GCC only * - * gcc xoroshiro128-test-data-gen.c xoroshiro128plus.orig.c / - * ../splitmix64/splitmix64.c -o xoroshiro128-test-data-gen - * ./xoroshiro128-test-data-gen - * + * gcc pcg64-test-data-gen.c pcg64.orig.c ../splitmix64/splitmix64.c -o pgc64-test-data-gen */ -#include "../splitmix64/splitmix64.h" #include "pcg64.orig.h" +#include "../splitmix64/splitmix64.h" #include #include #define N 1000 -typedef uint64_t __uint128_t; - int main() { - pcg64_random_t c; + pcg64_random_t rng; uint64_t state, seed = 0xDEADBEAF; state = seed; __uint128_t temp; @@ -30,7 +25,6 @@ int main() { uint64_t store[N]; for (i = 0; i < N; i++) { store[i] = pcg64_random_r(&rng); - ; } FILE *fp; @@ -48,16 +42,14 @@ int main() { } fclose(fp); - uint64_t state, seed = 0; - state = seed; + state = seed = 0; rng.state = (__uint128_t)splitmix64_next(&state) << 64 | splitmix64_next(&state); rng.inc = (__uint128_t)1; for (i = 0; i < N; i++) { store[i] = pcg64_random_r(&rng); - ; } - fp = fopen("xoroshiro128-testset-2.csv", "w"); + fp = fopen("pcg64-testset-2.csv", "w"); if (fp == NULL) { printf("Couldn't open file\n"); return -1; diff --git a/_randomgen/core_prng/src/pcg64/pcg64.h b/_randomgen/core_prng/src/pcg64/pcg64.h index 244eeb8cff49..54bd37efc7e6 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.h +++ b/_randomgen/core_prng/src/pcg64/pcg64.h @@ -29,7 +29,7 @@ #ifndef _INTTYPES #include "../common/stdint.h" #endif -#define inline __forceinline +#define inline __inline __forceinline #else #include #endif diff --git a/_randomgen/core_prng/src/pcg64/pcg64.orig.c b/_randomgen/core_prng/src/pcg64/pcg64.orig.c new file mode 100644 index 000000000000..4ce4736dbc58 --- /dev/null +++ b/_randomgen/core_prng/src/pcg64/pcg64.orig.c @@ -0,0 +1,6 @@ +#include "pcg64.orig.h" + +extern uint64_t pcg_rotr_64(uint64_t value, unsigned int rot); +extern inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state); +extern void pcg_setseq_128_step_r(struct pcg_state_setseq_128 *rng); +extern uint64_t pcg_setseq_128_xsl_rr_64_random_r(struct pcg_state_setseq_128 *rng); \ No newline at end of file diff --git a/_randomgen/core_prng/src/philox/philox-benchmark.c b/_randomgen/core_prng/src/philox/philox-benchmark.c index d80563e5e4b2..701ee03452cd 100644 --- a/_randomgen/core_prng/src/philox/philox-benchmark.c +++ b/_randomgen/core_prng/src/philox/philox-benchmark.c @@ -2,10 +2,8 @@ * Simple benchamrk command * * cl philox-benchmark.c /Ox - * Measure-Command { .\philox-benchmark.exe } * * gcc philox-benchmark.c -O3 -o philox-benchmark - * time ./philox-benchmark * * Requres the Random123 directory containing header files to be located in the * same directory (not included). @@ -13,6 +11,7 @@ #include "Random123/philox.h" #include #include +#include #define N 1000000000 @@ -20,14 +19,20 @@ int main() { philox4x64_ctr_t ctr = {{0, 0, 0, 0}}; philox4x64_key_t key = {{0, 0xDEADBEAF}}; philox4x64_ctr_t out; - uint64_t sum = 0; + uint64_t count = 0, sum = 0; int i, j; + clock_t begin = clock(); for (i = 0; i < N / 4UL; i++) { ctr.v[0]++; out = philox4x64_R(philox4x64_rounds, ctr, key); for (j = 0; j < 4; j++) { sum += out.v[j]; + count++; } } - printf("0x%" PRIx64 "\n", sum); + clock_t end = clock(); + double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; + printf("0x%" PRIx64 "\ncount: %" PRIu64 "\n", sum, count); + printf("%" PRIu64 " randoms per second\n", + (uint64_t)(N / time_spent) / 1000000 * 1000000); } \ No newline at end of file diff --git a/_randomgen/core_prng/src/threefry/threefry-benchmark.c b/_randomgen/core_prng/src/threefry/threefry-benchmark.c index e5f923551a54..a75e61001970 100644 --- a/_randomgen/core_prng/src/threefry/threefry-benchmark.c +++ b/_randomgen/core_prng/src/threefry/threefry-benchmark.c @@ -2,10 +2,8 @@ * Simple benchamrk command * * cl threefry-benchmark.c /Ox - * Measure-Command { .\threefry-benchmark.exe } * * gcc threefry-benchmark.c -O3 -o threefry-benchmark - * time ./threefry-benchmark * * Requres the Random123 directory containing header files to be located in the * same directory (not included). @@ -13,22 +11,28 @@ #include "Random123/threefry.h" #include #include +#include #define N 1000000000 int main() { - threefry4x64_key_t ctr = {{0, 0, 0, 0}}; threefry4x64_ctr_t key = {{0xDEADBEAF, 0, 0, 0}}; threefry4x64_ctr_t out; - uint64_t sum = 0; + uint64_t count = 0, sum = 0; int i, j; + clock_t begin = clock(); for (i = 0; i < N / 4UL; i++) { ctr.v[0]++; out = threefry4x64_R(threefry4x64_rounds, ctr, key); for (j = 0; j < 4; j++) { sum += out.v[j]; + count++; } } - printf("0x%" PRIx64 "\n", sum); + clock_t end = clock(); + double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; + printf("0x%" PRIx64 "\ncount: %" PRIu64 "\n", sum, count); + printf("%" PRIu64 " randoms per second\n", + (uint64_t)(N / time_spent) / 1000000 * 1000000); } \ No newline at end of file diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-benchmark.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-benchmark.c index f23411cf8d5e..108058eeb103 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-benchmark.c +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-benchmark.c @@ -1,28 +1,33 @@ /* * cl xoroshiro128-benchmark.c xoroshiro128plus.orig.c \ * ../splitmix64/splitmix64.c /Ox - * Measure-Command { .\xoroshiro128-benchmark.exe } * * gcc -O3 xoroshiro128-benchmark.c xoroshiro128plus.orig.c \ - * ../splitmix64/splitmix64.c -o xoroshiro128-benchmark time - * ./xoroshiro128-benchmark + * ../splitmix64/splitmix64.c -o xoroshiro128-benchmark * */ #include "../splitmix64/splitmix64.h" #include "xoroshiro128plus.orig.h" #include #include +#include #define N 1000000000 int main() { - uint64_t sum = 0; + uint64_t count = 0, sum = 0; uint64_t seed = 0xDEADBEAF; s[0] = splitmix64_next(&seed); s[1] = splitmix64_next(&seed); int i; + clock_t begin = clock(); for (i = 0; i < N; i++) { sum += next(); + count++; } - printf("0x%" PRIx64 "\n", sum); + clock_t end = clock(); + double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; + printf("0x%" PRIx64 "\ncount: %" PRIu64 "\n", sum, count); + printf("%" PRIu64 " randoms per second\n", + (uint64_t)(N / time_spent) / 1000000 * 1000000); } diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c b/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c index b4229d2f770e..0eef33537090 100644 --- a/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c @@ -2,30 +2,34 @@ * cl xorshift1024-benchmark.c xorshift2014.orig.c * ../splitmix64/splitmix64.c /Ox * - * Measure-Command { .\xorshift1024-benchmark.exe } - * * gcc -O3 xorshift1024-benchmark.c xorshift2014.orig.c / - * ../splitmix64/splitmix64.c -o xorshift1024-benchmark time - * ./xoroshiro128-benchmark + * ../splitmix64/splitmix64.c -o xorshift1024-benchmark * */ #include "../splitmix64/splitmix64.h" #include "xorshift1024.orig.h" #include #include +#include #define N 1000000000 int main() { - uint64_t sum = 0; + uint64_t count = 0, sum = 0; uint64_t seed = 0xDEADBEAF; int i; for (i = 0; i < 16; i++) { s[i] = splitmix64_next(&seed); } p = 0; + clock_t begin = clock(); for (i = 0; i < N; i++) { sum += next(); + count++; } - printf("0x%" PRIx64 "\n", sum); + clock_t end = clock(); + double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; + printf("0x%" PRIx64 "\ncount: %" PRIu64 "\n", sum, count); + printf("%" PRIu64 " randoms per second\n", + (uint64_t)(N / time_spent) / 1000000 * 1000000); } From e5cfe77ae5f566a4c430d21f0c71f3bd9fac75ca Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 7 Mar 2018 10:16:16 +0000 Subject: [PATCH 041/279] CLN: Reformat C files Reformat C files using clang-format --- _randomgen/core_prng/src/common/stdint.h | 239 +++--- .../src/distributions/distributions.c | 729 ++++++++---------- .../core_prng/src/dsfmt/dSFMT-test-gen.c | 93 ++- _randomgen/core_prng/src/dsfmt/dSFMT.c | 619 +++++++-------- _randomgen/core_prng/src/dsfmt/dSFMT.h | 325 ++++---- _randomgen/core_prng/src/mt19937/mt19937.c | 166 ++-- _randomgen/core_prng/src/mt19937/mt19937.h | 38 +- _randomgen/core_prng/src/mt19937/randomkit.c | 4 +- _randomgen/core_prng/src/mt19937/randomkit.h | 2 +- .../core_prng/src/pcg64/pcg64-test-data-gen.c | 7 +- _randomgen/core_prng/src/pcg64/pcg64.orig.c | 3 +- _randomgen/core_prng/src/pcg64/pcg64.orig.h | 8 +- .../core_prng/src/philox/philox-benchmark.c | 2 +- .../src/philox/philox-test-data-gen.c | 2 +- .../src/splitmix64/splitmix64.orig.c | 10 +- .../src/threefry/threefry-benchmark.c | 2 +- .../core_prng/src/threefry/threefry-orig.c | 29 +- .../src/threefry/threefry-test-data-gen.c | 2 +- .../xoroshiro128/xoroshiro128-test-data-gen.c | 2 +- .../src/xoroshiro128/xoroshiro128plus.orig.c | 47 +- .../xorshift1024/xorshift1024-test-data-gen.c | 2 +- .../core_prng/src/xorshift1024/xorshift1024.h | 2 +- .../src/xorshift1024/xorshift2014.orig.c | 47 +- 23 files changed, 1125 insertions(+), 1255 deletions(-) diff --git a/_randomgen/core_prng/src/common/stdint.h b/_randomgen/core_prng/src/common/stdint.h index 8941d67c8295..710de1570370 100644 --- a/_randomgen/core_prng/src/common/stdint.h +++ b/_randomgen/core_prng/src/common/stdint.h @@ -54,20 +54,19 @@ #ifdef __cplusplus extern "C" { #endif -# include +#include #ifdef __cplusplus } #endif // Define _W64 macros to mark types changing their size, like intptr_t. #ifndef _W64 -# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -# define _W64 __w64 -# else -# define _W64 -# endif +#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +#define _W64 __w64 +#else +#define _W64 +#endif #endif - // 7.18.1 Integer types @@ -77,167 +76,167 @@ extern "C" { // realize that, e.g. char has the same size as __int8 // so we give up on __intX for them. #if (_MSC_VER < 1300) - typedef signed char int8_t; - typedef signed short int16_t; - typedef signed int int32_t; - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; #else - typedef signed __int8 int8_t; - typedef signed __int16 int16_t; - typedef signed __int32 int32_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; #endif -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -typedef int64_t int_least64_t; -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -typedef uint64_t uint_least64_t; +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types -typedef int8_t int_fast8_t; -typedef int16_t int_fast16_t; -typedef int32_t int_fast32_t; -typedef int64_t int_fast64_t; -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers #ifdef _WIN64 // [ - typedef signed __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -#else // _WIN64 ][ - typedef _W64 signed int intptr_t; - typedef _W64 unsigned int uintptr_t; -#endif // _WIN64 ] +typedef signed __int64 intptr_t; +typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ +typedef _W64 signed int intptr_t; +typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] // 7.18.1.5 Greatest-width integer types -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 +#if !defined(__cplusplus) || \ + defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and + // footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] +#define PTRDIFF_MIN _I64_MIN +#define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +#define PTRDIFF_MIN _I32_MIN +#define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] +#ifdef _WIN64 // [ +#define SIZE_MAX _UI64_MAX +#else // _WIN64 ][ +#define SIZE_MAX _UI32_MAX +#endif // _WIN64 ] +#endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in #ifndef WCHAR_MIN // [ -# define WCHAR_MIN 0 -#endif // WCHAR_MIN ] +#define WCHAR_MIN 0 +#endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ -# define WCHAR_MAX _UI16_MAX -#endif // WCHAR_MAX ] +#define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] -#define WINT_MIN 0 -#define WINT_MAX _UI16_MAX +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] - // 7.18.4 Limits of other integer types -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 +#if !defined(__cplusplus) || \ + defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants -#define INT8_C(val) val##i8 +#define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 -#define UINT8_C(val) val##ui8 +#define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 @@ -246,10 +245,10 @@ typedef uint64_t uintmax_t; // These #ifndef's are needed to prevent collisions with . // Check out Issue 9 for the details. #ifndef INTMAX_C // [ -# define INTMAX_C INT64_C -#endif // INTMAX_C ] +#define INTMAX_C INT64_C +#endif // INTMAX_C ] #ifndef UINTMAX_C // [ -# define UINTMAX_C UINT64_C +#define UINTMAX_C UINT64_C #endif // UINTMAX_C ] #endif // __STDC_CONSTANT_MACROS ] diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 14cc85da0830..40b24472747b 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -2,17 +2,16 @@ #include "ziggurat.h" #include "ziggurat_constants.h" -static NPY_INLINE float next_float(prng_t *prng_state){ - return (prng_state->next_uint32(prng_state->state) >> 9) * (1.0f / 8388608.0f); +static NPY_INLINE float next_float(prng_t *prng_state) { + return (prng_state->next_uint32(prng_state->state) >> 9) * + (1.0f / 8388608.0f); } uint32_t random_uint32(prng_t *prng_state) { return prng_state->next_uint32(prng_state->state); } -float random_sample_f(prng_t *prng_state) { - return next_float(prng_state); -} +float random_sample_f(prng_t *prng_state) { return next_float(prng_state); } double random_sample(prng_t *prng_state) { return prng_state->next_double(prng_state->state); @@ -23,463 +22,373 @@ double random_standard_exponential(prng_t *prng_state) { } float random_standard_exponential_f(prng_t *prng_state) { - return -logf(1.0f - next_float(prng_state)); + return -logf(1.0f - next_float(prng_state)); } -double random_gauss(prng_t *prng_state) -{ - if (prng_state->has_gauss) - { - const double temp = prng_state->gauss; - prng_state->has_gauss = false; - return temp; - } - else - { - double f, x1, x2, r2; - - do - { - x1 = 2.0 * prng_state->next_double(prng_state->state) - 1.0; - x2 = 2.0 * prng_state->next_double(prng_state->state) - 1.0; - r2 = x1 * x1 + x2 * x2; - } while (r2 >= 1.0 || r2 == 0.0); - - /* Box-Muller transform */ - f = sqrt(-2.0 * log(r2) / r2); - /* Keep for next call */ - prng_state->gauss = f * x1; - prng_state->has_gauss = true; - return f * x2; - } +double random_gauss(prng_t *prng_state) { + if (prng_state->has_gauss) { + const double temp = prng_state->gauss; + prng_state->has_gauss = false; + return temp; + } else { + double f, x1, x2, r2; + + do { + x1 = 2.0 * prng_state->next_double(prng_state->state) - 1.0; + x2 = 2.0 * prng_state->next_double(prng_state->state) - 1.0; + r2 = x1 * x1 + x2 * x2; + } while (r2 >= 1.0 || r2 == 0.0); + + /* Box-Muller transform */ + f = sqrt(-2.0 * log(r2) / r2); + /* Keep for next call */ + prng_state->gauss = f * x1; + prng_state->has_gauss = true; + return f * x2; + } } -float random_gauss_f(prng_t *prng_state) -{ - if (prng_state->has_gauss_f) - { - const float temp = prng_state->gauss_f; - prng_state->has_gauss_f = false; - return temp; - } - else - { - float f, x1, x2, r2; - - do - { - x1 = 2.0f * next_float(prng_state) - 1.0f; - x2 = 2.0f * next_float(prng_state) - 1.0f; - r2 = x1 * x1 + x2 * x2; - } while (r2 >= 1.0 || r2 == 0.0); - - /* Box-Muller transform */ - f = sqrtf(-2.0f * logf(r2) / r2); - /* Keep for next call */ - prng_state->gauss_f = f * x1; - prng_state->has_gauss_f = true; - return f * x2; - } +float random_gauss_f(prng_t *prng_state) { + if (prng_state->has_gauss_f) { + const float temp = prng_state->gauss_f; + prng_state->has_gauss_f = false; + return temp; + } else { + float f, x1, x2, r2; + + do { + x1 = 2.0f * next_float(prng_state) - 1.0f; + x2 = 2.0f * next_float(prng_state) - 1.0f; + r2 = x1 * x1 + x2 * x2; + } while (r2 >= 1.0 || r2 == 0.0); + + /* Box-Muller transform */ + f = sqrtf(-2.0f * logf(r2) / r2); + /* Keep for next call */ + prng_state->gauss_f = f * x1; + prng_state->has_gauss_f = true; + return f * x2; + } } double standard_exponential_zig(prng_t *prng_state); -static double standard_exponential_zig_unlikely(prng_t *prng_state, uint8_t idx, double x) -{ - if (idx == 0) - { - return ziggurat_exp_r - log(prng_state->next_double(prng_state->state)); - } - else if ((fe_double[idx - 1] - fe_double[idx]) * prng_state->next_double(prng_state->state) + fe_double[idx] < exp(-x)) - { - return x; - } - else - { - return standard_exponential_zig(prng_state); - } +static double standard_exponential_zig_unlikely(prng_t *prng_state, uint8_t idx, + double x) { + if (idx == 0) { + return ziggurat_exp_r - log(prng_state->next_double(prng_state->state)); + } else if ((fe_double[idx - 1] - fe_double[idx]) * + prng_state->next_double(prng_state->state) + + fe_double[idx] < + exp(-x)) { + return x; + } else { + return standard_exponential_zig(prng_state); + } } -double standard_exponential_zig(prng_t *prng_state) -{ - uint64_t ri; - uint8_t idx; - double x; - ri = prng_state->next_uint64(prng_state->state); - ri >>= 3; - idx = ri & 0xFF; - ri >>= 8; - x = ri * we_double[idx]; - if (ri < ke_double[idx]) - { - return x; // 98.9% of the time we return here 1st try - } - return standard_exponential_zig_unlikely(prng_state, idx, x); +double standard_exponential_zig(prng_t *prng_state) { + uint64_t ri; + uint8_t idx; + double x; + ri = prng_state->next_uint64(prng_state->state); + ri >>= 3; + idx = ri & 0xFF; + ri >>= 8; + x = ri * we_double[idx]; + if (ri < ke_double[idx]) { + return x; // 98.9% of the time we return here 1st try + } + return standard_exponential_zig_unlikely(prng_state, idx, x); } -double random_standard_exponential_zig(prng_t *prng_state) -{ - return standard_exponential_zig(prng_state); +double random_standard_exponential_zig(prng_t *prng_state) { + return standard_exponential_zig(prng_state); } static NPY_INLINE float standard_exponential_zig_f(prng_t *prng_state); -static float standard_exponential_zig_unlikely_f(prng_t *prng_state, uint8_t idx, float x) -{ - if (idx == 0) - { - return ziggurat_exp_r_f - logf(next_float(prng_state)); - } - else if ((fe_float[idx - 1] - fe_float[idx]) * next_float(prng_state) + fe_float[idx] < expf(-x)) - { - return x; - } - else - { - return standard_exponential_zig_f(prng_state); - } +static float standard_exponential_zig_unlikely_f(prng_t *prng_state, + uint8_t idx, float x) { + if (idx == 0) { + return ziggurat_exp_r_f - logf(next_float(prng_state)); + } else if ((fe_float[idx - 1] - fe_float[idx]) * next_float(prng_state) + + fe_float[idx] < + expf(-x)) { + return x; + } else { + return standard_exponential_zig_f(prng_state); + } } -static NPY_INLINE float standard_exponential_zig_f(prng_t *prng_state) -{ - uint32_t ri; - uint8_t idx; - float x; - ri = prng_state->next_uint32(prng_state->state); - ri >>= 1; - idx = ri & 0xFF; - ri >>= 8; - x = ri * we_float[idx]; - if (ri < ke_float[idx]) - { - return x; // 98.9% of the time we return here 1st try - } - return standard_exponential_zig_unlikely_f(prng_state, idx, x); +static NPY_INLINE float standard_exponential_zig_f(prng_t *prng_state) { + uint32_t ri; + uint8_t idx; + float x; + ri = prng_state->next_uint32(prng_state->state); + ri >>= 1; + idx = ri & 0xFF; + ri >>= 8; + x = ri * we_float[idx]; + if (ri < ke_float[idx]) { + return x; // 98.9% of the time we return here 1st try + } + return standard_exponential_zig_unlikely_f(prng_state, idx, x); } -float random_standard_exponential_zig_f(prng_t *prng_state) -{ - return standard_exponential_zig_f(prng_state); +float random_standard_exponential_zig_f(prng_t *prng_state) { + return standard_exponential_zig_f(prng_state); } - -double random_gauss_zig(prng_t* prng_state) -{ - uint64_t r; - int sign; - int64_t rabs; - int idx; - double x, xx, yy; - for (;;) - { - /* r = e3n52sb8 */ - r = prng_state->next_uint64(prng_state->state); - idx = r & 0xff; - r >>= 8; - sign = r & 0x1; - rabs = (int64_t)((r >> 1) & 0x000fffffffffffff); - x = rabs * wi_double[idx]; - if (sign & 0x1) - x = -x; - if (rabs < ki_double[idx]) - return x; // # 99.3% of the time return here - if (idx == 0) - { - for (;;) - { - xx = -ziggurat_nor_inv_r * log(prng_state->next_double(prng_state->state)); - yy = -log(prng_state->next_double(prng_state->state)); - if (yy + yy > xx * xx) - return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r + xx) : ziggurat_nor_r + xx; - } - } - else - { - if (((fi_double[idx - 1] - fi_double[idx]) * prng_state->next_double(prng_state->state) + fi_double[idx]) < exp(-0.5 * x * x)) - return x; - } +double random_gauss_zig(prng_t *prng_state) { + uint64_t r; + int sign; + int64_t rabs; + int idx; + double x, xx, yy; + for (;;) { + /* r = e3n52sb8 */ + r = prng_state->next_uint64(prng_state->state); + idx = r & 0xff; + r >>= 8; + sign = r & 0x1; + rabs = (int64_t)((r >> 1) & 0x000fffffffffffff); + x = rabs * wi_double[idx]; + if (sign & 0x1) + x = -x; + if (rabs < ki_double[idx]) + return x; // # 99.3% of the time return here + if (idx == 0) { + for (;;) { + xx = -ziggurat_nor_inv_r * + log(prng_state->next_double(prng_state->state)); + yy = -log(prng_state->next_double(prng_state->state)); + if (yy + yy > xx * xx) + return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r + xx) + : ziggurat_nor_r + xx; + } + } else { + if (((fi_double[idx - 1] - fi_double[idx]) * + prng_state->next_double(prng_state->state) + + fi_double[idx]) < exp(-0.5 * x * x)) + return x; } + } } -float random_gauss_zig_f(prng_t* prng_state) -{ - uint32_t r; - int sign; - int32_t rabs; - int idx; - float x, xx, yy; - for (;;) - { - /* r = n23sb8 */ - r = prng_state->next_uint32(prng_state->state); - idx = r & 0xff; - sign = (r >> 8) & 0x1; - rabs = (int32_t)((r >> 9) & 0x0007fffff); - x = rabs * wi_float[idx]; - if (sign & 0x1) - x = -x; - if (rabs < ki_float[idx]) - return x; // # 99.3% of the time return here - if (idx == 0) - { - for (;;) - { - xx = -ziggurat_nor_inv_r_f * logf(next_float(prng_state)); - yy = -logf(next_float(prng_state)); - if (yy + yy > xx * xx) - return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r_f + xx) : ziggurat_nor_r_f + xx; - } - } - else - { - if (((fi_float[idx - 1] - fi_float[idx]) * next_float(prng_state) + fi_float[idx]) < exp(-0.5 * x * x)) - return x; - } +float random_gauss_zig_f(prng_t *prng_state) { + uint32_t r; + int sign; + int32_t rabs; + int idx; + float x, xx, yy; + for (;;) { + /* r = n23sb8 */ + r = prng_state->next_uint32(prng_state->state); + idx = r & 0xff; + sign = (r >> 8) & 0x1; + rabs = (int32_t)((r >> 9) & 0x0007fffff); + x = rabs * wi_float[idx]; + if (sign & 0x1) + x = -x; + if (rabs < ki_float[idx]) + return x; // # 99.3% of the time return here + if (idx == 0) { + for (;;) { + xx = -ziggurat_nor_inv_r_f * logf(next_float(prng_state)); + yy = -logf(next_float(prng_state)); + if (yy + yy > xx * xx) + return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r_f + xx) + : ziggurat_nor_r_f + xx; + } + } else { + if (((fi_float[idx - 1] - fi_float[idx]) * next_float(prng_state) + + fi_float[idx]) < exp(-0.5 * x * x)) + return x; } + } } -static NPY_INLINE double standard_gamma(prng_t* prng_state, double shape) -{ - double b, c; - double U, V, X, Y; - - if (shape == 1.0) - { - return random_standard_exponential(prng_state); - } - else if (shape < 1.0) - { - for (;;) - { - U = prng_state->next_double(prng_state->state); - V = random_standard_exponential(prng_state); - if (U <= 1.0 - shape) - { - X = pow(U, 1. / shape); - if (X <= V) - { - return X; - } - } - else - { - Y = -log((1 - U) / shape); - X = pow(1.0 - shape + shape * Y, 1. / shape); - if (X <= (V + Y)) - { - return X; - } - } +static NPY_INLINE double standard_gamma(prng_t *prng_state, double shape) { + double b, c; + double U, V, X, Y; + + if (shape == 1.0) { + return random_standard_exponential(prng_state); + } else if (shape < 1.0) { + for (;;) { + U = prng_state->next_double(prng_state->state); + V = random_standard_exponential(prng_state); + if (U <= 1.0 - shape) { + X = pow(U, 1. / shape); + if (X <= V) { + return X; } - } - else - { - b = shape - 1. / 3.; - c = 1. / sqrt(9 * b); - for (;;) - { - do - { - X = random_gauss(prng_state); - V = 1.0 + c * X; - } while (V <= 0.0); - - V = V * V * V; - U = random_sample(prng_state); - if (U < 1.0 - 0.0331 * (X * X) * (X * X)) - return (b * V); - if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) - return (b * V); + } else { + Y = -log((1 - U) / shape); + X = pow(1.0 - shape + shape * Y, 1. / shape); + if (X <= (V + Y)) { + return X; } + } + } + } else { + b = shape - 1. / 3.; + c = 1. / sqrt(9 * b); + for (;;) { + do { + X = random_gauss(prng_state); + V = 1.0 + c * X; + } while (V <= 0.0); + + V = V * V * V; + U = random_sample(prng_state); + if (U < 1.0 - 0.0331 * (X * X) * (X * X)) + return (b * V); + if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) + return (b * V); } + } } -static NPY_INLINE float standard_gamma_float(prng_t *prng_state, float shape) -{ - float b, c; - float U, V, X, Y; - - if (shape == 1.0f) - { - return random_standard_exponential_f(prng_state); - } - else if (shape < 1.0f) - { - for (;;) - { - U = random_sample_f(prng_state); - V = random_standard_exponential_f(prng_state); - if (U <= 1.0f - shape) - { - X = powf(U, 1.0f / shape); - if (X <= V) - { - return X; - } - } - else - { - Y = -logf((1.0f - U) / shape); - X = powf(1.0f - shape + shape * Y, 1.0f / shape); - if (X <= (V + Y)) - { - return X; - } - } +static NPY_INLINE float standard_gamma_float(prng_t *prng_state, float shape) { + float b, c; + float U, V, X, Y; + + if (shape == 1.0f) { + return random_standard_exponential_f(prng_state); + } else if (shape < 1.0f) { + for (;;) { + U = random_sample_f(prng_state); + V = random_standard_exponential_f(prng_state); + if (U <= 1.0f - shape) { + X = powf(U, 1.0f / shape); + if (X <= V) { + return X; } - } - else - { - b = shape - 1.0f / 3.0f; - c = 1.0f / sqrtf(9.0f * b); - for (;;) - { - do - { - X = random_gauss_f(prng_state); - V = 1.0f + c * X; - } while (V <= 0.0f); - - V = V * V * V; - U = random_sample_f(prng_state); - if (U < 1.0f - 0.0331f * (X * X) * (X * X)) - return (b * V); - if (logf(U) < 0.5f * X * X + b * (1.0f - V + logf(V))) - return (b * V); + } else { + Y = -logf((1.0f - U) / shape); + X = powf(1.0f - shape + shape * Y, 1.0f / shape); + if (X <= (V + Y)) { + return X; } + } } + } else { + b = shape - 1.0f / 3.0f; + c = 1.0f / sqrtf(9.0f * b); + for (;;) { + do { + X = random_gauss_f(prng_state); + V = 1.0f + c * X; + } while (V <= 0.0f); + + V = V * V * V; + U = random_sample_f(prng_state); + if (U < 1.0f - 0.0331f * (X * X) * (X * X)) + return (b * V); + if (logf(U) < 0.5f * X * X + b * (1.0f - V + logf(V))) + return (b * V); + } + } } - -double random_standard_gamma(prng_t* prng_state, double shape) -{ - return standard_gamma(prng_state, shape); +double random_standard_gamma(prng_t *prng_state, double shape) { + return standard_gamma(prng_state, shape); } -float random_standard_gamma_f(prng_t* prng_state, float shape) -{ - return standard_gamma_float(prng_state, shape); +float random_standard_gamma_f(prng_t *prng_state, float shape) { + return standard_gamma_float(prng_state, shape); } - -static NPY_INLINE double standard_gamma_zig(prng_t *prng_state, double shape) -{ - double b, c; - double U, V, X, Y; - - if (shape == 1.0) - { - return random_standard_exponential_zig(prng_state); - } - else if (shape < 1.0) - { - for (;;) - { - U = random_sample(prng_state); - V = random_standard_exponential_zig(prng_state); - if (U <= 1.0 - shape) - { - X = pow(U, 1. / shape); - if (X <= V) - { - return X; - } - } - else - { - Y = -log((1 - U) / shape); - X = pow(1.0 - shape + shape * Y, 1. / shape); - if (X <= (V + Y)) - { - return X; - } - } +static NPY_INLINE double standard_gamma_zig(prng_t *prng_state, double shape) { + double b, c; + double U, V, X, Y; + + if (shape == 1.0) { + return random_standard_exponential_zig(prng_state); + } else if (shape < 1.0) { + for (;;) { + U = random_sample(prng_state); + V = random_standard_exponential_zig(prng_state); + if (U <= 1.0 - shape) { + X = pow(U, 1. / shape); + if (X <= V) { + return X; } - } - else - { - b = shape - 1. / 3.; - c = 1. / sqrt(9 * b); - for (;;) - { - do - { - X = random_gauss_zig(prng_state); - V = 1.0 + c * X; - } while (V <= 0.0); - - V = V * V * V; - U = random_sample(prng_state); - if (U < 1.0 - 0.0331 * (X * X) * (X * X)) - return (b * V); - if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) - return (b * V); + } else { + Y = -log((1 - U) / shape); + X = pow(1.0 - shape + shape * Y, 1. / shape); + if (X <= (V + Y)) { + return X; } + } } + } else { + b = shape - 1. / 3.; + c = 1. / sqrt(9 * b); + for (;;) { + do { + X = random_gauss_zig(prng_state); + V = 1.0 + c * X; + } while (V <= 0.0); + + V = V * V * V; + U = random_sample(prng_state); + if (U < 1.0 - 0.0331 * (X * X) * (X * X)) + return (b * V); + if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) + return (b * V); + } + } } -static NPY_INLINE float standard_gamma_zig_f(prng_t *prng_state, float shape) -{ - float b, c; - float U, V, X, Y; - - if (shape == 1.0f) - { - return random_standard_exponential_zig_f(prng_state); - } - else if (shape < 1.0f) - { - for (;;) - { - U = random_sample_f(prng_state); - V = random_standard_exponential_zig_f(prng_state); - if (U <= 1.0f - shape) - { - X = powf(U, 1.0f / shape); - if (X <= V) - { - return X; - } - } - else - { - Y = -logf((1.0f - U) / shape); - X = powf(1.0f - shape + shape * Y, 1.0f / shape); - if (X <= (V + Y)) - { - return X; - } - } +static NPY_INLINE float standard_gamma_zig_f(prng_t *prng_state, float shape) { + float b, c; + float U, V, X, Y; + + if (shape == 1.0f) { + return random_standard_exponential_zig_f(prng_state); + } else if (shape < 1.0f) { + for (;;) { + U = random_sample_f(prng_state); + V = random_standard_exponential_zig_f(prng_state); + if (U <= 1.0f - shape) { + X = powf(U, 1.0f / shape); + if (X <= V) { + return X; } - } - else - { - b = shape - 1.0f / 3.0f; - c = 1.0f / sqrtf(9.0f * b); - for (;;) - { - do - { - X = random_gauss_zig_f(prng_state); - V = 1.0f + c * X; - } while (V <= 0.0f); - - V = V * V * V; - U = random_sample_f(prng_state); - if (U < 1.0f - 0.0331f * (X * X) * (X * X)) - return (b * V); - if (logf(U) < 0.5f * X * X + b * (1.0f - V + logf(V))) - return (b * V); + } else { + Y = -logf((1.0f - U) / shape); + X = powf(1.0f - shape + shape * Y, 1.0f / shape); + if (X <= (V + Y)) { + return X; } + } + } + } else { + b = shape - 1.0f / 3.0f; + c = 1.0f / sqrtf(9.0f * b); + for (;;) { + do { + X = random_gauss_zig_f(prng_state); + V = 1.0f + c * X; + } while (V <= 0.0f); + + V = V * V * V; + U = random_sample_f(prng_state); + if (U < 1.0f - 0.0331f * (X * X) * (X * X)) + return (b * V); + if (logf(U) < 0.5f * X * X + b * (1.0f - V + logf(V))) + return (b * V); } + } } -double random_standard_gamma_zig(prng_t *prng_state, double shape) -{ - return standard_gamma_zig(prng_state, shape); +double random_standard_gamma_zig(prng_t *prng_state, double shape) { + return standard_gamma_zig(prng_state, shape); } -float random_standard_gamma_zig_f(prng_t *prng_state, float shape) -{ - return standard_gamma_zig_f(prng_state, shape); +float random_standard_gamma_zig_f(prng_t *prng_state, float shape) { + return standard_gamma_zig_f(prng_state, shape); } diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c b/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c index 9103f6d5030d..c34451236ec7 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c @@ -1,53 +1,50 @@ /* -* -* gcc dSFMT-test-gen.c dSFMT.c -DHAVE_SSE2 -DDSFMT_MEXP=19937 -o dSFMT -*/ -#include -#include + * + * gcc dSFMT-test-gen.c dSFMT.c -DHAVE_SSE2 -DDSFMT_MEXP=19937 -o dSFMT + */ #include "dSFMT.h" +#include +#include -int main(void) -{ - int i; - double d; - uint64_t *temp; - uint32_t seed = 1UL; - dsfmt_t state; - dsfmt_init_gen_rand(&state, seed); - double out[1000]; - dsfmt_fill_array_close1_open2(&state, out, 1000); +int main(void) { + int i; + double d; + uint64_t *temp; + uint32_t seed = 1UL; + dsfmt_t state; + dsfmt_init_gen_rand(&state, seed); + double out[1000]; + dsfmt_fill_array_close1_open2(&state, out, 1000); - FILE *fp; - fp = fopen("dSFMT-testset-1.csv", "w"); - if(fp == NULL){ - printf("Couldn't open file\n"); - return -1; - } - fprintf(fp, "seed, %" PRIu32 "\n", seed); - for (i=0; i < 1000; i++) - { - d = out[i]; - temp = (uint64_t *)&d; - fprintf(fp, "%d, %" PRIu64 "\n", i, *temp); - printf("%d, %" PRIu64 "\n", i, *temp); - } - fclose(fp); + FILE *fp; + fp = fopen("dSFMT-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, %" PRIu32 "\n", seed); + for (i = 0; i < 1000; i++) { + d = out[i]; + temp = (uint64_t *)&d; + fprintf(fp, "%d, %" PRIu64 "\n", i, *temp); + printf("%d, %" PRIu64 "\n", i, *temp); + } + fclose(fp); - seed = 123456789UL; - dsfmt_init_gen_rand(&state, seed); - dsfmt_fill_array_close1_open2(&state, out, 1000); - fp = fopen("dSFMT-testset-2.csv", "w"); - if(fp == NULL){ - printf("Couldn't open file\n"); - return -1; - } - fprintf(fp, "seed, %" PRIu32 "\n", seed); - for (i=0; i < 1000; i++) - { - d = out[i]; - temp = (uint64_t *)&d; - fprintf(fp, "%d, %" PRIu64 "\n", i, *temp); - printf("%d, %" PRIu64 "\n", i, *temp); - } - fclose(fp); -} \ No newline at end of file + seed = 123456789UL; + dsfmt_init_gen_rand(&state, seed); + dsfmt_fill_array_close1_open2(&state, out, 1000); + fp = fopen("dSFMT-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, %" PRIu32 "\n", seed); + for (i = 0; i < 1000; i++) { + d = out[i]; + temp = (uint64_t *)&d; + fprintf(fp, "%d, %" PRIu64 "\n", i, *temp); + printf("%d, %" PRIu64 "\n", i, *temp); + } + fclose(fp); +} diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.c b/_randomgen/core_prng/src/dsfmt/dSFMT.c index 3ce156699175..0955e087fbaa 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT.c +++ b/_randomgen/core_prng/src/dsfmt/dSFMT.c @@ -11,11 +11,11 @@ * * The new BSD License is applied to this software, see LICENSE.txt */ +#include "dSFMT-common.h" +#include "dSFMT-params.h" #include -#include #include -#include "dSFMT-params.h" -#include "dSFMT-common.h" +#include #if defined(__cplusplus) extern "C" { @@ -31,14 +31,10 @@ static const int dsfmt_mexp = DSFMT_MEXP; ----------------*/ inline static uint32_t ini_func1(uint32_t x); inline static uint32_t ini_func2(uint32_t x); -inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, - int size); -inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, - int size); -inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, - int size); -inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, - int size); +inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, int size); +inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, int size); +inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, int size); +inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, int size); inline static int idxof(int i); static void initial_mask(dsfmt_t *dsfmt); static void period_certification(dsfmt_t *dsfmt); @@ -57,13 +53,9 @@ static const union X128D_T sse2_double_m_one = {{-1.0, -1.0}}; * array of LITTLE ENDIAN in BIG ENDIAN machine. */ #if defined(DSFMT_BIG_ENDIAN) -inline static int idxof(int i) { - return i ^ 1; -} +inline static int idxof(int i) { return i ^ 1; } #else -inline static int idxof(int i) { - return i; -} +inline static int idxof(int i) { return i; } #endif #if defined(HAVE_SSE2) @@ -74,7 +66,7 @@ inline static int idxof(int i) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_c0o1(w128_t *w) { - w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); + w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); } /** @@ -84,7 +76,7 @@ inline static void convert_c0o1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0c1(w128_t *w) { - w->sd = _mm_sub_pd(sse2_double_two.d128, w->sd); + w->sd = _mm_sub_pd(sse2_double_two.d128, w->sd); } /** @@ -94,8 +86,8 @@ inline static void convert_o0c1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0o1(w128_t *w) { - w->si = _mm_or_si128(w->si, sse2_int_one.i128); - w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); + w->si = _mm_or_si128(w->si, sse2_int_one.i128); + w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); } #else /* standard C and altivec */ /** @@ -105,8 +97,8 @@ inline static void convert_o0o1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_c0o1(w128_t *w) { - w->d[0] -= 1.0; - w->d[1] -= 1.0; + w->d[0] -= 1.0; + w->d[1] -= 1.0; } /** @@ -116,8 +108,8 @@ inline static void convert_c0o1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0c1(w128_t *w) { - w->d[0] = 2.0 - w->d[0]; - w->d[1] = 2.0 - w->d[1]; + w->d[0] = 2.0 - w->d[0]; + w->d[1] = 2.0 - w->d[1]; } /** @@ -127,10 +119,10 @@ inline static void convert_o0c1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0o1(w128_t *w) { - w->u[0] |= 1; - w->u[1] |= 1; - w->d[0] -= 1.0; - w->d[1] -= 1.0; + w->u[0] |= 1; + w->u[1] |= 1; + w->d[0] -= 1.0; + w->d[1] -= 1.0; } #endif @@ -142,34 +134,33 @@ inline static void convert_o0o1(w128_t *w) { * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], - &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], + &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], + &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -180,39 +171,38 @@ inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], - &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - convert_c0o1(&array[i - DSFMT_N]); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - convert_c0o1(&array[i - DSFMT_N]); - } - for (i = size - DSFMT_N; i < size; i++) { - convert_c0o1(&array[i]); - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], + &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], + &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_c0o1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_c0o1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_c0o1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -223,39 +213,38 @@ inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], - &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - convert_o0o1(&array[i - DSFMT_N]); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - convert_o0o1(&array[i - DSFMT_N]); - } - for (i = size - DSFMT_N; i < size; i++) { - convert_o0o1(&array[i]); - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], + &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], + &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_o0o1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_o0o1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_o0o1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -266,39 +255,38 @@ inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], - &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - convert_o0c1(&array[i - DSFMT_N]); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - convert_o0c1(&array[i - DSFMT_N]); - } - for (i = size - DSFMT_N; i < size; i++) { - convert_o0c1(&array[i]); - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], + &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], + &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_o0c1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_o0c1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_o0c1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -308,7 +296,7 @@ inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, * @return 32-bit integer */ static uint32_t ini_func1(uint32_t x) { - return (x ^ (x >> 27)) * (uint32_t)1664525UL; + return (x ^ (x >> 27)) * (uint32_t)1664525UL; } /** @@ -318,7 +306,7 @@ static uint32_t ini_func1(uint32_t x) { * @return 32-bit integer */ static uint32_t ini_func2(uint32_t x) { - return (x ^ (x >> 27)) * (uint32_t)1566083941UL; + return (x ^ (x >> 27)) * (uint32_t)1566083941UL; } /** @@ -327,13 +315,13 @@ static uint32_t ini_func2(uint32_t x) { * @param dsfmt dsfmt state vector. */ static void initial_mask(dsfmt_t *dsfmt) { - int i; - uint64_t *psfmt; + int i; + uint64_t *psfmt; - psfmt = &dsfmt->status[0].u[0]; - for (i = 0; i < DSFMT_N * 2; i++) { - psfmt[i] = (psfmt[i] & DSFMT_LOW_MASK) | DSFMT_HIGH_CONST; - } + psfmt = &dsfmt->status[0].u[0]; + for (i = 0; i < DSFMT_N * 2; i++) { + psfmt[i] = (psfmt[i] & DSFMT_LOW_MASK) | DSFMT_HIGH_CONST; + } } /** @@ -341,44 +329,44 @@ static void initial_mask(dsfmt_t *dsfmt) { * @param dsfmt dsfmt state vector. */ static void period_certification(dsfmt_t *dsfmt) { - uint64_t pcv[2] = {DSFMT_PCV1, DSFMT_PCV2}; - uint64_t tmp[2]; - uint64_t inner; - int i; + uint64_t pcv[2] = {DSFMT_PCV1, DSFMT_PCV2}; + uint64_t tmp[2]; + uint64_t inner; + int i; #if (DSFMT_PCV2 & 1) != 1 - int j; - uint64_t work; + int j; + uint64_t work; #endif - tmp[0] = (dsfmt->status[DSFMT_N].u[0] ^ DSFMT_FIX1); - tmp[1] = (dsfmt->status[DSFMT_N].u[1] ^ DSFMT_FIX2); - - inner = tmp[0] & pcv[0]; - inner ^= tmp[1] & pcv[1]; - for (i = 32; i > 0; i >>= 1) { - inner ^= inner >> i; - } - inner &= 1; - /* check OK */ - if (inner == 1) { - return; - } + tmp[0] = (dsfmt->status[DSFMT_N].u[0] ^ DSFMT_FIX1); + tmp[1] = (dsfmt->status[DSFMT_N].u[1] ^ DSFMT_FIX2); + + inner = tmp[0] & pcv[0]; + inner ^= tmp[1] & pcv[1]; + for (i = 32; i > 0; i >>= 1) { + inner ^= inner >> i; + } + inner &= 1; + /* check OK */ + if (inner == 1) { + return; + } /* check NG, and modification */ #if (DSFMT_PCV2 & 1) == 1 - dsfmt->status[DSFMT_N].u[1] ^= 1; + dsfmt->status[DSFMT_N].u[1] ^= 1; #else - for (i = 1; i >= 0; i--) { - work = 1; - for (j = 0; j < 64; j++) { - if ((work & pcv[i]) != 0) { - dsfmt->status[DSFMT_N].u[i] ^= work; - return; - } - work = work << 1; - } - } + for (i = 1; i >= 0; i--) { + work = 1; + for (j = 0; j < 64; j++) { + if ((work & pcv[i]) != 0) { + dsfmt->status[DSFMT_N].u[i] ^= work; + return; + } + work = work << 1; + } + } #endif - return; + return; } /*---------------- @@ -389,18 +377,14 @@ static void period_certification(dsfmt_t *dsfmt) { * the Mersenne exponent, and all parameters of this generator. * @return id string. */ -const char *dsfmt_get_idstring(void) { - return DSFMT_IDSTR; -} +const char *dsfmt_get_idstring(void) { return DSFMT_IDSTR; } /** * This function returns the minimum size of array used for \b * fill_array functions. * @return minimum size of array used for fill_array functions. */ -int dsfmt_get_min_array_size(void) { - return DSFMT_N64; -} +int dsfmt_get_min_array_size(void) { return DSFMT_N64; } /** * This function fills the internal state array with double precision @@ -408,21 +392,21 @@ int dsfmt_get_min_array_size(void) { * @param dsfmt dsfmt state vector. */ void dsfmt_gen_rand_all(dsfmt_t *dsfmt) { - int i; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&dsfmt->status[0], &dsfmt->status[0], - &dsfmt->status[DSFMT_POS1], &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&dsfmt->status[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&dsfmt->status[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1 - DSFMT_N], &lung); - } - dsfmt->status[DSFMT_N] = lung; + int i; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&dsfmt->status[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], + &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&dsfmt->status[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&dsfmt->status[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1 - DSFMT_N], &lung); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -454,9 +438,9 @@ void dsfmt_gen_rand_all(dsfmt_t *dsfmt) { * returns the pointer to the aligned memory block. */ void dsfmt_fill_array_close1_open2(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_c1o2(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_c1o2(dsfmt, (w128_t *)array, size / 2); } /** @@ -472,9 +456,9 @@ void dsfmt_fill_array_close1_open2(dsfmt_t *dsfmt, double array[], int size) { * see also \sa fill_array_close1_open2() */ void dsfmt_fill_array_open_close(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_o0c1(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_o0c1(dsfmt, (w128_t *)array, size / 2); } /** @@ -490,9 +474,9 @@ void dsfmt_fill_array_open_close(dsfmt_t *dsfmt, double array[], int size) { * see also \sa fill_array_close1_open2() */ void dsfmt_fill_array_close_open(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_c0o1(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_c0o1(dsfmt, (w128_t *)array, size / 2); } /** @@ -508,13 +492,13 @@ void dsfmt_fill_array_close_open(dsfmt_t *dsfmt, double array[], int size) { * see also \sa fill_array_close1_open2() */ void dsfmt_fill_array_open_open(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_o0o1(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_o0o1(dsfmt, (w128_t *)array, size / 2); } #if defined(__INTEL_COMPILER) -# pragma warning(disable:981) +#pragma warning(disable : 981) #endif /** * This function initializes the internal state array with a 32-bit @@ -524,23 +508,23 @@ void dsfmt_fill_array_open_open(dsfmt_t *dsfmt, double array[], int size) { * @param mexp caller's mersenne expornent */ void dsfmt_chk_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed, int mexp) { - int i; - uint32_t *psfmt; - - /* make sure caller program is compiled with the same MEXP */ - if (mexp != dsfmt_mexp) { - fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); - exit(1); - } - psfmt = &dsfmt->status[0].u32[0]; - psfmt[idxof(0)] = seed; - for (i = 1; i < (DSFMT_N + 1) * 4; i++) { - psfmt[idxof(i)] = 1812433253UL - * (psfmt[idxof(i - 1)] ^ (psfmt[idxof(i - 1)] >> 30)) + i; - } - initial_mask(dsfmt); - period_certification(dsfmt); - dsfmt->idx = DSFMT_N64; + int i; + uint32_t *psfmt; + + /* make sure caller program is compiled with the same MEXP */ + if (mexp != dsfmt_mexp) { + fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); + exit(1); + } + psfmt = &dsfmt->status[0].u32[0]; + psfmt[idxof(0)] = seed; + for (i = 1; i < (DSFMT_N + 1) * 4; i++) { + psfmt[idxof(i)] = + 1812433253UL * (psfmt[idxof(i - 1)] ^ (psfmt[idxof(i - 1)] >> 30)) + i; + } + initial_mask(dsfmt); + period_certification(dsfmt); + dsfmt->idx = DSFMT_N64; } /** @@ -552,80 +536,77 @@ void dsfmt_chk_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed, int mexp) { * @param mexp caller's mersenne expornent */ void dsfmt_chk_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], - int key_length, int mexp) { - int i, j, count; - uint32_t r; - uint32_t *psfmt32; - int lag; - int mid; - int size = (DSFMT_N + 1) * 4; /* pulmonary */ - - /* make sure caller program is compiled with the same MEXP */ - if (mexp != dsfmt_mexp) { - fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); - exit(1); - } - if (size >= 623) { - lag = 11; - } else if (size >= 68) { - lag = 7; - } else if (size >= 39) { - lag = 5; - } else { - lag = 3; - } - mid = (size - lag) / 2; - - psfmt32 = &dsfmt->status[0].u32[0]; - memset(dsfmt->status, 0x8b, sizeof(dsfmt->status)); - if (key_length + 1 > size) { - count = key_length + 1; - } else { - count = size; - } - r = ini_func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid % size)] - ^ psfmt32[idxof((size - 1) % size)]); - psfmt32[idxof(mid % size)] += r; - r += key_length; - psfmt32[idxof((mid + lag) % size)] += r; - psfmt32[idxof(0)] = r; - count--; - for (i = 1, j = 0; (j < count) && (j < key_length); j++) { - r = ini_func1(psfmt32[idxof(i)] - ^ psfmt32[idxof((i + mid) % size)] - ^ psfmt32[idxof((i + size - 1) % size)]); - psfmt32[idxof((i + mid) % size)] += r; - r += init_key[j] + i; - psfmt32[idxof((i + mid + lag) % size)] += r; - psfmt32[idxof(i)] = r; - i = (i + 1) % size; - } - for (; j < count; j++) { - r = ini_func1(psfmt32[idxof(i)] - ^ psfmt32[idxof((i + mid) % size)] - ^ psfmt32[idxof((i + size - 1) % size)]); - psfmt32[idxof((i + mid) % size)] += r; - r += i; - psfmt32[idxof((i + mid + lag) % size)] += r; - psfmt32[idxof(i)] = r; - i = (i + 1) % size; - } - for (j = 0; j < size; j++) { - r = ini_func2(psfmt32[idxof(i)] - + psfmt32[idxof((i + mid) % size)] - + psfmt32[idxof((i + size - 1) % size)]); - psfmt32[idxof((i + mid) % size)] ^= r; - r -= i; - psfmt32[idxof((i + mid + lag) % size)] ^= r; - psfmt32[idxof(i)] = r; - i = (i + 1) % size; - } - initial_mask(dsfmt); - period_certification(dsfmt); - dsfmt->idx = DSFMT_N64; + int key_length, int mexp) { + int i, j, count; + uint32_t r; + uint32_t *psfmt32; + int lag; + int mid; + int size = (DSFMT_N + 1) * 4; /* pulmonary */ + + /* make sure caller program is compiled with the same MEXP */ + if (mexp != dsfmt_mexp) { + fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); + exit(1); + } + if (size >= 623) { + lag = 11; + } else if (size >= 68) { + lag = 7; + } else if (size >= 39) { + lag = 5; + } else { + lag = 3; + } + mid = (size - lag) / 2; + + psfmt32 = &dsfmt->status[0].u32[0]; + memset(dsfmt->status, 0x8b, sizeof(dsfmt->status)); + if (key_length + 1 > size) { + count = key_length + 1; + } else { + count = size; + } + r = ini_func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid % size)] ^ + psfmt32[idxof((size - 1) % size)]); + psfmt32[idxof(mid % size)] += r; + r += key_length; + psfmt32[idxof((mid + lag) % size)] += r; + psfmt32[idxof(0)] = r; + count--; + for (i = 1, j = 0; (j < count) && (j < key_length); j++) { + r = ini_func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % size)] ^ + psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] += r; + r += init_key[j] + i; + psfmt32[idxof((i + mid + lag) % size)] += r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + for (; j < count; j++) { + r = ini_func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % size)] ^ + psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] += r; + r += i; + psfmt32[idxof((i + mid + lag) % size)] += r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + for (j = 0; j < size; j++) { + r = ini_func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % size)] + + psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] ^= r; + r -= i; + psfmt32[idxof((i + mid + lag) % size)] ^= r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + initial_mask(dsfmt); + period_certification(dsfmt); + dsfmt->idx = DSFMT_N64; } #if defined(__INTEL_COMPILER) -# pragma warning(default:981) +#pragma warning(default : 981) #endif #if defined(__cplusplus) @@ -636,4 +617,4 @@ extern inline double dsfmt_next_double(dsfmt_state *state); extern inline uint64_t dsfmt_next64(dsfmt_state *state); -extern inline uint32_t dsfmt_next32(dsfmt_state *state); \ No newline at end of file +extern inline uint32_t dsfmt_next32(dsfmt_state *state); diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.h b/_randomgen/core_prng/src/dsfmt/dSFMT.h index 52b6b3aedcc2..c9a34ae86691 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT.h +++ b/_randomgen/core_prng/src/dsfmt/dSFMT.h @@ -38,14 +38,14 @@ extern "C" { #endif -#include #include +#include #if !defined(DSFMT_MEXP) #ifdef __GNUC__ - #warning "DSFMT_MEXP is not defined. I assume DSFMT_MEXP is 19937." +#warning "DSFMT_MEXP is not defined. I assume DSFMT_MEXP is 19937." #endif - #define DSFMT_MEXP 19937 +#define DSFMT_MEXP 19937 #endif /*----------------- BASIC DEFINITIONS @@ -64,103 +64,103 @@ extern "C" { #define DSFMT_N64 (DSFMT_N * 2) #if !defined(DSFMT_BIG_ENDIAN) -# if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) -# if __BYTE_ORDER == __BIG_ENDIAN -# define DSFMT_BIG_ENDIAN 1 -# endif -# elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) -# if _BYTE_ORDER == _BIG_ENDIAN -# define DSFMT_BIG_ENDIAN 1 -# endif -# elif defined(__BYTE_ORDER__) && defined(__BIG_ENDIAN__) -# if __BYTE_ORDER__ == __BIG_ENDIAN__ -# define DSFMT_BIG_ENDIAN 1 -# endif -# elif defined(BYTE_ORDER) && defined(BIG_ENDIAN) -# if BYTE_ORDER == BIG_ENDIAN -# define DSFMT_BIG_ENDIAN 1 -# endif -# elif defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) \ - || defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) -# define DSFMT_BIG_ENDIAN 1 -# endif +#if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) +#if __BYTE_ORDER == __BIG_ENDIAN +#define DSFMT_BIG_ENDIAN 1 +#endif +#elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) +#if _BYTE_ORDER == _BIG_ENDIAN +#define DSFMT_BIG_ENDIAN 1 +#endif +#elif defined(__BYTE_ORDER__) && defined(__BIG_ENDIAN__) +#if __BYTE_ORDER__ == __BIG_ENDIAN__ +#define DSFMT_BIG_ENDIAN 1 +#endif +#elif defined(BYTE_ORDER) && defined(BIG_ENDIAN) +#if BYTE_ORDER == BIG_ENDIAN +#define DSFMT_BIG_ENDIAN 1 +#endif +#elif defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) || \ + defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) +#define DSFMT_BIG_ENDIAN 1 +#endif #endif #if defined(DSFMT_BIG_ENDIAN) && defined(__amd64) -# undef DSFMT_BIG_ENDIAN +#undef DSFMT_BIG_ENDIAN #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -# include +#include #elif defined(_MSC_VER) || defined(__BORLANDC__) -# if !defined(DSFMT_UINT32_DEFINED) && !defined(SFMT_UINT32_DEFINED) +#if !defined(DSFMT_UINT32_DEFINED) && !defined(SFMT_UINT32_DEFINED) typedef unsigned int uint32_t; typedef unsigned __int64 uint64_t; -# ifndef UINT64_C -# define UINT64_C(v) (v ## ui64) -# endif -# define DSFMT_UINT32_DEFINED -# if !defined(inline) && !defined(__cplusplus) -# define inline __forceinline -# endif -# endif +#ifndef UINT64_C +#define UINT64_C(v) (v##ui64) +#endif +#define DSFMT_UINT32_DEFINED +#if !defined(inline) && !defined(__cplusplus) +#define inline __forceinline +#endif +#endif +#else +#include +#if !defined(inline) && !defined(__cplusplus) +#if defined(__GNUC__) +#define inline __forceinline__ #else -# include -# if !defined(inline) && !defined(__cplusplus) -# if defined(__GNUC__) -# define inline __forceinline__ -# else -# define inline -# endif -# endif +#define inline +#endif +#endif #endif #ifndef PRIu64 -# if defined(_MSC_VER) || defined(__BORLANDC__) -# define PRIu64 "I64u" -# define PRIx64 "I64x" -# else -# define PRIu64 "llu" -# define PRIx64 "llx" -# endif +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#else +#define PRIu64 "llu" +#define PRIx64 "llx" +#endif #endif #ifndef UINT64_C -# define UINT64_C(v) (v ## ULL) +#define UINT64_C(v) (v##ULL) #endif /*------------------------------------------ 128-bit SIMD like data type for standard C ------------------------------------------*/ #if defined(HAVE_ALTIVEC) -# if !defined(__APPLE__) -# include -# endif +#if !defined(__APPLE__) +#include +#endif /** 128-bit data structure */ union W128_T { - vector unsigned int s; - uint64_t u[2]; - uint32_t u32[4]; - double d[2]; + vector unsigned int s; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; }; #elif defined(HAVE_SSE2) -# include +#include /** 128-bit data structure */ union W128_T { - __m128i si; - __m128d sd; - uint64_t u[2]; - uint32_t u32[4]; - double d[2]; + __m128i si; + __m128d sd; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; }; -#else /* standard C */ +#else /* standard C */ /** 128-bit data structure */ union W128_T { - uint64_t u[2]; - uint32_t u32[4]; - double d[2]; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; }; #endif @@ -169,8 +169,8 @@ typedef union W128_T w128_t; /** the 128-bit internal state array */ struct DSFMT_T { - w128_t status[DSFMT_N + 1]; - int idx; + w128_t status[DSFMT_N + 1]; + int idx; }; typedef struct DSFMT_T dsfmt_t; @@ -191,42 +191,42 @@ const char *dsfmt_get_idstring(void); int dsfmt_get_min_array_size(void); #if defined(__GNUC__) -# define DSFMT_PRE_INLINE inline static -# define DSFMT_PST_INLINE __attribute__((always_inline)) +#define DSFMT_PRE_INLINE inline static +#define DSFMT_PST_INLINE __attribute__((always_inline)) #elif defined(_MSC_VER) && _MSC_VER >= 1200 -# define DSFMT_PRE_INLINE __forceinline static -# define DSFMT_PST_INLINE +#define DSFMT_PRE_INLINE __forceinline static +#define DSFMT_PST_INLINE #else -# define DSFMT_PRE_INLINE inline static -# define DSFMT_PST_INLINE +#define DSFMT_PRE_INLINE inline static +#define DSFMT_PST_INLINE #endif DSFMT_PRE_INLINE uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double dsfmt_genrand_close_open(dsfmt_t *dsfmt) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double dsfmt_genrand_open_close(dsfmt_t *dsfmt) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double dsfmt_genrand_open_open(dsfmt_t *dsfmt) - DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double +dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double +dsfmt_genrand_close_open(dsfmt_t *dsfmt) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double +dsfmt_genrand_open_close(dsfmt_t *dsfmt) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double +dsfmt_genrand_open_open(dsfmt_t *dsfmt) DSFMT_PST_INLINE; DSFMT_PRE_INLINE uint32_t dsfmt_gv_genrand_uint32(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_close1_open2(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_close_open(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_open_close(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_open_open(void) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_close(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close_open(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_open(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close1_open2(double array[], int size) - DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_close(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close_open(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_open(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void +dsfmt_gv_fill_array_close1_open2(double array[], int size) DSFMT_PST_INLINE; DSFMT_PRE_INLINE void dsfmt_gv_init_gen_rand(uint32_t seed) DSFMT_PST_INLINE; DSFMT_PRE_INLINE void dsfmt_gv_init_by_array(uint32_t init_key[], int key_length) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) - DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_init_gen_rand(dsfmt_t *dsfmt, + uint32_t seed) DSFMT_PST_INLINE; DSFMT_PRE_INLINE void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) DSFMT_PST_INLINE; @@ -239,15 +239,15 @@ DSFMT_PRE_INLINE void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], * @return double precision floating point pseudorandom number */ inline static uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) { - uint32_t r; - uint64_t *psfmt64 = &dsfmt->status[0].u[0]; + uint32_t r; + uint64_t *psfmt64 = &dsfmt->status[0].u[0]; - if (dsfmt->idx >= DSFMT_N64) { - dsfmt_gen_rand_all(dsfmt); - dsfmt->idx = 0; - } - r = psfmt64[dsfmt->idx++] & 0xffffffffU; - return r; + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r = psfmt64[dsfmt->idx++] & 0xffffffffU; + return r; } /** @@ -260,15 +260,15 @@ inline static uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) { - double r; - double *psfmt64 = &dsfmt->status[0].d[0]; + double r; + double *psfmt64 = &dsfmt->status[0].d[0]; - if (dsfmt->idx >= DSFMT_N64) { - dsfmt_gen_rand_all(dsfmt); - dsfmt->idx = 0; - } - r = psfmt64[dsfmt->idx++]; - return r; + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r = psfmt64[dsfmt->idx++]; + return r; } /** @@ -279,7 +279,7 @@ inline static double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static uint32_t dsfmt_gv_genrand_uint32(void) { - return dsfmt_genrand_uint32(&dsfmt_global_data); + return dsfmt_genrand_uint32(&dsfmt_global_data); } /** @@ -290,7 +290,7 @@ inline static uint32_t dsfmt_gv_genrand_uint32(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_close1_open2(void) { - return dsfmt_genrand_close1_open2(&dsfmt_global_data); + return dsfmt_genrand_close1_open2(&dsfmt_global_data); } /** @@ -302,7 +302,7 @@ inline static double dsfmt_gv_genrand_close1_open2(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_close_open(dsfmt_t *dsfmt) { - return dsfmt_genrand_close1_open2(dsfmt) - 1.0; + return dsfmt_genrand_close1_open2(dsfmt) - 1.0; } /** @@ -313,7 +313,7 @@ inline static double dsfmt_genrand_close_open(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_close_open(void) { - return dsfmt_gv_genrand_close1_open2() - 1.0; + return dsfmt_gv_genrand_close1_open2() - 1.0; } /** @@ -325,7 +325,7 @@ inline static double dsfmt_gv_genrand_close_open(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_open_close(dsfmt_t *dsfmt) { - return 2.0 - dsfmt_genrand_close1_open2(dsfmt); + return 2.0 - dsfmt_genrand_close1_open2(dsfmt); } /** @@ -336,7 +336,7 @@ inline static double dsfmt_genrand_open_close(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_open_close(void) { - return 2.0 - dsfmt_gv_genrand_close1_open2(); + return 2.0 - dsfmt_gv_genrand_close1_open2(); } /** @@ -348,19 +348,19 @@ inline static double dsfmt_gv_genrand_open_close(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_open_open(dsfmt_t *dsfmt) { - double *dsfmt64 = &dsfmt->status[0].d[0]; - union { - double d; - uint64_t u; - } r; - - if (dsfmt->idx >= DSFMT_N64) { - dsfmt_gen_rand_all(dsfmt); - dsfmt->idx = 0; - } - r.d = dsfmt64[dsfmt->idx++]; - r.u |= 1; - return r.d - 1.0; + double *dsfmt64 = &dsfmt->status[0].d[0]; + union { + double d; + uint64_t u; + } r; + + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r.d = dsfmt64[dsfmt->idx++]; + r.u |= 1; + return r.d - 1.0; } /** @@ -371,7 +371,7 @@ inline static double dsfmt_genrand_open_open(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_open_open(void) { - return dsfmt_genrand_open_open(&dsfmt_global_data); + return dsfmt_genrand_open_open(&dsfmt_global_data); } /** @@ -386,7 +386,7 @@ inline static double dsfmt_gv_genrand_open_open(void) { * see also \sa dsfmt_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_close1_open2(double array[], int size) { - dsfmt_fill_array_close1_open2(&dsfmt_global_data, array, size); + dsfmt_fill_array_close1_open2(&dsfmt_global_data, array, size); } /** @@ -402,7 +402,7 @@ inline static void dsfmt_gv_fill_array_close1_open2(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_open_close(double array[], int size) { - dsfmt_fill_array_open_close(&dsfmt_global_data, array, size); + dsfmt_fill_array_open_close(&dsfmt_global_data, array, size); } /** @@ -418,7 +418,7 @@ inline static void dsfmt_gv_fill_array_open_close(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_close_open(double array[], int size) { - dsfmt_fill_array_close_open(&dsfmt_global_data, array, size); + dsfmt_fill_array_close_open(&dsfmt_global_data, array, size); } /** @@ -434,7 +434,7 @@ inline static void dsfmt_gv_fill_array_close_open(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_open_open(double array[], int size) { - dsfmt_fill_array_open_open(&dsfmt_global_data, array, size); + dsfmt_fill_array_open_open(&dsfmt_global_data, array, size); } /** @@ -444,7 +444,7 @@ inline static void dsfmt_gv_fill_array_open_open(double array[], int size) { * @param seed a 32-bit integer used as the seed. */ inline static void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) { - dsfmt_chk_init_gen_rand(dsfmt, seed, DSFMT_MEXP); + dsfmt_chk_init_gen_rand(dsfmt, seed, DSFMT_MEXP); } /** @@ -454,7 +454,7 @@ inline static void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) { * see also \sa dsfmt_init_gen_rand() */ inline static void dsfmt_gv_init_gen_rand(uint32_t seed) { - dsfmt_init_gen_rand(&dsfmt_global_data, seed); + dsfmt_init_gen_rand(&dsfmt_global_data, seed); } /** @@ -466,7 +466,7 @@ inline static void dsfmt_gv_init_gen_rand(uint32_t seed) { */ inline static void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) { - dsfmt_chk_init_by_array(dsfmt, init_key, key_length, DSFMT_MEXP); + dsfmt_chk_init_by_array(dsfmt, init_key, key_length, DSFMT_MEXP); } /** @@ -478,36 +478,34 @@ inline static void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], * see also \sa dsfmt_init_by_array() */ inline static void dsfmt_gv_init_by_array(uint32_t init_key[], int key_length) { - dsfmt_init_by_array(&dsfmt_global_data, init_key, key_length); + dsfmt_init_by_array(&dsfmt_global_data, init_key, key_length); } #if !defined(DSFMT_DO_NOT_USE_OLD_NAMES) DSFMT_PRE_INLINE const char *get_idstring(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE int get_min_array_size(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE void init_gen_rand(uint32_t seed) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void init_by_array(uint32_t init_key[], int key_length) - DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void init_by_array(uint32_t init_key[], + int key_length) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_close1_open2(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_close_open(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_open_close(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_open_open(void) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_open_close(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_close_open(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_open_open(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_close1_open2(double array[], int size) - DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_open_close(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_close_open(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_open_open(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_close1_open2(double array[], + int size) DSFMT_PST_INLINE; /** * This function is just the same as dsfmt_get_idstring(). * @return id string. * see also \sa dsfmt_get_idstring() */ -inline static const char *get_idstring(void) { - return dsfmt_get_idstring(); -} +inline static const char *get_idstring(void) { return dsfmt_get_idstring(); } /** * This function is just the same as dsfmt_get_min_array_size(). @@ -515,7 +513,7 @@ inline static const char *get_idstring(void) { * see also \sa dsfmt_get_min_array_size() */ inline static int get_min_array_size(void) { - return dsfmt_get_min_array_size(); + return dsfmt_get_min_array_size(); } /** @@ -524,7 +522,7 @@ inline static int get_min_array_size(void) { * see also \sa dsfmt_gv_init_gen_rand(), \sa dsfmt_init_gen_rand(). */ inline static void init_gen_rand(uint32_t seed) { - dsfmt_gv_init_gen_rand(seed); + dsfmt_gv_init_gen_rand(seed); } /** @@ -534,7 +532,7 @@ inline static void init_gen_rand(uint32_t seed) { * see also \sa dsfmt_gv_init_by_array(), \sa dsfmt_init_by_array(). */ inline static void init_by_array(uint32_t init_key[], int key_length) { - dsfmt_gv_init_by_array(init_key, key_length); + dsfmt_gv_init_by_array(init_key, key_length); } /** @@ -544,7 +542,7 @@ inline static void init_by_array(uint32_t init_key[], int key_length) { * dsfmt_gv_genrand_close1_open2() */ inline static double genrand_close1_open2(void) { - return dsfmt_gv_genrand_close1_open2(); + return dsfmt_gv_genrand_close1_open2(); } /** @@ -554,7 +552,7 @@ inline static double genrand_close1_open2(void) { * dsfmt_gv_genrand_close_open() */ inline static double genrand_close_open(void) { - return dsfmt_gv_genrand_close_open(); + return dsfmt_gv_genrand_close_open(); } /** @@ -564,7 +562,7 @@ inline static double genrand_close_open(void) { * dsfmt_gv_genrand_open_close() */ inline static double genrand_open_close(void) { - return dsfmt_gv_genrand_open_close(); + return dsfmt_gv_genrand_open_close(); } /** @@ -574,7 +572,7 @@ inline static double genrand_open_close(void) { * dsfmt_gv_genrand_open_open() */ inline static double genrand_open_open(void) { - return dsfmt_gv_genrand_open_open(); + return dsfmt_gv_genrand_open_open(); } /** @@ -587,7 +585,7 @@ inline static double genrand_open_open(void) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_open_close(double array[], int size) { - dsfmt_gv_fill_array_open_close(array, size); + dsfmt_gv_fill_array_open_close(array, size); } /** @@ -600,7 +598,7 @@ inline static void fill_array_open_close(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_close_open(double array[], int size) { - dsfmt_gv_fill_array_close_open(array, size); + dsfmt_gv_fill_array_close_open(array, size); } /** @@ -613,7 +611,7 @@ inline static void fill_array_close_open(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_open_open(double array[], int size) { - dsfmt_gv_fill_array_open_open(array, size); + dsfmt_gv_fill_array_open_open(array, size); } /** @@ -625,7 +623,7 @@ inline static void fill_array_open_open(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_close1_open2(double array[], int size) { - dsfmt_gv_fill_array_close1_open2(array, size); + dsfmt_gv_fill_array_close1_open2(array, size); } #endif /* DSFMT_DO_NOT_USE_OLD_NAMES */ @@ -635,7 +633,6 @@ inline static void fill_array_close1_open2(double array[], int size) { #endif /* DSFMT_H */ - typedef struct s_dsfmt_state { dsfmt_t *state; int has_uint32; @@ -651,7 +648,8 @@ static inline double dsfmt_next_double(dsfmt_state *state) { state->buffer_loc++; return out; } - dsfmt_fill_array_close_open(state->state, state->buffered_uniforms, DSFMT_N64); + dsfmt_fill_array_close_open(state->state, state->buffered_uniforms, + DSFMT_N64); state->buffer_loc = 1; return state->buffered_uniforms[0]; } @@ -669,7 +667,6 @@ static inline uint64_t dsfmt_next64(dsfmt_state *state) { return out; } - static inline uint32_t dsfmt_next32(dsfmt_state *state) { /* Discard bottom 16 bits */ double d = dsfmt_next_double(state); diff --git a/_randomgen/core_prng/src/mt19937/mt19937.c b/_randomgen/core_prng/src/mt19937/mt19937.c index 699efd21d08a..bb080c1a2ee1 100644 --- a/_randomgen/core_prng/src/mt19937/mt19937.c +++ b/_randomgen/core_prng/src/mt19937/mt19937.c @@ -1,109 +1,103 @@ #include "mt19937.h" -void mt19937_seed(mt19937_state *state, uint32_t seed) -{ - int pos; - seed &= 0xffffffffUL; - - /* Knuth's PRNG as used in the Mersenne Twister reference implementation */ - for (pos = 0; pos < RK_STATE_LEN; pos++) { - state->key[pos] = seed; - seed = (1812433253UL * (seed ^ (seed >> 30)) + pos + 1) & 0xffffffffUL; - } - state->pos = RK_STATE_LEN; +void mt19937_seed(mt19937_state *state, uint32_t seed) { + int pos; + seed &= 0xffffffffUL; + + /* Knuth's PRNG as used in the Mersenne Twister reference implementation */ + for (pos = 0; pos < RK_STATE_LEN; pos++) { + state->key[pos] = seed; + seed = (1812433253UL * (seed ^ (seed >> 30)) + pos + 1) & 0xffffffffUL; + } + state->pos = RK_STATE_LEN; } - /* initializes mt[RK_STATE_LEN] with a seed */ -static void init_genrand(mt19937_state *state, uint32_t s) -{ - int mti; - uint32_t *mt = state->key; - - mt[0] = s & 0xffffffffUL; - for (mti = 1; mti < RK_STATE_LEN; mti++) { - /* - * See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. - * In the previous versions, MSBs of the seed affect - * only MSBs of the array mt[]. - * 2002/01/09 modified by Makoto Matsumoto - */ - mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); - /* for > 32 bit machines */ - mt[mti] &= 0xffffffffUL; - } - state->pos = mti; - return; +static void init_genrand(mt19937_state *state, uint32_t s) { + int mti; + uint32_t *mt = state->key; + + mt[0] = s & 0xffffffffUL; + for (mti = 1; mti < RK_STATE_LEN; mti++) { + /* + * See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. + * In the previous versions, MSBs of the seed affect + * only MSBs of the array mt[]. + * 2002/01/09 modified by Makoto Matsumoto + */ + mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti); + /* for > 32 bit machines */ + mt[mti] &= 0xffffffffUL; + } + state->pos = mti; + return; } - /* * initialize by an array with array-length * init_key is the array for initializing keys * key_length is its length */ -void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, int key_length) -{ - /* was signed in the original code. RDH 12/16/2002 */ - int i = 1; - int j = 0; - uint32_t *mt = state->key; - int k; - - init_genrand(state, 19650218UL); - k = (RK_STATE_LEN > key_length ? RK_STATE_LEN : key_length); - for (; k; k--) { - /* non linear */ - mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL)) - + init_key[j] + j; - /* for > 32 bit machines */ - mt[i] &= 0xffffffffUL; - i++; - j++; - if (i >= RK_STATE_LEN) { - mt[0] = mt[RK_STATE_LEN - 1]; - i = 1; - } - if (j >= key_length) { - j = 0; - } +void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, + int key_length) { + /* was signed in the original code. RDH 12/16/2002 */ + int i = 1; + int j = 0; + uint32_t *mt = state->key; + int k; + + init_genrand(state, 19650218UL); + k = (RK_STATE_LEN > key_length ? RK_STATE_LEN : key_length); + for (; k; k--) { + /* non linear */ + mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL)) + + init_key[j] + j; + /* for > 32 bit machines */ + mt[i] &= 0xffffffffUL; + i++; + j++; + if (i >= RK_STATE_LEN) { + mt[0] = mt[RK_STATE_LEN - 1]; + i = 1; } - for (k = RK_STATE_LEN - 1; k; k--) { - mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - - i; /* non linear */ - mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ - i++; - if (i >= RK_STATE_LEN) { - mt[0] = mt[RK_STATE_LEN - 1]; - i = 1; - } + if (j >= key_length) { + j = 0; } - - mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ -} - -void mt19937_gen(mt19937_state *state) -{ - uint32_t y; - int i; - - for (i = 0; i < N - M; i++) { - y = (state->key[i] & UPPER_MASK) | (state->key[i+1] & LOWER_MASK); - state->key[i] = state->key[i+M] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); - } - for (; i < N - 1; i++) { - y = (state->key[i] & UPPER_MASK) | (state->key[i+1] & LOWER_MASK); - state->key[i] = state->key[i+(M-N)] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); + } + for (k = RK_STATE_LEN - 1; k; k--) { + mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1566083941UL)) - + i; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; + if (i >= RK_STATE_LEN) { + mt[0] = mt[RK_STATE_LEN - 1]; + i = 1; } - y = (state->key[N - 1] & UPPER_MASK) | (state->key[0] & LOWER_MASK); - state->key[N - 1] = state->key[M - 1] ^ (y >> 1) ^ (-(y & 1) & MATRIX_A); + } - state->pos = 0; + mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ } +void mt19937_gen(mt19937_state *state) { + uint32_t y; + int i; + + for (i = 0; i < N - M; i++) { + y = (state->key[i] & UPPER_MASK) | (state->key[i + 1] & LOWER_MASK); + state->key[i] = state->key[i + M] ^ (y >> 1) ^ (-(y & 1) & MATRIX_A); + } + for (; i < N - 1; i++) { + y = (state->key[i] & UPPER_MASK) | (state->key[i + 1] & LOWER_MASK); + state->key[i] = state->key[i + (M - N)] ^ (y >> 1) ^ (-(y & 1) & MATRIX_A); + } + y = (state->key[N - 1] & UPPER_MASK) | (state->key[0] & LOWER_MASK); + state->key[N - 1] = state->key[M - 1] ^ (y >> 1) ^ (-(y & 1) & MATRIX_A); + + state->pos = 0; +} extern inline uint64_t mt19937_next64(mt19937_state *state); extern inline uint32_t mt19937_next32(mt19937_state *state); -extern inline double mt19937_next_double(mt19937_state *state); \ No newline at end of file +extern inline double mt19937_next_double(mt19937_state *state); diff --git a/_randomgen/core_prng/src/mt19937/mt19937.h b/_randomgen/core_prng/src/mt19937/mt19937.h index b9617769a622..18da9622decf 100644 --- a/_randomgen/core_prng/src/mt19937/mt19937.h +++ b/_randomgen/core_prng/src/mt19937/mt19937.h @@ -14,7 +14,6 @@ #define inline __forceinline #endif - #define RK_STATE_LEN 624 #define N 624 @@ -23,10 +22,9 @@ #define UPPER_MASK 0x80000000UL #define LOWER_MASK 0x7fffffffUL -typedef struct s_mt19937_state -{ - uint32_t key[RK_STATE_LEN]; - int pos; +typedef struct s_mt19937_state { + uint32_t key[RK_STATE_LEN]; + int pos; } mt19937_state; extern void mt19937_seed(mt19937_state *state, uint32_t seed); @@ -34,26 +32,26 @@ extern void mt19937_seed(mt19937_state *state, uint32_t seed); extern void mt19937_gen(mt19937_state *state); /* Slightly optimized reference implementation of the Mersenne Twister */ -static inline uint32_t mt19937_next(mt19937_state *state) -{ - uint32_t y; +static inline uint32_t mt19937_next(mt19937_state *state) { + uint32_t y; - if (state->pos == RK_STATE_LEN) { - // Move to function to help inlining - mt19937_gen(state); - } - y = state->key[state->pos++]; + if (state->pos == RK_STATE_LEN) { + // Move to function to help inlining + mt19937_gen(state); + } + y = state->key[state->pos++]; - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & 0x9d2c5680UL; - y ^= (y << 15) & 0xefc60000UL; - y ^= (y >> 18); + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); - return y; + return y; } -extern void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, int key_length); +extern void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, + int key_length); static inline uint64_t mt19937_next64(mt19937_state *state) { return (uint64_t)mt19937_next(state) << 32 | mt19937_next(state); diff --git a/_randomgen/core_prng/src/mt19937/randomkit.c b/_randomgen/core_prng/src/mt19937/randomkit.c index 17f10a288f39..947d2adb1067 100644 --- a/_randomgen/core_prng/src/mt19937/randomkit.c +++ b/_randomgen/core_prng/src/mt19937/randomkit.c @@ -81,7 +81,6 @@ #include #include - /* * mingw msvcr lib import wrongly export _ftime, which does not exist in the * actual msvc runtime for version >= 8; we make it an alias to _ftime64, which @@ -128,7 +127,6 @@ #include #include - #ifndef RK_DEV_URANDOM #define RK_DEV_URANDOM "/dev/urandom" #endif @@ -577,4 +575,4 @@ double rk_gauss(rk_state *state) { state->has_gauss = 1; return f * x2; } -} \ No newline at end of file +} diff --git a/_randomgen/core_prng/src/mt19937/randomkit.h b/_randomgen/core_prng/src/mt19937/randomkit.h index f57f50ae360e..abb082cb2ed8 100644 --- a/_randomgen/core_prng/src/mt19937/randomkit.h +++ b/_randomgen/core_prng/src/mt19937/randomkit.h @@ -220,4 +220,4 @@ extern double rk_gauss(rk_state *state); } #endif -#endif /* _RANDOMKIT_ */ \ No newline at end of file +#endif /* _RANDOMKIT_ */ diff --git a/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c b/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c index d97632d759a0..cb675346c4c0 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c +++ b/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c @@ -3,11 +3,12 @@ * * GCC only * - * gcc pcg64-test-data-gen.c pcg64.orig.c ../splitmix64/splitmix64.c -o pgc64-test-data-gen + * gcc pcg64-test-data-gen.c pcg64.orig.c ../splitmix64/splitmix64.c -o + * pgc64-test-data-gen */ -#include "pcg64.orig.h" #include "../splitmix64/splitmix64.h" +#include "pcg64.orig.h" #include #include @@ -62,4 +63,4 @@ int main() { } } fclose(fp); -} \ No newline at end of file +} diff --git a/_randomgen/core_prng/src/pcg64/pcg64.orig.c b/_randomgen/core_prng/src/pcg64/pcg64.orig.c index 4ce4736dbc58..24488123edfe 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.orig.c +++ b/_randomgen/core_prng/src/pcg64/pcg64.orig.c @@ -3,4 +3,5 @@ extern uint64_t pcg_rotr_64(uint64_t value, unsigned int rot); extern inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state); extern void pcg_setseq_128_step_r(struct pcg_state_setseq_128 *rng); -extern uint64_t pcg_setseq_128_xsl_rr_64_random_r(struct pcg_state_setseq_128 *rng); \ No newline at end of file +extern uint64_t +pcg_setseq_128_xsl_rr_64_random_r(struct pcg_state_setseq_128 *rng); diff --git a/_randomgen/core_prng/src/pcg64/pcg64.orig.h b/_randomgen/core_prng/src/pcg64/pcg64.orig.h index 645025acb01e..74be91f31a50 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.orig.h +++ b/_randomgen/core_prng/src/pcg64/pcg64.orig.h @@ -241,10 +241,10 @@ inline pcg128_t pcg_output_xsl_rr_rr_128_128(pcg128_t state) { PCG_128BIT_CONSTANT(6364136223846793005ULL, 1442695040888963407ULL) #endif -/* - * Static initialization constants (if you can't call srandom for some - * bizarre reason). - */ + /* + * Static initialization constants (if you can't call srandom for some + * bizarre reason). + */ #define PCG_STATE_ONESEQ_8_INITIALIZER \ { 0xd7U } diff --git a/_randomgen/core_prng/src/philox/philox-benchmark.c b/_randomgen/core_prng/src/philox/philox-benchmark.c index 701ee03452cd..0cab04cf55ca 100644 --- a/_randomgen/core_prng/src/philox/philox-benchmark.c +++ b/_randomgen/core_prng/src/philox/philox-benchmark.c @@ -35,4 +35,4 @@ int main() { printf("0x%" PRIx64 "\ncount: %" PRIu64 "\n", sum, count); printf("%" PRIu64 " randoms per second\n", (uint64_t)(N / time_spent) / 1000000 * 1000000); -} \ No newline at end of file +} diff --git a/_randomgen/core_prng/src/philox/philox-test-data-gen.c b/_randomgen/core_prng/src/philox/philox-test-data-gen.c index fd717b959794..b17dd153b3d0 100644 --- a/_randomgen/core_prng/src/philox/philox-test-data-gen.c +++ b/_randomgen/core_prng/src/philox/philox-test-data-gen.c @@ -71,4 +71,4 @@ int main() { } } fclose(fp); -} \ No newline at end of file +} diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.orig.c b/_randomgen/core_prng/src/splitmix64/splitmix64.orig.c index d0c1e158fe0c..df6133aabf4d 100644 --- a/_randomgen/core_prng/src/splitmix64/splitmix64.orig.c +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.orig.c @@ -9,7 +9,7 @@ See . */ #include /* This is a fixed-increment version of Java 8's SplittableRandom generator - See http://dx.doi.org/10.1145/2714064.2660195 and + See http://dx.doi.org/10.1145/2714064.2660195 and http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html It is a very fast generator passing BigCrush, and it can be useful if @@ -21,8 +21,8 @@ See . */ uint64_t x; /* The state can be seeded with any value. */ uint64_t next() { - uint64_t z = (x += 0x9e3779b97f4a7c15); - z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; - z = (z ^ (z >> 27)) * 0x94d049bb133111eb; - return z ^ (z >> 31); + uint64_t z = (x += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + return z ^ (z >> 31); } diff --git a/_randomgen/core_prng/src/threefry/threefry-benchmark.c b/_randomgen/core_prng/src/threefry/threefry-benchmark.c index a75e61001970..6d6239cd3d24 100644 --- a/_randomgen/core_prng/src/threefry/threefry-benchmark.c +++ b/_randomgen/core_prng/src/threefry/threefry-benchmark.c @@ -35,4 +35,4 @@ int main() { printf("0x%" PRIx64 "\ncount: %" PRIu64 "\n", sum, count); printf("%" PRIu64 " randoms per second\n", (uint64_t)(N / time_spent) / 1000000 * 1000000); -} \ No newline at end of file +} diff --git a/_randomgen/core_prng/src/threefry/threefry-orig.c b/_randomgen/core_prng/src/threefry/threefry-orig.c index 1a5094fa6b6d..d27cfd7974ff 100644 --- a/_randomgen/core_prng/src/threefry/threefry-orig.c +++ b/_randomgen/core_prng/src/threefry/threefry-orig.c @@ -29,9 +29,8 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#include #include "threefry.h" +#include #define N_WORDS 2 #define KEY_LENGTH 3 @@ -42,9 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static const int ROTATION[] = {16, 42, 12, 31, 16, 32, 24, 21}; -uint64_t rotl_64(uint64_t x, int d) { - return ((x << d) | (x >> (64-d))); -} +uint64_t rotl_64(uint64_t x, int d) { return ((x << d) | (x >> (64 - d))); } threefry_t mix(threefry_t x, int R) { x.c0 += x.c1; @@ -53,21 +50,21 @@ threefry_t mix(threefry_t x, int R) { } threefry_t threefry(threefry_t p, threefry_t k) { - uint64_t K[] = {k.c0, k.c1, C240^k.c0^k.c1}; + uint64_t K[] = {k.c0, k.c1, C240 ^ k.c0 ^ k.c1}; int rmod4, rdiv4; threefry_t x; x = p; - for (int r=0; rc0++; return x.c0 * DOUBLE_MULT; -} \ No newline at end of file +} diff --git a/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c b/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c index 2fa09eed31f3..4494802489e6 100644 --- a/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c +++ b/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c @@ -77,4 +77,4 @@ int main() { } } fclose(fp); -} \ No newline at end of file +} diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-test-data-gen.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-test-data-gen.c index d49c87ce2109..d95260eca176 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-test-data-gen.c +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-test-data-gen.c @@ -69,4 +69,4 @@ int main() { } } fclose(fp); -} \ No newline at end of file +} diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.c index d55a3b3776ca..c0293cc2b586 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.c +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.c @@ -35,40 +35,39 @@ See . */ uint64_t s[2]; static inline uint64_t rotl(const uint64_t x, int k) { - return (x << k) | (x >> (64 - k)); + return (x << k) | (x >> (64 - k)); } uint64_t next(void) { - const uint64_t s0 = s[0]; - uint64_t s1 = s[1]; - const uint64_t result = s0 + s1; + const uint64_t s0 = s[0]; + uint64_t s1 = s[1]; + const uint64_t result = s0 + s1; - s1 ^= s0; - s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b - s[1] = rotl(s1, 36); // c + s1 ^= s0; + s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b + s[1] = rotl(s1, 36); // c - return result; + return result; } - /* This is the jump function for the generator. It is equivalent to 2^64 calls to next(); it can be used to generate 2^64 non-overlapping subsequences for parallel computations. */ void jump(void) { - static const uint64_t JUMP[] = { 0xbeac0467eba5facb, 0xd86b048b86aa9922 }; - - uint64_t s0 = 0; - uint64_t s1 = 0; - for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) - for(int b = 0; b < 64; b++) { - if (JUMP[i] & UINT64_C(1) << b) { - s0 ^= s[0]; - s1 ^= s[1]; - } - next(); - } - - s[0] = s0; - s[1] = s1; + static const uint64_t JUMP[] = {0xbeac0467eba5facb, 0xd86b048b86aa9922}; + + uint64_t s0 = 0; + uint64_t s1 = 0; + for (int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for (int b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) { + s0 ^= s[0]; + s1 ^= s[1]; + } + next(); + } + + s[0] = s0; + s[1] = s1; } diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024-test-data-gen.c b/_randomgen/core_prng/src/xorshift1024/xorshift1024-test-data-gen.c index aa0ebca33085..a2ae08df4f6b 100644 --- a/_randomgen/core_prng/src/xorshift1024/xorshift1024-test-data-gen.c +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024-test-data-gen.c @@ -71,4 +71,4 @@ int main() { } } fclose(fp); -} \ No newline at end of file +} diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.h b/_randomgen/core_prng/src/xorshift1024/xorshift1024.h index 141010d9d5e9..ae8d24f7dcff 100644 --- a/_randomgen/core_prng/src/xorshift1024/xorshift1024.h +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024.h @@ -30,4 +30,4 @@ static inline uint32_t xorshift1024_next32(xorshift1024_state *state) { return (uint32_t)(next >> 32); } -void xorshift1024_jump(xorshift1024_state *state); \ No newline at end of file +void xorshift1024_jump(xorshift1024_state *state); diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift2014.orig.c b/_randomgen/core_prng/src/xorshift1024/xorshift2014.orig.c index ed1cf8d6ef77..e4f899fb7b09 100644 --- a/_randomgen/core_prng/src/xorshift1024/xorshift2014.orig.c +++ b/_randomgen/core_prng/src/xorshift1024/xorshift2014.orig.c @@ -34,36 +34,35 @@ uint64_t s[16]; int p; uint64_t next(void) { - const uint64_t s0 = s[p]; - uint64_t s1 = s[p = (p + 1) & 15]; - s1 ^= s1 << 31; // a - s[p] = s1 ^ s0 ^ (s1 >> 11) ^ (s0 >> 30); // b,c - return s[p] * 0x9e3779b97f4a7c13; + const uint64_t s0 = s[p]; + uint64_t s1 = s[p = (p + 1) & 15]; + s1 ^= s1 << 31; // a + s[p] = s1 ^ s0 ^ (s1 >> 11) ^ (s0 >> 30); // b,c + return s[p] * 0x9e3779b97f4a7c13; } - /* This is the jump function for the generator. It is equivalent to 2^512 calls to next(); it can be used to generate 2^512 non-overlapping subsequences for parallel computations. */ void jump(void) { - static const uint64_t JUMP[] = { 0x84242f96eca9c41d, - 0xa3c65b8776f96855, 0x5b34a39f070b5837, 0x4489affce4f31a1e, - 0x2ffeeb0a48316f40, 0xdc2d9891fe68c022, 0x3659132bb12fea70, - 0xaac17d8efa43cab8, 0xc4cb815590989b13, 0x5ee975283d71c93b, - 0x691548c86c1bd540, 0x7910c41d10a1e6a5, 0x0b5fc64563b3e2a8, - 0x047f7684e9fc949d, 0xb99181f2d8f685ca, 0x284600e3f30e38c3 - }; + static const uint64_t JUMP[] = { + 0x84242f96eca9c41d, 0xa3c65b8776f96855, 0x5b34a39f070b5837, + 0x4489affce4f31a1e, 0x2ffeeb0a48316f40, 0xdc2d9891fe68c022, + 0x3659132bb12fea70, 0xaac17d8efa43cab8, 0xc4cb815590989b13, + 0x5ee975283d71c93b, 0x691548c86c1bd540, 0x7910c41d10a1e6a5, + 0x0b5fc64563b3e2a8, 0x047f7684e9fc949d, 0xb99181f2d8f685ca, + 0x284600e3f30e38c3}; - uint64_t t[16] = { 0 }; - for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) - for(int b = 0; b < 64; b++) { - if (JUMP[i] & UINT64_C(1) << b) - for(int j = 0; j < 16; j++) - t[j] ^= s[(j + p) & 15]; - next(); - } + uint64_t t[16] = {0}; + for (int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for (int b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) + for (int j = 0; j < 16; j++) + t[j] ^= s[(j + p) & 15]; + next(); + } - for(int j = 0; j < 16; j++) - s[(j + p) & 15] = t[j]; -} \ No newline at end of file + for (int j = 0; j < 16; j++) + s[(j + p) & 15] = t[j]; +} From f40788200c88a21dd1e34afb6070005c2e59d385 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 7 Mar 2018 10:29:53 +0000 Subject: [PATCH 042/279] CLN: Fix dsfmt import issues Revers DSFMT import changes --- .../core_prng/src/dsfmt/dSFMT-benchmark.c | 4 +- .../core_prng/src/dsfmt/dSFMT-test-gen.c | 14 +- _randomgen/core_prng/src/dsfmt/dSFMT.c | 619 +++++++++--------- _randomgen/core_prng/src/dsfmt/dSFMT.h | 325 ++++----- 4 files changed, 497 insertions(+), 465 deletions(-) diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-benchmark.c b/_randomgen/core_prng/src/dsfmt/dSFMT-benchmark.c index d311179fc2bd..af29d0e1f771 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT-benchmark.c +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-benchmark.c @@ -5,10 +5,12 @@ * gcc dSFMT-benchmark.c dSFMT.c -O3 -DHAVE_SSE2 -DDSFMT_MEXP=19937 -o * dSFMT-benchmark */ -#include "dSFMT.h" #include #include +#include "dSFMT.h" + + #define N 1000000000 int main() { diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c b/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c index c34451236ec7..697a3010afcb 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c @@ -1,11 +1,15 @@ /* + * cl dSFMT-test-gen.c dSFMT.c -DHAVE_SSE2 -DDSFMT_MEXP=19937 /Ox * * gcc dSFMT-test-gen.c dSFMT.c -DHAVE_SSE2 -DDSFMT_MEXP=19937 -o dSFMT */ -#include "dSFMT.h" + #include #include +#include "dSFMT.h" + + int main(void) { int i; double d; @@ -27,7 +31,9 @@ int main(void) { d = out[i]; temp = (uint64_t *)&d; fprintf(fp, "%d, %" PRIu64 "\n", i, *temp); - printf("%d, %" PRIu64 "\n", i, *temp); + if (i==999) { + printf("%d, %" PRIu64 "\n", i, *temp); + } } fclose(fp); @@ -44,7 +50,9 @@ int main(void) { d = out[i]; temp = (uint64_t *)&d; fprintf(fp, "%d, %" PRIu64 "\n", i, *temp); - printf("%d, %" PRIu64 "\n", i, *temp); + if (i==999) { + printf("%d, %" PRIu64 "\n", i, *temp); + } } fclose(fp); } diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.c b/_randomgen/core_prng/src/dsfmt/dSFMT.c index 0955e087fbaa..3ce156699175 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT.c +++ b/_randomgen/core_prng/src/dsfmt/dSFMT.c @@ -11,11 +11,11 @@ * * The new BSD License is applied to this software, see LICENSE.txt */ -#include "dSFMT-common.h" -#include "dSFMT-params.h" #include -#include #include +#include +#include "dSFMT-params.h" +#include "dSFMT-common.h" #if defined(__cplusplus) extern "C" { @@ -31,10 +31,14 @@ static const int dsfmt_mexp = DSFMT_MEXP; ----------------*/ inline static uint32_t ini_func1(uint32_t x); inline static uint32_t ini_func2(uint32_t x); -inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, int size); -inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, int size); -inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, int size); -inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, int size); +inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, + int size); +inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, + int size); +inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, + int size); +inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, + int size); inline static int idxof(int i); static void initial_mask(dsfmt_t *dsfmt); static void period_certification(dsfmt_t *dsfmt); @@ -53,9 +57,13 @@ static const union X128D_T sse2_double_m_one = {{-1.0, -1.0}}; * array of LITTLE ENDIAN in BIG ENDIAN machine. */ #if defined(DSFMT_BIG_ENDIAN) -inline static int idxof(int i) { return i ^ 1; } +inline static int idxof(int i) { + return i ^ 1; +} #else -inline static int idxof(int i) { return i; } +inline static int idxof(int i) { + return i; +} #endif #if defined(HAVE_SSE2) @@ -66,7 +74,7 @@ inline static int idxof(int i) { return i; } * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_c0o1(w128_t *w) { - w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); + w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); } /** @@ -76,7 +84,7 @@ inline static void convert_c0o1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0c1(w128_t *w) { - w->sd = _mm_sub_pd(sse2_double_two.d128, w->sd); + w->sd = _mm_sub_pd(sse2_double_two.d128, w->sd); } /** @@ -86,8 +94,8 @@ inline static void convert_o0c1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0o1(w128_t *w) { - w->si = _mm_or_si128(w->si, sse2_int_one.i128); - w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); + w->si = _mm_or_si128(w->si, sse2_int_one.i128); + w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); } #else /* standard C and altivec */ /** @@ -97,8 +105,8 @@ inline static void convert_o0o1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_c0o1(w128_t *w) { - w->d[0] -= 1.0; - w->d[1] -= 1.0; + w->d[0] -= 1.0; + w->d[1] -= 1.0; } /** @@ -108,8 +116,8 @@ inline static void convert_c0o1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0c1(w128_t *w) { - w->d[0] = 2.0 - w->d[0]; - w->d[1] = 2.0 - w->d[1]; + w->d[0] = 2.0 - w->d[0]; + w->d[1] = 2.0 - w->d[1]; } /** @@ -119,10 +127,10 @@ inline static void convert_o0c1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0o1(w128_t *w) { - w->u[0] |= 1; - w->u[1] |= 1; - w->d[0] -= 1.0; - w->d[1] -= 1.0; + w->u[0] |= 1; + w->u[1] |= 1; + w->d[0] -= 1.0; + w->d[1] -= 1.0; } #endif @@ -134,33 +142,34 @@ inline static void convert_o0o1(w128_t *w) { * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], - &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], - &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], + &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -171,38 +180,39 @@ inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], - &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], - &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - convert_c0o1(&array[i - DSFMT_N]); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - convert_c0o1(&array[i - DSFMT_N]); - } - for (i = size - DSFMT_N; i < size; i++) { - convert_c0o1(&array[i]); - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], + &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_c0o1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_c0o1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_c0o1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -213,38 +223,39 @@ inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], - &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], - &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - convert_o0o1(&array[i - DSFMT_N]); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - convert_o0o1(&array[i - DSFMT_N]); - } - for (i = size - DSFMT_N; i < size; i++) { - convert_o0o1(&array[i]); - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], + &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_o0o1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_o0o1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_o0o1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -255,38 +266,39 @@ inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], - &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], - &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - convert_o0c1(&array[i - DSFMT_N]); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - convert_o0c1(&array[i - DSFMT_N]); - } - for (i = size - DSFMT_N; i < size; i++) { - convert_o0c1(&array[i]); - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], + &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_o0c1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_o0c1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_o0c1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -296,7 +308,7 @@ inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, * @return 32-bit integer */ static uint32_t ini_func1(uint32_t x) { - return (x ^ (x >> 27)) * (uint32_t)1664525UL; + return (x ^ (x >> 27)) * (uint32_t)1664525UL; } /** @@ -306,7 +318,7 @@ static uint32_t ini_func1(uint32_t x) { * @return 32-bit integer */ static uint32_t ini_func2(uint32_t x) { - return (x ^ (x >> 27)) * (uint32_t)1566083941UL; + return (x ^ (x >> 27)) * (uint32_t)1566083941UL; } /** @@ -315,13 +327,13 @@ static uint32_t ini_func2(uint32_t x) { * @param dsfmt dsfmt state vector. */ static void initial_mask(dsfmt_t *dsfmt) { - int i; - uint64_t *psfmt; + int i; + uint64_t *psfmt; - psfmt = &dsfmt->status[0].u[0]; - for (i = 0; i < DSFMT_N * 2; i++) { - psfmt[i] = (psfmt[i] & DSFMT_LOW_MASK) | DSFMT_HIGH_CONST; - } + psfmt = &dsfmt->status[0].u[0]; + for (i = 0; i < DSFMT_N * 2; i++) { + psfmt[i] = (psfmt[i] & DSFMT_LOW_MASK) | DSFMT_HIGH_CONST; + } } /** @@ -329,44 +341,44 @@ static void initial_mask(dsfmt_t *dsfmt) { * @param dsfmt dsfmt state vector. */ static void period_certification(dsfmt_t *dsfmt) { - uint64_t pcv[2] = {DSFMT_PCV1, DSFMT_PCV2}; - uint64_t tmp[2]; - uint64_t inner; - int i; + uint64_t pcv[2] = {DSFMT_PCV1, DSFMT_PCV2}; + uint64_t tmp[2]; + uint64_t inner; + int i; #if (DSFMT_PCV2 & 1) != 1 - int j; - uint64_t work; + int j; + uint64_t work; #endif - tmp[0] = (dsfmt->status[DSFMT_N].u[0] ^ DSFMT_FIX1); - tmp[1] = (dsfmt->status[DSFMT_N].u[1] ^ DSFMT_FIX2); - - inner = tmp[0] & pcv[0]; - inner ^= tmp[1] & pcv[1]; - for (i = 32; i > 0; i >>= 1) { - inner ^= inner >> i; - } - inner &= 1; - /* check OK */ - if (inner == 1) { - return; - } + tmp[0] = (dsfmt->status[DSFMT_N].u[0] ^ DSFMT_FIX1); + tmp[1] = (dsfmt->status[DSFMT_N].u[1] ^ DSFMT_FIX2); + + inner = tmp[0] & pcv[0]; + inner ^= tmp[1] & pcv[1]; + for (i = 32; i > 0; i >>= 1) { + inner ^= inner >> i; + } + inner &= 1; + /* check OK */ + if (inner == 1) { + return; + } /* check NG, and modification */ #if (DSFMT_PCV2 & 1) == 1 - dsfmt->status[DSFMT_N].u[1] ^= 1; + dsfmt->status[DSFMT_N].u[1] ^= 1; #else - for (i = 1; i >= 0; i--) { - work = 1; - for (j = 0; j < 64; j++) { - if ((work & pcv[i]) != 0) { - dsfmt->status[DSFMT_N].u[i] ^= work; - return; - } - work = work << 1; - } - } + for (i = 1; i >= 0; i--) { + work = 1; + for (j = 0; j < 64; j++) { + if ((work & pcv[i]) != 0) { + dsfmt->status[DSFMT_N].u[i] ^= work; + return; + } + work = work << 1; + } + } #endif - return; + return; } /*---------------- @@ -377,14 +389,18 @@ static void period_certification(dsfmt_t *dsfmt) { * the Mersenne exponent, and all parameters of this generator. * @return id string. */ -const char *dsfmt_get_idstring(void) { return DSFMT_IDSTR; } +const char *dsfmt_get_idstring(void) { + return DSFMT_IDSTR; +} /** * This function returns the minimum size of array used for \b * fill_array functions. * @return minimum size of array used for fill_array functions. */ -int dsfmt_get_min_array_size(void) { return DSFMT_N64; } +int dsfmt_get_min_array_size(void) { + return DSFMT_N64; +} /** * This function fills the internal state array with double precision @@ -392,21 +408,21 @@ int dsfmt_get_min_array_size(void) { return DSFMT_N64; } * @param dsfmt dsfmt state vector. */ void dsfmt_gen_rand_all(dsfmt_t *dsfmt) { - int i; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&dsfmt->status[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], - &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&dsfmt->status[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&dsfmt->status[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1 - DSFMT_N], &lung); - } - dsfmt->status[DSFMT_N] = lung; + int i; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&dsfmt->status[0], &dsfmt->status[0], + &dsfmt->status[DSFMT_POS1], &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&dsfmt->status[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&dsfmt->status[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1 - DSFMT_N], &lung); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -438,9 +454,9 @@ void dsfmt_gen_rand_all(dsfmt_t *dsfmt) { * returns the pointer to the aligned memory block. */ void dsfmt_fill_array_close1_open2(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_c1o2(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_c1o2(dsfmt, (w128_t *)array, size / 2); } /** @@ -456,9 +472,9 @@ void dsfmt_fill_array_close1_open2(dsfmt_t *dsfmt, double array[], int size) { * see also \sa fill_array_close1_open2() */ void dsfmt_fill_array_open_close(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_o0c1(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_o0c1(dsfmt, (w128_t *)array, size / 2); } /** @@ -474,9 +490,9 @@ void dsfmt_fill_array_open_close(dsfmt_t *dsfmt, double array[], int size) { * see also \sa fill_array_close1_open2() */ void dsfmt_fill_array_close_open(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_c0o1(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_c0o1(dsfmt, (w128_t *)array, size / 2); } /** @@ -492,13 +508,13 @@ void dsfmt_fill_array_close_open(dsfmt_t *dsfmt, double array[], int size) { * see also \sa fill_array_close1_open2() */ void dsfmt_fill_array_open_open(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_o0o1(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_o0o1(dsfmt, (w128_t *)array, size / 2); } #if defined(__INTEL_COMPILER) -#pragma warning(disable : 981) +# pragma warning(disable:981) #endif /** * This function initializes the internal state array with a 32-bit @@ -508,23 +524,23 @@ void dsfmt_fill_array_open_open(dsfmt_t *dsfmt, double array[], int size) { * @param mexp caller's mersenne expornent */ void dsfmt_chk_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed, int mexp) { - int i; - uint32_t *psfmt; - - /* make sure caller program is compiled with the same MEXP */ - if (mexp != dsfmt_mexp) { - fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); - exit(1); - } - psfmt = &dsfmt->status[0].u32[0]; - psfmt[idxof(0)] = seed; - for (i = 1; i < (DSFMT_N + 1) * 4; i++) { - psfmt[idxof(i)] = - 1812433253UL * (psfmt[idxof(i - 1)] ^ (psfmt[idxof(i - 1)] >> 30)) + i; - } - initial_mask(dsfmt); - period_certification(dsfmt); - dsfmt->idx = DSFMT_N64; + int i; + uint32_t *psfmt; + + /* make sure caller program is compiled with the same MEXP */ + if (mexp != dsfmt_mexp) { + fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); + exit(1); + } + psfmt = &dsfmt->status[0].u32[0]; + psfmt[idxof(0)] = seed; + for (i = 1; i < (DSFMT_N + 1) * 4; i++) { + psfmt[idxof(i)] = 1812433253UL + * (psfmt[idxof(i - 1)] ^ (psfmt[idxof(i - 1)] >> 30)) + i; + } + initial_mask(dsfmt); + period_certification(dsfmt); + dsfmt->idx = DSFMT_N64; } /** @@ -536,77 +552,80 @@ void dsfmt_chk_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed, int mexp) { * @param mexp caller's mersenne expornent */ void dsfmt_chk_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], - int key_length, int mexp) { - int i, j, count; - uint32_t r; - uint32_t *psfmt32; - int lag; - int mid; - int size = (DSFMT_N + 1) * 4; /* pulmonary */ - - /* make sure caller program is compiled with the same MEXP */ - if (mexp != dsfmt_mexp) { - fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); - exit(1); - } - if (size >= 623) { - lag = 11; - } else if (size >= 68) { - lag = 7; - } else if (size >= 39) { - lag = 5; - } else { - lag = 3; - } - mid = (size - lag) / 2; - - psfmt32 = &dsfmt->status[0].u32[0]; - memset(dsfmt->status, 0x8b, sizeof(dsfmt->status)); - if (key_length + 1 > size) { - count = key_length + 1; - } else { - count = size; - } - r = ini_func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid % size)] ^ - psfmt32[idxof((size - 1) % size)]); - psfmt32[idxof(mid % size)] += r; - r += key_length; - psfmt32[idxof((mid + lag) % size)] += r; - psfmt32[idxof(0)] = r; - count--; - for (i = 1, j = 0; (j < count) && (j < key_length); j++) { - r = ini_func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % size)] ^ - psfmt32[idxof((i + size - 1) % size)]); - psfmt32[idxof((i + mid) % size)] += r; - r += init_key[j] + i; - psfmt32[idxof((i + mid + lag) % size)] += r; - psfmt32[idxof(i)] = r; - i = (i + 1) % size; - } - for (; j < count; j++) { - r = ini_func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % size)] ^ - psfmt32[idxof((i + size - 1) % size)]); - psfmt32[idxof((i + mid) % size)] += r; - r += i; - psfmt32[idxof((i + mid + lag) % size)] += r; - psfmt32[idxof(i)] = r; - i = (i + 1) % size; - } - for (j = 0; j < size; j++) { - r = ini_func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % size)] + - psfmt32[idxof((i + size - 1) % size)]); - psfmt32[idxof((i + mid) % size)] ^= r; - r -= i; - psfmt32[idxof((i + mid + lag) % size)] ^= r; - psfmt32[idxof(i)] = r; - i = (i + 1) % size; - } - initial_mask(dsfmt); - period_certification(dsfmt); - dsfmt->idx = DSFMT_N64; + int key_length, int mexp) { + int i, j, count; + uint32_t r; + uint32_t *psfmt32; + int lag; + int mid; + int size = (DSFMT_N + 1) * 4; /* pulmonary */ + + /* make sure caller program is compiled with the same MEXP */ + if (mexp != dsfmt_mexp) { + fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); + exit(1); + } + if (size >= 623) { + lag = 11; + } else if (size >= 68) { + lag = 7; + } else if (size >= 39) { + lag = 5; + } else { + lag = 3; + } + mid = (size - lag) / 2; + + psfmt32 = &dsfmt->status[0].u32[0]; + memset(dsfmt->status, 0x8b, sizeof(dsfmt->status)); + if (key_length + 1 > size) { + count = key_length + 1; + } else { + count = size; + } + r = ini_func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid % size)] + ^ psfmt32[idxof((size - 1) % size)]); + psfmt32[idxof(mid % size)] += r; + r += key_length; + psfmt32[idxof((mid + lag) % size)] += r; + psfmt32[idxof(0)] = r; + count--; + for (i = 1, j = 0; (j < count) && (j < key_length); j++) { + r = ini_func1(psfmt32[idxof(i)] + ^ psfmt32[idxof((i + mid) % size)] + ^ psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] += r; + r += init_key[j] + i; + psfmt32[idxof((i + mid + lag) % size)] += r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + for (; j < count; j++) { + r = ini_func1(psfmt32[idxof(i)] + ^ psfmt32[idxof((i + mid) % size)] + ^ psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] += r; + r += i; + psfmt32[idxof((i + mid + lag) % size)] += r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + for (j = 0; j < size; j++) { + r = ini_func2(psfmt32[idxof(i)] + + psfmt32[idxof((i + mid) % size)] + + psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] ^= r; + r -= i; + psfmt32[idxof((i + mid + lag) % size)] ^= r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + initial_mask(dsfmt); + period_certification(dsfmt); + dsfmt->idx = DSFMT_N64; } #if defined(__INTEL_COMPILER) -#pragma warning(default : 981) +# pragma warning(default:981) #endif #if defined(__cplusplus) @@ -617,4 +636,4 @@ extern inline double dsfmt_next_double(dsfmt_state *state); extern inline uint64_t dsfmt_next64(dsfmt_state *state); -extern inline uint32_t dsfmt_next32(dsfmt_state *state); +extern inline uint32_t dsfmt_next32(dsfmt_state *state); \ No newline at end of file diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.h b/_randomgen/core_prng/src/dsfmt/dSFMT.h index c9a34ae86691..52b6b3aedcc2 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT.h +++ b/_randomgen/core_prng/src/dsfmt/dSFMT.h @@ -38,14 +38,14 @@ extern "C" { #endif -#include #include +#include #if !defined(DSFMT_MEXP) #ifdef __GNUC__ -#warning "DSFMT_MEXP is not defined. I assume DSFMT_MEXP is 19937." + #warning "DSFMT_MEXP is not defined. I assume DSFMT_MEXP is 19937." #endif -#define DSFMT_MEXP 19937 + #define DSFMT_MEXP 19937 #endif /*----------------- BASIC DEFINITIONS @@ -64,103 +64,103 @@ extern "C" { #define DSFMT_N64 (DSFMT_N * 2) #if !defined(DSFMT_BIG_ENDIAN) -#if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) -#if __BYTE_ORDER == __BIG_ENDIAN -#define DSFMT_BIG_ENDIAN 1 -#endif -#elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) -#if _BYTE_ORDER == _BIG_ENDIAN -#define DSFMT_BIG_ENDIAN 1 -#endif -#elif defined(__BYTE_ORDER__) && defined(__BIG_ENDIAN__) -#if __BYTE_ORDER__ == __BIG_ENDIAN__ -#define DSFMT_BIG_ENDIAN 1 -#endif -#elif defined(BYTE_ORDER) && defined(BIG_ENDIAN) -#if BYTE_ORDER == BIG_ENDIAN -#define DSFMT_BIG_ENDIAN 1 -#endif -#elif defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) || \ - defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) -#define DSFMT_BIG_ENDIAN 1 -#endif +# if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) +# if __BYTE_ORDER == __BIG_ENDIAN +# define DSFMT_BIG_ENDIAN 1 +# endif +# elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) +# if _BYTE_ORDER == _BIG_ENDIAN +# define DSFMT_BIG_ENDIAN 1 +# endif +# elif defined(__BYTE_ORDER__) && defined(__BIG_ENDIAN__) +# if __BYTE_ORDER__ == __BIG_ENDIAN__ +# define DSFMT_BIG_ENDIAN 1 +# endif +# elif defined(BYTE_ORDER) && defined(BIG_ENDIAN) +# if BYTE_ORDER == BIG_ENDIAN +# define DSFMT_BIG_ENDIAN 1 +# endif +# elif defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) \ + || defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) +# define DSFMT_BIG_ENDIAN 1 +# endif #endif #if defined(DSFMT_BIG_ENDIAN) && defined(__amd64) -#undef DSFMT_BIG_ENDIAN +# undef DSFMT_BIG_ENDIAN #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -#include +# include #elif defined(_MSC_VER) || defined(__BORLANDC__) -#if !defined(DSFMT_UINT32_DEFINED) && !defined(SFMT_UINT32_DEFINED) +# if !defined(DSFMT_UINT32_DEFINED) && !defined(SFMT_UINT32_DEFINED) typedef unsigned int uint32_t; typedef unsigned __int64 uint64_t; -#ifndef UINT64_C -#define UINT64_C(v) (v##ui64) -#endif -#define DSFMT_UINT32_DEFINED -#if !defined(inline) && !defined(__cplusplus) -#define inline __forceinline -#endif -#endif -#else -#include -#if !defined(inline) && !defined(__cplusplus) -#if defined(__GNUC__) -#define inline __forceinline__ +# ifndef UINT64_C +# define UINT64_C(v) (v ## ui64) +# endif +# define DSFMT_UINT32_DEFINED +# if !defined(inline) && !defined(__cplusplus) +# define inline __forceinline +# endif +# endif #else -#define inline -#endif -#endif +# include +# if !defined(inline) && !defined(__cplusplus) +# if defined(__GNUC__) +# define inline __forceinline__ +# else +# define inline +# endif +# endif #endif #ifndef PRIu64 -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define PRIu64 "I64u" -#define PRIx64 "I64x" -#else -#define PRIu64 "llu" -#define PRIx64 "llx" -#endif +# if defined(_MSC_VER) || defined(__BORLANDC__) +# define PRIu64 "I64u" +# define PRIx64 "I64x" +# else +# define PRIu64 "llu" +# define PRIx64 "llx" +# endif #endif #ifndef UINT64_C -#define UINT64_C(v) (v##ULL) +# define UINT64_C(v) (v ## ULL) #endif /*------------------------------------------ 128-bit SIMD like data type for standard C ------------------------------------------*/ #if defined(HAVE_ALTIVEC) -#if !defined(__APPLE__) -#include -#endif +# if !defined(__APPLE__) +# include +# endif /** 128-bit data structure */ union W128_T { - vector unsigned int s; - uint64_t u[2]; - uint32_t u32[4]; - double d[2]; + vector unsigned int s; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; }; #elif defined(HAVE_SSE2) -#include +# include /** 128-bit data structure */ union W128_T { - __m128i si; - __m128d sd; - uint64_t u[2]; - uint32_t u32[4]; - double d[2]; + __m128i si; + __m128d sd; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; }; -#else /* standard C */ +#else /* standard C */ /** 128-bit data structure */ union W128_T { - uint64_t u[2]; - uint32_t u32[4]; - double d[2]; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; }; #endif @@ -169,8 +169,8 @@ typedef union W128_T w128_t; /** the 128-bit internal state array */ struct DSFMT_T { - w128_t status[DSFMT_N + 1]; - int idx; + w128_t status[DSFMT_N + 1]; + int idx; }; typedef struct DSFMT_T dsfmt_t; @@ -191,42 +191,42 @@ const char *dsfmt_get_idstring(void); int dsfmt_get_min_array_size(void); #if defined(__GNUC__) -#define DSFMT_PRE_INLINE inline static -#define DSFMT_PST_INLINE __attribute__((always_inline)) +# define DSFMT_PRE_INLINE inline static +# define DSFMT_PST_INLINE __attribute__((always_inline)) #elif defined(_MSC_VER) && _MSC_VER >= 1200 -#define DSFMT_PRE_INLINE __forceinline static -#define DSFMT_PST_INLINE +# define DSFMT_PRE_INLINE __forceinline static +# define DSFMT_PST_INLINE #else -#define DSFMT_PRE_INLINE inline static -#define DSFMT_PST_INLINE +# define DSFMT_PRE_INLINE inline static +# define DSFMT_PST_INLINE #endif DSFMT_PRE_INLINE uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double -dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double -dsfmt_genrand_close_open(dsfmt_t *dsfmt) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double -dsfmt_genrand_open_close(dsfmt_t *dsfmt) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double -dsfmt_genrand_open_open(dsfmt_t *dsfmt) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_genrand_close_open(dsfmt_t *dsfmt) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_genrand_open_close(dsfmt_t *dsfmt) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double dsfmt_genrand_open_open(dsfmt_t *dsfmt) + DSFMT_PST_INLINE; DSFMT_PRE_INLINE uint32_t dsfmt_gv_genrand_uint32(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_close1_open2(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_close_open(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_open_close(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_open_open(void) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_close(double array[], - int size) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close_open(double array[], - int size) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_open(double array[], - int size) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void -dsfmt_gv_fill_array_close1_open2(double array[], int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_close(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close_open(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_open(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close1_open2(double array[], int size) + DSFMT_PST_INLINE; DSFMT_PRE_INLINE void dsfmt_gv_init_gen_rand(uint32_t seed) DSFMT_PST_INLINE; DSFMT_PRE_INLINE void dsfmt_gv_init_by_array(uint32_t init_key[], int key_length) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_init_gen_rand(dsfmt_t *dsfmt, - uint32_t seed) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) + DSFMT_PST_INLINE; DSFMT_PRE_INLINE void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) DSFMT_PST_INLINE; @@ -239,15 +239,15 @@ DSFMT_PRE_INLINE void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], * @return double precision floating point pseudorandom number */ inline static uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) { - uint32_t r; - uint64_t *psfmt64 = &dsfmt->status[0].u[0]; + uint32_t r; + uint64_t *psfmt64 = &dsfmt->status[0].u[0]; - if (dsfmt->idx >= DSFMT_N64) { - dsfmt_gen_rand_all(dsfmt); - dsfmt->idx = 0; - } - r = psfmt64[dsfmt->idx++] & 0xffffffffU; - return r; + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r = psfmt64[dsfmt->idx++] & 0xffffffffU; + return r; } /** @@ -260,15 +260,15 @@ inline static uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) { - double r; - double *psfmt64 = &dsfmt->status[0].d[0]; + double r; + double *psfmt64 = &dsfmt->status[0].d[0]; - if (dsfmt->idx >= DSFMT_N64) { - dsfmt_gen_rand_all(dsfmt); - dsfmt->idx = 0; - } - r = psfmt64[dsfmt->idx++]; - return r; + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r = psfmt64[dsfmt->idx++]; + return r; } /** @@ -279,7 +279,7 @@ inline static double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static uint32_t dsfmt_gv_genrand_uint32(void) { - return dsfmt_genrand_uint32(&dsfmt_global_data); + return dsfmt_genrand_uint32(&dsfmt_global_data); } /** @@ -290,7 +290,7 @@ inline static uint32_t dsfmt_gv_genrand_uint32(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_close1_open2(void) { - return dsfmt_genrand_close1_open2(&dsfmt_global_data); + return dsfmt_genrand_close1_open2(&dsfmt_global_data); } /** @@ -302,7 +302,7 @@ inline static double dsfmt_gv_genrand_close1_open2(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_close_open(dsfmt_t *dsfmt) { - return dsfmt_genrand_close1_open2(dsfmt) - 1.0; + return dsfmt_genrand_close1_open2(dsfmt) - 1.0; } /** @@ -313,7 +313,7 @@ inline static double dsfmt_genrand_close_open(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_close_open(void) { - return dsfmt_gv_genrand_close1_open2() - 1.0; + return dsfmt_gv_genrand_close1_open2() - 1.0; } /** @@ -325,7 +325,7 @@ inline static double dsfmt_gv_genrand_close_open(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_open_close(dsfmt_t *dsfmt) { - return 2.0 - dsfmt_genrand_close1_open2(dsfmt); + return 2.0 - dsfmt_genrand_close1_open2(dsfmt); } /** @@ -336,7 +336,7 @@ inline static double dsfmt_genrand_open_close(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_open_close(void) { - return 2.0 - dsfmt_gv_genrand_close1_open2(); + return 2.0 - dsfmt_gv_genrand_close1_open2(); } /** @@ -348,19 +348,19 @@ inline static double dsfmt_gv_genrand_open_close(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_open_open(dsfmt_t *dsfmt) { - double *dsfmt64 = &dsfmt->status[0].d[0]; - union { - double d; - uint64_t u; - } r; - - if (dsfmt->idx >= DSFMT_N64) { - dsfmt_gen_rand_all(dsfmt); - dsfmt->idx = 0; - } - r.d = dsfmt64[dsfmt->idx++]; - r.u |= 1; - return r.d - 1.0; + double *dsfmt64 = &dsfmt->status[0].d[0]; + union { + double d; + uint64_t u; + } r; + + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r.d = dsfmt64[dsfmt->idx++]; + r.u |= 1; + return r.d - 1.0; } /** @@ -371,7 +371,7 @@ inline static double dsfmt_genrand_open_open(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_open_open(void) { - return dsfmt_genrand_open_open(&dsfmt_global_data); + return dsfmt_genrand_open_open(&dsfmt_global_data); } /** @@ -386,7 +386,7 @@ inline static double dsfmt_gv_genrand_open_open(void) { * see also \sa dsfmt_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_close1_open2(double array[], int size) { - dsfmt_fill_array_close1_open2(&dsfmt_global_data, array, size); + dsfmt_fill_array_close1_open2(&dsfmt_global_data, array, size); } /** @@ -402,7 +402,7 @@ inline static void dsfmt_gv_fill_array_close1_open2(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_open_close(double array[], int size) { - dsfmt_fill_array_open_close(&dsfmt_global_data, array, size); + dsfmt_fill_array_open_close(&dsfmt_global_data, array, size); } /** @@ -418,7 +418,7 @@ inline static void dsfmt_gv_fill_array_open_close(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_close_open(double array[], int size) { - dsfmt_fill_array_close_open(&dsfmt_global_data, array, size); + dsfmt_fill_array_close_open(&dsfmt_global_data, array, size); } /** @@ -434,7 +434,7 @@ inline static void dsfmt_gv_fill_array_close_open(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_open_open(double array[], int size) { - dsfmt_fill_array_open_open(&dsfmt_global_data, array, size); + dsfmt_fill_array_open_open(&dsfmt_global_data, array, size); } /** @@ -444,7 +444,7 @@ inline static void dsfmt_gv_fill_array_open_open(double array[], int size) { * @param seed a 32-bit integer used as the seed. */ inline static void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) { - dsfmt_chk_init_gen_rand(dsfmt, seed, DSFMT_MEXP); + dsfmt_chk_init_gen_rand(dsfmt, seed, DSFMT_MEXP); } /** @@ -454,7 +454,7 @@ inline static void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) { * see also \sa dsfmt_init_gen_rand() */ inline static void dsfmt_gv_init_gen_rand(uint32_t seed) { - dsfmt_init_gen_rand(&dsfmt_global_data, seed); + dsfmt_init_gen_rand(&dsfmt_global_data, seed); } /** @@ -466,7 +466,7 @@ inline static void dsfmt_gv_init_gen_rand(uint32_t seed) { */ inline static void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) { - dsfmt_chk_init_by_array(dsfmt, init_key, key_length, DSFMT_MEXP); + dsfmt_chk_init_by_array(dsfmt, init_key, key_length, DSFMT_MEXP); } /** @@ -478,34 +478,36 @@ inline static void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], * see also \sa dsfmt_init_by_array() */ inline static void dsfmt_gv_init_by_array(uint32_t init_key[], int key_length) { - dsfmt_init_by_array(&dsfmt_global_data, init_key, key_length); + dsfmt_init_by_array(&dsfmt_global_data, init_key, key_length); } #if !defined(DSFMT_DO_NOT_USE_OLD_NAMES) DSFMT_PRE_INLINE const char *get_idstring(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE int get_min_array_size(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE void init_gen_rand(uint32_t seed) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void init_by_array(uint32_t init_key[], - int key_length) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void init_by_array(uint32_t init_key[], int key_length) + DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_close1_open2(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_close_open(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_open_close(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_open_open(void) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_open_close(double array[], - int size) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_close_open(double array[], - int size) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_open_open(double array[], - int size) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_close1_open2(double array[], - int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_open_close(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_close_open(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_open_open(double array[], int size) + DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_close1_open2(double array[], int size) + DSFMT_PST_INLINE; /** * This function is just the same as dsfmt_get_idstring(). * @return id string. * see also \sa dsfmt_get_idstring() */ -inline static const char *get_idstring(void) { return dsfmt_get_idstring(); } +inline static const char *get_idstring(void) { + return dsfmt_get_idstring(); +} /** * This function is just the same as dsfmt_get_min_array_size(). @@ -513,7 +515,7 @@ inline static const char *get_idstring(void) { return dsfmt_get_idstring(); } * see also \sa dsfmt_get_min_array_size() */ inline static int get_min_array_size(void) { - return dsfmt_get_min_array_size(); + return dsfmt_get_min_array_size(); } /** @@ -522,7 +524,7 @@ inline static int get_min_array_size(void) { * see also \sa dsfmt_gv_init_gen_rand(), \sa dsfmt_init_gen_rand(). */ inline static void init_gen_rand(uint32_t seed) { - dsfmt_gv_init_gen_rand(seed); + dsfmt_gv_init_gen_rand(seed); } /** @@ -532,7 +534,7 @@ inline static void init_gen_rand(uint32_t seed) { * see also \sa dsfmt_gv_init_by_array(), \sa dsfmt_init_by_array(). */ inline static void init_by_array(uint32_t init_key[], int key_length) { - dsfmt_gv_init_by_array(init_key, key_length); + dsfmt_gv_init_by_array(init_key, key_length); } /** @@ -542,7 +544,7 @@ inline static void init_by_array(uint32_t init_key[], int key_length) { * dsfmt_gv_genrand_close1_open2() */ inline static double genrand_close1_open2(void) { - return dsfmt_gv_genrand_close1_open2(); + return dsfmt_gv_genrand_close1_open2(); } /** @@ -552,7 +554,7 @@ inline static double genrand_close1_open2(void) { * dsfmt_gv_genrand_close_open() */ inline static double genrand_close_open(void) { - return dsfmt_gv_genrand_close_open(); + return dsfmt_gv_genrand_close_open(); } /** @@ -562,7 +564,7 @@ inline static double genrand_close_open(void) { * dsfmt_gv_genrand_open_close() */ inline static double genrand_open_close(void) { - return dsfmt_gv_genrand_open_close(); + return dsfmt_gv_genrand_open_close(); } /** @@ -572,7 +574,7 @@ inline static double genrand_open_close(void) { * dsfmt_gv_genrand_open_open() */ inline static double genrand_open_open(void) { - return dsfmt_gv_genrand_open_open(); + return dsfmt_gv_genrand_open_open(); } /** @@ -585,7 +587,7 @@ inline static double genrand_open_open(void) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_open_close(double array[], int size) { - dsfmt_gv_fill_array_open_close(array, size); + dsfmt_gv_fill_array_open_close(array, size); } /** @@ -598,7 +600,7 @@ inline static void fill_array_open_close(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_close_open(double array[], int size) { - dsfmt_gv_fill_array_close_open(array, size); + dsfmt_gv_fill_array_close_open(array, size); } /** @@ -611,7 +613,7 @@ inline static void fill_array_close_open(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_open_open(double array[], int size) { - dsfmt_gv_fill_array_open_open(array, size); + dsfmt_gv_fill_array_open_open(array, size); } /** @@ -623,7 +625,7 @@ inline static void fill_array_open_open(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_close1_open2(double array[], int size) { - dsfmt_gv_fill_array_close1_open2(array, size); + dsfmt_gv_fill_array_close1_open2(array, size); } #endif /* DSFMT_DO_NOT_USE_OLD_NAMES */ @@ -633,6 +635,7 @@ inline static void fill_array_close1_open2(double array[], int size) { #endif /* DSFMT_H */ + typedef struct s_dsfmt_state { dsfmt_t *state; int has_uint32; @@ -648,8 +651,7 @@ static inline double dsfmt_next_double(dsfmt_state *state) { state->buffer_loc++; return out; } - dsfmt_fill_array_close_open(state->state, state->buffered_uniforms, - DSFMT_N64); + dsfmt_fill_array_close_open(state->state, state->buffered_uniforms, DSFMT_N64); state->buffer_loc = 1; return state->buffered_uniforms[0]; } @@ -667,6 +669,7 @@ static inline uint64_t dsfmt_next64(dsfmt_state *state) { return out; } + static inline uint32_t dsfmt_next32(dsfmt_state *state) { /* Discard bottom 16 bits */ double d = dsfmt_next_double(state); From 7beeba8572ca74950d57b16d5b0e76c2b85ca998 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 7 Mar 2018 11:36:37 +0000 Subject: [PATCH 043/279] ENH: Enable Python 2.7 compatability Enable Python 2.7 --- _randomgen/core_prng/src/common/inttypes.h | 306 ++++++++++++++++++ _randomgen/core_prng/src/pcg64/pcg64.h | 3 +- _randomgen/core_prng/src/philox/philox.h | 14 +- .../core_prng/src/splitmix64/splitmix64.h | 14 +- _randomgen/core_prng/src/threefry/threefry.c | 4 +- _randomgen/core_prng/src/threefry/threefry.h | 21 +- .../core_prng/src/xoroshiro128/xoroshiro128.c | 15 +- .../core_prng/src/xoroshiro128/xoroshiro128.h | 24 +- .../core_prng/src/xorshift1024/xorshift1024.c | 15 +- .../core_prng/src/xorshift1024/xorshift1024.h | 22 +- _randomgen/setup.py | 48 +-- 11 files changed, 427 insertions(+), 59 deletions(-) create mode 100644 _randomgen/core_prng/src/common/inttypes.h diff --git a/_randomgen/core_prng/src/common/inttypes.h b/_randomgen/core_prng/src/common/inttypes.h new file mode 100644 index 000000000000..8f8b61108a21 --- /dev/null +++ b/_randomgen/core_prng/src/common/inttypes.h @@ -0,0 +1,306 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + + +#endif // _MSC_INTTYPES_H_ ] \ No newline at end of file diff --git a/_randomgen/core_prng/src/pcg64/pcg64.h b/_randomgen/core_prng/src/pcg64/pcg64.h index 54bd37efc7e6..8b1746d9d0dc 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.h +++ b/_randomgen/core_prng/src/pcg64/pcg64.h @@ -213,11 +213,12 @@ static inline uint64_t pcg64_next64(pcg64_state *state) { } static inline uint32_t pcg64_next32(pcg64_state *state) { + uint64_t next; if (state->has_uint32) { state->has_uint32 = 0; return state->uinteger; } - uint64_t next = pcg64_random_r(state->pcg_state); + next = pcg64_random_r(state->pcg_state); state->has_uint32 = 1; state->uinteger = (uint32_t)(next & 0xffffffff); return (uint32_t)(next >> 32); diff --git a/_randomgen/core_prng/src/philox/philox.h b/_randomgen/core_prng/src/philox/philox.h index 477ba17accb6..bc87b3d3a125 100644 --- a/_randomgen/core_prng/src/philox/philox.h +++ b/_randomgen/core_prng/src/philox/philox.h @@ -6,7 +6,7 @@ #define INLINE inline #endif -#define PHILOX_BUFFER_SIZE 4UL +#define PHILOX_BUFFER_SIZE 4L struct r123array2x64 { uint64_t v[2]; @@ -143,14 +143,16 @@ typedef struct s_philox_state { } philox_state; static INLINE uint64_t philox_next(philox_state *state) { + uint64_t out; + int i; + philox4x64_ctr_t ct; + if (state->buffer_pos < PHILOX_BUFFER_SIZE) { - uint64_t out = state->buffer[state->buffer_pos]; + out = state->buffer[state->buffer_pos]; state->buffer_pos++; return out; } /* generate 4 new uint64_t */ - int i; - philox4x64_ctr_t ct; state->ctr->v[0]++; /* Handle carry */ if (state->ctr->v[0] == 0) { @@ -175,11 +177,13 @@ static INLINE uint64_t philox_next64(philox_state *state) { } static INLINE uint64_t philox_next32(philox_state *state) { + uint64_t next; + if (state->has_uint32) { state->has_uint32 = 0; return state->uinteger; } - uint64_t next = philox_next(state); + next = philox_next(state); state->has_uint32 = 1; state->uinteger = (uint32_t)(next & 0xffffffff); diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.h b/_randomgen/core_prng/src/splitmix64/splitmix64.h index 6fbaa1657abf..0691064428b7 100644 --- a/_randomgen/core_prng/src/splitmix64/splitmix64.h +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.h @@ -1,4 +1,13 @@ -#include +#ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/inttypes.h" +#define inline __forceinline +#else +#include +#endif +#else +#include +#endif typedef struct s_splitmix64_state { uint64_t state; @@ -18,11 +27,12 @@ static inline uint64_t splitmix64_next64(splitmix64_state *state) { } static inline uint32_t splitmix64_next32(splitmix64_state *state) { + uint64_t next; if (state->has_uint32) { state->has_uint32 = 0; return state->uinteger; } - uint64_t next = splitmix64_next64(state); + next = splitmix64_next64(state); state->uinteger = next & 0xffffffff; state->has_uint32 = 1; return (uint32_t)(next >> 32); diff --git a/_randomgen/core_prng/src/threefry/threefry.c b/_randomgen/core_prng/src/threefry/threefry.c index 069ac5356d9a..56b499bd9dda 100644 --- a/_randomgen/core_prng/src/threefry/threefry.c +++ b/_randomgen/core_prng/src/threefry/threefry.c @@ -33,9 +33,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "threefry.h" -extern inline uint64_t threefry_next64(threefry_state *state); +extern INLINE uint64_t threefry_next64(threefry_state *state); -extern inline uint64_t threefry_next32(threefry_state *state); +extern INLINE uint64_t threefry_next32(threefry_state *state); extern void threefry_jump(threefry_state *state) { /* Advances state as-if 2^128 draws were made */ diff --git a/_randomgen/core_prng/src/threefry/threefry.h b/_randomgen/core_prng/src/threefry/threefry.h index 5fa9a716b5a2..d620f6a1aaca 100644 --- a/_randomgen/core_prng/src/threefry/threefry.h +++ b/_randomgen/core_prng/src/threefry/threefry.h @@ -2,15 +2,20 @@ Adapted from random123's threefry.h */ -#include - #ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/inttypes.h" +#define INLINE __forceinline +#else +#include #define INLINE __inline __forceinline +#endif #else +#include #define INLINE inline #endif -#define THREEFRY_BUFFER_SIZE 4UL +#define THREEFRY_BUFFER_SIZE 4L enum r123_enum_threefry64x4 { /* These are the R_256 constants from the Threefish reference sources @@ -282,14 +287,15 @@ typedef struct s_threefry_state { } threefry_state; static INLINE uint64_t threefry_next(threefry_state *state) { + int i; + threefry4x64_ctr_t ct; + uint64_t out; if (state->buffer_pos < THREEFRY_BUFFER_SIZE) { - uint64_t out = state->buffer[state->buffer_pos]; + out = state->buffer[state->buffer_pos]; state->buffer_pos++; return out; } /* generate 4 new uint64_t */ - int i; - threefry4x64_ctr_t ct; state->ctr->v[0]++; /* Handle carry */ if (state->ctr->v[0] == 0) { @@ -314,11 +320,12 @@ static INLINE uint64_t threefry_next64(threefry_state *state) { } static INLINE uint64_t threefry_next32(threefry_state *state) { + uint64_t next; if (state->has_uint32) { state->has_uint32 = 0; return state->uinteger; } - uint64_t next = threefry_next(state); + next = threefry_next(state); state->has_uint32 = 1; state->uinteger = (uint32_t)(next & 0xffffffff); diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c index 928e5c523566..981aeab8478c 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c @@ -32,17 +32,20 @@ See . */ #include "xoroshiro128.h" -extern inline uint64_t xoroshiro128_next64(xoroshiro128_state *state); +extern INLINE uint64_t xoroshiro128_next64(xoroshiro128_state *state); -extern inline uint32_t xoroshiro128_next32(xoroshiro128_state *state); +extern INLINE uint32_t xoroshiro128_next32(xoroshiro128_state *state); void xoroshiro128_jump(xoroshiro128_state *state) { + int i, b; + uint64_t s0; + uint64_t s1; static const uint64_t JUMP[] = {0xbeac0467eba5facb, 0xd86b048b86aa9922}; - uint64_t s0 = 0; - uint64_t s1 = 0; - for (int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) - for (int b = 0; b < 64; b++) { + s0 = 0; + s1 = 0; + for (i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for (b = 0; b < 64; b++) { if (JUMP[i] & UINT64_C(1) << b) { s0 ^= state->s[0]; s1 ^= state->s[1]; diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h index bc6256aa6267..ad1ddb194901 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h @@ -1,4 +1,15 @@ -#include +#ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/inttypes.h" +#define INLINE __forceinline +#else +#include +#define INLINE __inline __forceinline +#endif +#else +#include +#define INLINE inline +#endif typedef struct s_xoroshiro128_state { uint64_t s[2]; @@ -6,11 +17,11 @@ typedef struct s_xoroshiro128_state { uint32_t uinteger; } xoroshiro128_state; -static inline uint64_t rotl(const uint64_t x, int k) { +static INLINE uint64_t rotl(const uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } -static inline uint64_t xoroshiro128_next(uint64_t *s) { +static INLINE uint64_t xoroshiro128_next(uint64_t *s) { const uint64_t s0 = s[0]; uint64_t s1 = s[1]; const uint64_t result = s0 + s1; @@ -22,16 +33,17 @@ static inline uint64_t xoroshiro128_next(uint64_t *s) { return result; } -static inline uint64_t xoroshiro128_next64(xoroshiro128_state *state) { +static INLINE uint64_t xoroshiro128_next64(xoroshiro128_state *state) { return xoroshiro128_next(&state->s[0]); } -static inline uint32_t xoroshiro128_next32(xoroshiro128_state *state) { +static INLINE uint32_t xoroshiro128_next32(xoroshiro128_state *state) { + uint64_t next; if (state->has_uint32) { state->has_uint32 = 0; return state->uinteger; } - uint64_t next = xoroshiro128_next(&state->s[0]); + next = xoroshiro128_next(&state->s[0]); state->has_uint32 = 1; state->uinteger = (uint32_t)(next & 0xffffffff); return (uint32_t)(next >> 32); diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.c b/_randomgen/core_prng/src/xorshift1024/xorshift1024.c index a7d1fe0fa9aa..8737b5a82ae4 100644 --- a/_randomgen/core_prng/src/xorshift1024/xorshift1024.c +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024.c @@ -4,11 +4,12 @@ to 2^512 calls to next(); it can be used to generate 2^512 non-overlapping subsequences for parallel computations. */ -extern inline uint64_t xorshift1024_next(xorshift1024_state *state); -extern inline uint64_t xorshift1024_next64(xorshift1024_state *state); -extern inline uint32_t xorshift1024_next32(xorshift1024_state *state); +extern INLINE uint64_t xorshift1024_next(xorshift1024_state *state); +extern INLINE uint64_t xorshift1024_next64(xorshift1024_state *state); +extern INLINE uint32_t xorshift1024_next32(xorshift1024_state *state); void xorshift1024_jump(xorshift1024_state *state) { + int i, j, b; static const uint64_t JUMP[] = { 0x84242f96eca9c41d, 0xa3c65b8776f96855, 0x5b34a39f070b5837, 0x4489affce4f31a1e, 0x2ffeeb0a48316f40, 0xdc2d9891fe68c022, @@ -18,14 +19,14 @@ void xorshift1024_jump(xorshift1024_state *state) { 0x284600e3f30e38c3}; uint64_t t[16] = {0}; - for (int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) - for (int b = 0; b < 64; b++) { + for (i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for (b = 0; b < 64; b++) { if (JUMP[i] & UINT64_C(1) << b) - for (int j = 0; j < 16; j++) + for (j = 0; j < 16; j++) t[j] ^= state->s[(j + state->p) & 15]; xorshift1024_next(state); } - for (int j = 0; j < 16; j++) + for (j = 0; j < 16; j++) state->s[(j + state->p) & 15] = t[j]; } diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.h b/_randomgen/core_prng/src/xorshift1024/xorshift1024.h index ae8d24f7dcff..2cceee7284f2 100644 --- a/_randomgen/core_prng/src/xorshift1024/xorshift1024.h +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024.h @@ -1,4 +1,15 @@ -#include +#ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/inttypes.h" +#define INLINE __forceinline +#else +#include +#define INLINE __inline __forceinline +#endif +#else +#include +#define INLINE inline +#endif typedef struct s_xorshift1024_state { uint64_t s[16]; @@ -7,7 +18,7 @@ typedef struct s_xorshift1024_state { uint32_t uinteger; } xorshift1024_state; -static inline uint64_t xorshift1024_next(xorshift1024_state *state) { +static INLINE uint64_t xorshift1024_next(xorshift1024_state *state) { const uint64_t s0 = state->s[state->p]; uint64_t s1 = state->s[state->p = ((state->p) + 1) & 15]; s1 ^= s1 << 31; // a @@ -15,16 +26,17 @@ static inline uint64_t xorshift1024_next(xorshift1024_state *state) { return state->s[state->p] * 0x9e3779b97f4a7c13; } -static inline uint64_t xorshift1024_next64(xorshift1024_state *state) { +static INLINE uint64_t xorshift1024_next64(xorshift1024_state *state) { return xorshift1024_next(state); } -static inline uint32_t xorshift1024_next32(xorshift1024_state *state) { +static INLINE uint32_t xorshift1024_next32(xorshift1024_state *state) { + uint64_t next; if (state->has_uint32) { state->has_uint32 = 0; return state->uinteger; } - uint64_t next = xorshift1024_next(state); + next = xorshift1024_next(state); state->has_uint32 = 1; state->uinteger = (uint32_t)(next & 0xffffffff); return (uint32_t)(next >> 32); diff --git a/_randomgen/setup.py b/_randomgen/setup.py index cb633f359ac7..2d726909bef8 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -19,6 +19,7 @@ DEBUG = False PCG_EMULATED_MATH = False +EXTRA_INCLUDE_DIRS = [] EXTRA_COMPILE_ARGS = [] EXTRA_LINK_ARGS = [] EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else ['-std=c99'] @@ -28,6 +29,8 @@ if DEBUG: EXTRA_LINK_ARGS += ['-debug'] EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] +if os.name == 'nt' and sys.version_info < (3, 0): + EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] if USE_SSE2: if os.name == 'nt': @@ -43,16 +46,18 @@ extensions = [Extension('core_prng.entropy', sources=[join(MOD_DIR, 'entropy.pyx'), join(MOD_DIR, 'src', 'entropy', 'entropy.c')], - include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'entropy')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join(MOD_DIR, 'src', + 'entropy')], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), Extension("core_prng.dsfmt", ["core_prng/dsfmt.pyx", join(MOD_DIR, 'src', 'dsfmt', 'dSFMT.c')], - include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'dsfmt')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join(MOD_DIR, 'src', + 'dsfmt')], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, define_macros=DSFMT_DEFS, @@ -60,16 +65,18 @@ Extension("core_prng.mt19937", ["core_prng/mt19937.pyx", join(MOD_DIR, 'src', 'mt19937', 'mt19937.c')], - include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'mt19937')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join(MOD_DIR, 'src', + 'mt19937')], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), Extension("core_prng.philox", ["core_prng/philox.pyx", join(MOD_DIR, 'src', 'philox', 'philox.c')], - include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'philox')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join(MOD_DIR, 'src', + 'philox')], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -77,16 +84,18 @@ ["core_prng/pcg64.pyx", join(MOD_DIR, 'src', 'pcg64', 'pcg64.c')], - include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'pcg64')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join(MOD_DIR, 'src', + 'pcg64')], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), Extension("core_prng.threefry", ["core_prng/threefry.pyx", join(MOD_DIR, 'src', 'threefry', 'threefry.c')], - include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'threefry')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join(MOD_DIR, 'src', + 'threefry')], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -94,8 +103,10 @@ ["core_prng/xoroshiro128.pyx", join(MOD_DIR, 'src', 'xoroshiro128', 'xoroshiro128.c')], - include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'xoroshiro128')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join( + MOD_DIR, 'src', + 'xoroshiro128')], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -103,8 +114,9 @@ ["core_prng/xorshift1024.pyx", join(MOD_DIR, 'src', 'xorshift1024', 'xorshift1024.c')], - include_dirs=[np.get_include(), - join(MOD_DIR, 'src', 'xorshift1024')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join(MOD_DIR, 'src', + 'xorshift1024')], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -112,13 +124,13 @@ ["core_prng/generator.pyx", join(MOD_DIR, 'src', 'distributions', 'distributions.c')], - include_dirs=[np.get_include()], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), Extension("core_prng.common", ["core_prng/common.pyx"], - include_dirs=[np.get_include()], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), From 108d9d60642dedaf9dbcfaf663c4e57ec7a940cd Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 7 Mar 2018 12:45:17 +0000 Subject: [PATCH 044/279] ENH: Add jump to mt19937 and dsfmt Add jump to dsfmt and mt19937 --- _randomgen/core_prng/dsfmt.pyx | 50 +- _randomgen/core_prng/mt19937.pyx | 5 + _randomgen/core_prng/src/dsfmt/dSFMT-jump.h | 2 +- _randomgen/core_prng/src/dsfmt/dSFMT-poly.h | 53 ++ _randomgen/core_prng/src/dsfmt/dSFMT.c | 621 +++++++++--------- _randomgen/core_prng/src/dsfmt/dSFMT.h | 327 +++++---- .../core_prng/src/mt19937/mt19937-jump.c | 224 +++++++ .../core_prng/src/mt19937/mt19937-jump.h | 15 + .../core_prng/src/mt19937/mt19937-poly.h | 207 ++++++ _randomgen/core_prng/src/mt19937/mt19937.c | 4 + _randomgen/core_prng/src/mt19937/mt19937.h | 2 + _randomgen/setup.py | 6 +- 12 files changed, 1008 insertions(+), 508 deletions(-) create mode 100644 _randomgen/core_prng/src/dsfmt/dSFMT-poly.h create mode 100644 _randomgen/core_prng/src/mt19937/mt19937-jump.c create mode 100644 _randomgen/core_prng/src/mt19937/mt19937-jump.h create mode 100644 _randomgen/core_prng/src/mt19937/mt19937-poly.h diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index 68663e4b0d10..b82007abe437 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -48,7 +48,7 @@ cdef extern from "src/dsfmt/dSFMT.h": void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) - # void dsfmt_jump(dsfmt_state *state) + void dsfmt_jump(dsfmt_state *state); cdef uint64_t dsfmt_uint64(void* st):# nogil: return dsfmt_next64(st) @@ -215,32 +215,34 @@ cdef class DSFMT: If seed values are out of range for the PRNG. """ - cdef np.ndarray init_key - ub = 2 ** 32 - if seed is None: - try: - state = random_entropy(1) - except RuntimeError: - state = random_entropy(1, 'fallback') - seed = state[0] - if np.isscalar(seed): - # TODO: This isn't correct, but works now - seed = int(seed) - if seed < 0 or seed > ub: - raise ValueError('seed must be an unsigned 32-bit integer') - dsfmt_init_gen_rand(self.rng_state.state, seed) - else: - # TODO: This also need to be impeoved to be more careful - init_key = np.asarray(seed, dtype=np.uint32).ravel() - dsfmt_init_by_array(self.rng_state.state, - init_key.data, - init_key.shape[0]) + cdef np.ndarray obj + try: + if seed is None: + try: + seed = random_entropy(1) + except RuntimeError: + seed = random_entropy(1, 'fallback') + dsfmt_init_gen_rand(self.rng_state.state, seed[0]) + else: + if hasattr(seed, 'squeeze'): + seed = seed.squeeze() + idx = operator.index(seed) + if idx > int(2**32 - 1) or idx < 0: + raise ValueError("Seed must be between 0 and 2**32 - 1") + dsfmt_init_gen_rand(self.rng_state.state, seed) + except TypeError: + obj = np.asarray(seed).astype(np.int64, casting='safe').ravel() + if ((obj > int(2**32 - 1)) | (obj < 0)).any(): + raise ValueError("Seed must be between 0 and 2**32 - 1") + obj = obj.astype(np.uint32, casting='unsafe', order='C') + dsfmt_init_by_array(self.rng_state.state, obj.data, + np.PyArray_DIM(obj, 0)) self._reset_state_variables() -# def jump(self): -# dsfmt_jump(self.rng_state) -# return self + def jump(self): + dsfmt_jump(self.rng_state) + return self @property def state(self): diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index a5b836699697..b1d9125c308a 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -25,6 +25,7 @@ cdef extern from "src/mt19937/mt19937.h": double mt19937_next_double(mt19937_state *state) nogil void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, int key_length) void mt19937_seed(mt19937_state *state, uint32_t seed) + void mt19937_jump(mt19937_state *state) cdef uint64_t mt19937_uint64(void *st) nogil: return mt19937_next64( st) @@ -162,6 +163,10 @@ cdef class MT19937: obj = obj.astype(np.uint32, casting='unsafe', order='C') mt19937_init_by_array(self.rng_state, obj.data, np.PyArray_DIM(obj, 0)) + def jump(self): + mt19937_jump(self.rng_state) + return self + @property def state(self): """Get or set the PRNG state""" diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-jump.h b/_randomgen/core_prng/src/dsfmt/dSFMT-jump.h index 2979f3269bc3..689f9499a833 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT-jump.h +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-jump.h @@ -21,7 +21,7 @@ extern "C" { #endif #include "dSFMT.h" -void dSFMT_jump(dsfmt_t * dsfmt, const char * jump_str); +void dSFMT_jump(dsfmt_t *dsfmt, const char *jump_str); #if defined(__cplusplus) } diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-poly.h b/_randomgen/core_prng/src/dsfmt/dSFMT-poly.h new file mode 100644 index 000000000000..f8e15c3eb419 --- /dev/null +++ b/_randomgen/core_prng/src/dsfmt/dSFMT-poly.h @@ -0,0 +1,53 @@ +static const char * poly_128 = +"f4dfa6c62049d0776e0bf6f1e953f3aa38abb113df86be024eab3773ad5f2b82ead936022e656dff7e562691c59dd5f7d2" +"566b78d9669002503c4ddb1888a49f32333f515e6c60c4ecd221078ec6f26f0a90f4875067ca1f399a99775037adf90556" +"6e2c7e6b42131420f8f04f112c92621c9b1502f2a8aefad6c667904af62f0d55e02d396902d3b89450103c5ce5fe0408d9" +"7cbb864861b49e4e42048ff3310b48faac55095a7f422eea4aade752f947f947c6be0a0c665bdea099246ab9eff658ea8c" +"a468bf49d0227748367878de06d7bd86ea6708fcac6e252f5f00f04309b2aac3036b64afb39d990427c6c9f03477cc7e93" +"5c43c0e61bc161db8eb15516eee8cb377ecbc1849207990fb6778721b29bfe0d89bfda1b3772fa5b0b1f7ec3daf3605203" +"2285898c6f6396f55010c31f8201b7e2e51d94f920bfe57684c5415cc342cb39a0045d9793d13cf8646096daeb8bb9bfc2" +"0a90de8f2426da8733267a9b9674f32154e8f84a9932223a2ca3c787d0b66df6675febbdfcba2f9cef09c621c57e11098b" +"3289c77397aaae8b104642ffe0c4b75598efbc53745984d68b4d6656cae299ae2be55217a9a02b009ca7be32f47fbe434b" +"ce4914a34d0c9b0085bede9b8a99319c34660d66f0124b5a7714c4bf3cbfec3ee43ed817087168bad80133bebaeeb68cf7" +"929a24d1bb3de831a8340d220906ab04159cf94b21d5ee813bd7c80f10f01b43052af530917513b169254c25d6fcfe6cb4" +"20d6ce92f54886ef6eaf9a5ba35e893ff593834d05ddf28899e42d729c7df3d21ef036020789739366f0c11ec52ff92a0b" +"fd8ba69508e27b20fabb8217bd36b90e5aa918159ac87913bc7b46c04e366c23c92807fbe9c6a407e6a4db0b4fc23c3b6c" +"706b5ca058fe8c190f849f18d16d6b48b5ed760eb202fd566291a799420b9654e08b8118bcbfead8e9dd2fdb9b053e9bdf" +"b665285c78718f726d0b3d6c37e116428ec9ac9db2637259e4e8d6402bbada46c6bdb03985e19a82e9b4e57de1b025a3cb" +"1f850beae7e8da9941655825bce0e89d536b6ee9064865b1a85c185e9fc9cb7f435de13d44773c00eed442a286e4ab807e" +"3cab4dc3441d1b7d2af693812ae8b39652bb8c835fc895d13d6da93541afeadeee450475c29f3b2dfa8ef1c1e2547463b2" +"cc2f0ff7a42ac4dd35e25c4fa030d2d2766fbe9f2d04c1304671747bace2f7dd55142bfa60f8cbc968bfc3d7a342152dc6" +"84a0fb5a32c0962a62b5220ac0f72add9d8b84d6cc76b97d03245e01fc8da3414a49bb4075d3488f29b56dc42ba69e3b58" +"529448c943ecfd98b3784a39d0b8609a8fb945e757f4569f53bd2cf80f7f638acf5b67fe9c560a3b7b0cf7e0398f31aa8b" +"03cf9c62b24296b6d8596b694469a02686c38daa16a1ef86e012d61a2f7de1693a5c00b3685175caec3c67146477eba548" +"30f1d546cb18a553779aa46adb4f2010e33f3def847c7d89b51a8462b227605f6c920fd558a6daf64bc98682e508ae960c" +"0c571870e603ba1fce0c13d53176f353fd319959e13db93eae1359f06e3dd4767c04f824cf34ec7bf8f60161ba1a615db8" +"2852eca9e3869afa711ab9a090660b0dc6cfbea310dda77e02310fbaeacd2636f975838c2dbcdbe9ac2cd85cee28f5e3f0" +"c73abf62f9fa02cd79a7606b7ba855db68a07848b057c3aaf38f1a70086e14616f6f88305a1f9ce6b41378a620d4db3e0e" +"7e1d421590dccaeff86212e232eeb5eb8a8d33a8c9b25ae88f3a7bd5032b4efa68f8af3186a02ffcbf5456f12beccace94" +"c81c360cc4a0dcc642b59f991eec68c59af78139ca60b96d6a18e9535f8995e89bd2cf6a0aef3acffd33d1c0c1b79b6641" +"4a91d9f65b2b4ec65844b96f725d2b4b0c309f3eb9d714e9dd939bbdfd85ce8fb43679aeab13f6c29549949503c9466dbd" +"337c4cdde46d6eacd15f21f4d8fdeaa627a47884c88a9c85f0b731d271a8ea7cb9e04a4a149c23c10f56b3a0476dc77a99" +"9d6e4f813e4b0f805e2a693e2ae4ae0ecc423c9ba5d17b42e691abf83784a582f2b1fd85d1e0a27ba38a500963568b2450" +"363d2c5e3f7b8ba3e5b56e4e9f745a3a710bf2ae233c303068c532ce78ff031e6ab28b705dd94d7db4500909edb5626b8c" +"9bd5ff4f0b4741388f0b91563ee516934c013e901572cba005ac5c535f4f107903be9af7b2793dfb61b5070facbe71eefe" +"1b5600f975c8c38c3a2350d78beadfecb78e981164ae8bc866e732972d3ceef4aac68e15861f9b881d9b51b4edece150bc" +"124b07645defb4202ef5d0e0962db98cae6ed459561c93c74c20bd64362e4f4fffc389a6cd80514604ff22eecc10c9cbc7" +"981d19a8102b24146354c463107c9dc070e29e70df3578022acf72289ef071ab9f9402a544d0399f1b1e5f206b6d46d445" +"f6d612a490e72918e00c853eda8493bef511149e80c9ab56e8b4b8cba3987249f77d060e61760e5792ac321c987c03c260" +"6e9393a7970212992cdbd16448078d5039d4c2c3199714f53278f4f7b1d2e514cf95bdfc078b8bb0db659cb2c3f5cc0289" +"0ea84f05d414c88d2db9e9f8455659b9fa6254405317245fa070d6970cafb4dadb2522b490a5c8e02fe973a8cdbfbfbdbf" +"b01535099ffba3d3896bc4d1189fc570c3e6fdc6469265b8da912772e75dd62ab71be507f700d56cac5e68fd6b57ec1661" +"68ab5258a69625c142a5b1b3519f94be1bde5e51d3bd8ea0c12d5af2fe4615b1b7bd4a96628a4fabc65925ff09718f63bb" +"ebaad98f89bd9543a27b3ff3b5d8bfa89f941a5eb8cc005ccd4a705190e1c9dc6a9f4264e5ee658520a4438e92de854bff" +"c39f8dc7dfbb5de4f14ba63ea16a37d14a7b4610f95b6cffd55e4679b29cedbdf20e7bd16da822fad910c359ee3a68e48a" +"ae6e769b0e291d5d3aa3e2ca9d8d23abe8a1d5349f4991e9300852cc0befb20c2fc0d169306b260763344024f8092cbcc2" +"4c6807363e9fc548a30d5faab3a94b2af0782a2942be80c45d8b0587efd587394ef33c33022436e285806ddffdd32fe363" +"45c3c38ed8d680abeb7a028b44ee6f94d060a14c7019bb6af1f1b5f0a562957d19826d8cc216f9b908c989ccd5415e3525" +"dfe9422ffb5b50b7cc3083dc325544751e5683535d7439d3da2b0bb73bea551dd99e04e0e793804f4774eb6b1daf781d9c" +"aa5128274e599e847862fe309027813d3e4eda0bbeb7201856a5c5d8370e44dabff0bb229c723ba0a6bcf29c44536147de" +"11b7835991018100105bd4329217f7386903fe8e7363cd7b3e893244e245e0a187467664c05b0be1fd429722b9b9a5e319" +"8147fad72776e8a63aab9054fa9d259af0198d088d71d132e6068676a8e9ebb0f616b51ee34aac39c2c2221c7112401727" +"0d75ff4a048363c389e04e9b440ad2032a381ac2cfc54f409caa791e65ee4f5d6cd035008f219b88a803a7382ae447bf65" +"a3df2176b25b3b7b67dabe34decd9a1384dc7a003916ca8fbcb29b3ad6fd8eac5bbbaa3bdfa6c6a3ad9427c4f3ed79fea2" +"6e14c8ce5fa3b4f82c5f7b6d2125916753a7b92ce9b46d45"; \ No newline at end of file diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.c b/_randomgen/core_prng/src/dsfmt/dSFMT.c index 3ce156699175..0f122c26c81e 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT.c +++ b/_randomgen/core_prng/src/dsfmt/dSFMT.c @@ -12,10 +12,14 @@ * The new BSD License is applied to this software, see LICENSE.txt */ #include -#include #include +#include + #include "dSFMT-params.h" + #include "dSFMT-common.h" +#include "dSFMT-jump.h" +#include "dSFMT-poly.h" #if defined(__cplusplus) extern "C" { @@ -31,14 +35,10 @@ static const int dsfmt_mexp = DSFMT_MEXP; ----------------*/ inline static uint32_t ini_func1(uint32_t x); inline static uint32_t ini_func2(uint32_t x); -inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, - int size); -inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, - int size); -inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, - int size); -inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, - int size); +inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, int size); +inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, int size); +inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, int size); +inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, int size); inline static int idxof(int i); static void initial_mask(dsfmt_t *dsfmt); static void period_certification(dsfmt_t *dsfmt); @@ -57,13 +57,9 @@ static const union X128D_T sse2_double_m_one = {{-1.0, -1.0}}; * array of LITTLE ENDIAN in BIG ENDIAN machine. */ #if defined(DSFMT_BIG_ENDIAN) -inline static int idxof(int i) { - return i ^ 1; -} +inline static int idxof(int i) { return i ^ 1; } #else -inline static int idxof(int i) { - return i; -} +inline static int idxof(int i) { return i; } #endif #if defined(HAVE_SSE2) @@ -74,7 +70,7 @@ inline static int idxof(int i) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_c0o1(w128_t *w) { - w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); + w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); } /** @@ -84,7 +80,7 @@ inline static void convert_c0o1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0c1(w128_t *w) { - w->sd = _mm_sub_pd(sse2_double_two.d128, w->sd); + w->sd = _mm_sub_pd(sse2_double_two.d128, w->sd); } /** @@ -94,8 +90,8 @@ inline static void convert_o0c1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0o1(w128_t *w) { - w->si = _mm_or_si128(w->si, sse2_int_one.i128); - w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); + w->si = _mm_or_si128(w->si, sse2_int_one.i128); + w->sd = _mm_add_pd(w->sd, sse2_double_m_one.d128); } #else /* standard C and altivec */ /** @@ -105,8 +101,8 @@ inline static void convert_o0o1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_c0o1(w128_t *w) { - w->d[0] -= 1.0; - w->d[1] -= 1.0; + w->d[0] -= 1.0; + w->d[1] -= 1.0; } /** @@ -116,8 +112,8 @@ inline static void convert_c0o1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0c1(w128_t *w) { - w->d[0] = 2.0 - w->d[0]; - w->d[1] = 2.0 - w->d[1]; + w->d[0] = 2.0 - w->d[0]; + w->d[1] = 2.0 - w->d[1]; } /** @@ -127,10 +123,10 @@ inline static void convert_o0c1(w128_t *w) { * @param w 128bit stracture of double precision floating point numbers (I/O) */ inline static void convert_o0o1(w128_t *w) { - w->u[0] |= 1; - w->u[1] |= 1; - w->d[0] -= 1.0; - w->d[1] -= 1.0; + w->u[0] |= 1; + w->u[1] |= 1; + w->d[0] -= 1.0; + w->d[1] -= 1.0; } #endif @@ -142,34 +138,33 @@ inline static void convert_o0o1(w128_t *w) { * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], - &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], + &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], + &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -180,39 +175,38 @@ inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t *array, * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], - &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - convert_c0o1(&array[i - DSFMT_N]); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - convert_c0o1(&array[i - DSFMT_N]); - } - for (i = size - DSFMT_N; i < size; i++) { - convert_c0o1(&array[i]); - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], + &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], + &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_c0o1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_c0o1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_c0o1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -223,39 +217,38 @@ inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t *array, * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], - &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - convert_o0o1(&array[i - DSFMT_N]); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - convert_o0o1(&array[i - DSFMT_N]); - } - for (i = size - DSFMT_N; i < size; i++) { - convert_o0o1(&array[i]); - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], + &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], + &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_o0o1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_o0o1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_o0o1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -266,39 +259,38 @@ inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t *array, * @param size number of 128-bit pseudorandom numbers to be generated. */ inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, - int size) { - int i, j; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], - &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&array[i], &dsfmt->status[i], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - } - for (; i < size - DSFMT_N; i++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - convert_o0c1(&array[i - DSFMT_N]); - } - for (j = 0; j < 2 * DSFMT_N - size; j++) { - dsfmt->status[j] = array[j + size - DSFMT_N]; - } - for (; i < size; i++, j++) { - do_recursion(&array[i], &array[i - DSFMT_N], - &array[i + DSFMT_POS1 - DSFMT_N], &lung); - dsfmt->status[j] = array[i]; - convert_o0c1(&array[i - DSFMT_N]); - } - for (i = size - DSFMT_N; i < size; i++) { - convert_o0c1(&array[i]); - } - dsfmt->status[DSFMT_N] = lung; + int size) { + int i, j; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&array[i], &dsfmt->status[i], &dsfmt->status[i + DSFMT_POS1], + &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&array[i], &dsfmt->status[i], &array[i + DSFMT_POS1 - DSFMT_N], + &lung); + } + for (; i < size - DSFMT_N; i++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + convert_o0c1(&array[i - DSFMT_N]); + } + for (j = 0; j < 2 * DSFMT_N - size; j++) { + dsfmt->status[j] = array[j + size - DSFMT_N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - DSFMT_N], + &array[i + DSFMT_POS1 - DSFMT_N], &lung); + dsfmt->status[j] = array[i]; + convert_o0c1(&array[i - DSFMT_N]); + } + for (i = size - DSFMT_N; i < size; i++) { + convert_o0c1(&array[i]); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -308,7 +300,7 @@ inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t *array, * @return 32-bit integer */ static uint32_t ini_func1(uint32_t x) { - return (x ^ (x >> 27)) * (uint32_t)1664525UL; + return (x ^ (x >> 27)) * (uint32_t)1664525UL; } /** @@ -318,7 +310,7 @@ static uint32_t ini_func1(uint32_t x) { * @return 32-bit integer */ static uint32_t ini_func2(uint32_t x) { - return (x ^ (x >> 27)) * (uint32_t)1566083941UL; + return (x ^ (x >> 27)) * (uint32_t)1566083941UL; } /** @@ -327,13 +319,13 @@ static uint32_t ini_func2(uint32_t x) { * @param dsfmt dsfmt state vector. */ static void initial_mask(dsfmt_t *dsfmt) { - int i; - uint64_t *psfmt; + int i; + uint64_t *psfmt; - psfmt = &dsfmt->status[0].u[0]; - for (i = 0; i < DSFMT_N * 2; i++) { - psfmt[i] = (psfmt[i] & DSFMT_LOW_MASK) | DSFMT_HIGH_CONST; - } + psfmt = &dsfmt->status[0].u[0]; + for (i = 0; i < DSFMT_N * 2; i++) { + psfmt[i] = (psfmt[i] & DSFMT_LOW_MASK) | DSFMT_HIGH_CONST; + } } /** @@ -341,44 +333,44 @@ static void initial_mask(dsfmt_t *dsfmt) { * @param dsfmt dsfmt state vector. */ static void period_certification(dsfmt_t *dsfmt) { - uint64_t pcv[2] = {DSFMT_PCV1, DSFMT_PCV2}; - uint64_t tmp[2]; - uint64_t inner; - int i; + uint64_t pcv[2] = {DSFMT_PCV1, DSFMT_PCV2}; + uint64_t tmp[2]; + uint64_t inner; + int i; #if (DSFMT_PCV2 & 1) != 1 - int j; - uint64_t work; + int j; + uint64_t work; #endif - tmp[0] = (dsfmt->status[DSFMT_N].u[0] ^ DSFMT_FIX1); - tmp[1] = (dsfmt->status[DSFMT_N].u[1] ^ DSFMT_FIX2); - - inner = tmp[0] & pcv[0]; - inner ^= tmp[1] & pcv[1]; - for (i = 32; i > 0; i >>= 1) { - inner ^= inner >> i; - } - inner &= 1; - /* check OK */ - if (inner == 1) { - return; - } + tmp[0] = (dsfmt->status[DSFMT_N].u[0] ^ DSFMT_FIX1); + tmp[1] = (dsfmt->status[DSFMT_N].u[1] ^ DSFMT_FIX2); + + inner = tmp[0] & pcv[0]; + inner ^= tmp[1] & pcv[1]; + for (i = 32; i > 0; i >>= 1) { + inner ^= inner >> i; + } + inner &= 1; + /* check OK */ + if (inner == 1) { + return; + } /* check NG, and modification */ #if (DSFMT_PCV2 & 1) == 1 - dsfmt->status[DSFMT_N].u[1] ^= 1; + dsfmt->status[DSFMT_N].u[1] ^= 1; #else - for (i = 1; i >= 0; i--) { - work = 1; - for (j = 0; j < 64; j++) { - if ((work & pcv[i]) != 0) { - dsfmt->status[DSFMT_N].u[i] ^= work; - return; - } - work = work << 1; - } - } + for (i = 1; i >= 0; i--) { + work = 1; + for (j = 0; j < 64; j++) { + if ((work & pcv[i]) != 0) { + dsfmt->status[DSFMT_N].u[i] ^= work; + return; + } + work = work << 1; + } + } #endif - return; + return; } /*---------------- @@ -389,18 +381,14 @@ static void period_certification(dsfmt_t *dsfmt) { * the Mersenne exponent, and all parameters of this generator. * @return id string. */ -const char *dsfmt_get_idstring(void) { - return DSFMT_IDSTR; -} +const char *dsfmt_get_idstring(void) { return DSFMT_IDSTR; } /** * This function returns the minimum size of array used for \b * fill_array functions. * @return minimum size of array used for fill_array functions. */ -int dsfmt_get_min_array_size(void) { - return DSFMT_N64; -} +int dsfmt_get_min_array_size(void) { return DSFMT_N64; } /** * This function fills the internal state array with double precision @@ -408,21 +396,21 @@ int dsfmt_get_min_array_size(void) { * @param dsfmt dsfmt state vector. */ void dsfmt_gen_rand_all(dsfmt_t *dsfmt) { - int i; - w128_t lung; - - lung = dsfmt->status[DSFMT_N]; - do_recursion(&dsfmt->status[0], &dsfmt->status[0], - &dsfmt->status[DSFMT_POS1], &lung); - for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { - do_recursion(&dsfmt->status[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1], &lung); - } - for (; i < DSFMT_N; i++) { - do_recursion(&dsfmt->status[i], &dsfmt->status[i], - &dsfmt->status[i + DSFMT_POS1 - DSFMT_N], &lung); - } - dsfmt->status[DSFMT_N] = lung; + int i; + w128_t lung; + + lung = dsfmt->status[DSFMT_N]; + do_recursion(&dsfmt->status[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1], + &lung); + for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) { + do_recursion(&dsfmt->status[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1], &lung); + } + for (; i < DSFMT_N; i++) { + do_recursion(&dsfmt->status[i], &dsfmt->status[i], + &dsfmt->status[i + DSFMT_POS1 - DSFMT_N], &lung); + } + dsfmt->status[DSFMT_N] = lung; } /** @@ -454,9 +442,9 @@ void dsfmt_gen_rand_all(dsfmt_t *dsfmt) { * returns the pointer to the aligned memory block. */ void dsfmt_fill_array_close1_open2(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_c1o2(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_c1o2(dsfmt, (w128_t *)array, size / 2); } /** @@ -472,9 +460,9 @@ void dsfmt_fill_array_close1_open2(dsfmt_t *dsfmt, double array[], int size) { * see also \sa fill_array_close1_open2() */ void dsfmt_fill_array_open_close(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_o0c1(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_o0c1(dsfmt, (w128_t *)array, size / 2); } /** @@ -490,9 +478,9 @@ void dsfmt_fill_array_open_close(dsfmt_t *dsfmt, double array[], int size) { * see also \sa fill_array_close1_open2() */ void dsfmt_fill_array_close_open(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_c0o1(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_c0o1(dsfmt, (w128_t *)array, size / 2); } /** @@ -508,13 +496,13 @@ void dsfmt_fill_array_close_open(dsfmt_t *dsfmt, double array[], int size) { * see also \sa fill_array_close1_open2() */ void dsfmt_fill_array_open_open(dsfmt_t *dsfmt, double array[], int size) { - assert(size % 2 == 0); - assert(size >= DSFMT_N64); - gen_rand_array_o0o1(dsfmt, (w128_t *)array, size / 2); + assert(size % 2 == 0); + assert(size >= DSFMT_N64); + gen_rand_array_o0o1(dsfmt, (w128_t *)array, size / 2); } #if defined(__INTEL_COMPILER) -# pragma warning(disable:981) +#pragma warning(disable : 981) #endif /** * This function initializes the internal state array with a 32-bit @@ -524,23 +512,23 @@ void dsfmt_fill_array_open_open(dsfmt_t *dsfmt, double array[], int size) { * @param mexp caller's mersenne expornent */ void dsfmt_chk_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed, int mexp) { - int i; - uint32_t *psfmt; - - /* make sure caller program is compiled with the same MEXP */ - if (mexp != dsfmt_mexp) { - fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); - exit(1); - } - psfmt = &dsfmt->status[0].u32[0]; - psfmt[idxof(0)] = seed; - for (i = 1; i < (DSFMT_N + 1) * 4; i++) { - psfmt[idxof(i)] = 1812433253UL - * (psfmt[idxof(i - 1)] ^ (psfmt[idxof(i - 1)] >> 30)) + i; - } - initial_mask(dsfmt); - period_certification(dsfmt); - dsfmt->idx = DSFMT_N64; + int i; + uint32_t *psfmt; + + /* make sure caller program is compiled with the same MEXP */ + if (mexp != dsfmt_mexp) { + fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); + exit(1); + } + psfmt = &dsfmt->status[0].u32[0]; + psfmt[idxof(0)] = seed; + for (i = 1; i < (DSFMT_N + 1) * 4; i++) { + psfmt[idxof(i)] = + 1812433253UL * (psfmt[idxof(i - 1)] ^ (psfmt[idxof(i - 1)] >> 30)) + i; + } + initial_mask(dsfmt); + period_certification(dsfmt); + dsfmt->idx = DSFMT_N64; } /** @@ -552,80 +540,77 @@ void dsfmt_chk_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed, int mexp) { * @param mexp caller's mersenne expornent */ void dsfmt_chk_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], - int key_length, int mexp) { - int i, j, count; - uint32_t r; - uint32_t *psfmt32; - int lag; - int mid; - int size = (DSFMT_N + 1) * 4; /* pulmonary */ - - /* make sure caller program is compiled with the same MEXP */ - if (mexp != dsfmt_mexp) { - fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); - exit(1); - } - if (size >= 623) { - lag = 11; - } else if (size >= 68) { - lag = 7; - } else if (size >= 39) { - lag = 5; - } else { - lag = 3; - } - mid = (size - lag) / 2; - - psfmt32 = &dsfmt->status[0].u32[0]; - memset(dsfmt->status, 0x8b, sizeof(dsfmt->status)); - if (key_length + 1 > size) { - count = key_length + 1; - } else { - count = size; - } - r = ini_func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid % size)] - ^ psfmt32[idxof((size - 1) % size)]); - psfmt32[idxof(mid % size)] += r; - r += key_length; - psfmt32[idxof((mid + lag) % size)] += r; - psfmt32[idxof(0)] = r; - count--; - for (i = 1, j = 0; (j < count) && (j < key_length); j++) { - r = ini_func1(psfmt32[idxof(i)] - ^ psfmt32[idxof((i + mid) % size)] - ^ psfmt32[idxof((i + size - 1) % size)]); - psfmt32[idxof((i + mid) % size)] += r; - r += init_key[j] + i; - psfmt32[idxof((i + mid + lag) % size)] += r; - psfmt32[idxof(i)] = r; - i = (i + 1) % size; - } - for (; j < count; j++) { - r = ini_func1(psfmt32[idxof(i)] - ^ psfmt32[idxof((i + mid) % size)] - ^ psfmt32[idxof((i + size - 1) % size)]); - psfmt32[idxof((i + mid) % size)] += r; - r += i; - psfmt32[idxof((i + mid + lag) % size)] += r; - psfmt32[idxof(i)] = r; - i = (i + 1) % size; - } - for (j = 0; j < size; j++) { - r = ini_func2(psfmt32[idxof(i)] - + psfmt32[idxof((i + mid) % size)] - + psfmt32[idxof((i + size - 1) % size)]); - psfmt32[idxof((i + mid) % size)] ^= r; - r -= i; - psfmt32[idxof((i + mid + lag) % size)] ^= r; - psfmt32[idxof(i)] = r; - i = (i + 1) % size; - } - initial_mask(dsfmt); - period_certification(dsfmt); - dsfmt->idx = DSFMT_N64; + int key_length, int mexp) { + int i, j, count; + uint32_t r; + uint32_t *psfmt32; + int lag; + int mid; + int size = (DSFMT_N + 1) * 4; /* pulmonary */ + + /* make sure caller program is compiled with the same MEXP */ + if (mexp != dsfmt_mexp) { + fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n"); + exit(1); + } + if (size >= 623) { + lag = 11; + } else if (size >= 68) { + lag = 7; + } else if (size >= 39) { + lag = 5; + } else { + lag = 3; + } + mid = (size - lag) / 2; + + psfmt32 = &dsfmt->status[0].u32[0]; + memset(dsfmt->status, 0x8b, sizeof(dsfmt->status)); + if (key_length + 1 > size) { + count = key_length + 1; + } else { + count = size; + } + r = ini_func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid % size)] ^ + psfmt32[idxof((size - 1) % size)]); + psfmt32[idxof(mid % size)] += r; + r += key_length; + psfmt32[idxof((mid + lag) % size)] += r; + psfmt32[idxof(0)] = r; + count--; + for (i = 1, j = 0; (j < count) && (j < key_length); j++) { + r = ini_func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % size)] ^ + psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] += r; + r += init_key[j] + i; + psfmt32[idxof((i + mid + lag) % size)] += r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + for (; j < count; j++) { + r = ini_func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % size)] ^ + psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] += r; + r += i; + psfmt32[idxof((i + mid + lag) % size)] += r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + for (j = 0; j < size; j++) { + r = ini_func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % size)] + + psfmt32[idxof((i + size - 1) % size)]); + psfmt32[idxof((i + mid) % size)] ^= r; + r -= i; + psfmt32[idxof((i + mid + lag) % size)] ^= r; + psfmt32[idxof(i)] = r; + i = (i + 1) % size; + } + initial_mask(dsfmt); + period_certification(dsfmt); + dsfmt->idx = DSFMT_N64; } #if defined(__INTEL_COMPILER) -# pragma warning(default:981) +#pragma warning(default : 981) #endif #if defined(__cplusplus) @@ -636,4 +621,6 @@ extern inline double dsfmt_next_double(dsfmt_state *state); extern inline uint64_t dsfmt_next64(dsfmt_state *state); -extern inline uint32_t dsfmt_next32(dsfmt_state *state); \ No newline at end of file +extern inline uint32_t dsfmt_next32(dsfmt_state *state); + +void dsfmt_jump(dsfmt_state *state) { dSFMT_jump(state->state, poly_128); }; \ No newline at end of file diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.h b/_randomgen/core_prng/src/dsfmt/dSFMT.h index 52b6b3aedcc2..2d616acd8276 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT.h +++ b/_randomgen/core_prng/src/dsfmt/dSFMT.h @@ -38,14 +38,14 @@ extern "C" { #endif -#include #include +#include #if !defined(DSFMT_MEXP) #ifdef __GNUC__ - #warning "DSFMT_MEXP is not defined. I assume DSFMT_MEXP is 19937." +#warning "DSFMT_MEXP is not defined. I assume DSFMT_MEXP is 19937." #endif - #define DSFMT_MEXP 19937 +#define DSFMT_MEXP 19937 #endif /*----------------- BASIC DEFINITIONS @@ -64,103 +64,103 @@ extern "C" { #define DSFMT_N64 (DSFMT_N * 2) #if !defined(DSFMT_BIG_ENDIAN) -# if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) -# if __BYTE_ORDER == __BIG_ENDIAN -# define DSFMT_BIG_ENDIAN 1 -# endif -# elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) -# if _BYTE_ORDER == _BIG_ENDIAN -# define DSFMT_BIG_ENDIAN 1 -# endif -# elif defined(__BYTE_ORDER__) && defined(__BIG_ENDIAN__) -# if __BYTE_ORDER__ == __BIG_ENDIAN__ -# define DSFMT_BIG_ENDIAN 1 -# endif -# elif defined(BYTE_ORDER) && defined(BIG_ENDIAN) -# if BYTE_ORDER == BIG_ENDIAN -# define DSFMT_BIG_ENDIAN 1 -# endif -# elif defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) \ - || defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) -# define DSFMT_BIG_ENDIAN 1 -# endif +#if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) +#if __BYTE_ORDER == __BIG_ENDIAN +#define DSFMT_BIG_ENDIAN 1 +#endif +#elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) +#if _BYTE_ORDER == _BIG_ENDIAN +#define DSFMT_BIG_ENDIAN 1 +#endif +#elif defined(__BYTE_ORDER__) && defined(__BIG_ENDIAN__) +#if __BYTE_ORDER__ == __BIG_ENDIAN__ +#define DSFMT_BIG_ENDIAN 1 +#endif +#elif defined(BYTE_ORDER) && defined(BIG_ENDIAN) +#if BYTE_ORDER == BIG_ENDIAN +#define DSFMT_BIG_ENDIAN 1 +#endif +#elif defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) || \ + defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) +#define DSFMT_BIG_ENDIAN 1 +#endif #endif #if defined(DSFMT_BIG_ENDIAN) && defined(__amd64) -# undef DSFMT_BIG_ENDIAN +#undef DSFMT_BIG_ENDIAN #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -# include +#include #elif defined(_MSC_VER) || defined(__BORLANDC__) -# if !defined(DSFMT_UINT32_DEFINED) && !defined(SFMT_UINT32_DEFINED) +#if !defined(DSFMT_UINT32_DEFINED) && !defined(SFMT_UINT32_DEFINED) typedef unsigned int uint32_t; typedef unsigned __int64 uint64_t; -# ifndef UINT64_C -# define UINT64_C(v) (v ## ui64) -# endif -# define DSFMT_UINT32_DEFINED -# if !defined(inline) && !defined(__cplusplus) -# define inline __forceinline -# endif -# endif +#ifndef UINT64_C +#define UINT64_C(v) (v##ui64) +#endif +#define DSFMT_UINT32_DEFINED +#if !defined(inline) && !defined(__cplusplus) +#define inline __forceinline +#endif +#endif +#else +#include +#if !defined(inline) && !defined(__cplusplus) +#if defined(__GNUC__) +#define inline __forceinline__ #else -# include -# if !defined(inline) && !defined(__cplusplus) -# if defined(__GNUC__) -# define inline __forceinline__ -# else -# define inline -# endif -# endif +#define inline +#endif +#endif #endif #ifndef PRIu64 -# if defined(_MSC_VER) || defined(__BORLANDC__) -# define PRIu64 "I64u" -# define PRIx64 "I64x" -# else -# define PRIu64 "llu" -# define PRIx64 "llx" -# endif +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#else +#define PRIu64 "llu" +#define PRIx64 "llx" +#endif #endif #ifndef UINT64_C -# define UINT64_C(v) (v ## ULL) +#define UINT64_C(v) (v##ULL) #endif /*------------------------------------------ 128-bit SIMD like data type for standard C ------------------------------------------*/ #if defined(HAVE_ALTIVEC) -# if !defined(__APPLE__) -# include -# endif +#if !defined(__APPLE__) +#include +#endif /** 128-bit data structure */ union W128_T { - vector unsigned int s; - uint64_t u[2]; - uint32_t u32[4]; - double d[2]; + vector unsigned int s; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; }; #elif defined(HAVE_SSE2) -# include +#include /** 128-bit data structure */ union W128_T { - __m128i si; - __m128d sd; - uint64_t u[2]; - uint32_t u32[4]; - double d[2]; + __m128i si; + __m128d sd; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; }; -#else /* standard C */ +#else /* standard C */ /** 128-bit data structure */ union W128_T { - uint64_t u[2]; - uint32_t u32[4]; - double d[2]; + uint64_t u[2]; + uint32_t u32[4]; + double d[2]; }; #endif @@ -169,8 +169,8 @@ typedef union W128_T w128_t; /** the 128-bit internal state array */ struct DSFMT_T { - w128_t status[DSFMT_N + 1]; - int idx; + w128_t status[DSFMT_N + 1]; + int idx; }; typedef struct DSFMT_T dsfmt_t; @@ -191,42 +191,42 @@ const char *dsfmt_get_idstring(void); int dsfmt_get_min_array_size(void); #if defined(__GNUC__) -# define DSFMT_PRE_INLINE inline static -# define DSFMT_PST_INLINE __attribute__((always_inline)) +#define DSFMT_PRE_INLINE inline static +#define DSFMT_PST_INLINE __attribute__((always_inline)) #elif defined(_MSC_VER) && _MSC_VER >= 1200 -# define DSFMT_PRE_INLINE __forceinline static -# define DSFMT_PST_INLINE +#define DSFMT_PRE_INLINE __forceinline static +#define DSFMT_PST_INLINE #else -# define DSFMT_PRE_INLINE inline static -# define DSFMT_PST_INLINE +#define DSFMT_PRE_INLINE inline static +#define DSFMT_PST_INLINE #endif DSFMT_PRE_INLINE uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double dsfmt_genrand_close_open(dsfmt_t *dsfmt) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double dsfmt_genrand_open_close(dsfmt_t *dsfmt) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE double dsfmt_genrand_open_open(dsfmt_t *dsfmt) - DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double +dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double +dsfmt_genrand_close_open(dsfmt_t *dsfmt) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double +dsfmt_genrand_open_close(dsfmt_t *dsfmt) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE double +dsfmt_genrand_open_open(dsfmt_t *dsfmt) DSFMT_PST_INLINE; DSFMT_PRE_INLINE uint32_t dsfmt_gv_genrand_uint32(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_close1_open2(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_close_open(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_open_close(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double dsfmt_gv_genrand_open_open(void) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_close(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close_open(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_open(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close1_open2(double array[], int size) - DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_close(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close_open(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_open(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void +dsfmt_gv_fill_array_close1_open2(double array[], int size) DSFMT_PST_INLINE; DSFMT_PRE_INLINE void dsfmt_gv_init_gen_rand(uint32_t seed) DSFMT_PST_INLINE; DSFMT_PRE_INLINE void dsfmt_gv_init_by_array(uint32_t init_key[], int key_length) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) - DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void dsfmt_init_gen_rand(dsfmt_t *dsfmt, + uint32_t seed) DSFMT_PST_INLINE; DSFMT_PRE_INLINE void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) DSFMT_PST_INLINE; @@ -239,15 +239,15 @@ DSFMT_PRE_INLINE void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], * @return double precision floating point pseudorandom number */ inline static uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) { - uint32_t r; - uint64_t *psfmt64 = &dsfmt->status[0].u[0]; + uint32_t r; + uint64_t *psfmt64 = &dsfmt->status[0].u[0]; - if (dsfmt->idx >= DSFMT_N64) { - dsfmt_gen_rand_all(dsfmt); - dsfmt->idx = 0; - } - r = psfmt64[dsfmt->idx++] & 0xffffffffU; - return r; + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r = psfmt64[dsfmt->idx++] & 0xffffffffU; + return r; } /** @@ -260,15 +260,15 @@ inline static uint32_t dsfmt_genrand_uint32(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) { - double r; - double *psfmt64 = &dsfmt->status[0].d[0]; + double r; + double *psfmt64 = &dsfmt->status[0].d[0]; - if (dsfmt->idx >= DSFMT_N64) { - dsfmt_gen_rand_all(dsfmt); - dsfmt->idx = 0; - } - r = psfmt64[dsfmt->idx++]; - return r; + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r = psfmt64[dsfmt->idx++]; + return r; } /** @@ -279,7 +279,7 @@ inline static double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static uint32_t dsfmt_gv_genrand_uint32(void) { - return dsfmt_genrand_uint32(&dsfmt_global_data); + return dsfmt_genrand_uint32(&dsfmt_global_data); } /** @@ -290,7 +290,7 @@ inline static uint32_t dsfmt_gv_genrand_uint32(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_close1_open2(void) { - return dsfmt_genrand_close1_open2(&dsfmt_global_data); + return dsfmt_genrand_close1_open2(&dsfmt_global_data); } /** @@ -302,7 +302,7 @@ inline static double dsfmt_gv_genrand_close1_open2(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_close_open(dsfmt_t *dsfmt) { - return dsfmt_genrand_close1_open2(dsfmt) - 1.0; + return dsfmt_genrand_close1_open2(dsfmt) - 1.0; } /** @@ -313,7 +313,7 @@ inline static double dsfmt_genrand_close_open(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_close_open(void) { - return dsfmt_gv_genrand_close1_open2() - 1.0; + return dsfmt_gv_genrand_close1_open2() - 1.0; } /** @@ -325,7 +325,7 @@ inline static double dsfmt_gv_genrand_close_open(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_open_close(dsfmt_t *dsfmt) { - return 2.0 - dsfmt_genrand_close1_open2(dsfmt); + return 2.0 - dsfmt_genrand_close1_open2(dsfmt); } /** @@ -336,7 +336,7 @@ inline static double dsfmt_genrand_open_close(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_open_close(void) { - return 2.0 - dsfmt_gv_genrand_close1_open2(); + return 2.0 - dsfmt_gv_genrand_close1_open2(); } /** @@ -348,19 +348,19 @@ inline static double dsfmt_gv_genrand_open_close(void) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_genrand_open_open(dsfmt_t *dsfmt) { - double *dsfmt64 = &dsfmt->status[0].d[0]; - union { - double d; - uint64_t u; - } r; - - if (dsfmt->idx >= DSFMT_N64) { - dsfmt_gen_rand_all(dsfmt); - dsfmt->idx = 0; - } - r.d = dsfmt64[dsfmt->idx++]; - r.u |= 1; - return r.d - 1.0; + double *dsfmt64 = &dsfmt->status[0].d[0]; + union { + double d; + uint64_t u; + } r; + + if (dsfmt->idx >= DSFMT_N64) { + dsfmt_gen_rand_all(dsfmt); + dsfmt->idx = 0; + } + r.d = dsfmt64[dsfmt->idx++]; + r.u |= 1; + return r.d - 1.0; } /** @@ -371,7 +371,7 @@ inline static double dsfmt_genrand_open_open(dsfmt_t *dsfmt) { * @return double precision floating point pseudorandom number */ inline static double dsfmt_gv_genrand_open_open(void) { - return dsfmt_genrand_open_open(&dsfmt_global_data); + return dsfmt_genrand_open_open(&dsfmt_global_data); } /** @@ -386,7 +386,7 @@ inline static double dsfmt_gv_genrand_open_open(void) { * see also \sa dsfmt_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_close1_open2(double array[], int size) { - dsfmt_fill_array_close1_open2(&dsfmt_global_data, array, size); + dsfmt_fill_array_close1_open2(&dsfmt_global_data, array, size); } /** @@ -402,7 +402,7 @@ inline static void dsfmt_gv_fill_array_close1_open2(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_open_close(double array[], int size) { - dsfmt_fill_array_open_close(&dsfmt_global_data, array, size); + dsfmt_fill_array_open_close(&dsfmt_global_data, array, size); } /** @@ -418,7 +418,7 @@ inline static void dsfmt_gv_fill_array_open_close(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_close_open(double array[], int size) { - dsfmt_fill_array_close_open(&dsfmt_global_data, array, size); + dsfmt_fill_array_close_open(&dsfmt_global_data, array, size); } /** @@ -434,7 +434,7 @@ inline static void dsfmt_gv_fill_array_close_open(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void dsfmt_gv_fill_array_open_open(double array[], int size) { - dsfmt_fill_array_open_open(&dsfmt_global_data, array, size); + dsfmt_fill_array_open_open(&dsfmt_global_data, array, size); } /** @@ -444,7 +444,7 @@ inline static void dsfmt_gv_fill_array_open_open(double array[], int size) { * @param seed a 32-bit integer used as the seed. */ inline static void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) { - dsfmt_chk_init_gen_rand(dsfmt, seed, DSFMT_MEXP); + dsfmt_chk_init_gen_rand(dsfmt, seed, DSFMT_MEXP); } /** @@ -454,7 +454,7 @@ inline static void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) { * see also \sa dsfmt_init_gen_rand() */ inline static void dsfmt_gv_init_gen_rand(uint32_t seed) { - dsfmt_init_gen_rand(&dsfmt_global_data, seed); + dsfmt_init_gen_rand(&dsfmt_global_data, seed); } /** @@ -466,7 +466,7 @@ inline static void dsfmt_gv_init_gen_rand(uint32_t seed) { */ inline static void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) { - dsfmt_chk_init_by_array(dsfmt, init_key, key_length, DSFMT_MEXP); + dsfmt_chk_init_by_array(dsfmt, init_key, key_length, DSFMT_MEXP); } /** @@ -478,36 +478,34 @@ inline static void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], * see also \sa dsfmt_init_by_array() */ inline static void dsfmt_gv_init_by_array(uint32_t init_key[], int key_length) { - dsfmt_init_by_array(&dsfmt_global_data, init_key, key_length); + dsfmt_init_by_array(&dsfmt_global_data, init_key, key_length); } #if !defined(DSFMT_DO_NOT_USE_OLD_NAMES) DSFMT_PRE_INLINE const char *get_idstring(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE int get_min_array_size(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE void init_gen_rand(uint32_t seed) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void init_by_array(uint32_t init_key[], int key_length) - DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void init_by_array(uint32_t init_key[], + int key_length) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_close1_open2(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_close_open(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_open_close(void) DSFMT_PST_INLINE; DSFMT_PRE_INLINE double genrand_open_open(void) DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_open_close(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_close_open(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_open_open(double array[], int size) - DSFMT_PST_INLINE; -DSFMT_PRE_INLINE void fill_array_close1_open2(double array[], int size) - DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_open_close(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_close_open(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_open_open(double array[], + int size) DSFMT_PST_INLINE; +DSFMT_PRE_INLINE void fill_array_close1_open2(double array[], + int size) DSFMT_PST_INLINE; /** * This function is just the same as dsfmt_get_idstring(). * @return id string. * see also \sa dsfmt_get_idstring() */ -inline static const char *get_idstring(void) { - return dsfmt_get_idstring(); -} +inline static const char *get_idstring(void) { return dsfmt_get_idstring(); } /** * This function is just the same as dsfmt_get_min_array_size(). @@ -515,7 +513,7 @@ inline static const char *get_idstring(void) { * see also \sa dsfmt_get_min_array_size() */ inline static int get_min_array_size(void) { - return dsfmt_get_min_array_size(); + return dsfmt_get_min_array_size(); } /** @@ -524,7 +522,7 @@ inline static int get_min_array_size(void) { * see also \sa dsfmt_gv_init_gen_rand(), \sa dsfmt_init_gen_rand(). */ inline static void init_gen_rand(uint32_t seed) { - dsfmt_gv_init_gen_rand(seed); + dsfmt_gv_init_gen_rand(seed); } /** @@ -534,7 +532,7 @@ inline static void init_gen_rand(uint32_t seed) { * see also \sa dsfmt_gv_init_by_array(), \sa dsfmt_init_by_array(). */ inline static void init_by_array(uint32_t init_key[], int key_length) { - dsfmt_gv_init_by_array(init_key, key_length); + dsfmt_gv_init_by_array(init_key, key_length); } /** @@ -544,7 +542,7 @@ inline static void init_by_array(uint32_t init_key[], int key_length) { * dsfmt_gv_genrand_close1_open2() */ inline static double genrand_close1_open2(void) { - return dsfmt_gv_genrand_close1_open2(); + return dsfmt_gv_genrand_close1_open2(); } /** @@ -554,7 +552,7 @@ inline static double genrand_close1_open2(void) { * dsfmt_gv_genrand_close_open() */ inline static double genrand_close_open(void) { - return dsfmt_gv_genrand_close_open(); + return dsfmt_gv_genrand_close_open(); } /** @@ -564,7 +562,7 @@ inline static double genrand_close_open(void) { * dsfmt_gv_genrand_open_close() */ inline static double genrand_open_close(void) { - return dsfmt_gv_genrand_open_close(); + return dsfmt_gv_genrand_open_close(); } /** @@ -574,7 +572,7 @@ inline static double genrand_open_close(void) { * dsfmt_gv_genrand_open_open() */ inline static double genrand_open_open(void) { - return dsfmt_gv_genrand_open_open(); + return dsfmt_gv_genrand_open_open(); } /** @@ -587,7 +585,7 @@ inline static double genrand_open_open(void) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_open_close(double array[], int size) { - dsfmt_gv_fill_array_open_close(array, size); + dsfmt_gv_fill_array_open_close(array, size); } /** @@ -600,7 +598,7 @@ inline static void fill_array_open_close(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_close_open(double array[], int size) { - dsfmt_gv_fill_array_close_open(array, size); + dsfmt_gv_fill_array_close_open(array, size); } /** @@ -613,7 +611,7 @@ inline static void fill_array_close_open(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_open_open(double array[], int size) { - dsfmt_gv_fill_array_open_open(array, size); + dsfmt_gv_fill_array_open_open(array, size); } /** @@ -625,7 +623,7 @@ inline static void fill_array_open_open(double array[], int size) { * dsfmt_gv_fill_array_close1_open2() */ inline static void fill_array_close1_open2(double array[], int size) { - dsfmt_gv_fill_array_close1_open2(array, size); + dsfmt_gv_fill_array_close1_open2(array, size); } #endif /* DSFMT_DO_NOT_USE_OLD_NAMES */ @@ -635,7 +633,6 @@ inline static void fill_array_close1_open2(double array[], int size) { #endif /* DSFMT_H */ - typedef struct s_dsfmt_state { dsfmt_t *state; int has_uint32; @@ -651,7 +648,8 @@ static inline double dsfmt_next_double(dsfmt_state *state) { state->buffer_loc++; return out; } - dsfmt_fill_array_close_open(state->state, state->buffered_uniforms, DSFMT_N64); + dsfmt_fill_array_close_open(state->state, state->buffered_uniforms, + DSFMT_N64); state->buffer_loc = 1; return state->buffered_uniforms[0]; } @@ -669,10 +667,11 @@ static inline uint64_t dsfmt_next64(dsfmt_state *state) { return out; } - static inline uint32_t dsfmt_next32(dsfmt_state *state) { /* Discard bottom 16 bits */ double d = dsfmt_next_double(state); uint64_t *out = (uint64_t *)&d; return (uint32_t)((*out >> 16) & 0xffffffff); } + +void dsfmt_jump(dsfmt_state *state); \ No newline at end of file diff --git a/_randomgen/core_prng/src/mt19937/mt19937-jump.c b/_randomgen/core_prng/src/mt19937/mt19937-jump.c new file mode 100644 index 000000000000..46b28cf96bcb --- /dev/null +++ b/_randomgen/core_prng/src/mt19937/mt19937-jump.c @@ -0,0 +1,224 @@ +#include "mt19937-jump.h" +#include "mt19937.h" + +/* 32-bits function */ +/* return the i-th coefficient of the polynomial pf */ +unsigned long get_coef(unsigned long *pf, unsigned int deg) { + if ((pf[deg >> 5] & (LSB << (deg & 0x1ful))) != 0) + return (1); + else + return (0); +} + +/* 32-bit function */ +/* set the coefficient of the polynomial pf with v */ +void set_coef(unsigned long *pf, unsigned int deg, unsigned long v) { + if (v != 0) + pf[deg >> 5] ^= (LSB << (deg & 0x1ful)); + else + ; +} + +void gray_code(unsigned long *h) { + unsigned int i, j = 1, l = 1, term = LL; + + h[0] = 0; + + for (i = 1; i <= QQ; i++) { + l = (l << 1); + term = (term >> 1); + for (; j < l; j++) + h[j] = h[l - j - 1] ^ term; + } +} + +void copy_state(mt19937_state *target_state, mt19937_state *state) { + int i; + + for (i = 0; i < N; i++) + target_state->key[i] = state->key[i]; + + target_state->pos = state->pos; +} + +/* next state generating function */ +void gen_next(mt19937_state *state) { + int num; + unsigned long y; + static unsigned long mag02[2] = {0x0ul, MATRIX_A}; + + num = state->pos; + if (num < N - M) { + y = (state->key[num] & UPPER_MASK) | (state->key[num + 1] & LOWER_MASK); + state->key[num] = state->key[num + M] ^ (y >> 1) ^ mag02[y % 2]; + state->pos++; + } else if (num < N - 1) { + y = (state->key[num] & UPPER_MASK) | (state->key[num + 1] & LOWER_MASK); + state->key[num] = state->key[num + (M - N)] ^ (y >> 1) ^ mag02[y % 2]; + state->pos++; + } else if (num == N - 1) { + y = (state->key[N - 1] & UPPER_MASK) | (state->key[0] & LOWER_MASK); + state->key[N - 1] = state->key[M - 1] ^ (y >> 1) ^ mag02[y % 2]; + state->pos = 0; + } +} + +void add_state(mt19937_state *state1, mt19937_state *state2) { + int i, pt1 = state1->pos, pt2 = state2->pos; + + if (pt2 - pt1 >= 0) { + for (i = 0; i < N - pt2; i++) + state1->key[i + pt1] ^= state2->key[i + pt2]; + for (; i < N - pt1; i++) + state1->key[i + pt1] ^= state2->key[i + (pt2 - N)]; + for (; i < N; i++) + state1->key[i + (pt1 - N)] ^= state2->key[i + (pt2 - N)]; + } else { + for (i = 0; i < N - pt1; i++) + state1->key[i + pt1] ^= state2->key[i + pt2]; + for (; i < N - pt2; i++) + state1->key[i + (pt1 - N)] ^= state2->key[i + pt2]; + for (; i < N; i++) + state1->key[i + (pt1 - N)] ^= state2->key[i + (pt2 - N)]; + } +} + +/* +void gen_vec_h(mt19937_state *state, mt19937_state *vec_h, + unsigned long *h) { + int i; + unsigned long k, g; + mt19937_state v; + + gray_code(h); + + copy_state(&vec_h[0], state); + + for (i = 0; i < QQ; i++) + gen_next(&vec_h[0]); + + for (i = 1; i < LL; i++) { + copy_state(&v, state); + g = h[i] ^ h[i - 1]; + for (k = 1; k < g; k = (k << 1)) + gen_next(&v); + copy_state(&vec_h[h[i]], &vec_h[h[i - 1]]); + add_state(&vec_h[h[i]], &v); + } +} +*/ + +/* compute pf(ss) using Sliding window algorithm */ +/* +void calc_state(unsigned long *pf, mt19937_state *state, + mt19937_state *vec_h) { + mt19937_state *temp1; + int i = MEXP - 1, j, digit, skip = 0; + + temp1 = (mt19937_state *)calloc(1, sizeof(mt19937_state)); + + while (get_coef(pf, i) == 0) + i--; + + for (; i >= QQ; i--) { + if (get_coef(pf, i) != 0) { + for (j = 0; j < QQ + 1; j++) + gen_next(temp1); + digit = 0; + for (j = 0; j < QQ; j++) + digit = (digit << 1) ^ get_coef(pf, i - j - 1); + add_state(temp1, &vec_h[digit]); + i -= QQ; + } else + gen_next(temp1); + } + + for (; i > -1; i--) { + gen_next(temp1); + if (get_coef(pf, i) == 1) + add_state(temp1, state); + else + ; + } + + copy_state(state, temp1); + free(temp1); +} +*/ + +/* compute pf(ss) using standard Horner method */ +void horner1(unsigned long *pf, mt19937_state *state) { + int i = MEXP - 1; + mt19937_state *temp; + + temp = (mt19937_state *)calloc(1, sizeof(mt19937_state)); + + while (get_coef(pf, i) == 0) + i--; + + if (i > 0) { + copy_state(temp, state); + gen_next(temp); + i--; + for (; i > 0; i--) { + if (get_coef(pf, i) != 0) + add_state(temp, state); + else + ; + gen_next(temp); + } + if (get_coef(pf, 0) != 0) + add_state(temp, state); + else + ; + } else if (i == 0) + copy_state(temp, state); + else + ; + + copy_state(state, temp); + free(temp); +} + +void mt19937_jump_state(mt19937_state *state, const char *jump_str) { + unsigned long *pf; + int i; + + pf = (unsigned long *)calloc(P_SIZE, sizeof(unsigned long)); + + for (i = MEXP - 1; i > -1; i--) { + if (jump_str[i] == '1') + set_coef(pf, i, 1); + } + /* TODO: Should generate the next set and start from 0, but doesn't matter ?? + */ + if (state->pos >= N) { + state->pos = 0; + } + + horner1(pf, state); + + free(pf); +} +/* +void mt19937_jump(mt19937_state *state, const char *jump_str) +{ + unsigned long h[LL]; + mt19937_state vec_h[LL]; + unsigned long *pf; + int i; + + pf = (unsigned long *)calloc(P_SIZE, sizeof(unsigned long)); + + for (i = MEXP - 1; i > -1; i--) + { + if (jump_str[i] == '1') + set_coef(pf, i, 1); + } + + gen_vec_h(state, &vec_h, &h); + calc_state(pf, state, &vec_h); + + free(pf); +} +*/ \ No newline at end of file diff --git a/_randomgen/core_prng/src/mt19937/mt19937-jump.h b/_randomgen/core_prng/src/mt19937/mt19937-jump.h new file mode 100644 index 000000000000..394c150a0336 --- /dev/null +++ b/_randomgen/core_prng/src/mt19937/mt19937-jump.h @@ -0,0 +1,15 @@ +#pragma once +#include "mt19937.h" +#include + +/* parameters for computing Jump */ +#define W_SIZE 32 /* size of unsigned long */ +#define MEXP 19937 +#define P_SIZE ((MEXP / W_SIZE) + 1) +#define LSB 0x00000001UL +#define QQ 7 +#define LL 128 /* LL = 2^(QQ) */ + +void mt19937_jump_state(mt19937_state *state, const char *jump_str); + +void set_coef(unsigned long *pf, unsigned int deg, unsigned long v); \ No newline at end of file diff --git a/_randomgen/core_prng/src/mt19937/mt19937-poly.h b/_randomgen/core_prng/src/mt19937/mt19937-poly.h new file mode 100644 index 000000000000..b03747881348 --- /dev/null +++ b/_randomgen/core_prng/src/mt19937/mt19937-poly.h @@ -0,0 +1,207 @@ +static const char * poly = +"0001000111110111011100100010101111000000010100100101000001110111100010101000110100101001011001010" +"1110101101100101011100101101011001110011100011110100001000001011100101100010100000010011101110011" +"0100001001111010000100100101001011100111101101001100000111001000011101100100010000001111110100010" +"0000111101000101000101101111001011000011001001001011010011001000001000011100100010110101111111101" +"0010001001100010011011101111101110111010111000010000011010110011111101100000100100101001010000001" +"1001111000011010011101001101011000111001110010110000011000110101111010110011011000001110110010001" +"1001101011011101000011001011111111100011001010111100000001111011111101000101000011000011111100101" +"0100001111101010101100000110100110010010101011011100110011000101100101011110010101110000101011100" +"0001010100010110100000111001100000011101011001101000001000101101010100010101100000100011110110011" +"0101100110111101010111100010100110100011111011100111000001110110010000000100000110101010111001111" +"0011110010000110101101010001110010100111111111100100101010010011101111011000010111101001110110110" +"1011101101101100110111000100101100111001011111110101001000011111010011000111110011100100001101111" +"1001010110110001000100001001000010000000001011011100101010010100011000110101001000010101100111101" +"0011110101100110111100000111001011011001100101111011000101001011011111110110100010001100101001100" +"1111110011111111110111011011100011000100110011011011011001101011100110010001111100001111100100001" +"1000100011001010100101010100111110001100111111011111100100011110011101101000110100101110010111111" +"1001010110000101001110010110001011011010101111111001110001100100011001000010111001011011000111100" +"1101001011110111111010011000110100001010000000101010101001111101111110101111110101110101010010100" +"1100100101010110011111001101100110001011000101010001000110011011111101111110001100000010110110101" +"1111110100001011101011101110111101100001111000011100000110110100100100100101011000111000100110001" +"0110110001001000111110101111000000100100010100100101101111100011010100111101110010000001011111111" +"1101010000011001010101111001111110001111100010100010100001011001110001010010100001011111110110111" +"1100100100001111000111110111000100010101010110100111100001011001101001111101001110010110110011010" +"1000010011000110000000110110110000111010010000111001100010100101010101111100010111000000011101110" +"1100011010110001101100110000001010001100111101101011100111110111000110010011011011001101001111100" +"1011111001100011010110101111100110111101011100000011000010001010001101001011000001111000101000100" +"0110001011001010110000001101100000011000011110010000101000011010011110001101111111010010101100100" +"1111010100000011011001111111011011111001101110101010110111110110101000100001011110111010100111100" +"0000001001111100111111111000100000100100010001011001100001111100100000001111011101100010011000111" +"0011110110100011011001110011100011011000010000000101101101001010111000010000010101111110000000100" +"1011010100001001000011001100011000000111100111100101010100000111000000110111011101011111100010101" +"0011001100110000010101111001000111001001010100011000110010011011101001001100101100000000111000111" +"0111111000010010010100000101010010000100101011111111111001100101101010011010100010111001011100011" +"1001001011010000110000111100010110110100000100110010000010010000001000110010101000110101101100100" +"0001100001100011110110010000100000100010011001010010110111100011011000101011001100001111110110110" +"0001100110010100011001101000100001110011011111101001101011110011011011111110111110101110010011001" +"1000000101100000101100100000100000001011000100100001100100101101010111101010111101010001001010110" +"0011111011001101001110110010100100000011001001111010001001100101110000000010111101000111111101010" +"0110101110101110001001110000111110100000101101100110010001111101111011001000101110111010110111110" +"0011001101011010001011000010000111111111101001011100110101011000000001111000101100011101011011100" +"1111101110000000000110001110011001101100111111010001110000111110100011000100001100110010000110111" +"1001011011001111011100000000011011000100000011000010010111000111101000011001001100011010001111000" +"0011110010100010001101011101010011001100000010101001001101111101000111001110110000000010111101001" +"1110110011101110111010011100101001010101100100011111100110001111011111110010100000011100110110001" +"1011100000101000010100011101000010111100101111101100110001010001010000101110000000110100010110011" +"1111110100101010011010100001100110110110011111110010000100001010011110010110001000000100000111000" +"0111001010011001000010111001100110100110110101111011110111001001000101010010010011000111110010101" +"1100110001100101001000010001101010011001110011001110001110010100010000000000000110111001010101000" +"0111111011011101000111011001011011000101110100010001111100101110000100001011111101111101010011001" +"0010001100011011101100010010101011001000001001010101100110001111001110011100110111111010110010001" +"1111111101111001001101101001001010011001110000101000110010111110010110111111000100101000101011010" +"0000101101101100000110101000101000010001111000100000111110011111111110010010001010001111011001100" +"0011110111000000111111000100001111101110100010101011001010110110011001010010001011100001010110101" +"0100000010101101000011001101110010000010110011000101100100000111111100011001110011010011001110000" +"1110011110000000001001001010100000111001010110001110011100011010010010001110010011001010111100000" +"1110000101101001011010001001010000111000010011010100001010110000101101110110011000011100111100001" +"1001000011010001110110111001100100001111110010110010011111000010100000001101110100000000101101000" +"0011000000100011000111110001000011100111110110000110101111101100011110100111111000000011011110110" +"1101011010111010010001001101000110110010000010101000000001100100100000001111011001001010110100011" +"1011000010101111010111000001001100111110000010110010011011110011111001000101111011010011010100001" +"0110011111100001011111101010010100110001001001001000100010101011011000011100111000110101110000001" +"1100001111100011110010000101011000010101111010001101010101100001100101100000100100000101011001100" +"0011001000101010101010100111000100100010101000111111101010000000101010101001000101010100100111001" +"1001100001010001100110111101010001111010011100000001001110100010010011110100001000011111100010001" +"0010001000100110101011001110100110101110110110100101111000110101101101001000001110011010110011001" +"0111111101011011101001111001011100001010110111000001100010110110100011010111011000111010100011000" +"1111010110001001010000110001000101101100010100000000100001111100000010111001000011000101010100001" +"0001101100011100010100101110010100000010011011010100000111110110000110101011011010010001110000111" +"0110101000110101110010011100010010100111001101110110010001101001101101010100001010001110111011011" +"1010011001010111101001011000100111001110011000000001101000001111001100001100000011001110100110011" +"0011000110001001010111111111110110111111000111100010010101110000101100101000001010001011010100010" +"1010010100010011101111100111010010010001110101011110110100001000001001000111001110010001001100100" +"1100100010001010011011110100000101101011101010110110100100010001110000111010111001111011111001011" +"0000000000011000100100100111001000101111000000110001011110101111110111100000000100101011000111011" +"1011010011101000001011001001110001111010000100101101010111001010001000100001000111011010000110111" +"1010110001001110001100001110011000101100000101100000000110101000000110101100100101110001100100100" +"0110000110101011100001010001010000011101111011111011011000100100101011110101111000001011110010110" +"0111011011100111101010110001111011010011111000010111110100001001010001011001000110111100000101011" +"0010111111010100000110111101001100000100001011101010100011010010000001101100100101001000100011000" +"0101010111111100100000111011101111100000011011111111010001100011001100101101011110101011101100001" +"0100010011101111111011000111111101001000101101111001111000101110010111001010101011010111000000101" +"0110010000010010101111100010111110000000011101001000011111001011111100111100100101100101111010110" +"1010101001110011111100111110100000111100100000111111000010100001111011111110110010001001000000000" +"1110100110010111100101111111001010001111001101100001011000111011100010100001000010100000011001000" +"0000111000110111001001100010111010100111111001111101100101000011001001110011100110101110001101110" +"1110000010110110010110000111001110110000011011100111000101100101000000001110011011001001111001111" +"0000101100001000000111100110110000110111111001101001111111010000001011110011011011100100110000110" +"1001011111101100100111111000000010001110111011010011011101001100000011001010000010101111111010110" +"0001000100101110101101100001001010100110010000110110100110011001000111011110110011001110111110101" +"0000011111011011001111010010101011000010011101001011100001010001111001000110000010000101010011111" +"0110011000001111101001110001101011111111001010010110100001101000000011101000101011101000110101111" +"0000101110011010010000110100000101100011000100101111100011001111011101001010100111001110100001101" +"0000110111011000000110011001101011110000101100110110000101100000110110100001001001110001110001001" +"1100110111111100101001100010010110011011110001000111111111001101111110010000011001011010111101001" +"1101111110101110110100101100110001101101001010111101101000000011111111100101000101110001000011001" +"1000111110111011010010101011110110110001010001001001100111111010011101111000000111011000011010011" +"0111010101001110010100101101000110000110001100010101001110101011010100000110110111111111110011110" +"0100011110100011001000110101111010000001011011110101001100111100010100101100010000010110011001111" +"0011011110001110010010100100011111110000110011011100010110110101001110011010101111011001010101011" +"1001001111001000001100100111000001000110110101100111000101011000000100001000100010011000001110011" +"0000111100000111001101011111010000010001100000010101101000111100001000010011110000001011001001100" +"0011011011111011100000111101001011101000010010001001111110010101111010110101101110110111010000101" +"1100011000000000110110100011010100100010001101010101101110110111111011010110011101011010110101011" +"1101000000010010011111000000101000110001000011100001101111010101100000100000100111111111100000000" +"0011100011100101110010111100010111110010101110101000011000111111001110111111000001101101011011111" +"1100110101001000011111001111000000001010001001010101101000001100111010101100010111001001111100000" +"1110101101110001011100011101101100001001001011100111100110011101111000100010010001111100001010010" +"1011001001010100101100010010000110010000101010111111001000011100000000101101110010001101110101001" +"1110000011100101010000011110000010001000001010110001010000100111001100110001111000100100011100110" +"1100010011110111001001100000100111001010000000000011100011111111101110010101111010100010000100001" +"0101101001010111111110000110110010100000001011110100010111110111010000001011110110111000000110010" +"0001100100111110001100010101000010011111100000100010000101110000111001101100100000011111111100010" +"1001101101001000001111000100100001010110111011110110001001010001110001001100011001001100000000101" +"1100011110101101011001100001010110001010000111100000011011011001000010101100010101110011001101110" +"0000101011010001010011111001011000010101010100110110111110101000111110001000010100000000100010100" +"1000111111000110110010001111000010101011101101111101011110101111100111111100111101000101000010011" +"0010111010100010011001000000010111100010000101001011001101100011100001001111010100100110101111111" +"1000010011110101001010011111111011101001110100001001100010000100001001100101101111011100100011001" +"1111010001011001111101011110101101000111110101001010011101010010010101001000000000011001100110001" +"0001000010101010101000010100111000001110000111001110001101111111000010101010111001011101001001011" +"0011001111011010101110101111110001001100100111010001011000010100000100000001001100000011000011101" +"1100000110000001011001110000101001010111101000110101000011000000111011100101010000111000010010101" +"1010100101100001011011011110110011000100100101010011111101000000100001001101000011000101010111101" +"1110111111100010111000111000010110111010010110000000000100101001000111101101100000000110111011001" +"0100000000100100011110111011101101101101010110001110100001100001001011000000111111110100011110011" +"0010000010000000010100110011110000000010000011111000111101011110000000000010101101001100000010010" +"1011001001101110110011100001100011101001101011110011010001011101000100011111001010100000011111111" +"1010101100000010001000110000110000101000110100110011100000110010110100011111010001000011100001001" +"1000101000010111111011100010111000111001010100110000000010011011101010101111000110001000110111011" +"1011100001100011010001101011010100110110011100000010111001011111110010100110100010001100000011100" +"0001011001011000101011010000001010011010001011000111000011000011110011111001111010001101011010010" +"0010010001001001101000101001011011101110001100010001010100010111111001100100000010001111100010111" +"0100001111001100101001011101010010110010100010001100011010100110000100011010111110001011011001000" +"1001001111011010010011101110100001111100000110101001010111110001101100110010111010111001011111010" +"1110111011111110000001110010000010011111000111011011000011000010011110011111111101100101111011100" +"0101101100000110101110000111111111111010110101010100111000011111011001100000100000101011000101110" +"1011010010100000000100100000010111101110111001000011111011111110100011010010000110001101111101100" +"1100010111001011011001011001010100100110100101001000111011011001100011001010010101111001100100110" +"1000110000111011100101110101101000011001010010100011000001111001110110101101010010110110001100100" +"0100001011101100111001010001111011010110010010110010110111110001001001111001111010010001010001101" +"1110100110101100011110100100110111000111010110011000100100110110001101111100111110100001000110000" +"1110011011001101100101100000001010100011101000010100111011111100011010000110000001011100010000101" +"0100101000010001110010001100010110011111111101111000011001110111011100110010010100100010001000010" +"0100001110010000011000110001101011101001110100100011011001000111010101110100110011010111001100001" +"0100001001101010010111110101110111000000010100111101011010101001000001001000001000101101111000000" +"0110000101110100001111001101110111011110010111101000100101110111010101001101100001110001101101101" +"0010101100100101000100100100110111000111000111100111000001100001000111101011000110111110001010000" +"0100110010001101100011010111000111010111000111110000110000101111101110010110111001011000111010001" +"1011000010010101010010011001000011010110111011010001001010100111001000010110110110101110000110000" +"1110110010011001011011000100011101001001000111011100100000000000100001101101000101000100000111001" +"0011100001100110101011011101110111101111000100100011100001010001011001110010101010001110101101110" +"1011001110111111111010101101000010111111011011011100011100101010001011011100011111011100101011000" +"1000110100101000011111010011110000000101101110010000101100001000100000000010010110000000000110011" +"1000000000001111001001000100000111001110111111001111101100001100111000101100011000100111111110011" +"1110010101011010111100110010110001010000101111111101001010100010001001111010111000010000010010001" +"1111111101100100001101011011100001010101000111110111111101011010011111111101000111011001011011000" +"0000101011100011101110110011101111011110011110010000011001111001110111011011111010011011001110111" +"0101100111110100000100010110010010101001010100010111000101111001011011001001110010100011101111110" +"1101011110010101101011010010011111110000011010011101000000010000111010100100111110111000001101010" +"0101100001111001111010101011110001001010000011010110010100011100100100111110100110000010011111001" +"0100010011001001010101110111111010011101101100000101011110111010011110001111110100111011110011010" +"0111001010110101010110000011001010000000101101010101001101011000011011010110101010101111101101100" +"1100100000111101010111011011011110011001100010010000010100101000111111101011100111010101011000111" +"1100110010101100010011111100000110011111101011100100001110001100001010101001001100010011001000100" +"1101101000101101110010000001101001001110101111000110111000011101111110100100110111000000101011110" +"0001100100001010101001101111001000001100000011010000100101100000001110100010010000110110101010111" +"1100010100000110011100101010111110010110111100000010110011011001011110111001010011011110010001110" +"1101110000001011101101011111101011111110110110000111110011101100110100010000100000110100010010110" +"0011000011000110101001110100111010110000100010110101110111100010110001000111100111001011011110010" +"0001001110101001101101011010111001001101100011101001011011001110011010001010110100111001111100101" +"1000111001010010000010111010101110001100110111111000011101001000001010010011101000111001100111110" +"1110100100100110010111111101010011101111011011111011011010011110100101100001011000001001001010010" +"1100001000000110110011011101010001011110010001001110110100100001101101001011101010001110111111010" +"1100011100101000011110111110110011111111100010110010110111010010001111101110011011010110000001000" +"0010110100010101110100001000010011100110001110001110010100010010010110011100100110010100001110011" +"1100001011010000001101011011011110100000001110100111001000101000001000001001000010000111010000100" +"0111100000101010110010111010010101100000001100110101001001000110001110111011110001010010010011000" +"1100001111101101100001111000101100110010001000111001101101011110100110100011101000011111011010101" +"0101000011111010010110001001100110110111000100100011011101000010001010110001111001111101110001111" +"0100100000010111010011111110000101001001011110100100010011101110011010100101100001010000001110100" +"0011111101111000100110011000011001100100001010110011111100111010100011110100010101011110011001000" +"0000110000100100001011101110111010001001011110010101111100001111101101111011011110001010000100010" +"1001100100100100110010010101100110000000100000000111110011100111101001010000010000000000101011100" +"0011101011100110000001100101010101011111111011010011110010011011001010011101010010100010001011010" +"1100010011101011010111110100001010100011000011001001011011101111110011001110010001100101011001101" +"0100010001111111100000101000001011010100011100111011010111001100110110001100110101000011010001010" +"1011100001001010011110001010100100001101110011101011100100101010001100110011110010001100100001000" +"0110001001110110010111101011101101010111001010011010101110000010100010000111011000010110011000001" +"1000110010100001110001100010010000001101111110000010010110100000000000001111110010001110111100001" +"0100111101000011101110010101011011000101011010111100111111001011110001110011110011011010010111101" +"1010111011101101000001110111001010011001110010100100100100001010001100101010111001110100000110111" +"1010000111000011101101100101101001100000011100100111100110010110011100101000111110111000110111110" +"1101100101011101100111011111111001111000011110111110101100000111000101100100110111000010100101000" +"0110000011011101111101111000110101011000010111010000111011000000100011101010100111001111101010111" +"0001110100001000100001011101001010001110100000101100001011101111100111101011111001111100101101111" +"0101100001110011111110110100110010000011011111101101110110000110110011100110111000111101000010111" +"0111101011100100000000011101111011000100001000111000000111011010101010110000111111101010110001111" +"0000110100111101111011001010101110000011001101001101000010011001101011111110111101010111010011100" +"0101010011001111101111001100101000101000111110111001011111100000001101111011000001001100111111111" +"1010111101000001111011110010001001001110100111110010000011110000011000000101001100011110110011001" +"1010101001000010001010110000010011110101011110010111010001010111101100001001100011101001111101001" +"0110110100111001110011100011111010010010100010111000001100001011010010000100100110101010111001001" +"0110000101011011011100110111111001010000001001011010101010010001011010111100111010101101000101101" +"0100100001011101110111111001111111110110111011000101010000010000011111001000100101100100100110110" +"1100000111110010110011010100000100011111110001110010110001000001001111001101110110110101101010111" +"0000100111101100010001110010110111100011100101100011"; diff --git a/_randomgen/core_prng/src/mt19937/mt19937.c b/_randomgen/core_prng/src/mt19937/mt19937.c index bb080c1a2ee1..e5ca9e0cff67 100644 --- a/_randomgen/core_prng/src/mt19937/mt19937.c +++ b/_randomgen/core_prng/src/mt19937/mt19937.c @@ -1,4 +1,6 @@ #include "mt19937.h" +#include "mt19937-jump.h" +#include "mt19937-poly.h" void mt19937_seed(mt19937_state *state, uint32_t seed) { int pos; @@ -101,3 +103,5 @@ extern inline uint64_t mt19937_next64(mt19937_state *state); extern inline uint32_t mt19937_next32(mt19937_state *state); extern inline double mt19937_next_double(mt19937_state *state); + +void mt19937_jump(mt19937_state *state) { mt19937_jump_state(state, poly); } diff --git a/_randomgen/core_prng/src/mt19937/mt19937.h b/_randomgen/core_prng/src/mt19937/mt19937.h index 18da9622decf..8105329ece6b 100644 --- a/_randomgen/core_prng/src/mt19937/mt19937.h +++ b/_randomgen/core_prng/src/mt19937/mt19937.h @@ -65,3 +65,5 @@ static inline double mt19937_next_double(mt19937_state *state) { int32_t a = mt19937_next(state) >> 5, b = mt19937_next(state) >> 6; return (a * 67108864.0 + b) / 9007199254740992.0; } + +void mt19937_jump(mt19937_state *state); diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 2d726909bef8..3c40089a4e7f 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -54,7 +54,8 @@ ), Extension("core_prng.dsfmt", ["core_prng/dsfmt.pyx", - join(MOD_DIR, 'src', 'dsfmt', 'dSFMT.c')], + join(MOD_DIR, 'src', 'dsfmt', 'dSFMT.c'), + join(MOD_DIR, 'src', 'dsfmt', 'dSFMT-jump.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'dsfmt')], @@ -64,7 +65,8 @@ ), Extension("core_prng.mt19937", ["core_prng/mt19937.pyx", - join(MOD_DIR, 'src', 'mt19937', 'mt19937.c')], + join(MOD_DIR, 'src', 'mt19937', 'mt19937.c'), + join(MOD_DIR, 'src', 'mt19937', 'mt19937-jump.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'mt19937')], From 034b27b287d8800a6369bf3b2db2cce3f8f02285 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 7 Mar 2018 17:45:56 +0000 Subject: [PATCH 045/279] ENH: Add ctypes interface and examples Add prototype ctypes interface to Xoroshiro128 Add example showing use in Cython Add eample showing use in Numba --- _randomgen/core_prng/xoroshiro128.pyx | 11 ++++++++ _randomgen/examples/cython/extending.pyx | 25 ++++++++++++++++ _randomgen/examples/cython/setup.py | 11 ++++++++ _randomgen/examples/numba/extending.py | 36 ++++++++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 _randomgen/examples/cython/extending.pyx create mode 100644 _randomgen/examples/cython/setup.py create mode 100644 _randomgen/examples/numba/extending.py diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 820ae0476e49..4e5240ced998 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -2,6 +2,9 @@ from libc.stdint cimport uint32_t, uint64_t from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New +from collections import namedtuple +ctypes_interface = namedtuple('ctypes_interface', ['state','next_uint64','next_uint32','next_double']) + import numpy as np cimport numpy as np @@ -10,6 +13,8 @@ from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy +import ctypes + np.import_array() cdef extern from "src/xoroshiro128/xoroshiro128.h": @@ -51,6 +56,7 @@ cdef class Xoroshiro128: cdef xoroshiro128_state *rng_state cdef prng_t *_prng cdef public object _prng_capsule + cdef public object ctypes def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoroshiro128_state)) @@ -62,6 +68,11 @@ cdef class Xoroshiro128: self._prng.next_uint64 = &xoroshiro128_uint64 self._prng.next_uint32 = &xoroshiro128_uint32 self._prng.next_double = &xoroshiro128_double + + self.ctypes = ctypes_interface(ctypes.c_void_p(self.rng_state), + ctypes.cast(&xoroshiro128_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), + ctypes.cast(&xoroshiro128_uint32, ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), + ctypes.cast(&xoroshiro128_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p))) cdef const char *name = "CorePRNG" self._prng_capsule = PyCapsule_New(self._prng, name, NULL) diff --git a/_randomgen/examples/cython/extending.pyx b/_randomgen/examples/cython/extending.pyx new file mode 100644 index 000000000000..1af47b48d267 --- /dev/null +++ b/_randomgen/examples/cython/extending.pyx @@ -0,0 +1,25 @@ +import numpy as np +cimport numpy as np +from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer +from core_prng.common cimport prng_t +from core_prng.xoroshiro128 import Xoroshiro128 + +np.import_array() + +def uniform_mean(Py_ssize_t N): + cdef Py_ssize_t i + cdef prng_t *rng + cdef const char *anon_name = "CorePRNG" + cdef double[::1] random_values + cdef np.ndarray randoms + + x = Xoroshiro128() + capsule = x._prng_capsule + if not PyCapsule_IsValid(capsule, anon_name): + raise ValueError("Invalid pointer to anon_func_state") + rng = PyCapsule_GetPointer(capsule, anon_name) + random_values = np.empty(N) + for i in range(N): + random_values[i] = rng.next_double(rng.state) + randoms = np.asarray(random_values) + return randoms.mean() diff --git a/_randomgen/examples/cython/setup.py b/_randomgen/examples/cython/setup.py new file mode 100644 index 000000000000..408ea3254ea8 --- /dev/null +++ b/_randomgen/examples/cython/setup.py @@ -0,0 +1,11 @@ +# python setup.py build_ext -i +import numpy as np +from distutils.core import setup +from Cython.Build import cythonize +from setuptools.extension import Extension + +setup( + ext_modules=cythonize([Extension("extending", + sources=['extending.pyx'], + include_dirs=[np.get_include()])]) +) diff --git a/_randomgen/examples/numba/extending.py b/_randomgen/examples/numba/extending.py new file mode 100644 index 000000000000..46b125dc2e88 --- /dev/null +++ b/_randomgen/examples/numba/extending.py @@ -0,0 +1,36 @@ +from core_prng import Xoroshiro128 +import numpy as np +import numba as nb + +x = Xoroshiro128() +f = x.ctypes.next_uint32 +s = x.ctypes.state + + +@nb.jit(nopython=True) +def bounded_uint(lb, ub, state): + mask = delta = ub - lb + mask |= mask >> 1 + mask |= mask >> 2 + mask |= mask >> 4 + mask |= mask >> 8 + mask |= mask >> 16 + + val = f(state) & mask + while val > delta: + val = f(state) & mask + + return lb + val + + +bounded_uint(323, 2394691, s.value) + + +@nb.jit(nopython=True) +def bounded_uints(lb, ub, n, state): + out = np.empty(n, dtype=np.uint32) + for i in range(n): + bounded_uint(lb, ub, state) + + +bounded_uints(323, 2394691, 10000000, s.value) From 45f6299f413100017f9d88cce9a986a0a8697cae Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 7 Mar 2018 20:10:39 +0000 Subject: [PATCH 046/279] CLN: Mix skipped nogils Re-enable all nogils --- _randomgen/core_prng/dsfmt.pyx | 2 +- _randomgen/core_prng/pcg64.pyx | 2 +- _randomgen/core_prng/xoroshiro128.pyx | 2 +- _randomgen/core_prng/xorshift1024.pyx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index b82007abe437..90b2a6bffec3 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -50,7 +50,7 @@ cdef extern from "src/dsfmt/dSFMT.h": void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) void dsfmt_jump(dsfmt_state *state); -cdef uint64_t dsfmt_uint64(void* st):# nogil: +cdef uint64_t dsfmt_uint64(void* st) nogil: return dsfmt_next64(st) cdef uint32_t dsfmt_uint32(void *st) nogil: diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index 3e447ae3a92a..dcacb797179a 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -51,7 +51,7 @@ cdef extern from "src/pcg64/pcg64.h": void pcg64_advance(pcg64_state *state, uint64_t *step) -cdef uint64_t pcg64_uint64(void* st):# nogil: +cdef uint64_t pcg64_uint64(void* st) nogil: return pcg64_next64(st) cdef uint32_t pcg64_uint32(void *st) nogil: diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 4e5240ced998..17807c4efb50 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -30,7 +30,7 @@ cdef extern from "src/xoroshiro128/xoroshiro128.h": uint64_t xoroshiro128_next32(xoroshiro128_state *state) nogil void xoroshiro128_jump(xoroshiro128_state *state) -cdef uint64_t xoroshiro128_uint64(void* st):# nogil: +cdef uint64_t xoroshiro128_uint64(void* st) nogil: return xoroshiro128_next64(st) cdef uint32_t xoroshiro128_uint32(void *st) nogil: diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index 6c0585369479..27499e30c2a0 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -25,7 +25,7 @@ cdef extern from "src/xorshift1024/xorshift1024.h": uint64_t xorshift1024_next32(xorshift1024_state *state) nogil void xorshift1024_jump(xorshift1024_state *state) -cdef uint64_t xorshift1024_uint64(void* st):# nogil: +cdef uint64_t xorshift1024_uint64(void* st) nogil: return xorshift1024_next64(st) cdef uint32_t xorshift1024_uint32(void *st) nogil: From 456a3993f29449bf3be39482106e544982a46b1a Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 7 Mar 2018 22:48:10 +0000 Subject: [PATCH 047/279] ENH: Add cffi interface Add xffi interface for xoroshir128 --- _randomgen/core_prng/xoroshiro128.pyx | 28 ++++++++++++++---- _randomgen/examples/numba/extending.py | 39 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 17807c4efb50..76d78652dadd 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -3,7 +3,7 @@ from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New from collections import namedtuple -ctypes_interface = namedtuple('ctypes_interface', ['state','next_uint64','next_uint32','next_double']) +interface = namedtuple('interface', ['state_address','state','next_uint64','next_uint32','next_double']) import numpy as np cimport numpy as np @@ -14,6 +14,7 @@ import core_prng.pickle cimport entropy import ctypes +import cffi np.import_array() @@ -57,6 +58,8 @@ cdef class Xoroshiro128: cdef prng_t *_prng cdef public object _prng_capsule cdef public object ctypes + cdef public object cffi + cdef public object state_address def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoroshiro128_state)) @@ -68,11 +71,26 @@ cdef class Xoroshiro128: self._prng.next_uint64 = &xoroshiro128_uint64 self._prng.next_uint32 = &xoroshiro128_uint32 self._prng.next_double = &xoroshiro128_double + + ffi = cffi.FFI() + self.cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',&xoroshiro128_uint64), + ffi.cast('uint32_t (*)(void *)',&xoroshiro128_uint32), + ffi.cast('double (*)(void *)',&xoroshiro128_double)) - self.ctypes = ctypes_interface(ctypes.c_void_p(self.rng_state), - ctypes.cast(&xoroshiro128_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&xoroshiro128_uint32, ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&xoroshiro128_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p))) + self.state_address = self.rng_state + self.ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&xoroshiro128_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&xoroshiro128_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&xoroshiro128_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p))) cdef const char *name = "CorePRNG" self._prng_capsule = PyCapsule_New(self._prng, name, NULL) diff --git a/_randomgen/examples/numba/extending.py b/_randomgen/examples/numba/extending.py index 46b125dc2e88..aa7122c9543a 100644 --- a/_randomgen/examples/numba/extending.py +++ b/_randomgen/examples/numba/extending.py @@ -34,3 +34,42 @@ def bounded_uints(lb, ub, n, state): bounded_uints(323, 2394691, 10000000, s.value) + + +g = x.cffi.next_double +cffi_state = x.cffi.state +state_addr = x.cffi.state_address + + +def normals(n, state): + out = np.empty(n) + for i in range(n//2): + x1 = 2.0*g(state) - 1.0 + x2 = 2.0*g(state) - 1.0 + r2 = x1*x1 + x2*x2 + while r2 >= 1.0 or r2 == 0.0: + x1 = 2.0*g(state) - 1.0 + x2 = 2.0*g(state) - 1.0 + r2 = x1*x1 + x2*x2 + f = np.sqrt(-2.0*np.log(r2)/r2) + out[2*i] = f*x1 + out[2*i+1] = f*x2 + + if n % 2 == 1: + x1 = 2.0*g(state) - 1.0 + x2 = 2.0*g(state) - 1.0 + r2 = x1*x1 + x2*x2 + while r2 >= 1.0 or r2 == 0.0: + x1 = 2.0*g(state) - 1.0 + x2 = 2.0*g(state) - 1.0 + r2 = x1*x1 + x2*x2 + f = np.sqrt(-2.0*np.log(r2)/r2) + out[n] = f*x1 + return out + + +print(normals(10, cffi_state).var()) + +normalsj = nb.jit(normals, nopython=True) + +print(normalsj(10000000, state_addr).var()) From 2aaa0aaddd9f04e605c335f9f47cc56278a2b0b0 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 8 Mar 2018 09:39:58 +0000 Subject: [PATCH 048/279] ENH: Add example using distributions Add example Rename _prng_capsule to capsule Use common.pxd to gather all information about distirbutionsh --- _randomgen/core_prng/common.pxd | 21 ++++++- _randomgen/core_prng/dsfmt.pyx | 4 +- _randomgen/core_prng/generator.pyx | 19 +------ _randomgen/core_prng/mt19937.pyx | 4 +- _randomgen/core_prng/pcg64.pyx | 4 +- _randomgen/core_prng/philox.pyx | 4 +- _randomgen/core_prng/threefry.pyx | 4 +- _randomgen/core_prng/xoroshiro128.pyx | 57 ++++++++++--------- _randomgen/core_prng/xorshift1024.pyx | 4 +- _randomgen/examples/cython/extending.pyx | 45 +++++++++++++-- .../cython/extending_distributions.pyx | 44 ++++++++++++++ _randomgen/examples/cython/setup.py | 15 ++++- 12 files changed, 158 insertions(+), 67 deletions(-) create mode 100644 _randomgen/examples/cython/extending_distributions.pyx diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index 38c66814775b..3387894e81e8 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -21,7 +21,7 @@ ctypedef ConstraintType constraint_type cdef extern from "src/distributions/distributions.h": - cdef struct s_binomial_t: + struct s_binomial_t: int has_binomial; double psave; long nsave; @@ -42,7 +42,7 @@ cdef extern from "src/distributions/distributions.h": ctypedef s_binomial_t binomial_t - cdef struct prng: + struct prng: void *state uint64_t (*next_uint64)(void *st) uint32_t (*next_uint32)(void *st) @@ -55,6 +55,23 @@ cdef extern from "src/distributions/distributions.h": ctypedef prng prng_t + double random_sample(prng_t *prng_state) nogil + double random_standard_exponential(prng_t *prng_state) nogil + double random_standard_exponential_zig(prng_t *prng_state) nogil + double random_gauss(prng_t *prng_state) nogil + double random_gauss_zig(prng_t* prng_state) nogil + double random_standard_gamma(prng_t *prng_state, double shape) nogil + double random_standard_gamma_zig(prng_t *prng_state, double shape) nogil + + float random_sample_f(prng_t *prng_state) nogil + float random_standard_exponential_f(prng_t *prng_state) nogil + float random_standard_exponential_zig_f(prng_t *prng_state) nogil + float random_gauss_f(prng_t *prng_state) nogil + float random_gauss_zig_f(prng_t* prng_state) nogil + float random_standard_gamma_f(prng_t *prng_state, float shape) nogil + float random_standard_gamma_zig_f(prng_t *prng_state, float shape) nogil + + ctypedef double (*random_double_0)(prng_t *state) nogil ctypedef double (*random_double_1)(prng_t *state, double a) nogil ctypedef double (*random_double_2)(prng_t *state, double a, double b) nogil diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index 90b2a6bffec3..0341d9a43c8d 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -75,7 +75,7 @@ cdef class DSFMT: """ cdef dsfmt_state *rng_state cdef prng_t *_prng - cdef public object _prng_capsule + cdef public object capsule def __init__(self, seed=None): self.rng_state = malloc(sizeof(dsfmt_state)) @@ -90,7 +90,7 @@ cdef class DSFMT: self._prng.next_uint32 = &dsfmt_uint32 self._prng.next_double = &dsfmt_double cdef const char *name = "CorePRNG" - self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + self.capsule = PyCapsule_New(self._prng, name, NULL) # Pickling support: def __getstate__(self): diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index c48afd199aa4..69205245be6f 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -20,23 +20,6 @@ import core_prng.pickle np.import_array() -cdef extern from "src/distributions/distributions.h": - double random_sample(prng_t *prng_state) nogil - double random_standard_exponential(prng_t *prng_state) nogil - double random_standard_exponential_zig(prng_t *prng_state) nogil - double random_gauss(prng_t *prng_state) nogil - double random_gauss_zig(prng_t* prng_state) nogil - double random_standard_gamma(prng_t *prng_state, double shape) nogil - double random_standard_gamma_zig(prng_t *prng_state, double shape) nogil - - float random_sample_f(prng_t *prng_state) nogil - float random_standard_exponential_f(prng_t *prng_state) nogil - float random_standard_exponential_zig_f(prng_t *prng_state) nogil - float random_gauss_f(prng_t *prng_state) nogil - float random_gauss_zig_f(prng_t* prng_state) nogil - float random_standard_gamma_f(prng_t *prng_state, float shape) nogil - float random_standard_gamma_zig_f(prng_t *prng_state, float shape) nogil - cdef class RandomGenerator: """ Prototype Random Generator that consumes randoms from a CorePRNG class @@ -61,7 +44,7 @@ cdef class RandomGenerator: prng = Xoroshiro128() self.__core_prng = prng - capsule = prng._prng_capsule + capsule = prng.capsule cdef const char *anon_name = "CorePRNG" if not PyCapsule_IsValid(capsule, anon_name): raise ValueError("Invalid pointer to anon_func_state") diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index b1d9125c308a..5c09709921e2 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -52,7 +52,7 @@ cdef class MT19937: """ cdef mt19937_state *rng_state cdef prng_t *_prng - cdef public object _prng_capsule + cdef public object capsule def __init__(self, seed=None): self.rng_state = malloc(sizeof(mt19937_state)) @@ -66,7 +66,7 @@ cdef class MT19937: self._prng.next_double = &mt19937_double cdef const char *name = "CorePRNG" - self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + self.capsule = PyCapsule_New(self._prng, name, NULL) def __dealloc__(self): free(self.rng_state) diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index dcacb797179a..a2e0842eb1c5 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -76,7 +76,7 @@ cdef class PCG64: """ cdef pcg64_state *rng_state cdef prng_t *_prng - cdef public object _prng_capsule + cdef public object capsule def __init__(self, seed=None, inc=1): self.rng_state = malloc(sizeof(pcg64_state)) @@ -91,7 +91,7 @@ cdef class PCG64: self._prng.next_double = &pcg64_double cdef const char *name = "CorePRNG" - self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + self.capsule = PyCapsule_New(self._prng, name, NULL) # Pickling support: def __getstate__(self): diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx index f0dcc3a7d1ea..ce9e47be9e73 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/core_prng/philox.pyx @@ -66,7 +66,7 @@ cdef class Philox: """ cdef philox_state *rng_state cdef prng_t *_prng - cdef public object _prng_capsule + cdef public object capsule def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(philox_state)) @@ -84,7 +84,7 @@ cdef class Philox: self._prng.next_double = &philox_double cdef const char *name = 'CorePRNG' - self._prng_capsule = PyCapsule_New( self._prng, name, NULL) + self.capsule = PyCapsule_New( self._prng, name, NULL) # Pickling support: def __getstate__(self): diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index db83379eb9c5..aedfc70c7cea 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -62,7 +62,7 @@ cdef class ThreeFry: """ cdef threefry_state *rng_state cdef prng_t *_prng - cdef public object _prng_capsule + cdef public object capsule def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(threefry_state)) @@ -78,7 +78,7 @@ cdef class ThreeFry: self._prng.next_double = &threefry_double cdef const char *name = 'CorePRNG' - self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + self.capsule = PyCapsule_New(self._prng, name, NULL) # Pickling support: def __getstate__(self): diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 76d78652dadd..367d140c0169 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -13,9 +13,6 @@ from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy -import ctypes -import cffi - np.import_array() cdef extern from "src/xoroshiro128/xoroshiro128.h": @@ -56,10 +53,7 @@ cdef class Xoroshiro128: """ cdef xoroshiro128_state *rng_state cdef prng_t *_prng - cdef public object _prng_capsule - cdef public object ctypes - cdef public object cffi - cdef public object state_address + cdef public object capsule def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoroshiro128_state)) @@ -72,28 +66,8 @@ cdef class Xoroshiro128: self._prng.next_uint32 = &xoroshiro128_uint32 self._prng.next_double = &xoroshiro128_double - ffi = cffi.FFI() - self.cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',&xoroshiro128_uint64), - ffi.cast('uint32_t (*)(void *)',&xoroshiro128_uint32), - ffi.cast('double (*)(void *)',&xoroshiro128_double)) - - self.state_address = self.rng_state - self.ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&xoroshiro128_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&xoroshiro128_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&xoroshiro128_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p))) - cdef const char *name = "CorePRNG" - self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + self.capsule = PyCapsule_New(self._prng, name, NULL) # Pickling support: def __getstate__(self): @@ -213,3 +187,30 @@ cdef class Xoroshiro128: self.rng_state.s[1] = value['s'][1] self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] + + @property + def ctypes(self): + import ctypes + + return interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&xoroshiro128_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&xoroshiro128_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&xoroshiro128_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p))) + + @property + def cffi(self): + import cffi + + ffi = cffi.FFI() + return interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._prng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._prng.next_uint32), + ffi.cast('double (*)(void *)',self._prng.next_double)) diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index 27499e30c2a0..635bb24961f9 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -50,7 +50,7 @@ cdef class Xorshift1024: """ cdef xorshift1024_state *rng_state cdef prng_t *_prng - cdef public object _prng_capsule + cdef public object capsule def __init__(self, seed=None): self.rng_state = malloc(sizeof(xorshift1024_state)) @@ -64,7 +64,7 @@ cdef class Xorshift1024: self._prng.next_double = &xorshift1024_double cdef const char *name = "CorePRNG" - self._prng_capsule = PyCapsule_New(self._prng, name, NULL) + self.capsule = PyCapsule_New(self._prng, name, NULL) # Pickling support: def __getstate__(self): diff --git a/_randomgen/examples/cython/extending.pyx b/_randomgen/examples/cython/extending.pyx index 1af47b48d267..f09563aff5ee 100644 --- a/_randomgen/examples/cython/extending.pyx +++ b/_randomgen/examples/cython/extending.pyx @@ -1,5 +1,7 @@ import numpy as np cimport numpy as np +cimport cython +from libc.stdint cimport uint32_t from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from core_prng.common cimport prng_t from core_prng.xoroshiro128 import Xoroshiro128 @@ -9,17 +11,52 @@ np.import_array() def uniform_mean(Py_ssize_t N): cdef Py_ssize_t i cdef prng_t *rng - cdef const char *anon_name = "CorePRNG" + cdef const char *capsule_name = "CorePRNG" cdef double[::1] random_values cdef np.ndarray randoms x = Xoroshiro128() - capsule = x._prng_capsule - if not PyCapsule_IsValid(capsule, anon_name): + capsule = x.capsule + if not PyCapsule_IsValid(capsule, capsule_name): raise ValueError("Invalid pointer to anon_func_state") - rng = PyCapsule_GetPointer(capsule, anon_name) + rng = PyCapsule_GetPointer(capsule, capsule_name) random_values = np.empty(N) for i in range(N): random_values[i] = rng.next_double(rng.state) randoms = np.asarray(random_values) return randoms.mean() + +cdef uint32_t bounded_uint(uint32_t lb, uint32_t ub, prng_t *rng): + cdef uint32_t mask, delta, val + mask = delta = ub - lb + mask |= mask >> 1 + mask |= mask >> 2 + mask |= mask >> 4 + mask |= mask >> 8 + mask |= mask >> 16 + + val = rng.next_uint32(rng.state) & mask + while val > delta: + val = rng.next_uint32(rng.state) & mask + + return lb + val + +@cython.boundscheck(False) +@cython.wraparound(False) +def bounded_uints(uint32_t lb, uint32_t ub, Py_ssize_t n): + cdef Py_ssize_t i + cdef prng_t *rng + cdef uint32_t[::1] out + cdef const char *capsule_name = "CorePRNG" + + x = Xoroshiro128() + out = np.empty(n, dtype=np.uint32) + capsule = x.capsule + + if not PyCapsule_IsValid(capsule, capsule_name): + raise ValueError("Invalid pointer to anon_func_state") + rng = PyCapsule_GetPointer(capsule, capsule_name) + + for i in range(n): + out[i] = bounded_uint(lb, ub, rng) + return np.asarray(out) diff --git a/_randomgen/examples/cython/extending_distributions.pyx b/_randomgen/examples/cython/extending_distributions.pyx new file mode 100644 index 000000000000..9d16743a6384 --- /dev/null +++ b/_randomgen/examples/cython/extending_distributions.pyx @@ -0,0 +1,44 @@ +import numpy as np +cimport numpy as np +cimport cython +from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer +from core_prng.common cimport * +from core_prng.xoroshiro128 import Xoroshiro128 + +@cython.boundscheck(False) +@cython.wraparound(False) +def normals_bm(Py_ssize_t n): + cdef Py_ssize_t i + cdef prng_t *rng + cdef const char *capsule_name = "CorePRNG" + cdef double[::1] random_values + + x = Xoroshiro128() + capsule = x.capsule + if not PyCapsule_IsValid(capsule, capsule_name): + raise ValueError("Invalid pointer to anon_func_state") + rng = PyCapsule_GetPointer(capsule, capsule_name) + random_values = np.empty(n) + for i in range(n): + random_values[i] = random_gauss(rng) + randoms = np.asarray(random_values) + return randoms + +@cython.boundscheck(False) +@cython.wraparound(False) +def normals_zig(Py_ssize_t n): + cdef Py_ssize_t i + cdef prng_t *rng + cdef const char *capsule_name = "CorePRNG" + cdef double[::1] random_values + + x = Xoroshiro128() + capsule = x.capsule + if not PyCapsule_IsValid(capsule, capsule_name): + raise ValueError("Invalid pointer to anon_func_state") + rng = PyCapsule_GetPointer(capsule, capsule_name) + random_values = np.empty(n) + for i in range(n): + random_values[i] = random_gauss_zig(rng) + randoms = np.asarray(random_values) + return randoms diff --git a/_randomgen/examples/cython/setup.py b/_randomgen/examples/cython/setup.py index 408ea3254ea8..61bdc5f606f3 100644 --- a/_randomgen/examples/cython/setup.py +++ b/_randomgen/examples/cython/setup.py @@ -3,9 +3,18 @@ from distutils.core import setup from Cython.Build import cythonize from setuptools.extension import Extension +from os.path import join + +extending = Extension("extending", + sources=['extending.pyx'], + include_dirs=[np.get_include()]) +distributions = Extension("extending_distributions", + sources=['extending_distributions.pyx', + join('..', '..', 'core_prng', 'src', 'distributions', 'distributions.c')], + include_dirs=[np.get_include()]) + +extensions = [extending, distributions] setup( - ext_modules=cythonize([Extension("extending", - sources=['extending.pyx'], - include_dirs=[np.get_include()])]) + ext_modules=cythonize(extensions) ) From be92147cbde355b25880e4fcd3c7a5ac56445a23 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 8 Mar 2018 10:30:20 +0000 Subject: [PATCH 049/279] ENH: Enable building distributions as a DLL Enable using distributions as a DLL --- .../src/distributions/distributions.h | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index 3672060eab3b..9048784467a4 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -17,6 +17,12 @@ typedef int bool; #include "numpy/npy_common.h" #include +#ifdef DLL_EXPORT +#define DECLDIR __declspec(dllexport) +#else +#define DECLDIR extern +#endif + typedef double (*random_double_0)(void *st); typedef float (*random_float_0)(void *st); @@ -52,22 +58,22 @@ typedef struct prng { binomial_t *binomial; } prng_t; -extern float random_sample_f(prng_t *prng_state); -extern double random_sample(prng_t *prng_state); +DECLDIR float random_sample_f(prng_t *prng_state); +DECLDIR double random_sample(prng_t *prng_state); -extern uint32_t random_uint32(prng_t *prng_state); +DECLDIR uint32_t random_uint32(prng_t *prng_state); -extern double random_standard_exponential(prng_t *prng_state); -extern float random_standard_exponential_f(prng_t *prng_state); -extern double random_standard_exponential_zig(prng_t *prng_state); -extern float random_standard_exponential_zig_f(prng_t *prng_state); +DECLDIR double random_standard_exponential(prng_t *prng_state); +DECLDIR float random_standard_exponential_f(prng_t *prng_state); +DECLDIR double random_standard_exponential_zig(prng_t *prng_state); +DECLDIR float random_standard_exponential_zig_f(prng_t *prng_state); -extern double random_gauss(prng_t *prng_state); -extern float random_gauss_f(prng_t *prng_state); -extern double random_gauss_zig(prng_t *prng_state); -extern float random_gauss_zig_f(prng_t *prng_state); +DECLDIR double random_gauss(prng_t *prng_state); +DECLDIR float random_gauss_f(prng_t *prng_state); +DECLDIR double random_gauss_zig(prng_t *prng_state); +DECLDIR float random_gauss_zig_f(prng_t *prng_state); -extern double random_standard_gamma(prng_t *prng_state, double shape); -extern float random_standard_gamma_f(prng_t *prng_state, float shape); -extern double random_standard_gamma_zig(prng_t *prng_state, double shape); -extern float random_standard_gamma_zig_f(prng_t *prng_state, float shape); +DECLDIR double random_standard_gamma(prng_t *prng_state, double shape); +DECLDIR float random_standard_gamma_f(prng_t *prng_state, float shape); +DECLDIR double random_standard_gamma_zig(prng_t *prng_state, double shape); +DECLDIR float random_standard_gamma_zig_f(prng_t *prng_state, float shape); From 214cef65c7a1166c4954c0772fcb6a534744af12 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 8 Mar 2018 10:30:55 +0000 Subject: [PATCH 050/279] ENH: Example numba example using external distributions Add example using external distributions --- _randomgen/core_prng/xoroshiro128.pyx | 11 +++- .../examples/numba/extending_distributions.py | 56 +++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 _randomgen/examples/numba/extending_distributions.py diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 367d140c0169..b56f643f73e5 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -3,7 +3,7 @@ from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New from collections import namedtuple -interface = namedtuple('interface', ['state_address','state','next_uint64','next_uint32','next_double']) +interface = namedtuple('interface', ['state_address','state','next_uint64','next_uint32','next_double','prng']) import numpy as np cimport numpy as np @@ -89,6 +89,9 @@ cdef class Xoroshiro128: def _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 + # TODO: These should be done everywhere for safety + self._prng.has_gauss = 0 + self._prng.has_gauss_f = 0 def __random_integer(self, bits=64): """ @@ -202,7 +205,8 @@ cdef class Xoroshiro128: ctypes.c_void_p)), ctypes.cast(&xoroshiro128_double, ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p))) + ctypes.c_void_p)), + ctypes.c_void_p(self._prng)) @property def cffi(self): @@ -213,4 +217,5 @@ cdef class Xoroshiro128: ffi.cast('void *',self.rng_state), ffi.cast('uint64_t (*)(void *)',self._prng.next_uint64), ffi.cast('uint32_t (*)(void *)',self._prng.next_uint32), - ffi.cast('double (*)(void *)',self._prng.next_double)) + ffi.cast('double (*)(void *)',self._prng.next_double), + ffi.cast('void *',self._prng)) diff --git a/_randomgen/examples/numba/extending_distributions.py b/_randomgen/examples/numba/extending_distributions.py new file mode 100644 index 000000000000..b04f5f49f995 --- /dev/null +++ b/_randomgen/examples/numba/extending_distributions.py @@ -0,0 +1,56 @@ +""" + +On *nix, execute in core_prng/src/distributions + +export PYTHON_INCLUDE=#path to Python's include folder, usually ${PYTHON_HOME}/include/python${PYTHON_VERSION}m +export NUMPY_INCLUDE=#path to numpy's include folder, usually ${PYTHON_HOME}/lib/python${PYTHON_VERSION}/site-packages/numpy/core/include +gcc -shared -o libdistributions.so -fPIC distributions.c -I${NUMPY_INCLUDE} -I${PYTHON_INCLUDE} +mv libdistributions.so ../../../examples/numba/ + +On Windows + +rem PYTHON_HOME is setup dependent, this is an example +set PYTHON_HOME=c:\Anaconda +cl.exe /LD .\distributions.c -DDLL_EXPORT -I%PYTHON_HOME%\lib\site-packages\numpy\core\include -I%PYTHON_HOME%\include %PYTHON_HOME%\libs\python36.lib +move distributions.dll ../../../examples/numba/ +""" +import numpy as np +from cffi import FFI +from core_prng import Xoroshiro128 +import numba as nb + +ffi = FFI() +lib = ffi.dlopen('./libdistributions.so') +ffi.cdef(""" +double random_gauss(void *prng_state); +double random_gauss_zig(void *prng_state); +""") +x = Xoroshiro128() +xffi = x.cffi +prng = xffi.prng + +random_gauss = lib.random_gauss +random_gauss_zig = lib.random_gauss_zig + + +def normals(n, prng): + out = np.empty(n) + for i in range(n): + out[i] = random_gauss(prng) + return out + + +def normals_zig(n, prng): + out = np.empty(n) + for i in range(n): + out[i] = random_gauss_zig(prng) + return out + + +normalsj = nb.jit(normals, nopython=True) +normals_zigj = nb.jit(normals_zig, nopython=True) + +prng_address = int(ffi.cast('uintptr_t', prng)) + +norm = normalsj(1000, prng_address) +norm_zig = normals_zigj(1000, prng_address) From 71f6181bea015c0981d38302173cdac24090dc00 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 8 Mar 2018 10:30:55 +0000 Subject: [PATCH 051/279] ENH: Example numba example using external distributions Add example using external distributions --- _randomgen/examples/numba/extending_distributions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/_randomgen/examples/numba/extending_distributions.py b/_randomgen/examples/numba/extending_distributions.py index b04f5f49f995..2091d2b97595 100644 --- a/_randomgen/examples/numba/extending_distributions.py +++ b/_randomgen/examples/numba/extending_distributions.py @@ -1,5 +1,4 @@ """ - On *nix, execute in core_prng/src/distributions export PYTHON_INCLUDE=#path to Python's include folder, usually ${PYTHON_HOME}/include/python${PYTHON_VERSION}m From 85f9671a6bc0fac48f0b18648f6fb3edd04b4498 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 8 Mar 2018 10:39:25 +0000 Subject: [PATCH 052/279] ENH: Enable numba example on windows Enable numba on windows --- .../examples/numba/extending_distributions.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/_randomgen/examples/numba/extending_distributions.py b/_randomgen/examples/numba/extending_distributions.py index 2091d2b97595..5c365f338a6c 100644 --- a/_randomgen/examples/numba/extending_distributions.py +++ b/_randomgen/examples/numba/extending_distributions.py @@ -1,4 +1,4 @@ -""" +r""" On *nix, execute in core_prng/src/distributions export PYTHON_INCLUDE=#path to Python's include folder, usually ${PYTHON_HOME}/include/python${PYTHON_VERSION}m @@ -13,13 +13,20 @@ cl.exe /LD .\distributions.c -DDLL_EXPORT -I%PYTHON_HOME%\lib\site-packages\numpy\core\include -I%PYTHON_HOME%\include %PYTHON_HOME%\libs\python36.lib move distributions.dll ../../../examples/numba/ """ +import os import numpy as np from cffi import FFI from core_prng import Xoroshiro128 import numba as nb ffi = FFI() -lib = ffi.dlopen('./libdistributions.so') +if os.path.exists('./distributions.dll'): + lib = ffi.dlopen('./distributions.dll') +elif os.path.exists('./libdistributions.so'): + lib = ffi.dlopen('./libdistributions.so') +else: + raise RuntimeError('Required DLL/so file was not found.') + ffi.cdef(""" double random_gauss(void *prng_state); double random_gauss_zig(void *prng_state); @@ -49,6 +56,8 @@ def normals_zig(n, prng): normalsj = nb.jit(normals, nopython=True) normals_zigj = nb.jit(normals_zig, nopython=True) +# Numba requires a memory address for void * +# Can also get address from x.ctypes.prng.value prng_address = int(ffi.cast('uintptr_t', prng)) norm = normalsj(1000, prng_address) From 244f86299cf5328b666ba5577a9fc5eeaab425ff Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 8 Mar 2018 11:54:34 +0000 Subject: [PATCH 053/279] BUG: Precent GC of CorePRNG when using CFFI/CTypes Keep a copy of cffi/ctypes interface handing over to end users to prevent main class from being garbage collected --- _randomgen/core_prng/xoroshiro128.pyx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index b56f643f73e5..0b59f6dccd12 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -54,6 +54,8 @@ cdef class Xoroshiro128: cdef xoroshiro128_state *rng_state cdef prng_t *_prng cdef public object capsule + cdef object ctypes + cdef object cffi def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoroshiro128_state)) @@ -66,6 +68,9 @@ cdef class Xoroshiro128: self._prng.next_uint32 = &xoroshiro128_uint32 self._prng.next_double = &xoroshiro128_double + self.ctypes = None + self.cffi = None + cdef const char *name = "CorePRNG" self.capsule = PyCapsule_New(self._prng, name, NULL) @@ -193,9 +198,12 @@ cdef class Xoroshiro128: @property def ctypes(self): + if self.ctypes is not None: + return self.ctypes + import ctypes - return interface(self.rng_state, + self.ctypes = interface(self.rng_state, ctypes.c_void_p(self.rng_state), ctypes.cast(&xoroshiro128_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, @@ -207,15 +215,19 @@ cdef class Xoroshiro128: ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), ctypes.c_void_p(self._prng)) + return self.ctypes @property def cffi(self): + if self.cffi is not None: + return self.cffi import cffi ffi = cffi.FFI() - return interface(self.rng_state, + self.cffi = interface(self.rng_state, ffi.cast('void *',self.rng_state), ffi.cast('uint64_t (*)(void *)',self._prng.next_uint64), ffi.cast('uint32_t (*)(void *)',self._prng.next_uint32), ffi.cast('double (*)(void *)',self._prng.next_double), ffi.cast('void *',self._prng)) + return self.cffi From d401359412986faa68d151f84306486ca369b094 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 8 Mar 2018 20:04:20 +0000 Subject: [PATCH 054/279] ENH: Port over external functions Power over external functionss from randomstate --- _randomgen/core_prng/common.pxd | 148 +- _randomgen/core_prng/common.pyx | 12 + _randomgen/core_prng/dsfmt.pyx | 15 +- _randomgen/core_prng/generator.pyx | 4058 ++++++++++++++++- _randomgen/core_prng/mt19937.pyx | 1 + _randomgen/core_prng/philox.pyx | 1 + .../src/aligned_malloc/aligned_malloc.c | 9 + .../src/aligned_malloc/aligned_malloc.h | 49 + .../src/distributions/distributions.c | 993 ++++ .../src/distributions/distributions.h | 88 +- _randomgen/core_prng/src/dsfmt/dSFMT.h | 22 +- _randomgen/core_prng/threefry.pyx | 1 + _randomgen/core_prng/xoroshiro128.pyx | 1 + _randomgen/core_prng/xorshift1024.pyx | 1 + _randomgen/setup.py | 3 +- 15 files changed, 5255 insertions(+), 147 deletions(-) create mode 100644 _randomgen/core_prng/src/aligned_malloc/aligned_malloc.c create mode 100644 _randomgen/core_prng/src/aligned_malloc/aligned_malloc.h diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index 3387894e81e8..ec4029e59db9 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -1,4 +1,6 @@ -from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t +from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, + int8_t, int16_t, int32_t, int64_t, intptr_t) +from libc.math cimport sqrt from cpython cimport PyInt_AsLong, PyFloat_AsDouble import numpy as np @@ -19,34 +21,41 @@ cdef enum ConstraintType: ctypedef ConstraintType constraint_type +cdef extern from "src/aligned_malloc/aligned_malloc.h": + cdef void *PyArray_realloc_aligned(void *p, size_t n); + cdef void *PyArray_malloc_aligned(size_t n); + cdef void *PyArray_calloc_aligned(size_t n, size_t s); + cdef void PyArray_free_aligned(void *p); + cdef extern from "src/distributions/distributions.h": struct s_binomial_t: - int has_binomial; - double psave; - long nsave; - double r; - double q; - double fm; - long m; - double p1; - double xm; - double xl; - double xr; - double c; - double laml; - double lamr; - double p2; - double p3; - double p4; + int has_binomial + double psave + long nsave + double r + double q + double fm + long m + double p1 + double xm + double xl + double xr + double c + double laml + double lamr + double p2 + double p3 + double p4 ctypedef s_binomial_t binomial_t struct prng: void *state - uint64_t (*next_uint64)(void *st) - uint32_t (*next_uint32)(void *st) - double (*next_double)(void *st) + uint64_t (*next_uint64)(void *st) nogil + uint32_t (*next_uint32)(void *st) nogil + double (*next_double)(void *st) nogil + uint64_t (*next_raw)(void *st) nogil int has_gauss double gauss int has_gauss_f @@ -71,6 +80,81 @@ cdef extern from "src/distributions/distributions.h": float random_standard_gamma_f(prng_t *prng_state, float shape) nogil float random_standard_gamma_zig_f(prng_t *prng_state, float shape) nogil + uint32_t random_uint32(prng_t *prng_state) nogil + int64_t random_positive_int64(prng_t *prng_state) nogil + int32_t random_positive_int32(prng_t *prng_state) nogil + long random_positive_int(prng_t *prng_state) nogil + unsigned long random_uint(prng_t *prng_state) nogil + + double random_normal(prng_t *prng_state, double loc, double scale) nogil + double random_normal_zig(prng_t *prng_state, double loc, double scale) nogil + + double random_gamma(prng_t *prng_state, double shape, double scale) nogil + float random_gamma_float(prng_t *prng_state, float shape, float scale) nogil + + double random_exponential(prng_t *prng_state, double scale) nogil + double random_uniform(prng_t *prng_state, double lower, double range) nogil + double random_beta(prng_t *prng_state, double a, double b) nogil + double random_chisquare(prng_t *prng_state, double df) nogil + double random_f(prng_t *prng_state, double dfnum, double dfden) nogil + double random_standard_cauchy(prng_t *prng_state) nogil + double random_pareto(prng_t *prng_state, double a) nogil + double random_weibull(prng_t *prng_state, double a) nogil + double random_power(prng_t *prng_state, double a) nogil + double random_laplace(prng_t *prng_state, double loc, double scale) nogil + double random_gumbel(prng_t *prng_state, double loc, double scale) nogil + double random_logistic(prng_t *prng_state, double loc, double scale) nogil + double random_lognormal(prng_t *prng_state, double mean, double sigma) nogil + double random_rayleigh(prng_t *prng_state, double mode) nogil + double random_standard_t(prng_t *prng_state, double df) nogil + double random_noncentral_chisquare(prng_t *prng_state, double df, + double nonc) nogil + double random_noncentral_f(prng_t *prng_state, double dfnum, + double dfden, double nonc) nogil + double random_wald(prng_t *prng_state, double mean, double scale) nogil + double random_vonmises(prng_t *prng_state, double mu, double kappa) nogil + double random_triangular(prng_t *prng_state, double left, double mode, + double right) nogil + + long random_poisson(prng_t *prng_state, double lam) nogil + long random_negative_binomial(prng_t *prng_state, double n, double p) nogil + long random_binomial(prng_t *prng_state, double p, long n) nogil + long random_logseries(prng_t *prng_state, double p) nogil + long random_geometric_search(prng_t *prng_state, double p) nogil + long random_geometric_inversion(prng_t *prng_state, double p) nogil + long random_geometric(prng_t *prng_state, double p) nogil + long random_zipf(prng_t *prng_state, double a) nogil + long random_hypergeometric(prng_t *prng_state, long good, long bad, + long sample) nogil + unsigned long random_interval(prng_t *prng_state, unsigned long max) nogil + uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, + uint64_t rng, uint64_t mask) nogil + uint32_t random_buffered_bounded_uint32(prng_t *prng_state, uint32_t off, + uint32_t rng, uint32_t mask, + int *bcnt, uint32_t *buf) nogil + + uint16_t random_buffered_bounded_uint16(prng_t *prng_state, uint16_t off, + uint16_t rng, uint16_t mask, + int *bcnt, uint32_t *buf) nogil + uint8_t random_buffered_bounded_uint8(prng_t *prng_state, uint8_t off, + uint8_t rng, uint8_t mask, + int *bcnt, uint32_t *buf) nogil + np.npy_bool random_buffered_bounded_bool(prng_t *prng_state, np.npy_bool off, + np.npy_bool rng, np.npy_bool mask, + int *bcnt, uint32_t *buf) nogil + void random_bounded_uint64_fill(prng_t *prng_state, uint64_t off, + uint64_t rng, np.npy_intp cnt, + uint64_t *out) nogil + void random_bounded_uint32_fill(prng_t *prng_state, uint32_t off, + uint32_t rng, np.npy_intp cnt, + uint32_t *out) nogil + void random_bounded_uint16_fill(prng_t *prng_state, uint16_t off, + uint16_t rng, np.npy_intp cnt, + uint16_t *out) nogil + void random_bounded_uint8_fill(prng_t *prng_state, uint8_t off, + uint8_t rng, np.npy_intp cnt, uint8_t *out) nogil + void random_bounded_bool_fill(prng_t *prng_state, np.npy_bool off, + np.npy_bool rng, np.npy_intp cnt, np.npy_bool *out) nogil ctypedef double (*random_double_0)(prng_t *state) nogil ctypedef double (*random_double_1)(prng_t *state, double a) nogil @@ -93,6 +177,7 @@ ctypedef uint32_t (*random_uint_1_i_32)(prng_t *state, uint32_t a) nogil ctypedef int32_t (*random_int_2_i_32)(prng_t *state, int32_t a, int32_t b) nogil ctypedef int64_t (*random_int_2_i)(prng_t *state, int64_t a, int64_t b) nogil +cdef double kahan_sum(double *darr, np.npy_intp n) cdef inline double uint64_to_double(uint64_t rnd) nogil: return (rnd >> 11) * (1.0 / 9007199254740992.0) @@ -120,3 +205,24 @@ cdef object disc(void *func, prng_t *state, object size, object lock, cdef object cont_f(void *func, prng_t *state, object size, object lock, object a, object a_name, constraint_type a_constraint, object out) + +cdef object cont_broadcast_3(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint, + np.ndarray b_arr, object b_name, constraint_type b_constraint, + np.ndarray c_arr, object c_name, constraint_type c_constraint) + +cdef object discrete_broadcast_iii(void *func, prng_t *state, object size, object lock, + np.ndarray a_arr, object a_name, constraint_type a_constraint, + np.ndarray b_arr, object b_name, constraint_type b_constraint, + np.ndarray c_arr, object c_name, constraint_type c_constraint) + +cdef inline void compute_complex(double *rv_r, double *rv_i, double loc_r, + double loc_i, double var_r, double var_i, double rho) nogil: + cdef double scale_c, scale_i, scale_r + + scale_c = sqrt(1 - rho * rho) + scale_r = sqrt(var_r) + scale_i = sqrt(var_i) + + rv_i[0] = loc_i + scale_i * (rho * rv_r[0] + scale_c * rv_i[0]) + rv_r[0] = loc_r + scale_r * rv_r[0] diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index 811824985663..b7a6f5327cfd 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -5,6 +5,18 @@ from common cimport * np.import_array() +cdef double kahan_sum(double *darr, np.npy_intp n): + cdef double c, y, t, sum + cdef np.npy_intp i + sum = darr[0] + c = 0.0 + for i in range(1, n): + y = darr[i] - c + t = sum + y + c = (t-sum) - y + sum = t + return sum + cdef np.ndarray int_to_array(object value, object name, object bits): len = bits // 64 value = np.asarray(value) diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index 0341d9a43c8d..5acc2960f86c 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -44,7 +44,8 @@ cdef extern from "src/dsfmt/dSFMT.h": double dsfmt_next_double(dsfmt_state *state) nogil uint64_t dsfmt_next64(dsfmt_state *state) nogil - uint64_t dsfmt_next32(dsfmt_state *state) nogil + uint32_t dsfmt_next32(dsfmt_state *state) nogil + uint64_t dsfmt_next_raw(dsfmt_state *state) nogil void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) @@ -59,6 +60,9 @@ cdef uint32_t dsfmt_uint32(void *st) nogil: cdef double dsfmt_double(void* st) nogil: return dsfmt_next_double(st) +cdef uint64_t dsfmt_raw(void *st) nogil: + return dsfmt_next_raw(st) + cdef class DSFMT: """ Prototype Core PRNG using dsfmt @@ -79,8 +83,8 @@ cdef class DSFMT: def __init__(self, seed=None): self.rng_state = malloc(sizeof(dsfmt_state)) - self.rng_state.state = malloc(sizeof(dsfmt_t)) - self.rng_state.buffered_uniforms = malloc(DSFMT_N64 * sizeof(double)) + self.rng_state.state = PyArray_malloc_aligned(sizeof(dsfmt_t)) + self.rng_state.buffered_uniforms = PyArray_malloc_aligned(DSFMT_N64 * sizeof(double)) self.rng_state.buffer_loc = DSFMT_N64 self._prng = malloc(sizeof(prng_t)) self._prng.binomial = malloc(sizeof(binomial_t)) @@ -89,6 +93,7 @@ cdef class DSFMT: self._prng.next_uint64 = &dsfmt_uint64 self._prng.next_uint32 = &dsfmt_uint32 self._prng.next_double = &dsfmt_double + self._prng.next_raw = &dsfmt_raw cdef const char *name = "CorePRNG" self.capsule = PyCapsule_New(self._prng, name, NULL) @@ -105,8 +110,8 @@ cdef class DSFMT: self.state) def __dealloc__(self): - free(self.rng_state.state) - free(self.rng_state.buffered_uniforms) + PyArray_free_aligned(self.rng_state.state) + PyArray_free_aligned(self.rng_state.buffered_uniforms) free(self.rng_state) free(self._prng.binomial) free(self._prng) diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 69205245be6f..80a4d0a60018 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -1,7 +1,15 @@ +#!python +#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True +import operator +import warnings + import numpy as np cimport numpy as np +cimport cython from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer +from cpython cimport Py_INCREF, PyComplex_RealAsDouble, PyComplex_ImagAsDouble, PyComplex_FromDoubles from common cimport * +from libc cimport string from libc.stdlib cimport malloc, free cimport numpy as np @@ -84,6 +92,122 @@ cdef class RandomGenerator: self._prng.gauss_f = value['gauss_f'] self.__core_prng.state = value + def random_uintegers(self, size=None, int bits=64): + """ + random_uintegers(size=None, bits=64) + + Return random unsigned integers + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + bits : int {32, 64} + Size of the unsigned integer to return, either 32 bit or 64 bit. + + Returns + ------- + out : uint or ndarray + Drawn samples. + + Notes + ----- + This method effectively exposes access to the raw underlying + pseudo-random number generator since these all produce unsigned + integers. In practice these are most useful for generating other + random numbers. + + These should not be used to produce bounded random numbers by + simple truncation. + """ + cdef np.npy_intp i, n + cdef np.ndarray array + cdef uint32_t* data32 + cdef uint64_t* data64 + if bits == 64: + if size is None: + with self.lock: + return self._prng.next_uint64(self._prng.state) + array = np.empty(size, np.uint64) + n = np.PyArray_SIZE(array) + data64 = np.PyArray_DATA(array) + with self.lock, nogil: + for i in range(n): + data64[i] = self._prng.next_uint64(self._prng.state) + elif bits == 32: + if size is None: + with self.lock: + return self._prng.next_uint32(self._prng.state) + array = np.empty(size, np.uint32) + n = np.PyArray_SIZE(array) + data32 = np.PyArray_DATA(array) + with self.lock, nogil: + for i in range(n): + data32[i] = self._prng.next_uint32(self._prng.state) + else: + raise ValueError('Unknown value of bits. Must be either 32 or 64.') + + return array + + def random_raw(self, size=None, output=True): + """ + random_raw(self, size=None) + + Return randoms as generated by the underlying PRNG + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. + + Returns + ------- + out : uint or ndarray + Drawn samples. + + Notes + ----- + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. + """ + cdef np.ndarray randoms + cdef uint64_t *randoms_data + cdef Py_ssize_t i, n + + if not output: + if size is None: + with self.lock: + self._prng.next_raw(self._prng.state) + return None + n = np.asarray(size).sum() + with self.lock, nogil: + for i in range(n): + self._prng.next_raw(self._prng.state) + return None + + if size is None: + with self.lock: + return self._prng.next_raw(self._prng.state) + + randoms = np.empty(size, np.uint64) + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + with self.lock, nogil: + for i in range(n): + randoms_data[i] = self._prng.next_raw(self._prng.state) + return randoms + def random_integer(self, bits=64): #print("In random_integer") if bits == 64: @@ -159,6 +283,101 @@ cdef class RandomGenerator: else: raise TypeError('Unsupported dtype "%s" for random_sample' % key) + def beta(self, a, b, size=None): + """ + beta(a, b, size=None) + + Draw samples from a Beta distribution. + + The Beta distribution is a special case of the Dirichlet distribution, + and is related to the Gamma distribution. It has the probability + distribution function + + .. math:: f(x; a,b) = \\frac{1}{B(\\alpha, \\beta)} x^{\\alpha - 1} + (1 - x)^{\\beta - 1}, + + where the normalisation, B, is the beta function, + + .. math:: B(\\alpha, \\beta) = \\int_0^1 t^{\\alpha - 1} + (1 - t)^{\\beta - 1} dt. + + It is often seen in Bayesian inference and order statistics. + + Parameters + ---------- + a : float or array_like of floats + Alpha, non-negative. + b : float or array_like of floats + Beta, non-negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` and ``b`` are both scalars. + Otherwise, ``np.broadcast(a, b).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized beta distribution. + + """ + return cont(&random_beta, self._prng, size, self.lock, 2, + a, 'a', CONS_POSITIVE, + b, 'b', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + + def exponential(self, scale=1.0, size=None): + """ + exponential(scale=1.0, size=None) + + Draw samples from an exponential distribution. + + Its probability density function is + + .. math:: f(x; \\frac{1}{\\beta}) = \\frac{1}{\\beta} \\exp(-\\frac{x}{\\beta}), + + for ``x > 0`` and 0 elsewhere. :math:`\\beta` is the scale parameter, + which is the inverse of the rate parameter :math:`\\lambda = 1/\\beta`. + The rate parameter is an alternative, widely used parameterization + of the exponential distribution [3]_. + + The exponential distribution is a continuous analogue of the + geometric distribution. It describes many common situations, such as + the size of raindrops measured over many rainstorms [1]_, or the time + between page requests to Wikipedia [2]_. + + Parameters + ---------- + scale : float or array_like of floats + The scale parameter, :math:`\\beta = 1/\\lambda`. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``scale`` is a scalar. Otherwise, + ``np.array(scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized exponential distribution. + + References + ---------- + .. [1] Peyton Z. Peebles Jr., "Probability, Random Variables and + Random Signal Principles", 4th ed, 2001, p. 57. + .. [2] Wikipedia, "Poisson process", + http://en.wikipedia.org/wiki/Poisson_process + .. [3] Wikipedia, "Exponential distribution", + http://en.wikipedia.org/wiki/Exponential_distribution + + """ + return cont(&random_exponential, self._prng, size, self.lock, 1, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) + def standard_exponential(self, size=None, dtype=np.float64, method=u'zig', out=None): """ standard_exponential(size=None, dtype='d', method='zig', out=None) @@ -212,12 +431,14 @@ cdef class RandomGenerator: raise TypeError('Unsupported dtype "%s" for standard_exponential' % key) - # Complicated, continuous distributions: - def standard_normal(self, size=None, dtype=np.float64, method=u'zig', out=None): + def tomaxint(self, size=None): """ - standard_normal(size=None, dtype='d', method='zig', out=None) + tomaxint(size=None) - Draw samples from a standard Normal distribution (mean=0, stdev=1). + Random integers between 0 and ``sys.maxint``, inclusive. + + Return a sample of uniformly distributed random integers in the interval + [0, ``sys.maxint``]. Parameters ---------- @@ -225,152 +446,3765 @@ cdef class RandomGenerator: Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - dtype : {str, dtype}, optional - Desired dtype of the result, either 'd' (or 'float64') or 'f' - (or 'float32'). All dtypes are determined by their name. The - default value is 'd'. - method : str, optional - Either 'bm' or 'zig'. 'bm' uses the Box-Muller transformations - method. 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. - out : ndarray, optional - Alternative output array in which to place the result. If size is not None, - it must have the same shape as the provided size and must match the type of - the output values. Returns ------- - out : float or ndarray - Drawn samples. + out : ndarray + Drawn samples, with shape `size`. + + See Also + -------- + randint : Uniform sampling over a given half-open interval of integers. + random_integers : Uniform sampling over a given closed interval of + integers. Examples -------- - >>> s = np.random.standard_normal(8000) - >>> s - array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random - -0.38672696, -0.4685006 ]) #random - >>> s.shape - (8000,) - >>> s = np.random.standard_normal(size=(3, 4, 2)) - >>> s.shape - (3, 4, 2) + >>> RS = np.random.mtrand.RandomState() # need a RandomState object + >>> RS.tomaxint((2,2,2)) + array([[[1170048599, 1600360186], + [ 739731006, 1947757578]], + [[1871712945, 752307660], + [1601631370, 1479324245]]]) + >>> import sys + >>> sys.maxint + 2147483647 + >>> RS.tomaxint((2,2,2)) < sys.maxint + array([[[ True, True], + [ True, True]], + [[ True, True], + [ True, True]]], dtype=bool) """ - key = np.dtype(dtype).name - if key == 'float64': - if method == u'zig': - return double_fill(&random_gauss_zig, self._prng, size, self.lock, out) - else: - return double_fill(&random_gauss, self._prng, size, self.lock, out) - elif key == 'float32': - if method == u'zig': - return float_fill(&random_gauss_zig_f, self._prng, size, self.lock, out) - else: - return float_fill(&random_gauss_f, self._prng, size, self.lock, out) - else: - raise TypeError('Unsupported dtype "%s" for standard_normal' % key) + cdef np.npy_intp n + cdef np.ndarray randoms + cdef long *randoms_data + if size is None: + with self.lock: + return random_positive_int(self._prng) - def standard_gamma(self, shape, size=None, dtype=np.float64, method='zig', - out=None): + randoms = np.empty(size, dtype=np.int) + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + for i in range(n): + with self.lock, nogil: + randoms_data[i] = random_positive_int(self._prng) + return randoms + + def randint(self, low, high=None, size=None, dtype=int): """ - standard_gamma(shape, size=None, dtype='d', method='inv', out=None) + randint(low, high=None, size=None, dtype='l') - Draw samples from a standard Gamma distribution. + Return random integers from `low` (inclusive) to `high` (exclusive). - Samples are drawn from a Gamma distribution with specified parameters, - shape (sometimes designated "k") and scale=1. + Return random integers from the "discrete uniform" distribution of + the specified dtype in the "half-open" interval [`low`, `high`). If + `high` is None (the default), then results are from [0, `low`). Parameters ---------- - shape : float or array_like of floats - Parameter, should be > 0. + low : int or array-like of ints + Lowest (signed) integers to be drawn from the distribution (unless + ``high=None``, in which case this parameter is one above the + *highest* such integer). + high : int or array-like of ints, optional + If provided, one above the largest (signed) integer to be drawn + from the distribution (see above for behavior if ``high=None``). + If array-like, must contain integer values size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``shape`` is a scalar. Otherwise, - ``np.array(shape).size`` samples are drawn. + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. dtype : {str, dtype}, optional - Desired dtype of the result, either 'd' (or 'float64') or 'f' - (or 'float32'). All dtypes are determined by their name. The - default value is 'd'. - method : str, optional - Either 'inv' or 'zig'. 'inv' uses the default inverse CDF method. - 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. - out : ndarray, optional - Alternative output array in which to place the result. If size is - not None, it must have the same shape as the provided size and - must match the type of the output values. + Desired dtype of the result. All dtypes are determined by their + name, i.e., 'int64', 'int', etc, so byteorder is not available + and a specific precision may have different C types depending + on the platform. The default value is 'np.int'. + + .. versionadded:: 1.11.0 Returns ------- - out : ndarray or scalar - Drawn samples from the parameterized standard gamma distribution. + out : int or ndarray of ints + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. See Also -------- - scipy.stats.gamma : probability density function, distribution or - cumulative density function, etc. + random.random_integers : similar to `randint`, only for the closed + interval [`low`, `high`], and 1 is the lowest value if `high` is + omitted. In particular, this other one is the one to use to generate + uniformly distributed discrete non-integers. - Notes - ----- - The probability density for the Gamma distribution is + Examples + -------- + >>> np.random.randint(2, size=10) + array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) + >>> np.random.randint(1, size=10) + array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) - .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + Generate a 2 x 4 array of ints between 0 and 4, inclusive: - where :math:`k` is the shape and :math:`\\theta` the scale, - and :math:`\\Gamma` is the Gamma function. + >>> np.random.randint(5, size=(2, 4)) + array([[4, 0, 2, 1], + [3, 2, 2, 0]]) - The Gamma distribution is often used to model the times to failure of - electronic components, and arises naturally in processes for which the - waiting times between Poisson distributed events are relevant. + Generate a 1 x 3 array with 3 different upper bounds - References + >>> np.random.randint(1, [3, 5, 10]) + array([2, 2, 9]) + + Generate a 1 by 3 array with 3 different lower bounds + + >>> np.random.randint([1, 5, 7], 10) + array([9, 8, 7]) + + Generate a 2 by 4 array using broadcasting with dtype of uint8 + + >>> np.random.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) + array([[ 8, 6, 9, 7], + [ 1, 16, 9, 12]], dtype=uint8) + """ + raise NotImplementedError('To be completed') + + def bytes(self, np.npy_intp length): + """ + bytes(length) + + Return random bytes. + + Parameters ---------- - .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A - Wolfram Web Resource. - http://mathworld.wolfram.com/GammaDistribution.html - .. [2] Wikipedia, "Gamma distribution", - http://en.wikipedia.org/wiki/Gamma_distribution + length : int + Number of random bytes. + + Returns + ------- + out : str + String of length `length`. Examples -------- - Draw samples from the distribution: + >>> np.random.bytes(10) + ' eh\\x85\\x022SZ\\xbf\\xa4' #random - >>> shape, scale = 2., 1. # mean and width - >>> s = np.random.standard_gamma(shape, 1000000) + """ + cdef Py_ssize_t n_uint32 = ((length - 1) // 4 + 1) + return self.randint(0, 4294967296, size=n_uint32, dtype=np.uint32).tobytes()[:length] - Display the histogram of the samples, along with - the probability density function: - >>> import matplotlib.pyplot as plt - >>> import scipy.special as sps - >>> count, bins, ignored = plt.hist(s, 50, normed=True) - >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ - ... (sps.gamma(shape) * scale**shape)) - >>> plt.plot(bins, y, linewidth=2, color='r') - >>> plt.show() + @cython.wraparound(True) + def choice(self, a, size=None, replace=True, p=None): """ - cdef void *func - if method != u'zig' and method != u'inv': - raise ValueError("method must be either 'inv' or 'zig'") - key = np.dtype(dtype).name - if key == 'float64': - if method == 'inv': - func = &random_standard_gamma + choice(a, size=None, replace=True, p=None) + + Generates a random sample from a given 1-D array + + .. versionadded:: 1.7.0 + + Parameters + ---------- + a : 1-D array-like or int + If an ndarray, a random sample is generated from its elements. + If an int, the random sample is generated as if a were np.arange(a) + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + replace : boolean, optional + Whether the sample is with or without replacement + p : 1-D array-like, optional + The probabilities associated with each entry in a. + If not given the sample assumes a uniform distribution over all + entries in a. + + Returns + ------- + samples : single item or ndarray + The generated random samples + + Raises + ------ + ValueError + If a is an int and less than zero, if a or p are not 1-dimensional, + if a is an array-like of size 0, if p is not a vector of + probabilities, if a and p have different lengths, or if + replace=False and the sample size is greater than the population + size + + See Also + -------- + randint, shuffle, permutation + + Examples + -------- + Generate a uniform random sample from np.arange(5) of size 3: + + >>> np.random.choice(5, 3) + array([0, 3, 4]) + >>> #This is equivalent to np.random.randint(0,5,3) + + Generate a non-uniform random sample from np.arange(5) of size 3: + + >>> np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) + array([3, 3, 0]) + + Generate a uniform random sample from np.arange(5) of size 3 without + replacement: + + >>> np.random.choice(5, 3, replace=False) + array([3,1,0]) + >>> #This is equivalent to np.random.permutation(np.arange(5))[:3] + + Generate a non-uniform random sample from np.arange(5) of size + 3 without replacement: + + >>> np.random.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) + array([2, 3, 0]) + + Any of the above can be repeated with an arbitrary array-like + instead of just integers. For instance: + + >>> aa_milne_arr = ['pooh', 'rabbit', 'piglet', 'Christopher'] + >>> np.random.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) + array(['pooh', 'pooh', 'pooh', 'Christopher', 'piglet'], + dtype='|S11') + + """ + + # Format and Verify input + a = np.array(a, copy=False) + if a.ndim == 0: + try: + # __index__ must return an integer by python rules. + pop_size = operator.index(a.item()) + except TypeError: + raise ValueError("a must be 1-dimensional or an integer") + if pop_size <= 0: + raise ValueError("a must be greater than 0") + elif a.ndim != 1: + raise ValueError("a must be 1-dimensional") + else: + pop_size = a.shape[0] + if pop_size is 0: + raise ValueError("a must be non-empty") + + if p is not None: + d = len(p) + + atol = np.sqrt(np.finfo(np.float64).eps) + if isinstance(p, np.ndarray): + if np.issubdtype(p.dtype, np.floating): + atol = max(atol, np.sqrt(np.finfo(p.dtype).eps)) + + p = np.PyArray_FROM_OTF(p, np.NPY_DOUBLE, np.NPY_ALIGNED) + pix = np.PyArray_DATA(p) + + if p.ndim != 1: + raise ValueError("p must be 1-dimensional") + if p.size != pop_size: + raise ValueError("a and p must have same size") + if np.logical_or.reduce(p < 0): + raise ValueError("probabilities are not non-negative") + if abs(kahan_sum(pix, d) - 1.) > atol: + raise ValueError("probabilities do not sum to 1") + + shape = size + if shape is not None: + size = np.prod(shape, dtype=np.intp) + else: + size = 1 + + # Actual sampling + if replace: + if p is not None: + cdf = p.cumsum() + cdf /= cdf[-1] + uniform_samples = self.random_sample(shape) + idx = cdf.searchsorted(uniform_samples, side='right') + idx = np.array(idx, copy=False) # searchsorted returns a scalar else: - func = &random_standard_gamma_zig - return cont(func, self._prng, size, self.lock, 1, - shape, 'shape', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, - out) - if key == 'float32': - if method == 'inv': - func = &random_standard_gamma_f + idx = self.randint(0, pop_size, size=shape) + else: + if size > pop_size: + raise ValueError("Cannot take a larger sample than " + "population when 'replace=False'") + + if p is not None: + if np.count_nonzero(p > 0) < size: + raise ValueError("Fewer non-zero entries in p than size") + n_uniq = 0 + p = p.copy() + found = np.zeros(shape, dtype=np.int) + flat_found = found.ravel() + while n_uniq < size: + x = self.rand(size - n_uniq) + if n_uniq > 0: + p[flat_found[0:n_uniq]] = 0 + cdf = np.cumsum(p) + cdf /= cdf[-1] + new = cdf.searchsorted(x, side='right') + _, unique_indices = np.unique(new, return_index=True) + unique_indices.sort() + new = new.take(unique_indices) + flat_found[n_uniq:n_uniq + new.size] = new + n_uniq += new.size + idx = found else: - func = &random_standard_gamma_zig_f - return cont_f(func, self._prng, size, self.lock, - shape, 'shape', CONS_NON_NEGATIVE, - out) + idx = self.permutation(pop_size)[:size] + if shape is not None: + idx.shape = shape + + if shape is None and isinstance(idx, np.ndarray): + # In most cases a scalar will have been made an array + idx = idx.item(0) + + #Use samples as indices for a if a is array-like + if a.ndim == 0: + return idx + + if shape is not None and idx.ndim == 0: + # If size == () then the user requested a 0-d array as opposed to + # a scalar object when size is None. However a[idx] is always a + # scalar and not an array. So this makes sure the result is an + # array, taking into account that np.array(item) may not work + # for object arrays. + res = np.empty((), dtype=a.dtype) + res[()] = a[idx] + return res + + return a[idx] + + + def uniform(self, low=0.0, high=1.0, size=None): + """ + uniform(low=0.0, high=1.0, size=None) + + Draw samples from a uniform distribution. + + Samples are uniformly distributed over the half-open interval + ``[low, high)`` (includes low, but excludes high). In other words, + any value within the given interval is equally likely to be drawn + by `uniform`. + + Parameters + ---------- + low : float or array_like of floats, optional + Lower boundary of the output interval. All values generated will be + greater than or equal to low. The default value is 0. + high : float or array_like of floats + Upper boundary of the output interval. All values generated will be + less than high. The default value is 1.0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``low`` and ``high`` are both scalars. + Otherwise, ``np.broadcast(low, high).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized uniform distribution. + + See Also + -------- + randint : Discrete uniform distribution, yielding integers. + random_integers : Discrete uniform distribution over the closed + interval ``[low, high]``. + random_sample : Floats uniformly distributed over ``[0, 1)``. + random : Alias for `random_sample`. + rand : Convenience function that accepts dimensions as input, e.g., + ``rand(2,2)`` would generate a 2-by-2 array of floats, + uniformly distributed over ``[0, 1)``. + + Notes + ----- + The probability density function of the uniform distribution is + + .. math:: p(x) = \\frac{1}{b - a} + + anywhere within the interval ``[a, b)``, and zero elsewhere. + + When ``high`` == ``low``, values of ``low`` will be returned. + If ``high`` < ``low``, the results are officially undefined + and may eventually raise an error, i.e. do not rely on this + function to behave when passed arguments satisfying that + inequality condition. + + Examples + -------- + Draw samples from the distribution: + + >>> s = np.random.uniform(-1,0,1000) + + All values are within the given interval: + + >>> np.all(s >= -1) + True + >>> np.all(s < 0) + True + + Display the histogram of the samples, along with the + probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 15, normed=True) + >>> plt.plot(bins, np.ones_like(bins), linewidth=2, color='r') + >>> plt.show() + """ + cdef bint is_scalar = True + cdef np.ndarray alow, ahigh, arange + cdef double _low, _high, range + cdef object temp + + alow = np.PyArray_FROM_OTF(low, np.NPY_DOUBLE, np.NPY_ALIGNED) + ahigh = np.PyArray_FROM_OTF(high, np.NPY_DOUBLE, np.NPY_ALIGNED) + + if np.PyArray_NDIM(alow) == np.PyArray_NDIM(ahigh) == 0: + _low = PyFloat_AsDouble(low) + _high = PyFloat_AsDouble(high) + range = _high - _low + if not np.isfinite(range): + raise OverflowError('Range exceeds valid bounds') + + return cont(&random_uniform, self._prng, size, self.lock, 2, + _low, '', CONS_NONE, + range, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) + + temp = np.subtract(ahigh, alow) + Py_INCREF(temp) # needed to get around Pyrex's automatic reference-counting + # rules because EnsureArray steals a reference + arange = np.PyArray_EnsureArray(temp) + if not np.all(np.isfinite(arange)): + raise OverflowError('Range exceeds valid bounds') + return cont(&random_uniform, self._prng, size, self.lock, 2, + alow, '', CONS_NONE, + arange, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) + + def rand(self, *args, dtype=np.float64): + """ + rand(d0, d1, ..., dn, dtype='d') + + Random values in a given shape. + + Create an array of the given shape and populate it with + random samples from a uniform distribution + over ``[0, 1)``. + + Parameters + ---------- + d0, d1, ..., dn : int, optional + The dimensions of the returned array, should all be positive. + If no argument is given a single Python float is returned. + dtype : {str, dtype}, optional + Desired dtype of the result, either 'd' (or 'float64') or 'f' + (or 'float32'). All dtypes are determined by their name. The + default value is 'd'. + + Returns + ------- + out : ndarray, shape ``(d0, d1, ..., dn)`` + Random values. + + See Also + -------- + random + + Notes + ----- + This is a convenience function. If you want an interface that takes + a shape-tuple as the first argument, refer to np.random.random_sample. + + ``dtype`` can only be changed using a keyword argument. + + Examples + -------- + >>> np.random.rand(3,2) + array([[ 0.14022471, 0.96360618], #random + [ 0.37601032, 0.25528411], #random + [ 0.49313049, 0.94909878]]) #random + """ + if len(args) == 0: + return self.random_sample(dtype=dtype) else: - raise TypeError('Unsupported dtype "%s" for standard_gamma' % key) + return self.random_sample(size=args, dtype=dtype) + + def randn(self, *args, method=u'zig', dtype=np.float64): + """ + randn(d0, d1, ..., dn, method='zig', dtype='d') + + Return a sample (or samples) from the "standard normal" distribution. + + If positive, int_like or int-convertible arguments are provided, + `randn` generates an array of shape ``(d0, d1, ..., dn)``, filled + with random floats sampled from a univariate "normal" (Gaussian) + distribution of mean 0 and variance 1 (if any of the :math:`d_i` are + floats, they are first converted to integers by truncation). A single + float randomly sampled from the distribution is returned if no + argument is provided. + + This is a convenience function. If you want an interface that takes a + tuple as the first argument, use `numpy.random.standard_normal` instead. + + Parameters + ---------- + d0, d1, ..., dn : int, optional + The dimensions of the returned array, should be all positive. + If no argument is given a single Python float is returned. + method : str, optional + Either 'bm' or 'zig'. 'bm' uses the default Box-Muller + transformations method. 'zig' uses the much faster Ziggurat + method of Marsaglia and Tsang. + dtype : {str, dtype}, optional + Desired dtype of the result, either 'd' (or 'float64') or 'f' + (or 'float32'). All dtypes are determined by their name. The + default value is 'd'. + + Returns + ------- + Z : ndarray or float + A ``(d0, d1, ..., dn)``-shaped array of floating-point samples from + the standard normal distribution, or a single such float if + no parameters were supplied. + + See Also + -------- + random.standard_normal : Similar, but takes a tuple as its argument. + + Notes + ----- + For random samples from :math:`N(\\mu, \\sigma^2)`, use: + + ``sigma * np.random.randn(...) + mu`` + + Examples + -------- + >>> np.random.randn() + 2.1923875335537315 #random + + Two-by-four array of samples from N(3, 6.25): + + >>> 2.5 * np.random.randn(2, 4) + 3 + array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random + [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random + + """ + if len(args) == 0: + return self.standard_normal(method=method, dtype=dtype) + else: + return self.standard_normal(size=args, method=method, dtype=dtype) + + def random_integers(self, low, high=None, size=None): + """ + random_integers(low, high=None, size=None) + + Random integers of type np.int between `low` and `high`, inclusive. + + Return random integers of type np.int from the "discrete uniform" + distribution in the closed interval [`low`, `high`]. If `high` is + None (the default), then results are from [1, `low`]. The np.int + type translates to the C long type used by Python 2 for "short" + integers and its precision is platform dependent. + + This function has been deprecated. Use randint instead. + + .. deprecated:: 1.11.0 + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int, optional + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : int or ndarray of ints + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + See Also + -------- + random.randint : Similar to `random_integers`, only for the half-open + interval [`low`, `high`), and 0 is the lowest value if `high` is + omitted. + + Notes + ----- + To sample from N evenly spaced floating-point numbers between a and b, + use:: + + a + (b - a) * (np.random.random_integers(N) - 1) / (N - 1.) + + Examples + -------- + >>> np.random.random_integers(5) + 4 + >>> type(np.random.random_integers(5)) + + >>> np.random.random_integers(5, size=(3.,2.)) + array([[5, 4], + [3, 3], + [4, 5]]) + + Choose five random numbers from the set of five evenly-spaced + numbers between 0 and 2.5, inclusive (*i.e.*, from the set + :math:`{0, 5/8, 10/8, 15/8, 20/8}`): + + >>> 2.5 * (np.random.random_integers(5, size=(5,)) - 1) / 4. + array([ 0.625, 1.25 , 0.625, 0.625, 2.5 ]) + + Roll two six sided dice 1000 times and sum the results: + + >>> d1 = np.random.random_integers(1, 6, 1000) + >>> d2 = np.random.random_integers(1, 6, 1000) + >>> dsums = d1 + d2 + + Display results as a histogram: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(dsums, 11, normed=True) + >>> plt.show() + + """ + if high is None: + warnings.warn(("This function is deprecated. Please call " + "randint(1, {low} + 1) instead".format(low=low)), + DeprecationWarning) + high = low + low = 1 + + else: + warnings.warn(("This function is deprecated. Please call " + "randint({low}, {high} + 1) instead".format( + low=low, high=high)), DeprecationWarning) + + return self.randint(low, high + 1, size=size, dtype='l') + + + + # Complicated, continuous distributions: + def standard_normal(self, size=None, dtype=np.float64, method=u'zig', out=None): + """ + standard_normal(size=None, dtype='d', method='zig', out=None) + + Draw samples from a standard Normal distribution (mean=0, stdev=1). + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + dtype : {str, dtype}, optional + Desired dtype of the result, either 'd' (or 'float64') or 'f' + (or 'float32'). All dtypes are determined by their name. The + default value is 'd'. + method : str, optional + Either 'bm' or 'zig'. 'bm' uses the Box-Muller transformations + method. 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. + out : ndarray, optional + Alternative output array in which to place the result. If size is not None, + it must have the same shape as the provided size and must match the type of + the output values. + + Returns + ------- + out : float or ndarray + Drawn samples. + + Examples + -------- + >>> s = np.random.standard_normal(8000) + >>> s + array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random + -0.38672696, -0.4685006 ]) #random + >>> s.shape + (8000,) + >>> s = np.random.standard_normal(size=(3, 4, 2)) + >>> s.shape + (3, 4, 2) + + """ + key = np.dtype(dtype).name + if key == 'float64': + if method == u'zig': + return double_fill(&random_gauss_zig, self._prng, size, self.lock, out) + else: + return double_fill(&random_gauss, self._prng, size, self.lock, out) + elif key == 'float32': + if method == u'zig': + return float_fill(&random_gauss_zig_f, self._prng, size, self.lock, out) + else: + return float_fill(&random_gauss_f, self._prng, size, self.lock, out) + else: + raise TypeError('Unsupported dtype "%s" for standard_normal' % key) + + + def normal(self, loc=0.0, scale=1.0, size=None, method=u'zig'): + """ + normal(loc=0.0, scale=1.0, size=None, method='zig') + + Draw random samples from a normal (Gaussian) distribution. + + The probability density function of the normal distribution, first + derived by De Moivre and 200 years later by both Gauss and Laplace + independently [2]_, is often called the bell curve because of + its characteristic shape (see the example below). + + The normal distributions occurs often in nature. For example, it + describes the commonly occurring distribution of samples influenced + by a large number of tiny, random disturbances, each with its own + unique distribution [2]_. + + Parameters + ---------- + loc : float or array_like of floats + Mean ("centre") of the distribution. + scale : float or array_like of floats + Standard deviation (spread or "width") of the distribution. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + method : str, optional + Either 'bm' or 'zig'. 'bm' uses the default Box-Muller transformations + method. 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. + + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized normal distribution. + + See Also + -------- + scipy.stats.norm : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gaussian distribution is + + .. math:: p(x) = \\frac{1}{\\sqrt{ 2 \\pi \\sigma^2 }} + e^{ - \\frac{ (x - \\mu)^2 } {2 \\sigma^2} }, + + where :math:`\\mu` is the mean and :math:`\\sigma` the standard + deviation. The square of the standard deviation, :math:`\\sigma^2`, + is called the variance. + + The function has its peak at the mean, and its "spread" increases with + the standard deviation (the function reaches 0.607 times its maximum at + :math:`x + \\sigma` and :math:`x - \\sigma` [2]_). This implies that + `numpy.random.normal` is more likely to return samples lying close to + the mean, rather than those far away. + + References + ---------- + .. [1] Wikipedia, "Normal distribution", + http://en.wikipedia.org/wiki/Normal_distribution + .. [2] P. R. Peebles Jr., "Central Limit Theorem" in "Probability, + Random Variables and Random Signal Principles", 4th ed., 2001, + pp. 51, 51, 125. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, sigma = 0, 0.1 # mean and standard deviation + >>> s = np.random.normal(mu, sigma, 1000) + + Verify the mean and the variance: + + >>> abs(mu - np.mean(s)) < 0.01 + True + + >>> abs(sigma - np.std(s, ddof=1)) < 0.01 + True + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * + ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ), + ... linewidth=2, color='r') + >>> plt.show() + + """ + if method == 'bm': + return cont(&random_normal, self._prng, size, self.lock, 2, + loc, '', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + None) + else: + return cont(&random_normal_zig, self._prng, size, self.lock, 2, + loc, '', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + None) + + def complex_normal(self, loc=0.0, gamma=1.0, relation=0.0, size=None, + method=u'zig'): + """ + complex_normal(loc=0.0, gamma=1.0, relation=0.0, size=None, method='zig') + + Draw random samples from a complex normal (Gaussian) distribution. + + Parameters + ---------- + loc : complex or array_like of complex + Mean of the distribution. + gamma : float, complex or array_like of float or complex + Variance of the distribution + relation : float, complex or array_like of float or complex + Relation between the two component normals + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc``, ``gamma`` and ``relation`` + are all scalars. Otherwise, + ``np.broadcast(loc, gamma, relation).size`` samples are drawn. + method : str, optional + Either 'bm' or 'zig'. 'bm' uses the default Box-Muller + transformations method. 'zig' uses the much faster Ziggurat + method of Marsaglia and Tsang. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized complex normal distribution. + + See Also + -------- + numpy.random.normal : random values from a real-valued normal + distribution + + Notes + ----- + **EXPERIMENTAL** Not part of official NumPy RandomState, may change until + formal release on PyPi. + + Complex normals are generated from a bivariate normal where the + variance of the real component is 0.5 Re(gamma + relation), the + variance of the imaginary component is 0.5 Re(gamma - relation), and + the covariance between the two is 0.5 Im(relation). The implied + covariance matrix must be positive semi-definite and so both variances + must be zero and the covariance must be weakly smaller than the + product of the two standard deviations. + + References + ---------- + .. [1] Wikipedia, "Complex normal distribution", + https://en.wikipedia.org/wiki/Complex_normal_distribution + .. [2] Leigh J. Halliwell, "Complex Random Variables" in "Casualty + Actuarial Society E-Forum", Fall 2015. + + Examples + -------- + Draw samples from the distribution: + + >>> s = np.random.complex_normal(size=1000) + """ + if method != u'zig' and method != u'bm': + raise ValueError("method must be either 'bm' or 'zig'") + cdef np.ndarray ogamma, orelation, oloc, randoms, v_real, v_imag, rho + cdef double *randoms_data + cdef double fgamma_r, fgamma_i, frelation_r, frelation_i, frho, fvar_r , fvar_i, \ + floc_r, floc_i, f_real, f_imag, i_r_scale, r_scale, i_scale, f_rho + cdef np.npy_intp i, j, n + cdef np.broadcast it + + oloc = np.PyArray_FROM_OTF(loc, np.NPY_COMPLEX128, np.NPY_ALIGNED) + ogamma = np.PyArray_FROM_OTF(gamma, np.NPY_COMPLEX128, np.NPY_ALIGNED) + orelation = np.PyArray_FROM_OTF(relation, np.NPY_COMPLEX128, np.NPY_ALIGNED) + + if np.PyArray_NDIM(ogamma) == np.PyArray_NDIM(orelation) == np.PyArray_NDIM(oloc) == 0: + floc_r = PyComplex_RealAsDouble(loc) + floc_i = PyComplex_ImagAsDouble(loc) + fgamma_r = PyComplex_RealAsDouble(gamma) + fgamma_i = PyComplex_ImagAsDouble(gamma) + frelation_r = PyComplex_RealAsDouble(relation) + frelation_i = 0.5 * PyComplex_ImagAsDouble(relation) + + fvar_r = 0.5 * (fgamma_r + frelation_r) + fvar_i = 0.5 * (fgamma_r - frelation_r) + if fgamma_i != 0: + raise ValueError('Im(gamma) != 0') + if fvar_i < 0: + raise ValueError('Re(gamma - relation) < 0') + if fvar_r < 0: + raise ValueError('Re(gamma + relation) < 0') + f_rho = 0.0 + if fvar_i > 0 and fvar_r > 0: + f_rho = frelation_i / sqrt(fvar_i * fvar_r) + if f_rho > 1.0 or f_rho < -1.0: + raise ValueError('Im(relation) ** 2 > Re(gamma ** 2 - relation** 2)') + + if size is None: + if method == u'zig': + f_real = random_gauss_zig(self._prng) + f_imag = random_gauss_zig(self._prng) + else: + f_real = random_gauss(self._prng) + f_imag = random_gauss(self._prng) + + compute_complex(&f_real, &f_imag, floc_r, floc_i, fvar_r, fvar_i, f_rho) + return PyComplex_FromDoubles(f_real, f_imag) + + randoms = np.empty(size, np.complex128) + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + i_r_scale = sqrt(1 - f_rho * f_rho) + r_scale = sqrt(fvar_r) + i_scale = sqrt(fvar_i) + j = 0 + with self.lock, nogil: + if method == u'zig': + for i in range(n): + f_real = random_gauss_zig(self._prng) + f_imag = random_gauss_zig(self._prng) + randoms_data[j+1] = floc_i + i_scale * (f_rho * f_real + i_r_scale * f_imag) + randoms_data[j] = floc_r + r_scale * f_real + j += 2 + else: + for i in range(n): + f_real = random_gauss(self._prng) + f_imag = random_gauss(self._prng) + randoms_data[j+1] = floc_i + i_scale * (f_rho * f_real + i_r_scale * f_imag) + randoms_data[j] = floc_r + r_scale * f_real + j += 2 + + return randoms + + gpc = ogamma + orelation + gmc = ogamma - orelation + v_real = (0.5 * np.real(gpc)) + if np.any(np.less(v_real, 0)): + raise ValueError('Re(gamma + relation) < 0') + v_imag = (0.5 * np.real(gmc)) + if np.any(np.less(v_imag, 0)): + raise ValueError('Re(gamma - relation) < 0') + if np.any(np.not_equal(np.imag(ogamma), 0)): + raise ValueError('Im(gamma) != 0') + + cov = 0.5 * np.imag(orelation) + rho = np.zeros_like(cov) + idx = (v_real.flat > 0) & (v_imag.flat > 0) + rho.flat[idx] = cov.flat[idx] / np.sqrt(v_real.flat[idx] * v_imag.flat[idx]) + if np.any(cov.flat[~idx] != 0) or np.any(np.abs(rho) > 1): + raise ValueError('Im(relation) ** 2 > Re(gamma ** 2 - relation ** 2)') + + if size is not None: + randoms = np.empty(size, np.complex128) + else: + it = np.PyArray_MultiIterNew4(oloc, v_real, v_imag, rho) + randoms = np.empty(it.shape, np.complex128) + + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + it = np.PyArray_MultiIterNew5(randoms, oloc, v_real, v_imag, rho) + with self.lock, nogil: + if method == u'zig': + for i in range( 2 * n): + randoms_data[i] = random_gauss_zig(self._prng) + else: + for i in range( 2 * n): + randoms_data[i] = random_gauss(self._prng) + with nogil: + j = 0 + for i in range(n): + floc_r= (np.PyArray_MultiIter_DATA(it, 1))[0] + floc_i= (np.PyArray_MultiIter_DATA(it, 1))[1] + fvar_r = (np.PyArray_MultiIter_DATA(it, 2))[0] + fvar_i = (np.PyArray_MultiIter_DATA(it, 3))[0] + f_rho = (np.PyArray_MultiIter_DATA(it, 4))[0] + compute_complex(&randoms_data[j], &randoms_data[j+1], floc_r, floc_i, fvar_r, fvar_i, f_rho) + j += 2 + np.PyArray_MultiIter_NEXT(it) + + return randoms + + def standard_gamma(self, shape, size=None, dtype=np.float64, method=u'zig', + out=None): + """ + standard_gamma(shape, size=None, dtype='d', method='inv', out=None) + + Draw samples from a standard Gamma distribution. + + Samples are drawn from a Gamma distribution with specified parameters, + shape (sometimes designated "k") and scale=1. + + Parameters + ---------- + shape : float or array_like of floats + Parameter, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``shape`` is a scalar. Otherwise, + ``np.array(shape).size`` samples are drawn. + dtype : {str, dtype}, optional + Desired dtype of the result, either 'd' (or 'float64') or 'f' + (or 'float32'). All dtypes are determined by their name. The + default value is 'd'. + method : str, optional + Either 'inv' or 'zig'. 'inv' uses the default inverse CDF method. + 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. + out : ndarray, optional + Alternative output array in which to place the result. If size is + not None, it must have the same shape as the provided size and + must match the type of the output values. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized standard gamma distribution. + + See Also + -------- + scipy.stats.gamma : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gamma distribution is + + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. + + References + ---------- + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + http://en.wikipedia.org/wiki/Gamma_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> shape, scale = 2., 1. # mean and width + >>> s = np.random.standard_gamma(shape, 1000000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ + ... (sps.gamma(shape) * scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') + >>> plt.show() + """ + cdef void *func + if method != u'zig' and method != u'inv': + raise ValueError("method must be either 'inv' or 'zig'") + key = np.dtype(dtype).name + if key == 'float64': + if method == 'inv': + func = &random_standard_gamma + else: + func = &random_standard_gamma_zig + return cont(func, self._prng, size, self.lock, 1, + shape, 'shape', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, + out) + if key == 'float32': + if method == 'inv': + func = &random_standard_gamma_f + else: + func = &random_standard_gamma_zig_f + return cont_f(func, self._prng, size, self.lock, + shape, 'shape', CONS_NON_NEGATIVE, + out) + else: + raise TypeError('Unsupported dtype "%s" for standard_gamma' % key) + + def gamma(self, shape, scale=1.0, size=None): + """ + gamma(shape, scale=1.0, size=None) + + Draw samples from a Gamma distribution. + + Samples are drawn from a Gamma distribution with specified parameters, + `shape` (sometimes designated "k") and `scale` (sometimes designated + "theta"), where both parameters are > 0. + + Parameters + ---------- + shape : float or array_like of floats + The shape of the gamma distribution. Should be greater than zero. + scale : float or array_like of floats, optional + The scale of the gamma distribution. Should be greater than zero. + Default is equal to 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``shape`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(shape, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized gamma distribution. + + See Also + -------- + scipy.stats.gamma : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gamma distribution is + + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. + + References + ---------- + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + http://en.wikipedia.org/wiki/Gamma_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> shape, scale = 2., 2. # mean and dispersion + >>> s = np.random.gamma(shape, scale, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> y = bins**(shape-1)*(np.exp(-bins/scale) / + ... (sps.gamma(shape)*scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') + >>> plt.show() + + """ + return cont(&random_gamma, self._prng, size, self.lock, 2, + shape, 'shape', CONS_NON_NEGATIVE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def f(self, dfnum, dfden, size=None): + """ + f(dfnum, dfden, size=None) + + Draw samples from an F distribution. + + Samples are drawn from an F distribution with specified parameters, + `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of + freedom in denominator), where both parameters should be greater than + zero. + + The random variate of the F distribution (also known as the + Fisher distribution) is a continuous probability distribution + that arises in ANOVA tests, and is the ratio of two chi-square + variates. + + Parameters + ---------- + dfnum : int or array_like of ints + Degrees of freedom in numerator. Should be greater than zero. + dfden : int or array_like of ints + Degrees of freedom in denominator. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``dfnum`` and ``dfden`` are both scalars. + Otherwise, ``np.broadcast(dfnum, dfden).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Fisher distribution. + + See Also + -------- + scipy.stats.f : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The F statistic is used to compare in-group variances to between-group + variances. Calculating the distribution depends on the sampling, and + so it is a function of the respective degrees of freedom in the + problem. The variable `dfnum` is the number of samples minus one, the + between-groups degrees of freedom, while `dfden` is the within-groups + degrees of freedom, the sum of the number of samples in each group + minus the number of groups. + + References + ---------- + .. [1] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, + Fifth Edition, 2002. + .. [2] Wikipedia, "F-distribution", + http://en.wikipedia.org/wiki/F-distribution + + Examples + -------- + An example from Glantz[1], pp 47-40: + + Two groups, children of diabetics (25 people) and children from people + without diabetes (25 controls). Fasting blood glucose was measured, + case group had a mean value of 86.1, controls had a mean value of + 82.2. Standard deviations were 2.09 and 2.49 respectively. Are these + data consistent with the null hypothesis that the parents diabetic + status does not affect their children's blood glucose levels? + Calculating the F statistic from the data gives a value of 36.01. + + Draw samples from the distribution: + + >>> dfnum = 1. # between group degrees of freedom + >>> dfden = 48. # within groups degrees of freedom + >>> s = np.random.f(dfnum, dfden, 1000) + + The lower bound for the top 1% of the samples is : + + >>> sort(s)[-10] + 7.61988120985 + + So there is about a 1% chance that the F statistic will exceed 7.62, + the measured value is 36, so the null hypothesis is rejected at the 1% + level. + + """ + return cont(&random_f, self._prng, size, self.lock, 2, + dfnum, 'dfnum', CONS_POSITIVE, + dfden, 'dfden', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + def noncentral_f(self, dfnum, dfden, nonc, size=None): + """ + noncentral_f(dfnum, dfden, nonc, size=None) + + Draw samples from the noncentral F distribution. + + Samples are drawn from an F distribution with specified parameters, + `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of + freedom in denominator), where both parameters > 1. + `nonc` is the non-centrality parameter. + + Parameters + ---------- + dfnum : int or array_like of ints + Parameter, should be > 1. + dfden : int or array_like of ints + Parameter, should be > 1. + nonc : float or array_like of floats + Parameter, should be >= 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``dfnum``, ``dfden``, and ``nonc`` + are all scalars. Otherwise, ``np.broadcast(dfnum, dfden, nonc).size`` + samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized noncentral Fisher distribution. + + Notes + ----- + When calculating the power of an experiment (power = probability of + rejecting the null hypothesis when a specific alternative is true) the + non-central F statistic becomes important. When the null hypothesis is + true, the F statistic follows a central F distribution. When the null + hypothesis is not true, then it follows a non-central F statistic. + + References + ---------- + .. [1] Weisstein, Eric W. "Noncentral F-Distribution." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/NoncentralF-Distribution.html + .. [2] Wikipedia, "Noncentral F-distribution", + http://en.wikipedia.org/wiki/Noncentral_F-distribution + + Examples + -------- + In a study, testing for a specific alternative to the null hypothesis + requires use of the Noncentral F distribution. We need to calculate the + area in the tail of the distribution that exceeds the value of the F + distribution for the null hypothesis. We'll plot the two probability + distributions for comparison. + + >>> dfnum = 3 # between group deg of freedom + >>> dfden = 20 # within groups degrees of freedom + >>> nonc = 3.0 + >>> nc_vals = np.random.noncentral_f(dfnum, dfden, nonc, 1000000) + >>> NF = np.histogram(nc_vals, bins=50, normed=True) + >>> c_vals = np.random.f(dfnum, dfden, 1000000) + >>> F = np.histogram(c_vals, bins=50, normed=True) + >>> plt.plot(F[1][1:], F[0]) + >>> plt.plot(NF[1][1:], NF[0]) + >>> plt.show() + + """ + return cont(&random_noncentral_f, self._prng, size, self.lock, 3, + dfnum, 'dfnum', CONS_POSITIVE, + dfden, 'dfden', CONS_POSITIVE, + nonc, 'nonc', CONS_NON_NEGATIVE, None) + + def chisquare(self, df, size=None): + """ + chisquare(df, size=None) + + Draw samples from a chi-square distribution. + + When `df` independent random variables, each with standard normal + distributions (mean 0, variance 1), are squared and summed, the + resulting distribution is chi-square (see Notes). This distribution + is often used in hypothesis testing. + + Parameters + ---------- + df : int or array_like of ints + Number of degrees of freedom. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` is a scalar. Otherwise, + ``np.array(df).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized chi-square distribution. + + Raises + ------ + ValueError + When `df` <= 0 or when an inappropriate `size` (e.g. ``size=-1``) + is given. + + Notes + ----- + The variable obtained by summing the squares of `df` independent, + standard normally distributed random variables: + + .. math:: Q = \\sum_{i=0}^{\\mathtt{df}} X^2_i + + is chi-square distributed, denoted + + .. math:: Q \\sim \\chi^2_k. + + The probability density function of the chi-squared distribution is + + .. math:: p(x) = \\frac{(1/2)^{k/2}}{\\Gamma(k/2)} + x^{k/2 - 1} e^{-x/2}, + + where :math:`\\Gamma` is the gamma function, + + .. math:: \\Gamma(x) = \\int_0^{-\\infty} t^{x - 1} e^{-t} dt. + + References + ---------- + .. [1] NIST "Engineering Statistics Handbook" + http://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm + + Examples + -------- + >>> np.random.chisquare(2,4) + array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) + + """ + return cont(&random_chisquare, self._prng, size, self.lock, 1, + df, 'df', CONS_POSITIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def noncentral_chisquare(self, df, nonc, size=None): + """ + noncentral_chisquare(df, nonc, size=None) + + Draw samples from a noncentral chi-square distribution. + + The noncentral :math:`\\chi^2` distribution is a generalisation of + the :math:`\\chi^2` distribution. + + Parameters + ---------- + df : int or array_like of ints + Degrees of freedom, should be > 0 as of NumPy 1.10.0, + should be > 1 for earlier versions. + nonc : float or array_like of floats + Non-centrality, should be non-negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` and ``nonc`` are both scalars. + Otherwise, ``np.broadcast(df, nonc).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized noncentral chi-square distribution. + + Notes + ----- + The probability density function for the noncentral Chi-square + distribution is + + .. math:: P(x;df,nonc) = \\sum^{\\infty}_{i=0} + \\frac{e^{-nonc/2}(nonc/2)^{i}}{i!} + \\P_{Y_{df+2i}}(x), + + where :math:`Y_{q}` is the Chi-square with q degrees of freedom. + + In Delhi (2007), it is noted that the noncentral chi-square is + useful in bombing and coverage problems, the probability of + killing the point target given by the noncentral chi-squared + distribution. + + References + ---------- + .. [1] Delhi, M.S. Holla, "On a noncentral chi-square distribution in + the analysis of weapon systems effectiveness", Metrika, + Volume 15, Number 1 / December, 1970. + .. [2] Wikipedia, "Noncentral chi-square distribution" + http://en.wikipedia.org/wiki/Noncentral_chi-square_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram + + >>> import matplotlib.pyplot as plt + >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), + ... bins=200, normed=True) + >>> plt.show() + + Draw values from a noncentral chisquare with very small noncentrality, + and compare to a chisquare. + + >>> plt.figure() + >>> values = plt.hist(np.random.noncentral_chisquare(3, .0000001, 100000), + ... bins=np.arange(0., 25, .1), normed=True) + >>> values2 = plt.hist(np.random.chisquare(3, 100000), + ... bins=np.arange(0., 25, .1), normed=True) + >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') + >>> plt.show() + + Demonstrate how large values of non-centrality lead to a more symmetric + distribution. + + >>> plt.figure() + >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), + ... bins=200, normed=True) + >>> plt.show() + + """ + return cont(&random_noncentral_chisquare, self._prng, size, self.lock, 2, + df, 'df', CONS_POSITIVE, + nonc, 'nonc', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def standard_cauchy(self, size=None): + """ + standard_cauchy(size=None) + + Draw samples from a standard Cauchy distribution with mode = 0. + + Also known as the Lorentz distribution. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + samples : ndarray or scalar + The drawn samples. + + Notes + ----- + The probability density function for the full Cauchy distribution is + + .. math:: P(x; x_0, \\gamma) = \\frac{1}{\\pi \\gamma \\bigl[ 1+ + (\\frac{x-x_0}{\\gamma})^2 \\bigr] } + + and the Standard Cauchy distribution just sets :math:`x_0=0` and + :math:`\\gamma=1` + + The Cauchy distribution arises in the solution to the driven harmonic + oscillator problem, and also describes spectral line broadening. It + also describes the distribution of values at which a line tilted at + a random angle will cut the x axis. + + When studying hypothesis tests that assume normality, seeing how the + tests perform on data from a Cauchy distribution is a good indicator of + their sensitivity to a heavy-tailed distribution, since the Cauchy looks + very much like a Gaussian distribution, but with heavier tails. + + References + ---------- + .. [1] NIST/SEMATECH e-Handbook of Statistical Methods, "Cauchy + Distribution", + http://www.itl.nist.gov/div898/handbook/eda/section3/eda3663.htm + .. [2] Weisstein, Eric W. "Cauchy Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/CauchyDistribution.html + .. [3] Wikipedia, "Cauchy distribution" + http://en.wikipedia.org/wiki/Cauchy_distribution + + Examples + -------- + Draw samples and plot the distribution: + + >>> s = np.random.standard_cauchy(1000000) + >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well + >>> plt.hist(s, bins=100) + >>> plt.show() + + """ + return cont(&random_standard_cauchy, self._prng, size, self.lock, 0, + 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) + + def standard_t(self, df, size=None): + """ + standard_t(df, size=None) + + Draw samples from a standard Student's t distribution with `df` degrees + of freedom. + + A special case of the hyperbolic distribution. As `df` gets + large, the result resembles that of the standard normal + distribution (`standard_normal`). + + Parameters + ---------- + df : int or array_like of ints + Degrees of freedom, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` is a scalar. Otherwise, + ``np.array(df).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized standard Student's t distribution. + + Notes + ----- + The probability density function for the t distribution is + + .. math:: P(x, df) = \\frac{\\Gamma(\\frac{df+1}{2})}{\\sqrt{\\pi df} + \\Gamma(\\frac{df}{2})}\\Bigl( 1+\\frac{x^2}{df} \\Bigr)^{-(df+1)/2} + + The t test is based on an assumption that the data come from a + Normal distribution. The t test provides a way to test whether + the sample mean (that is the mean calculated from the data) is + a good estimate of the true mean. + + The derivation of the t-distribution was first published in + 1908 by William Gosset while working for the Guinness Brewery + in Dublin. Due to proprietary issues, he had to publish under + a pseudonym, and so he used the name Student. + + References + ---------- + .. [1] Dalgaard, Peter, "Introductory Statistics With R", + Springer, 2002. + .. [2] Wikipedia, "Student's t-distribution" + http://en.wikipedia.org/wiki/Student's_t-distribution + + Examples + -------- + From Dalgaard page 83 [1]_, suppose the daily energy intake for 11 + women in Kj is: + + >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\ + ... 7515, 8230, 8770]) + + Does their energy intake deviate systematically from the recommended + value of 7725 kJ? + + We have 10 degrees of freedom, so is the sample mean within 95% of the + recommended value? + + >>> s = np.random.standard_t(10, size=100000) + >>> np.mean(intake) + 6753.636363636364 + >>> intake.std(ddof=1) + 1142.1232221373727 + + Calculate the t statistic, setting the ddof parameter to the unbiased + value so the divisor in the standard deviation will be degrees of + freedom, N-1. + + >>> t = (np.mean(intake)-7725)/(intake.std(ddof=1)/np.sqrt(len(intake))) + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(s, bins=100, normed=True) + + For a one-sided t-test, how far out in the distribution does the t + statistic appear? + + >>> np.sum(s=0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mu`` and ``kappa`` are both scalars. + Otherwise, ``np.broadcast(mu, kappa).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized von Mises distribution. + + See Also + -------- + scipy.stats.vonmises : probability density function, distribution, or + cumulative density function, etc. + + Notes + ----- + The probability density for the von Mises distribution is + + .. math:: p(x) = \\frac{e^{\\kappa cos(x-\\mu)}}{2\\pi I_0(\\kappa)}, + + where :math:`\\mu` is the mode and :math:`\\kappa` the dispersion, + and :math:`I_0(\\kappa)` is the modified Bessel function of order 0. + + The von Mises is named for Richard Edler von Mises, who was born in + Austria-Hungary, in what is now the Ukraine. He fled to the United + States in 1939 and became a professor at Harvard. He worked in + probability theory, aerodynamics, fluid mechanics, and philosophy of + science. + + References + ---------- + .. [1] Abramowitz, M. and Stegun, I. A. (Eds.). "Handbook of + Mathematical Functions with Formulas, Graphs, and Mathematical + Tables, 9th printing," New York: Dover, 1972. + .. [2] von Mises, R., "Mathematical Theory of Probability + and Statistics", New York: Academic Press, 1964. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, kappa = 0.0, 4.0 # mean and dispersion + >>> s = np.random.vonmises(mu, kappa, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> from scipy.special import i0 + >>> plt.hist(s, 50, normed=True) + >>> x = np.linspace(-np.pi, np.pi, num=51) + >>> y = np.exp(kappa*np.cos(x-mu))/(2*np.pi*i0(kappa)) + >>> plt.plot(x, y, linewidth=2, color='r') + >>> plt.show() + + """ + return cont(&random_vonmises, self._prng, size, self.lock, 2, + mu, 'mu', CONS_NONE, + kappa, 'kappa', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def pareto(self, a, size=None): + """ + pareto(a, size=None) + + Draw samples from a Pareto II or Lomax distribution with + specified shape. + + The Lomax or Pareto II distribution is a shifted Pareto + distribution. The classical Pareto distribution can be + obtained from the Lomax distribution by adding 1 and + multiplying by the scale parameter ``m`` (see Notes). The + smallest value of the Lomax distribution is zero while for the + classical Pareto distribution it is ``mu``, where the standard + Pareto distribution has location ``mu = 1``. Lomax can also + be considered as a simplified version of the Generalized + Pareto distribution (available in SciPy), with the scale set + to one and the location set to zero. + + The Pareto distribution must be greater than zero, and is + unbounded above. It is also known as the "80-20 rule". In + this distribution, 80 percent of the weights are in the lowest + 20 percent of the range, while the other 20 percent fill the + remaining 80 percent of the range. + + Parameters + ---------- + a : float or array_like of floats + Shape of the distribution. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Pareto distribution. + + See Also + -------- + scipy.stats.lomax : probability density function, distribution or + cumulative density function, etc. + scipy.stats.genpareto : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Pareto distribution is + + .. math:: p(x) = \\frac{am^a}{x^{a+1}} + + where :math:`a` is the shape and :math:`m` the scale. + + The Pareto distribution, named after the Italian economist + Vilfredo Pareto, is a power law probability distribution + useful in many real world problems. Outside the field of + economics it is generally referred to as the Bradford + distribution. Pareto developed the distribution to describe + the distribution of wealth in an economy. It has also found + use in insurance, web page access statistics, oil field sizes, + and many other problems, including the download frequency for + projects in Sourceforge [1]_. It is one of the so-called + "fat-tailed" distributions. + + + References + ---------- + .. [1] Francis Hunt and Paul Johnson, On the Pareto Distribution of + Sourceforge projects. + .. [2] Pareto, V. (1896). Course of Political Economy. Lausanne. + .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme + Values, Birkhauser Verlag, Basel, pp 23-30. + .. [4] Wikipedia, "Pareto distribution", + http://en.wikipedia.org/wiki/Pareto_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a, m = 3., 2. # shape and mode + >>> s = (np.random.pareto(a, 1000) + 1) * m + + Display the histogram of the samples, along with the probability + density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, _ = plt.hist(s, 100, normed=True) + >>> fit = a*m**a / bins**(a+1) + >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r') + >>> plt.show() + + """ + return cont(&random_pareto, self._prng, size, self.lock, 1, + a, 'a', CONS_POSITIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def weibull(self, a, size=None): + """ + weibull(a, size=None) + + Draw samples from a Weibull distribution. + + Draw samples from a 1-parameter Weibull distribution with the given + shape parameter `a`. + + .. math:: X = (-ln(U))^{1/a} + + Here, U is drawn from the uniform distribution over (0,1]. + + The more common 2-parameter Weibull, including a scale parameter + :math:`\\lambda` is just :math:`X = \\lambda(-ln(U))^{1/a}`. + + Parameters + ---------- + a : float or array_like of floats + Shape of the distribution. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Weibull distribution. + + See Also + -------- + scipy.stats.weibull_max + scipy.stats.weibull_min + scipy.stats.genextreme + gumbel + + Notes + ----- + The Weibull (or Type III asymptotic extreme value distribution + for smallest values, SEV Type III, or Rosin-Rammler + distribution) is one of a class of Generalized Extreme Value + (GEV) distributions used in modeling extreme value problems. + This class includes the Gumbel and Frechet distributions. + + The probability density for the Weibull distribution is + + .. math:: p(x) = \\frac{a} + {\\lambda}(\\frac{x}{\\lambda})^{a-1}e^{-(x/\\lambda)^a}, + + where :math:`a` is the shape and :math:`\\lambda` the scale. + + The function has its peak (the mode) at + :math:`\\lambda(\\frac{a-1}{a})^{1/a}`. + + When ``a = 1``, the Weibull distribution reduces to the exponential + distribution. + + References + ---------- + .. [1] Waloddi Weibull, Royal Technical University, Stockholm, + 1939 "A Statistical Theory Of The Strength Of Materials", + Ingeniorsvetenskapsakademiens Handlingar Nr 151, 1939, + Generalstabens Litografiska Anstalts Forlag, Stockholm. + .. [2] Waloddi Weibull, "A Statistical Distribution Function of + Wide Applicability", Journal Of Applied Mechanics ASME Paper + 1951. + .. [3] Wikipedia, "Weibull distribution", + http://en.wikipedia.org/wiki/Weibull_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a = 5. # shape + >>> s = np.random.weibull(a, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> x = np.arange(1,100.)/50. + >>> def weib(x,n,a): + ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) + + >>> count, bins, ignored = plt.hist(np.random.weibull(5.,1000)) + >>> x = np.arange(1,100.)/50. + >>> scale = count.max()/weib(x, 1., 5.).max() + >>> plt.plot(x, weib(x, 1., 5.)*scale) + >>> plt.show() + + """ + return cont(&random_weibull, self._prng, size, self.lock, 1, + a, 'a', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def power(self, a, size=None): + """ + power(a, size=None) + + Draws samples in [0, 1] from a power distribution with positive + exponent a - 1. + + Also known as the power function distribution. + + Parameters + ---------- + a : float or array_like of floats + Parameter of the distribution. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized power distribution. + + Raises + ------ + ValueError + If a < 1. + + Notes + ----- + The probability density function is + + .. math:: P(x; a) = ax^{a-1}, 0 \\le x \\le 1, a>0. + + The power function distribution is just the inverse of the Pareto + distribution. It may also be seen as a special case of the Beta + distribution. + + It is used, for example, in modeling the over-reporting of insurance + claims. + + References + ---------- + .. [1] Christian Kleiber, Samuel Kotz, "Statistical size distributions + in economics and actuarial sciences", Wiley, 2003. + .. [2] Heckert, N. A. and Filliben, James J. "NIST Handbook 148: + Dataplot Reference Manual, Volume 2: Let Subcommands and Library + Functions", National Institute of Standards and Technology + Handbook Series, June 2003. + http://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf + + Examples + -------- + Draw samples from the distribution: + + >>> a = 5. # shape + >>> samples = 1000 + >>> s = np.random.power(a, samples) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, bins=30) + >>> x = np.linspace(0, 1, 100) + >>> y = a*x**(a-1.) + >>> normed_y = samples*np.diff(bins)[0]*y + >>> plt.plot(x, normed_y) + >>> plt.show() + + Compare the power function distribution to the inverse of the Pareto. + + >>> from scipy import stats + >>> rvs = np.random.power(5, 1000000) + >>> rvsp = np.random.pareto(5, 1000000) + >>> xx = np.linspace(0,1,100) + >>> powpdf = stats.powerlaw.pdf(xx,5) + + >>> plt.figure() + >>> plt.hist(rvs, bins=50, normed=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('np.random.power(5)') + + >>> plt.figure() + >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('inverse of 1 + np.random.pareto(5)') + + >>> plt.figure() + >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('inverse of stats.pareto(5)') + + """ + return cont(&random_power, self._prng, size, self.lock, 1, + a, 'a', CONS_POSITIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def laplace(self, loc=0.0, scale=1.0, size=None): + """ + laplace(loc=0.0, scale=1.0, size=None) + + Draw samples from the Laplace or double exponential distribution with + specified location (or mean) and scale (decay). + + The Laplace distribution is similar to the Gaussian/normal distribution, + but is sharper at the peak and has fatter tails. It represents the + difference between two independent, identically distributed exponential + random variables. + + Parameters + ---------- + loc : float or array_like of floats, optional + The position, :math:`\\mu`, of the distribution peak. Default is 0. + scale : float or array_like of floats, optional + :math:`\\lambda`, the exponential decay. Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Laplace distribution. + + Notes + ----- + It has the probability density function + + .. math:: f(x; \\mu, \\lambda) = \\frac{1}{2\\lambda} + \\exp\\left(-\\frac{|x - \\mu|}{\\lambda}\\right). + + The first law of Laplace, from 1774, states that the frequency + of an error can be expressed as an exponential function of the + absolute magnitude of the error, which leads to the Laplace + distribution. For many problems in economics and health + sciences, this distribution seems to model the data better + than the standard Gaussian distribution. + + References + ---------- + .. [1] Abramowitz, M. and Stegun, I. A. (Eds.). "Handbook of + Mathematical Functions with Formulas, Graphs, and Mathematical + Tables, 9th printing," New York: Dover, 1972. + .. [2] Kotz, Samuel, et. al. "The Laplace Distribution and + Generalizations, " Birkhauser, 2001. + .. [3] Weisstein, Eric W. "Laplace Distribution." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/LaplaceDistribution.html + .. [4] Wikipedia, "Laplace distribution", + http://en.wikipedia.org/wiki/Laplace_distribution + + Examples + -------- + Draw samples from the distribution + + >>> loc, scale = 0., 1. + >>> s = np.random.laplace(loc, scale, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> x = np.arange(-8., 8., .01) + >>> pdf = np.exp(-abs(x-loc)/scale)/(2.*scale) + >>> plt.plot(x, pdf) + + Plot Gaussian for comparison: + + >>> g = (1/(scale * np.sqrt(2 * np.pi)) * + ... np.exp(-(x - loc)**2 / (2 * scale**2))) + >>> plt.plot(x,g) + + """ + return cont(&random_laplace, self._prng, size, self.lock, 2, + loc, 'loc', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def gumbel(self, loc=0.0, scale=1.0, size=None): + """ + gumbel(loc=0.0, scale=1.0, size=None) + + Draw samples from a Gumbel distribution. + + Draw samples from a Gumbel distribution with specified location and + scale. For more information on the Gumbel distribution, see + Notes and References below. + + Parameters + ---------- + loc : float or array_like of floats, optional + The location of the mode of the distribution. Default is 0. + scale : float or array_like of floats, optional + The scale parameter of the distribution. Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Gumbel distribution. + + See Also + -------- + scipy.stats.gumbel_l + scipy.stats.gumbel_r + scipy.stats.genextreme + weibull + + Notes + ----- + The Gumbel (or Smallest Extreme Value (SEV) or the Smallest Extreme + Value Type I) distribution is one of a class of Generalized Extreme + Value (GEV) distributions used in modeling extreme value problems. + The Gumbel is a special case of the Extreme Value Type I distribution + for maximums from distributions with "exponential-like" tails. + + The probability density for the Gumbel distribution is + + .. math:: p(x) = \\frac{e^{-(x - \\mu)/ \\beta}}{\\beta} e^{ -e^{-(x - \\mu)/ + \\beta}}, + + where :math:`\\mu` is the mode, a location parameter, and + :math:`\\beta` is the scale parameter. + + The Gumbel (named for German mathematician Emil Julius Gumbel) was used + very early in the hydrology literature, for modeling the occurrence of + flood events. It is also used for modeling maximum wind speed and + rainfall rates. It is a "fat-tailed" distribution - the probability of + an event in the tail of the distribution is larger than if one used a + Gaussian, hence the surprisingly frequent occurrence of 100-year + floods. Floods were initially modeled as a Gaussian process, which + underestimated the frequency of extreme events. + + It is one of a class of extreme value distributions, the Generalized + Extreme Value (GEV) distributions, which also includes the Weibull and + Frechet. + + The function has a mean of :math:`\\mu + 0.57721\\beta` and a variance + of :math:`\\frac{\\pi^2}{6}\\beta^2`. + + References + ---------- + .. [1] Gumbel, E. J., "Statistics of Extremes," + New York: Columbia University Press, 1958. + .. [2] Reiss, R.-D. and Thomas, M., "Statistical Analysis of Extreme + Values from Insurance, Finance, Hydrology and Other Fields," + Basel: Birkhauser Verlag, 2001. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, beta = 0, 0.1 # location and scale + >>> s = np.random.gumbel(mu, beta, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta) + ... * np.exp( -np.exp( -(bins - mu) /beta) ), + ... linewidth=2, color='r') + >>> plt.show() + + Show how an extreme value distribution can arise from a Gaussian process + and compare to a Gaussian: + + >>> means = [] + >>> maxima = [] + >>> for i in range(0,1000) : + ... a = np.random.normal(mu, beta, 1000) + ... means.append(a.mean()) + ... maxima.append(a.max()) + >>> count, bins, ignored = plt.hist(maxima, 30, normed=True) + >>> beta = np.std(maxima) * np.sqrt(6) / np.pi + >>> mu = np.mean(maxima) - 0.57721*beta + >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta) + ... * np.exp(-np.exp(-(bins - mu)/beta)), + ... linewidth=2, color='r') + >>> plt.plot(bins, 1/(beta * np.sqrt(2 * np.pi)) + ... * np.exp(-(bins - mu)**2 / (2 * beta**2)), + ... linewidth=2, color='g') + >>> plt.show() + + """ + return cont(&random_gumbel, self._prng, size, self.lock, 2, + loc, 'loc', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def logistic(self, loc=0.0, scale=1.0, size=None): + """ + logistic(loc=0.0, scale=1.0, size=None) + + Draw samples from a logistic distribution. + + Samples are drawn from a logistic distribution with specified + parameters, loc (location or mean, also median), and scale (>0). + + Parameters + ---------- + loc : float or array_like of floats, optional + Parameter of the distribution. Default is 0. + scale : float or array_like of floats, optional + Parameter of the distribution. Should be greater than zero. + Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized logistic distribution. + + See Also + -------- + scipy.stats.logistic : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Logistic distribution is + + .. math:: P(x) = P(x) = \\frac{e^{-(x-\\mu)/s}}{s(1+e^{-(x-\\mu)/s})^2}, + + where :math:`\\mu` = location and :math:`s` = scale. + + The Logistic distribution is used in Extreme Value problems where it + can act as a mixture of Gumbel distributions, in Epidemiology, and by + the World Chess Federation (FIDE) where it is used in the Elo ranking + system, assuming the performance of each player is a logistically + distributed random variable. + + References + ---------- + .. [1] Reiss, R.-D. and Thomas M. (2001), "Statistical Analysis of + Extreme Values, from Insurance, Finance, Hydrology and Other + Fields," Birkhauser Verlag, Basel, pp 132-133. + .. [2] Weisstein, Eric W. "Logistic Distribution." From + MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/LogisticDistribution.html + .. [3] Wikipedia, "Logistic-distribution", + http://en.wikipedia.org/wiki/Logistic_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> loc, scale = 10, 1 + >>> s = np.random.logistic(loc, scale, 10000) + >>> count, bins, ignored = plt.hist(s, bins=50) + + # plot against distribution + + >>> def logist(x, loc, scale): + ... return exp((loc-x)/scale)/(scale*(1+exp((loc-x)/scale))**2) + >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\\ + ... logist(bins, loc, scale).max()) + >>> plt.show() + + """ + return cont(&random_logistic, self._prng, size, self.lock, 2, + loc, 'loc', CONS_NONE, + scale, 'scale', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + def lognormal(self, mean=0.0, sigma=1.0, size=None): + """ + lognormal(mean=0.0, sigma=1.0, size=None) + + Draw samples from a log-normal distribution. + + Draw samples from a log-normal distribution with specified mean, + standard deviation, and array shape. Note that the mean and standard + deviation are not the values for the distribution itself, but of the + underlying normal distribution it is derived from. + + Parameters + ---------- + mean : float or array_like of floats, optional + Mean value of the underlying normal distribution. Default is 0. + sigma : float or array_like of floats, optional + Standard deviation of the underlying normal distribution. Should + be greater than zero. Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mean`` and ``sigma`` are both scalars. + Otherwise, ``np.broadcast(mean, sigma).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized log-normal distribution. + + See Also + -------- + scipy.stats.lognorm : probability density function, distribution, + cumulative density function, etc. + + Notes + ----- + A variable `x` has a log-normal distribution if `log(x)` is normally + distributed. The probability density function for the log-normal + distribution is: + + .. math:: p(x) = \\frac{1}{\\sigma x \\sqrt{2\\pi}} + e^{(-\\frac{(ln(x)-\\mu)^2}{2\\sigma^2})} + + where :math:`\\mu` is the mean and :math:`\\sigma` is the standard + deviation of the normally distributed logarithm of the variable. + A log-normal distribution results if a random variable is the *product* + of a large number of independent, identically-distributed variables in + the same way that a normal distribution results if the variable is the + *sum* of a large number of independent, identically-distributed + variables. + + References + ---------- + .. [1] Limpert, E., Stahel, W. A., and Abbt, M., "Log-normal + Distributions across the Sciences: Keys and Clues," + BioScience, Vol. 51, No. 5, May, 2001. + http://stat.ethz.ch/~stahel/lognormal/bioscience.pdf + .. [2] Reiss, R.D. and Thomas, M., "Statistical Analysis of Extreme + Values," Basel: Birkhauser Verlag, 2001, pp. 31-32. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, sigma = 3., 1. # mean and standard deviation + >>> s = np.random.lognormal(mu, sigma, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 100, normed=True, align='mid') + + >>> x = np.linspace(min(bins), max(bins), 10000) + >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) + ... / (x * sigma * np.sqrt(2 * np.pi))) + + >>> plt.plot(x, pdf, linewidth=2, color='r') + >>> plt.axis('tight') + >>> plt.show() + + Demonstrate that taking the products of random samples from a uniform + distribution can be fit well by a log-normal probability density + function. + + >>> # Generate a thousand samples: each is the product of 100 random + >>> # values, drawn from a normal distribution. + >>> b = [] + >>> for i in range(1000): + ... a = 10. + np.random.random(100) + ... b.append(np.product(a)) + + >>> b = np.array(b) / np.min(b) # scale values to be positive + >>> count, bins, ignored = plt.hist(b, 100, normed=True, align='mid') + >>> sigma = np.std(np.log(b)) + >>> mu = np.mean(np.log(b)) + + >>> x = np.linspace(min(bins), max(bins), 10000) + >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) + ... / (x * sigma * np.sqrt(2 * np.pi))) + + >>> plt.plot(x, pdf, color='r', linewidth=2) + >>> plt.show() + + """ + return cont(&random_lognormal, self._prng, size, self.lock, 2, + mean, 'mean', CONS_NONE, + sigma, 'sigma', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def rayleigh(self, scale=1.0, size=None): + """ + rayleigh(scale=1.0, size=None) + + Draw samples from a Rayleigh distribution. + + The :math:`\\chi` and Weibull distributions are generalizations of the + Rayleigh. + + Parameters + ---------- + scale : float or array_like of floats, optional + Scale, also equals the mode. Should be >= 0. Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``scale`` is a scalar. Otherwise, + ``np.array(scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Rayleigh distribution. + + Notes + ----- + The probability density function for the Rayleigh distribution is + + .. math:: P(x;scale) = \\frac{x}{scale^2}e^{\\frac{-x^2}{2 \\cdotp scale^2}} + + The Rayleigh distribution would arise, for example, if the East + and North components of the wind velocity had identical zero-mean + Gaussian distributions. Then the wind speed would have a Rayleigh + distribution. + + References + ---------- + .. [1] Brighton Webs Ltd., "Rayleigh Distribution," + http://www.brighton-webs.co.uk/distributions/rayleigh.asp + .. [2] Wikipedia, "Rayleigh distribution" + http://en.wikipedia.org/wiki/Rayleigh_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram + + >>> values = hist(np.random.rayleigh(3, 100000), bins=200, normed=True) + + Wave heights tend to follow a Rayleigh distribution. If the mean wave + height is 1 meter, what fraction of waves are likely to be larger than 3 + meters? + + >>> meanvalue = 1 + >>> modevalue = np.sqrt(2 / np.pi) * meanvalue + >>> s = np.random.rayleigh(modevalue, 1000000) + + The percentage of waves larger than 3 meters is: + + >>> 100.*sum(s>3)/1000000. + 0.087300000000000003 + + """ + return cont(&random_rayleigh, self._prng, size, self.lock, 1, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def wald(self, mean, scale, size=None): + """ + wald(mean, scale, size=None) + + Draw samples from a Wald, or inverse Gaussian, distribution. + + As the scale approaches infinity, the distribution becomes more like a + Gaussian. Some references claim that the Wald is an inverse Gaussian + with mean equal to 1, but this is by no means universal. + + The inverse Gaussian distribution was first studied in relationship to + Brownian motion. In 1956 M.C.K. Tweedie used the name inverse Gaussian + because there is an inverse relationship between the time to cover a + unit distance and distance covered in unit time. + + Parameters + ---------- + mean : float or array_like of floats + Distribution mean, should be > 0. + scale : float or array_like of floats + Scale parameter, should be >= 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mean`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(mean, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Wald distribution. + + Notes + ----- + The probability density function for the Wald distribution is + + .. math:: P(x;mean,scale) = \\sqrt{\\frac{scale}{2\\pi x^3}}e^ + \\frac{-scale(x-mean)^2}{2\\cdotp mean^2x} + + As noted above the inverse Gaussian distribution first arise + from attempts to model Brownian motion. It is also a + competitor to the Weibull for use in reliability modeling and + modeling stock returns and interest rate processes. + + References + ---------- + .. [1] Brighton Webs Ltd., Wald Distribution, + http://www.brighton-webs.co.uk/distributions/wald.asp + .. [2] Chhikara, Raj S., and Folks, J. Leroy, "The Inverse Gaussian + Distribution: Theory : Methodology, and Applications", CRC Press, + 1988. + .. [3] Wikipedia, "Wald distribution" + http://en.wikipedia.org/wiki/Wald_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram: + + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(np.random.wald(3, 2, 100000), bins=200, normed=True) + >>> plt.show() + + """ + return cont(&random_wald, self._prng, size, self.lock, 2, + mean, 'mean', CONS_POSITIVE, + scale, 'scale', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + def triangular(self, left, mode, right, size=None): + """ + triangular(left, mode, right, size=None) + + Draw samples from the triangular distribution over the + interval ``[left, right]``. + + The triangular distribution is a continuous probability + distribution with lower limit left, peak at mode, and upper + limit right. Unlike the other distributions, these parameters + directly define the shape of the pdf. + + Parameters + ---------- + left : float or array_like of floats + Lower limit. + mode : float or array_like of floats + The value where the peak of the distribution occurs. + The value should fulfill the condition ``left <= mode <= right``. + right : float or array_like of floats + Upper limit, should be larger than `left`. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``left``, ``mode``, and ``right`` + are all scalars. Otherwise, ``np.broadcast(left, mode, right).size`` + samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized triangular distribution. + + Notes + ----- + The probability density function for the triangular distribution is + + .. math:: P(x;l, m, r) = \\begin{cases} + \\frac{2(x-l)}{(r-l)(m-l)}& \\text{for $l \\leq x \\leq m$},\\\\ + \\frac{2(r-x)}{(r-l)(r-m)}& \\text{for $m \\leq x \\leq r$},\\\\ + 0& \\text{otherwise}. + \\end{cases} + + The triangular distribution is often used in ill-defined + problems where the underlying distribution is not known, but + some knowledge of the limits and mode exists. Often it is used + in simulations. + + References + ---------- + .. [1] Wikipedia, "Triangular distribution" + http://en.wikipedia.org/wiki/Triangular_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram: + + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(np.random.triangular(-3, 0, 8, 100000), bins=200, + ... normed=True) + >>> plt.show() + + """ + cdef bint is_scalar = True + cdef double fleft, fmode, fright + cdef np.ndarray oleft, omode, oright + + oleft = np.PyArray_FROM_OTF(left, np.NPY_DOUBLE, np.NPY_ALIGNED) + omode = np.PyArray_FROM_OTF(mode, np.NPY_DOUBLE, np.NPY_ALIGNED) + oright = np.PyArray_FROM_OTF(right, np.NPY_DOUBLE, np.NPY_ALIGNED) + + if np.PyArray_NDIM(oleft) == np.PyArray_NDIM(omode) == np.PyArray_NDIM(oright) == 0: + fleft = PyFloat_AsDouble(left) + fright = PyFloat_AsDouble(right) + fmode = PyFloat_AsDouble(mode) + + if fleft > fmode: + raise ValueError("left > mode") + if fmode > fright: + raise ValueError("mode > right") + if fleft == fright: + raise ValueError("left == right") + return cont(&random_triangular, self._prng, size, self.lock, 3, + fleft, '', CONS_NONE, + fmode, '', CONS_NONE, + fright, '', CONS_NONE, None) + + if np.any(np.greater(oleft, omode)): + raise ValueError("left > mode") + if np.any(np.greater(omode, oright)): + raise ValueError("mode > right") + if np.any(np.equal(oleft, oright)): + raise ValueError("left == right") + + return cont_broadcast_3(&random_triangular, self._prng, size, self.lock, + oleft, '', CONS_NONE, + omode, '', CONS_NONE, + oright, '', CONS_NONE) + + # Complicated, discrete distributions: + def binomial(self, n, p, size=None): + """ + binomial(n, p, size=None) + + Draw samples from a binomial distribution. + + Samples are drawn from a binomial distribution with specified + parameters, n trials and p probability of success where + n an integer >= 0 and p is in the interval [0,1]. (n may be + input as a float, but it is truncated to an integer in use) + + Parameters + ---------- + n : int or array_like of ints + Parameter of the distribution, >= 0. Floats are also accepted, + but they will be truncated to integers. + p : float or array_like of floats + Parameter of the distribution, >= 0 and <=1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``n`` and ``p`` are both scalars. + Otherwise, ``np.broadcast(n, p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized binomial distribution, where + each sample is equal to the number of successes over the n trials. + + See Also + -------- + scipy.stats.binom : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the binomial distribution is + + .. math:: P(N) = \\binom{n}{N}p^N(1-p)^{n-N}, + + where :math:`n` is the number of trials, :math:`p` is the probability + of success, and :math:`N` is the number of successes. + + When estimating the standard error of a proportion in a population by + using a random sample, the normal distribution works well unless the + product p*n <=5, where p = population proportion estimate, and n = + number of samples, in which case the binomial distribution is used + instead. For example, a sample of 15 people shows 4 who are left + handed, and 11 who are right handed. Then p = 4/15 = 27%. 0.27*15 = 4, + so the binomial distribution should be used in this case. + + References + ---------- + .. [1] Dalgaard, Peter, "Introductory Statistics with R", + Springer-Verlag, 2002. + .. [2] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, + Fifth Edition, 2002. + .. [3] Lentner, Marvin, "Elementary Applied Statistics", Bogden + and Quigley, 1972. + .. [4] Weisstein, Eric W. "Binomial Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/BinomialDistribution.html + .. [5] Wikipedia, "Binomial distribution", + http://en.wikipedia.org/wiki/Binomial_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> n, p = 10, .5 # number of trials, probability of each trial + >>> s = np.random.binomial(n, p, 1000) + # result of flipping a coin 10 times, tested 1000 times. + + A real world example. A company drills 9 wild-cat oil exploration + wells, each with an estimated probability of success of 0.1. All nine + wells fail. What is the probability of that happening? + + Let's do 20,000 trials of the model, and count the number that + generate zero positive results. + + >>> sum(np.random.binomial(9, 0.1, 20000) == 0)/20000. + # answer = 0.38885, or 38%. + + """ + return disc(&random_binomial, self._prng, size, self.lock, 1, 1, + p, 'p', CONS_BOUNDED_0_1_NOTNAN, + n, 'n', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE) + + def negative_binomial(self, n, p, size=None): + """ + negative_binomial(n, p, size=None) + + Draw samples from a negative binomial distribution. + + Samples are drawn from a negative binomial distribution with specified + parameters, `n` trials and `p` probability of success where `n` is an + integer > 0 and `p` is in the interval [0, 1]. + + Parameters + ---------- + n : int or array_like of ints + Parameter of the distribution, > 0. Floats are also accepted, + but they will be truncated to integers. + p : float or array_like of floats + Parameter of the distribution, >= 0 and <=1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``n`` and ``p`` are both scalars. + Otherwise, ``np.broadcast(n, p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized negative binomial distribution, + where each sample is equal to N, the number of trials it took to + achieve n - 1 successes, N - (n - 1) failures, and a success on the, + (N + n)th trial. + + Notes + ----- + The probability density for the negative binomial distribution is + + .. math:: P(N;n,p) = \\binom{N+n-1}{n-1}p^{n}(1-p)^{N}, + + where :math:`n-1` is the number of successes, :math:`p` is the + probability of success, and :math:`N+n-1` is the number of trials. + The negative binomial distribution gives the probability of n-1 + successes and N failures in N+n-1 trials, and success on the (N+n)th + trial. + + If one throws a die repeatedly until the third time a "1" appears, + then the probability distribution of the number of non-"1"s that + appear before the third "1" is a negative binomial distribution. + + References + ---------- + .. [1] Weisstein, Eric W. "Negative Binomial Distribution." From + MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/NegativeBinomialDistribution.html + .. [2] Wikipedia, "Negative binomial distribution", + http://en.wikipedia.org/wiki/Negative_binomial_distribution + + Examples + -------- + Draw samples from the distribution: + + A real world example. A company drills wild-cat oil + exploration wells, each with an estimated probability of + success of 0.1. What is the probability of having one success + for each successive well, that is what is the probability of a + single success after drilling 5 wells, after 6 wells, etc.? + + >>> s = np.random.negative_binomial(1, 0.1, 100000) + >>> for i in range(1, 11): + ... probability = sum(s= 0. A sequence of expectation + intervals must be broadcastable over the requested size. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``lam`` is a scalar. Otherwise, + ``np.array(lam).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Poisson distribution. + + Notes + ----- + The Poisson distribution + + .. math:: f(k; \\lambda)=\\frac{\\lambda^k e^{-\\lambda}}{k!} + + For events with an expected separation :math:`\\lambda` the Poisson + distribution :math:`f(k; \\lambda)` describes the probability of + :math:`k` events occurring within the observed + interval :math:`\\lambda`. + + Because the output is limited to the range of the C long type, a + ValueError is raised when `lam` is within 10 sigma of the maximum + representable value. + + References + ---------- + .. [1] Weisstein, Eric W. "Poisson Distribution." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/PoissonDistribution.html + .. [2] Wikipedia, "Poisson distribution", + http://en.wikipedia.org/wiki/Poisson_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> import numpy as np + >>> s = np.random.poisson(5, 10000) + + Display histogram of the sample: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 14, normed=True) + >>> plt.show() + + Draw each 100 values for lambda 100 and 500: + + >>> s = np.random.poisson(lam=(100., 500.), size=(100, 2)) + + """ + return disc(&random_poisson, self._prng, size, self.lock, 1, 0, + lam, 'lam', CONS_POISSON, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) + + def zipf(self, a, size=None): + """ + zipf(a, size=None) + + Draw samples from a Zipf distribution. + + Samples are drawn from a Zipf distribution with specified parameter + `a` > 1. + + The Zipf distribution (also known as the zeta distribution) is a + continuous probability distribution that satisfies Zipf's law: the + frequency of an item is inversely proportional to its rank in a + frequency table. + + Parameters + ---------- + a : float or array_like of floats + Distribution parameter. Should be greater than 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Zipf distribution. + + See Also + -------- + scipy.stats.zipf : probability density function, distribution, or + cumulative density function, etc. + + Notes + ----- + The probability density for the Zipf distribution is + + .. math:: p(x) = \\frac{x^{-a}}{\\zeta(a)}, + + where :math:`\\zeta` is the Riemann Zeta function. + + It is named for the American linguist George Kingsley Zipf, who noted + that the frequency of any word in a sample of a language is inversely + proportional to its rank in the frequency table. + + References + ---------- + .. [1] Zipf, G. K., "Selected Studies of the Principle of Relative + Frequency in Language," Cambridge, MA: Harvard Univ. Press, + 1932. + + Examples + -------- + Draw samples from the distribution: + + >>> a = 2. # parameter + >>> s = np.random.zipf(a, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> from scipy import special + + Truncate s values at 50 so plot is interesting: + + >>> count, bins, ignored = plt.hist(s[s<50], 50, normed=True) + >>> x = np.arange(1., 50.) + >>> y = x**(-a) / special.zetac(a) + >>> plt.plot(x, y/max(y), linewidth=2, color='r') + >>> plt.show() + + """ + return disc(&random_zipf, self._prng, size, self.lock, 1, 0, + a, 'a', CONS_GT_1, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) + + def geometric(self, p, size=None): + """ + geometric(p, size=None) + + Draw samples from the geometric distribution. + + Bernoulli trials are experiments with one of two outcomes: + success or failure (an example of such an experiment is flipping + a coin). The geometric distribution models the number of trials + that must be run in order to achieve success. It is therefore + supported on the positive integers, ``k = 1, 2, ...``. + + The probability mass function of the geometric distribution is + + .. math:: f(k) = (1 - p)^{k - 1} p + + where `p` is the probability of success of an individual trial. + + Parameters + ---------- + p : float or array_like of floats + The probability of success of an individual trial. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``p`` is a scalar. Otherwise, + ``np.array(p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized geometric distribution. + + Examples + -------- + Draw ten thousand values from the geometric distribution, + with the probability of an individual success equal to 0.35: + + >>> z = np.random.geometric(p=0.35, size=10000) + + How many trials succeeded after a single run? + + >>> (z == 1).sum() / 10000. + 0.34889999999999999 #random + + """ + return disc(&random_geometric, self._prng, size, self.lock, 1, 0, + p, 'p', CONS_BOUNDED_0_1, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) + + def hypergeometric(self, ngood, nbad, nsample, size=None): + """ + hypergeometric(ngood, nbad, nsample, size=None) + + Draw samples from a Hypergeometric distribution. + + Samples are drawn from a hypergeometric distribution with specified + parameters, ngood (ways to make a good selection), nbad (ways to make + a bad selection), and nsample = number of items sampled, which is less + than or equal to the sum ngood + nbad. + + Parameters + ---------- + ngood : int or array_like of ints + Number of ways to make a good selection. Must be nonnegative. + nbad : int or array_like of ints + Number of ways to make a bad selection. Must be nonnegative. + nsample : int or array_like of ints + Number of items sampled. Must be at least 1 and at most + ``ngood + nbad``. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``ngood``, ``nbad``, and ``nsample`` + are all scalars. Otherwise, ``np.broadcast(ngood, nbad, nsample).size`` + samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized hypergeometric distribution. + + See Also + -------- + scipy.stats.hypergeom : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Hypergeometric distribution is + + .. math:: P(x) = \\frac{\\binom{m}{n}\\binom{N-m}{n-x}}{\\binom{N}{n}}, + + where :math:`0 \\le x \\le m` and :math:`n+m-N \\le x \\le n` + + for P(x) the probability of x successes, n = ngood, m = nbad, and + N = number of samples. + + Consider an urn with black and white marbles in it, ngood of them + black and nbad are white. If you draw nsample balls without + replacement, then the hypergeometric distribution describes the + distribution of black balls in the drawn sample. + + Note that this distribution is very similar to the binomial + distribution, except that in this case, samples are drawn without + replacement, whereas in the Binomial case samples are drawn with + replacement (or the sample space is infinite). As the sample space + becomes large, this distribution approaches the binomial. + + References + ---------- + .. [1] Lentner, Marvin, "Elementary Applied Statistics", Bogden + and Quigley, 1972. + .. [2] Weisstein, Eric W. "Hypergeometric Distribution." From + MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/HypergeometricDistribution.html + .. [3] Wikipedia, "Hypergeometric distribution", + http://en.wikipedia.org/wiki/Hypergeometric_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> ngood, nbad, nsamp = 100, 2, 10 + # number of good, number of bad, and number of samples + >>> s = np.random.hypergeometric(ngood, nbad, nsamp, 1000) + >>> hist(s) + # note that it is very unlikely to grab both bad items + + Suppose you have an urn with 15 white and 15 black marbles. + If you pull 15 marbles at random, how likely is it that + 12 or more of them are one color? + + >>> s = np.random.hypergeometric(15, 15, 15, 100000) + >>> sum(s>=12)/100000. + sum(s<=3)/100000. + # answer = 0.003 ... pretty unlikely! + + """ + cdef bint is_scalar = True + cdef np.ndarray ongood, onbad, onsample + cdef long lngood, lnbad, lnsample + + ongood = np.PyArray_FROM_OTF(ngood, np.NPY_LONG, np.NPY_ALIGNED) + onbad = np.PyArray_FROM_OTF(nbad, np.NPY_LONG, np.NPY_ALIGNED) + onsample = np.PyArray_FROM_OTF(nsample, np.NPY_LONG, np.NPY_ALIGNED) + + if np.PyArray_NDIM(ongood) == np.PyArray_NDIM(onbad) == np.PyArray_NDIM(onsample) == 0: + + lngood = PyInt_AsLong(ngood) + lnbad = PyInt_AsLong(nbad) + lnsample = PyInt_AsLong(nsample) + + if lngood < 0: + raise ValueError("ngood < 0") + if lnbad < 0: + raise ValueError("nbad < 0") + if lnsample < 1: + raise ValueError("nsample < 1") + if lngood + lnbad < lnsample: + raise ValueError("ngood + nbad < nsample") + return disc(&random_hypergeometric, self._prng, size, self.lock, 0, 3, + lngood, 'ngood', CONS_NON_NEGATIVE, + lnbad, 'nbad', CONS_NON_NEGATIVE, + lnsample, 'nsample', CONS_GTE_1) + + if np.any(np.less(np.add(ongood, onbad),onsample)): + raise ValueError("ngood + nbad < nsample") + return discrete_broadcast_iii(&random_hypergeometric, self._prng, size, self.lock, + ongood, 'ngood', CONS_NON_NEGATIVE, + onbad, nbad, CONS_NON_NEGATIVE, + onsample, 'nsample', CONS_GTE_1) + + def logseries(self, p, size=None): + """ + logseries(p, size=None) + + Draw samples from a logarithmic series distribution. + + Samples are drawn from a log series distribution with specified + shape parameter, 0 < ``p`` < 1. + + Parameters + ---------- + p : float or array_like of floats + Shape parameter for the distribution. Must be in the range (0, 1). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``p`` is a scalar. Otherwise, + ``np.array(p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized logarithmic series distribution. + + See Also + -------- + scipy.stats.logser : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Log Series distribution is + + .. math:: P(k) = \\frac{-p^k}{k \\ln(1-p)}, + + where p = probability. + + The log series distribution is frequently used to represent species + richness and occurrence, first proposed by Fisher, Corbet, and + Williams in 1943 [2]. It may also be used to model the numbers of + occupants seen in cars [3]. + + References + ---------- + .. [1] Buzas, Martin A.; Culver, Stephen J., Understanding regional + species diversity through the log series distribution of + occurrences: BIODIVERSITY RESEARCH Diversity & Distributions, + Volume 5, Number 5, September 1999 , pp. 187-195(9). + .. [2] Fisher, R.A,, A.S. Corbet, and C.B. Williams. 1943. The + relation between the number of species and the number of + individuals in a random sample of an animal population. + Journal of Animal Ecology, 12:42-58. + .. [3] D. J. Hand, F. Daly, D. Lunn, E. Ostrowski, A Handbook of Small + Data Sets, CRC Press, 1994. + .. [4] Wikipedia, "Logarithmic distribution", + http://en.wikipedia.org/wiki/Logarithmic_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a = .6 + >>> s = np.random.logseries(a, 10000) + >>> count, bins, ignored = plt.hist(s) + + # plot against distribution + + >>> def logseries(k, p): + ... return -p**k/(k*log(1-p)) + >>> plt.plot(bins, logseries(bins, a)*count.max()/ + logseries(bins, a).max(), 'r') + >>> plt.show() + + """ + return disc(&random_logseries, self._prng, size, self.lock, 1, 0, + p, 'p', CONS_BOUNDED_0_1, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) + + # Multivariate distributions: + def multivariate_normal(self, mean, cov, size=None, check_valid='warn', + tol=1e-8, method=u'zig'): + """ + multivariate_normal(self, mean, cov, size=None, check_valid='warn', + tol=1e-8, method='zig') + + Draw random samples from a multivariate normal distribution. + + The multivariate normal, multinormal or Gaussian distribution is a + generalization of the one-dimensional normal distribution to higher + dimensions. Such a distribution is specified by its mean and + covariance matrix. These parameters are analogous to the mean + (average or "center") and variance (standard deviation, or "width," + squared) of the one-dimensional normal distribution. + + Parameters + ---------- + mean : 1-D array_like, of length N + Mean of the N-dimensional distribution. + cov : 2-D array_like, of shape (N, N) + Covariance matrix of the distribution. It must be symmetric and + positive-semidefinite for proper sampling. + size : int or tuple of ints, optional + Given a shape of, for example, ``(m,n,k)``, ``m*n*k`` samples are + generated, and packed in an `m`-by-`n`-by-`k` arrangement. Because + each sample is `N`-dimensional, the output shape is ``(m,n,k,N)``. + If no shape is specified, a single (`N`-D) sample is returned. + check_valid : { 'warn', 'raise', 'ignore' }, optional + Behavior when the covariance matrix is not positive semidefinite. + tol : float, optional + Tolerance when checking the singular values in covariance matrix. + method : str, optional + Either 'bm' or 'zig'. 'bm' uses the default Box-Muller transformations + method. 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. + + Returns + ------- + out : ndarray + The drawn samples, of shape *size*, if that was provided. If not, + the shape is ``(N,)``. + + In other words, each entry ``out[i,j,...,:]`` is an N-dimensional + value drawn from the distribution. + + Notes + ----- + The mean is a coordinate in N-dimensional space, which represents the + location where samples are most likely to be generated. This is + analogous to the peak of the bell curve for the one-dimensional or + univariate normal distribution. + + Covariance indicates the level to which two variables vary together. + From the multivariate normal distribution, we draw N-dimensional + samples, :math:`X = [x_1, x_2, ... x_N]`. The covariance matrix + element :math:`C_{ij}` is the covariance of :math:`x_i` and :math:`x_j`. + The element :math:`C_{ii}` is the variance of :math:`x_i` (i.e. its + "spread"). + + Instead of specifying the full covariance matrix, popular + approximations include: + + - Spherical covariance (`cov` is a multiple of the identity matrix) + - Diagonal covariance (`cov` has non-negative elements, and only on + the diagonal) + + This geometrical property can be seen in two dimensions by plotting + generated data-points: + + >>> mean = [0, 0] + >>> cov = [[1, 0], [0, 100]] # diagonal covariance + + Diagonal covariance means that points are oriented along x or y-axis: + + >>> import matplotlib.pyplot as plt + >>> x, y = np.random.multivariate_normal(mean, cov, 5000).T + >>> plt.plot(x, y, 'x') + >>> plt.axis('equal') + >>> plt.show() + + Note that the covariance matrix must be positive semidefinite (a.k.a. + nonnegative-definite). Otherwise, the behavior of this method is + undefined and backwards compatibility is not guaranteed. + + References + ---------- + .. [1] Papoulis, A., "Probability, Random Variables, and Stochastic + Processes," 3rd ed., New York: McGraw-Hill, 1991. + .. [2] Duda, R. O., Hart, P. E., and Stork, D. G., "Pattern + Classification," 2nd ed., New York: Wiley, 2001. + + Examples + -------- + >>> mean = (1, 2) + >>> cov = [[1, 0], [0, 1]] + >>> x = np.random.multivariate_normal(mean, cov, (3, 3)) + >>> x.shape + (3, 3, 2) + + The following is probably true, given that 0.6 is roughly twice the + standard deviation: + + >>> list((x[0,0,:] - mean) < 0.6) + [True, True] + + """ + from numpy.dual import svd + + # Check preconditions on arguments + mean = np.array(mean) + cov = np.array(cov) + if size is None: + shape = [] + elif isinstance(size, (int, long, np.integer)): + shape = [size] + else: + shape = size + + if len(mean.shape) != 1: + raise ValueError("mean must be 1 dimensional") + if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + raise ValueError("cov must be 2 dimensional and square") + if mean.shape[0] != cov.shape[0]: + raise ValueError("mean and cov must have same length") + + # Compute shape of output and create a matrix of independent + # standard normally distributed random numbers. The matrix has rows + # with the same length as mean and as many rows are necessary to + # form a matrix of shape final_shape. + final_shape = list(shape[:]) + final_shape.append(mean.shape[0]) + x = self.standard_normal(final_shape, method=method).reshape(-1, mean.shape[0]) + + # Transform matrix of standard normals into matrix where each row + # contains multivariate normals with the desired covariance. + # Compute A such that dot(transpose(A),A) == cov. + # Then the matrix products of the rows of x and A has the desired + # covariance. Note that sqrt(s)*v where (u,s,v) is the singular value + # decomposition of cov is such an A. + # + # Also check that cov is positive-semidefinite. If so, the u.T and v + # matrices should be equal up to roundoff error if cov is + # symmetrical and the singular value of the corresponding row is + # not zero. We continue to use the SVD rather than Cholesky in + # order to preserve current outputs. Note that symmetry has not + # been checked. + + (u, s, v) = svd(cov) + + if check_valid != 'ignore': + if check_valid != 'warn' and check_valid != 'raise': + raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") + + psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) + if not psd: + if check_valid == 'warn': + warnings.warn("covariance is not positive-semidefinite.", + RuntimeWarning) + else: + raise ValueError("covariance is not positive-semidefinite.") + + x = np.dot(x, np.sqrt(s)[:, None] * v) + x += mean + x.shape = tuple(final_shape) + return x + + def multinomial(self, np.npy_intp n, object pvals, size=None): + """ + multinomial(n, pvals, size=None) + + Draw samples from a multinomial distribution. + + The multinomial distribution is a multivariate generalisation of the + binomial distribution. Take an experiment with one of ``p`` + possible outcomes. An example of such an experiment is throwing a dice, + where the outcome can be 1 through 6. Each sample drawn from the + distribution represents `n` such experiments. Its values, + ``X_i = [X_0, X_1, ..., X_p]``, represent the number of times the + outcome was ``i``. + + Parameters + ---------- + n : int + Number of experiments. + pvals : sequence of floats, length p + Probabilities of each of the ``p`` different outcomes. These + should sum to 1 (however, the last element is always assumed to + account for the remaining probability, as long as + ``sum(pvals[:-1]) <= 1)``. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : ndarray + The drawn samples, of shape *size*, if that was provided. If not, + the shape is ``(N,)``. + + In other words, each entry ``out[i,j,...,:]`` is an N-dimensional + value drawn from the distribution. + + Examples + -------- + Throw a dice 20 times: + + >>> np.random.multinomial(20, [1/6.]*6, size=1) + array([[4, 1, 7, 5, 2, 1]]) + + It landed 4 times on 1, once on 2, etc. + + Now, throw the dice 20 times, and 20 times again: + + >>> np.random.multinomial(20, [1/6.]*6, size=2) + array([[3, 4, 3, 3, 4, 3], + [2, 4, 3, 4, 0, 7]]) + + For the first run, we threw 3 times 1, 4 times 2, etc. For the second, + we threw 2 times 1, 4 times 2, etc. + + A loaded die is more likely to land on number 6: + + >>> np.random.multinomial(100, [1/7.]*5 + [2/7.]) + array([11, 16, 14, 17, 16, 26]) + + The probability inputs should be normalized. As an implementation + detail, the value of the last entry is ignored and assumed to take + up any leftover probability mass, but this should not be relied on. + A biased coin which has twice as much weight on one side as on the + other should be sampled like so: + + >>> np.random.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT + array([38, 62]) + + not like: + + >>> np.random.multinomial(100, [1.0, 2.0]) # WRONG + array([100, 0]) + + """ + cdef np.npy_intp d + cdef np.ndarray parr "arrayObject_parr", mnarr "arrayObject_mnarr" + cdef double *pix + cdef long *mnix + cdef np.npy_intp i, j, dn, sz + cdef double Sum + + d = len(pvals) + parr = np.PyArray_FROM_OTF(pvals, np.NPY_DOUBLE, np.NPY_ALIGNED) + pix = np.PyArray_DATA(parr) + + if kahan_sum(pix, d-1) > (1.0 + 1e-12): + raise ValueError("sum(pvals[:-1]) > 1.0") + + if size is None: + shape = (d,) + else: + try: + shape = (operator.index(size), d) + except: + shape = tuple(size) + (d,) + + multin = np.zeros(shape, dtype=np.int) + mnarr = multin + mnix = np.PyArray_DATA(mnarr) + sz = np.PyArray_SIZE(mnarr) + + with self.lock, nogil: + i = 0 + while i < sz: + Sum = 1.0 + dn = n + for j in range(d-1): + mnix[i+j] = random_binomial(self._prng, pix[j]/Sum, dn) + dn = dn - mnix[i+j] + if dn <= 0: + break + Sum = Sum - pix[j] + if dn > 0: + mnix[i+d-1] = dn + + i = i + d + + return multin + + def dirichlet(self, object alpha, size=None): + """ + dirichlet(alpha, size=None) + + Draw samples from the Dirichlet distribution. + + Draw `size` samples of dimension k from a Dirichlet distribution. A + Dirichlet-distributed random variable can be seen as a multivariate + generalization of a Beta distribution. Dirichlet pdf is the conjugate + prior of a multinomial in Bayesian inference. + + Parameters + ---------- + alpha : array + Parameter of the distribution (k dimension for sample of + dimension k). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + samples : ndarray, + The drawn samples, of shape (size, alpha.ndim). + + Notes + ----- + .. math:: X \\approx \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i} + + Uses the following property for computation: for each dimension, + draw a random sample y_i from a standard gamma generator of shape + `alpha_i`, then + :math:`X = \\frac{1}{\\sum_{i=1}^k{y_i}} (y_1, \\ldots, y_n)` is + Dirichlet distributed. + + References + ---------- + .. [1] David McKay, "Information Theory, Inference and Learning + Algorithms," chapter 23, + http://www.inference.phy.cam.ac.uk/mackay/ + .. [2] Wikipedia, "Dirichlet distribution", + http://en.wikipedia.org/wiki/Dirichlet_distribution + + Examples + -------- + Taking an example cited in Wikipedia, this distribution can be used if + one wanted to cut strings (each of initial length 1.0) into K pieces + with different lengths, where each piece had, on average, a designated + average length, but allowing some variation in the relative sizes of + the pieces. + + >>> s = np.random.dirichlet((10, 5, 3), 20).transpose() + + >>> plt.barh(range(20), s[0]) + >>> plt.barh(range(20), s[1], left=s[0], color='g') + >>> plt.barh(range(20), s[2], left=s[0]+s[1], color='r') + >>> plt.title("Lengths of Strings") + + """ + + #================= + # Pure python algo + #================= + #alpha = N.atleast_1d(alpha) + #k = alpha.size + + #if n == 1: + # val = N.zeros(k) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val) + #else: + # val = N.zeros((k, n)) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val, axis = 0) + # val = val.T + + #return val + + cdef np.npy_intp k + cdef np.npy_intp totsize + cdef np.ndarray alpha_arr, val_arr + cdef double *alpha_data + cdef double *val_data + cdef np.npy_intp i, j + cdef double acc, invacc + + k = len(alpha) + alpha_arr = np.PyArray_FROM_OTF(alpha, np.NPY_DOUBLE, np.NPY_ALIGNED) + if np.any(np.less_equal(alpha_arr, 0)): + raise ValueError('alpha <= 0') + alpha_data = np.PyArray_DATA(alpha_arr) + + if size is None: + shape = (k,) + else: + try: + shape = (operator.index(size), k) + except: + shape = tuple(size) + (k,) + + diric = np.zeros(shape, np.float64) + val_arr = diric + val_data= np.PyArray_DATA(val_arr) + + i = 0 + totsize = np.PyArray_SIZE(val_arr) + with self.lock, nogil: + while i < totsize: + acc = 0.0 + for j in range(k): + val_data[i+j] = random_standard_gamma(self._prng, alpha_data[j]) + acc = acc + val_data[i + j] + invacc = 1/acc + for j in range(k): + val_data[i + j] = val_data[i + j] * invacc + i = i + k + + return diric + + # Shuffling and permutations: + def shuffle(self, object x): + """ + shuffle(x) + + Modify a sequence in-place by shuffling its contents. + + This function only shuffles the array along the first axis of a + multi-dimensional array. The order of sub-arrays is changed but + their contents remains the same. + + Parameters + ---------- + x : array_like + The array or list to be shuffled. + + Returns + ------- + None + + Examples + -------- + >>> arr = np.arange(10) + >>> np.random.shuffle(arr) + >>> arr + [1 7 5 2 9 4 3 6 0 8] + + Multi-dimensional arrays are only shuffled along the first axis: + + >>> arr = np.arange(9).reshape((3, 3)) + >>> np.random.shuffle(arr) + >>> arr + array([[3, 4, 5], + [6, 7, 8], + [0, 1, 2]]) + + """ + cdef: + np.npy_intp i, j, n = len(x), stride, itemsize + char* x_ptr + char* buf_ptr + + if type(x) is np.ndarray and x.ndim == 1 and x.size: + # Fast, statically typed path: shuffle the underlying buffer. + # Only for non-empty, 1d objects of class ndarray (subclasses such + # as MaskedArrays may not support this approach). + x_ptr = x.ctypes.data + stride = x.strides[0] + itemsize = x.dtype.itemsize + # As the array x could contain python objects we use a buffer + # of bytes for the swaps to avoid leaving one of the objects + # within the buffer and erroneously decrementing it's refcount + # when the function exits. + buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit + buf_ptr = buf.ctypes.data + with self.lock: + # We trick gcc into providing a specialized implementation for + # the most common case, yielding a ~33% performance improvement. + # Note that apparently, only one branch can ever be specialized. + if itemsize == sizeof(np.npy_intp): + self._shuffle_raw(n, sizeof(np.npy_intp), stride, x_ptr, buf_ptr) + else: + self._shuffle_raw(n, itemsize, stride, x_ptr, buf_ptr) + elif isinstance(x, np.ndarray) and x.ndim > 1 and x.size: + # Multidimensional ndarrays require a bounce buffer. + buf = np.empty_like(x[0]) + with self.lock: + for i in reversed(range(1, n)): + j = random_interval(self._prng, i) + if i == j : continue # i == j is not needed and memcpy is undefined. + buf[...] = x[j] + x[j] = x[i] + x[i] = buf + else: + # Untyped path. + with self.lock: + for i in reversed(range(1, n)): + j = random_interval(self._prng, i) + x[i], x[j] = x[j], x[i] + + cdef inline _shuffle_raw(self, np.npy_intp n, np.npy_intp itemsize, + np.npy_intp stride, char* data, char* buf): + cdef np.npy_intp i, j + for i in reversed(range(1, n)): + j = random_interval(self._prng, i) + string.memcpy(buf, data + j * stride, itemsize) + string.memcpy(data + j * stride, data + i * stride, itemsize) + string.memcpy(data + i * stride, buf, itemsize) + + def permutation(self, object x): + """ + permutation(x) + + Randomly permute a sequence, or return a permuted range. + + If `x` is a multi-dimensional array, it is only shuffled along its + first index. + + Parameters + ---------- + x : int or array_like + If `x` is an integer, randomly permute ``np.arange(x)``. + If `x` is an array, make a copy and shuffle the elements + randomly. + + Returns + ------- + out : ndarray + Permuted sequence or array range. + + Examples + -------- + >>> np.random.permutation(10) + array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) + + >>> np.random.permutation([1, 4, 9, 12, 15]) + array([15, 1, 9, 4, 12]) + + >>> arr = np.arange(9).reshape((3, 3)) + >>> np.random.permutation(arr) + array([[6, 7, 8], + [0, 1, 2], + [3, 4, 5]]) + + """ + if isinstance(x, (int, long, np.integer)): + arr = np.arange(x) + else: + arr = np.array(x) + self.shuffle(arr) + return arr diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index 5c09709921e2..230a29a74b5a 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -64,6 +64,7 @@ cdef class MT19937: self._prng.next_uint64 = &mt19937_uint64 self._prng.next_uint32 = &mt19937_uint32 self._prng.next_double = &mt19937_double + self._prng.next_raw = &mt19937_uint64 cdef const char *name = "CorePRNG" self.capsule = PyCapsule_New(self._prng, name, NULL) diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx index ce9e47be9e73..2765334cf050 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/core_prng/philox.pyx @@ -82,6 +82,7 @@ cdef class Philox: self._prng.next_uint64 = &philox_uint64 self._prng.next_uint32 = &philox_uint32 self._prng.next_double = &philox_double + self._prng.next_raw = &philox_uint64 cdef const char *name = 'CorePRNG' self.capsule = PyCapsule_New( self._prng, name, NULL) diff --git a/_randomgen/core_prng/src/aligned_malloc/aligned_malloc.c b/_randomgen/core_prng/src/aligned_malloc/aligned_malloc.c new file mode 100644 index 000000000000..6e8192cfbeed --- /dev/null +++ b/_randomgen/core_prng/src/aligned_malloc/aligned_malloc.c @@ -0,0 +1,9 @@ +#include "aligned_malloc.h" + +static NPY_INLINE void *PyArray_realloc_aligned(void *p, size_t n); + +static NPY_INLINE void *PyArray_malloc_aligned(size_t n); + +static NPY_INLINE void *PyArray_calloc_aligned(size_t n, size_t s); + +static NPY_INLINE void PyArray_free_aligned(void *p); \ No newline at end of file diff --git a/_randomgen/core_prng/src/aligned_malloc/aligned_malloc.h b/_randomgen/core_prng/src/aligned_malloc/aligned_malloc.h new file mode 100644 index 000000000000..55716525338b --- /dev/null +++ b/_randomgen/core_prng/src/aligned_malloc/aligned_malloc.h @@ -0,0 +1,49 @@ +#include "Python.h" +#include "numpy/npy_common.h" + +#define NPY_MEMALIGN 16 /* 16 for SSE2, 32 for AVX, 64 for Xeon Phi */ + +static NPY_INLINE void *PyArray_realloc_aligned(void *p, size_t n) +{ + void *p1, **p2, *base; + size_t old_offs, offs = NPY_MEMALIGN - 1 + sizeof(void *); + if (NPY_UNLIKELY(p != NULL)) + { + base = *(((void **)p) - 1); + if (NPY_UNLIKELY((p1 = PyMem_Realloc(base, n + offs)) == NULL)) + return NULL; + if (NPY_LIKELY(p1 == base)) + return p; + p2 = (void **)(((Py_uintptr_t)(p1) + offs) & ~(NPY_MEMALIGN - 1)); + old_offs = (size_t)((Py_uintptr_t)p - (Py_uintptr_t)base); + memmove((void *)p2, ((char *)p1) + old_offs, n); + } + else + { + if (NPY_UNLIKELY((p1 = PyMem_Malloc(n + offs)) == NULL)) + return NULL; + p2 = (void **)(((Py_uintptr_t)(p1) + offs) & ~(NPY_MEMALIGN - 1)); + } + *(p2 - 1) = p1; + return (void *)p2; +} + +static NPY_INLINE void *PyArray_malloc_aligned(size_t n) +{ + return PyArray_realloc_aligned(NULL, n); +} + +static NPY_INLINE void *PyArray_calloc_aligned(size_t n, size_t s) +{ + void *p; + if (NPY_UNLIKELY((p = PyArray_realloc_aligned(NULL, n * s)) == NULL)) + return NULL; + memset(p, 0, n * s); + return p; +} + +static NPY_INLINE void PyArray_free_aligned(void *p) +{ + void *base = *(((void **)p) - 1); + PyMem_Free(base); +} \ No newline at end of file diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 40b24472747b..3edc59261041 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -11,6 +11,10 @@ uint32_t random_uint32(prng_t *prng_state) { return prng_state->next_uint32(prng_state->state); } +static NPY_INLINE uint64_t random_uint64(prng_t *prng_state) { + return prng_state->next_uint64(prng_state->state); +} + float random_sample_f(prng_t *prng_state) { return next_float(prng_state); } double random_sample(prng_t *prng_state) { @@ -392,3 +396,992 @@ double random_standard_gamma_zig(prng_t *prng_state, double shape) { float random_standard_gamma_zig_f(prng_t *prng_state, float shape) { return standard_gamma_zig_f(prng_state, shape); } + +int64_t random_positive_int64(prng_t *prng_state) { + return prng_state->next_uint64(prng_state->state) >> 1; +} + +int32_t random_positive_int32(prng_t *prng_state) { + return prng_state->next_uint32(prng_state->state) >> 1; +} + +long random_positive_int(prng_t *prng_state) { +#if ULONG_MAX <= 0xffffffffUL + return (long)(prng_state->next_uint32(prng_state->state) >> 1); +#else + return (long)(prng_state->next_uint64(prng_state->state) >> 1); +#endif +} + +unsigned long random_uint(prng_t *prng_state) { +#if ULONG_MAX <= 0xffffffffUL + return prng_state->next_uint32(prng_state->state); +#else + return prng_state->next_uint64(prng_state->state); +#endif +} + +/* + * log-gamma function to support some of these distributions. The + * algorithm comes from SPECFUN by Shanjie Zhang and Jianming Jin and their + * book "Computation of Special Functions", 1996, John Wiley & Sons, Inc. + */ +static double loggam(double x) { + double x0, x2, xp, gl, gl0; + long k, n; + + static double a[10] = {8.333333333333333e-02, -2.777777777777778e-03, + 7.936507936507937e-04, -5.952380952380952e-04, + 8.417508417508418e-04, -1.917526917526918e-03, + 6.410256410256410e-03, -2.955065359477124e-02, + 1.796443723688307e-01, -1.39243221690590e+00}; + x0 = x; + n = 0; + if ((x == 1.0) || (x == 2.0)) { + return 0.0; + } else if (x <= 7.0) { + n = (long)(7 - x); + x0 = x + n; + } + x2 = 1.0 / (x0 * x0); + xp = 2 * M_PI; + gl0 = a[9]; + for (k = 8; k >= 0; k--) { + gl0 *= x2; + gl0 += a[k]; + } + gl = gl0 / x0 + 0.5 * log(xp) + (x0 - 0.5) * log(x0) - x0; + if (x <= 7.0) { + for (k = 1; k <= n; k++) { + gl -= log(x0 - 1.0); + x0 -= 1.0; + } + } + return gl; +} + +double random_normal(prng_t *prng_state, double loc, double scale) { + return loc + scale * random_gauss(prng_state); +} + +double random_normal_zig(prng_t *prng_state, double loc, double scale) { + return loc + scale * random_gauss_zig(prng_state); +} + +double random_exponential(prng_t *prng_state, double scale) { + return scale * random_standard_exponential(prng_state); +} + +double random_uniform(prng_t *prng_state, double lower, double range) { + return lower + range * random_sample(prng_state); +} + +double random_gamma(prng_t *prng_state, double shape, double scale) { + return scale * random_standard_gamma(prng_state, shape); +} + +float random_gamma_float(prng_t *prng_state, float shape, float scale) { + return scale * random_standard_gamma_f(prng_state, shape); +} + +double random_beta(prng_t *prng_state, double a, double b) { + double Ga, Gb; + + if ((a <= 1.0) && (b <= 1.0)) { + double U, V, X, Y; + /* Use Johnk's algorithm */ + + while (1) { + U = random_sample(prng_state); + V = random_sample(prng_state); + X = pow(U, 1.0 / a); + Y = pow(V, 1.0 / b); + + if ((X + Y) <= 1.0) { + if (X + Y > 0) { + return X / (X + Y); + } else { + double logX = log(U) / a; + double logY = log(V) / b; + double logM = logX > logY ? logX : logY; + logX -= logM; + logY -= logM; + + return exp(logX - log(exp(logX) + exp(logY))); + } + } + } + } else { + Ga = random_standard_gamma(prng_state, a); + Gb = random_standard_gamma(prng_state, b); + return Ga / (Ga + Gb); + } +} + +double random_chisquare(prng_t *prng_state, double df) { + return 2.0 * random_standard_gamma(prng_state, df / 2.0); +} + +double random_f(prng_t *prng_state, double dfnum, double dfden) { + return ((random_chisquare(prng_state, dfnum) * dfden) / + (random_chisquare(prng_state, dfden) * dfnum)); +} + +double random_standard_cauchy(prng_t *prng_state) { + return random_gauss(prng_state) / random_gauss(prng_state); +} + +double random_pareto(prng_t *prng_state, double a) { + return exp(random_standard_exponential(prng_state) / a) - 1; +} + +double random_weibull(prng_t *prng_state, double a) { + return pow(random_standard_exponential(prng_state), 1. / a); +} + +double random_power(prng_t *prng_state, double a) { + return pow(1 - exp(-random_standard_exponential(prng_state)), 1. / a); +} + +double random_laplace(prng_t *prng_state, double loc, double scale) { + double U; + + U = random_sample(prng_state); + if (U < 0.5) { + U = loc + scale * log(U + U); + } else { + U = loc - scale * log(2.0 - U - U); + } + return U; +} + +double random_gumbel(prng_t *prng_state, double loc, double scale) { + double U; + + U = 1.0 - random_sample(prng_state); + return loc - scale * log(-log(U)); +} + +double random_logistic(prng_t *prng_state, double loc, double scale) { + double U; + + U = random_sample(prng_state); + return loc + scale * log(U / (1.0 - U)); +} + +double random_lognormal(prng_t *prng_state, double mean, double sigma) { + return exp(random_normal(prng_state, mean, sigma)); +} + +double random_rayleigh(prng_t *prng_state, double mode) { + return mode * sqrt(-2.0 * log(1.0 - random_sample(prng_state))); +} + +double random_standard_t(prng_t *prng_state, double df) { + double num, denom; + + num = random_gauss(prng_state); + denom = random_standard_gamma(prng_state, df / 2); + return sqrt(df / 2) * num / sqrt(denom); +} + +static long random_poisson_mult(prng_t *prng_state, double lam) { + long X; + double prod, U, enlam; + + enlam = exp(-lam); + X = 0; + prod = 1.0; + while (1) { + U = random_sample(prng_state); + prod *= U; + if (prod > enlam) { + X += 1; + } else { + return X; + } + } +} + +/* + * The transformed rejection method for generating Poisson random variables + * W. Hoermann + * Insurance: Mathematics and Economics 12, 39-45 (1993) + */ +#define LS2PI 0.91893853320467267 +#define TWELFTH 0.083333333333333333333333 +static long random_poisson_ptrs(prng_t *prng_state, double lam) { + long k; + double U, V, slam, loglam, a, b, invalpha, vr, us; + + slam = sqrt(lam); + loglam = log(lam); + b = 0.931 + 2.53 * slam; + a = -0.059 + 0.02483 * b; + invalpha = 1.1239 + 1.1328 / (b - 3.4); + vr = 0.9277 - 3.6224 / (b - 2); + + while (1) { + U = random_sample(prng_state) - 0.5; + V = random_sample(prng_state); + us = 0.5 - fabs(U); + k = (long)floor((2 * a / us + b) * U + lam + 0.43); + if ((us >= 0.07) && (V <= vr)) { + return k; + } + if ((k < 0) || ((us < 0.013) && (V > us))) { + continue; + } + if ((log(V) + log(invalpha) - log(a / (us * us) + b)) <= + (-lam + k * loglam - loggam(k + 1))) { + return k; + } + } +} + +long random_poisson(prng_t *prng_state, double lam) { + if (lam >= 10) { + return random_poisson_ptrs(prng_state, lam); + } else if (lam == 0) { + return 0; + } else { + return random_poisson_mult(prng_state, lam); + } +} + +long random_negative_binomial(prng_t *prng_state, double n, double p) { + double Y = random_gamma(prng_state, n, (1 - p) / p); + return random_poisson(prng_state, Y); +} + +long random_binomial_btpe(prng_t *prng_state, long n, double p) { + double r, q, fm, p1, xm, xl, xr, c, laml, lamr, p2, p3, p4; + double a, u, v, s, F, rho, t, A, nrq, x1, x2, f1, f2, z, z2, w, w2, x; + long m, y, k, i; + + if (!(prng_state->binomial->has_binomial) || + (prng_state->binomial->nsave != n) || + (prng_state->binomial->psave != p)) { + /* initialize */ + prng_state->binomial->nsave = n; + prng_state->binomial->psave = p; + prng_state->binomial->has_binomial = 1; + prng_state->binomial->r = r = min(p, 1.0 - p); + prng_state->binomial->q = q = 1.0 - r; + prng_state->binomial->fm = fm = n * r + r; + prng_state->binomial->m = m = (long)floor(prng_state->binomial->fm); + prng_state->binomial->p1 = p1 = + floor(2.195 * sqrt(n * r * q) - 4.6 * q) + 0.5; + prng_state->binomial->xm = xm = m + 0.5; + prng_state->binomial->xl = xl = xm - p1; + prng_state->binomial->xr = xr = xm + p1; + prng_state->binomial->c = c = 0.134 + 20.5 / (15.3 + m); + a = (fm - xl) / (fm - xl * r); + prng_state->binomial->laml = laml = a * (1.0 + a / 2.0); + a = (xr - fm) / (xr * q); + prng_state->binomial->lamr = lamr = a * (1.0 + a / 2.0); + prng_state->binomial->p2 = p2 = p1 * (1.0 + 2.0 * c); + prng_state->binomial->p3 = p3 = p2 + c / laml; + prng_state->binomial->p4 = p4 = p3 + c / lamr; + } else { + r = prng_state->binomial->r; + q = prng_state->binomial->q; + fm = prng_state->binomial->fm; + m = prng_state->binomial->m; + p1 = prng_state->binomial->p1; + xm = prng_state->binomial->xm; + xl = prng_state->binomial->xl; + xr = prng_state->binomial->xr; + c = prng_state->binomial->c; + laml = prng_state->binomial->laml; + lamr = prng_state->binomial->lamr; + p2 = prng_state->binomial->p2; + p3 = prng_state->binomial->p3; + p4 = prng_state->binomial->p4; + } + +/* sigh ... */ +Step10: + nrq = n * r * q; + u = random_sample(prng_state) * p4; + v = random_sample(prng_state); + if (u > p1) + goto Step20; + y = (long)floor(xm - p1 * v + u); + goto Step60; + +Step20: + if (u > p2) + goto Step30; + x = xl + (u - p1) / c; + v = v * c + 1.0 - fabs(m - x + 0.5) / p1; + if (v > 1.0) + goto Step10; + y = (long)floor(x); + goto Step50; + +Step30: + if (u > p3) + goto Step40; + y = (long)floor(xl + log(v) / laml); + if (y < 0) + goto Step10; + v = v * (u - p2) * laml; + goto Step50; + +Step40: + y = (long)floor(xr - log(v) / lamr); + if (y > n) + goto Step10; + v = v * (u - p3) * lamr; + +Step50: + k = labs(y - m); + if ((k > 20) && (k < ((nrq) / 2.0 - 1))) + goto Step52; + + s = r / q; + a = s * (n + 1); + F = 1.0; + if (m < y) { + for (i = m + 1; i <= y; i++) { + F *= (a / i - s); + } + } else if (m > y) { + for (i = y + 1; i <= m; i++) { + F /= (a / i - s); + } + } + if (v > F) + goto Step10; + goto Step60; + +Step52: + rho = + (k / (nrq)) * ((k * (k / 3.0 + 0.625) + 0.16666666666666666) / nrq + 0.5); + t = -k * k / (2 * nrq); + A = log(v); + if (A < (t - rho)) + goto Step60; + if (A > (t + rho)) + goto Step10; + + x1 = y + 1; + f1 = m + 1; + z = n + 1 - m; + w = n - y + 1; + x2 = x1 * x1; + f2 = f1 * f1; + z2 = z * z; + w2 = w * w; + if (A > (xm * log(f1 / x1) + (n - m + 0.5) * log(z / w) + + (y - m) * log(w * r / (x1 * q)) + + (13680. - (462. - (132. - (99. - 140. / f2) / f2) / f2) / f2) / f1 / + 166320. + + (13680. - (462. - (132. - (99. - 140. / z2) / z2) / z2) / z2) / z / + 166320. + + (13680. - (462. - (132. - (99. - 140. / x2) / x2) / x2) / x2) / x1 / + 166320. + + (13680. - (462. - (132. - (99. - 140. / w2) / w2) / w2) / w2) / w / + 166320.)) { + goto Step10; + } + +Step60: + if (p > 0.5) { + y = n - y; + } + + return y; +} + +long random_binomial_inversion(prng_t *prng_state, long n, double p) { + double q, qn, np, px, U; + long X, bound; + + if (!(prng_state->binomial->has_binomial) || + (prng_state->binomial->nsave != n) || + (prng_state->binomial->psave != p)) { + prng_state->binomial->nsave = n; + prng_state->binomial->psave = p; + prng_state->binomial->has_binomial = 1; + prng_state->binomial->q = q = 1.0 - p; + prng_state->binomial->r = qn = exp(n * log(q)); + prng_state->binomial->c = np = n * p; + prng_state->binomial->m = bound = + (long)min(n, np + 10.0 * sqrt(np * q + 1)); + } else { + q = prng_state->binomial->q; + qn = prng_state->binomial->r; + np = prng_state->binomial->c; + bound = prng_state->binomial->m; + } + X = 0; + px = qn; + U = random_sample(prng_state); + while (U > px) { + X++; + if (X > bound) { + X = 0; + px = qn; + U = random_sample(prng_state); + } else { + U -= px; + px = ((n - X + 1) * p * px) / (X * q); + } + } + return X; +} + +long random_binomial(prng_t *prng_state, double p, long n) { + double q; + + if (p <= 0.5) { + if (p * n <= 30.0) { + return random_binomial_inversion(prng_state, n, p); + } else { + return random_binomial_btpe(prng_state, n, p); + } + } else { + q = 1.0 - p; + if (q * n <= 30.0) { + return n - random_binomial_inversion(prng_state, n, q); + } else { + return n - random_binomial_btpe(prng_state, n, q); + } + } +} + +double random_noncentral_chisquare(prng_t *prng_state, double df, double nonc) { + if (nonc == 0) { + return random_chisquare(prng_state, df); + } + if (1 < df) { + const double Chi2 = random_chisquare(prng_state, df - 1); + const double n = random_gauss(prng_state) + sqrt(nonc); + return Chi2 + n * n; + } else { + const long i = random_poisson(prng_state, nonc / 2.0); + return random_chisquare(prng_state, df + 2 * i); + } +} + +double random_noncentral_f(prng_t *prng_state, double dfnum, double dfden, + double nonc) { + double t = random_noncentral_chisquare(prng_state, dfnum, nonc) * dfden; + return t / (random_chisquare(prng_state, dfden) * dfnum); +} + +double random_wald(prng_t *prng_state, double mean, double scale) { + double U, X, Y; + double mu_2l; + + mu_2l = mean / (2 * scale); + Y = random_gauss(prng_state); + Y = mean * Y * Y; + X = mean + mu_2l * (Y - sqrt(4 * scale * Y + Y * Y)); + U = random_sample(prng_state); + if (U <= mean / (mean + X)) { + return X; + } else { + return mean * mean / X; + } +} + +double random_vonmises(prng_t *prng_state, double mu, double kappa) { + double s; + double U, V, W, Y, Z; + double result, mod; + int neg; + + if (kappa < 1e-8) { + return M_PI * (2 * random_sample(prng_state) - 1); + } else { + /* with double precision rho is zero until 1.4e-8 */ + if (kappa < 1e-5) { + /* + * second order taylor expansion around kappa = 0 + * precise until relatively large kappas as second order is 0 + */ + s = (1. / kappa + kappa); + } else { + double r = 1 + sqrt(1 + 4 * kappa * kappa); + double rho = (r - sqrt(2 * r)) / (2 * kappa); + s = (1 + rho * rho) / (2 * rho); + } + + while (1) { + U = random_sample(prng_state); + Z = cos(M_PI * U); + W = (1 + s * Z) / (s + Z); + Y = kappa * (s - W); + V = random_sample(prng_state); + if ((Y * (2 - Y) - V >= 0) || (log(Y / V) + 1 - Y >= 0)) { + break; + } + } + + U = random_sample(prng_state); + + result = acos(W); + if (U < 0.5) { + result = -result; + } + result += mu; + neg = (result < 0); + mod = fabs(result); + mod = (fmod(mod + M_PI, 2 * M_PI) - M_PI); + if (neg) { + mod *= -1; + } + + return mod; + } +} + +long random_logseries(prng_t *prng_state, double p) { + double q, r, U, V; + long result; + + r = log(1.0 - p); + + while (1) { + V = random_sample(prng_state); + if (V >= p) { + return 1; + } + U = random_sample(prng_state); + q = 1.0 - exp(r * U); + if (V <= q * q) { + result = (long)floor(1 + log(V) / log(q)); + if (result < 1) { + continue; + } else { + return result; + } + } + if (V >= q) { + return 1; + } + return 2; + } +} + +long random_geometric_search(prng_t *prng_state, double p) { + double U; + long X; + double sum, prod, q; + + X = 1; + sum = prod = p; + q = 1.0 - p; + U = random_sample(prng_state); + while (U > sum) { + prod *= q; + sum += prod; + X++; + } + return X; +} + +long random_geometric_inversion(prng_t *prng_state, double p) { + return (long)ceil(log(1.0 - random_sample(prng_state)) / log(1.0 - p)); +} + +long random_geometric(prng_t *prng_state, double p) { + if (p >= 0.333333333333333333333333) { + return random_geometric_search(prng_state, p); + } else { + return random_geometric_inversion(prng_state, p); + } +} + +long random_zipf(prng_t *prng_state, double a) { + double T, U, V; + long X; + double am1, b; + + am1 = a - 1.0; + b = pow(2.0, am1); + do { + U = 1.0 - random_sample(prng_state); + V = random_sample(prng_state); + X = (long)floor(pow(U, -1.0 / am1)); + /* The real result may be above what can be represented in a signed + * long. It will get casted to -sys.maxint-1. Since this is + * a straightforward rejection algorithm, we can just reject this value + * in the rejection condition below. This function then models a Zipf + * distribution truncated to sys.maxint. + */ + T = pow(1.0 + 1.0 / X, am1); + } while (((V * X * (T - 1.0) / (b - 1.0)) > (T / b)) || X < 1); + return X; +} + +double random_triangular(prng_t *prng_state, double left, double mode, + double right) { + double base, leftbase, ratio, leftprod, rightprod; + double U; + + base = right - left; + leftbase = mode - left; + ratio = leftbase / base; + leftprod = leftbase * base; + rightprod = (right - mode) * base; + + U = random_sample(prng_state); + if (U <= ratio) { + return left + sqrt(U * leftprod); + } else { + return right - sqrt((1.0 - U) * rightprod); + } +} + +long random_hypergeometric_hyp(prng_t *prng_state, long good, long bad, + long sample) { + long d1, k, z; + double d2, u, y; + + d1 = bad + good - sample; + d2 = (double)min(bad, good); + + y = d2; + k = sample; + while (y > 0.0) { + u = random_sample(prng_state); + y -= (long)floor(u + y / (d1 + k)); + k--; + if (k == 0) + break; + } + z = (long)(d2 - y); + if (good > bad) + z = sample - z; + return z; +} + +/* D1 = 2*sqrt(2/e) */ +/* D2 = 3 - 2*sqrt(3/e) */ +#define D1 1.7155277699214135 +#define D2 0.8989161620588988 +long random_hypergeometric_hrua(prng_t *prng_state, long good, long bad, + long sample) { + long mingoodbad, maxgoodbad, popsize, m, d9; + double d4, d5, d6, d7, d8, d10, d11; + long Z; + double T, W, X, Y; + + mingoodbad = min(good, bad); + popsize = good + bad; + maxgoodbad = max(good, bad); + m = min(sample, popsize - sample); + d4 = ((double)mingoodbad) / popsize; + d5 = 1.0 - d4; + d6 = m * d4 + 0.5; + d7 = sqrt((double)(popsize - m) * sample * d4 * d5 / (popsize - 1) + 0.5); + d8 = D1 * d7 + D2; + d9 = (long)floor((double)(m + 1) * (mingoodbad + 1) / (popsize + 2)); + d10 = (loggam(d9 + 1) + loggam(mingoodbad - d9 + 1) + loggam(m - d9 + 1) + + loggam(maxgoodbad - m + d9 + 1)); + d11 = min(min(m, mingoodbad) + 1.0, floor(d6 + 16 * d7)); + /* 16 for 16-decimal-digit precision in D1 and D2 */ + + while (1) { + X = random_sample(prng_state); + Y = random_sample(prng_state); + W = d6 + d8 * (Y - 0.5) / X; + + /* fast rejection: */ + if ((W < 0.0) || (W >= d11)) + continue; + + Z = (long)floor(W); + T = d10 - (loggam(Z + 1) + loggam(mingoodbad - Z + 1) + loggam(m - Z + 1) + + loggam(maxgoodbad - m + Z + 1)); + + /* fast acceptance: */ + if ((X * (4.0 - X) - 3.0) <= T) + break; + + /* fast rejection: */ + if (X * (X - T) >= 1) + continue; + + if (2.0 * log(X) <= T) + break; /* acceptance */ + } + + /* this is a correction to HRUA* by Ivan Frohne in rv.py */ + if (good > bad) + Z = m - Z; + + /* another fix from rv.py to allow sample to exceed popsize/2 */ + if (m < sample) + Z = good - Z; + + return Z; +} +#undef D1 +#undef D2 + +long random_hypergeometric(prng_t *prng_state, long good, long bad, + long sample) { + if (sample > 10) { + return random_hypergeometric_hrua(prng_state, good, bad, sample); + } else { + return random_hypergeometric_hyp(prng_state, good, bad, sample); + } +} + +unsigned long random_interval(prng_t *prng_state, unsigned long max) { + unsigned long mask, value; + if (max == 0) { + return 0; + } + + mask = max; + + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; +#if ULONG_MAX > 0xffffffffUL + mask |= mask >> 32; +#endif + +/* Search a random value in [0..mask] <= max */ +#if ULONG_MAX > 0xffffffffUL + if (max <= 0xffffffffUL) { + while ((value = (random_uint32(prng_state) & mask)) > max) + ; + } else { + while ((value = (random_uint64(prng_state) & mask)) > max) + ; + } +#else + while ((value = (random_uint32(prng_state) & mask)) > max) + ; +#endif + return value; +} + +static NPY_INLINE uint64_t gen_mask(uint64_t max) { + uint64_t mask = max; + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; + mask |= mask >> 32; + return mask; +} + +/* + * Fills an array with cnt random npy_uint64 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ + +static NPY_INLINE uint64_t bounded_uint64(prng_t *prng_state, uint64_t off, + uint64_t rng, uint64_t mask) { + uint64_t val; + if (rng == 0) + return off; + + if (rng <= 0xffffffffUL) { + while ((val = (random_uint32(prng_state) & mask)) > rng) + ; + } else { + while ((val = (random_uint64(prng_state) & mask)) > rng) + ; + } + return off + val; +} + +uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, uint64_t rng, + uint64_t mask) { + return bounded_uint64(prng_state, off, rng, mask); +} + +static NPY_INLINE uint32_t bounded_uint32(prng_t *prng_state, uint32_t off, + uint32_t rng, uint32_t mask) { + /* + * The buffer and buffer count are not used here but are included to allow + * this function to be templated with the similar uint8 and uint16 + * functions + */ + + uint32_t val; + if (rng == 0) + return off; + + while ((val = (random_uint32(prng_state) & mask)) > rng) + ; + return off + val; +} + +uint32_t random_buffered_bounded_uint32(prng_t *prng_state, uint32_t off, + uint32_t rng, uint32_t mask, int *bcnt, + uint32_t *buf) { + /* + * Unused bcnt and buf are here only to allow templating with other uint + * generators + */ + return bounded_uint32(prng_state, off, rng, mask); +} + +static NPY_INLINE uint16_t buffered_bounded_uint16(prng_t *prng_state, + uint16_t off, uint16_t rng, + uint16_t mask, int *bcnt, + uint32_t *buf) { + uint16_t val; + if (rng == 0) + return off; + + do { + if (!(bcnt[0])) { + buf[0] = random_uint32(prng_state); + bcnt[0] = 1; + } else { + buf[0] >>= 16; + bcnt[0] -= 1; + } + val = (uint16_t)buf[0] & mask; + } while (val > rng); + return off + val; +} + +uint16_t random_buffered_bounded_uint16(prng_t *prng_state, uint16_t off, + uint16_t rng, uint16_t mask, int *bcnt, + uint32_t *buf) { + return buffered_bounded_uint16(prng_state, off, rng, mask, bcnt, buf); +} + +static NPY_INLINE uint8_t buffered_bounded_uint8(prng_t *prng_state, + uint8_t off, uint8_t rng, + uint8_t mask, int *bcnt, + uint32_t *buf) { + uint8_t val; + if (rng == 0) + return off; + do { + if (!(bcnt[0])) { + buf[0] = random_uint32(prng_state); + bcnt[0] = 3; + } else { + buf[0] >>= 8; + bcnt[0] -= 1; + } + val = (uint8_t)buf[0] & mask; + } while (val > rng); + return off + val; +} + +uint8_t random_buffered_bounded_uint8(prng_t *prng_state, uint8_t off, + uint8_t rng, uint8_t mask, int *bcnt, + uint32_t *buf) { + return buffered_bounded_uint8(prng_state, off, rng, mask, bcnt, buf); +} + +static NPY_INLINE npy_bool buffered_bounded_bool(prng_t *prng_state, + npy_bool off, npy_bool rng, + npy_bool mask, int *bcnt, + uint32_t *buf) { + if (rng == 0) + return off; + if (!(bcnt[0])) { + buf[0] = random_uint32(prng_state); + bcnt[0] = 31; + } else { + buf[0] >>= 1; + bcnt[0] -= 1; + } + return (buf[0] & 0x00000001UL) != 0; +} + +npy_bool random_buffered_bounded_bool(prng_t *prng_state, npy_bool off, + npy_bool rng, npy_bool mask, int *bcnt, + uint32_t *buf) { + return buffered_bounded_bool(prng_state, off, rng, mask, bcnt, buf); +} + +void random_bounded_uint64_fill(prng_t *prng_state, uint64_t off, uint64_t rng, + npy_intp cnt, uint64_t *out) { + uint64_t mask; + npy_intp i; + + /* Smallest bit mask >= max */ + mask = gen_mask(rng); + for (i = 0; i < cnt; i++) { + out[i] = bounded_uint64(prng_state, off, rng, mask); + } +} + +/* + * Fills an array with cnt random npy_uint32 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void random_bounded_uint32_fill(prng_t *prng_state, uint32_t off, uint32_t rng, + npy_intp cnt, uint32_t *out) { + uint32_t mask; + npy_intp i; + + /* Smallest bit mask >= max */ + mask = (uint32_t)gen_mask(rng); + for (i = 0; i < cnt; i++) { + out[i] = bounded_uint32(prng_state, off, rng, mask); + } +} + +/* + * Fills an array with cnt random npy_uint16 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void random_bounded_uint16_fill(prng_t *prng_state, uint16_t off, uint16_t rng, + npy_intp cnt, uint16_t *out) { + uint16_t mask; + npy_intp i; + uint32_t buf = 0; + int bcnt = 0; + + /* Smallest bit mask >= max */ + mask = (uint16_t)gen_mask(rng); + for (i = 0; i < cnt; i++) { + out[i] = buffered_bounded_uint16(prng_state, off, rng, mask, &bcnt, &buf); + } +} + +/* + * Fills an array with cnt random npy_uint8 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void random_bounded_uint8_fill(prng_t *prng_state, uint8_t off, uint8_t rng, + npy_intp cnt, uint8_t *out) { + uint8_t mask; + npy_intp i; + uint32_t buf = 0; + int bcnt = 0; + + /* Smallest bit mask >= max */ + mask = (uint8_t)gen_mask(rng); + for (i = 0; i < cnt; i++) { + out[i] = buffered_bounded_uint8(prng_state, off, rng, mask, &bcnt, &buf); + } +} + +/* + * Fills an array with cnt random npy_bool between off and off + rng + * inclusive. + */ +void random_bounded_bool_fill(prng_t *prng_state, npy_bool off, npy_bool rng, + npy_intp cnt, npy_bool *out) { + npy_bool mask = 0; + npy_intp i; + uint32_t buf = 0; + int bcnt = 0; + + for (i = 0; i < cnt; i++) { + out[i] = buffered_bounded_bool(prng_state, off, rng, mask, &bcnt, &buf); + } +} diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index 9048784467a4..aedd0c6505e8 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -23,8 +23,14 @@ typedef int bool; #define DECLDIR extern #endif -typedef double (*random_double_0)(void *st); -typedef float (*random_float_0)(void *st); +#ifndef min +#define min(x, y) ((x < y) ? x : y) +#define max(x, y) ((x > y) ? x : y) +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338328 +#endif typedef struct s_binomial_t { int has_binomial; /* !=0: following parameters initialized for binomial */ @@ -51,6 +57,7 @@ typedef struct prng { uint64_t (*next_uint64)(void *st); uint32_t (*next_uint32)(void *st); double (*next_double)(void *st); + uint64_t (*next_raw)(void *st); int has_gauss; double gauss; int has_gauss_f; @@ -62,6 +69,10 @@ DECLDIR float random_sample_f(prng_t *prng_state); DECLDIR double random_sample(prng_t *prng_state); DECLDIR uint32_t random_uint32(prng_t *prng_state); +DECLDIR int64_t random_positive_int64(prng_t *prng_state); +DECLDIR int32_t random_positive_int32(prng_t *prng_state); +DECLDIR long random_positive_int(prng_t *prng_state); +DECLDIR unsigned long random_uint(prng_t *prng_state); DECLDIR double random_standard_exponential(prng_t *prng_state); DECLDIR float random_standard_exponential_f(prng_t *prng_state); @@ -77,3 +88,76 @@ DECLDIR double random_standard_gamma(prng_t *prng_state, double shape); DECLDIR float random_standard_gamma_f(prng_t *prng_state, float shape); DECLDIR double random_standard_gamma_zig(prng_t *prng_state, double shape); DECLDIR float random_standard_gamma_zig_f(prng_t *prng_state, float shape); + +DECLDIR double random_normal(prng_t *prng_state, double loc, double scale); +DECLDIR double random_normal_zig(prng_t *prng_state, double loc, double scale); + +DECLDIR double random_gamma(prng_t *prng_state, double shape, double scale); +DECLDIR float random_gamma_float(prng_t *prng_state, float shape, float scale); + +DECLDIR double random_exponential(prng_t *prng_state, double scale); +DECLDIR double random_uniform(prng_t *prng_state, double lower, double range); +DECLDIR double random_beta(prng_t *prng_state, double a, double b); +DECLDIR double random_chisquare(prng_t *prng_state, double df); +DECLDIR double random_f(prng_t *prng_state, double dfnum, double dfden); +DECLDIR double random_standard_cauchy(prng_t *prng_state); +DECLDIR double random_pareto(prng_t *prng_state, double a); +DECLDIR double random_weibull(prng_t *prng_state, double a); +DECLDIR double random_power(prng_t *prng_state, double a); +DECLDIR double random_laplace(prng_t *prng_state, double loc, double scale); +DECLDIR double random_gumbel(prng_t *prng_state, double loc, double scale); +DECLDIR double random_logistic(prng_t *prng_state, double loc, double scale); +DECLDIR double random_lognormal(prng_t *prng_state, double mean, double sigma); +DECLDIR double random_rayleigh(prng_t *prng_state, double mode); +DECLDIR double random_standard_t(prng_t *prng_state, double df); +DECLDIR double random_noncentral_chisquare(prng_t *prng_state, double df, + double nonc); +DECLDIR double random_noncentral_f(prng_t *prng_state, double dfnum, + double dfden, double nonc); +DECLDIR double random_wald(prng_t *prng_state, double mean, double scale); +DECLDIR double random_vonmises(prng_t *prng_state, double mu, double kappa); +DECLDIR double random_triangular(prng_t *prng_state, double left, double mode, + double right); + +DECLDIR long random_poisson(prng_t *prng_state, double lam); +DECLDIR long random_negative_binomial(prng_t *prng_state, double n, double p); +DECLDIR long random_binomial(prng_t *prng_state, double p, long n); +DECLDIR long random_logseries(prng_t *prng_state, double p); +DECLDIR long random_geometric_search(prng_t *prng_state, double p); +DECLDIR long random_geometric_inversion(prng_t *prng_state, double p); +DECLDIR long random_geometric(prng_t *prng_state, double p); +DECLDIR long random_zipf(prng_t *prng_state, double a); +DECLDIR long random_hypergeometric(prng_t *prng_state, long good, long bad, + long sample); +DECLDIR unsigned long random_interval(prng_t *prng_state, unsigned long max); +DECLDIR uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, + uint64_t rng, uint64_t mask); +DECLDIR uint32_t random_buffered_bounded_uint32(prng_t *prng_state, + uint32_t off, uint32_t rng, + uint32_t mask, int *bcnt, + uint32_t *buf); + +DECLDIR uint16_t random_buffered_bounded_uint16(prng_t *prng_state, + uint16_t off, uint16_t rng, + uint16_t mask, int *bcnt, + uint32_t *buf); +DECLDIR uint8_t random_buffered_bounded_uint8(prng_t *prng_state, uint8_t off, + uint8_t rng, uint8_t mask, + int *bcnt, uint32_t *buf); +DECLDIR npy_bool random_buffered_bounded_bool(prng_t *prng_state, npy_bool off, + npy_bool rng, npy_bool mask, + int *bcnt, uint32_t *buf); +DECLDIR void random_bounded_uint64_fill(prng_t *prng_state, uint64_t off, + uint64_t rng, npy_intp cnt, + uint64_t *out); +DECLDIR void random_bounded_uint32_fill(prng_t *prng_state, uint32_t off, + uint32_t rng, npy_intp cnt, + uint32_t *out); +DECLDIR void random_bounded_uint16_fill(prng_t *prng_state, uint16_t off, + uint16_t rng, npy_intp cnt, + uint16_t *out); +DECLDIR void random_bounded_uint8_fill(prng_t *prng_state, uint8_t off, + uint8_t rng, npy_intp cnt, uint8_t *out); +DECLDIR void random_bounded_bool_fill(prng_t *prng_state, npy_bool off, + npy_bool rng, npy_intp cnt, + npy_bool *out); diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.h b/_randomgen/core_prng/src/dsfmt/dSFMT.h index 2d616acd8276..fa608cd758f1 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT.h +++ b/_randomgen/core_prng/src/dsfmt/dSFMT.h @@ -642,26 +642,30 @@ typedef struct s_dsfmt_state { int buffer_loc; } dsfmt_state; -static inline double dsfmt_next_double(dsfmt_state *state) { +static inline double dsfmt_next_buffer(dsfmt_state *state) { if (state->buffer_loc < DSFMT_N64) { double out = state->buffered_uniforms[state->buffer_loc]; state->buffer_loc++; return out; } - dsfmt_fill_array_close_open(state->state, state->buffered_uniforms, - DSFMT_N64); + dsfmt_fill_array_close1_open2(state->state, state->buffered_uniforms, + DSFMT_N64); state->buffer_loc = 1; return state->buffered_uniforms[0]; } +static inline double dsfmt_next_double(dsfmt_state *state) { + return dsfmt_next_buffer(state) - 1.0; +} + static inline uint64_t dsfmt_next64(dsfmt_state *state) { /* Discard bottom 16 bits */ - double d = dsfmt_next_double(state); + double d = dsfmt_next_buffer(state); uint64_t out; uint64_t *tmp; tmp = (uint64_t *)&d; out = (*tmp >> 16) << 32; - d = dsfmt_next_double(state); + d = dsfmt_next_buffer(state); tmp = (uint64_t *)&d; out |= (*tmp >> 16) & 0xffffffff; return out; @@ -669,9 +673,15 @@ static inline uint64_t dsfmt_next64(dsfmt_state *state) { static inline uint32_t dsfmt_next32(dsfmt_state *state) { /* Discard bottom 16 bits */ - double d = dsfmt_next_double(state); + double d = dsfmt_next_buffer(state); uint64_t *out = (uint64_t *)&d; return (uint32_t)((*out >> 16) & 0xffffffff); } +static inline uint64_t dsfmt_next_raw(dsfmt_state *state) { + double d; + d = dsfmt_next_buffer(state); + return *((uint64_t *)&d); +} + void dsfmt_jump(dsfmt_state *state); \ No newline at end of file diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index aedfc70c7cea..eb580671bb8c 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -76,6 +76,7 @@ cdef class ThreeFry: self._prng.next_uint64 = &threefry_uint64 self._prng.next_uint32 = &threefry_uint32 self._prng.next_double = &threefry_double + self._prng.next_raw = &threefry_uint64 cdef const char *name = 'CorePRNG' self.capsule = PyCapsule_New(self._prng, name, NULL) diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 0b59f6dccd12..07abc9b233a1 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -67,6 +67,7 @@ cdef class Xoroshiro128: self._prng.next_uint64 = &xoroshiro128_uint64 self._prng.next_uint32 = &xoroshiro128_uint32 self._prng.next_double = &xoroshiro128_double + self._prng.next_raw = &xoroshiro128_uint64 self.ctypes = None self.cffi = None diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index 635bb24961f9..0eb6a9f3f8d5 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -62,6 +62,7 @@ cdef class Xorshift1024: self._prng.next_uint64 = &xorshift1024_uint64 self._prng.next_uint32 = &xorshift1024_uint32 self._prng.next_double = &xorshift1024_double + self._prng.next_raw = &xorshift1024_uint64 cdef const char *name = "CorePRNG" self.capsule = PyCapsule_New(self._prng, name, NULL) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 3c40089a4e7f..8307ade74ee1 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -55,7 +55,8 @@ Extension("core_prng.dsfmt", ["core_prng/dsfmt.pyx", join(MOD_DIR, 'src', 'dsfmt', 'dSFMT.c'), - join(MOD_DIR, 'src', 'dsfmt', 'dSFMT-jump.c')], + join(MOD_DIR, 'src', 'dsfmt', 'dSFMT-jump.c'), + join(MOD_DIR, 'src', 'aligned_malloc', 'aligned_malloc.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'dsfmt')], From 3f7406d961af798c703856ce450be1a4047fe98a Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 9 Mar 2018 08:58:09 +0000 Subject: [PATCH 055/279] ENH: Add bounded intergers Add bounded integers Refactors distributions headers Add benchmark --- _randomgen/benchmark.py | 128 ++++++++++ _randomgen/core_prng/bounded_integers.pxd.in | 39 +++ _randomgen/core_prng/bounded_integers.pyx.in | 236 +++++++++++++++++++ _randomgen/core_prng/common.pxd | 131 +--------- _randomgen/core_prng/distributions.pxd | 133 +++++++++++ _randomgen/core_prng/dsfmt.pyx | 1 + _randomgen/core_prng/generator.pyx | 1 + _randomgen/core_prng/mt19937.pyx | 6 +- _randomgen/core_prng/pcg64.pyx | 2 + _randomgen/core_prng/philox.pyx | 1 + _randomgen/core_prng/threefry.pyx | 1 + _randomgen/core_prng/xoroshiro128.pyx | 1 + _randomgen/core_prng/xorshift1024.pyx | 1 + _randomgen/setup.py | 31 +++ 14 files changed, 581 insertions(+), 131 deletions(-) create mode 100644 _randomgen/benchmark.py create mode 100644 _randomgen/core_prng/bounded_integers.pxd.in create mode 100644 _randomgen/core_prng/bounded_integers.pyx.in create mode 100644 _randomgen/core_prng/distributions.pxd diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py new file mode 100644 index 000000000000..e670e72657c5 --- /dev/null +++ b/_randomgen/benchmark.py @@ -0,0 +1,128 @@ +import os +import struct +import timeit + +import numpy as np +import pandas as pd +from numpy.random import RandomState + +rs = RandomState() + +SETUP = ''' +import numpy as np +if '{prng}' == 'numpy': + import numpy.random + rg = numpy.random.RandomState() +else: + from core_prng import RandomGenerator, {prng} + rg = RandomGenerator({prng}()) +rg.random_sample() +''' + +scale_32 = scale_64 = 1 +if struct.calcsize('P') == 8 and os.name != 'nt': + # 64 bit + scale_32 = 0.5 +else: + scale_64 = 2 + +PRNGS = ['PCG64', 'MT19937', 'Xoroshiro128', 'Xorshift1024', + 'Philox', 'ThreeFry', 'numpy'] # , 'Xorshift1024', +#'Xoroshiro128', 'DSFMT', 'random'] + + +def timer(code, setup): + return 1000 * min(timeit.Timer(code, setup=setup).repeat(10, 10)) / 10.0 + + +def print_legend(legend): + print('\n' + legend + '\n' + '*' * max(60, len(legend))) + + +def run_timer(dist, command, numpy_command=None, setup='', random_type=''): + print('-' * 80) + if numpy_command is None: + numpy_command = command + + res = {} + for prng in PRNGS: + cmd = numpy_command if prng == 'numpy' else command + res[prng] = timer(cmd, setup=setup.format(prng=prng)) + + s = pd.Series(res) + t = s.apply(lambda x: '{0:0.2f} ms'.format(x)) + print_legend('Time to produce 1,000,000 ' + random_type) + print(t.sort_index()) + + p = 1000.0 / s + p = p.apply(lambda x: '{0:0.2f} million'.format(x)) + print_legend(random_type + ' per second') + print(p.sort_index()) + + baseline = [k for k in p.index if 'numpy' in k][0] + p = 1000.0 / s + p = p / p[baseline] * 100 - 100 + p = p.drop(baseline, 0) + p = p.apply(lambda x: '{0:0.1f}%'.format(x)) + print_legend('Speed-up relative to NumPy') + print(p.sort_index()) + print('-' * 80) + + +def timer_raw(): + dist = 'random_raw' + command = 'rg.random_raw(size=1000000, output=False)' + info = np.iinfo(np.int32) + command_numpy = 'rg.random_integers({max},size=1000000)' + command_numpy = command_numpy.format(max=info.max) + run_timer(dist, command, command_numpy, SETUP, 'Raw Values') + + +def timer_uniform(): + dist = 'random_sample' + command = 'rg.random_sample(1000000)' + run_timer(dist, command, None, SETUP, 'Uniforms') + + +def timer_32bit(): + info = np.iinfo(np.uint32) + min, max = info.min, info.max + dist = 'random_uintegers' + command = 'rg.random_uintegers(1000000, 32)' + command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32)' + command_numpy = command_numpy.format(min=min, max=max) + run_timer(dist, command, command_numpy, SETUP, '32-bit unsigned integers') + + +def timer_64bit(): + info = np.iinfo(np.uint64) + min, max = info.min, info.max + dist = 'random_uintegers' + command = 'rg.random_uintegers(1000000)' + command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64)' + command_numpy = command_numpy.format(min=min, max=max) + run_timer(dist, command, command_numpy, SETUP, '64-bit unsigned integers') + + +def timer_normal(): + dist = 'standard_normal' + command = 'rg.standard_normal(1000000, method="bm")' + command_numpy = 'rg.standard_normal(1000000)' + run_timer(dist, command, command_numpy, SETUP, 'Box-Muller normals') + + +def timer_normal_zig(): + dist = 'standard_normal' + command = 'rg.standard_normal(1000000, method="zig")' + command_numpy = 'rg.standard_normal(1000000)' + run_timer(dist, command, command_numpy, SETUP, + 'Standard normals (Ziggurat)') + + +if __name__ == '__main__': + timer_raw() + timer_uniform() + timer_32bit() + timer_64bit() + timer_normal() + timer_normal_zig() diff --git a/_randomgen/core_prng/bounded_integers.pxd.in b/_randomgen/core_prng/bounded_integers.pxd.in new file mode 100644 index 000000000000..c04aba7cedc2 --- /dev/null +++ b/_randomgen/core_prng/bounded_integers.pxd.in @@ -0,0 +1,39 @@ +from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, + int8_t, int16_t, int32_t, int64_t, intptr_t) +from common cimport prng_t +import numpy as np +cimport numpy as np +ctypedef np.npy_bool bool_t + +cdef inline uint64_t _gen_mask(uint64_t max_val) nogil: + """Mask generator for use in bounded random numbers""" + # Smallest bit mask >= max + cdef uint64_t mask = max_val + mask |= mask >> 1 + mask |= mask >> 2 + mask |= mask >> 4 + mask |= mask >> 8 + mask |= mask >> 16 + mask |= mask >> 32 + return mask +{{ +py: +type_info = ('uint32','uint16','uint8','bool','int32','int16','int8') +}} +{{for nptype in type_info}} +cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock) +{{endfor}} +{{ +py: +big_type_info = ('uint64', 'int64') +}} +{{for nptype in big_type_info}} +cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, prng_t *state, object lock) +{{endfor}} +{{ +py: +type_info = ('uint64','uint32','uint16','uint8','bool','int64','int32','int16','int8') +}} +{{for nptype in type_info}} +cdef object _rand_{{nptype}}(object low, object high, object size, prng_t *state, object lock) +{{endfor}} diff --git a/_randomgen/core_prng/bounded_integers.pyx.in b/_randomgen/core_prng/bounded_integers.pyx.in new file mode 100644 index 000000000000..00dc08571125 --- /dev/null +++ b/_randomgen/core_prng/bounded_integers.pyx.in @@ -0,0 +1,236 @@ +from distributions cimport * + +_randint_type = {'bool': (0, 2), + 'int8': (-2**7, 2**7), + 'int16': (-2**15, 2**15), + 'int32': (-2**31, 2**31), + 'int64': (-2**63, 2**63), + 'uint8': (0, 2**8), + 'uint16': (0, 2**16), + 'uint32': (0, 2**32), + 'uint64': (0, 2**64) + } + +{{ +py: +type_info = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000ULL'), + ('uint16', 'uint16', 'uint32', 'NPY_UINT32', 1, 16, 0, '0X10000UL'), + ('uint8', 'uint8', 'uint16', 'NPY_UINT16', 3, 8, 0, '0X100UL'), + ('bool','bool', 'uint8', 'NPY_UINT8', 31, 1, 0, '0x2UL'), + ('int32', 'uint32', 'uint64', 'NPY_INT64', 0, 0, '-0x80000000LL', '0x80000000LL'), + ('int16', 'uint16', 'uint32', 'NPY_INT32', 1, 16, '-0x8000LL', '0x8000LL' ), + ('int8', 'uint8', 'uint16', 'NPY_INT16', 3, 8, '-0x80LL', '0x80LL' ), +)}} +{{for nptype, utype, nptype_up, npctype, remaining, bitshift, lb, ub in type_info}} +{{ py: otype = nptype + '_' if nptype == 'bool' else nptype }} + +cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): + """Array path for smaller integer types""" + cdef {{utype}}_t rng, last_rng, off, val, mask, out_val + cdef uint32_t buf + cdef {{utype}}_t *out_data + cdef {{nptype_up}}_t low_v, high_v + cdef np.ndarray low_arr, high_arr, out_arr + cdef np.npy_intp i, cnt + cdef np.broadcast it + cdef int buf_rem = 0 + + + # Array path + low_arr = low + high_arr = high + if np.any(np.less(low_arr, {{lb}})): + raise ValueError('low is out of bounds for {{nptype}}') + if np.any(np.greater(high_arr, {{ub}})): + raise ValueError('high is out of bounds for {{nptype}}') + if np.any(np.greater_equal(low_arr, high_arr)): + raise ValueError('low >= high') + + low_arr = np.PyArray_FROM_OTF(low, np.{{npctype}}, np.NPY_ALIGNED | np.NPY_FORCECAST) + high_arr = np.PyArray_FROM_OTF(high, np.{{npctype}}, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.{{otype}}) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.{{otype}}) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = <{{utype}}_t *>np.PyArray_DATA(out_arr) + cnt = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(cnt): + low_v = (<{{nptype_up}}_t*>np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (<{{nptype_up}}_t*>np.PyArray_MultiIter_DATA(it, 1))[0] + rng = <{{utype}}_t>((high_v - 1) - low_v) + off = <{{utype}}_t>(<{{nptype_up}}_t>low_v) + + if rng != last_rng: + # Smallest bit mask >= max + mask = <{{utype}}_t>_gen_mask(rng) + + out_data[i] = random_buffered_bounded_{{utype}}(state, off, rng, mask, &buf_rem, &buf) + + np.PyArray_MultiIter_NEXT(it) + return out_arr +{{endfor}} + +{{ +py: +big_type_info = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFFFULL'), + ('int64', 'uint64', 'NPY_INT64', '-0x8000000000000000LL', '0x7FFFFFFFFFFFFFFFLL' ) +)}} +{{for nptype, utype, npctype, lb, ub in big_type_info}} +{{ py: otype = nptype}} +cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, prng_t *state, object lock): + """Array path for 64-bit integer types""" + cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr + cdef np.npy_intp i, cnt + cdef np.broadcast it + cdef object closed_upper + cdef uint64_t *out_data + cdef {{nptype}}_t *highm1_data + cdef {{nptype}}_t low_v, high_v + cdef uint64_t rng, last_rng, val, mask, off, out_val + + low_arr = low + high_arr = high + + if np.any(np.less(low_arr, {{lb}})): + raise ValueError('low is out of bounds for {{nptype}}') + + highm1_arr = np.empty_like(high_arr, dtype=np.{{nptype}}) + highm1_data = <{{nptype}}_t *>np.PyArray_DATA(highm1_arr) + cnt = np.PyArray_SIZE(high_arr) + flat = high_arr.flat + for i in range(cnt): + closed_upper = int(flat[i]) - 1 + if closed_upper > {{ub}}: + raise ValueError('high is out of bounds for {{nptype}}') + if closed_upper < {{lb}}: + raise ValueError('low >= high') + highm1_data[i] = <{{nptype}}_t>closed_upper + + if np.any(np.greater(low_arr, highm1_arr)): + raise ValueError('low >= high') + + high_arr = highm1_arr + low_arr = np.PyArray_FROM_OTF(low, np.{{npctype}}, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.{{nptype}}) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.{{nptype}}) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = np.PyArray_DATA(out_arr) + n = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(n): + low_v = (<{{nptype}}_t*>np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (<{{nptype}}_t*>np.PyArray_MultiIter_DATA(it, 1))[0] + rng = <{{utype}}_t>(high_v - low_v) # No -1 here since implemented above + off = <{{utype}}_t>(<{{nptype}}_t>low_v) + + if rng != last_rng: + mask = _gen_mask(rng) + out_data[i] = random_bounded_uint64(state, off, rng, mask) + + np.PyArray_MultiIter_NEXT(it) + + return out_arr +{{endfor}} + +{{ +py: +type_info = (('uint64', 'uint64', '0x0ULL', '0xFFFFFFFFFFFFFFFFULL'), + ('uint32', 'uint32', '0x0UL', '0XFFFFFFFFUL'), + ('uint16', 'uint16', '0x0UL', '0XFFFFUL'), + ('uint8', 'uint8', '0x0UL', '0XFFUL'), + ('bool', 'bool', '0x0UL', '0x1UL'), + ('int64', 'uint64', '-0x8000000000000000LL', '0x7FFFFFFFFFFFFFFFL'), + ('int32', 'uint32', '-0x80000000L', '0x7FFFFFFFL'), + ('int16', 'uint16', '-0x8000L', '0x7FFFL' ), + ('int8', 'uint8', '-0x80L', '0x7FL' ) +)}} +{{for nptype, utype, lb, ub in type_info}} +{{ py: otype = nptype + '_' if nptype == 'bool' else nptype }} +cdef object _rand_{{nptype}}(object low, object high, object size, prng_t *state, object lock): + """ + _rand_{{nptype}}(low, high, size, *state, lock) + + Return random np.{{nptype}} integers between `low` and `high`, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [`low`, `high`). If `high` is None (the default), + then results are from [0, `low`). On entry the arguments are presumed + to have been validated for size and order for the np.{{nptype}} type. + + Parameters + ---------- + low : int or array-like + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int or array-like + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + state : augmented random state + State to use in the core random number generators + lock : threading.Lock + Lock to prevent multiple using a single RandomState simultaneously + + Returns + ------- + out : python scalar or ndarray of np.{{nptype}} + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + """ + cdef np.ndarray out_arr, low_arr, high_arr + cdef {{utype}}_t rng, off, out_val + cdef {{utype}}_t *out_data + cdef np.npy_intp i, cnt + + if size is not None: + if (np.prod(size) == 0): + return np.empty(size, dtype=np.{{nptype}}) + + low_arr = np.array(low, copy=False) + high_arr = np.array(high, copy=False) + low_ndim = np.PyArray_NDIM(low_arr) + high_ndim = np.PyArray_NDIM(high_arr) + if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and + (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + low = int(low_arr) + high = int(high_arr) + high -= 1 + + if low < {{lb}}: + raise ValueError("low is out of bounds for {{nptype}}") + if high > {{ub}}: + raise ValueError("high is out of bounds for {{nptype}}") + if low > high: # -1 already subtracted, closed interval + raise ValueError("low >= high") + + rng = <{{utype}}_t>(high - low) + off = <{{utype}}_t>(<{{nptype}}_t>low) + if size is None: + with lock: + random_bounded_{{utype}}_fill(state, off, rng, 1, &out_val) + return np.{{otype}}(<{{nptype}}_t>out_val) + else: + out_arr = np.empty(size, np.{{nptype}}) + cnt = np.PyArray_SIZE(out_arr) + out_data = <{{utype}}_t *>np.PyArray_DATA(out_arr) + with lock, nogil: + random_bounded_{{utype}}_fill(state, off, rng, cnt, out_data) + return out_arr + return _rand_{{nptype}}_broadcast(low_arr, high_arr, size, state, lock) +{{endfor}} diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index ec4029e59db9..a6419cfa4958 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -2,7 +2,7 @@ from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t) from libc.math cimport sqrt from cpython cimport PyInt_AsLong, PyFloat_AsDouble - +from distributions cimport prng_t import numpy as np cimport numpy as np @@ -27,135 +27,6 @@ cdef extern from "src/aligned_malloc/aligned_malloc.h": cdef void *PyArray_calloc_aligned(size_t n, size_t s); cdef void PyArray_free_aligned(void *p); -cdef extern from "src/distributions/distributions.h": - - struct s_binomial_t: - int has_binomial - double psave - long nsave - double r - double q - double fm - long m - double p1 - double xm - double xl - double xr - double c - double laml - double lamr - double p2 - double p3 - double p4 - - ctypedef s_binomial_t binomial_t - - struct prng: - void *state - uint64_t (*next_uint64)(void *st) nogil - uint32_t (*next_uint32)(void *st) nogil - double (*next_double)(void *st) nogil - uint64_t (*next_raw)(void *st) nogil - int has_gauss - double gauss - int has_gauss_f - float gauss_f - binomial_t *binomial - - ctypedef prng prng_t - - double random_sample(prng_t *prng_state) nogil - double random_standard_exponential(prng_t *prng_state) nogil - double random_standard_exponential_zig(prng_t *prng_state) nogil - double random_gauss(prng_t *prng_state) nogil - double random_gauss_zig(prng_t* prng_state) nogil - double random_standard_gamma(prng_t *prng_state, double shape) nogil - double random_standard_gamma_zig(prng_t *prng_state, double shape) nogil - - float random_sample_f(prng_t *prng_state) nogil - float random_standard_exponential_f(prng_t *prng_state) nogil - float random_standard_exponential_zig_f(prng_t *prng_state) nogil - float random_gauss_f(prng_t *prng_state) nogil - float random_gauss_zig_f(prng_t* prng_state) nogil - float random_standard_gamma_f(prng_t *prng_state, float shape) nogil - float random_standard_gamma_zig_f(prng_t *prng_state, float shape) nogil - - uint32_t random_uint32(prng_t *prng_state) nogil - int64_t random_positive_int64(prng_t *prng_state) nogil - int32_t random_positive_int32(prng_t *prng_state) nogil - long random_positive_int(prng_t *prng_state) nogil - unsigned long random_uint(prng_t *prng_state) nogil - - double random_normal(prng_t *prng_state, double loc, double scale) nogil - double random_normal_zig(prng_t *prng_state, double loc, double scale) nogil - - double random_gamma(prng_t *prng_state, double shape, double scale) nogil - float random_gamma_float(prng_t *prng_state, float shape, float scale) nogil - - double random_exponential(prng_t *prng_state, double scale) nogil - double random_uniform(prng_t *prng_state, double lower, double range) nogil - double random_beta(prng_t *prng_state, double a, double b) nogil - double random_chisquare(prng_t *prng_state, double df) nogil - double random_f(prng_t *prng_state, double dfnum, double dfden) nogil - double random_standard_cauchy(prng_t *prng_state) nogil - double random_pareto(prng_t *prng_state, double a) nogil - double random_weibull(prng_t *prng_state, double a) nogil - double random_power(prng_t *prng_state, double a) nogil - double random_laplace(prng_t *prng_state, double loc, double scale) nogil - double random_gumbel(prng_t *prng_state, double loc, double scale) nogil - double random_logistic(prng_t *prng_state, double loc, double scale) nogil - double random_lognormal(prng_t *prng_state, double mean, double sigma) nogil - double random_rayleigh(prng_t *prng_state, double mode) nogil - double random_standard_t(prng_t *prng_state, double df) nogil - double random_noncentral_chisquare(prng_t *prng_state, double df, - double nonc) nogil - double random_noncentral_f(prng_t *prng_state, double dfnum, - double dfden, double nonc) nogil - double random_wald(prng_t *prng_state, double mean, double scale) nogil - double random_vonmises(prng_t *prng_state, double mu, double kappa) nogil - double random_triangular(prng_t *prng_state, double left, double mode, - double right) nogil - - long random_poisson(prng_t *prng_state, double lam) nogil - long random_negative_binomial(prng_t *prng_state, double n, double p) nogil - long random_binomial(prng_t *prng_state, double p, long n) nogil - long random_logseries(prng_t *prng_state, double p) nogil - long random_geometric_search(prng_t *prng_state, double p) nogil - long random_geometric_inversion(prng_t *prng_state, double p) nogil - long random_geometric(prng_t *prng_state, double p) nogil - long random_zipf(prng_t *prng_state, double a) nogil - long random_hypergeometric(prng_t *prng_state, long good, long bad, - long sample) nogil - unsigned long random_interval(prng_t *prng_state, unsigned long max) nogil - uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, - uint64_t rng, uint64_t mask) nogil - uint32_t random_buffered_bounded_uint32(prng_t *prng_state, uint32_t off, - uint32_t rng, uint32_t mask, - int *bcnt, uint32_t *buf) nogil - - uint16_t random_buffered_bounded_uint16(prng_t *prng_state, uint16_t off, - uint16_t rng, uint16_t mask, - int *bcnt, uint32_t *buf) nogil - uint8_t random_buffered_bounded_uint8(prng_t *prng_state, uint8_t off, - uint8_t rng, uint8_t mask, - int *bcnt, uint32_t *buf) nogil - np.npy_bool random_buffered_bounded_bool(prng_t *prng_state, np.npy_bool off, - np.npy_bool rng, np.npy_bool mask, - int *bcnt, uint32_t *buf) nogil - void random_bounded_uint64_fill(prng_t *prng_state, uint64_t off, - uint64_t rng, np.npy_intp cnt, - uint64_t *out) nogil - void random_bounded_uint32_fill(prng_t *prng_state, uint32_t off, - uint32_t rng, np.npy_intp cnt, - uint32_t *out) nogil - void random_bounded_uint16_fill(prng_t *prng_state, uint16_t off, - uint16_t rng, np.npy_intp cnt, - uint16_t *out) nogil - void random_bounded_uint8_fill(prng_t *prng_state, uint8_t off, - uint8_t rng, np.npy_intp cnt, uint8_t *out) nogil - void random_bounded_bool_fill(prng_t *prng_state, np.npy_bool off, - np.npy_bool rng, np.npy_intp cnt, np.npy_bool *out) nogil - ctypedef double (*random_double_0)(prng_t *state) nogil ctypedef double (*random_double_1)(prng_t *state, double a) nogil ctypedef double (*random_double_2)(prng_t *state, double a, double b) nogil diff --git a/_randomgen/core_prng/distributions.pxd b/_randomgen/core_prng/distributions.pxd new file mode 100644 index 000000000000..22761826af74 --- /dev/null +++ b/_randomgen/core_prng/distributions.pxd @@ -0,0 +1,133 @@ +from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, + int8_t, int16_t, int32_t, int64_t, intptr_t) +import numpy as np +cimport numpy as np + +cdef extern from "src/distributions/distributions.h": + + struct s_binomial_t: + int has_binomial + double psave + long nsave + double r + double q + double fm + long m + double p1 + double xm + double xl + double xr + double c + double laml + double lamr + double p2 + double p3 + double p4 + + ctypedef s_binomial_t binomial_t + + struct prng: + void *state + uint64_t (*next_uint64)(void *st) nogil + uint32_t (*next_uint32)(void *st) nogil + double (*next_double)(void *st) nogil + uint64_t (*next_raw)(void *st) nogil + int has_gauss + double gauss + int has_gauss_f + float gauss_f + binomial_t *binomial + + ctypedef prng prng_t + + double random_sample(prng_t *prng_state) nogil + double random_standard_exponential(prng_t *prng_state) nogil + double random_standard_exponential_zig(prng_t *prng_state) nogil + double random_gauss(prng_t *prng_state) nogil + double random_gauss_zig(prng_t* prng_state) nogil + double random_standard_gamma(prng_t *prng_state, double shape) nogil + double random_standard_gamma_zig(prng_t *prng_state, double shape) nogil + + float random_sample_f(prng_t *prng_state) nogil + float random_standard_exponential_f(prng_t *prng_state) nogil + float random_standard_exponential_zig_f(prng_t *prng_state) nogil + float random_gauss_f(prng_t *prng_state) nogil + float random_gauss_zig_f(prng_t* prng_state) nogil + float random_standard_gamma_f(prng_t *prng_state, float shape) nogil + float random_standard_gamma_zig_f(prng_t *prng_state, float shape) nogil + + uint32_t random_uint32(prng_t *prng_state) nogil + int64_t random_positive_int64(prng_t *prng_state) nogil + int32_t random_positive_int32(prng_t *prng_state) nogil + long random_positive_int(prng_t *prng_state) nogil + unsigned long random_uint(prng_t *prng_state) nogil + + double random_normal(prng_t *prng_state, double loc, double scale) nogil + double random_normal_zig(prng_t *prng_state, double loc, double scale) nogil + + double random_gamma(prng_t *prng_state, double shape, double scale) nogil + float random_gamma_float(prng_t *prng_state, float shape, float scale) nogil + + double random_exponential(prng_t *prng_state, double scale) nogil + double random_uniform(prng_t *prng_state, double lower, double range) nogil + double random_beta(prng_t *prng_state, double a, double b) nogil + double random_chisquare(prng_t *prng_state, double df) nogil + double random_f(prng_t *prng_state, double dfnum, double dfden) nogil + double random_standard_cauchy(prng_t *prng_state) nogil + double random_pareto(prng_t *prng_state, double a) nogil + double random_weibull(prng_t *prng_state, double a) nogil + double random_power(prng_t *prng_state, double a) nogil + double random_laplace(prng_t *prng_state, double loc, double scale) nogil + double random_gumbel(prng_t *prng_state, double loc, double scale) nogil + double random_logistic(prng_t *prng_state, double loc, double scale) nogil + double random_lognormal(prng_t *prng_state, double mean, double sigma) nogil + double random_rayleigh(prng_t *prng_state, double mode) nogil + double random_standard_t(prng_t *prng_state, double df) nogil + double random_noncentral_chisquare(prng_t *prng_state, double df, + double nonc) nogil + double random_noncentral_f(prng_t *prng_state, double dfnum, + double dfden, double nonc) nogil + double random_wald(prng_t *prng_state, double mean, double scale) nogil + double random_vonmises(prng_t *prng_state, double mu, double kappa) nogil + double random_triangular(prng_t *prng_state, double left, double mode, + double right) nogil + + long random_poisson(prng_t *prng_state, double lam) nogil + long random_negative_binomial(prng_t *prng_state, double n, double p) nogil + long random_binomial(prng_t *prng_state, double p, long n) nogil + long random_logseries(prng_t *prng_state, double p) nogil + long random_geometric_search(prng_t *prng_state, double p) nogil + long random_geometric_inversion(prng_t *prng_state, double p) nogil + long random_geometric(prng_t *prng_state, double p) nogil + long random_zipf(prng_t *prng_state, double a) nogil + long random_hypergeometric(prng_t *prng_state, long good, long bad, + long sample) nogil + unsigned long random_interval(prng_t *prng_state, unsigned long max) nogil + uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, + uint64_t rng, uint64_t mask) nogil + uint32_t random_buffered_bounded_uint32(prng_t *prng_state, uint32_t off, + uint32_t rng, uint32_t mask, + int *bcnt, uint32_t *buf) nogil + + uint16_t random_buffered_bounded_uint16(prng_t *prng_state, uint16_t off, + uint16_t rng, uint16_t mask, + int *bcnt, uint32_t *buf) nogil + uint8_t random_buffered_bounded_uint8(prng_t *prng_state, uint8_t off, + uint8_t rng, uint8_t mask, + int *bcnt, uint32_t *buf) nogil + np.npy_bool random_buffered_bounded_bool(prng_t *prng_state, np.npy_bool off, + np.npy_bool rng, np.npy_bool mask, + int *bcnt, uint32_t *buf) nogil + void random_bounded_uint64_fill(prng_t *prng_state, uint64_t off, + uint64_t rng, np.npy_intp cnt, + uint64_t *out) nogil + void random_bounded_uint32_fill(prng_t *prng_state, uint32_t off, + uint32_t rng, np.npy_intp cnt, + uint32_t *out) nogil + void random_bounded_uint16_fill(prng_t *prng_state, uint16_t off, + uint16_t rng, np.npy_intp cnt, + uint16_t *out) nogil + void random_bounded_uint8_fill(prng_t *prng_state, uint8_t off, + uint8_t rng, np.npy_intp cnt, uint8_t *out) nogil + void random_bounded_bool_fill(prng_t *prng_state, np.npy_bool off, + np.npy_bool rng, np.npy_intp cnt, np.npy_bool *out) nogil diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index 5acc2960f86c..09857aa621fb 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -6,6 +6,7 @@ import numpy as np cimport numpy as np from common cimport * +from distributions cimport prng_t, binomial_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 80a4d0a60018..811b8d978224 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -9,6 +9,7 @@ cimport cython from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from cpython cimport Py_INCREF, PyComplex_RealAsDouble, PyComplex_ImagAsDouble, PyComplex_FromDoubles from common cimport * +from distributions cimport * from libc cimport string from libc.stdlib cimport malloc, free diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index 230a29a74b5a..8f2f77f83922 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -7,6 +7,7 @@ import numpy as np cimport numpy as np from common cimport * +from distributions cimport prng_t, binomial_t import core_prng.pickle from core_prng.entropy import random_entropy @@ -36,6 +37,9 @@ cdef uint32_t mt19937_uint32(void *st) nogil: cdef double mt19937_double(void *st) nogil: return mt19937_next_double( st) +cdef uint64_t mt19937_raw(void *st) nogil: + return mt19937_next32( st) + cdef class MT19937: """ Prototype Core PRNG using MT19937 @@ -64,7 +68,7 @@ cdef class MT19937: self._prng.next_uint64 = &mt19937_uint64 self._prng.next_uint32 = &mt19937_uint32 self._prng.next_double = &mt19937_double - self._prng.next_raw = &mt19937_uint64 + self._prng.next_raw = &mt19937_raw cdef const char *name = "CorePRNG" self.capsule = PyCapsule_New(self._prng, name, NULL) diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index a2e0842eb1c5..bba905c19c98 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -5,6 +5,7 @@ import numpy as np cimport numpy as np from common cimport * +from distributions cimport prng_t, binomial_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy @@ -89,6 +90,7 @@ cdef class PCG64: self._prng.next_uint64 = &pcg64_uint64 self._prng.next_uint32 = &pcg64_uint32 self._prng.next_double = &pcg64_double + self._prng.next_raw = &pcg64_uint64 cdef const char *name = "CorePRNG" self.capsule = PyCapsule_New(self._prng, name, NULL) diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx index 2765334cf050..41c520a1aba3 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/core_prng/philox.pyx @@ -4,6 +4,7 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np from common cimport * +from distributions cimport prng_t, binomial_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index eb580671bb8c..4322baf3575a 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -4,6 +4,7 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np from common cimport * +from distributions cimport prng_t, binomial_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 07abc9b233a1..3cbb73752512 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -9,6 +9,7 @@ import numpy as np cimport numpy as np from common cimport * +from distributions cimport prng_t, binomial_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index 0eb6a9f3f8d5..ef686e003291 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -5,6 +5,7 @@ import numpy as np cimport numpy as np from common cimport * +from distributions cimport prng_t, binomial_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 8307ade74ee1..330d0cfeea16 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -1,4 +1,5 @@ import os +import glob import struct import sys from os.path import join @@ -9,6 +10,15 @@ from setuptools import setup, find_packages, Distribution from setuptools.extension import Extension +try: + import Cython.Tempita as tempita +except ImportError: + try: + import tempita + except ImportError: + raise ImportError('tempita required to install, ' + 'use pip install tempita') + import versioneer Cython.Compiler.Options.annotate = True @@ -43,6 +53,19 @@ if USE_SSE2: DSFMT_DEFS += [('HAVE_SSE2', '1')] +files = glob.glob('./core_prng/*.in') +for templated_file in files: + print(templated_file) + output_file_name = os.path.splitext(templated_file)[0] + if (os.path.exists(output_file_name) and + (os.path.getmtime(templated_file) < os.path.getmtime(output_file_name))): + continue + with open(templated_file, 'r') as source_file: + template = tempita.Template(source_file.read()) + with open(output_file_name, 'w') as output_file: + output_file.write(template.substitute()) + + extensions = [Extension('core_prng.entropy', sources=[join(MOD_DIR, 'entropy.pyx'), join(MOD_DIR, 'src', 'entropy', 'entropy.c')], @@ -137,6 +160,14 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), + Extension("core_prng.bounded_integers", + ["core_prng/bounded_integers.pyx", + join(MOD_DIR, 'src', 'distributions', + 'distributions.c')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), ] From ad04bc7fd61dafe089733856fa06609223849ae0 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 9 Mar 2018 23:55:20 +0000 Subject: [PATCH 056/279] TST: Add smoke tests Fix bug in bounded integers Fix other small bugs Use consistent initialization --- _randomgen/core_prng/__init__.py | 4 +- _randomgen/core_prng/bounded_integers.pxd | 39 + _randomgen/core_prng/bounded_integers.pxd.in | 31 +- _randomgen/core_prng/bounded_integers.pyx | 1181 +++++++++++++++++ _randomgen/core_prng/bounded_integers.pyx.in | 21 +- _randomgen/core_prng/common.pyx | 9 +- _randomgen/core_prng/distributions.pxd | 1 - _randomgen/core_prng/dsfmt.pyx | 10 +- _randomgen/core_prng/generator.pyx | 54 +- _randomgen/core_prng/mt19937.pyx | 7 + _randomgen/core_prng/pcg64.pyx | 44 +- _randomgen/core_prng/philox.pyx | 6 +- _randomgen/core_prng/pickle.py | 2 + .../src/distributions/distributions.c | 2 +- .../src/distributions/distributions.h | 1 - _randomgen/core_prng/src/pcg64/pcg64.c | 14 + _randomgen/core_prng/src/pcg64/pcg64.h | 10 +- _randomgen/core_prng/tests/test_smoke.py | 976 ++++++++++++++ _randomgen/core_prng/threefry.pyx | 6 +- _randomgen/core_prng/xoroshiro128.pyx | 10 +- _randomgen/core_prng/xorshift1024.pyx | 6 +- _randomgen/setup.py | 1 - 22 files changed, 2363 insertions(+), 72 deletions(-) create mode 100644 _randomgen/core_prng/bounded_integers.pxd create mode 100644 _randomgen/core_prng/bounded_integers.pyx create mode 100644 _randomgen/core_prng/tests/test_smoke.py diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index 2d8d0ae6f2e4..d5577f3bf3cb 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -7,8 +7,8 @@ from .xoroshiro128 import Xoroshiro128 from .xorshift1024 import Xorshift1024 -__all__ = ['RandomGenerator', 'DSFMT', 'PCG64', 'Xoroshiro128', - 'ThreeFry', 'MT19937', 'Xorshift1024'] +__all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'Philox', + 'ThreeFry', 'Xoroshiro128', 'Xorshift1024'] from ._version import get_versions diff --git a/_randomgen/core_prng/bounded_integers.pxd b/_randomgen/core_prng/bounded_integers.pxd new file mode 100644 index 000000000000..0da686427dec --- /dev/null +++ b/_randomgen/core_prng/bounded_integers.pxd @@ -0,0 +1,39 @@ +from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, + int8_t, int16_t, int32_t, int64_t, intptr_t) +from common cimport prng_t +import numpy as np +cimport numpy as np +ctypedef np.npy_bool bool_t + +_randint_types = {'bool': (0, 2), + 'int8': (-2**7, 2**7), + 'int16': (-2**15, 2**15), + 'int32': (-2**31, 2**31), + 'int64': (-2**63, 2**63), + 'uint8': (0, 2**8), + 'uint16': (0, 2**16), + 'uint32': (0, 2**32), + 'uint64': (0, 2**64) + } + +cdef inline uint64_t _gen_mask(uint64_t max_val) nogil: + """Mask generator for use in bounded random numbers""" + # Smallest bit mask >= max + cdef uint64_t mask = max_val + mask |= mask >> 1 + mask |= mask >> 2 + mask |= mask >> 4 + mask |= mask >> 8 + mask |= mask >> 16 + mask |= mask >> 32 + return mask + +cdef object _rand_uint64(object low, object high, object size, prng_t *state, object lock) +cdef object _rand_uint32(object low, object high, object size, prng_t *state, object lock) +cdef object _rand_uint16(object low, object high, object size, prng_t *state, object lock) +cdef object _rand_uint8(object low, object high, object size, prng_t *state, object lock) +cdef object _rand_bool(object low, object high, object size, prng_t *state, object lock) +cdef object _rand_int64(object low, object high, object size, prng_t *state, object lock) +cdef object _rand_int32(object low, object high, object size, prng_t *state, object lock) +cdef object _rand_int16(object low, object high, object size, prng_t *state, object lock) +cdef object _rand_int8(object low, object high, object size, prng_t *state, object lock) diff --git a/_randomgen/core_prng/bounded_integers.pxd.in b/_randomgen/core_prng/bounded_integers.pxd.in index c04aba7cedc2..1b87e8d7ed69 100644 --- a/_randomgen/core_prng/bounded_integers.pxd.in +++ b/_randomgen/core_prng/bounded_integers.pxd.in @@ -5,6 +5,17 @@ import numpy as np cimport numpy as np ctypedef np.npy_bool bool_t +_randint_types = {'bool': (0, 2), + 'int8': (-2**7, 2**7), + 'int16': (-2**15, 2**15), + 'int32': (-2**31, 2**31), + 'int64': (-2**63, 2**63), + 'uint8': (0, 2**8), + 'uint16': (0, 2**16), + 'uint32': (0, 2**32), + 'uint64': (0, 2**64) + } + cdef inline uint64_t _gen_mask(uint64_t max_val) nogil: """Mask generator for use in bounded random numbers""" # Smallest bit mask >= max @@ -18,22 +29,8 @@ cdef inline uint64_t _gen_mask(uint64_t max_val) nogil: return mask {{ py: -type_info = ('uint32','uint16','uint8','bool','int32','int16','int8') -}} -{{for nptype in type_info}} -cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock) -{{endfor}} -{{ -py: -big_type_info = ('uint64', 'int64') -}} -{{for nptype in big_type_info}} -cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, prng_t *state, object lock) -{{endfor}} -{{ -py: -type_info = ('uint64','uint32','uint16','uint8','bool','int64','int32','int16','int8') +inttypes = ('uint64','uint32','uint16','uint8','bool','int64','int32','int16','int8') }} -{{for nptype in type_info}} -cdef object _rand_{{nptype}}(object low, object high, object size, prng_t *state, object lock) +{{for inttype in inttypes}} +cdef object _rand_{{inttype}}(object low, object high, object size, prng_t *state, object lock) {{endfor}} diff --git a/_randomgen/core_prng/bounded_integers.pyx b/_randomgen/core_prng/bounded_integers.pyx new file mode 100644 index 000000000000..e8840d341f6c --- /dev/null +++ b/_randomgen/core_prng/bounded_integers.pyx @@ -0,0 +1,1181 @@ +#!python +#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True + +import numpy as np +cimport numpy as np +from distributions cimport * +np.import_array() + + + + +cdef object _rand_uint32_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): + """Array path for smaller integer types""" + cdef uint32_t rng, last_rng, off, val, mask, out_val + cdef uint32_t buf + cdef uint32_t *out_data + cdef uint64_t low_v, high_v + cdef np.ndarray low_arr, high_arr, out_arr + cdef np.npy_intp i, cnt + cdef np.broadcast it + cdef int buf_rem = 0 + + + # Array path + low_arr = low + high_arr = high + if np.any(np.less(low_arr, 0)): + raise ValueError('low is out of bounds for uint32') + if np.any(np.greater(high_arr, 0X100000000ULL)): + raise ValueError('high is out of bounds for uint32') + if np.any(np.greater_equal(low_arr, high_arr)): + raise ValueError('low >= high') + + low_arr = np.PyArray_FROM_OTF(low, np.NPY_UINT64, np.NPY_ALIGNED | np.NPY_FORCECAST) + high_arr = np.PyArray_FROM_OTF(high, np.NPY_UINT64, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.uint32) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.uint32) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = np.PyArray_DATA(out_arr) + cnt = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(cnt): + low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] + rng = ((high_v - 1) - low_v) + off = (low_v) + + if rng != last_rng: + # Smallest bit mask >= max + mask = _gen_mask(rng) + + out_data[i] = random_buffered_bounded_uint32(state, off, rng, mask, &buf_rem, &buf) + + np.PyArray_MultiIter_NEXT(it) + return out_arr + + +cdef object _rand_uint16_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): + """Array path for smaller integer types""" + cdef uint16_t rng, last_rng, off, val, mask, out_val + cdef uint32_t buf + cdef uint16_t *out_data + cdef uint32_t low_v, high_v + cdef np.ndarray low_arr, high_arr, out_arr + cdef np.npy_intp i, cnt + cdef np.broadcast it + cdef int buf_rem = 0 + + + # Array path + low_arr = low + high_arr = high + if np.any(np.less(low_arr, 0)): + raise ValueError('low is out of bounds for uint16') + if np.any(np.greater(high_arr, 0X10000UL)): + raise ValueError('high is out of bounds for uint16') + if np.any(np.greater_equal(low_arr, high_arr)): + raise ValueError('low >= high') + + low_arr = np.PyArray_FROM_OTF(low, np.NPY_UINT32, np.NPY_ALIGNED | np.NPY_FORCECAST) + high_arr = np.PyArray_FROM_OTF(high, np.NPY_UINT32, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.uint16) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.uint16) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = np.PyArray_DATA(out_arr) + cnt = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(cnt): + low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] + rng = ((high_v - 1) - low_v) + off = (low_v) + + if rng != last_rng: + # Smallest bit mask >= max + mask = _gen_mask(rng) + + out_data[i] = random_buffered_bounded_uint16(state, off, rng, mask, &buf_rem, &buf) + + np.PyArray_MultiIter_NEXT(it) + return out_arr + + +cdef object _rand_uint8_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): + """Array path for smaller integer types""" + cdef uint8_t rng, last_rng, off, val, mask, out_val + cdef uint32_t buf + cdef uint8_t *out_data + cdef uint16_t low_v, high_v + cdef np.ndarray low_arr, high_arr, out_arr + cdef np.npy_intp i, cnt + cdef np.broadcast it + cdef int buf_rem = 0 + + + # Array path + low_arr = low + high_arr = high + if np.any(np.less(low_arr, 0)): + raise ValueError('low is out of bounds for uint8') + if np.any(np.greater(high_arr, 0X100UL)): + raise ValueError('high is out of bounds for uint8') + if np.any(np.greater_equal(low_arr, high_arr)): + raise ValueError('low >= high') + + low_arr = np.PyArray_FROM_OTF(low, np.NPY_UINT16, np.NPY_ALIGNED | np.NPY_FORCECAST) + high_arr = np.PyArray_FROM_OTF(high, np.NPY_UINT16, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.uint8) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.uint8) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = np.PyArray_DATA(out_arr) + cnt = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(cnt): + low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] + rng = ((high_v - 1) - low_v) + off = (low_v) + + if rng != last_rng: + # Smallest bit mask >= max + mask = _gen_mask(rng) + + out_data[i] = random_buffered_bounded_uint8(state, off, rng, mask, &buf_rem, &buf) + + np.PyArray_MultiIter_NEXT(it) + return out_arr + + +cdef object _rand_bool_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): + """Array path for smaller integer types""" + cdef bool_t rng, last_rng, off, val, mask, out_val + cdef uint32_t buf + cdef bool_t *out_data + cdef uint8_t low_v, high_v + cdef np.ndarray low_arr, high_arr, out_arr + cdef np.npy_intp i, cnt + cdef np.broadcast it + cdef int buf_rem = 0 + + + # Array path + low_arr = low + high_arr = high + if np.any(np.less(low_arr, 0)): + raise ValueError('low is out of bounds for bool') + if np.any(np.greater(high_arr, 0x2UL)): + raise ValueError('high is out of bounds for bool') + if np.any(np.greater_equal(low_arr, high_arr)): + raise ValueError('low >= high') + + low_arr = np.PyArray_FROM_OTF(low, np.NPY_UINT8, np.NPY_ALIGNED | np.NPY_FORCECAST) + high_arr = np.PyArray_FROM_OTF(high, np.NPY_UINT8, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.bool_) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.bool_) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = np.PyArray_DATA(out_arr) + cnt = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(cnt): + low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] + rng = ((high_v - 1) - low_v) + off = (low_v) + + if rng != last_rng: + # Smallest bit mask >= max + mask = _gen_mask(rng) + + out_data[i] = random_buffered_bounded_bool(state, off, rng, mask, &buf_rem, &buf) + + np.PyArray_MultiIter_NEXT(it) + return out_arr + + +cdef object _rand_int32_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): + """Array path for smaller integer types""" + cdef uint32_t rng, last_rng, off, val, mask, out_val + cdef uint32_t buf + cdef uint32_t *out_data + cdef uint64_t low_v, high_v + cdef np.ndarray low_arr, high_arr, out_arr + cdef np.npy_intp i, cnt + cdef np.broadcast it + cdef int buf_rem = 0 + + + # Array path + low_arr = low + high_arr = high + if np.any(np.less(low_arr, -0x80000000LL)): + raise ValueError('low is out of bounds for int32') + if np.any(np.greater(high_arr, 0x80000000LL)): + raise ValueError('high is out of bounds for int32') + if np.any(np.greater_equal(low_arr, high_arr)): + raise ValueError('low >= high') + + low_arr = np.PyArray_FROM_OTF(low, np.NPY_INT64, np.NPY_ALIGNED | np.NPY_FORCECAST) + high_arr = np.PyArray_FROM_OTF(high, np.NPY_INT64, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.int32) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.int32) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = np.PyArray_DATA(out_arr) + cnt = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(cnt): + low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] + rng = ((high_v - 1) - low_v) + off = (low_v) + + if rng != last_rng: + # Smallest bit mask >= max + mask = _gen_mask(rng) + + out_data[i] = random_buffered_bounded_uint32(state, off, rng, mask, &buf_rem, &buf) + + np.PyArray_MultiIter_NEXT(it) + return out_arr + + +cdef object _rand_int16_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): + """Array path for smaller integer types""" + cdef uint16_t rng, last_rng, off, val, mask, out_val + cdef uint32_t buf + cdef uint16_t *out_data + cdef uint32_t low_v, high_v + cdef np.ndarray low_arr, high_arr, out_arr + cdef np.npy_intp i, cnt + cdef np.broadcast it + cdef int buf_rem = 0 + + + # Array path + low_arr = low + high_arr = high + if np.any(np.less(low_arr, -0x8000LL)): + raise ValueError('low is out of bounds for int16') + if np.any(np.greater(high_arr, 0x8000LL)): + raise ValueError('high is out of bounds for int16') + if np.any(np.greater_equal(low_arr, high_arr)): + raise ValueError('low >= high') + + low_arr = np.PyArray_FROM_OTF(low, np.NPY_INT32, np.NPY_ALIGNED | np.NPY_FORCECAST) + high_arr = np.PyArray_FROM_OTF(high, np.NPY_INT32, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.int16) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.int16) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = np.PyArray_DATA(out_arr) + cnt = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(cnt): + low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] + rng = ((high_v - 1) - low_v) + off = (low_v) + + if rng != last_rng: + # Smallest bit mask >= max + mask = _gen_mask(rng) + + out_data[i] = random_buffered_bounded_uint16(state, off, rng, mask, &buf_rem, &buf) + + np.PyArray_MultiIter_NEXT(it) + return out_arr + + +cdef object _rand_int8_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): + """Array path for smaller integer types""" + cdef uint8_t rng, last_rng, off, val, mask, out_val + cdef uint32_t buf + cdef uint8_t *out_data + cdef uint16_t low_v, high_v + cdef np.ndarray low_arr, high_arr, out_arr + cdef np.npy_intp i, cnt + cdef np.broadcast it + cdef int buf_rem = 0 + + + # Array path + low_arr = low + high_arr = high + if np.any(np.less(low_arr, -0x80LL)): + raise ValueError('low is out of bounds for int8') + if np.any(np.greater(high_arr, 0x80LL)): + raise ValueError('high is out of bounds for int8') + if np.any(np.greater_equal(low_arr, high_arr)): + raise ValueError('low >= high') + + low_arr = np.PyArray_FROM_OTF(low, np.NPY_INT16, np.NPY_ALIGNED | np.NPY_FORCECAST) + high_arr = np.PyArray_FROM_OTF(high, np.NPY_INT16, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.int8) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.int8) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = np.PyArray_DATA(out_arr) + cnt = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(cnt): + low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] + rng = ((high_v - 1) - low_v) + off = (low_v) + + if rng != last_rng: + # Smallest bit mask >= max + mask = _gen_mask(rng) + + out_data[i] = random_buffered_bounded_uint8(state, off, rng, mask, &buf_rem, &buf) + + np.PyArray_MultiIter_NEXT(it) + return out_arr + + + +cdef object _rand_uint64_broadcast(object low, object high, object size, prng_t *state, object lock): + """Array path for 64-bit integer types""" + cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr + cdef np.npy_intp i, cnt, n + cdef np.broadcast it + cdef object closed_upper + cdef uint64_t *out_data + cdef uint64_t *highm1_data + cdef uint64_t low_v, high_v + cdef uint64_t rng, last_rng, val, mask, off, out_val + + low_arr = low + high_arr = high + + if np.any(np.less(low_arr, 0x0ULL)): + raise ValueError('low is out of bounds for uint64') + + highm1_arr = np.empty_like(high_arr, dtype=np.uint64) + highm1_data = np.PyArray_DATA(highm1_arr) + cnt = np.PyArray_SIZE(high_arr) + flat = high_arr.flat + for i in range(cnt): + closed_upper = int(flat[i]) - 1 + if closed_upper > 0xFFFFFFFFFFFFFFFFULL: + raise ValueError('high is out of bounds for uint64') + if closed_upper < 0x0ULL: + raise ValueError('low >= high') + highm1_data[i] = closed_upper + + if np.any(np.greater(low_arr, highm1_arr)): + raise ValueError('low >= high') + + high_arr = highm1_arr + low_arr = np.PyArray_FROM_OTF(low, np.NPY_UINT64, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.uint64) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.uint64) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = np.PyArray_DATA(out_arr) + n = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(n): + low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] + rng = (high_v - low_v) # No -1 here since implemented above + off = (low_v) + + if rng != last_rng: + mask = _gen_mask(rng) + out_data[i] = random_bounded_uint64(state, off, rng, mask) + + np.PyArray_MultiIter_NEXT(it) + + return out_arr + +cdef object _rand_int64_broadcast(object low, object high, object size, prng_t *state, object lock): + """Array path for 64-bit integer types""" + cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr + cdef np.npy_intp i, cnt, n + cdef np.broadcast it + cdef object closed_upper + cdef uint64_t *out_data + cdef int64_t *highm1_data + cdef int64_t low_v, high_v + cdef uint64_t rng, last_rng, val, mask, off, out_val + + low_arr = low + high_arr = high + + if np.any(np.less(low_arr, -0x8000000000000000LL)): + raise ValueError('low is out of bounds for int64') + + highm1_arr = np.empty_like(high_arr, dtype=np.int64) + highm1_data = np.PyArray_DATA(highm1_arr) + cnt = np.PyArray_SIZE(high_arr) + flat = high_arr.flat + for i in range(cnt): + closed_upper = int(flat[i]) - 1 + if closed_upper > 0x7FFFFFFFFFFFFFFFLL: + raise ValueError('high is out of bounds for int64') + if closed_upper < -0x8000000000000000LL: + raise ValueError('low >= high') + highm1_data[i] = closed_upper + + if np.any(np.greater(low_arr, highm1_arr)): + raise ValueError('low >= high') + + high_arr = highm1_arr + low_arr = np.PyArray_FROM_OTF(low, np.NPY_INT64, np.NPY_ALIGNED | np.NPY_FORCECAST) + + if size is not None: + out_arr = np.empty(size, np.int64) + else: + it = np.PyArray_MultiIterNew2(low_arr, high_arr) + out_arr = np.empty(it.shape, np.int64) + + it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) + out_data = np.PyArray_DATA(out_arr) + n = np.PyArray_SIZE(out_arr) + mask = last_rng = 0 + with lock, nogil: + for i in range(n): + low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] + high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] + rng = (high_v - low_v) # No -1 here since implemented above + off = (low_v) + + if rng != last_rng: + mask = _gen_mask(rng) + out_data[i] = random_bounded_uint64(state, off, rng, mask) + + np.PyArray_MultiIter_NEXT(it) + + return out_arr + + + +cdef object _rand_uint64(object low, object high, object size, prng_t *state, object lock): + """ + _rand_uint64(low, high, size, *state, lock) + + Return random np.uint64 integers between `low` and `high`, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [`low`, `high`). If `high` is None (the default), + then results are from [0, `low`). On entry the arguments are presumed + to have been validated for size and order for the np.uint64 type. + + Parameters + ---------- + low : int or array-like + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int or array-like + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + state : augmented random state + State to use in the core random number generators + lock : threading.Lock + Lock to prevent multiple using a single RandomState simultaneously + + Returns + ------- + out : python scalar or ndarray of np.uint64 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + """ + cdef np.ndarray out_arr, low_arr, high_arr + cdef uint64_t rng, off, out_val + cdef uint64_t *out_data + cdef np.npy_intp i, n, cnt + + if size is not None: + if (np.prod(size) == 0): + return np.empty(size, dtype=np.uint64) + + low_arr = np.array(low, copy=False) + high_arr = np.array(high, copy=False) + low_ndim = np.PyArray_NDIM(low_arr) + high_ndim = np.PyArray_NDIM(high_arr) + if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and + (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + low = int(low_arr) + high = int(high_arr) + high -= 1 + + if low < 0x0ULL: + raise ValueError("low is out of bounds for uint64") + if high > 0xFFFFFFFFFFFFFFFFULL: + raise ValueError("high is out of bounds for uint64") + if low > high: # -1 already subtracted, closed interval + raise ValueError("low >= high") + + rng = (high - low) + off = (low) + if size is None: + with lock: + random_bounded_uint64_fill(state, off, rng, 1, &out_val) + return np.uint64(out_val) + else: + out_arr = np.empty(size, np.uint64) + cnt = np.PyArray_SIZE(out_arr) + out_data = np.PyArray_DATA(out_arr) + with lock, nogil: + random_bounded_uint64_fill(state, off, rng, cnt, out_data) + return out_arr + return _rand_uint64_broadcast(low_arr, high_arr, size, state, lock) + +cdef object _rand_uint32(object low, object high, object size, prng_t *state, object lock): + """ + _rand_uint32(low, high, size, *state, lock) + + Return random np.uint32 integers between `low` and `high`, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [`low`, `high`). If `high` is None (the default), + then results are from [0, `low`). On entry the arguments are presumed + to have been validated for size and order for the np.uint32 type. + + Parameters + ---------- + low : int or array-like + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int or array-like + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + state : augmented random state + State to use in the core random number generators + lock : threading.Lock + Lock to prevent multiple using a single RandomState simultaneously + + Returns + ------- + out : python scalar or ndarray of np.uint32 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + """ + cdef np.ndarray out_arr, low_arr, high_arr + cdef uint32_t rng, off, out_val + cdef uint32_t *out_data + cdef np.npy_intp i, n, cnt + + if size is not None: + if (np.prod(size) == 0): + return np.empty(size, dtype=np.uint32) + + low_arr = np.array(low, copy=False) + high_arr = np.array(high, copy=False) + low_ndim = np.PyArray_NDIM(low_arr) + high_ndim = np.PyArray_NDIM(high_arr) + if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and + (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + low = int(low_arr) + high = int(high_arr) + high -= 1 + + if low < 0x0UL: + raise ValueError("low is out of bounds for uint32") + if high > 0XFFFFFFFFUL: + raise ValueError("high is out of bounds for uint32") + if low > high: # -1 already subtracted, closed interval + raise ValueError("low >= high") + + rng = (high - low) + off = (low) + if size is None: + with lock: + random_bounded_uint32_fill(state, off, rng, 1, &out_val) + return np.uint32(out_val) + else: + out_arr = np.empty(size, np.uint32) + cnt = np.PyArray_SIZE(out_arr) + out_data = np.PyArray_DATA(out_arr) + with lock, nogil: + random_bounded_uint32_fill(state, off, rng, cnt, out_data) + return out_arr + return _rand_uint32_broadcast(low_arr, high_arr, size, state, lock) + +cdef object _rand_uint16(object low, object high, object size, prng_t *state, object lock): + """ + _rand_uint16(low, high, size, *state, lock) + + Return random np.uint16 integers between `low` and `high`, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [`low`, `high`). If `high` is None (the default), + then results are from [0, `low`). On entry the arguments are presumed + to have been validated for size and order for the np.uint16 type. + + Parameters + ---------- + low : int or array-like + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int or array-like + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + state : augmented random state + State to use in the core random number generators + lock : threading.Lock + Lock to prevent multiple using a single RandomState simultaneously + + Returns + ------- + out : python scalar or ndarray of np.uint16 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + """ + cdef np.ndarray out_arr, low_arr, high_arr + cdef uint16_t rng, off, out_val + cdef uint16_t *out_data + cdef np.npy_intp i, n, cnt + + if size is not None: + if (np.prod(size) == 0): + return np.empty(size, dtype=np.uint16) + + low_arr = np.array(low, copy=False) + high_arr = np.array(high, copy=False) + low_ndim = np.PyArray_NDIM(low_arr) + high_ndim = np.PyArray_NDIM(high_arr) + if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and + (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + low = int(low_arr) + high = int(high_arr) + high -= 1 + + if low < 0x0UL: + raise ValueError("low is out of bounds for uint16") + if high > 0XFFFFUL: + raise ValueError("high is out of bounds for uint16") + if low > high: # -1 already subtracted, closed interval + raise ValueError("low >= high") + + rng = (high - low) + off = (low) + if size is None: + with lock: + random_bounded_uint16_fill(state, off, rng, 1, &out_val) + return np.uint16(out_val) + else: + out_arr = np.empty(size, np.uint16) + cnt = np.PyArray_SIZE(out_arr) + out_data = np.PyArray_DATA(out_arr) + with lock, nogil: + random_bounded_uint16_fill(state, off, rng, cnt, out_data) + return out_arr + return _rand_uint16_broadcast(low_arr, high_arr, size, state, lock) + +cdef object _rand_uint8(object low, object high, object size, prng_t *state, object lock): + """ + _rand_uint8(low, high, size, *state, lock) + + Return random np.uint8 integers between `low` and `high`, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [`low`, `high`). If `high` is None (the default), + then results are from [0, `low`). On entry the arguments are presumed + to have been validated for size and order for the np.uint8 type. + + Parameters + ---------- + low : int or array-like + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int or array-like + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + state : augmented random state + State to use in the core random number generators + lock : threading.Lock + Lock to prevent multiple using a single RandomState simultaneously + + Returns + ------- + out : python scalar or ndarray of np.uint8 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + """ + cdef np.ndarray out_arr, low_arr, high_arr + cdef uint8_t rng, off, out_val + cdef uint8_t *out_data + cdef np.npy_intp i, n, cnt + + if size is not None: + if (np.prod(size) == 0): + return np.empty(size, dtype=np.uint8) + + low_arr = np.array(low, copy=False) + high_arr = np.array(high, copy=False) + low_ndim = np.PyArray_NDIM(low_arr) + high_ndim = np.PyArray_NDIM(high_arr) + if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and + (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + low = int(low_arr) + high = int(high_arr) + high -= 1 + + if low < 0x0UL: + raise ValueError("low is out of bounds for uint8") + if high > 0XFFUL: + raise ValueError("high is out of bounds for uint8") + if low > high: # -1 already subtracted, closed interval + raise ValueError("low >= high") + + rng = (high - low) + off = (low) + if size is None: + with lock: + random_bounded_uint8_fill(state, off, rng, 1, &out_val) + return np.uint8(out_val) + else: + out_arr = np.empty(size, np.uint8) + cnt = np.PyArray_SIZE(out_arr) + out_data = np.PyArray_DATA(out_arr) + with lock, nogil: + random_bounded_uint8_fill(state, off, rng, cnt, out_data) + return out_arr + return _rand_uint8_broadcast(low_arr, high_arr, size, state, lock) + +cdef object _rand_bool(object low, object high, object size, prng_t *state, object lock): + """ + _rand_bool(low, high, size, *state, lock) + + Return random np.bool integers between `low` and `high`, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [`low`, `high`). If `high` is None (the default), + then results are from [0, `low`). On entry the arguments are presumed + to have been validated for size and order for the np.bool type. + + Parameters + ---------- + low : int or array-like + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int or array-like + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + state : augmented random state + State to use in the core random number generators + lock : threading.Lock + Lock to prevent multiple using a single RandomState simultaneously + + Returns + ------- + out : python scalar or ndarray of np.bool + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + """ + cdef np.ndarray out_arr, low_arr, high_arr + cdef bool_t rng, off, out_val + cdef bool_t *out_data + cdef np.npy_intp i, n, cnt + + if size is not None: + if (np.prod(size) == 0): + return np.empty(size, dtype=np.bool) + + low_arr = np.array(low, copy=False) + high_arr = np.array(high, copy=False) + low_ndim = np.PyArray_NDIM(low_arr) + high_ndim = np.PyArray_NDIM(high_arr) + if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and + (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + low = int(low_arr) + high = int(high_arr) + high -= 1 + + if low < 0x0UL: + raise ValueError("low is out of bounds for bool") + if high > 0x1UL: + raise ValueError("high is out of bounds for bool") + if low > high: # -1 already subtracted, closed interval + raise ValueError("low >= high") + + rng = (high - low) + off = (low) + if size is None: + with lock: + random_bounded_bool_fill(state, off, rng, 1, &out_val) + return np.bool_(out_val) + else: + out_arr = np.empty(size, np.bool) + cnt = np.PyArray_SIZE(out_arr) + out_data = np.PyArray_DATA(out_arr) + with lock, nogil: + random_bounded_bool_fill(state, off, rng, cnt, out_data) + return out_arr + return _rand_bool_broadcast(low_arr, high_arr, size, state, lock) + +cdef object _rand_int64(object low, object high, object size, prng_t *state, object lock): + """ + _rand_int64(low, high, size, *state, lock) + + Return random np.int64 integers between `low` and `high`, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [`low`, `high`). If `high` is None (the default), + then results are from [0, `low`). On entry the arguments are presumed + to have been validated for size and order for the np.int64 type. + + Parameters + ---------- + low : int or array-like + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int or array-like + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + state : augmented random state + State to use in the core random number generators + lock : threading.Lock + Lock to prevent multiple using a single RandomState simultaneously + + Returns + ------- + out : python scalar or ndarray of np.int64 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + """ + cdef np.ndarray out_arr, low_arr, high_arr + cdef uint64_t rng, off, out_val + cdef uint64_t *out_data + cdef np.npy_intp i, n, cnt + + if size is not None: + if (np.prod(size) == 0): + return np.empty(size, dtype=np.int64) + + low_arr = np.array(low, copy=False) + high_arr = np.array(high, copy=False) + low_ndim = np.PyArray_NDIM(low_arr) + high_ndim = np.PyArray_NDIM(high_arr) + if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and + (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + low = int(low_arr) + high = int(high_arr) + high -= 1 + + if low < -0x8000000000000000LL: + raise ValueError("low is out of bounds for int64") + if high > 0x7FFFFFFFFFFFFFFFL: + raise ValueError("high is out of bounds for int64") + if low > high: # -1 already subtracted, closed interval + raise ValueError("low >= high") + + rng = (high - low) + off = (low) + if size is None: + with lock: + random_bounded_uint64_fill(state, off, rng, 1, &out_val) + return np.int64(out_val) + else: + out_arr = np.empty(size, np.int64) + cnt = np.PyArray_SIZE(out_arr) + out_data = np.PyArray_DATA(out_arr) + with lock, nogil: + random_bounded_uint64_fill(state, off, rng, cnt, out_data) + return out_arr + return _rand_int64_broadcast(low_arr, high_arr, size, state, lock) + +cdef object _rand_int32(object low, object high, object size, prng_t *state, object lock): + """ + _rand_int32(low, high, size, *state, lock) + + Return random np.int32 integers between `low` and `high`, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [`low`, `high`). If `high` is None (the default), + then results are from [0, `low`). On entry the arguments are presumed + to have been validated for size and order for the np.int32 type. + + Parameters + ---------- + low : int or array-like + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int or array-like + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + state : augmented random state + State to use in the core random number generators + lock : threading.Lock + Lock to prevent multiple using a single RandomState simultaneously + + Returns + ------- + out : python scalar or ndarray of np.int32 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + """ + cdef np.ndarray out_arr, low_arr, high_arr + cdef uint32_t rng, off, out_val + cdef uint32_t *out_data + cdef np.npy_intp i, n, cnt + + if size is not None: + if (np.prod(size) == 0): + return np.empty(size, dtype=np.int32) + + low_arr = np.array(low, copy=False) + high_arr = np.array(high, copy=False) + low_ndim = np.PyArray_NDIM(low_arr) + high_ndim = np.PyArray_NDIM(high_arr) + if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and + (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + low = int(low_arr) + high = int(high_arr) + high -= 1 + + if low < -0x80000000L: + raise ValueError("low is out of bounds for int32") + if high > 0x7FFFFFFFL: + raise ValueError("high is out of bounds for int32") + if low > high: # -1 already subtracted, closed interval + raise ValueError("low >= high") + + rng = (high - low) + off = (low) + if size is None: + with lock: + random_bounded_uint32_fill(state, off, rng, 1, &out_val) + return np.int32(out_val) + else: + out_arr = np.empty(size, np.int32) + cnt = np.PyArray_SIZE(out_arr) + out_data = np.PyArray_DATA(out_arr) + with lock, nogil: + random_bounded_uint32_fill(state, off, rng, cnt, out_data) + return out_arr + return _rand_int32_broadcast(low_arr, high_arr, size, state, lock) + +cdef object _rand_int16(object low, object high, object size, prng_t *state, object lock): + """ + _rand_int16(low, high, size, *state, lock) + + Return random np.int16 integers between `low` and `high`, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [`low`, `high`). If `high` is None (the default), + then results are from [0, `low`). On entry the arguments are presumed + to have been validated for size and order for the np.int16 type. + + Parameters + ---------- + low : int or array-like + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int or array-like + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + state : augmented random state + State to use in the core random number generators + lock : threading.Lock + Lock to prevent multiple using a single RandomState simultaneously + + Returns + ------- + out : python scalar or ndarray of np.int16 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + """ + cdef np.ndarray out_arr, low_arr, high_arr + cdef uint16_t rng, off, out_val + cdef uint16_t *out_data + cdef np.npy_intp i, n, cnt + + if size is not None: + if (np.prod(size) == 0): + return np.empty(size, dtype=np.int16) + + low_arr = np.array(low, copy=False) + high_arr = np.array(high, copy=False) + low_ndim = np.PyArray_NDIM(low_arr) + high_ndim = np.PyArray_NDIM(high_arr) + if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and + (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + low = int(low_arr) + high = int(high_arr) + high -= 1 + + if low < -0x8000L: + raise ValueError("low is out of bounds for int16") + if high > 0x7FFFL: + raise ValueError("high is out of bounds for int16") + if low > high: # -1 already subtracted, closed interval + raise ValueError("low >= high") + + rng = (high - low) + off = (low) + if size is None: + with lock: + random_bounded_uint16_fill(state, off, rng, 1, &out_val) + return np.int16(out_val) + else: + out_arr = np.empty(size, np.int16) + cnt = np.PyArray_SIZE(out_arr) + out_data = np.PyArray_DATA(out_arr) + with lock, nogil: + random_bounded_uint16_fill(state, off, rng, cnt, out_data) + return out_arr + return _rand_int16_broadcast(low_arr, high_arr, size, state, lock) + +cdef object _rand_int8(object low, object high, object size, prng_t *state, object lock): + """ + _rand_int8(low, high, size, *state, lock) + + Return random np.int8 integers between `low` and `high`, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [`low`, `high`). If `high` is None (the default), + then results are from [0, `low`). On entry the arguments are presumed + to have been validated for size and order for the np.int8 type. + + Parameters + ---------- + low : int or array-like + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int or array-like + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + state : augmented random state + State to use in the core random number generators + lock : threading.Lock + Lock to prevent multiple using a single RandomState simultaneously + + Returns + ------- + out : python scalar or ndarray of np.int8 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + """ + cdef np.ndarray out_arr, low_arr, high_arr + cdef uint8_t rng, off, out_val + cdef uint8_t *out_data + cdef np.npy_intp i, n, cnt + + if size is not None: + if (np.prod(size) == 0): + return np.empty(size, dtype=np.int8) + + low_arr = np.array(low, copy=False) + high_arr = np.array(high, copy=False) + low_ndim = np.PyArray_NDIM(low_arr) + high_ndim = np.PyArray_NDIM(high_arr) + if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and + (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + low = int(low_arr) + high = int(high_arr) + high -= 1 + + if low < -0x80L: + raise ValueError("low is out of bounds for int8") + if high > 0x7FL: + raise ValueError("high is out of bounds for int8") + if low > high: # -1 already subtracted, closed interval + raise ValueError("low >= high") + + rng = (high - low) + off = (low) + if size is None: + with lock: + random_bounded_uint8_fill(state, off, rng, 1, &out_val) + return np.int8(out_val) + else: + out_arr = np.empty(size, np.int8) + cnt = np.PyArray_SIZE(out_arr) + out_data = np.PyArray_DATA(out_arr) + with lock, nogil: + random_bounded_uint8_fill(state, off, rng, cnt, out_data) + return out_arr + return _rand_int8_broadcast(low_arr, high_arr, size, state, lock) diff --git a/_randomgen/core_prng/bounded_integers.pyx.in b/_randomgen/core_prng/bounded_integers.pyx.in index 00dc08571125..ea0bba028d0b 100644 --- a/_randomgen/core_prng/bounded_integers.pyx.in +++ b/_randomgen/core_prng/bounded_integers.pyx.in @@ -1,15 +1,10 @@ -from distributions cimport * +#!python +#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True -_randint_type = {'bool': (0, 2), - 'int8': (-2**7, 2**7), - 'int16': (-2**15, 2**15), - 'int32': (-2**31, 2**31), - 'int64': (-2**63, 2**63), - 'uint8': (0, 2**8), - 'uint16': (0, 2**16), - 'uint32': (0, 2**32), - 'uint64': (0, 2**64) - } +import numpy as np +cimport numpy as np +from distributions cimport * +np.import_array() {{ py: @@ -86,7 +81,7 @@ big_type_info = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFF cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, prng_t *state, object lock): """Array path for 64-bit integer types""" cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr - cdef np.npy_intp i, cnt + cdef np.npy_intp i, cnt, n cdef np.broadcast it cdef object closed_upper cdef uint64_t *out_data @@ -196,7 +191,7 @@ cdef object _rand_{{nptype}}(object low, object high, object size, prng_t *state cdef np.ndarray out_arr, low_arr, high_arr cdef {{utype}}_t rng, off, out_val cdef {{utype}}_t *out_data - cdef np.npy_intp i, cnt + cdef np.npy_intp i, n, cnt if size is not None: if (np.prod(size) == 0): diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index b7a6f5327cfd..5dedbdbde1e8 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -1,3 +1,6 @@ +#!python +#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True + import sys import numpy as np cimport numpy as np @@ -59,7 +62,7 @@ cdef object double_fill(void *func, prng_t *state, object size, object lock, obj cdef np.ndarray out_array cdef np.npy_intp i, n - if size is None: + if size is None and out is None: with lock: return random_func(state) @@ -82,7 +85,7 @@ cdef object float_fill(void *func, prng_t *state, object size, object lock, obje cdef np.ndarray out_array cdef np.npy_intp i, n - if size is None: + if size is None and out is None: with lock: return random_func(state) @@ -105,7 +108,7 @@ cdef object float_fill_from_double(void *func, prng_t *state, object size, objec cdef np.ndarray out_array cdef np.npy_intp i, n - if size is None: + if size is None and out is None: with lock: return random_func(state) diff --git a/_randomgen/core_prng/distributions.pxd b/_randomgen/core_prng/distributions.pxd index 22761826af74..5359a1be0eaa 100644 --- a/_randomgen/core_prng/distributions.pxd +++ b/_randomgen/core_prng/distributions.pxd @@ -56,7 +56,6 @@ cdef extern from "src/distributions/distributions.h": float random_standard_gamma_f(prng_t *prng_state, float shape) nogil float random_standard_gamma_zig_f(prng_t *prng_state, float shape) nogil - uint32_t random_uint32(prng_t *prng_state) nogil int64_t random_positive_int64(prng_t *prng_state) nogil int32_t random_positive_int32(prng_t *prng_state) nogil long random_positive_int(prng_t *prng_state) nogil diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index 09857aa621fb..c95f4f2d3918 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -85,7 +85,7 @@ cdef class DSFMT: def __init__(self, seed=None): self.rng_state = malloc(sizeof(dsfmt_state)) self.rng_state.state = PyArray_malloc_aligned(sizeof(dsfmt_t)) - self.rng_state.buffered_uniforms = PyArray_malloc_aligned(DSFMT_N64 * sizeof(double)) + self.rng_state.buffered_uniforms = PyArray_calloc_aligned(DSFMT_N64, sizeof(double)) self.rng_state.buffer_loc = DSFMT_N64 self._prng = malloc(sizeof(prng_t)) self._prng.binomial = malloc(sizeof(binomial_t)) @@ -117,8 +117,11 @@ cdef class DSFMT: free(self._prng.binomial) free(self._prng) - def _reset_state_variables(self): - pass + cdef _reset_state_variables(self): + self._prng.has_gauss = 0 + self._prng.has_gauss_f = 0 + self._prng.gauss = 0.0 + self._prng.gauss_f = 0.0 def __random_integer(self, bits=64): """ @@ -199,6 +202,7 @@ cdef class DSFMT: dsfmt_init_by_array(self.rng_state.state, obj.data, np.PyArray_DIM(obj, 0)) + self._reset_state_variables() def seed(self, seed=None): """ diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 811b8d978224..240fb192eacd 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -10,6 +10,7 @@ from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from cpython cimport Py_INCREF, PyComplex_RealAsDouble, PyComplex_ImagAsDouble, PyComplex_FromDoubles from common cimport * from distributions cimport * +from bounded_integers cimport * from libc cimport string from libc.stdlib cimport malloc, free @@ -29,6 +30,17 @@ import core_prng.pickle np.import_array() +_randint_types = {'bool': (0, 2), + 'int8': (-2**7, 2**7), + 'int16': (-2**15, 2**15), + 'int32': (-2**31, 2**31), + 'int64': (-2**63, 2**63), + 'uint8': (0, 2**8), + 'uint16': (0, 2**16), + 'uint32': (0, 2**32), + 'uint64': (0, 2**64) + } + cdef class RandomGenerator: """ Prototype Random Generator that consumes randoms from a CorePRNG class @@ -75,6 +87,13 @@ cdef class RandomGenerator: (self.state['prng'],), self.state) + def seed(self, *args, **kwargs): + """ + TODO: Should this remain + """ + self.__core_prng.seed(*args, **kwargs) + return self + @property def state(self): """Get or set the underlying PRNG's state""" @@ -210,7 +229,6 @@ cdef class RandomGenerator: return randoms def random_integer(self, bits=64): - #print("In random_integer") if bits == 64: return self._prng.next_uint64(self._prng.state) elif bits == 32: @@ -568,7 +586,37 @@ cdef class RandomGenerator: array([[ 8, 6, 9, 7], [ 1, 16, 9, 12]], dtype=uint8) """ - raise NotImplementedError('To be completed') + if high is None: + high = low + low = 0 + + key = np.dtype(dtype).name + if not key in _randint_types: + raise TypeError('Unsupported dtype "%s" for randint' % key) + + if key == 'int32': + ret = _rand_int32(low, high, size, self._prng, self.lock) + elif key == 'int64': + ret = _rand_int64(low, high, size, self._prng, self.lock) + elif key == 'int16': + ret = _rand_int16(low, high, size, self._prng, self.lock) + elif key == 'int8': + ret = _rand_int8(low, high, size, self._prng, self.lock) + elif key == 'uint64': + ret = _rand_uint64(low, high, size, self._prng, self.lock) + elif key == 'uint32': + ret = _rand_uint32(low, high, size, self._prng, self.lock) + elif key == 'uint16': + ret = _rand_uint16(low, high, size, self._prng, self.lock) + elif key == 'uint8': + ret = _rand_uint8(low, high, size, self._prng, self.lock) + elif key == 'bool': + ret = _rand_bool(low, high, size, self._prng, self.lock) + + if size is None and dtype in (np.bool, np.int, np.long): + if np.array(ret).shape == (): + return dtype(ret) + return ret def bytes(self, np.npy_intp length): """ @@ -1095,8 +1143,6 @@ cdef class RandomGenerator: return self.randint(low, high + 1, size=size, dtype='l') - - # Complicated, continuous distributions: def standard_normal(self, size=None, dtype=np.float64, method=u'zig', out=None): """ diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index 8f2f77f83922..c8ea21b66654 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -78,6 +78,12 @@ cdef class MT19937: free(self._prng.binomial) free(self._prng) + cdef _reset_state_variables(self): + self._prng.has_gauss = 0 + self._prng.has_gauss_f = 0 + self._prng.gauss = 0.0 + self._prng.gauss_f = 0.0 + # Pickling support: def __getstate__(self): return self.state @@ -167,6 +173,7 @@ cdef class MT19937: raise ValueError("Seed must be between 0 and 2**32 - 1") obj = obj.astype(np.uint32, casting='unsafe', order='C') mt19937_init_by_array(self.rng_state, obj.data, np.PyArray_DIM(obj, 0)) + self._reset_state_variables() def jump(self): mt19937_jump(self.rng_state) diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index bba905c19c98..7353a77beaf2 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -50,7 +50,7 @@ cdef extern from "src/pcg64/pcg64.h": uint64_t pcg64_next32(pcg64_state *state) nogil void pcg64_jump(pcg64_state *state) void pcg64_advance(pcg64_state *state, uint64_t *step) - + void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc) cdef uint64_t pcg64_uint64(void* st) nogil: return pcg64_next64(st) @@ -112,9 +112,13 @@ cdef class PCG64: free(self._prng.binomial) free(self._prng) - def _reset_state_variables(self): + cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 + self._prng.has_gauss = 0 + self._prng.has_gauss_f = 0 + self._prng.gauss = 0.0 + self._prng.gauss_f = 0.0 def __random_integer(self, bits=64): """ @@ -176,23 +180,33 @@ cdef class PCG64: If seed values are out of range for the PRNG. """ - ub = 2 ** 64 + cdef np.ndarray _seed, _inc + ub = 2 ** 128 if seed is None: try: - state = random_entropy(4) + _seed = random_entropy(4) except RuntimeError: - state = random_entropy(4, 'fallback') - state = state.view(np.uint64) + _seed = random_entropy(4, 'fallback') + + _seed = _seed.view(np.uint64) else: - state = entropy.seed_by_array(seed, 2) - IF PCG_EMULATED_MATH==1: - self.rng_state.pcg_state.state.high = int(state[0]) - self.rng_state.pcg_state.state.low = int(state[1]) - self.rng_state.pcg_state.inc.high = inc // 2**64 - self.rng_state.pcg_state.inc.low = inc % 2**64 - ELSE: - self.rng_state.pcg_state.state = state[0] * 2**64 + state[1] - self.rng_state.pcg_state.inc = inc + if not np.isscalar(seed): + raise TypeError('seed must be a scalar integer between 0 and {ub}'.format(ub=ub)) + if seed < 0 or seed > ub or int(seed) != seed: + raise ValueError('inc must be a scalar integer between 0 and {ub}'.format(ub=ub)) + _seed = np.empty(2, np.uint64) + _seed[0] = int(seed) // 2**64 + _seed[1] = int(seed) % 2**64 + + if not np.isscalar(inc): + raise TypeError('inc must be a scalar integer between 0 and {ub}'.format(ub=ub)) + if inc < 0 or inc > ub or int(inc) != inc: + raise ValueError('inc must be a scalar integer between 0 and {ub}'.format(ub=ub)) + _inc = np.empty(2, np.uint64) + _inc[0] = int(inc) // 2**64 + _inc[1] = int(inc) % 2**64 + + pcg64_set_seed(self.rng_state, _seed.data, _inc.data) self._reset_state_variables() @property diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx index 41c520a1aba3..12d69fe6813a 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/core_prng/philox.pyx @@ -107,9 +107,13 @@ cdef class Philox: free(self._prng.binomial) free(self._prng) - def _reset_state_variables(self): + cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 + self._prng.has_gauss = 0 + self._prng.has_gauss_f = 0 + self._prng.gauss = 0.0 + self._prng.gauss_f = 0.0 self.rng_state.buffer_pos = PHILOX_BUFFER_SIZE for i in range(PHILOX_BUFFER_SIZE): self.rng_state.buffer[i] = 0 diff --git a/_randomgen/core_prng/pickle.py b/_randomgen/core_prng/pickle.py index d4e5a1f71d63..44b7e6b24210 100644 --- a/_randomgen/core_prng/pickle.py +++ b/_randomgen/core_prng/pickle.py @@ -1,4 +1,5 @@ from .generator import RandomGenerator +from .dsfmt import DSFMT from .mt19937 import MT19937 from .pcg64 import PCG64 from .philox import Philox @@ -7,6 +8,7 @@ from .xorshift1024 import Xorshift1024 PRNGS = {'MT19937': MT19937, + 'DSFMT': DSFMT, 'PCG64': PCG64, 'Philox': Philox, 'ThreeFry': ThreeFry, diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 3edc59261041..7238cfa03cbe 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -7,7 +7,7 @@ static NPY_INLINE float next_float(prng_t *prng_state) { (1.0f / 8388608.0f); } -uint32_t random_uint32(prng_t *prng_state) { +static NPY_INLINE uint32_t random_uint32(prng_t *prng_state) { return prng_state->next_uint32(prng_state->state); } diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index aedd0c6505e8..ce24cb11772e 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -68,7 +68,6 @@ typedef struct prng { DECLDIR float random_sample_f(prng_t *prng_state); DECLDIR double random_sample(prng_t *prng_state); -DECLDIR uint32_t random_uint32(prng_t *prng_state); DECLDIR int64_t random_positive_int64(prng_t *prng_state); DECLDIR int32_t random_positive_int32(prng_t *prng_state); DECLDIR long random_positive_int(prng_t *prng_state); diff --git a/_randomgen/core_prng/src/pcg64/pcg64.c b/_randomgen/core_prng/src/pcg64/pcg64.c index f51099f3f314..c7c1eb045a41 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.c +++ b/_randomgen/core_prng/src/pcg64/pcg64.c @@ -102,3 +102,17 @@ extern void pcg64_advance(pcg64_state *state, uint64_t *step) { #endif pcg64_advance_r(state->pcg_state, delta); } + +extern void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc) { + pcg128_t s, i; +#if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH) + s = (((pcg128_t)seed[0]) << 64) | seed[1]; + i = (((pcg128_t)inc[0]) << 64) | inc[1]; +#else + s.high = seed[0]; + s.low = seed[1]; + i.high = inc[0]; + i.low = inc[1]; +#endif + pcg64_srandom_r(state->pcg_state, s, i); +} diff --git a/_randomgen/core_prng/src/pcg64/pcg64.h b/_randomgen/core_prng/src/pcg64/pcg64.h index 8b1746d9d0dc..8122d5579650 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.h +++ b/_randomgen/core_prng/src/pcg64/pcg64.h @@ -61,9 +61,7 @@ inline pcg128_t PCG_128BIT_CONSTANT(uint64_t high, uint64_t low) { #define PCG_EMULATED_128BIT_MATH 1 #endif -typedef struct { - pcg128_t state; -} pcg_state_128; +typedef struct { pcg128_t state; } pcg_state_128; typedef struct { pcg128_t state; @@ -76,8 +74,8 @@ typedef struct { PCG_128BIT_CONSTANT(6364136223846793005ULL, 1442695040888963407ULL) #define PCG_STATE_SETSEQ_128_INITIALIZER \ { \ - PCG_128BIT_CONSTANT(0x979c9a98d8462005ULL, 0x7d3e9cb6cfe0549bULL), \ - PCG_128BIT_CONSTANT(0x0000000000000001ULL, 0xda3e39cb94b95bdbULL) \ + PCG_128BIT_CONSTANT(0x979c9a98d8462005ULL, 0x7d3e9cb6cfe0549bULL) \ + , PCG_128BIT_CONSTANT(0x0000000000000001ULL, 0xda3e39cb94b95bdbULL) \ } inline uint64_t pcg_rotr_64(uint64_t value, unsigned int rot) { @@ -225,3 +223,5 @@ static inline uint32_t pcg64_next32(pcg64_state *state) { } void pcg64_advance(pcg64_state *state, uint64_t *step); + +void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc); diff --git a/_randomgen/core_prng/tests/test_smoke.py b/_randomgen/core_prng/tests/test_smoke.py new file mode 100644 index 000000000000..a5678dbaa406 --- /dev/null +++ b/_randomgen/core_prng/tests/test_smoke.py @@ -0,0 +1,976 @@ +import pickle +import time +import sys +import os +import numpy as np +import pytest + +from core_prng import * +from core_prng import entropy + +from numpy.testing import assert_almost_equal, assert_equal, assert_raises, assert_, assert_array_equal + + +@pytest.fixture(scope='module', params=(np.bool, np.int8, np.int16, np.int32, np.int64, + np.uint8, np.uint16, np.uint32, np.uint64)) +def dtype(request): + return request.param + + +def params_0(f): + val = f() + assert_(np.isscalar(val)) + val = f(10) + assert_(val.shape == (10,)) + val = f((10, 10)) + assert_(val.shape == (10, 10)) + val = f((10, 10, 10)) + assert_(val.shape == (10, 10, 10)) + val = f(size=(5, 5)) + assert_(val.shape == (5, 5)) + + +def params_1(f, bounded=False): + a = 5.0 + b = np.arange(2.0, 12.0) + c = np.arange(2.0, 102.0).reshape(10, 10) + d = np.arange(2.0, 1002.0).reshape(10, 10, 10) + e = np.array([2.0, 3.0]) + g = np.arange(2.0, 12.0).reshape(1, 10, 1) + if bounded: + a = 0.5 + b = b / (1.5 * b.max()) + c = c / (1.5 * c.max()) + d = d / (1.5 * d.max()) + e = e / (1.5 * e.max()) + g = g / (1.5 * g.max()) + + # Scalar + f(a) + # Scalar - size + f(a, size=(10, 10)) + # 1d + f(b) + # 2d + f(c) + # 3d + f(d) + # 1d size + f(b, size=10) + # 2d - size - broadcast + f(e, size=(10, 2)) + # 3d - size + f(g, size=(10, 10, 10)) + + +def comp_state(state1, state2): + identical = True + if isinstance(state1, dict): + for key in state1: + identical &= comp_state(state1[key], state2[key]) + elif type(state1) != type(state2): + identical &= type(state1) == type(state2) + else: + if (isinstance(state1, (list, tuple, np.ndarray)) and isinstance(state2, (list, tuple, np.ndarray))): + for s1, s2 in zip(state1, state2): + identical &= comp_state(s1, s2) + else: + identical &= state1 == state2 + return identical + + +def warmup(rg, n=None): + if n is None: + n = 11 + np.random.randint(0, 20) + rg.standard_normal(n, method='bm') + rg.standard_normal(n, method='zig') + rg.standard_normal(n, method='bm', dtype=np.float32) + rg.standard_normal(n, method='zig', dtype=np.float32) + rg.randint(0, 2 ** 24, n, dtype=np.uint64) + rg.randint(0, 2 ** 48, n, dtype=np.uint64) + rg.standard_gamma(11.0, n) + rg.standard_gamma(11.0, n, dtype=np.float32) + rg.random_sample(n, dtype=np.float64) + rg.random_sample(n, dtype=np.float32) + + +class RNG(object): + @classmethod + def _extra_setup(cls): + cls.vec_1d = np.arange(2.0, 102.0) + cls.vec_2d = np.arange(2.0, 102.0)[None, :] + cls.mat = np.arange(2.0, 102.0, 0.01).reshape((100, 100)) + cls.seed_error = TypeError + + def _reset_state(self): + self.rg.state = self.initial_state + + def test_init(self): + rg = RandomGenerator(self.prng()) + state = rg.state + rg.standard_normal(1, method='bm') + rg.standard_normal(1, method='zig') + rg.state = state + new_state = rg.state + assert_(comp_state(state, new_state)) + + def test_advance(self): + state = self.rg.state + if hasattr(self.rg, 'advance'): + self.rg.advance(self.advance) + assert_(not comp_state(state, self.rg.state)) + else: + pytest.skip() + + def test_jump(self): + state = self.rg.state + if hasattr(self.rg, 'jump'): + self.rg.jump() + jumped_state = self.rg.state + assert_(not comp_state(state, jumped_state)) + self.rg.random_sample(2*3*5*7*11*13*17) + self.rg.state = state + self.rg.jump() + rejumped_state = self.rg.state + assert_(comp_state(jumped_state, rejumped_state)) + else: + pytest.skip() + + def test_random_uintegers(self): + assert_(len(self.rg.random_uintegers(10)) == 10) + + def test_random_raw(self): + assert_(len(self.rg.random_raw(10)) == 10) + assert_(self.rg.random_raw((10, 10)).shape == (10, 10)) + + def test_uniform(self): + r = self.rg.uniform(-1.0, 0.0, size=10) + assert_(len(r) == 10) + assert_((r > -1).all()) + assert_((r <= 0).all()) + + def test_uniform_array(self): + r = self.rg.uniform(np.array([-1.0] * 10), 0.0, size=10) + assert_(len(r) == 10) + assert_((r > -1).all()) + assert_((r <= 0).all()) + r = self.rg.uniform(np.array([-1.0] * 10), + np.array([0.0] * 10), size=10) + assert_(len(r) == 10) + assert_((r > -1).all()) + assert_((r <= 0).all()) + r = self.rg.uniform(-1.0, np.array([0.0] * 10), size=10) + assert_(len(r) == 10) + assert_((r > -1).all()) + assert_((r <= 0).all()) + + def test_random_sample(self): + assert_(len(self.rg.random_sample(10)) == 10) + params_0(self.rg.random_sample) + + def test_standard_normal_zig(self): + assert_(len(self.rg.standard_normal(10, method='zig')) == 10) + + def test_standard_normal(self): + assert_(len(self.rg.standard_normal(10)) == 10) + params_0(self.rg.standard_normal) + + def test_standard_gamma(self): + assert_(len(self.rg.standard_gamma(10, 10)) == 10) + assert_(len(self.rg.standard_gamma(np.array([10] * 10), 10)) == 10) + params_1(self.rg.standard_gamma) + + def test_standard_exponential(self): + assert_(len(self.rg.standard_exponential(10)) == 10) + params_0(self.rg.standard_exponential) + + def test_standard_cauchy(self): + assert_(len(self.rg.standard_cauchy(10)) == 10) + params_0(self.rg.standard_cauchy) + + def test_standard_t(self): + assert_(len(self.rg.standard_t(10, 10)) == 10) + params_1(self.rg.standard_t) + + def test_binomial(self): + assert_(self.rg.binomial(10, .5) >= 0) + assert_(self.rg.binomial(1000, .5) >= 0) + + def test_reset_state(self): + state = self.rg.state + int_1 = self.rg.random_raw(1) + self.rg.state = state + int_2 = self.rg.random_raw(1) + assert_(int_1 == int_2) + + def test_entropy_init(self): + rg = RandomGenerator(self.prng()) + rg2 = RandomGenerator(self.prng()) + s1 = rg.state + s2 = rg2.state + assert_(not comp_state(rg.state, rg2.state)) + + def test_seed(self): + rg = RandomGenerator(self.prng(*self.seed)) + rg2 = RandomGenerator(self.prng(*self.seed)) + rg.random_sample() + rg2.random_sample() + if not comp_state(rg.state, rg2.state): + for key in rg.state: + print(key) + print(rg.state[key]) + print(rg2.state[key]) + assert_(comp_state(rg.state, rg2.state)) + + def test_reset_state_gauss(self): + rg = RandomGenerator(self.prng(*self.seed)) + rg.standard_normal() + state = rg.state + n1 = rg.standard_normal(size=10) + rg2 = RandomGenerator(self.prng()) + rg2.state = state + n2 = rg2.standard_normal(size=10) + assert_array_equal(n1, n2) + + def test_reset_state_uint32(self): + rg = RandomGenerator(self.prng(*self.seed)) + rg.randint(0, 2 ** 24, 120, dtype=np.uint32) + state = rg.state + n1 = rg.randint(0, 2 ** 24, 10, dtype=np.uint32) + rg2 = RandomGenerator(self.prng()) + rg2.state = state + n2 = rg2.randint(0, 2 ** 24, 10, dtype=np.uint32) + assert_array_equal(n1, n2) + + def test_reset_state_uintegers(self): + rg = RandomGenerator(self.prng(*self.seed)) + rg.random_uintegers(bits=32) + state = rg.state + n1 = rg.random_uintegers(bits=32, size=10) + rg2 = RandomGenerator(self.prng()) + rg2.state = state + n2 = rg2.random_uintegers(bits=32, size=10) + assert_((n1 == n2).all()) + + def test_shuffle(self): + original = np.arange(200, 0, -1) + permuted = self.rg.permutation(original) + assert_((original != permuted).any()) + + def test_permutation(self): + original = np.arange(200, 0, -1) + permuted = self.rg.permutation(original) + assert_((original != permuted).any()) + + def test_tomaxint(self): + vals = self.rg.tomaxint(size=100000) + maxsize = 0 + if os.name == 'nt': + maxsize = 2 ** 31 - 1 + else: + try: + maxsize = sys.maxint + except: + maxsize = sys.maxsize + if maxsize < 2 ** 32: + assert_((vals < sys.maxsize).all()) + else: + assert_((vals >= 2 ** 32).any()) + + def test_beta(self): + vals = self.rg.beta(2.0, 2.0, 10) + assert_(len(vals) == 10) + vals = self.rg.beta(np.array([2.0] * 10), 2.0) + assert_(len(vals) == 10) + vals = self.rg.beta(2.0, np.array([2.0] * 10)) + assert_(len(vals) == 10) + vals = self.rg.beta(np.array([2.0] * 10), np.array([2.0] * 10)) + assert_(len(vals) == 10) + vals = self.rg.beta(np.array([2.0] * 10), np.array([[2.0]] * 10)) + assert_(vals.shape == (10, 10)) + + def test_bytes(self): + vals = self.rg.bytes(10) + assert_(len(vals) == 10) + + def test_chisquare(self): + vals = self.rg.chisquare(2.0, 10) + assert_(len(vals) == 10) + params_1(self.rg.chisquare) + + def test_complex_normal(self): + st = self.rg.state + vals = self.rg.complex_normal( + 2.0 + 7.0j, 10.0, 5.0 - 5.0j, size=10, method='zig') + assert_(len(vals) == 10) + + self.rg.state = st + vals2 = [self.rg.complex_normal( + 2.0 + 7.0j, 10.0, 5.0 - 5.0j, method='zig') for _ in range(10)] + np.testing.assert_allclose(vals, vals2) + + self.rg.state = st + vals3 = self.rg.complex_normal( + 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j, method='zig') + np.testing.assert_allclose(vals, vals3) + + self.rg.state = st + norms = self.rg.standard_normal(size=20, method='zig') + norms = np.reshape(norms, (10, 2)) + cov = 0.5 * (-5.0) + v_real = 7.5 + v_imag = 2.5 + rho = cov / np.sqrt(v_real * v_imag) + imag = 7 + np.sqrt(v_imag) * (rho * + norms[:, 0] + np.sqrt(1 - rho ** 2) * norms[:, 1]) + real = 2 + np.sqrt(v_real) * norms[:, 0] + vals4 = [re + im * (0 + 1.0j) for re, im in zip(real, imag)] + + np.testing.assert_allclose(vals4, vals) + + def test_complex_normal_bm(self): + st = self.rg.state + vals = self.rg.complex_normal( + 2.0 + 7.0j, 10.0, 5.0 - 5.0j, size=10, method='bm') + assert_(len(vals) == 10) + + self.rg.state = st + vals2 = [self.rg.complex_normal( + 2.0 + 7.0j, 10.0, 5.0 - 5.0j, method='bm') for _ in range(10)] + np.testing.assert_allclose(vals, vals2) + + self.rg.state = st + vals3 = self.rg.complex_normal( + 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j, method='bm') + np.testing.assert_allclose(vals, vals3) + + def test_complex_normal_zero_variance(self): + st = self.rg.state + c = self.rg.complex_normal(0, 1.0, 1.0) + assert_almost_equal(c.imag, 0.0) + self.rg.state = st + n = self.rg.standard_normal() + np.testing.assert_allclose(c, n, atol=1e-8) + + st = self.rg.state + c = self.rg.complex_normal(0, 1.0, -1.0) + assert_almost_equal(c.real, 0.0) + self.rg.state = st + self.rg.standard_normal() + n = self.rg.standard_normal() + assert_almost_equal(c.real, 0.0) + np.testing.assert_allclose(c.imag, n, atol=1e-8) + + def test_exponential(self): + vals = self.rg.exponential(2.0, 10) + assert_(len(vals) == 10) + params_1(self.rg.exponential) + + def test_f(self): + vals = self.rg.f(3, 1000, 10) + assert_(len(vals) == 10) + + def test_gamma(self): + vals = self.rg.gamma(3, 2, 10) + assert_(len(vals) == 10) + + def test_geometric(self): + vals = self.rg.geometric(0.5, 10) + assert_(len(vals) == 10) + params_1(self.rg.exponential, bounded=True) + + def test_gumbel(self): + vals = self.rg.gumbel(2.0, 2.0, 10) + assert_(len(vals) == 10) + + def test_laplace(self): + vals = self.rg.laplace(2.0, 2.0, 10) + assert_(len(vals) == 10) + + def test_logitic(self): + vals = self.rg.logistic(2.0, 2.0, 10) + assert_(len(vals) == 10) + + def test_logseries(self): + vals = self.rg.logseries(0.5, 10) + assert_(len(vals) == 10) + + def test_negative_binomial(self): + vals = self.rg.negative_binomial(10, 0.2, 10) + assert_(len(vals) == 10) + + def test_rand(self): + state = self.rg.state + vals = self.rg.rand(10, 10, 10) + self.rg.state = state + assert_((vals == self.rg.random_sample((10, 10, 10))).all()) + assert_(vals.shape == (10, 10, 10)) + vals = self.rg.rand(10, 10, 10, dtype=np.float32) + assert_(vals.shape == (10, 10, 10)) + + def test_randn(self): + state = self.rg.state + vals = self.rg.randn(10, 10, 10) + self.rg.state = state + assert_equal(vals, self.rg.standard_normal((10, 10, 10))) + assert_equal(vals.shape, (10, 10, 10)) + + state = self.rg.state + vals = self.rg.randn(10, 10, 10, method='bm') + self.rg.state = state + assert_equal(vals, self.rg.standard_normal((10, 10, 10), method='bm')) + + state = self.rg.state + vals_inv = self.rg.randn(10, 10, 10, method='bm') + self.rg.state = state + vals_zig = self.rg.randn(10, 10, 10, method='zig') + assert_((vals_zig != vals_inv).any()) + + vals = self.rg.randn(10, 10, 10, dtype=np.float32) + assert_(vals.shape == (10, 10, 10)) + + def test_noncentral_chisquare(self): + vals = self.rg.noncentral_chisquare(10, 2, 10) + assert_(len(vals) == 10) + + def test_noncentral_f(self): + vals = self.rg.noncentral_f(3, 1000, 2, 10) + assert_(len(vals) == 10) + vals = self.rg.noncentral_f(np.array([3] * 10), 1000, 2) + assert_(len(vals) == 10) + vals = self.rg.noncentral_f(3, np.array([1000] * 10), 2) + assert_(len(vals) == 10) + vals = self.rg.noncentral_f(3, 1000, np.array([2] * 10)) + assert_(len(vals) == 10) + + def test_normal(self): + vals = self.rg.normal(10, 0.2, 10) + assert_(len(vals) == 10) + + def test_pareto(self): + vals = self.rg.pareto(3.0, 10) + assert_(len(vals) == 10) + + def test_poisson(self): + vals = self.rg.poisson(10, 10) + assert_(len(vals) == 10) + vals = self.rg.poisson(np.array([10] * 10)) + assert_(len(vals) == 10) + params_1(self.rg.poisson) + + def test_power(self): + vals = self.rg.power(0.2, 10) + assert_(len(vals) == 10) + + def test_randint(self): + vals = self.rg.randint(10, 20, 10) + assert_(len(vals) == 10) + + def test_random_integers(self): + vals = self.rg.random_integers(10, 20, 10) + assert_(len(vals) == 10) + + def test_rayleigh(self): + vals = self.rg.rayleigh(0.2, 10) + assert_(len(vals) == 10) + params_1(self.rg.rayleigh, bounded=True) + + def test_vonmises(self): + vals = self.rg.vonmises(10, 0.2, 10) + assert_(len(vals) == 10) + + def test_wald(self): + vals = self.rg.wald(1.0, 1.0, 10) + assert_(len(vals) == 10) + + def test_weibull(self): + vals = self.rg.weibull(1.0, 10) + assert_(len(vals) == 10) + + def test_zipf(self): + vals = self.rg.zipf(10, 10) + assert_(len(vals) == 10) + vals = self.rg.zipf(self.vec_1d) + assert_(len(vals) == 100) + vals = self.rg.zipf(self.vec_2d) + assert_(vals.shape == (1, 100)) + vals = self.rg.zipf(self.mat) + assert_(vals.shape == (100, 100)) + + def test_hypergeometric(self): + vals = self.rg.hypergeometric(25, 25, 20) + assert_(np.isscalar(vals)) + vals = self.rg.hypergeometric(np.array([25] * 10), 25, 20) + assert_(vals.shape == (10,)) + + def test_triangular(self): + vals = self.rg.triangular(-5, 0, 5) + assert_(np.isscalar(vals)) + vals = self.rg.triangular(-5, np.array([0] * 10), 5) + assert_(vals.shape == (10,)) + + def test_multivariate_normal(self): + mean = [0, 0] + cov = [[1, 0], [0, 100]] # diagonal covariance + x = self.rg.multivariate_normal(mean, cov, 5000) + assert_(x.shape == (5000, 2)) + x_zig = self.rg.multivariate_normal(mean, cov, 5000, method='zig') + assert_(x.shape == (5000, 2)) + x_inv = self.rg.multivariate_normal(mean, cov, 5000, method='bm') + assert_(x.shape == (5000, 2)) + assert_((x_zig != x_inv).any()) + + def test_multinomial(self): + vals = self.rg.multinomial(100, [1.0 / 3, 2.0 / 3]) + assert_(vals.shape == (2,)) + vals = self.rg.multinomial(100, [1.0 / 3, 2.0 / 3], size=10) + assert_(vals.shape == (10, 2)) + + def test_dirichlet(self): + s = self.rg.dirichlet((10, 5, 3), 20) + assert_(s.shape == (20, 3)) + + def test_pickle(self): + pick = pickle.dumps(self.rg) + unpick = pickle.loads(pick) + assert_((type(self.rg) == type(unpick))) + assert_(comp_state(self.rg.state, unpick.state)) + + pick = pickle.dumps(self.rg) + unpick = pickle.loads(pick) + assert_((type(self.rg) == type(unpick))) + assert_(comp_state(self.rg.state, unpick.state)) + + @pytest.mark.xfail + def test_version(self): + state = self.rg.state + assert_('version' in state) + assert_(state['version'] == 0) + + def test_seed_array(self): + if self.seed_vector_bits is None: + pytest.skip() + + if self.seed_vector_bits == 32: + dtype = np.uint32 + else: + dtype = np.uint64 + seed = np.array([1], dtype=dtype) + self.rg.seed(seed) + state1 = self.rg.state + self.rg.seed(1) + state2 = self.rg.state + assert_(comp_state(state1, state2)) + + seed = np.arange(4, dtype=dtype) + self.rg.seed(seed) + state1 = self.rg.state + self.rg.seed(seed[0]) + state2 = self.rg.state + assert_(not comp_state(state1, state2)) + + seed = np.arange(1500, dtype=dtype) + self.rg.seed(seed) + state1 = self.rg.state + self.rg.seed(seed[0]) + state2 = self.rg.state + assert_(not comp_state(state1, state2)) + + seed = 2 ** np.mod(np.arange(1500, dtype=dtype), + self.seed_vector_bits - 1) + 1 + self.rg.seed(seed) + state1 = self.rg.state + self.rg.seed(seed[0]) + state2 = self.rg.state + assert_(not comp_state(state1, state2)) + + def test_seed_array_error(self): + if self.seed_vector_bits == 32: + out_of_bounds = 2 ** 32 + else: + out_of_bounds = 2 ** 64 + + seed = -1 + with pytest.raises(ValueError): + self.rg.seed(seed) + + seed = np.array([-1], dtype=np.int32) + with pytest.raises(ValueError): + self.rg.seed(seed) + + seed = np.array([1, 2, 3, -5], dtype=np.int32) + with pytest.raises(ValueError): + self.rg.seed(seed) + + seed = np.array([1, 2, 3, out_of_bounds]) + with pytest.raises(ValueError): + self.rg.seed(seed) + + def test_uniform_float(self): + rg = RandomGenerator(self.prng(12345)) + warmup(rg) + state = rg.state + r1 = rg.random_sample(11, dtype=np.float32) + rg2 = RandomGenerator(self.prng()) + warmup(rg2) + rg2.state = state + r2 = rg2.random_sample(11, dtype=np.float32) + assert_array_equal(r1, r2) + assert_equal(r1.dtype, np.float32) + assert_(comp_state(rg.state, rg2.state)) + + def test_gamma_floats(self): + rg = RandomGenerator(self.prng()) + warmup(rg) + state = rg.state + r1 = rg.standard_gamma(4.0, 11, dtype=np.float32) + rg2 = RandomGenerator(self.prng()) + warmup(rg2) + rg2.state = state + r2 = rg2.standard_gamma(4.0, 11, dtype=np.float32) + assert_array_equal(r1, r2) + assert_equal(r1.dtype, np.float32) + assert_(comp_state(rg.state, rg2.state)) + + def test_normal_floats(self): + rg = RandomGenerator(self.prng()) + warmup(rg) + state = rg.state + r1 = rg.standard_normal(11, method='bm', dtype=np.float32) + rg2 = RandomGenerator(self.prng()) + warmup(rg2) + rg2.state = state + r2 = rg2.standard_normal(11, method='bm', dtype=np.float32) + assert_array_equal(r1, r2) + assert_equal(r1.dtype, np.float32) + assert_(comp_state(rg.state, rg2.state)) + + def test_normal_zig_floats(self): + rg = RandomGenerator(self.prng()) + warmup(rg) + state = rg.state + r1 = rg.standard_normal(11, method='zig', dtype=np.float32) + rg2 = RandomGenerator(self.prng()) + warmup(rg2) + rg2.state = state + r2 = rg2.standard_normal(11, method='zig', dtype=np.float32) + assert_array_equal(r1, r2) + assert_equal(r1.dtype, np.float32) + assert_(comp_state(rg.state, rg2.state)) + + def test_output_fill(self): + rg = self.rg + state = rg.state + size = (31, 7, 97) + existing = np.empty(size) + rg.state = state + rg.standard_normal(out=existing) + rg.state = state + direct = rg.standard_normal(size=size) + assert_equal(direct, existing) + + existing = np.empty(size, dtype=np.float32) + rg.state = state + rg.standard_normal(out=existing, dtype=np.float32) + rg.state = state + direct = rg.standard_normal(size=size, dtype=np.float32) + assert_equal(direct, existing) + + def test_output_filling_uniform(self): + rg = self.rg + state = rg.state + size = (31, 7, 97) + existing = np.empty(size) + rg.state = state + rg.random_sample(out=existing) + rg.state = state + direct = rg.random_sample(size=size) + assert_equal(direct, existing) + + existing = np.empty(size, dtype=np.float32) + rg.state = state + rg.random_sample(out=existing, dtype=np.float32) + rg.state = state + direct = rg.random_sample(size=size, dtype=np.float32) + assert_equal(direct, existing) + + def test_output_filling_exponential(self): + rg = self.rg + state = rg.state + size = (31, 7, 97) + existing = np.empty(size) + rg.state = state + rg.standard_exponential(out=existing) + rg.state = state + direct = rg.standard_exponential(size=size) + assert_equal(direct, existing) + + existing = np.empty(size, dtype=np.float32) + rg.state = state + rg.standard_exponential(out=existing, dtype=np.float32) + rg.state = state + direct = rg.standard_exponential(size=size, dtype=np.float32) + assert_equal(direct, existing) + + def test_output_filling_gamma(self): + rg = self.rg + state = rg.state + size = (31, 7, 97) + existing = np.zeros(size) + rg.state = state + rg.standard_gamma(1.0, out=existing) + rg.state = state + direct = rg.standard_gamma(1.0, size=size) + assert_equal(direct, existing) + + existing = np.zeros(size, dtype=np.float32) + rg.state = state + rg.standard_gamma(1.0, out=existing, dtype=np.float32) + rg.state = state + direct = rg.standard_gamma(1.0, size=size, dtype=np.float32) + assert_equal(direct, existing) + + def test_output_filling_gamma_broadcast(self): + rg = self.rg + state = rg.state + size = (31, 7, 97) + mu = np.arange(97.0) + 1.0 + existing = np.zeros(size) + rg.state = state + rg.standard_gamma(mu, out=existing) + rg.state = state + direct = rg.standard_gamma(mu, size=size) + assert_equal(direct, existing) + + existing = np.zeros(size, dtype=np.float32) + rg.state = state + rg.standard_gamma(mu, out=existing, dtype=np.float32) + rg.state = state + direct = rg.standard_gamma(mu, size=size, dtype=np.float32) + assert_equal(direct, existing) + + def test_output_fill_error(self): + rg = self.rg + size = (31, 7, 97) + existing = np.empty(size) + with pytest.raises(TypeError): + rg.standard_normal(out=existing, dtype=np.float32) + with pytest.raises(ValueError): + rg.standard_normal(out=existing[::3]) + existing = np.empty(size, dtype=np.float32) + with pytest.raises(TypeError): + rg.standard_normal(out=existing, dtype=np.float64) + + existing = np.zeros(size, dtype=np.float32) + with pytest.raises(TypeError): + rg.standard_gamma(1.0, out=existing, dtype=np.float64) + with pytest.raises(ValueError): + rg.standard_gamma(1.0, out=existing[::3], dtype=np.float32) + existing = np.zeros(size, dtype=np.float64) + with pytest.raises(TypeError): + rg.standard_gamma(1.0, out=existing, dtype=np.float32) + with pytest.raises(ValueError): + rg.standard_gamma(1.0, out=existing[::3]) + + def test_randint_broadcast(self, dtype): + if dtype == np.bool: + upper = 2 + lower = 0 + else: + info = np.iinfo(dtype) + upper = int(info.max) + 1 + lower = info.min + self._reset_state() + a = self.rg.randint(lower, [upper] * 10, dtype=dtype) + self._reset_state() + b = self.rg.randint([lower] * 10, upper, dtype=dtype) + assert_equal(a, b) + self._reset_state() + c = self.rg.randint(lower, upper, size=10, dtype=dtype) + assert_equal(a, c) + self._reset_state() + d = self.rg.randint(np.array( + [lower] * 10), np.array([upper], dtype=np.object), size=10, dtype=dtype) + assert_equal(a, d) + self._reset_state() + e = self.rg.randint( + np.array([lower] * 10), np.array([upper] * 10), size=10, dtype=dtype) + assert_equal(a, e) + + self._reset_state() + a = self.rg.randint(0, upper, size=10, dtype=dtype) + self._reset_state() + b = self.rg.randint([upper] * 10, dtype=dtype) + assert_equal(a, b) + + def test_randint_numpy(self, dtype): + high = np.array([1]) + low = np.array([0]) + + out = self.rg.randint(low, high, dtype=dtype) + assert out.shape == (1,) + + out = self.rg.randint(low[0], high, dtype=dtype) + assert out.shape == (1,) + + out = self.rg.randint(low, high[0], dtype=dtype) + assert out.shape == (1,) + + def test_randint_broadcast_errors(self, dtype): + if dtype == np.bool: + upper = 2 + lower = 0 + else: + info = np.iinfo(dtype) + upper = int(info.max) + 1 + lower = info.min + with pytest.raises(ValueError): + self.rg.randint(lower, [upper + 1] * 10, dtype=dtype) + with pytest.raises(ValueError): + self.rg.randint(lower - 1, [upper] * 10, dtype=dtype) + with pytest.raises(ValueError): + self.rg.randint([lower - 1], [upper] * 10, dtype=dtype) + with pytest.raises(ValueError): + self.rg.randint([0], [0], dtype=dtype) + + +class TestMT19937(RNG): + @classmethod + def setup_class(cls): + cls.prng = MT19937 + cls.advance = None + cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] + cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = 32 + cls._extra_setup() + cls.seed_error = ValueError + + @pytest.mark.xfail + def test_numpy_state(self): + # TODO: Do we want lagacy state support + nprg = np.random.RandomState() + nprg.standard_normal(99) + state = nprg.state + self.rg.state = state + state2 = self.rg.state + assert_((state[1] == state2['state'][0]).all()) + assert_((state[2] == state2['state'][1])) + assert_((state[3] == state2['gauss']['has_gauss'])) + assert_((state[4] == state2['gauss']['gauss'])) + + +class TestPCG64(RNG): + @classmethod + def setup_class(cls): + cls.prng = PCG64 + cls.advance = 2 ** 96 + 2 ** 48 + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1 + cls.seed = [2 ** 96 + 2 ** 48 + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1, + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1] + cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = None + cls._extra_setup() + + def test_seed_array_error(self): + # GH #82 for error type changes + if self.seed_vector_bits == 32: + out_of_bounds = 2 ** 32 + else: + out_of_bounds = 2 ** 64 + + seed = -1 + with pytest.raises(ValueError): + self.rg.seed(seed) + + error_type = ValueError if self.seed_vector_bits else TypeError + seed = np.array([-1], dtype=np.int32) + with pytest.raises(error_type): + self.rg.seed(seed) + + seed = np.array([1, 2, 3, -5], dtype=np.int32) + with pytest.raises(error_type): + self.rg.seed(seed) + + seed = np.array([1, 2, 3, out_of_bounds]) + with pytest.raises(error_type): + self.rg.seed(seed) + + +class TestPhilox(RNG): + @classmethod + def setup_class(cls): + cls.prng = Philox + cls.advance = None + cls.seed = [12345] + cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = 64 + cls._extra_setup() + + +class TestThreeFry(RNG): + @classmethod + def setup_class(cls): + cls.prng = ThreeFry + cls.advance = None + cls.seed = [12345] + cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = 64 + cls._extra_setup() + + +class TestXoroshiro128(RNG): + @classmethod + def setup_class(cls): + cls.prng = Xoroshiro128 + cls.advance = None + cls.seed = [12345] + cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = 64 + cls._extra_setup() + + +class TestXorshift1024(RNG): + @classmethod + def setup_class(cls): + cls.prng = Xorshift1024 + cls.advance = None + cls.seed = [12345] + cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = 64 + cls._extra_setup() + + +class TestDSFMT(RNG): + @classmethod + def setup_class(cls): + cls.prng = DSFMT + cls.advance = None + cls.seed = [12345] + cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.initial_state = cls.rg.state + cls._extra_setup() + cls.seed_vector_bits = 32 + + +class TestEntropy(object): + def test_entropy(self): + e1 = entropy.random_entropy() + e2 = entropy.random_entropy() + assert_((e1 != e2)) + e1 = entropy.random_entropy(10) + e2 = entropy.random_entropy(10) + assert_((e1 != e2).all()) + e1 = entropy.random_entropy(10, source='system') + e2 = entropy.random_entropy(10, source='system') + assert_((e1 != e2).all()) + + def test_fallback(self): + e1 = entropy.random_entropy(source='fallback') + time.sleep(0.1) + e2 = entropy.random_entropy(source='fallback') + assert_((e1 != e2)) diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index 4322baf3575a..99c7027734a3 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -101,9 +101,13 @@ cdef class ThreeFry: free(self._prng.binomial) free(self._prng) - def _reset_state_variables(self): + cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 + self._prng.has_gauss = 0 + self._prng.has_gauss_f = 0 + self._prng.gauss = 0.0 + self._prng.gauss_f = 0.0 self.rng_state.buffer_pos = THREEFRY_BUFFER_SIZE for i in range(THREEFRY_BUFFER_SIZE): self.rng_state.buffer[i] = 0 diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 3cbb73752512..34f88859d1c1 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -93,12 +93,13 @@ cdef class Xoroshiro128: free(self._prng.binomial) free(self._prng) - def _reset_state_variables(self): + cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - # TODO: These should be done everywhere for safety self._prng.has_gauss = 0 self._prng.has_gauss_f = 0 + self._prng.gauss = 0.0 + self._prng.gauss_f = 0.0 def __random_integer(self, bits=64): """ @@ -223,7 +224,10 @@ cdef class Xoroshiro128: def cffi(self): if self.cffi is not None: return self.cffi - import cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') ffi = cffi.FFI() self.cffi = interface(self.rng_state, diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index ef686e003291..effc2b3d0538 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -85,9 +85,13 @@ cdef class Xorshift1024: free(self._prng.binomial) free(self._prng) - def _reset_state_variables(self): + cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 + self._prng.has_gauss = 0 + self._prng.has_gauss_f = 0 + self._prng.gauss = 0.0 + self._prng.gauss_f = 0.0 def __random_integer(self, bits=64): """ diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 330d0cfeea16..0f48e3f7aa10 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -55,7 +55,6 @@ files = glob.glob('./core_prng/*.in') for templated_file in files: - print(templated_file) output_file_name = os.path.splitext(templated_file)[0] if (os.path.exists(output_file_name) and (os.path.getmtime(templated_file) < os.path.getmtime(output_file_name))): From 68a169f2d2e653b367c72b7d4d2aa9fd1a34e409 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 11 Mar 2018 09:19:25 +0000 Subject: [PATCH 057/279] TST: Add direct testing Add direct testing and resolve related bugs --- _randomgen/core_prng/generator.pyx | 5 +- _randomgen/core_prng/mt19937.pyx | 11 + .../src/distributions/distributions.c | 2 + .../src/mt19937/mt19937-test-data-gen.c | 11 +- _randomgen/core_prng/src/pcg64/pcg64.h | 4 +- .../src/philox/philox-test-data-gen.c | 18 +- _randomgen/core_prng/src/philox/philox.h | 5 +- .../core_prng/src/splitmix64/splitmix64.h | 4 +- .../src/threefry/threefry-test-data-gen.c | 29 +- _randomgen/core_prng/src/threefry/threefry.h | 5 +- .../core_prng/src/xoroshiro128/xoroshiro128.h | 4 +- .../core_prng/src/xorshift1024/xorshift1024.h | 4 +- ...orshift2014.orig.c => xorshift1024.orig.c} | 0 .../core_prng/tests/data/dSFMT-testset-1.csv | 1001 ++++++++++ .../core_prng/tests/data/dSFMT-testset-2.csv | 1001 ++++++++++ .../tests/data/mt19937-testset-1.csv | 1001 ++++++++++ .../tests/data/mt19937-testset-2.csv | 1001 ++++++++++ .../core_prng/tests/data/philox-testset-1.csv | 1001 ++++++++++ .../core_prng/tests/data/philox-testset-2.csv | 1001 ++++++++++ .../tests/data/threefry-testset-1.csv | 1001 ++++++++++ .../tests/data/threefry-testset-2.csv | 1001 ++++++++++ .../tests/data/xoroshiro128-testset-1.csv | 1001 ++++++++++ .../tests/data/xoroshiro128-testset-2.csv | 1001 ++++++++++ .../tests/data/xorshift1024-testset-1.csv | 1001 ++++++++++ .../tests/data/xorshift1024-testset-2.csv | 1001 ++++++++++ .../core_prng/tests/test_against_numpy.py | 533 +++++ _randomgen/core_prng/tests/test_direct.py | 337 ++++ .../core_prng/tests/test_numpy_mt19937.py | 1754 +++++++++++++++++ .../tests/test_numpy_mt19937_regressions.py | 140 ++ 29 files changed, 14835 insertions(+), 43 deletions(-) rename _randomgen/core_prng/src/xorshift1024/{xorshift2014.orig.c => xorshift1024.orig.c} (100%) create mode 100644 _randomgen/core_prng/tests/data/dSFMT-testset-1.csv create mode 100644 _randomgen/core_prng/tests/data/dSFMT-testset-2.csv create mode 100644 _randomgen/core_prng/tests/data/mt19937-testset-1.csv create mode 100644 _randomgen/core_prng/tests/data/mt19937-testset-2.csv create mode 100644 _randomgen/core_prng/tests/data/philox-testset-1.csv create mode 100644 _randomgen/core_prng/tests/data/philox-testset-2.csv create mode 100644 _randomgen/core_prng/tests/data/threefry-testset-1.csv create mode 100644 _randomgen/core_prng/tests/data/threefry-testset-2.csv create mode 100644 _randomgen/core_prng/tests/data/xoroshiro128-testset-1.csv create mode 100644 _randomgen/core_prng/tests/data/xoroshiro128-testset-2.csv create mode 100644 _randomgen/core_prng/tests/data/xorshift1024-testset-1.csv create mode 100644 _randomgen/core_prng/tests/data/xorshift1024-testset-2.csv create mode 100644 _randomgen/core_prng/tests/test_against_numpy.py create mode 100644 _randomgen/core_prng/tests/test_direct.py create mode 100644 _randomgen/core_prng/tests/test_numpy_mt19937.py create mode 100644 _randomgen/core_prng/tests/test_numpy_mt19937_regressions.py diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 240fb192eacd..0e3bbf0cc799 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -106,11 +106,14 @@ cdef class RandomGenerator: @state.setter def state(self, value): + self.__core_prng.state = value + if isinstance(value, tuple): + # Legacy MT19937 state + return self._prng.has_gauss = value['has_gauss'] self._prng.has_gauss_f = value['has_gauss_f'] self._prng.gauss = value['gauss'] self._prng.gauss_f = value['gauss_f'] - self.__core_prng.state = value def random_uintegers(self, size=None, int bits=64): """ diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index c8ea21b66654..53a909100727 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -191,6 +191,17 @@ cdef class MT19937: @state.setter def state(self, value): + if isinstance(value, tuple): + if value[0] != 'MT19937' or len(value) not in (3,5): + raise ValueError('state is not a legacy MT19937 state') + self._reset_state_variables() + if len(value) == 5: + self._prng.has_gauss = value[3] + self._prng.gauss = value[4] + value ={'prng': 'MT19937', + 'state':{'key': value[1], 'pos': value[2]} + } + if not isinstance(value, dict): raise TypeError('state must be a dict') prng = value.get('prng', '') diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 7238cfa03cbe..4c2896e888ab 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -33,6 +33,7 @@ double random_gauss(prng_t *prng_state) { if (prng_state->has_gauss) { const double temp = prng_state->gauss; prng_state->has_gauss = false; + prng_state->gauss = 0.0; return temp; } else { double f, x1, x2, r2; @@ -56,6 +57,7 @@ float random_gauss_f(prng_t *prng_state) { if (prng_state->has_gauss_f) { const float temp = prng_state->gauss_f; prng_state->has_gauss_f = false; + prng_state->gauss_f = 0.0f; return temp; } else { float f, x1, x2, r2; diff --git a/_randomgen/core_prng/src/mt19937/mt19937-test-data-gen.c b/_randomgen/core_prng/src/mt19937/mt19937-test-data-gen.c index ef98be160b55..4f4ec1d6458d 100644 --- a/_randomgen/core_prng/src/mt19937/mt19937-test-data-gen.c +++ b/_randomgen/core_prng/src/mt19937/mt19937-test-data-gen.c @@ -14,17 +14,13 @@ int main() { uint64_t sum = 0; - uint64_t temp; uint32_t seed = 0xDEADBEAF; int i; rk_state state; rk_seed(seed, &state); uint64_t store[N]; for (i = 0; i < N; i++) { - temp = 0; - temp = (uint64_t)rk_random(&state) << 32; - temp |= rk_random(&state); - store[i] = temp; + store[i] = (uint64_t)rk_random(&state); } FILE *fp; @@ -45,10 +41,7 @@ int main() { seed = 0; rk_seed(seed, &state); for (i = 0; i < N; i++) { - temp = 0; - temp = (uint64_t)rk_random(&state) << 32; - temp |= rk_random(&state); - store[i] = temp; + store[i] = (uint64_t)rk_random(&state); } fp = fopen("mt19937-testset-2.csv", "w"); if (fp == NULL) { diff --git a/_randomgen/core_prng/src/pcg64/pcg64.h b/_randomgen/core_prng/src/pcg64/pcg64.h index 8122d5579650..df265cb1a3a4 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.h +++ b/_randomgen/core_prng/src/pcg64/pcg64.h @@ -218,8 +218,8 @@ static inline uint32_t pcg64_next32(pcg64_state *state) { } next = pcg64_random_r(state->pcg_state); state->has_uint32 = 1; - state->uinteger = (uint32_t)(next & 0xffffffff); - return (uint32_t)(next >> 32); + state->uinteger = (uint32_t)(next >> 32); + return (uint32_t)(next & 0xffffffff); } void pcg64_advance(pcg64_state *state, uint64_t *step); diff --git a/_randomgen/core_prng/src/philox/philox-test-data-gen.c b/_randomgen/core_prng/src/philox/philox-test-data-gen.c index b17dd153b3d0..442e18b559c3 100644 --- a/_randomgen/core_prng/src/philox/philox-test-data-gen.c +++ b/_randomgen/core_prng/src/philox/philox-test-data-gen.c @@ -12,6 +12,7 @@ * */ +#include "../splitmix64/splitmix64.h" #include "Random123/philox.h" #include #include @@ -20,10 +21,15 @@ int main() { philox4x64_ctr_t ctr = {{0, 0, 0, 0}}; - philox4x64_key_t key = {{0, 0xDEADBEAF}}; + philox4x64_key_t key = {{0, 0}}; + uint64_t state, seed = 0xDEADBEAF; philox4x64_ctr_t out; uint64_t store[N]; + state = seed; int i, j; + for (i = 0; i < 2; i++) { + key.v[i] = splitmix64_next(&state); + } for (i = 0; i < N / 4UL; i++) { ctr.v[0]++; out = philox4x64_R(philox4x64_rounds, ctr, key); @@ -38,7 +44,7 @@ int main() { printf("Couldn't open file\n"); return -1; } - fprintf(fp, "key, 0x%" PRIx64 ", 0x%" PRIx64 "\n", key.v[0], key.v[1]); + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); for (i = 0; i < N; i++) { fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); if (i == 999) { @@ -48,8 +54,10 @@ int main() { fclose(fp); ctr.v[0] = 0; - key.v[0] = 0xDEADBEAF; - key.v[1] = 0xFBADBEEF; + state = seed = 0; + for (i = 0; i < 2; i++) { + key.v[i] = splitmix64_next(&state); + } for (i = 0; i < N / 4UL; i++) { ctr.v[0]++; out = philox4x64_R(philox4x64_rounds, ctr, key); @@ -63,7 +71,7 @@ int main() { printf("Couldn't open file\n"); return -1; } - fprintf(fp, "key, 0x%" PRIx64 ", 0x%" PRIx64 "\n", key.v[0], key.v[1]); + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); for (i = 0; i < N; i++) { fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); if (i == 999) { diff --git a/_randomgen/core_prng/src/philox/philox.h b/_randomgen/core_prng/src/philox/philox.h index bc87b3d3a125..d469eabb2adc 100644 --- a/_randomgen/core_prng/src/philox/philox.h +++ b/_randomgen/core_prng/src/philox/philox.h @@ -186,9 +186,8 @@ static INLINE uint64_t philox_next32(philox_state *state) { next = philox_next(state); state->has_uint32 = 1; - state->uinteger = (uint32_t)(next & 0xffffffff); - - return (uint32_t)(next >> 32); + state->uinteger = (uint32_t)(next >> 32); + return (uint32_t)(next & 0xffffffff); } extern void philox_jump(philox_state *state); diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.h b/_randomgen/core_prng/src/splitmix64/splitmix64.h index 0691064428b7..880132970744 100644 --- a/_randomgen/core_prng/src/splitmix64/splitmix64.h +++ b/_randomgen/core_prng/src/splitmix64/splitmix64.h @@ -33,7 +33,7 @@ static inline uint32_t splitmix64_next32(splitmix64_state *state) { return state->uinteger; } next = splitmix64_next64(state); - state->uinteger = next & 0xffffffff; state->has_uint32 = 1; - return (uint32_t)(next >> 32); + state->uinteger = (uint32_t)(next >> 32); + return (uint32_t)(next & 0xffffffff); } diff --git a/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c b/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c index 4494802489e6..444824c1231a 100644 --- a/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c +++ b/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c @@ -1,10 +1,11 @@ /* * Generate testing csv files * - * cl threefry-test-data-gen.c /Ox + * cl threefry-test-data-gen.c /Ox ../splitmix64/splitmix64.c /Ox * threefry-test-data-gen.exe * - * gcc threefry-test-data-gen.c -o threefry-test-data-gen + * gcc threefry-test-data-gen.c ../splitmix64/splitmix64.c /Ox -o + * threefry-test-data-gen * ./threefry-test-data-gen * * Requres the Random123 directory containing header files to be located in the @@ -12,6 +13,7 @@ * */ +#include "../splitmix64/splitmix64.h" #include "Random123/threefry.h" #include #include @@ -20,10 +22,15 @@ int main() { threefry4x64_key_t ctr = {{0, 0, 0, 0}}; - threefry4x64_ctr_t key = {{0xDEADBEAF, 0, 0, 0}}; + uint64_t state, seed = 0xDEADBEAF; + state = seed; + threefry4x64_ctr_t key = {{0}}; threefry4x64_ctr_t out; uint64_t store[N]; int i, j; + for (i = 0; i < 4; i++) { + key.v[i] = splitmix64_next(&state); + } for (i = 0; i < N / 4UL; i++) { ctr.v[0]++; out = threefry4x64_R(threefry4x64_rounds, ctr, key); @@ -38,9 +45,6 @@ int main() { printf("Couldn't open file\n"); return -1; } - fprintf(fp, - "key, 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 "\n", - key.v[0], key.v[1], key.v[2], key.v[3]); for (i = 0; i < N; i++) { fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); if (i == 999) { @@ -50,11 +54,11 @@ int main() { fclose(fp); ctr.v[0] = 0; - key.v[0] = 0; - key.v[1] = 0; - key.v[2] = 0xFBADBEEF; - key.v[3] = 0xDEADBEAF; - for (i = 0; i < N / 4UL; i++) { + state = seed = 0; + for (i = 0; i < 4; i++) { + key.v[i] = splitmix64_next(&state); + } + for (i = 0; i < N / 4; i++) { ctr.v[0]++; out = threefry4x64_R(threefry4x64_rounds, ctr, key); for (j = 0; j < 4; j++) { @@ -67,9 +71,6 @@ int main() { printf("Couldn't open file\n"); return -1; } - fprintf(fp, - "key, 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 "\n", - key.v[0], key.v[1], key.v[2], key.v[3]); for (i = 0; i < N; i++) { fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); if (i == 999) { diff --git a/_randomgen/core_prng/src/threefry/threefry.h b/_randomgen/core_prng/src/threefry/threefry.h index d620f6a1aaca..0b557a00d119 100644 --- a/_randomgen/core_prng/src/threefry/threefry.h +++ b/_randomgen/core_prng/src/threefry/threefry.h @@ -328,9 +328,8 @@ static INLINE uint64_t threefry_next32(threefry_state *state) { next = threefry_next(state); state->has_uint32 = 1; - state->uinteger = (uint32_t)(next & 0xffffffff); - - return (uint32_t)(next >> 32); + state->uinteger = (uint32_t)(next >> 32); + return (uint32_t)(next & 0xffffffff); } extern void threefry_jump(threefry_state *state); diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h index ad1ddb194901..3fa5b32e9a46 100644 --- a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h +++ b/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h @@ -45,8 +45,8 @@ static INLINE uint32_t xoroshiro128_next32(xoroshiro128_state *state) { } next = xoroshiro128_next(&state->s[0]); state->has_uint32 = 1; - state->uinteger = (uint32_t)(next & 0xffffffff); - return (uint32_t)(next >> 32); + state->uinteger = (uint32_t)(next >> 32); + return (uint32_t)(next & 0xffffffff); } void xoroshiro128_jump(xoroshiro128_state *state); diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.h b/_randomgen/core_prng/src/xorshift1024/xorshift1024.h index 2cceee7284f2..998dde06c6b3 100644 --- a/_randomgen/core_prng/src/xorshift1024/xorshift1024.h +++ b/_randomgen/core_prng/src/xorshift1024/xorshift1024.h @@ -38,8 +38,8 @@ static INLINE uint32_t xorshift1024_next32(xorshift1024_state *state) { } next = xorshift1024_next(state); state->has_uint32 = 1; - state->uinteger = (uint32_t)(next & 0xffffffff); - return (uint32_t)(next >> 32); + state->uinteger = (uint32_t)(next >> 32); + return (uint32_t)(next & 0xffffffff); } void xorshift1024_jump(xorshift1024_state *state); diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift2014.orig.c b/_randomgen/core_prng/src/xorshift1024/xorshift1024.orig.c similarity index 100% rename from _randomgen/core_prng/src/xorshift1024/xorshift2014.orig.c rename to _randomgen/core_prng/src/xorshift1024/xorshift1024.orig.c diff --git a/_randomgen/core_prng/tests/data/dSFMT-testset-1.csv b/_randomgen/core_prng/tests/data/dSFMT-testset-1.csv new file mode 100644 index 000000000000..9f3f68aeefd2 --- /dev/null +++ b/_randomgen/core_prng/tests/data/dSFMT-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 1 +0, 4607719943344484518 +1, 4611291582431749820 +2, 4609448534071823958 +3, 4611106200950903790 +4, 4609580282971267356 +5, 4609720762470045007 +6, 4607636870422133563 +7, 4611678836133173816 +8, 4610735809705346030 +9, 4608789817543785341 +10, 4610393651369520670 +11, 4611623758339670553 +12, 4608444108616433164 +13, 4607465458608330898 +14, 4610235165931416513 +15, 4608103709635697272 +16, 4608100588970381609 +17, 4608641074646810943 +18, 4608616221842668388 +19, 4607549343270027634 +20, 4610344140656206312 +21, 4610535464314418457 +22, 4611312430982209353 +23, 4607401331162512449 +24, 4609116099984352425 +25, 4611257698187747276 +26, 4607645174989853474 +27, 4608837854111428888 +28, 4608691299413198001 +29, 4608930266190921041 +30, 4608332808182207925 +31, 4608421484748440698 +32, 4608383650014337452 +33, 4611545817730524178 +34, 4611496890204636496 +35, 4610861924086585884 +36, 4608194351754852419 +37, 4610283774852204513 +38, 4609474926233319727 +39, 4608727547276598994 +40, 4609717674488922238 +41, 4609423015229480073 +42, 4609349380679114027 +43, 4610751388265382808 +44, 4607733281112877867 +45, 4610591846531581004 +46, 4610735578621585065 +47, 4611251806424951188 +48, 4609460646876881407 +49, 4611551161354804803 +50, 4611249469634822485 +51, 4608821959551777081 +52, 4610052971574464565 +53, 4607777094091618436 +54, 4610851094220499210 +55, 4607702337070583856 +56, 4611414385520522876 +57, 4611576460026085858 +58, 4611473034943841786 +59, 4608897639026169673 +60, 4607883926313481761 +61, 4608797023994348324 +62, 4610894444453627505 +63, 4608376332448068935 +64, 4609893849888152414 +65, 4610202941918038529 +66, 4611056233415559924 +67, 4610877544761426248 +68, 4610994780372079388 +69, 4609067797141254153 +70, 4610982998126297925 +71, 4610789518257002641 +72, 4610598903890296442 +73, 4608025197953180744 +74, 4610185556158198401 +75, 4608809010429661575 +76, 4608768447244428523 +77, 4609124503281513660 +78, 4611101360372917414 +79, 4611042322702996474 +80, 4610858523716073186 +81, 4610375945852385997 +82, 4608483154301089968 +83, 4607798251963762687 +84, 4609119835265156007 +85, 4609188963843200093 +86, 4607266275697659547 +87, 4610923287424505039 +88, 4609618008081028402 +89, 4608201696292514469 +90, 4611530915051149734 +91, 4607364802882841466 +92, 4611236492431573193 +93, 4610807042893722656 +94, 4610080772943107179 +95, 4608570487813674878 +96, 4610901704116296546 +97, 4610535849683417477 +98, 4609487776344637464 +99, 4607684048114742415 +100, 4609756145565247020 +101, 4609839920313018364 +102, 4607300199263955605 +103, 4608349701001143604 +104, 4608563526536655950 +105, 4608211471894692660 +106, 4611561832400682724 +107, 4607607690303987255 +108, 4609884829632656291 +109, 4610554863807344395 +110, 4609913857729390656 +111, 4608533735726217242 +112, 4611205573734963697 +113, 4608825835576863771 +114, 4611237004326669392 +115, 4609254174450399374 +116, 4607622879864982635 +117, 4610819003887309229 +118, 4607698308712315302 +119, 4607833259972583494 +120, 4607681632288287295 +121, 4607910755187354207 +122, 4611122191561013257 +123, 4611656235846796861 +124, 4610565432604340253 +125, 4610908827351842030 +126, 4611268340320100590 +127, 4609313851656821466 +128, 4608528427564169020 +129, 4608200570336395038 +130, 4610538403125154877 +131, 4608888436053455398 +132, 4611543165544411944 +133, 4610250257231662522 +134, 4609297917742740245 +135, 4610400815978769483 +136, 4610528657337572565 +137, 4610705415667566712 +138, 4611077904559980731 +139, 4609927849369442287 +140, 4609397759777226314 +141, 4609010898016502992 +142, 4609120772081864228 +143, 4607237141609153161 +144, 4610571899308981431 +145, 4609008993363640801 +146, 4610287560785901157 +147, 4608623756174376020 +148, 4608653243870415213 +149, 4609547819331301107 +150, 4609673847833623842 +151, 4608235666485521661 +152, 4610114805542994107 +153, 4610479707694856806 +154, 4609103555741806169 +155, 4608500007602890176 +156, 4610672856146553685 +157, 4611610717675563449 +158, 4610730068759051595 +159, 4608685224971234052 +160, 4609413185190097208 +161, 4608897450787802174 +162, 4607186845514749512 +163, 4607348569795042779 +164, 4611009214373065786 +165, 4609635836233645619 +166, 4610977547720639382 +167, 4610180471225090534 +168, 4608711346241655575 +169, 4608627118356010890 +170, 4611222988628267196 +171, 4610585467803239650 +172, 4608953295299223634 +173, 4610267719343621921 +174, 4608384815012305523 +175, 4610760760005158447 +176, 4609888294496573856 +177, 4608487712307397941 +178, 4610046813921597302 +179, 4607901372889700267 +180, 4611648045743259157 +181, 4611287922111507955 +182, 4609242748471226007 +183, 4607755201380013067 +184, 4611417807283839436 +185, 4609947268752725748 +186, 4610889795243117380 +187, 4610682734427309711 +188, 4609430103755831273 +189, 4610392513282878252 +190, 4608028130931026108 +191, 4609354927353821574 +192, 4607999262827197226 +193, 4608772265877184447 +194, 4611465843018312306 +195, 4607857062574325894 +196, 4610666426888867633 +197, 4610600830920094283 +198, 4609205915408410545 +199, 4607853688411879209 +200, 4607747795491854335 +201, 4608262126937716822 +202, 4611534185487112177 +203, 4610074422869556166 +204, 4609237471248388861 +205, 4609177882315404739 +206, 4607287155741697257 +207, 4611476554139586317 +208, 4609517208333105115 +209, 4607319309983389553 +210, 4608526076922090888 +211, 4610748479257207053 +212, 4609931527304084444 +213, 4608009987636217635 +214, 4610407130291313714 +215, 4608891664598965696 +216, 4610296160139884006 +217, 4611484560328101663 +218, 4611019501503618978 +219, 4610246433435823295 +220, 4608562757718917889 +221, 4607471913719777131 +222, 4611613370049530904 +223, 4608319297993304206 +224, 4607745017639172981 +225, 4609731861577957712 +226, 4609663467149266458 +227, 4609543591294589508 +228, 4608524115958204496 +229, 4611293271186698245 +230, 4610645493162693253 +231, 4607841282620685061 +232, 4608714555579084575 +233, 4608149900642705668 +234, 4609881346718346991 +235, 4609652423006025080 +236, 4610576204477932347 +237, 4608419142720251589 +238, 4609292870725527035 +239, 4607915743890091921 +240, 4610631007573258876 +241, 4611091737638956363 +242, 4610866832498942602 +243, 4608679206316379049 +244, 4611254040795706209 +245, 4608564985000526959 +246, 4609448881222436994 +247, 4611606861023266002 +248, 4608930513670169902 +249, 4607323764955464423 +250, 4607288181905687970 +251, 4610373160370490855 +252, 4608411794278861897 +253, 4610212894218458057 +254, 4610694380708700429 +255, 4609922533346642803 +256, 4609392056590729641 +257, 4609803732845487397 +258, 4608878803170308012 +259, 4611524443328391151 +260, 4608174079771415727 +261, 4607408890033763317 +262, 4607845699541088935 +263, 4611555920103058967 +264, 4607479194613061911 +265, 4607653663534995980 +266, 4610070893479029228 +267, 4611538868870820080 +268, 4608567899678704260 +269, 4608770231079288078 +270, 4610411454914405807 +271, 4607820664883172463 +272, 4610714780751262327 +273, 4607194611952450391 +274, 4609087763682578279 +275, 4608165254026394594 +276, 4609234355157830083 +277, 4609341303623897409 +278, 4607843258265880283 +279, 4609385462693327627 +280, 4610305709185463397 +281, 4607607148427164960 +282, 4608714881122218799 +283, 4609651616092383148 +284, 4609231203213271499 +285, 4611257982347817477 +286, 4610152698091154688 +287, 4608144133423192484 +288, 4610573628352437761 +289, 4608544728261953288 +290, 4610198309467009097 +291, 4610449593868273119 +292, 4610593290392091594 +293, 4609046058809591309 +294, 4611622292530238189 +295, 4610657414068263882 +296, 4611165834719653845 +297, 4610350928332385108 +298, 4611352448760095628 +299, 4609948012409647959 +300, 4610309189747788666 +301, 4607755081207867022 +302, 4610231879852064105 +303, 4607888125265337265 +304, 4609172092280206898 +305, 4608588257784565842 +306, 4607741678424158070 +307, 4609025150930086850 +308, 4609393539064468217 +309, 4610911632660167908 +310, 4610958667007850644 +311, 4611286666277101605 +312, 4609804183682242390 +313, 4611608707704948262 +314, 4609669610113267167 +315, 4607666787328441261 +316, 4607581099645179700 +317, 4610190388918185110 +318, 4610216151360211572 +319, 4608284982213104796 +320, 4609043908200033150 +321, 4610094358636174240 +322, 4607727851642292863 +323, 4607748339680477190 +324, 4610333796608461237 +325, 4611630659133526098 +326, 4611011836822995398 +327, 4611271586336335851 +328, 4608676990846072419 +329, 4610486194528414452 +330, 4607576606876065603 +331, 4607719568700291080 +332, 4608551235063435831 +333, 4611011581816455613 +334, 4608841433006333809 +335, 4609590566174099924 +336, 4610751108417575356 +337, 4609783802139185311 +338, 4610078674097919534 +339, 4608133838483219458 +340, 4609277956691541130 +341, 4608489591310323203 +342, 4608190218485836055 +343, 4611079531841410411 +344, 4608880618309483643 +345, 4608911948674088293 +346, 4611291894381153496 +347, 4608451717289459361 +348, 4608796294882212937 +349, 4608414460486049632 +350, 4607422609721232463 +351, 4608080483385313266 +352, 4607622634488318995 +353, 4609289604313013439 +354, 4609239936097680379 +355, 4608372018123900887 +356, 4610702814261825804 +357, 4611274091783983647 +358, 4611215484124931059 +359, 4608990421919168365 +360, 4609097190054835106 +361, 4610994750415795356 +362, 4611072443902954170 +363, 4608952917718970557 +364, 4608900180943861654 +365, 4608934424322310689 +366, 4609731940535270405 +367, 4610297241526025992 +368, 4608524744985785409 +369, 4610233647335282974 +370, 4609397840502965617 +371, 4609931050226720744 +372, 4607823742164438535 +373, 4607386223202154150 +374, 4611077706407577954 +375, 4608540055157729754 +376, 4610737951147572257 +377, 4610902929285966658 +378, 4611385693211960164 +379, 4607224622379354821 +380, 4609166781986849209 +381, 4608748083335025668 +382, 4610443657454469430 +383, 4610468401119056286 +384, 4610937884247828753 +385, 4609084940396193513 +386, 4611415358123142084 +387, 4610501805353766962 +388, 4607767036448986638 +389, 4607461223165192234 +390, 4608226484980255663 +391, 4611607256659641032 +392, 4609945211367732974 +393, 4609006453263783302 +394, 4610265844375613630 +395, 4607694615392738521 +396, 4608606212547814938 +397, 4610034239111814504 +398, 4610103751968466900 +399, 4611088505838050253 +400, 4608851769231884474 +401, 4610288514235425111 +402, 4608505539036108714 +403, 4611453738759382658 +404, 4611101647329150173 +405, 4607983202842737743 +406, 4607628593913051809 +407, 4610817169808213622 +408, 4610274104936495796 +409, 4607686898188473999 +410, 4611494545938384459 +411, 4609445238317096124 +412, 4609809658023272942 +413, 4610395993443671939 +414, 4609532016275791584 +415, 4610018501692092651 +416, 4608683763430851439 +417, 4608548880896401248 +418, 4610478349829709585 +419, 4607855690965045385 +420, 4609679774972563395 +421, 4609301972366993458 +422, 4609957828433462989 +423, 4611601276026033182 +424, 4610886414042292178 +425, 4610540517589250995 +426, 4609329807459066933 +427, 4611012060649555364 +428, 4611004988464520281 +429, 4610092518739796845 +430, 4608982525313436661 +431, 4610220581774992574 +432, 4608389110412341488 +433, 4610577194017978099 +434, 4607777219986546519 +435, 4608552325706694521 +436, 4609384775042120780 +437, 4610819470183619029 +438, 4608862514454376763 +439, 4608050912492519261 +440, 4609954958938789219 +441, 4611451357502982166 +442, 4607476785936630269 +443, 4611329691194458319 +444, 4610683876885297263 +445, 4608922438780754530 +446, 4607347319284557650 +447, 4610212564213298006 +448, 4607187736152210274 +449, 4607821132969264993 +450, 4610701944842365016 +451, 4609138892484188991 +452, 4607579978932469946 +453, 4608297026731285373 +454, 4609117946354613867 +455, 4609873371753866995 +456, 4609883036162181473 +457, 4610617143057865264 +458, 4609705966715129773 +459, 4609266086686667759 +460, 4611092203109148192 +461, 4607277668644988197 +462, 4610243051742855164 +463, 4611488200475462773 +464, 4610159190694085398 +465, 4607187122077884953 +466, 4609178002227614028 +467, 4607200609172450908 +468, 4607203109970409745 +469, 4610157519627986095 +470, 4608168608616624151 +471, 4607556712879928934 +472, 4610602971628266891 +473, 4607272386871519909 +474, 4609226601189759664 +475, 4608821958178910465 +476, 4610337925540682923 +477, 4607756826141445338 +478, 4610670714123277518 +479, 4609997633318663199 +480, 4610992528318514467 +481, 4610508873379935121 +482, 4610548944839799582 +483, 4608576872646763539 +484, 4611475238517289488 +485, 4609969545809504006 +486, 4611604653736723262 +487, 4610513754499061149 +488, 4610047791400434915 +489, 4610466779122303079 +490, 4609199569907073109 +491, 4611355331378329938 +492, 4609211256613089457 +493, 4611345984656025190 +494, 4609276744577281463 +495, 4610677520254288398 +496, 4611565920468553537 +497, 4608887769347254935 +498, 4607891688277052029 +499, 4611210417809931519 +500, 4609181196197018924 +501, 4608620849445253589 +502, 4610338756450099522 +503, 4610235666137930968 +504, 4610190689620274242 +505, 4608156139098624503 +506, 4610233351376219666 +507, 4611116196066412550 +508, 4611244546095227734 +509, 4608354486449139402 +510, 4608722837522685541 +511, 4607298792335449598 +512, 4610940117180049531 +513, 4609905783847698405 +514, 4611068115688450709 +515, 4609567280627055335 +516, 4609668102454567333 +517, 4608575291283631952 +518, 4608606739858036458 +519, 4609920659405064132 +520, 4609633855399730395 +521, 4607420399082287137 +522, 4607497830797814837 +523, 4608734929795542569 +524, 4611677103224173563 +525, 4609895185651955231 +526, 4608551100268458835 +527, 4608794936863357442 +528, 4608839444940253689 +529, 4609723875823547919 +530, 4609134168731540965 +531, 4610864297289180458 +532, 4609561568240290174 +533, 4609455706988469654 +534, 4610110730269692806 +535, 4607590724900811004 +536, 4609841446856073581 +537, 4607519144944801539 +538, 4610958924924618965 +539, 4608058978781928209 +540, 4608930736822030783 +541, 4610339624224904683 +542, 4611268940884582276 +543, 4611614440252938509 +544, 4610283933065539718 +545, 4610827563929259801 +546, 4610238281320018148 +547, 4609068702417082470 +548, 4609965625349945622 +549, 4610567655464689798 +550, 4609517999871284092 +551, 4608853313183377285 +552, 4608597386123068580 +553, 4608596804275711127 +554, 4608806942254133750 +555, 4611595740982862812 +556, 4610653226348519116 +557, 4610010878229382699 +558, 4611430012536690008 +559, 4608194334909286956 +560, 4609770785529395235 +561, 4609636612234158840 +562, 4610467762650198285 +563, 4611250113292757754 +564, 4611123483515753501 +565, 4610256050464540468 +566, 4611554812085476534 +567, 4609545597507432057 +568, 4610251629953739706 +569, 4608097940038860692 +570, 4608939256004427493 +571, 4609549477949346267 +572, 4607856563525396488 +573, 4608407566119329436 +574, 4610977065049540740 +575, 4608677612836947043 +576, 4611670385382852661 +577, 4609169914628845192 +578, 4608385528780825832 +579, 4608431699759708725 +580, 4610213210579325967 +581, 4607790519129120154 +582, 4611460475578903177 +583, 4611645204412117197 +584, 4611045465835867018 +585, 4610795725227740679 +586, 4607610666986980838 +587, 4607713533366355938 +588, 4608008411737790225 +589, 4607218032541409981 +590, 4610712747455657843 +591, 4607322986186115065 +592, 4608609778168478040 +593, 4609117986895835630 +594, 4608387138944308707 +595, 4609405159006321483 +596, 4609201389487900126 +597, 4610814010656557822 +598, 4610461402205528089 +599, 4608856848982780180 +600, 4610009661369407408 +601, 4609531046728456306 +602, 4608781638378145485 +603, 4611071218907304246 +604, 4607718364365206169 +605, 4610766522014845193 +606, 4610418511682022913 +607, 4611489866910598987 +608, 4611024768525348505 +609, 4608411227740737072 +610, 4608347021514952714 +611, 4607229154687220486 +612, 4609527688395331186 +613, 4608610487126715045 +614, 4610163014754346271 +615, 4610119594096556803 +616, 4609099103543638986 +617, 4607960911715387937 +618, 4610543345562112354 +619, 4611673200269784439 +620, 4607890122556287450 +621, 4610510919142595773 +622, 4611000945873569885 +623, 4609861297670464893 +624, 4607365464269028252 +625, 4610263820456779466 +626, 4608382757430988076 +627, 4608592826360850405 +628, 4607897223655826864 +629, 4608783406301942627 +630, 4610831809342653056 +631, 4610592838071858481 +632, 4607625427481844846 +633, 4610803200293531160 +634, 4607315949328468373 +635, 4609568473332490124 +636, 4608018723588381940 +637, 4610473680670701003 +638, 4608867424437758236 +639, 4607226771732395005 +640, 4607648878101783522 +641, 4608407495823699878 +642, 4609303470297933457 +643, 4607995287639912115 +644, 4610604756706603303 +645, 4608065328364362400 +646, 4607659009213858799 +647, 4609407180393559403 +648, 4610161232799622667 +649, 4608312339248283632 +650, 4611365830215244879 +651, 4609241343071166241 +652, 4607187426157508336 +653, 4611008486844877795 +654, 4609348293209960853 +655, 4611430342690450936 +656, 4610022123422557819 +657, 4610662613803950933 +658, 4610421175429479085 +659, 4609631547889552562 +660, 4609940555785407216 +661, 4609822163096232669 +662, 4608970136612861659 +663, 4609427082274890719 +664, 4608697401879465484 +665, 4611207783165609518 +666, 4611373087590380940 +667, 4610545384528497527 +668, 4607694071454287047 +669, 4607913509258771897 +670, 4607226952976335318 +671, 4611367164497924691 +672, 4610773799850733403 +673, 4608923576905855388 +674, 4610829132227252858 +675, 4611539466506594954 +676, 4607450455252831956 +677, 4607924760556738513 +678, 4609257351177318999 +679, 4607886491020993167 +680, 4607262386448907585 +681, 4608805527475164058 +682, 4608519384875417362 +683, 4609768003609528793 +684, 4607990620996706344 +685, 4608000541499168509 +686, 4607514221391064237 +687, 4610596308708149427 +688, 4608457358343713720 +689, 4611109413177548323 +690, 4609292098957449828 +691, 4608275497070553256 +692, 4609949308659603960 +693, 4610508332440425814 +694, 4610523421224858005 +695, 4611628503654168653 +696, 4608988043865917565 +697, 4609452807254068291 +698, 4611008104380823402 +699, 4609415493514583781 +700, 4608204811849219551 +701, 4608154991732011594 +702, 4609565684575358357 +703, 4607201300980991047 +704, 4611578953897989322 +705, 4608949284388541303 +706, 4608953402339590043 +707, 4611094520261253641 +708, 4611564299263181877 +709, 4611244613212746921 +710, 4607665698546290637 +711, 4609929742865966113 +712, 4608756528459788870 +713, 4608559801324682100 +714, 4611161313083363936 +715, 4610640544822605367 +716, 4610461950314271130 +717, 4608429389531989501 +718, 4610594975443340868 +719, 4610653541215203471 +720, 4610354404384656514 +721, 4611322467270517926 +722, 4609004358268238303 +723, 4610113217342068535 +724, 4607247286313434436 +725, 4607936058322365025 +726, 4607498677954044120 +727, 4607367643972642434 +728, 4610903724213995603 +729, 4608398398619525170 +730, 4609011100867415968 +731, 4609286350498400836 +732, 4610564846286379047 +733, 4610610842418549113 +734, 4609379950548700715 +735, 4608749477629127198 +736, 4609389534628643041 +737, 4609709510894589547 +738, 4609720477301256427 +739, 4610433170873472685 +740, 4607581786915955136 +741, 4610426993537088574 +742, 4609893496842706786 +743, 4608182222083733544 +744, 4607415409292672163 +745, 4608909799371727180 +746, 4609682438519448644 +747, 4609837420608110159 +748, 4607722492204198941 +749, 4608063142644927447 +750, 4611212896211946065 +751, 4610459279330601000 +752, 4610766525803719281 +753, 4610541719260518609 +754, 4608446538192511629 +755, 4608529268885531628 +756, 4607702152237957857 +757, 4608797703031075472 +758, 4607439116134819826 +759, 4608311115301487628 +760, 4611675179452768396 +761, 4608076597967526423 +762, 4611585923502702782 +763, 4611007505903425519 +764, 4610334401882712716 +765, 4611292864862708587 +766, 4610520603991775838 +767, 4610790439348561649 +768, 4608020323209861832 +769, 4609132354146195150 +770, 4611648991029158429 +771, 4608415373761338387 +772, 4611222889759456059 +773, 4610394879407915891 +774, 4611223274533537520 +775, 4611048920373264726 +776, 4611203040226595031 +777, 4608581225592953052 +778, 4607944132899105268 +779, 4610553416357950208 +780, 4609183189134981159 +781, 4610931403284842449 +782, 4609626797792255137 +783, 4608437008274383407 +784, 4608841271194024119 +785, 4609511843950082189 +786, 4608432804080683600 +787, 4607886713946305196 +788, 4610350555892554303 +789, 4611041162152526452 +790, 4608810036185927099 +791, 4609731609025465382 +792, 4608387458587420116 +793, 4608846429123315125 +794, 4610376323596472588 +795, 4609423912646885032 +796, 4609218872949994167 +797, 4611375967003041069 +798, 4609485140993387628 +799, 4607604870717557062 +800, 4609495797464442279 +801, 4611456949409319675 +802, 4610344977769413626 +803, 4610598065942935600 +804, 4608013012863891262 +805, 4610252455143552284 +806, 4607700593028756519 +807, 4610045641566183312 +808, 4609480926180737252 +809, 4610275596338864080 +810, 4607659695464558950 +811, 4607219197645073589 +812, 4608177295501330522 +813, 4611273956331899579 +814, 4610913813005660249 +815, 4608470207120093898 +816, 4608174217124512103 +817, 4610065364926597101 +818, 4607349317207213784 +819, 4607602167222023985 +820, 4607657145979677117 +821, 4611508729708873431 +822, 4607908717595303714 +823, 4609727931398518344 +824, 4609540956592359987 +825, 4610440481396242417 +826, 4611346585992438567 +827, 4611152612229187917 +828, 4610384157247730087 +829, 4610830126611132722 +830, 4610272123470087431 +831, 4607234503905390991 +832, 4610613653079230069 +833, 4609179215008588124 +834, 4608441295871321425 +835, 4608116436734160239 +836, 4607605033373857689 +837, 4610599359267200688 +838, 4611379096030431268 +839, 4609842285031861233 +840, 4611250379332137731 +841, 4608487405142537379 +842, 4607380789043538335 +843, 4609546285413174259 +844, 4608919052624376420 +845, 4611474363794717141 +846, 4611079221421189606 +847, 4607871497110868045 +848, 4608251852430693481 +849, 4611271625089563201 +850, 4608142282722604751 +851, 4610614961087854140 +852, 4611030874745849847 +853, 4609674534508351596 +854, 4610748124279118172 +855, 4610214076525417764 +856, 4608915989016466776 +857, 4611186209375381383 +858, 4609729165373960964 +859, 4608171107224247283 +860, 4608322267844345836 +861, 4611385726702876896 +862, 4607526082606428148 +863, 4609300797912528830 +864, 4607995042613073018 +865, 4609544162095522243 +866, 4607273392907536721 +867, 4610915254133616443 +868, 4608528592480458486 +869, 4611065489354804147 +870, 4610750286707033259 +871, 4609777244768435300 +872, 4610807148417457906 +873, 4607877316209555589 +874, 4610316726265842451 +875, 4608771732565061950 +876, 4611471267762612145 +877, 4607984815868159369 +878, 4608744077489931245 +879, 4611032300367986435 +880, 4609572801223705776 +881, 4607388928679638867 +882, 4610440380910085523 +883, 4611677400759288526 +884, 4608231223120382380 +885, 4609826308636672129 +886, 4610729764513821105 +887, 4608945691565841376 +888, 4608283276108322908 +889, 4611090204591740692 +890, 4610600988861462466 +891, 4608814357404053556 +892, 4611331328900205001 +893, 4610440474296736006 +894, 4607431388306045801 +895, 4610821334292221218 +896, 4608554210663333875 +897, 4609824397495829498 +898, 4607541211343519985 +899, 4608435017263349928 +900, 4607219271691108353 +901, 4608430070452421044 +902, 4609082847439943417 +903, 4610866784520449850 +904, 4608287501071307688 +905, 4609218510235145503 +906, 4608114112360957267 +907, 4609922412275378983 +908, 4608601574612929512 +909, 4608063236537296892 +910, 4610507352144992045 +911, 4610831100303954067 +912, 4610989778846895898 +913, 4611131006465079227 +914, 4607610719457154999 +915, 4610658650342157966 +916, 4607418499615550301 +917, 4610402445180375078 +918, 4610463803051786556 +919, 4610040245423397003 +920, 4610291132556872432 +921, 4610915180727115233 +922, 4607198239226330244 +923, 4610719993407015954 +924, 4608790436210431943 +925, 4611518788065155885 +926, 4609410806758155597 +927, 4610354727542013410 +928, 4609032496183417847 +929, 4607612835462448389 +930, 4609119308314247716 +931, 4610676295665807893 +932, 4610030018059715751 +933, 4610396681520935881 +934, 4610115299841718605 +935, 4610531703556384068 +936, 4607313656834232832 +937, 4607826054856970203 +938, 4609717410497090129 +939, 4609043343821435147 +940, 4607629724646231370 +941, 4611347190635269674 +942, 4607431356324177025 +943, 4609743147159956874 +944, 4608919951624732686 +945, 4608549836830011507 +946, 4609835749585271216 +947, 4610001878208091800 +948, 4607727638454636808 +949, 4608140523490695322 +950, 4610951723878037203 +951, 4609561113218416843 +952, 4607375879120504969 +953, 4610968421496640577 +954, 4608729663137359994 +955, 4611521561048982293 +956, 4607647181466306462 +957, 4608815536941397702 +958, 4611410078681334217 +959, 4610883601143579986 +960, 4609217767853028115 +961, 4610569694955441160 +962, 4608142872889589658 +963, 4609078496262967192 +964, 4610075946790752678 +965, 4607952350453678296 +966, 4610919620741525096 +967, 4611050224420434596 +968, 4608163018441029734 +969, 4611368242936987963 +970, 4607644493316907613 +971, 4611292201819050900 +972, 4610919228494056420 +973, 4607225037781465524 +974, 4609803354294636294 +975, 4610012640039408504 +976, 4610054964621136538 +977, 4609178240405976665 +978, 4607687932449852507 +979, 4609284420963602445 +980, 4609123874172501167 +981, 4608282636137081729 +982, 4609729376153713229 +983, 4611206065074370636 +984, 4609819396180228727 +985, 4610891933717707670 +986, 4608390654319867654 +987, 4610530001352182832 +988, 4608968440000980355 +989, 4611276663454436837 +990, 4609638657758409036 +991, 4610986200094730228 +992, 4610734380577234553 +993, 4609408663096464249 +994, 4609878290485950846 +995, 4607522064640469547 +996, 4610791378999926894 +997, 4607540164715119602 +998, 4609346418539511860 +999, 4611057822391293948 diff --git a/_randomgen/core_prng/tests/data/dSFMT-testset-2.csv b/_randomgen/core_prng/tests/data/dSFMT-testset-2.csv new file mode 100644 index 000000000000..2ec2d7a51cb1 --- /dev/null +++ b/_randomgen/core_prng/tests/data/dSFMT-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 123456789 +0, 4611184391270596398 +1, 4607748002806405513 +2, 4610950593283603895 +3, 4608090221984835117 +4, 4608620401509188549 +5, 4608933259318787038 +6, 4609013189947794152 +7, 4610981701838014712 +8, 4607749361849391199 +9, 4607937126452632796 +10, 4607787877636103702 +11, 4610534911848167216 +12, 4610758085486021829 +13, 4608376900672555174 +14, 4611475749905869564 +15, 4610499914926478618 +16, 4610900925684457179 +17, 4609184136046668572 +18, 4610480821748015478 +19, 4609898134786890046 +20, 4610017288264709787 +21, 4610945461469807520 +22, 4611377383751342990 +23, 4610945102533068783 +24, 4611669662318553242 +25, 4609191925356202514 +26, 4607369493394647937 +27, 4610171428966243908 +28, 4608117572388953111 +29, 4608266910229155519 +30, 4608559463354581151 +31, 4608291596231703883 +32, 4609993154230249063 +33, 4608158820656759750 +34, 4607825861011031752 +35, 4611091529260321033 +36, 4609803558980700204 +37, 4610892045184692457 +38, 4607844754686911799 +39, 4609239584278564809 +40, 4608975935937490223 +41, 4611186452462884146 +42, 4610644474758878544 +43, 4608188546959932195 +44, 4610317408616093972 +45, 4607827178108179262 +46, 4611275432938764949 +47, 4608511443742655969 +48, 4607200952336491646 +49, 4609727773590041393 +50, 4609137674464229063 +51, 4611529391150713249 +52, 4607446200291229812 +53, 4608618724431091553 +54, 4608231197118968153 +55, 4609848377535763472 +56, 4609769454787363651 +57, 4609093431634418146 +58, 4610941233823434235 +59, 4609301175512188901 +60, 4610884340334734656 +61, 4610063958683836346 +62, 4607897080185028324 +63, 4610305504370096344 +64, 4609499707572786607 +65, 4609874865902334026 +66, 4610351583670684094 +67, 4607292638794148255 +68, 4609412782688385863 +69, 4610390851314330496 +70, 4610340712140767101 +71, 4611109929809487388 +72, 4608431958302562464 +73, 4611491800847619506 +74, 4611664179902108071 +75, 4609243488780021515 +76, 4611114015923144350 +77, 4608524512724098287 +78, 4610450327089558934 +79, 4608720370826377375 +80, 4609572763010883699 +81, 4610381056495781763 +82, 4610005210825690556 +83, 4610341565220388232 +84, 4609034688757121677 +85, 4608823563858030255 +86, 4607971981785212736 +87, 4608714648124969040 +88, 4608968779454607977 +89, 4607272316660152324 +90, 4610748035362895446 +91, 4611319709331049410 +92, 4611390662594804501 +93, 4610054939662414847 +94, 4610394601776085983 +95, 4611424622746948620 +96, 4609395571329163407 +97, 4608527159228147662 +98, 4608379506646233343 +99, 4608996098073467200 +100, 4609633861067625056 +101, 4609387288473331641 +102, 4609369354653726335 +103, 4609305386464755625 +104, 4609085462578529471 +105, 4607213117834450226 +106, 4608676147693465985 +107, 4609894016428056597 +108, 4610808023909042858 +109, 4608152398284126687 +110, 4608864655829389907 +111, 4608853043279974421 +112, 4609998495057236534 +113, 4610971344400740897 +114, 4610947677840469570 +115, 4608888205458648733 +116, 4607306226266885750 +117, 4609476897174960733 +118, 4609298769587075756 +119, 4608046849854182276 +120, 4607709982476583693 +121, 4608905629015127110 +122, 4610027478304152622 +123, 4610378827605636632 +124, 4609168469605184889 +125, 4608424320664524511 +126, 4611224145925927248 +127, 4610598390440508158 +128, 4607548101463088366 +129, 4610445109429344448 +130, 4608982837349247842 +131, 4611526772283530460 +132, 4609215133306156120 +133, 4610747257006687691 +134, 4611305960482481336 +135, 4610602687315818756 +136, 4607839670910202130 +137, 4610527601541091852 +138, 4611462737727028786 +139, 4609212169757271808 +140, 4608447721028771557 +141, 4608224903291976145 +142, 4607298632533980318 +143, 4607975637289743494 +144, 4608776340673956742 +145, 4608578170133208214 +146, 4611177429384019220 +147, 4607665628038835535 +148, 4609531011383000577 +149, 4609360969802432085 +150, 4609908488618542164 +151, 4607366945146869514 +152, 4610136614778041377 +153, 4611168569218164361 +154, 4610462572118833671 +155, 4608070981696376487 +156, 4611058778037833630 +157, 4608159294705821382 +158, 4607530053661949689 +159, 4609136441084496096 +160, 4609331241894336822 +161, 4611313107630037707 +162, 4607957053472625207 +163, 4609675126838719650 +164, 4609482958203648215 +165, 4609691585561697624 +166, 4611475423312731438 +167, 4611412076067906505 +168, 4610429355560523848 +169, 4610625875093760541 +170, 4607241368914269823 +171, 4608589893979475221 +172, 4610073186156188115 +173, 4607291233411155158 +174, 4607675047628278616 +175, 4610869395774400226 +176, 4610232438803745722 +177, 4611554162813131112 +178, 4611642473714833781 +179, 4610563419014907913 +180, 4608459192490850885 +181, 4610780149188594220 +182, 4608960376226045768 +183, 4609069361322693819 +184, 4607256923555182400 +185, 4608474664242579394 +186, 4610207389506744572 +187, 4609112003475072746 +188, 4609240603140788354 +189, 4607525348408117354 +190, 4611149396864007205 +191, 4609114686465130118 +192, 4608849128028589904 +193, 4607248401924217556 +194, 4611387244175010347 +195, 4610567855974092668 +196, 4608169346845917282 +197, 4608490452199719856 +198, 4611203596728963611 +199, 4609287639795895008 +200, 4611614031789088265 +201, 4607236671819565824 +202, 4607466608820858068 +203, 4609639323480231358 +204, 4611254610116912557 +205, 4608807229543638034 +206, 4608381564380368174 +207, 4607428682272410485 +208, 4611229637925604134 +209, 4609236526826003496 +210, 4608889880949328886 +211, 4611135901473627148 +212, 4609923185324027506 +213, 4608879482743843897 +214, 4607662449177713187 +215, 4609980811569949840 +216, 4608275147595190524 +217, 4610799005466054235 +218, 4607667917597769158 +219, 4610185589593486163 +220, 4607529819757965470 +221, 4608839547249506178 +222, 4607706145147011973 +223, 4610988495472186250 +224, 4611534361958731542 +225, 4611641549824093970 +226, 4607316484858856298 +227, 4608641757303921184 +228, 4609375357848069574 +229, 4610565635665894453 +230, 4611147322350665952 +231, 4610071054475069545 +232, 4608886005124134993 +233, 4611384240695070553 +234, 4609556577749744408 +235, 4607688273402525356 +236, 4609395656487625483 +237, 4607920617948366178 +238, 4608233544953726639 +239, 4607736865102992897 +240, 4611554956498550667 +241, 4608735997467283056 +242, 4608499613076219431 +243, 4607926707839352263 +244, 4607349468190181214 +245, 4607855564980078814 +246, 4608566548361033733 +247, 4608689878198670581 +248, 4607485839302113425 +249, 4611493753178685166 +250, 4608566613320387204 +251, 4609743179886038389 +252, 4610508594994820223 +253, 4608995913792958562 +254, 4610248353463386070 +255, 4609788192124211795 +256, 4610619330306161425 +257, 4610873599325465005 +258, 4607324385499645328 +259, 4610611165167596515 +260, 4608006298637673371 +261, 4608540339048264499 +262, 4609631136716349669 +263, 4608685013736282276 +264, 4607363759784022848 +265, 4609492611310929004 +266, 4607780070180818716 +267, 4611531753698196550 +268, 4609227266216837458 +269, 4609211002065400677 +270, 4610668395253295080 +271, 4609134381345731597 +272, 4609382192034225627 +273, 4607208308209034488 +274, 4610579328733327647 +275, 4608921603525338555 +276, 4608290209927931669 +277, 4610866583781415461 +278, 4608182329361248100 +279, 4611648549813945436 +280, 4608601920453704621 +281, 4607406218324299637 +282, 4610748358143595351 +283, 4607437422367397844 +284, 4610299319830347312 +285, 4607992330520188137 +286, 4607658701765777668 +287, 4610721959305012250 +288, 4608971493894533044 +289, 4610010722223631500 +290, 4611050493332836673 +291, 4611164520867402836 +292, 4610619993846650787 +293, 4610600062391983254 +294, 4610986071470687711 +295, 4607815296700712791 +296, 4608678841251990428 +297, 4609887779099788759 +298, 4609503319862290027 +299, 4608809762931362117 +300, 4608037449870401927 +301, 4607755403017924034 +302, 4609087730452781738 +303, 4608773046045154889 +304, 4609803415624001168 +305, 4610998875554212160 +306, 4610380022165388956 +307, 4607984105708776524 +308, 4607847620250154418 +309, 4609666480042052524 +310, 4609307223459772378 +311, 4610669103098622941 +312, 4611513493576426284 +313, 4610110724985187558 +314, 4607584875859460118 +315, 4607466337518526743 +316, 4610953875036984820 +317, 4608473324196281668 +318, 4610528420574205379 +319, 4611218523029715214 +320, 4609404517070225101 +321, 4610679296055932161 +322, 4611602007192673713 +323, 4608768227857799294 +324, 4611351262607349204 +325, 4608656666931918232 +326, 4607814222059811944 +327, 4610377735718844205 +328, 4609693488663627404 +329, 4607234605916181353 +330, 4610438458653690136 +331, 4607691881688829838 +332, 4610084067104393530 +333, 4610193058189981242 +334, 4610500065590109969 +335, 4608182288567589802 +336, 4610884979206264676 +337, 4607934930963198287 +338, 4608198333740812601 +339, 4611615912551444803 +340, 4611091273781746311 +341, 4609878217869378267 +342, 4610329799427547900 +343, 4608946066069950044 +344, 4610517372931467061 +345, 4610173879547218394 +346, 4610768143539619524 +347, 4608251912463490886 +348, 4609138858501301814 +349, 4609537774087558923 +350, 4607501599203475779 +351, 4608820206286486654 +352, 4607594549608867563 +353, 4608928529430502872 +354, 4610326793501581341 +355, 4609216901643916714 +356, 4609921023396761286 +357, 4610188250845345370 +358, 4609056567531193554 +359, 4608042356944953893 +360, 4611153374110275273 +361, 4607652688871602388 +362, 4607736758450185452 +363, 4607772815382776660 +364, 4610793989334300613 +365, 4610810029813744832 +366, 4608713713202824549 +367, 4610555523666319407 +368, 4608933966316349782 +369, 4610847233909664040 +370, 4610569003709254271 +371, 4610141934611190870 +372, 4609800637427386711 +373, 4609531911954538534 +374, 4610018946619778104 +375, 4607563033735657544 +376, 4609466294634090519 +377, 4609110904485970900 +378, 4608802716203741548 +379, 4611231193234792818 +380, 4609853965624850005 +381, 4607407678664700238 +382, 4611560957363283790 +383, 4607258843130776963 +384, 4607438437753792222 +385, 4610880518315386981 +386, 4608724997072138032 +387, 4607896367882266335 +388, 4609466683623316620 +389, 4609649679136642775 +390, 4607572059242669390 +391, 4610690224087953221 +392, 4607212888873300995 +393, 4610115548532567091 +394, 4611204182849533970 +395, 4611480154563209673 +396, 4607313745181304733 +397, 4609677304468142434 +398, 4608230866091821000 +399, 4607916785319391722 +400, 4607735989143160304 +401, 4608364795273033367 +402, 4608202139927885958 +403, 4608897400704372931 +404, 4611267249785141575 +405, 4609988674862878902 +406, 4607825900064550736 +407, 4611018040541037989 +408, 4608438772151688632 +409, 4610422591938237999 +410, 4607217184553988938 +411, 4607633087503746743 +412, 4609394147749351901 +413, 4608101641384193571 +414, 4609733515509206078 +415, 4611489547250433971 +416, 4607834589624331833 +417, 4611349716992792673 +418, 4609707846875238752 +419, 4607311797705362203 +420, 4608945328148355588 +421, 4611273525690510581 +422, 4611458884537996759 +423, 4607997755969685936 +424, 4609048489714323017 +425, 4610334128017869552 +426, 4607485869716832613 +427, 4607547499540098372 +428, 4611447798198333473 +429, 4607207442813565439 +430, 4611108178646490883 +431, 4609758124675924332 +432, 4610269457948568827 +433, 4607360068671694963 +434, 4607781179483110631 +435, 4610840076859630697 +436, 4609605188868326206 +437, 4610833404575495679 +438, 4609202151986229830 +439, 4607653465598307819 +440, 4610341806509732173 +441, 4608937637268370608 +442, 4608846981481205936 +443, 4609890399657918800 +444, 4607475810914216914 +445, 4610779510882657410 +446, 4607200291019787105 +447, 4608763897810030884 +448, 4611030953084521579 +449, 4610608205209840707 +450, 4609901665329352338 +451, 4608229933322773774 +452, 4608306405922059711 +453, 4609402784224466904 +454, 4607797912916831810 +455, 4609320676286567523 +456, 4611203509963612873 +457, 4609443449463211381 +458, 4611201121136708490 +459, 4607891679344035909 +460, 4609295647591940857 +461, 4608699650823090334 +462, 4610113773137160513 +463, 4609644998840868353 +464, 4607236971413190205 +465, 4610986387001985169 +466, 4607686165213831157 +467, 4608006708913412573 +468, 4611617607231087789 +469, 4607950605030537282 +470, 4611312308422726037 +471, 4609920921889730694 +472, 4611272051294701454 +473, 4610732866915233164 +474, 4611475736494024667 +475, 4609129855793761412 +476, 4610896503566695638 +477, 4608983293576256239 +478, 4611337113271775442 +479, 4607264202049306366 +480, 4609273459645222412 +481, 4607686257312802596 +482, 4610552669683473434 +483, 4609573159080816112 +484, 4610109994193793014 +485, 4609104807624348930 +486, 4609056640876615682 +487, 4611233171931551808 +488, 4610700243077601839 +489, 4609689839939656894 +490, 4608154258714850667 +491, 4611519937102265713 +492, 4608524210713510379 +493, 4609408429794931452 +494, 4608727835041307081 +495, 4608363974471195432 +496, 4611053981101408157 +497, 4611244348235020563 +498, 4611215359362792075 +499, 4611323939601701219 +500, 4607339198007393537 +501, 4611192785515763411 +502, 4609520870364372480 +503, 4610305448099707859 +504, 4607627137213702268 +505, 4609512376112901200 +506, 4607188668249670063 +507, 4611507107596430103 +508, 4611290552034620332 +509, 4610948015281142465 +510, 4610082188797301672 +511, 4611154579920165202 +512, 4607910614898084038 +513, 4609111687709912685 +514, 4607756890586988655 +515, 4611478346930052063 +516, 4610271854072480776 +517, 4607666773584055448 +518, 4611269065667018778 +519, 4607229932372594880 +520, 4609361761863029782 +521, 4610810902409829664 +522, 4608310590726885309 +523, 4611549741777094242 +524, 4608905382237807476 +525, 4607539324166606283 +526, 4611302527859497090 +527, 4607673514510851852 +528, 4610239139758062881 +529, 4608296614307074920 +530, 4611131538327332418 +531, 4610491790884660304 +532, 4608012090568842826 +533, 4611145939579689859 +534, 4611569174305843109 +535, 4607548241749347055 +536, 4611302507266314629 +537, 4607334076415859573 +538, 4610759794541675536 +539, 4611562195466283509 +540, 4608064277646826273 +541, 4611362206697199696 +542, 4611267027417975453 +543, 4609817290222129321 +544, 4610075404291128380 +545, 4609555606129743990 +546, 4607220569899493231 +547, 4611584841957177930 +548, 4609037839026191075 +549, 4611594336803497113 +550, 4607225960438616513 +551, 4609362154617705500 +552, 4609887291423254556 +553, 4608541390551696577 +554, 4608696812349818364 +555, 4608371224718817057 +556, 4610715234165102256 +557, 4607906422122850842 +558, 4610831254800690212 +559, 4607810400373332275 +560, 4608705747590604299 +561, 4608938946760670556 +562, 4610310158116436046 +563, 4610355131502528018 +564, 4609768625905121586 +565, 4610143261296345738 +566, 4611431373682787281 +567, 4608146686998001641 +568, 4609198539721817636 +569, 4608916158230506393 +570, 4607654288747635129 +571, 4611682519183492769 +572, 4607197631212679817 +573, 4607299807028695407 +574, 4609116180622479613 +575, 4611019095836572557 +576, 4608581189094026112 +577, 4607488328508280547 +578, 4608587490233232612 +579, 4607245708447615950 +580, 4607189799494915135 +581, 4609348574263949313 +582, 4608021918670812153 +583, 4608172706554967110 +584, 4608811025395016288 +585, 4609364751750743520 +586, 4607844470980185823 +587, 4609405096277516268 +588, 4607748139765213490 +589, 4608512257043070004 +590, 4609962195184017357 +591, 4608461665680660962 +592, 4611127630212845842 +593, 4609686172238940069 +594, 4608777755231651430 +595, 4608284543534209439 +596, 4610868067515254496 +597, 4611535716997037852 +598, 4611319738221220860 +599, 4608658969391651641 +600, 4609452813595548756 +601, 4610236109831493974 +602, 4609938178451088584 +603, 4610331640367617101 +604, 4610901433958649983 +605, 4609766058585980491 +606, 4609222434831315585 +607, 4609778306904942608 +608, 4609448207660443683 +609, 4611299794046339746 +610, 4607801595505703392 +611, 4609594326292439532 +612, 4607668862605395543 +613, 4608245023900457864 +614, 4610578512588843180 +615, 4608185699959219467 +616, 4610904181340375013 +617, 4610647304739305074 +618, 4609795287579987586 +619, 4607960349041110093 +620, 4607703003215776639 +621, 4609403905570407605 +622, 4611233143041131400 +623, 4610530479829073842 +624, 4610679919769197229 +625, 4611448708224350289 +626, 4611445633822299312 +627, 4610496480556319861 +628, 4609555553457224207 +629, 4607626163577357218 +630, 4608595404165123581 +631, 4610510352711119715 +632, 4610203134139830798 +633, 4607550008954478579 +634, 4611603434572420257 +635, 4609780364056746558 +636, 4607295948877799964 +637, 4609867047995237092 +638, 4607936708021896797 +639, 4608897965423418533 +640, 4611287469240086203 +641, 4608515945123070881 +642, 4609851530250371283 +643, 4607577382199018499 +644, 4607744147814966969 +645, 4607260472041943130 +646, 4610683962948666275 +647, 4609625943316701593 +648, 4607251851603159602 +649, 4608016163551470839 +650, 4607202891515091580 +651, 4609099272171658208 +652, 4608510662830783836 +653, 4607744672536335386 +654, 4608142194450948613 +655, 4609476103099505412 +656, 4611399217441119768 +657, 4611495773005281088 +658, 4608815211248586470 +659, 4607337589064315457 +660, 4611394644152964336 +661, 4610812001439064700 +662, 4610702350009793284 +663, 4611075442411386625 +664, 4611077060876180663 +665, 4608164209437610624 +666, 4611368259599962784 +667, 4608333197470863467 +668, 4607183015995911227 +669, 4607199710185468635 +670, 4609413972037912933 +671, 4609234714230829818 +672, 4607739028685645905 +673, 4608232319438231981 +674, 4609333542787352994 +675, 4607657722219109388 +676, 4609193924059916664 +677, 4611141187805060655 +678, 4611068281150742947 +679, 4610549552759132313 +680, 4610085533805630329 +681, 4607232810679281805 +682, 4608493447592041083 +683, 4607355443052807819 +684, 4608410340438808883 +685, 4610315775824782427 +686, 4610312241247357403 +687, 4611287815156776852 +688, 4608076401857758978 +689, 4607457081882300105 +690, 4610908420357480199 +691, 4609797527119137644 +692, 4607351051017728429 +693, 4607618982820305008 +694, 4609846699151054310 +695, 4609389871379854176 +696, 4611243148153910479 +697, 4609270449294231868 +698, 4610832482336321517 +699, 4608101914557495685 +700, 4609128450704503077 +701, 4607351438344234793 +702, 4610010340063776057 +703, 4608461610523881117 +704, 4607869099658377415 +705, 4611211613048598168 +706, 4611196065771110369 +707, 4610515053922650643 +708, 4610096469861694516 +709, 4610477093507778048 +710, 4611547661480689243 +711, 4608438911039690892 +712, 4611311311815318674 +713, 4609279386396407118 +714, 4608222142760880731 +715, 4611613394716251191 +716, 4607603661150022989 +717, 4610135239835120022 +718, 4610929039427992532 +719, 4610757208246529003 +720, 4610920496514785256 +721, 4607326205191641070 +722, 4607938491595237155 +723, 4608585902537439220 +724, 4609326104534891368 +725, 4609325776820376036 +726, 4609693740995539995 +727, 4611329366056096595 +728, 4609303022615335557 +729, 4611512548552170265 +730, 4610404528899365728 +731, 4608023620660481005 +732, 4609431135637339890 +733, 4610767321626117704 +734, 4611106580332635792 +735, 4607433026987401919 +736, 4609580917376189588 +737, 4608816125719706388 +738, 4608380327649573838 +739, 4608700977565012592 +740, 4609148128564608995 +741, 4609631585490496912 +742, 4610745913090661333 +743, 4607498234984630394 +744, 4608367220496728902 +745, 4608365876885021447 +746, 4611537321062599251 +747, 4611238252705917535 +748, 4607525503355262497 +749, 4610601812175940986 +750, 4610145907668011789 +751, 4610384184669464682 +752, 4610699305276533889 +753, 4611440399153628650 +754, 4607963045023571960 +755, 4611498554915678298 +756, 4609015832347581911 +757, 4610795942139040060 +758, 4608894432143218464 +759, 4609704019108678046 +760, 4608168143636007672 +761, 4609566697927636482 +762, 4608690694207868944 +763, 4607746195488024521 +764, 4608350743731006452 +765, 4608442252024570087 +766, 4608428784099249674 +767, 4608941009071857822 +768, 4609298165329524240 +769, 4610447927377989769 +770, 4608304643580688447 +771, 4611265394576506233 +772, 4611210499769545678 +773, 4610114198739241967 +774, 4610653279632780678 +775, 4609515286518383576 +776, 4607984314013723903 +777, 4611541983726033367 +778, 4611393756437132236 +779, 4608968117844197920 +780, 4609367443784351367 +781, 4609488775108334110 +782, 4607529648757616057 +783, 4610676930934349350 +784, 4607750265025461672 +785, 4610373465791644318 +786, 4609305678766837551 +787, 4608947449753189724 +788, 4610366767677719066 +789, 4610439177886004542 +790, 4611242968978180676 +791, 4609370292455902521 +792, 4607754584885122450 +793, 4611224375496789735 +794, 4608921239858925416 +795, 4609513753577022933 +796, 4608075523570985167 +797, 4608608957047081948 +798, 4611273688846153770 +799, 4608394757574873003 +800, 4610377036529664140 +801, 4608600356910393592 +802, 4609667431524003711 +803, 4608601585637259149 +804, 4611533564639785432 +805, 4607510309835958191 +806, 4609651505654903275 +807, 4608166496451053374 +808, 4609515171183335141 +809, 4609776525693204395 +810, 4607696284598399608 +811, 4608607508956363891 +812, 4609695267960623947 +813, 4607576367302408137 +814, 4608741052307396862 +815, 4611095472713646530 +816, 4610161900255157770 +817, 4609145054582502965 +818, 4607410140376051944 +819, 4608126518935915215 +820, 4608269617716261203 +821, 4609477491264110038 +822, 4607463147955504958 +823, 4608999294660391637 +824, 4608694924732427850 +825, 4611156031005634796 +826, 4608453663346634965 +827, 4611380857524502488 +828, 4611362793875369801 +829, 4611632478058955853 +830, 4609434664425350531 +831, 4607606564530411276 +832, 4607391976443208678 +833, 4607762558563019180 +834, 4608554249145639939 +835, 4607806692993216225 +836, 4609510831152869655 +837, 4608164624489904634 +838, 4608455009317767175 +839, 4607280108540066925 +840, 4610080527249430824 +841, 4608840198094196329 +842, 4608916984669714190 +843, 4609771655387294402 +844, 4611351501375292078 +845, 4610356649846014183 +846, 4609861702465798084 +847, 4609335612683847594 +848, 4608963836668425606 +849, 4611448716653608808 +850, 4611618237088472583 +851, 4607650248665393412 +852, 4609477068480641193 +853, 4611408250260317487 +854, 4607799702152927524 +855, 4608984567553844241 +856, 4608966215304179278 +857, 4607599007502108199 +858, 4611197470586031919 +859, 4607738821906038713 +860, 4610174343711771016 +861, 4609411396159113704 +862, 4610528341790372072 +863, 4610621185894682737 +864, 4611164850264296206 +865, 4607500722733965482 +866, 4608747074062289526 +867, 4609587390330409056 +868, 4608013778287410191 +869, 4609438917309909895 +870, 4611359511257377419 +871, 4611161903145694224 +872, 4609908825458581349 +873, 4609974364203149964 +874, 4608056454984693014 +875, 4607485841556578933 +876, 4607689636557505920 +877, 4607225026099434704 +878, 4608918180817633858 +879, 4607389899324828547 +880, 4609528891100730648 +881, 4609347474444270651 +882, 4610604256334495724 +883, 4607717534965049292 +884, 4607416814400338843 +885, 4609568365470566179 +886, 4609490489177847460 +887, 4609959177607409888 +888, 4608249931585238164 +889, 4608374394377617948 +890, 4609359264913370700 +891, 4610789661266619275 +892, 4607881230950036624 +893, 4608163786355022310 +894, 4608830462616805753 +895, 4609531962596587483 +896, 4610555549279318514 +897, 4610008765530009024 +898, 4609509527271380682 +899, 4608445793235798406 +900, 4608895922045956617 +901, 4611496044586314375 +902, 4609855938206283389 +903, 4610584515201059904 +904, 4608185787632733541 +905, 4609925998848840417 +906, 4609746471060930910 +907, 4608322802169846228 +908, 4611668609080045996 +909, 4610918346613262546 +910, 4607487495258046096 +911, 4610091716845110326 +912, 4611060358092721143 +913, 4610617258787020006 +914, 4607968616643301279 +915, 4607216453440634248 +916, 4607683961727519867 +917, 4610192441377241514 +918, 4611340079503032986 +919, 4607737818907905432 +920, 4608040273267030617 +921, 4609075420363483026 +922, 4610025209467938351 +923, 4608669897432477872 +924, 4608611467736828996 +925, 4610963769428151250 +926, 4611230933830803123 +927, 4609892039139108424 +928, 4608322827835753071 +929, 4608048405227745232 +930, 4611336950552458383 +931, 4609990562309176924 +932, 4608539034786829718 +933, 4609715165139430182 +934, 4608805499266985258 +935, 4607728070995330274 +936, 4608780877909747196 +937, 4607569412899178661 +938, 4607268788340312926 +939, 4608510300788384404 +940, 4609202712081615466 +941, 4609583146251705462 +942, 4610981698790205568 +943, 4607925526524476327 +944, 4607793604049723576 +945, 4610915422726587727 +946, 4607690153123448022 +947, 4610957908781080072 +948, 4609688199240625930 +949, 4609195637372175715 +950, 4607455193109906152 +951, 4607614996131060051 +952, 4607821739007708428 +953, 4611432473374206640 +954, 4609331676904204846 +955, 4607810059335115947 +956, 4611077768988065423 +957, 4611510065592294343 +958, 4608753144000455824 +959, 4610618261702230984 +960, 4609478955747078670 +961, 4608250680894683660 +962, 4611056070648131063 +963, 4607756102257795122 +964, 4610370838903190290 +965, 4611412764774525666 +966, 4609100881666906368 +967, 4610119679924928715 +968, 4609686905253473358 +969, 4608711239949443984 +970, 4607839187561408271 +971, 4609413459785445169 +972, 4609209994304368132 +973, 4609118705149046785 +974, 4607291458128247233 +975, 4611161411572838996 +976, 4610256654040673624 +977, 4608882855825268963 +978, 4609049328169514708 +979, 4609651814435298462 +980, 4609304465056789103 +981, 4607682759379096849 +982, 4609946393233090661 +983, 4609946524554590950 +984, 4610880973039636436 +985, 4607217356662986962 +986, 4608230276563898969 +987, 4610664933477117472 +988, 4607562227262100270 +989, 4610133121835039282 +990, 4609071027656845298 +991, 4610444138469204749 +992, 4607185460608050805 +993, 4609895459462574326 +994, 4610016322490782234 +995, 4609380549113996677 +996, 4609371524623560982 +997, 4610108153607631096 +998, 4607489006177078361 +999, 4607632190656691768 diff --git a/_randomgen/core_prng/tests/data/mt19937-testset-1.csv b/_randomgen/core_prng/tests/data/mt19937-testset-1.csv new file mode 100644 index 000000000000..3d4995840fcf --- /dev/null +++ b/_randomgen/core_prng/tests/data/mt19937-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 0xdeadbeaf +0, 0xca6b2fb1 +1, 0x3fa2a974 +2, 0xc12788fe +3, 0x27c9b64d +4, 0xabea28ce +5, 0x540ac30f +6, 0xb239d7be +7, 0x440e5156 +8, 0xc65c133c +9, 0x7333c5fa +10, 0x8292807d +11, 0x459bdab6 +12, 0x4f9f1306 +13, 0xe261f5f7 +14, 0xdb8b69 +15, 0xdf65ed00 +16, 0x5fc8bb71 +17, 0x35a46ece +18, 0x6344e7ce +19, 0xd4c1c08b +20, 0xb88c9bf1 +21, 0x72292bb3 +22, 0xbfb6a51f +23, 0xbb2ab6f +24, 0x9378d4f3 +25, 0x85bc696 +26, 0x1fa92b2a +27, 0x5816122 +28, 0x54e84469 +29, 0x8cdbea8c +30, 0xefa62749 +31, 0x7b13a32e +32, 0xe0c88cc3 +33, 0x238fba9f +34, 0xbee28cb4 +35, 0xc4a2bbe1 +36, 0x8ebb893f +37, 0x53333007 +38, 0x42c59297 +39, 0x507542da +40, 0x4c89a1d9 +41, 0x28cd06c0 +42, 0x63b1b8ff +43, 0x890947ca +44, 0x73996302 +45, 0x7b9afff +46, 0x3d6cf3a2 +47, 0x2d8cf12c +48, 0x1915a047 +49, 0x2e9f42a2 +50, 0xe1d7ea8 +51, 0x8ce9eb49 +52, 0x452706b0 +53, 0x1495dda9 +54, 0x62339095 +55, 0x1fb22d23 +56, 0x6f68cf26 +57, 0x905f8cc4 +58, 0xde25d38f +59, 0xf4f3efa2 +60, 0x8b60b406 +61, 0xecf051fb +62, 0x287a9210 +63, 0x96e96fb +64, 0xb60dd795 +65, 0x305f4bb5 +66, 0xfe838ef2 +67, 0x40671f78 +68, 0xa1cfdcb3 +69, 0xa06c0c2d +70, 0xbcbce0a0 +71, 0x6485453c +72, 0xd6d9e7b5 +73, 0xeac233ef +74, 0xb2a276b4 +75, 0xb5b97ad1 +76, 0x87bc49da +77, 0x1036f82b +78, 0x1e6fc3df +79, 0x87afcd40 +80, 0xe827dc29 +81, 0x16d11b25 +82, 0xe0c549ba +83, 0x427b8a +84, 0x346fa564 +85, 0x5449ea5c +86, 0x511199c6 +87, 0x5ccf41ab +88, 0x9a8a0bbc +89, 0x77f12026 +90, 0x4c9b8ad3 +91, 0xead800a7 +92, 0x80c8a86b +93, 0x3c84c630 +94, 0x19a6c752 +95, 0xc9187482 +96, 0x7eb43f2f +97, 0x89f4fdeb +98, 0x14db06ce +99, 0xcbdc6e25 +100, 0x43ac775 +101, 0xbd730a54 +102, 0xf722dcaa +103, 0x41768d48 +104, 0x20992130 +105, 0xe9973805 +106, 0x61d15976 +107, 0x94c478c8 +108, 0x2b743992 +109, 0xf6fff8fa +110, 0xaac859b1 +111, 0xf03d49ec +112, 0x620dc61 +113, 0x4ce7143c +114, 0x6b85f7cc +115, 0x5fa31164 +116, 0xa284fa6a +117, 0x8714fcfe +118, 0x5d7713ff +119, 0x423c4261 +120, 0x78897296 +121, 0x84281814 +122, 0xec3f65c5 +123, 0xa3922399 +124, 0x7465ebf7 +125, 0x5e794eae +126, 0xaca415d0 +127, 0x277cf6ea +128, 0x248357fa +129, 0xefabaa92 +130, 0x57982e83 +131, 0xb1d764c +132, 0x7c945b58 +133, 0xfd684cf6 +134, 0xeac7a06d +135, 0x367835e0 +136, 0x1a5d6883 +137, 0xf900c7da +138, 0xe3571db7 +139, 0x9d6834db +140, 0xbba4a672 +141, 0x4cd219a3 +142, 0x58c4197e +143, 0x4b037cf4 +144, 0x357acf28 +145, 0x284d7c27 +146, 0x8d0c4569 +147, 0x6ed031f +148, 0xd43e8a5f +149, 0x9cef208b +150, 0x189ea68b +151, 0xf7dad179 +152, 0x5e562f3d +153, 0x322b1e73 +154, 0x3a328762 +155, 0xc4078884 +156, 0x20798ff2 +157, 0xbcfbf409 +158, 0xeb6d471 +159, 0x8a0cba0d +160, 0x53726e18 +161, 0x22b38033 +162, 0xa321a604 +163, 0xf40c90a3 +164, 0x755bb1d3 +165, 0x2832a2a8 +166, 0xfffce275 +167, 0x3afdb520 +168, 0x98d8f18d +169, 0x7a4183b4 +170, 0x69a43d75 +171, 0xd631a4ef +172, 0x2aec3183 +173, 0x60767685 +174, 0x214e1dfd +175, 0x9f14f54d +176, 0xfde4f2bc +177, 0x60a7d47b +178, 0xeaece219 +179, 0xd634f4a0 +180, 0x80ad6fab +181, 0xbe1a53d2 +182, 0xf9a527a4 +183, 0xfdf0ac75 +184, 0x924f54f +185, 0xf99626ee +186, 0xcf7140d3 +187, 0xc8169d5d +188, 0xeb43d58d +189, 0x4b44ace +190, 0xb44ecabe +191, 0x613d8bdf +192, 0x65e3c025 +193, 0x2e324718 +194, 0x9dba63bc +195, 0x8e01c6d2 +196, 0x34800136 +197, 0xc2b01a3 +198, 0x59a182fa +199, 0xf834c79f +200, 0x20e41a8d +201, 0x94079cae +202, 0xcafb9877 +203, 0x87a4b067 +204, 0xa89f22a7 +205, 0xa2932911 +206, 0x580f0787 +207, 0xe4ca48c5 +208, 0x65c9677a +209, 0x37a7ae16 +210, 0xb978422c +211, 0x565bef70 +212, 0xbd7e6dc4 +213, 0xe4ebe924 +214, 0x4a789e96 +215, 0x99520b24 +216, 0xebad792e +217, 0x5d28630a +218, 0x4b33a5bb +219, 0x5a5dedda +220, 0x7ce8d5e +221, 0xa6cdd3a9 +222, 0xb2bcef6a +223, 0x13a8db8c +224, 0x61791eb4 +225, 0xb71e2381 +226, 0xb80dbbcf +227, 0x4d82b92f +228, 0x4f655a9b +229, 0x7748a0a9 +230, 0x508f7c48 +231, 0xd0713d9b +232, 0x3f48b380 +233, 0xd71d7c16 +234, 0x1f8ccd28 +235, 0xebcb920 +236, 0x2f5f4540 +237, 0xb9f69275 +238, 0x6dd968b4 +239, 0x417759f7 +240, 0x7a73257d +241, 0x154ecc84 +242, 0x12f280ce +243, 0x8391eb4b +244, 0xd76d638d +245, 0xf6c44241 +246, 0x8b137d48 +247, 0x71fb30ef +248, 0xe738bba6 +249, 0x28f9bbac +250, 0x46b0dcfe +251, 0x933856e8 +252, 0xad21fdbb +253, 0x5706c9d +254, 0x254b3ce +255, 0xc95fa489 +256, 0x4cc8fd61 +257, 0x9f6d990f +258, 0x3ed84328 +259, 0xfb1251c7 +260, 0x1da78081 +261, 0x2592d895 +262, 0x5c8396cf +263, 0x47fa1df +264, 0x94526768 +265, 0xa41e6fb4 +266, 0x97d47f9a +267, 0x35a56c1f +268, 0xc7af497e +269, 0x906dbbfc +270, 0x861e3287 +271, 0xe91e3387 +272, 0x5b08570d +273, 0x69574f7c +274, 0x32ccf53 +275, 0xf6a6bee3 +276, 0x373d970f +277, 0xaa780838 +278, 0x309d4cc9 +279, 0x58ec672f +280, 0x47cb0305 +281, 0xd4809ac9 +282, 0x138a774d +283, 0x82fa852b +284, 0x53bbd107 +285, 0x1512b55d +286, 0x6d53592c +287, 0x92b7ab58 +288, 0x6654f430 +289, 0xe11837f3 +290, 0x4538410d +291, 0xa2101ede +292, 0x93c2435e +293, 0x5e91b4e4 +294, 0x8f16260 +295, 0x3e64fed1 +296, 0x267fc0f9 +297, 0x3d3ecd37 +298, 0xc4352f2d +299, 0x2170164d +300, 0x3fc50df +301, 0x2c9313dc +302, 0xe69e1950 +303, 0xf834dec1 +304, 0x598d6cb1 +305, 0x79b36360 +306, 0x5d49f11a +307, 0x2ab7af4b +308, 0xf80cc125 +309, 0x824e4b68 +310, 0x36800a00 +311, 0x39186f93 +312, 0x84e177fd +313, 0xe6a40078 +314, 0x86f11e7a +315, 0xa1e79fe1 +316, 0x19fc66f9 +317, 0xb3a2dfb4 +318, 0x88e8091f +319, 0x37dce87d +320, 0xd54b5bc1 +321, 0x323e0c83 +322, 0x1c3d9868 +323, 0x14096d96 +324, 0xe5fbfe55 +325, 0x330004c2 +326, 0x8991d8f +327, 0x934ba7db +328, 0x828aea71 +329, 0xaa955f4d +330, 0xb9097b03 +331, 0xdb924c7c +332, 0xc0fd3c77 +333, 0x6571bc9e +334, 0x3f89462f +335, 0x30ec5ce9 +336, 0xd5083782 +337, 0x68f7c4cc +338, 0x4fd9cbe6 +339, 0xbcf08518 +340, 0xeebb9016 +341, 0xadaf6dbe +342, 0x5aadbf38 +343, 0x5b52ba6c +344, 0x6f31bd06 +345, 0x76b03446 +346, 0xec383171 +347, 0xe5547138 +348, 0x8c87998a +349, 0x1c166e4 +350, 0xd73c5950 +351, 0xa257e0fd +352, 0x9f042772 +353, 0x7b26801e +354, 0x16bce15d +355, 0xb1b3b033 +356, 0x12fc256e +357, 0x8426ed90 +358, 0x16dc30d0 +359, 0x3e003f97 +360, 0x22bf7feb +361, 0x12941766 +362, 0x4da7a3e3 +363, 0x4e4e9900 +364, 0xc2a6efe8 +365, 0x16522570 +366, 0xc49fd435 +367, 0xfc8137a5 +368, 0xe595897e +369, 0xf9dcef1b +370, 0xabdef12a +371, 0x4ebe25f0 +372, 0x86f58fdd +373, 0x46cac45a +374, 0xe430ec3a +375, 0xfd6e6a04 +376, 0xeacffe64 +377, 0xe026aa7f +378, 0xdaf0b65b +379, 0xc0b72e68 +380, 0x63c1dd42 +381, 0x18ec01ec +382, 0x18678c16 +383, 0x2cbbbcc5 +384, 0x457872b4 +385, 0x937347d4 +386, 0x6bdf0813 +387, 0xc6e572de +388, 0x9e0c6f94 +389, 0x45225c3b +390, 0x6fe099ce +391, 0x73b82a0f +392, 0x27203a8e +393, 0xc402180c +394, 0x3b26ea4d +395, 0x852b4444 +396, 0xa6b9a99e +397, 0xecb23332 +398, 0x27fff68a +399, 0x234a59a3 +400, 0xd8a13a6c +401, 0x9e4e99a +402, 0xd4500a99 +403, 0x97822d54 +404, 0x1747949e +405, 0x79b82e14 +406, 0xe907796e +407, 0x2b4bd2ce +408, 0x242b9adf +409, 0xc6979922 +410, 0xa122e4c9 +411, 0x45289a38 +412, 0xa123f35d +413, 0x4464993d +414, 0x89a70091 +415, 0x29f6e129 +416, 0xa2bc559b +417, 0x7b9d89c9 +418, 0x74969534 +419, 0x97fdef8c +420, 0xff09ac83 +421, 0x8a8e913f +422, 0xcfb04bba +423, 0x4ae8ce80 +424, 0x5113f1b6 +425, 0x5e8cfda0 +426, 0x1c3b5e35 +427, 0xeab9562c +428, 0x18a11b6e +429, 0x2f8a0ac1 +430, 0xd564482f +431, 0x772b6c44 +432, 0x27937ce5 +433, 0x202aa930 +434, 0x1a6fb83a +435, 0x3514c661 +436, 0x8c6d26b2 +437, 0x62ce4154 +438, 0x86a82cf2 +439, 0x8a73e17f +440, 0xd7798e07 +441, 0xbd83717d +442, 0x886b880b +443, 0xf7ff35c6 +444, 0x3357dc52 +445, 0x3266f4f8 +446, 0x384ad1fb +447, 0xb34e4e06 +448, 0xfbe250d8 +449, 0xd3d37e83 +450, 0x862b1b12 +451, 0x839a3f7 +452, 0xb22afe3a +453, 0x851d430d +454, 0x514d7503 +455, 0xf8bb3e8 +456, 0x4acdb849 +457, 0xcdd0ace0 +458, 0x6f6b6638 +459, 0x37a6e0ef +460, 0x3e55d305 +461, 0x9ac94ea4 +462, 0x34d82789 +463, 0x1e50a54b +464, 0x12eca710 +465, 0x7813b899 +466, 0x7d56587 +467, 0xa0daf18d +468, 0x461f0a88 +469, 0xc38a68a8 +470, 0xb61e025f +471, 0x9c27611e +472, 0x21a055c9 +473, 0x5f2545d9 +474, 0x981e0107 +475, 0x3f651b42 +476, 0x72b8aece +477, 0x84b09757 +478, 0x3ce97c5 +479, 0x4ebc1ac2 +480, 0x395c23d +481, 0x7c87b77d +482, 0xa5a5b68 +483, 0x5b8a13a8 +484, 0xe5e6f965 +485, 0xf47c69d0 +486, 0x8a7bd38a +487, 0x59a94533 +488, 0xb506fe84 +489, 0x8d96d007 +490, 0x4052151e +491, 0xcaf48e44 +492, 0x2889548b +493, 0x4262fe1e +494, 0x93e43134 +495, 0xb585fdf2 +496, 0x3339e66a +497, 0xe530ee9e +498, 0xa2987fae +499, 0x977205c +500, 0xbfece4e0 +501, 0xf9c925bb +502, 0x999b687b +503, 0x35a166ed +504, 0xe9eba709 +505, 0x40827685 +506, 0xa301a157 +507, 0x18f6e790 +508, 0x8148659f +509, 0x1896e693 +510, 0x90cc1b28 +511, 0x4189c62e +512, 0xda765fdc +513, 0xd219eb8f +514, 0xfac2dd2e +515, 0xef5a48f5 +516, 0xe16f0fe +517, 0x341cba94 +518, 0x69d6e865 +519, 0xaa36eeb8 +520, 0xcfb99f18 +521, 0x8bb61595 +522, 0xa8c2123b +523, 0x3c9310e8 +524, 0x1ee33b4 +525, 0x70c4ca87 +526, 0x1fe3babc +527, 0x7e1a697d +528, 0xf950c974 +529, 0x62c4350f +530, 0xdf4b4b4c +531, 0xb3c8c87f +532, 0xf406b1b9 +533, 0x5b53d2a3 +534, 0x283606bf +535, 0xdf1dc8a8 +536, 0xdaf05fe +537, 0x6bd95a2c +538, 0xa40ffa04 +539, 0xc59ffac5 +540, 0x333bbaa2 +541, 0xa2e970e9 +542, 0x8686876e +543, 0xe7eff30f +544, 0xce8349c5 +545, 0xfb32eef3 +546, 0x692e678 +547, 0xb22eef64 +548, 0x32309c10 +549, 0xd28593bc +550, 0x1055cd1a +551, 0xeec5e7a4 +552, 0x9b15bd7f +553, 0x62068ffb +554, 0x35d431e6 +555, 0x6f795d99 +556, 0x5a583e83 +557, 0x940f9322 +558, 0xbb6392db +559, 0x9133e1be +560, 0x4ba22917 +561, 0x3d98a18d +562, 0xd7aa3d1a +563, 0xdd912a6 +564, 0x99265a2b +565, 0x7d2e4e3f +566, 0x9cfc42f3 +567, 0xad2be67e +568, 0xed7ef841 +569, 0xb1d3b8b4 +570, 0xa56b36f8 +571, 0xe2ef74e0 +572, 0xdf0ef0d9 +573, 0xfd944a1a +574, 0x8dbaa48 +575, 0x7842914 +576, 0x316243c2 +577, 0x2e4c5f54 +578, 0xb86e001a +579, 0x46546448 +580, 0x9643c3d6 +581, 0xbdf7d2da +582, 0xc4e703cb +583, 0x4a45fbad +584, 0xa6375deb +585, 0xa9fc789a +586, 0xc0d075d4 +587, 0xe1824e00 +588, 0xdb54581 +589, 0x645bd158 +590, 0x2044aaa9 +591, 0x706ab8db +592, 0x35151344 +593, 0x2ef15d18 +594, 0xf48d0690 +595, 0x5c23ba6c +596, 0x565c730e +597, 0xc8ed50ad +598, 0xbc6d554e +599, 0x37a911d2 +600, 0x865dc33b +601, 0xfb9ab637 +602, 0x453dcafe +603, 0x7889820c +604, 0xb9f6ef68 +605, 0x7815d4a0 +606, 0xe97080ad +607, 0xbbef816a +608, 0x52d9c2b8 +609, 0x15ea5696 +610, 0x3a83f72f +611, 0xa1378189 +612, 0x892d5668 +613, 0x919e54b4 +614, 0xdb28c6f5 +615, 0xdf6cdf84 +616, 0x8f8f8a52 +617, 0xb3ee2710 +618, 0x9ece78ae +619, 0xe60ffbb4 +620, 0x1e7646ac +621, 0x1682946d +622, 0xd4a252d0 +623, 0xcbc981de +624, 0x5261bf81 +625, 0xa33cd368 +626, 0x98e9e554 +627, 0xa14efd44 +628, 0xcd777d9 +629, 0x8ee578e5 +630, 0x169fcd30 +631, 0x46964c36 +632, 0x49415678 +633, 0xfbc239f3 +634, 0xe00071f4 +635, 0x5a4c1d76 +636, 0xa753cb6d +637, 0x6327b16e +638, 0xb38c5ebd +639, 0x8185adf5 +640, 0xb1cfdc44 +641, 0xaffdc601 +642, 0x46559995 +643, 0xf739bbda +644, 0x950a90f9 +645, 0x779bec0e +646, 0x55791e65 +647, 0xfd94fd72 +648, 0x982b57d6 +649, 0x935efae1 +650, 0x18707a87 +651, 0x5123add3 +652, 0x54b8a239 +653, 0xff5a40bd +654, 0x63ead20d +655, 0x125e8aa0 +656, 0xbae0eba5 +657, 0xc9238af1 +658, 0x3767fc3a +659, 0xc3df41b7 +660, 0xdc53148b +661, 0xd2fb97c5 +662, 0xf8c89afc +663, 0xbb6deecf +664, 0xbcc6ec6f +665, 0xc7931d3c +666, 0x9f40e3be +667, 0x4d966e4e +668, 0xf369918f +669, 0x43c3d8dd +670, 0x305248ca +671, 0xb6b52eab +672, 0x97aa1849 +673, 0x840729bf +674, 0x4cb6e57 +675, 0xa7d59069 +676, 0x1a9a8197 +677, 0xf584e7b5 +678, 0x699c6a70 +679, 0x189b83e8 +680, 0x49f4b09e +681, 0xe726ab1a +682, 0x243775c8 +683, 0x8220f49d +684, 0x6edba081 +685, 0x2fbd3b8a +686, 0x34818276 +687, 0x81bbd13c +688, 0xf30e9f84 +689, 0x2b75ac4b +690, 0xfe66b7ff +691, 0x178b6c29 +692, 0x89ff4e30 +693, 0xc047a72d +694, 0x87977310 +695, 0xa91bf888 +696, 0xf2abc0c6 +697, 0x8547f3ce +698, 0xe78699e9 +699, 0x7c715be7 +700, 0x715aec9c +701, 0x260708ea +702, 0x4bf72dba +703, 0x19134f34 +704, 0xcefe0ecc +705, 0xb74397aa +706, 0x8e48750 +707, 0xb4c2d35e +708, 0x76d81bcd +709, 0x9788da5d +710, 0x234182d6 +711, 0x7efb59e4 +712, 0x15656eb2 +713, 0x2b2ebf2c +714, 0x4d44ac09 +715, 0x57cb6312 +716, 0xe5facad4 +717, 0x6f2dda2 +718, 0x1ace7d61 +719, 0x703ca72e +720, 0x88481396 +721, 0x7235f4bc +722, 0x30921317 +723, 0xd0575405 +724, 0x7c96cf3a +725, 0xabf955c7 +726, 0x27ecd579 +727, 0xfc70f045 +728, 0x68a835b +729, 0x73bc67ba +730, 0x84fd3806 +731, 0x8e08d696 +732, 0x5454e052 +733, 0x1e2dd75d +734, 0xc7903278 +735, 0x50ddb207 +736, 0xcf7431a9 +737, 0x5e2db746 +738, 0x817e811c +739, 0x56c11bf +740, 0xe6f5e4e9 +741, 0x97816caf +742, 0x7abaa833 +743, 0x7d7d777e +744, 0x62d02361 +745, 0x162b687f +746, 0x1360b813 +747, 0xe1c25671 +748, 0x19cd787 +749, 0x9321cab6 +750, 0x799dc638 +751, 0x1b49aef0 +752, 0x6ebd59a5 +753, 0x173cdc79 +754, 0x77e4d187 +755, 0x21803577 +756, 0xa75154bc +757, 0xd92067f1 +758, 0xfcbbda1c +759, 0x713722ff +760, 0xb95dedf +761, 0x10c217fa +762, 0xb166163 +763, 0x39a49d38 +764, 0x4a5f52c6 +765, 0xba172c1 +766, 0x471eb536 +767, 0x9dec38e5 +768, 0x14d3b53 +769, 0x5c588a4c +770, 0xe1a85acc +771, 0x78a5baad +772, 0xd6f90a59 +773, 0xe8d371f7 +774, 0x931890ae +775, 0xea3e4b0e +776, 0xd63407ac +777, 0xf797c99d +778, 0x48da86e8 +779, 0xe23019c0 +780, 0xa70bebaa +781, 0xa49dde13 +782, 0x3f242449 +783, 0x1eddf689 +784, 0xad0e89a4 +785, 0x32e046dd +786, 0x572feee9 +787, 0xfe8cd35e +788, 0x361ade3f +789, 0x2781da1c +790, 0x7fe09627 +791, 0x9a81a896 +792, 0xb52dfbad +793, 0x862b12c8 +794, 0xd0dc9c3b +795, 0x410e82c1 +796, 0x20d95af3 +797, 0x17357938 +798, 0xd1f2e42a +799, 0x99efd6c3 +800, 0x2dae59f4 +801, 0x51702dba +802, 0xa020dc62 +803, 0xd71ebd9d +804, 0x9c498db6 +805, 0xc50017ae +806, 0x4f944ffc +807, 0xe9a8e62f +808, 0xac490f79 +809, 0xc816d8b0 +810, 0xf3770304 +811, 0x4ba63128 +812, 0x7f4be54f +813, 0xdcf19d03 +814, 0x589718c4 +815, 0xed7c3114 +816, 0x70e5d73d +817, 0xdce25620 +818, 0x411e12af +819, 0xd68dfd60 +820, 0xbd44f0e1 +821, 0xb2962c96 +822, 0x4c7fa632 +823, 0x85136387 +824, 0x41b232a4 +825, 0xdb9a8997 +826, 0xfcb5df1b +827, 0xa046c4 +828, 0x5a7e53d4 +829, 0xe214dfbf +830, 0xc0861c7d +831, 0x3087ed3 +832, 0xd70b7358 +833, 0x369a9dee +834, 0xb99e904c +835, 0x22052e4b +836, 0x9afd4d95 +837, 0xd9dbcec +838, 0x9c18c47a +839, 0x97caa173 +840, 0x6f124137 +841, 0x26db8abb +842, 0x2dfeba8f +843, 0xc9ebd4dd +844, 0x2bf6f89b +845, 0xec81549f +846, 0xee3f1ac2 +847, 0xa3bad22a +848, 0xb9597c71 +849, 0xe220adf +850, 0xa9fbfdb5 +851, 0x9d817858 +852, 0x5679190d +853, 0x216c47c0 +854, 0x6c1d0b13 +855, 0x401d2e42 +856, 0xf3ca424f +857, 0x2894625e +858, 0xa614fdd8 +859, 0xa11e427 +860, 0xbc937623 +861, 0xe684b934 +862, 0x33821e19 +863, 0xbfc008f9 +864, 0x11579cd9 +865, 0x9886df8f +866, 0x5889e2e8 +867, 0xefbba03b +868, 0x182e7d44 +869, 0x217f4e99 +870, 0x82623484 +871, 0x6bb6f662 +872, 0x49bb5fcf +873, 0xf7c8d1a9 +874, 0xea51c810 +875, 0x40ef965e +876, 0x24d4b1a3 +877, 0xe9266bbf +878, 0xfb5179a0 +879, 0x92d23fc +880, 0x8c646351 +881, 0x527608ec +882, 0xd215edf3 +883, 0x3434a6ad +884, 0x757e915e +885, 0x62ef706f +886, 0x467080bc +887, 0x2578c3b6 +888, 0xc308bc20 +889, 0x44fe744f +890, 0x50ea3915 +891, 0xeb3995d3 +892, 0xe5ee8390 +893, 0xb9c7a39f +894, 0x83ab2921 +895, 0xb194f017 +896, 0x17e00f01 +897, 0x54ca5220 +898, 0xa10e3a60 +899, 0x1426c5ca +900, 0xdd42073d +901, 0x6a7b3945 +902, 0xda2127d7 +903, 0x4b0dd400 +904, 0xd35134fd +905, 0xcfa033e8 +906, 0xcbf475f0 +907, 0xcdb92b39 +908, 0xde8c0c75 +909, 0x219d1cd7 +910, 0xd6398be +911, 0xa3eaac5f +912, 0x92898b14 +913, 0xf4c27fce +914, 0xd5f7cb82 +915, 0xc10ec953 +916, 0xa01d0f31 +917, 0xc794c9e4 +918, 0x54168123 +919, 0x723bcdf2 +920, 0x6cea1b +921, 0xdf18376a +922, 0x922a0845 +923, 0x8eda2a83 +924, 0x9b0608f +925, 0x472cbc78 +926, 0x7afdce6b +927, 0x1bfa7fdd +928, 0x5ada3d12 +929, 0x5cf41e17 +930, 0xc506060b +931, 0x7214c2ac +932, 0xc19ae321 +933, 0x9b031d30 +934, 0x4c7b88da +935, 0xd00e5d13 +936, 0xee6b59c4 +937, 0x79ddaf5b +938, 0x29cf931 +939, 0xc6fa4b96 +940, 0x874ab89b +941, 0x4abc046c +942, 0x366d693e +943, 0xd6a1758b +944, 0xd964eb41 +945, 0x7eabd20b +946, 0xf71f17ac +947, 0xdb5d8c06 +948, 0x54602ce1 +949, 0x786313f6 +950, 0xae4aea46 +951, 0xca92465b +952, 0x60047085 +953, 0x39f7dd56 +954, 0x9d1ff152 +955, 0xfdf62ba0 +956, 0xa15cf163 +957, 0xb953b33 +958, 0xc912dbb9 +959, 0x9e7f36f1 +960, 0x34c02ede +961, 0x6742f244 +962, 0xd586cf43 +963, 0xc2bf8b07 +964, 0x814f36b4 +965, 0xaef9cfbd +966, 0x1ec4b840 +967, 0x7aaaf552 +968, 0x5eab3290 +969, 0xc6f9bfdc +970, 0x7e43bf8e +971, 0x3c63bf8 +972, 0x4ce6e886 +973, 0x4b1e48ca +974, 0xff5bade3 +975, 0xdf72eca5 +976, 0x48e273a4 +977, 0x8b186129 +978, 0xcf6f6016 +979, 0x7c70ccf7 +980, 0xe82e54f8 +981, 0xcfdb9cfb +982, 0x884af787 +983, 0x839fb72d +984, 0x6f021358 +985, 0xbe27e737 +986, 0x12de7b8c +987, 0x946ce6c1 +988, 0xd95a0cee +989, 0x54adc084 +990, 0x6850d90e +991, 0x8e7e4a4a +992, 0x27e99d2c +993, 0xa966b606 +994, 0x6f9e586 +995, 0x141df137 +996, 0x80bdaf81 +997, 0xa1cd6dce +998, 0xecd7c0de +999, 0x44dc0c32 diff --git a/_randomgen/core_prng/tests/data/mt19937-testset-2.csv b/_randomgen/core_prng/tests/data/mt19937-testset-2.csv new file mode 100644 index 000000000000..d2f6c156c97d --- /dev/null +++ b/_randomgen/core_prng/tests/data/mt19937-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 0x0 +0, 0x8c7f0aac +1, 0x97c4aa2f +2, 0xb716a675 +3, 0xd821ccc0 +4, 0x9a4eb343 +5, 0xdba252fb +6, 0x8b7d76c3 +7, 0xd8e57d67 +8, 0x6c74a409 +9, 0x9fa1ded3 +10, 0xa5595115 +11, 0x6266d6f2 +12, 0x7005b724 +13, 0x4c2b3a57 +14, 0xe44b3c46 +15, 0xe84bdd8 +16, 0xf6b29a58 +17, 0x45cccd8c +18, 0x6229393a +19, 0x7a4842c1 +20, 0xcaae7de6 +21, 0xcfea4a27 +22, 0x8765a857 +23, 0x7adfc8ae +24, 0x916b5e58 +25, 0x648d8b51 +26, 0xecf3e6a5 +27, 0xd6094219 +28, 0x122f6b4d +29, 0x565f9848 +30, 0x164e1b09 +31, 0xa5ee9794 +32, 0x52d0873 +33, 0x5e4513d0 +34, 0xd52692f3 +35, 0xf5081ec5 +36, 0xc73547fe +37, 0x23ee074f +38, 0xdeb91daf +39, 0xdebe09c0 +40, 0xfa86bb52 +41, 0x793e6063 +42, 0xcc95a7d8 +43, 0xcd087cb1 +44, 0x762382f3 +45, 0x853e031d +46, 0xc7d0c293 +47, 0xadcb0c93 +48, 0x1e473b8e +49, 0xb87b61a7 +50, 0xa3d1dd20 +51, 0x94ff3fc1 +52, 0x24b2cd09 +53, 0x89914ab9 +54, 0xf1d5d27f +55, 0xc234a220 +56, 0x8597da1f +57, 0x1b1cc2ca +58, 0x6a2748f4 +59, 0x793de097 +60, 0x43b9eaa3 +61, 0x2fb379fe +62, 0xc6342dcb +63, 0xbca6ab72 +64, 0x74c644b7 +65, 0x376fd81c +66, 0x9184e322 +67, 0x229da880 +68, 0x4cf6880 +69, 0x52fae7a4 +70, 0x9e1d5c35 +71, 0x26511785 +72, 0x9cb24e26 +73, 0x38ea0de8 +74, 0x9def62f4 +75, 0x62f0f111 +76, 0xf199794f +77, 0xe710b184 +78, 0xae8bc669 +79, 0x732fec2a +80, 0x5c08b5ba +81, 0x9cf1ba1f +82, 0x6fe15378 +83, 0xe7005101 +84, 0xb297f541 +85, 0x196a6fe7 +86, 0xf6aefa9 +87, 0xf8456839 +88, 0xaab13923 +89, 0xa7342f66 +90, 0xabaeec77 +91, 0x2bc0bb0b +92, 0x35dba1ae +93, 0x5bafdc52 +94, 0x2101505b +95, 0xc02cf780 +96, 0x50bfe98e +97, 0x9b9aca63 +98, 0x5d1c2635 +99, 0x53364b8c +100, 0x91f86a79 +101, 0x9d63faa +102, 0x70483054 +103, 0xa25fc8cb +104, 0xfd061144 +105, 0xf57db306 +106, 0x1a1f9bc4 +107, 0xa71d442f +108, 0x3578f27f +109, 0xa29337f4 +110, 0x294b9483 +111, 0xfecbf3cc +112, 0xa7321b64 +113, 0x94f424b4 +114, 0x40d7b7e8 +115, 0x6a140f4e +116, 0x7760248f +117, 0x7985c694 +118, 0x3e92ace3 +119, 0x9f9e5bba +120, 0x28b23b17 +121, 0x5687aacf +122, 0x1c418b8d +123, 0xacbc9175 +124, 0xa8053755 +125, 0x51342230 +126, 0x235ff531 +127, 0xc741a645 +128, 0x325338a9 +129, 0xf31716a3 +130, 0x5e64c5c0 +131, 0xa99b5c5f +132, 0xd22c9cc5 +133, 0x3796e5e +134, 0x18dba100 +135, 0x9f72d771 +136, 0xd6838eb2 +137, 0xac74f524 +138, 0x1899e7a2 +139, 0xf8d16330 +140, 0xf9f93f5d +141, 0xe0d14983 +142, 0x77f98662 +143, 0x8276be2a +144, 0xfa0d03cd +145, 0xe435170 +146, 0x9ad727e7 +147, 0x737f2b95 +148, 0xbd4060c9 +149, 0x51de97f +150, 0xa083600 +151, 0x7113f78a +152, 0x48660972 +153, 0xfac6322b +154, 0x1ec533ba +155, 0x5c048d7f +156, 0x4bcfd817 +157, 0x7b1bd6bb +158, 0x1e64f082 +159, 0xb04c1979 +160, 0x51675862 +161, 0xe166de3e +162, 0x6a0d23a3 +163, 0xeb117ade +164, 0x106bf87b +165, 0x3781a7c3 +166, 0xb145da52 +167, 0x90b037ae +168, 0x910ccae3 +169, 0xdd775c94 +170, 0x43f090d1 +171, 0x824bca32 +172, 0x85f3959b +173, 0xeaae5b0e +174, 0x180c7c29 +175, 0xebd0fc3a +176, 0x93713ac1 +177, 0x1546dc24 +178, 0xede65b0a +179, 0x47189056 +180, 0x518dbc2b +181, 0x2653368 +182, 0xaadb680b +183, 0xd7a3bb02 +184, 0x21bd8133 +185, 0xa5ad3450 +186, 0xb7613820 +187, 0xd76514b6 +188, 0x4a168480 +189, 0x43c55b26 +190, 0x2ee5a113 +191, 0x65d794ae +192, 0x9625b62a +193, 0x8d85b573 +194, 0x525c4b8 +195, 0x2a3989bc +196, 0xd43569e8 +197, 0x5eabbe4d +198, 0x133b91e +199, 0x257d3518 +200, 0xad85627d +201, 0x91d28302 +202, 0x451f3e03 +203, 0xb428205e +204, 0xbc35ace2 +205, 0x49d9976b +206, 0xf651fd0d +207, 0x6eebf770 +208, 0x3fae4928 +209, 0xc1903548 +210, 0x937f0c13 +211, 0x6566b25f +212, 0x97900f48 +213, 0xe562c59a +214, 0x927f19c2 +215, 0xa39054f8 +216, 0x391be0b4 +217, 0xe43ce943 +218, 0xf3e75bec +219, 0xae181f3d +220, 0x7276cf0e +221, 0x72fe9f60 +222, 0xd8ae3d04 +223, 0xfa839fc3 +224, 0xb31112ed +225, 0x1dbf688b +226, 0x4c24d3fc +227, 0xc45baa56 +228, 0xd0550dcd +229, 0x696d0b79 +230, 0x6581666d +231, 0xace9934b +232, 0xe18ffab8 +233, 0x3ff2a610 +234, 0x94ce4c98 +235, 0x502f139d +236, 0xe1b96895 +237, 0xf725846e +238, 0xb149c019 +239, 0x96a5a5d0 +240, 0xb9aa43bc +241, 0xa8e00779 +242, 0x8056cb76 +243, 0x88803475 +244, 0xf4c1e5bd +245, 0x3b043653 +246, 0xa4dc8aa1 +247, 0x65162768 +248, 0x6c81c3a0 +249, 0x9e6a3ce4 +250, 0x9b3c95fb +251, 0x7990eafb +252, 0x4e9d879 +253, 0x785a9546 +254, 0x4d3401d5 +255, 0xb750a91f +256, 0xa901220d +257, 0x49b9c747 +258, 0x4a4286b8 +259, 0x622a9498 +260, 0x9e36424f +261, 0xbfc99829 +262, 0x6dc3c912 +263, 0xe0e23e28 +264, 0x22ae6db6 +265, 0x1a5540cf +266, 0x4c5c3b0b +267, 0x17a5d0a6 +268, 0x91e9386f +269, 0x5aa2cd5d +270, 0x97436ff9 +271, 0x8d43d481 +272, 0x9306fadf +273, 0x89ba776 +274, 0xa7382b2c +275, 0xf80de0d8 +276, 0xa6f03d7d +277, 0x522ce018 +278, 0x6e717043 +279, 0x38a4abd2 +280, 0xe58413ef +281, 0x2429df03 +282, 0x5e1888ea +283, 0x18e606cc +284, 0x6f94d7e6 +285, 0xfbea3123 +286, 0xe45516d6 +287, 0x42a5b3fe +288, 0xce62babd +289, 0x897a4ec5 +290, 0xb4320ad7 +291, 0x72ab4a2b +292, 0x19a87820 +293, 0x197d5c0b +294, 0xeb633668 +295, 0x5a3118d4 +296, 0xb6d8848a +297, 0x7820b6b6 +298, 0xffb46feb +299, 0xd754f5a5 +300, 0x26423e7d +301, 0xe796fe9c +302, 0xde3d826f +303, 0x99d7de8 +304, 0x29992302 +305, 0x8220f61b +306, 0x9d954fd3 +307, 0x2ab684d9 +308, 0x1fb2aa97 +309, 0xc76fe335 +310, 0xd9171133 +311, 0xdd6c44ae +312, 0xceac7494 +313, 0x69514bb5 +314, 0x91b0961d +315, 0x23d53e43 +316, 0x683d2a23 +317, 0x8814327 +318, 0x11b4ed89 +319, 0xfb8a0849 +320, 0xb28ab129 +321, 0x5f8ffb97 +322, 0x741b5f83 +323, 0x6b8a0f2e +324, 0xb8d8a2da +325, 0xcf357b2 +326, 0xddcb3b6c +327, 0x5d912703 +328, 0xf9bbc71f +329, 0x441bb09 +330, 0xdb15ed8a +331, 0x3b11ee1b +332, 0x2ffb1ad +333, 0xc3d140c7 +334, 0x5c2785a7 +335, 0xf1b2143d +336, 0xbae0a955 +337, 0xbffff361 +338, 0x2befec2c +339, 0x56e32b22 +340, 0x8562a7a2 +341, 0x7d531458 +342, 0xde91821 +343, 0x56c7ba85 +344, 0x3332f8e8 +345, 0x2df312ff +346, 0x4bdd824 +347, 0x2bc5c700 +348, 0xcb2fc5cb +349, 0x76a4b922 +350, 0x395320c5 +351, 0xdfe4037e +352, 0x5868f7b5 +353, 0xf1b1d4fe +354, 0xed96bc50 +355, 0x9bb675be +356, 0xb4548088 +357, 0x98be68bd +358, 0x8269881 +359, 0xc89ce8d1 +360, 0x2a296570 +361, 0x8001b923 +362, 0x9f193578 +363, 0xce50d5b +364, 0x93c540a8 +365, 0xb2f81774 +366, 0x3ce68b24 +367, 0xfe0db0b0 +368, 0xef28a619 +369, 0x446b5143 +370, 0x9d2cdf67 +371, 0xadd8e1fc +372, 0x891f3b23 +373, 0xdd418c72 +374, 0x9704571e +375, 0xc037541d +376, 0xbae946f1 +377, 0xf6e8cd21 +378, 0x4fdba092 +379, 0x8de2d511 +380, 0x65f1d0dd +381, 0x365f3954 +382, 0x35b851fd +383, 0x38f20a02 +384, 0x2faa5845 +385, 0x37fff565 +386, 0xf1c2638c +387, 0x91cf922c +388, 0xbd533375 +389, 0x73bd6afd +390, 0x7d8eb542 +391, 0xf8616e6f +392, 0x3a37d85b +393, 0xae382d55 +394, 0x411d81a7 +395, 0x15d5ee27 +396, 0xedaffcb +397, 0xe716e96 +398, 0x6f35ed9e +399, 0x7ce2ee91 +400, 0x4fd1dac6 +401, 0xe18983c7 +402, 0xb2439112 +403, 0xf9f5a35c +404, 0x60b4582b +405, 0x9e1ed453 +406, 0x2dfa81b1 +407, 0x8ae13329 +408, 0x651585d +409, 0xdac7f4ae +410, 0x11374595 +411, 0xbe6bf0c9 +412, 0xadecaf59 +413, 0x7a8549f2 +414, 0x742579e0 +415, 0xad5537db +416, 0x895d4149 +417, 0x9b674e1c +418, 0xe58c3feb +419, 0xb6f660d1 +420, 0xfd86da69 +421, 0x7830f7ba +422, 0x37868f80 +423, 0x74bd5fd6 +424, 0xa9bf7e3f +425, 0xe80b0410 +426, 0x4369186a +427, 0x2320e0a4 +428, 0x549625e +429, 0x3aae1e18 +430, 0xc2251a74 +431, 0xe1af94bf +432, 0x51eca4c3 +433, 0xe7886533 +434, 0x622ab088 +435, 0xa55223b8 +436, 0x969bf35b +437, 0x531e6c5d +438, 0xd4bf977b +439, 0x850bcaee +440, 0xa104f457 +441, 0x3a0a0 +442, 0xdf660893 +443, 0x4fd61248 +444, 0x4606d9c7 +445, 0x6cea6457 +446, 0xcc4ccc0d +447, 0xe2a57d3a +448, 0x2f85d651 +449, 0xae0c9478 +450, 0xf3ea2774 +451, 0x74c4ebb7 +452, 0xafff3b40 +453, 0x7bc0aacb +454, 0x372b82dc +455, 0xc9ead3a4 +456, 0xf286e119 +457, 0x3abcb320 +458, 0xbb195daa +459, 0xe15b2f0e +460, 0x410251d6 +461, 0x504e251c +462, 0x369b9d14 +463, 0xf51b7fd2 +464, 0x84a8cd44 +465, 0x78c4b616 +466, 0x691d4e3 +467, 0xb62a5b7a +468, 0x351cc253 +469, 0x27588287 +470, 0x6cb82fc8 +471, 0xbafe423d +472, 0x5fc99a8d +473, 0xa5719605 +474, 0x76ace100 +475, 0x37026c88 +476, 0x4712accf +477, 0x2fbbb9cf +478, 0x96377fb5 +479, 0xcebd948b +480, 0xdd25a404 +481, 0xbf4099a7 +482, 0x1e16915c +483, 0xacc2cbad +484, 0x8472f51a +485, 0x46e2824a +486, 0x21cf3734 +487, 0x2cc6d3ee +488, 0xb7841db1 +489, 0xb4586cdb +490, 0x65642b33 +491, 0x769102e3 +492, 0x90bf7369 +493, 0xd7265312 +494, 0x2eeb6d75 +495, 0x34721522 +496, 0x2514be33 +497, 0x2a3abe9e +498, 0x7cf141b5 +499, 0x1ff50f3a +500, 0x5b096fab +501, 0xb8da4737 +502, 0xf0c025fc +503, 0x7cbc3fc +504, 0xc3ec5b12 +505, 0xbf3b03ad +506, 0xbfa86b57 +507, 0x17b461c1 +508, 0xe75a2d46 +509, 0x37aad5ea +510, 0x155b2c35 +511, 0xbfcf2330 +512, 0x8d5c7c5e +513, 0xbb50483b +514, 0x95a03950 +515, 0xbad669a +516, 0xf641767c +517, 0x358b50a3 +518, 0x4aca2e3a +519, 0x497343b1 +520, 0x3da6f46a +521, 0xad6120c9 +522, 0x19acdd2c +523, 0x1023470d +524, 0x434bb79 +525, 0x8e3f0746 +526, 0xedf5a226 +527, 0x25d8ea7 +528, 0xab7fa688 +529, 0xd541fc0d +530, 0xc8ffc7f8 +531, 0xfbfd0387 +532, 0x481f76d0 +533, 0xb4183bf8 +534, 0x961efa16 +535, 0x2e7f61f8 +536, 0x105f5f4f +537, 0x832c37d9 +538, 0x7c521708 +539, 0x94982ee3 +540, 0xfa3d1f06 +541, 0xc99c5cd1 +542, 0xe062a5c7 +543, 0x9b41f9d4 +544, 0x569195d9 +545, 0x37e93fc2 +546, 0xf629763c +547, 0x7485f190 +548, 0x3b50cc38 +549, 0xe0fd9b72 +550, 0xf3068eed +551, 0x7e054a97 +552, 0xf0fe2118 +553, 0xb72f0404 +554, 0xcc988a64 +555, 0x7c74f3ec +556, 0xa1650931 +557, 0xb5636957 +558, 0xdfd1561e +559, 0x7f861e36 +560, 0x4b036099 +561, 0xd8346f14 +562, 0xd9545d61 +563, 0x31c06965 +564, 0x9e2d2ab9 +565, 0xc5f8b197 +566, 0x3637d9b +567, 0xf969041d +568, 0x58e44ba1 +569, 0xdcc05573 +570, 0x25ec8f35 +571, 0xc7ca0a77 +572, 0xfb592bb3 +573, 0xfc2b1356 +574, 0x7a7679f6 +575, 0xc0e9f007 +576, 0x7f550a69 +577, 0x1094bf1 +578, 0xa3b47889 +579, 0x44fc9ab6 +580, 0x5e5b8f80 +581, 0x69160353 +582, 0x230be578 +583, 0x6da013a4 +584, 0xd2764ed1 +585, 0x4c3f5c94 +586, 0x3099df75 +587, 0x66b09bf0 +588, 0x82e5cd03 +589, 0x1ee3607e +590, 0x396cd72a +591, 0xfb0f2241 +592, 0x190c5614 +593, 0x67f78324 +594, 0xdcb89544 +595, 0x91b7cbd0 +596, 0xf9114070 +597, 0x57f687af +598, 0xf5f9428a +599, 0xc9f390ed +600, 0xe8140568 +601, 0x694fb3de +602, 0xc627f75b +603, 0x5bf9362b +604, 0x5549003f +605, 0x66458f9f +606, 0x14c30f94 +607, 0x4d44c9c6 +608, 0x6840f509 +609, 0xc674cdbc +610, 0x3b73b25b +611, 0xed1c4a6f +612, 0x21eab5a3 +613, 0x53478953 +614, 0xdad674c +615, 0xf3ef5512 +616, 0xb9c08d71 +617, 0x3921f4a +618, 0x2ece8e2 +619, 0x889134e1 +620, 0xc544c7ab +621, 0x4df91683 +622, 0x259e4b8c +623, 0xe2031ce4 +624, 0x145b8f3a +625, 0x4028cf81 +626, 0x16f03971 +627, 0xad6adc80 +628, 0xac0b5327 +629, 0xcf77f418 +630, 0x3ed062ba +631, 0x6ea14124 +632, 0x6ba87963 +633, 0xc08be345 +634, 0x8eafb886 +635, 0xd460d003 +636, 0xdc4d14e2 +637, 0x61085b79 +638, 0xba1f92a8 +639, 0x18b779bc +640, 0x453435a1 +641, 0x41925d1c +642, 0x21a8db44 +643, 0x9789101a +644, 0xe2d02e0 +645, 0x79fa68f8 +646, 0x4d35916d +647, 0x7ce947b3 +648, 0x431a2cc9 +649, 0x756135b5 +650, 0x74c5a0c5 +651, 0x864bb3a1 +652, 0xaeeb8687 +653, 0x7127ea7d +654, 0xb214825e +655, 0xda464848 +656, 0x4894b0f6 +657, 0x6ef5db54 +658, 0x6142e487 +659, 0xd3adc6c3 +660, 0x2e5fe8d5 +661, 0x82643ddb +662, 0xc9de1e6c +663, 0x161ccd43 +664, 0xe8d9866 +665, 0xa8f85f54 +666, 0xb26e6947 +667, 0x34e36253 +668, 0xc75894df +669, 0xd8e70900 +670, 0xc7042e85 +671, 0xae6d8d5b +672, 0x4269846b +673, 0x2da97b9e +674, 0x5fb237c9 +675, 0x11e247d3 +676, 0x966cee07 +677, 0x27aec95 +678, 0x45d7a7e5 +679, 0xe45d5ddc +680, 0x5ef03588 +681, 0x222ac6ab +682, 0x3272262e +683, 0xc7792000 +684, 0x75b91d68 +685, 0xecd782b3 +686, 0xb6bb626 +687, 0xb715f459 +688, 0xccbf6c4a +689, 0x7da649f3 +690, 0x13b36ae2 +691, 0x78310a7b +692, 0x84d26157 +693, 0xe1f93c60 +694, 0x4e8b1b53 +695, 0x7d08711a +696, 0x93d9dace +697, 0x6a211820 +698, 0xf59d6c73 +699, 0x2c9299c6 +700, 0xa5441761 +701, 0x79ac91ac +702, 0x90d833b +703, 0xc89d2739 +704, 0x6e2edab2 +705, 0x8e7228ad +706, 0x829076e9 +707, 0x28ed0c84 +708, 0x8942edb9 +709, 0x24d2005d +710, 0xae6fbd5b +711, 0xa6433591 +712, 0x471089a3 +713, 0x8a0a8ec2 +714, 0x20fd0194 +715, 0x536013ad +716, 0x648664b9 +717, 0x25a2b3cf +718, 0xf4d70177 +719, 0x28ed3ea4 +720, 0x2fe7cf69 +721, 0x21212abe +722, 0xe76b7e04 +723, 0x943441f1 +724, 0x8b36ddf2 +725, 0x179e5ccd +726, 0x74f8259e +727, 0xe919756d +728, 0xe1cd7757 +729, 0x153da2e2 +730, 0x756711a3 +731, 0xcce59a49 +732, 0xb9630cda +733, 0xe08ba7b7 +734, 0x6626861a +735, 0x17ecf576 +736, 0xe76f7416 +737, 0x6d2261cc +738, 0xb0a57acf +739, 0x7924fd62 +740, 0xb31a6e5a +741, 0x9487cc33 +742, 0x53e57be6 +743, 0xb75bc72e +744, 0xc1bc3ed0 +745, 0x6edfe3d +746, 0xa2d4e5bc +747, 0xbb3cdb2f +748, 0x3d71f7fa +749, 0xc457b868 +750, 0x29191280 +751, 0x2800d8a +752, 0xcbe04fcb +753, 0x4eebd78d +754, 0xf58bf147 +755, 0x3b9d125e +756, 0x75489606 +757, 0x80e09ead +758, 0x974abcf5 +759, 0xf427159e +760, 0xdb93b60f +761, 0x8eccb8a9 +762, 0x750c98a6 +763, 0x18f3b535 +764, 0xf3ae0bab +765, 0x9f265252 +766, 0x93646d87 +767, 0xdcef0cdc +768, 0xd21dcb41 +769, 0x285a96a9 +770, 0xe8a9fb42 +771, 0xfe0fdc72 +772, 0xd0c62b5c +773, 0x15c2a14e +774, 0x28cf62e5 +775, 0x182e64db +776, 0xa0ff7cf6 +777, 0xa2342064 +778, 0x65ffc99f +779, 0xf30528dd +780, 0x100df4b2 +781, 0xefce9dfc +782, 0x6c8d60ae +783, 0x7287625d +784, 0x42391e72 +785, 0xba4a4ea1 +786, 0xd95a930c +787, 0xbe034ee0 +788, 0x886a6e9 +789, 0x4e96a350 +790, 0xf57fe442 +791, 0x1ea955c8 +792, 0x5af973f3 +793, 0x71a2087d +794, 0x5b51248a +795, 0x644b5270 +796, 0x42e1ada +797, 0x8827449b +798, 0x2f6b62b8 +799, 0xd8695c78 +800, 0x66b8f141 +801, 0x894949c0 +802, 0xede60ac5 +803, 0xae262f58 +804, 0x19805d22 +805, 0x9bf30fcf +806, 0xf1ff4803 +807, 0x1935dabc +808, 0xde96ccee +809, 0x178f1ea5 +810, 0x7443fcab +811, 0xe53c6d3 +812, 0x53a2ab58 +813, 0x1626fe46 +814, 0x3b951e94 +815, 0x3cb76386 +816, 0x9d4d8f1c +817, 0xd6ea5273 +818, 0x8779386 +819, 0x85ba1342 +820, 0x3fec25c +821, 0x8358dfdc +822, 0x6dc58e66 +823, 0xa65b6365 +824, 0x116d4d7b +825, 0x8b6a4ec5 +826, 0x407f346d +827, 0x84fa549 +828, 0x389e0064 +829, 0x9484d2b6 +830, 0x40d1234d +831, 0xc5661795 +832, 0x218cd5fb +833, 0x6050629f +834, 0x314ce51 +835, 0x7db3cc23 +836, 0x1d9060ed +837, 0xfb4cbcf3 +838, 0x9e54b8fa +839, 0x3ea17988 +840, 0xf968dafe +841, 0x5fd3a519 +842, 0xfd874015 +843, 0xbb059ad +844, 0x68b7c4e5 +845, 0x4f6097d6 +846, 0x29b76190 +847, 0xd4de7499 +848, 0xa385e3ee +849, 0xce990c77 +850, 0x7d84a6a5 +851, 0xa3d89f7f +852, 0xfd49f581 +853, 0x5e3bf585 +854, 0x10b7c6c6 +855, 0x5010998c +856, 0xc8820d5a +857, 0xcd45224a +858, 0x49d47bfb +859, 0x1208d3b6 +860, 0x3dcd9c4e +861, 0xaefea33e +862, 0xa999e648 +863, 0x617778c7 +864, 0x3efdff2d +865, 0xa2494c85 +866, 0xaa75be2f +867, 0xed47f2bb +868, 0x846e54aa +869, 0xda9bd1c3 +870, 0x6c91188a +871, 0x7f67d2f2 +872, 0x8e000539 +873, 0x6d868ddb +874, 0x497c3559 +875, 0xd2934183 +876, 0xb4e2147d +877, 0xbcfc6ace +878, 0x6a340f52 +879, 0x727804c5 +880, 0x5c4cb6ba +881, 0xf80a0784 +882, 0xd422dc11 +883, 0x5cf822c5 +884, 0xeccaa1bf +885, 0x65c4c15e +886, 0xbc72298 +887, 0xbd1a4e83 +888, 0x3b8d7145 +889, 0x72f721a8 +890, 0x593890a4 +891, 0xeff1de3a +892, 0xd0a1a4b1 +893, 0x41da0db7 +894, 0xfc492a98 +895, 0x61bb02a1 +896, 0xf80e8792 +897, 0xb277df61 +898, 0xe7aab1ce +899, 0xe5a662f1 +900, 0x4beb1c87 +901, 0x1efdc7b5 +902, 0xfdf472eb +903, 0x3dd5f02e +904, 0x3fd9fdf0 +905, 0x3a6f7bf4 +906, 0x1b1caa7f +907, 0x7d507ba1 +908, 0xf371a151 +909, 0xe43ad49d +910, 0x3bc16e0c +911, 0x5bacee76 +912, 0xb094a72e +913, 0x629eeb76 +914, 0xef07120 +915, 0xeaae9f22 +916, 0xbb0fc073 +917, 0x1d231657 +918, 0xe1b86a7c +919, 0xa1917199 +920, 0x45be6cae +921, 0x220029f2 +922, 0x6109df6b +923, 0x5fce7e34 +924, 0x5fd1dfe9 +925, 0x530c326e +926, 0xbfb09640 +927, 0xae1c0d4c +928, 0x3ce0ef76 +929, 0xcba82a49 +930, 0x2bfe9092 +931, 0x8101cb04 +932, 0x7304c707 +933, 0x4bd68a83 +934, 0x4df1a430 +935, 0xe2ce6c4c +936, 0xd6d51925 +937, 0x5a143074 +938, 0x3cdca5ed +939, 0xbd072630 +940, 0x809c986d +941, 0x8e2c27d2 +942, 0xf14d28b3 +943, 0x3396aa31 +944, 0xa24dac47 +945, 0x8c6bbf5a +946, 0xde06adb1 +947, 0x85074fee +948, 0xf0b1951d +949, 0x5949d203 +950, 0xc032204a +951, 0x64d7e54 +952, 0xb31759ea +953, 0x2619ad41 +954, 0xf7cc9777 +955, 0x21c10e14 +956, 0xfe910cd0 +957, 0xb53a142a +958, 0x73aa95f2 +959, 0xb585c01c +960, 0x1224859a +961, 0x9c9b8b57 +962, 0x4af48cb4 +963, 0xac021930 +964, 0x2700b7c2 +965, 0x72906666 +966, 0x6ae06309 +967, 0xb2321d02 +968, 0x219c2d74 +969, 0x60d9fb6c +970, 0x9aa776e9 +971, 0x199bb359 +972, 0x61ffb57c +973, 0xf5d36375 +974, 0xe5380264 +975, 0x128b105a +976, 0xf7c16444 +977, 0x4f0e269 +978, 0x8c00a60a +979, 0xfac5500c +980, 0x465ad668 +981, 0x2602a8e1 +982, 0x979c69a5 +983, 0x423a50a7 +984, 0xe59223a0 +985, 0x372ce57a +986, 0x681fad21 +987, 0x9475239a +988, 0x8d550063 +989, 0xf9cadcd9 +990, 0x458b0932 +991, 0x45e3e958 +992, 0x7497fcd2 +993, 0xf856d714 +994, 0x66d6b2de +995, 0x686fe9c +996, 0x3f980648 +997, 0xe356d512 +998, 0x81807599 +999, 0xb5676398 diff --git a/_randomgen/core_prng/tests/data/philox-testset-1.csv b/_randomgen/core_prng/tests/data/philox-testset-1.csv new file mode 100644 index 000000000000..64c1516cbdc0 --- /dev/null +++ b/_randomgen/core_prng/tests/data/philox-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 0xdeadbeaf +0, 0xa4016d3bd1adb1dc +1, 0xa554a8f84b75ce6e +2, 0x64aaf86f2a8b501a +3, 0xd1de65006998520b +4, 0x392794fdb78e642e +5, 0x13aba45f3ded2bc7 +6, 0x72953d6a6ed0ce9b +7, 0x81dc11fff0ade5e9 +8, 0x28c22fa622755161 +9, 0x2d0bf144d156bca8 +10, 0x88c67c8c249075ea +11, 0xaf979d9c3fa6a9f4 +12, 0x8351dedf59eda5c3 +13, 0xa597c60a8db6df19 +14, 0xbd22a90d6d81b032 +15, 0x3034c0d2086b8564 +16, 0x2879c4883a14c06 +17, 0x5a66f8a2208a94f5 +18, 0xcda7bf16739a6681 +19, 0x369b3461c902a66f +20, 0x14a3541487ef7613 +21, 0x60dc1cc40c854dba +22, 0xb8d6129bcbdf1894 +23, 0xddc1e842a5ce4b82 +24, 0xf5a5c000d4804841 +25, 0x29c1123be4c5a3 +26, 0x928197be48d100b +27, 0x9164d36b36459765 +28, 0xa5b361d3b9fe5094 +29, 0x966e6293e46a92e9 +30, 0x380b501fcd0e9e1b +31, 0x538c1834694cb627 +32, 0x68397c2b7e36891a +33, 0x569416ce7905efdc +34, 0xf58f21254316c4ce +35, 0x1e19d04d36f0446b +36, 0x4eab321b90c3059e +37, 0xf4eef8577ce3621e +38, 0x86aa30aad7e74bd7 +39, 0x46ad14d76a4e9edc +40, 0x9158798abc57ef60 +41, 0x54206b8453720f00 +42, 0x44e68b9350e349a4 +43, 0xfee4ef034f34ec46 +44, 0xd47125c4a5cd9a5d +45, 0x174e9bb06dab2e1b +46, 0xc6a3beafe03adf09 +47, 0x8a155bf8f077f2ff +48, 0xc037f7a702e0e091 +49, 0x7121788b47bb1f67 +50, 0xcc1e3035fd6cee3f +51, 0xf59ef1e37c98f033 +52, 0x54e5c5049de62701 +53, 0x46353528f1594539 +54, 0xb93695a2d9cf5a1c +55, 0x29e0dfdf2ce8cfa7 +56, 0x598f527bbe1f0abd +57, 0x7b1c84c93d833619 +58, 0xe05228837711bc0c +59, 0x1cb8fc3e70fd977a +60, 0x109d878184b67919 +61, 0x9f971fe0d44411b7 +62, 0x886c0994aaf201e1 +63, 0xc0dd321f1390b2e7 +64, 0x3fdef712372f8321 +65, 0xfa7c6d8918cd8a29 +66, 0x11c1eb4cb16252c4 +67, 0xbc57160901fbbc4e +68, 0x9035cb331c1c6032 +69, 0xa75b7195d844181d +70, 0xaee9b050676d9595 +71, 0x34d540b1d61818ca +72, 0x851885a79cfef55f +73, 0x2f5602c107a51176 +74, 0xf02cce653d94ae18 +75, 0x69703c81d7642c2e +76, 0xc37f35a3762bf75d +77, 0x584d48c1678ba110 +78, 0x214f883b77e43d91 +79, 0x32c9f2e834bc151e +80, 0xa25ec540319a0279 +81, 0xd0ef31b3a764dd1e +82, 0x413fc1760f4696b0 +83, 0x2ec088887c392c6e +84, 0x643e07972c0d7edf +85, 0x181da5ad37378493 +86, 0x7807a71aee267e7a +87, 0xc8251e8b6f84c9cc +88, 0xaecd92db4caa82db +89, 0xe6b737b621d0f5e4 +90, 0x74a594617dfd217a +91, 0xa167df989d02c069 +92, 0xea01be29eee2049f +93, 0xeee29b33c17d78a9 +94, 0x3491d38fb23f3fc8 +95, 0xeb4487ea874377e6 +96, 0x7997f3b9ba996313 +97, 0x8eb5bda3e878f439 +98, 0x1a17f0c4997b9dac +99, 0x449f4caa3e49d3bd +100, 0x1d6864b879e608b1 +101, 0x32c53c6d5e4e51ae +102, 0x508f8f76cf4660ec +103, 0x6c06057521c22c33 +104, 0x868a66b6414f4e2 +105, 0x5715002f33452e98 +106, 0x115fbd06a3ac4e8a +107, 0xfcac2badb17c901a +108, 0x4c44e1e868322197 +109, 0xeb8fa2d7d096a4fa +110, 0x5418a67b92163d7 +111, 0xd9c592de8e80a341 +112, 0x732a44e5218c1cf0 +113, 0xa9368ebfa3fe327 +114, 0xc5fea8642de21f5b +115, 0x8aa7606b2c790548 +116, 0xdc345a26c0b0d0be +117, 0xf3926ddb06d16b69 +118, 0x8221732a3335efcc +119, 0xf9617131e08d7747 +120, 0x99327d82da6c2710 +121, 0x489965f6c29fc095 +122, 0x489883ac61fbf8a5 +123, 0xf93180c072491e2d +124, 0xbc652ef0fb7fa413 +125, 0x26b645337e0f0151 +126, 0x221c4fd98d9d04a0 +127, 0xbf37f891d23b1a5a +128, 0xf895c9daa40736d4 +129, 0xce74ab4966a7df8b +130, 0xd2ede8866e13602a +131, 0x6f1c653376aed88c +132, 0x795f01d45d648320 +133, 0xe871c1ca660fb460 +134, 0x40ab3bbc97818d76 +135, 0x35d7ffca14a7ade7 +136, 0xc4e33deed96936a +137, 0x23e3678027f084a +138, 0xaca324e1826bc2bc +139, 0x912083410f2c9602 +140, 0xe60447c78d94dab8 +141, 0xccfa70966b894010 +142, 0xda52cf984a6fcecc +143, 0x4bd41ad2099c8555 +144, 0xd48a643116cbfdfb +145, 0xbf7fc5b1bc00ce08 +146, 0xada212b7bd53caf1 +147, 0xd6852e20e7ec8990 +148, 0x37334ee1ef839cb6 +149, 0x4cfcfdfb1210ba72 +150, 0x86621c6062cecdce +151, 0xaa81f5bd7dc7f04b +152, 0x6803d22953c928 +153, 0x25af4104ef0196bc +154, 0x3f43caa463f637f1 +155, 0x752c82a0d44e4276 +156, 0x564b16249685d0d6 +157, 0xba4752d6711744b +158, 0x78ff9b2d759bd294 +159, 0xb93c8b5b9ca0ab4f +160, 0x7a3b59e3c26e8aeb +161, 0x483b45671cc7a011 +162, 0x600055f7d0ab48b5 +163, 0xe83dfca027b30174 +164, 0x5283c2d730c533de +165, 0xf5ff0af35cc16bef +166, 0xe65e629ad63ace2 +167, 0x4599b59b43471c90 +168, 0x3b883221ddd0edbe +169, 0xd1bd681d7571586a +170, 0x2f76707a866652f4 +171, 0xfa431b2763618557 +172, 0xbb30fd01840f73fe +173, 0x4e05560dda8ff28 +174, 0x7d463765716205db +175, 0x6802d6a4c64bc942 +176, 0x23f97ab176fc38c7 +177, 0x6fa71a806a74e049 +178, 0x4f8c47e05d613085 +179, 0x1c62a84ea1a987c2 +180, 0xb985dd9fcfcbaf12 +181, 0xbfd1d96717312296 +182, 0xf7623c95eba45fef +183, 0x9aacb0d9d2bc45ed +184, 0xe479947525498f64 +185, 0x6fcef0ca0aca8a90 +186, 0x278894094d25783a +187, 0xdc02388636ed13d5 +188, 0xc62e48f5953cbcd7 +189, 0xe19a9fa5bed7628e +190, 0xdeb078ae8fe5dfb0 +191, 0x4e6860e046964ce5 +192, 0xd8cdb2898e2a30b4 +193, 0x635e6d7bf2d5ad3c +194, 0x382287d0bbc15096 +195, 0x4dce30919aaed075 +196, 0x91f2eeeb2e9d3bc0 +197, 0x8815aed14f2ce31a +198, 0xd1587cbd77a69435 +199, 0xf27ba7a7f17e068e +200, 0xc91ea6657949ca8a +201, 0x8fb304e0fd14e8aa +202, 0x20435550a23087b3 +203, 0x711f1c68e57b2b9a +204, 0xea6994cf0be86f7f +205, 0xd18c615acc777905 +206, 0xb90960bb87ffd1a0 +207, 0xac90e55e19311295 +208, 0x31659affc36aae91 +209, 0xd7d7e48ef29c958a +210, 0xaee7da2da84dc993 +211, 0xdc7dffa68e28f198 +212, 0x2a640b7dddf397ff +213, 0x96c8eb4f3eee1b5c +214, 0x783f85e380c37624 +215, 0xe03c5ffaab657342 +216, 0x699873d780917aa6 +217, 0xb19fdd3fdfe2195a +218, 0xe5ac242b8935d3d3 +219, 0x40fefd049828e9a2 +220, 0xc5376b89b3da4996 +221, 0x4a41f1092c5468bb +222, 0x2155cf97cbf75962 +223, 0xaa3ec3edde80ba66 +224, 0x1caec347492ffadd +225, 0xd80dc91a46a52d31 +226, 0x12f749bee8cd142b +227, 0x82212e1e4913e774 +228, 0x5746ee2f1e40f3c5 +229, 0x8e62e2276ac29cb6 +230, 0x267b7a85f83e8b95 +231, 0x3c6436ef222f439c +232, 0xb52ff729bf93362b +233, 0x169d41a9b76ad990 +234, 0xcffd92d5315e9a76 +235, 0x2b6596632a14e62b +236, 0x4b86680bf8d00375 +237, 0xe57684dbc26d0e4f +238, 0xd437041fa45a59f5 +239, 0x7e1f0aac84d7e4e2 +240, 0x1187ce212e5e7834 +241, 0x76f1c2154a2e3d50 +242, 0x712d0e28711856a9 +243, 0xd5f54dc83e5c12ad +244, 0xc24a17f46e4c418a +245, 0xc51e029ea6d4f2e2 +246, 0xc31a655846a16146 +247, 0xef88f4da62201b06 +248, 0xf33e2f9d0a8d91e0 +249, 0xdc679372436366b3 +250, 0x25c9763e8013baee +251, 0xd8aa69cdaac03261 +252, 0x57e8bde3bc84e10c +253, 0x21c8c1336d7f36e1 +254, 0xe8accbc264dab29 +255, 0xc98322f62b53cf6a +256, 0x8b83421277b969f +257, 0xb57131b80e2e277b +258, 0x444d7e89c60d71dd +259, 0xb0d9e46bb1c33e76 +260, 0x3d5a684c6113db38 +261, 0x2711e1981a992b2d +262, 0xf2d4db5c46a2ec57 +263, 0xed7b35c56ef6a104 +264, 0x83f3cdb9bc4ada6a +265, 0xe022709b7ea47148 +266, 0xb570382def08f207 +267, 0x1ff1a063da5e52e6 +268, 0x1431c8c76bfd271f +269, 0x36a3ae42d26ae46b +270, 0xe49797ad98a160ee +271, 0xd1facb5e688b3c6f +272, 0xa9080cfeb38b849c +273, 0x35e77aa7d3827d44 +274, 0x96d94f159c2bc6f5 +275, 0x9a1005b1aae0602c +276, 0xc12ba0bda081de45 +277, 0x12781e7aa9155495 +278, 0xbc8bf25c33eb784a +279, 0x2c59317df88aeaef +280, 0x712c3f6f0647fe7f +281, 0x6de6cc238b4334b4 +282, 0x5084214e6a6e8e44 +283, 0xfccf29c93e989fd2 +284, 0x908bd387fff422a4 +285, 0x1bea6614135216b5 +286, 0xfc77a0b775e22d6f +287, 0xe060b6e9fea8bc24 +288, 0x28efa8a899554d2 +289, 0x2472913e201c807d +290, 0x7105e53d38203b17 +291, 0xfd930d5b12f274af +292, 0xde103731a6b10d73 +293, 0x1abed9ae891a6fd5 +294, 0x2ac90b2b44327c6c +295, 0x8b2590bb2b05e83f +296, 0xfa1d4711c71d541f +297, 0xd4ca45335ac19253 +298, 0x8e1d05c7517e4e72 +299, 0x9c0902deb45e3f6e +300, 0xbaba37c175ce76b0 +301, 0x601af65183731007 +302, 0x7eb8587a2d4c135b +303, 0x20bb71c6e9199a23 +304, 0xc0ca4dc39757b5a6 +305, 0xcc6be1e1ed4d8273 +306, 0xcc74c8e5d18f5f7b +307, 0x86ce3a5781885ae9 +308, 0x7b62ce783ec46209 +309, 0xfb266311a6c0550c +310, 0x554773cccbec1559 +311, 0xa977c8205a4aae08 +312, 0x9ee5fc0c8fbf6dce +313, 0x4f5705626b4f2d17 +314, 0x22d88963961cbf4f +315, 0xfd6dc42eb7fcc0e +316, 0xf88e30d786e0ecbe +317, 0x78fe0f1b15436367 +318, 0x7499f2d214cb7268 +319, 0x913d1695a973ce15 +320, 0xb83d91cdf10b568f +321, 0x93dbc1f9fb7d1e0c +322, 0x7d7bc7061aad68ac +323, 0xaa0601e59a625056 +324, 0xa72cbfff7c7ff448 +325, 0x7318a8d3915ace11 +326, 0x36842549fb894417 +327, 0xb68ea7ad73e99b6a +328, 0xcbdf94cb59042237 +329, 0xa2a7fd9eddd13720 +330, 0x732dd9f06eb3c5fc +331, 0x4fb08823a37032ed +332, 0xe6c856ed41016c49 +333, 0x996c3d0e4f3b417 +334, 0x7b34a700117568fb +335, 0x199eefcf92de5f86 +336, 0xa3f4961be1c5b0d5 +337, 0x5f41b28cf7b244b5 +338, 0x312410aa5e2fb5f9 +339, 0x1586dba27b082c7e +340, 0x84ed5134c1917f33 +341, 0x59f4afdb3c49271a +342, 0x925d17fb348c7028 +343, 0xfc7d3c57ea5636b9 +344, 0x6d1171ae97fb0915 +345, 0x398f4cbc4e9c54fc +346, 0x1c2ebb92b1b504ef +347, 0x3b2328cb18c05023 +348, 0x8d9db4e20415c26f +349, 0x6a0a8a1b1845e93 +350, 0x8dc25082c60f2f7 +351, 0x717be0ac6519b0fc +352, 0x96b0e9458c83e3aa +353, 0x95672c97c1e1d811 +354, 0x38eeff8eaee7b86d +355, 0xfcaf43097da98c20 +356, 0x3c3e92583d27de30 +357, 0x9c497d64afc8474d +358, 0xd9490e6e4d69e245 +359, 0x659965798924d480 +360, 0x3fe6c83496d2e8a3 +361, 0x35f0e70b604c298b +362, 0x6b2b04775eabc4be +363, 0x91db116a3482d1f +364, 0x4530affe8ed6651b +365, 0xaeb91d6b34fac1ea +366, 0x84c7b10dbcb7c855 +367, 0xa484c7232eb07597 +368, 0xbc408d28ff7b549b +369, 0x59806824675e1397 +370, 0xd090322df3ed7160 +371, 0x98584fcfd0731210 +372, 0x72f1dfc286dac4c6 +373, 0xf19a3de3ac829f2d +374, 0xfded8b979c32a9c3 +375, 0x11183cf8e5fd735b +376, 0x1fd22c3a64e887aa +377, 0xf1ad39eaea361b09 +378, 0xca21672cc4c0afcf +379, 0xcf9ca801297c015d +380, 0xb58af039ca2132a9 +381, 0xb2c1cfebc559a4d3 +382, 0xe6aeeddc924fe174 +383, 0xa4ee5d69059f2a35 +384, 0xb4891d7ce04994fc +385, 0x2d86e4a3aebe4406 +386, 0xe0e37a9afe1410dd +387, 0x3fad3ef7713a378e +388, 0xe6546dc8f25626ce +389, 0x610065e43da6b067 +390, 0x246433cc66b2ae3 +391, 0x987f33b8819a1248 +392, 0xdef42b9ae3070ada +393, 0x372e29ed9ca79858 +394, 0xa77c59d5f963ad7a +395, 0xab30aad91674d0f8 +396, 0xdef9084c78c88b91 +397, 0xf43176d0a08831dd +398, 0x3c9199a67d636dae +399, 0x1c1740467f01f9d3 +400, 0x526f48081c053f81 +401, 0xfb3e2a79343e5e29 +402, 0x18c4950887faec3a +403, 0x8bc979d8a8985fa6 +404, 0xcf40e8843fd3059b +405, 0xb19676125f3f52f2 +406, 0x4a0a6b19170a7ad7 +407, 0xd34de55b18b57416 +408, 0xbdc1e59e8ec23c6e +409, 0x8ec4b1a49fecac44 +410, 0xfdc61f4b5c67d0b6 +411, 0xe2fe45308ec48888 +412, 0x14cdeaf1d4e6d7cd +413, 0xc3ba3ec042a56233 +414, 0x332da8b89898979c +415, 0xfba5de9a6658a159 +416, 0x6a8e39f8f9251c9 +417, 0x99de3f00ca6ac555 +418, 0x6b83762f9cde7610 +419, 0x2c9724e61be893d0 +420, 0x482951b5de7a8676 +421, 0x94c864bf7b7b3ce1 +422, 0xe7fb63eaa8034f7b +423, 0x3606766d32778e49 +424, 0x832fb6d1c1702fad +425, 0x231a34aa65f35f3 +426, 0x2dbbb19d5057dc11 +427, 0xadc96a7b0ec4d7c6 +428, 0xcedb950834baeeaf +429, 0x10454de5dd5b2b4c +430, 0xacb5218055b223a8 +431, 0xfc7935a53eef226a +432, 0x7ecfef66f3a0a28d +433, 0xa3c506354fdf354d +434, 0xbf718d5dc3f872f +435, 0x58a8cd40351434ff +436, 0xf4a5f71e6b8feb50 +437, 0x7c362e216ad9c96a +438, 0x2a6431ffce1c07ad +439, 0xae65a7b73a58f481 +440, 0x67653634cd12e61a +441, 0x6d1fcfb52e19bf3c +442, 0x91ad77d4053b6726 +443, 0xd945d1507c4924f2 +444, 0xf45ae9093c093257 +445, 0x64b2b6a4bac0adff +446, 0x5ff6f2b342d71de5 +447, 0x59925318c904944d +448, 0x95dbf54419fb4864 +449, 0xd55ba61f567a0a97 +450, 0xee563293f29b5750 +451, 0x5837051585cad45c +452, 0xfcf40f619994def9 +453, 0x5260f8ee6f748019 +454, 0x71764f26e092ad15 +455, 0x3ccbde223b20fea3 +456, 0xad863d51bde55140 +457, 0xc580fad0c3e9843 +458, 0xa5337a7858a6a49c +459, 0xc43e9199c2d296a7 +460, 0xa3172bc5d23744fb +461, 0x6fb2b18f90271d5a +462, 0x1061bd95c79f5218 +463, 0x38002aa34425849f +464, 0x4cefbbbc74ff719e +465, 0xcadbed5627af6154 +466, 0x7bebd30f09338836 +467, 0xba48fd224dbcf41f +468, 0x6fb65073938adfdd +469, 0x1c74e5ea63a196f +470, 0x6aa6af9b2f2c56b7 +471, 0xb34d1259dbc5283e +472, 0x4e31ff60e92e2d44 +473, 0xefe7fa9b9e3f35b5 +474, 0x980e16e5be4f7b63 +475, 0x750f9235268a94cc +476, 0x6007d403696373c2 +477, 0x13bcd1966ef5491c +478, 0xa10fd6a45986ae0f +479, 0x14bfd2c4cef77b84 +480, 0x9e337eaad201c664 +481, 0x87b8f2c4b3f086e +482, 0x5f70b6cdb796ed2 +483, 0x1982229ded0932a1 +484, 0x466663c9cff20aa3 +485, 0x3272c93bbfd9638b +486, 0xe403c4d56c483b55 +487, 0x93280ac4c48d7eec +488, 0x614d81b45505675 +489, 0xac26c793b1c92d2f +490, 0x98c856891490319b +491, 0xc860935122dddb3c +492, 0x4c8a4de8767c40bd +493, 0x2ff98c8c4470f390 +494, 0x2f1c72a213351fe3 +495, 0xda85b3af5a866362 +496, 0x791b0597c01db174 +497, 0xb57b6f82b8cb8538 +498, 0x66b967b6d6b78e1f +499, 0x10e25dff7fa9eb1 +500, 0xd7221749de25e2c4 +501, 0xe7de3dd12683afbc +502, 0x4fab8db8efc41caf +503, 0x55c69af11e357f2d +504, 0x819ae1c6dc834542 +505, 0x181feb56b1b09fea +506, 0x8c02b115f96e8a13 +507, 0xfcd520bd3bde3795 +508, 0xb8f13e1a17520781 +509, 0xc5077e62eb3455f6 +510, 0xb35be37dfe324f62 +511, 0x215c3528cfabaea2 +512, 0x4e8f73eb0ecfacba +513, 0xb53be656d283bc61 +514, 0xc84605b63da1659d +515, 0xdd14e6951ae728a9 +516, 0x23bf5133fcdb04bb +517, 0x635b0a6bf6d16290 +518, 0x69d3fce4b4da412b +519, 0xa7642708d4edf170 +520, 0xdfd18fcd236b3ada +521, 0xdee7ba05f5412891 +522, 0x4ef5da00ff54f4e0 +523, 0x7996c43afbd32752 +524, 0x9ab61401c8ed09d7 +525, 0x9f0cbb35ba418b5c +526, 0xcd335f0227cbb2e +527, 0xeeb415a10dc69acc +528, 0x8f306fd5fb98c8ce +529, 0x87d290a1e5a13313 +530, 0x73bb14ad65f03b8f +531, 0x1c38b0604e39eae2 +532, 0x6255e18db9d3f32f +533, 0x821de64507a248c4 +534, 0x43aa3f96160e265d +535, 0xb3933c53a37e8d6a +536, 0x40537d6206fce5a4 +537, 0x3d6562e600316952 +538, 0x853babe67dc6d5fc +539, 0xc9ec1b74c77a1be6 +540, 0xb17e8cba32fcb3b0 +541, 0x49acd5802328ad54 +542, 0x4f709402e925e357 +543, 0x17419c407e3c214 +544, 0x5e758c00e4ad3ff +545, 0x7fde5d319d81baeb +546, 0x979a20b570910f27 +547, 0x8f97c3b7bc9e2298 +548, 0x12e2ad36da1cc7f7 +549, 0xa236e7dca97e968f +550, 0x1f04cbca5bc0154 +551, 0x3d6f127682d12600 +552, 0xc804b6f9d73c745f +553, 0x46aa2378c21345cc +554, 0x5c22330d6f5a499b +555, 0xc4afed1b7326be94 +556, 0x1641ecf0c9a05ed2 +557, 0x1f78fcb51185438d +558, 0x4e9d044248ccc312 +559, 0xa2bb59525d96e061 +560, 0xd3b0cbbe755638eb +561, 0x8c8aa4004d6c679 +562, 0x7f8f8bedc781d3c0 +563, 0x80f49ed821a1a95f +564, 0x773058f8744da45 +565, 0x7ad50eacc2795e2 +566, 0xb9e5489a8c83b4f2 +567, 0xc69f139896eebc1f +568, 0x1e43056dd8930ca7 +569, 0x6f301a2edb56134a +570, 0x6c2317117ee73dec +571, 0xb2c8685976f265d9 +572, 0x16b2bde0a97af5a0 +573, 0x742f17525776cf92 +574, 0x1c61c4de2d9a2698 +575, 0x8c9af9dc2211b55d +576, 0xa3cedd5c5841f80a +577, 0xb59a544f559dc6a4 +578, 0xdf8fff92e4ee4db +579, 0x56b7366da8b55759 +580, 0xd8e36fe0d19f75ab +581, 0x23e355b5133d1b2d +582, 0x372dbbfd1a91bfa0 +583, 0xec3a5bfc17d9f90c +584, 0xda6fe7ef39ac4212 +585, 0xba4be9c5525834c1 +586, 0xd7fce5922edc81e2 +587, 0x601ea3b1ef2b295c +588, 0x7019d5f3f8590283 +589, 0xd335a01edc3f7cc5 +590, 0x561e4eec723f9a8f +591, 0x25d5c1063d9ce2f3 +592, 0xd92c0a861004228 +593, 0x4ced9cfa54381973 +594, 0x64575d21559fff7a +595, 0x9b9941185367da2b +596, 0x81bb1186ab30672f +597, 0x3e22dee929fae7cd +598, 0x9316d034a8d5f460 +599, 0x5544fa1e4ccfd6b6 +600, 0xb548fce22e15c29c +601, 0x4a0c0d2156cec5c4 +602, 0xaf626e963a3d720c +603, 0xa18ccb5d828344cd +604, 0xacb3dad256bd3927 +605, 0xd9415709dd1b9838 +606, 0x5c5b91e09865d9f +607, 0x916e81ea4277c555 +608, 0x47fd254a985abcb9 +609, 0xb4bf05873d1de57b +610, 0x78be8dbe976e57be +611, 0xe4497bee300305ad +612, 0xa35bc9c0b8790666 +613, 0x50e32823b12df325 +614, 0x2d2235134b876e43 +615, 0x4d11093673d2f723 +616, 0xba9a6386593bb306 +617, 0xff94de871ecb0f5b +618, 0xfa30dee676c84ad3 +619, 0x3deaa3f79a9c0e3e +620, 0xee5884952aa60b5 +621, 0xc785a19fdff41a34 +622, 0x8b0845fe5f10501 +623, 0xa152b0aa81b88df6 +624, 0xa19f3d7b2118d7e7 +625, 0xd85b2d1b42a29eb9 +626, 0xc9e3567083b1b07 +627, 0x173666e13a07198e +628, 0x5d523316500ff20e +629, 0x911ba2359d617b98 +630, 0x5e2e9d9033cb6c6e +631, 0x28d18aca1d7a2bc7 +632, 0xfd8b5c9ac51081bc +633, 0xae9791fd100e0e0a +634, 0x62bbcfdfac3357cd +635, 0xad0eb70d33a1528c +636, 0x3f6bf8f30c99a45f +637, 0xcef98adf350e59a7 +638, 0x42a3ce1618e864ea +639, 0xe593360a79499134 +640, 0xd2bd28c812adbd7b +641, 0x4ea00dde869a07c8 +642, 0xf0fa202e5de5c677 +643, 0x80e31fa27e0bf3 +644, 0xf6e3947034e63c80 +645, 0xd792c5bd89a9ed4d +646, 0xfab57bccb903c09e +647, 0xff018b3b5e307f5c +648, 0x9bfca67e7f2358d6 +649, 0xdec771cacfb0257e +650, 0xeeefd9fea081fda7 +651, 0x1076a0fbd79b2c07 +652, 0xf44113350dd482e8 +653, 0xf191e0fc45973564 +654, 0xc3e3444776e39e6a +655, 0xfdd317f3d4debba6 +656, 0x54ccec6719532a9b +657, 0x9a6e8ca48d8c1e7d +658, 0xc609af730bb6d832 +659, 0xa8b4c8470d968391 +660, 0x5cf64a7f47b204e6 +661, 0x5e965176dfa25003 +662, 0x66813628e15874bd +663, 0xd35f6b140e1878e0 +664, 0xaac7f75e4539ee5d +665, 0x39be402d139f7abe +666, 0x1cbe6759828a8ccd +667, 0xc670bbac7cb8211 +668, 0xb2c2d0f58e907080 +669, 0x93ef7a9684abfe0 +670, 0xceb30e0e22ed95a0 +671, 0x2c440668139c0076 +672, 0x32e60072a459bcea +673, 0xb0bc43bf10e8f79a +674, 0xa8531d49c980b58d +675, 0x45f37d8f1c93663 +676, 0xc9fd75750fdfe198 +677, 0xc36b9ce50aeeeae0 +678, 0xe8fc776625253cb3 +679, 0x70c77614d74d06bf +680, 0x51c1cad2d2f2badd +681, 0x66a4db21d7db02db +682, 0xfaf1271dee5b290f +683, 0xae86058acd20130f +684, 0x745443d08c22783a +685, 0x223143faa7c25250 +686, 0x5b1cde70be845cb4 +687, 0x4f0df398464d9edd +688, 0x6b20e39a68f7c30e +689, 0xd37f02c77f07e8f0 +690, 0xe1bf957b24c8b2a9 +691, 0x562dc0bf6f77d28c +692, 0x76c9f88dc50f60ae +693, 0x9702059e9c5919c9 +694, 0x281383e10e722801 +695, 0x171f956c8b0712b2 +696, 0x5eaf54175f8edeb +697, 0x7cc99560d2398c4f +698, 0xc4d69f843120e45 +699, 0xc941f10439e94167 +700, 0xb34086ca06e338c6 +701, 0xa01d149b929f36bd +702, 0xbd19942652a4afcf +703, 0x4722d03a7e6970ab +704, 0xc0e805aa2dc36bdd +705, 0x6e68e26fecfeee1c +706, 0x4aba8fbd1caf2a03 +707, 0xdebe09b8084c052d +708, 0xb332c6c54337d33f +709, 0x903cfa39f4899243 +710, 0xe688cd984e93f499 +711, 0x2c6ae72dc00fc910 +712, 0xde0d582c9957f91b +713, 0xebe5afa3d0c3d91b +714, 0x4fc2b36f2a137cc +715, 0xed2107ce829ed259 +716, 0x8ffeb322143a2190 +717, 0x8e53ef386fb835a0 +718, 0xc73496bdb11c7047 +719, 0x6ca8c4835c9c4f8c +720, 0x8ea4f4901f2e0265 +721, 0x644a3a28ff8560df +722, 0x8953e7fdf979ed19 +723, 0x43dc435a24a800a3 +724, 0x2f15b97ed169e6f8 +725, 0x3ce69e60d6bcd79d +726, 0x5a733285b92355f8 +727, 0x31606b5b067028be +728, 0x1b4f051f3664639e +729, 0x859f66e980f2a3a +730, 0x46572b5b026e4d99 +731, 0x3a8c3dbab89136e3 +732, 0x30fcbfb69d4e2045 +733, 0xc2001ffc2ee041da +734, 0xe2e789a7d6b5c353 +735, 0x20a6a29c6bc894a +736, 0xb9c75c4ffd10962 +737, 0x58de12481df29458 +738, 0xc3a269b0fcf75ec2 +739, 0xfaba5acbbc077e5e +740, 0x8c281f561efe477f +741, 0x61d8922c3b1e9f79 +742, 0xc92d49730840a9ba +743, 0x5ad9b3bd172d9804 +744, 0x4da50ea6a7a283b2 +745, 0x5e781612f5f1ca9f +746, 0xb6a3887cbb2c4080 +747, 0x2b2a7dc43c678866 +748, 0x5a556144413f6593 +749, 0x286ee3aa8819f92c +750, 0x45c169e82a919218 +751, 0x913f34ea9bf5d6e7 +752, 0x48d84f1aef099220 +753, 0x843e00085d83b19b +754, 0xe639c98005983b17 +755, 0x223f1d8680cfe4ed +756, 0x6b589d901b8e5ddb +757, 0xce43033319d740cd +758, 0xb400d5b22521cbd3 +759, 0x6b89f6ac56a9f684 +760, 0x21dc6e3bd591ee5 +761, 0xe062d33650fe9bac +762, 0x7d843bb328d65a27 +763, 0xc4ba63ee38e9d608 +764, 0xdefe72f65f0185dd +765, 0xfbcd7e2ef2ea79f9 +766, 0x514e2e715ce8f7d2 +767, 0x21af168dda65563 +768, 0xf0952635f1b9b8b6 +769, 0xcd098331c00eb2dc +770, 0x88d48ac80843c49a +771, 0x3fcef1cdf0cc92a +772, 0xea558fc018ffc6d4 +773, 0x53fe63708554d32b +774, 0x82a976d57ad79413 +775, 0x5671621e1cfcc958 +776, 0x9057b32b84fd54eb +777, 0xecf93fd1f073494 +778, 0x95e3be825c83bbea +779, 0x31f711958b37fcb3 +780, 0x7764e9c1b68905d5 +781, 0x19ff29bbe3450d1 +782, 0xbe9d66d0b7a63370 +783, 0xb90d94f54339e1c7 +784, 0xb86e7e4f983f5058 +785, 0xbb37df7a822c631d +786, 0x34d71226eddefe66 +787, 0x647b6f2dd0167b3d +788, 0x2964bea0cb5814b8 +789, 0x5111f6bf0575d9b0 +790, 0x598e941686def9ad +791, 0x541a6d6e840b4142 +792, 0x6a9ec878a98f32cf +793, 0x28e7a3598a6cbe38 +794, 0x22b0e914e1d9aad0 +795, 0x6e4f306af93619a8 +796, 0x62ad701e6072aafc +797, 0x20f304620a3e4459 +798, 0xd7217bc244bb9cc1 +799, 0xeb66fa201326ce9d +800, 0x60a8de18a022c5e2 +801, 0x31a14a91815a918b +802, 0xd90de92cb757c772 +803, 0x738a110b95e161f8 +804, 0x2ef5cf2da3e98788 +805, 0x76b0bb8ff3123517 +806, 0x4bef942413b602e9 +807, 0x1c90bd1e24c93bd9 +808, 0x20eba165958bac22 +809, 0xcd5639b3751988cf +810, 0x6fc8cc48b1dd184a +811, 0xfdf2eab5e428ac3 +812, 0x621d191371614b86 +813, 0x3977622fee6de38e +814, 0x501165fbcfb2a7bf +815, 0x3d117c309c6a11a2 +816, 0xf1f6a98f2d352d28 +817, 0xf7b0984596865aca +818, 0xb9eb071ad42bb21d +819, 0x19c555aeeaf0cf28 +820, 0x425c90febfcc526c +821, 0x8133e767f229ca4c +822, 0x50534af80dc7d238 +823, 0x4267194590c15804 +824, 0x5afc2d9d7a0692ea +825, 0x66feaa4a0443081 +826, 0x10f74efe039c5534 +827, 0xd79bc6e3e26cb0e +828, 0xfd511b94e4229f4d +829, 0x4b3735fb47ceecb5 +830, 0x7f3da62bb14a61d5 +831, 0xd92a4f2f534a654e +832, 0xb906bf6a9989e53b +833, 0x13018c2b34f999fa +834, 0x6590385a18c6a603 +835, 0x8fc8db59a2567498 +836, 0x3cc13cfa2306cc4f +837, 0xdd79e765006a327e +838, 0xcb3dbb849468b870 +839, 0x9932fe5f00ea0e19 +840, 0xdb36176dc85cc926 +841, 0xff36a852d77a76a2 +842, 0x7228cc6dc7a583dc +843, 0x3239f99e8c1e75bb +844, 0xcaebcc7ada26fb97 +845, 0x58695e996613ec7a +846, 0x2167b9da13f07e09 +847, 0xbe7bab67bb8bf660 +848, 0x22d605faa70bd9b +849, 0x4126e31a67fa20e4 +850, 0x9f5e1b0c6ce38bdc +851, 0xafdff88a50a87b2 +852, 0xcf22aadf30733a23 +853, 0x1fd9969ff955272d +854, 0x8f7488ef919369da +855, 0x9fc58576f9366b +856, 0xcd113f7c06d404ee +857, 0xf0c3dfbb77faa02 +858, 0xfa6b4df32e5b13cf +859, 0xfcdfd2ef4ed2901b +860, 0x2dc695fbefb81029 +861, 0x66cfcef096b1aa07 +862, 0xce6c9411a0a43c1e +863, 0x7ce97001b7b94086 +864, 0xa9e80966efa21989 +865, 0x9db01384e57130f2 +866, 0xb4c4481e7ea597ca +867, 0x1fc20274d0a21c7a +868, 0x4e23bbbeb9f83211 +869, 0xd8cad36baeec8333 +870, 0x8742502cb17ca60f +871, 0xd79d2dc157d5afd4 +872, 0xea1b2c00ffcf7ca0 +873, 0x1aa557af2fd43a1d +874, 0xe73708cc03d175ca +875, 0x6229a5af98522983 +876, 0xfa42c93d6b4f22f +877, 0x1e65a381061656e2 +878, 0x8933f33ef286b6b5 +879, 0x17c422cf0aff3638 +880, 0x66c1c8e8488bdded +881, 0x2d3c290f57f89df1 +882, 0x7be0a80f249572f1 +883, 0xe04b4abafd35f742 +884, 0xe7ae3420d1ae8262 +885, 0x7ac0a00e9418b10a +886, 0x2c459481c2268d1d +887, 0x4d83267be8955a75 +888, 0xdeac45087ce7e783 +889, 0x6ba80c634128a42c +890, 0xaccf8778cb440125 +891, 0xee610bb6dbe2316d +892, 0x4354e249ac02fd00 +893, 0x9d2fa76bc69ed31a +894, 0x3e6119655e632f1 +895, 0x94b9895001a11b04 +896, 0x2e24e88414b70981 +897, 0x68ada416de03c378 +898, 0xaa35f41451efd2cf +899, 0x28eb447c4d24bfe8 +900, 0xa5137e57245e7f9e +901, 0xc9b19572f5c16c79 +902, 0xc940ce6692436e95 +903, 0x67411f98ce32ad1 +904, 0x1d40e58013165af0 +905, 0x3cec810dd5b24273 +906, 0xa7c6bc87d530d864 +907, 0xfc43ba7ae1a3fe7a +908, 0x9d8794810bf47814 +909, 0xec8cddf1e0f9e93d +910, 0xa564bd558f2d6414 +911, 0xc5106bef612f55a2 +912, 0x7be0dce9a92ba80 +913, 0x2eb62f6a3f2074de +914, 0xc36ee0b068558f0d +915, 0xf5684163785c9867 +916, 0x338887da708650da +917, 0xbb716f53f9844869 +918, 0xdcfc496eecdda21 +919, 0xdf53415424439f94 +920, 0x3a05abd08e2d9ee4 +921, 0x18a6480a9399523f +922, 0x9cc0dab9dc1983b0 +923, 0xb375dcd416372e71 +924, 0xbd8d75af2b5984a3 +925, 0xe86d2b59f0e26c0e +926, 0xcb6b2f761c2c8fb6 +927, 0x2549bff97b63663c +928, 0xfd29bc4f73ab6a9a +929, 0xf690ba893bafe3c7 +930, 0x94c30c32da8d8ca2 +931, 0x44899149ffb1c95e +932, 0xc23549c093cdf753 +933, 0xe2029fe9cc90d5 +934, 0xb2c70637a91ce191 +935, 0xbcc0420e35bf6942 +936, 0xe108b087861a186e +937, 0x54a69c4b23f5f6b9 +938, 0x4ac1a35efeb13e67 +939, 0x39982383bf0173a1 +940, 0x9eb169c7613a5e48 +941, 0x848940fd0d654ff2 +942, 0xdb663c2c2718be99 +943, 0xe4b7a6ef4ca1cdf6 +944, 0xa560cffd62c75504 +945, 0x26ddb1df4420b2d0 +946, 0x980b3101000e3e29 +947, 0x2dd1445c80dbb8bf +948, 0x135c42daf949295b +949, 0xd19f5c74b895dae2 +950, 0xb690a628b77a9293 +951, 0xfe04f5a5928ab34d +952, 0x2df10dc128a516f0 +953, 0x89f79ab12e337c3b +954, 0xb98c589f33c1748b +955, 0x30df1793cd9f6b01 +956, 0x6538ad32fa56a9da +957, 0x93453d17e6ea27b +958, 0xe2a92ebb82c104ca +959, 0x2ce2b05ef3bc1404 +960, 0x1a327d3cdc07ed1f +961, 0xa7c4bed4e2c10779 +962, 0xfe9c13e0e6912c65 +963, 0x15ea29dc894638 +964, 0x887160de1f9f0149 +965, 0x13a80eb973cf8899 +966, 0xef27446cc86e47a6 +967, 0x8890e569d70fc03e +968, 0x1d0136f928ea9c40 +969, 0x99cb2f3b50431cbd +970, 0xbba687f34ac3061e +971, 0x23a9b639b2bb1a83 +972, 0xa93c79780f08e4da +973, 0x1b9f12f0c9997121 +974, 0x512ab00fd2ed5bb8 +975, 0x928815bf7a2288ad +976, 0xfb76b86de4b7f17a +977, 0x38513665d5c85718 +978, 0xa7af48360b80b6e1 +979, 0xc08b51b293e84a8 +980, 0x7f044ecd175afdf4 +981, 0x73e18a7f5c3efa06 +982, 0xf6ef1911e91f0c87 +983, 0xe09e6a85a182b1d1 +984, 0xeca0e6fcfa3d7c66 +985, 0x2466210516727cc0 +986, 0xb8cc106a4bffefda +987, 0x41ad3e2899041e58 +988, 0x4b5ba3abf6a9fec3 +989, 0x436fd42b29a1e822 +990, 0x9d9f29ada8a6b310 +991, 0xf9f066631426bda4 +992, 0x36660b826a0a1b8d +993, 0x26aee243162a41ea +994, 0x8c38cbfbf0d4b792 +995, 0xcda46557b68f0ae6 +996, 0x5900339a5e9132c1 +997, 0x6de1710051cdc7e8 +998, 0xb76aaba70884f776 +999, 0x297c27d0daac3c3c diff --git a/_randomgen/core_prng/tests/data/philox-testset-2.csv b/_randomgen/core_prng/tests/data/philox-testset-2.csv new file mode 100644 index 000000000000..1c2d4eba06ba --- /dev/null +++ b/_randomgen/core_prng/tests/data/philox-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 0x0 +0, 0x79969cc23abb91b4 +1, 0x5d45aaf4ec59c2d0 +2, 0x694e6df1b3048ed4 +3, 0x29caa3dbe7b3fad3 +4, 0x40de4437fb7c6391 +5, 0xced65c8c17cbd934 +6, 0x3a34149842e4c076 +7, 0x4bd68ff0459067c7 +8, 0x22a1cd386c044cb +9, 0x707d516e7b2321bb +10, 0xd31e9fbe226156b3 +11, 0x1e7c92b4a1111385 +12, 0x40b26d1e3ad54f68 +13, 0x2b512df2e2c7b340 +14, 0xbc566a77564902eb +15, 0x38019add5d6c49f2 +16, 0xabc12bede6d19b9f +17, 0x8ffda997c28b3314 +18, 0x7758a16e37aa29dd +19, 0xc75be56d772bbd45 +20, 0x7dd842b9b7ef652f +21, 0x874bb05dffe32330 +22, 0x6215b5d304389ab0 +23, 0x67b7659e0f6f074d +24, 0x3dee6f7f663aa80e +25, 0x35f1ebc3a43422e2 +26, 0x91ca84accba13894 +27, 0x19a82e52cf0a5aa5 +28, 0x99193ec846ff4752 +29, 0xaa85d8c7b98454eb +30, 0xdc9fd9a6cf639903 +31, 0x6a7f3a04051963e4 +32, 0xe6315de20fb99cc5 +33, 0xc6e64d30591ea5e4 +34, 0x2c3a032c8af3ea95 +35, 0x4a6ac2609731f163 +36, 0xd0075b64c816b32f +37, 0x6ba834fc94d46b11 +38, 0xce81c72980d4c0d5 +39, 0xe4527c390cd95d99 +40, 0x281a4f40fbef803a +41, 0x8b96b67ef65af945 +42, 0xd8228d14e17d995c +43, 0x822e355afd5a0708 +44, 0x76875e970f78780 +45, 0x1dd4625c16f578fa +46, 0xed94ce7d1cf6affd +47, 0xfd92c8d7728d9656 +48, 0x31da5185dee2c21f +49, 0x8cb0591af5c81267 +50, 0xfca589420074336f +51, 0x8521d19430fae019 +52, 0x20273ae3419daf9 +53, 0x27ee172bbae69340 +54, 0x98fce350defda2d6 +55, 0xbf8b350e4cc6c7ff +56, 0x30718006f3e0170b +57, 0xe06ba2542d7acd63 +58, 0xdd2af87a79df1722 +59, 0xd7fdadbfc51ac4fe +60, 0xbf5cac7b6b07e5cd +61, 0xead793949b8ed548 +62, 0x1840f7d95c0fcaa9 +63, 0x9abd3340d80c15af +64, 0xa287da079eb9a1d8 +65, 0x1f0f530858927e87 +66, 0x56abe10813899150 +67, 0xbe0182c8f2ab4575 +68, 0xf9e318a24d72471a +69, 0xca9fa810134e0866 +70, 0xd6f89ce5a65a0791 +71, 0x120528d7fc273c9f +72, 0xef0c8cfe4b167be9 +73, 0xef5d36463f4d8c7f +74, 0xa017cd944ee9c3d7 +75, 0x6c38f735847f9c65 +76, 0xafb6a0a5ced5e991 +77, 0x6d474406bcbfab26 +78, 0xa90b7997de0d58f3 +79, 0x1fed779ebc5d221a +80, 0x77a5fb8e08e9ae6d +81, 0x70150de0fda752f7 +82, 0x55a942db08ffdd56 +83, 0x6a79d3640b2e7d68 +84, 0xf74772c9926374c1 +85, 0x8f37888d12b4d52f +86, 0xe331da4eb3ede8d6 +87, 0x9a248bc67dbf1b35 +88, 0x35fb9ec1b8f35151 +89, 0xd55260d8fa30259c +90, 0xf2dc194b962d0dc3 +91, 0x7421accacb7612e4 +92, 0x84188c4b9af469a1 +93, 0x7dbf34d5fcc07b5b +94, 0x6814325ad6bd0142 +95, 0xe81c0fb52c978dc0 +96, 0x7383aeadf20cdad7 +97, 0xdf578a6544720b72 +98, 0x2bf78fa3ee23ee5d +99, 0x86de4a9a5d5b30ec +100, 0x5399499273ab2312 +101, 0xb7e56b49c81098ad +102, 0x545c46236115c503 +103, 0xbb1ebf762b9f6d50 +104, 0xfdf2aa180180f729 +105, 0x53cc5b07cfcbfe8c +106, 0xb83e28400cedb4e +107, 0x9c31e53a2e1d5692 +108, 0x3f0826e1d4354c85 +109, 0xf4fcfe401a637569 +110, 0x1efcd12f58dcbf87 +111, 0xa444a0c48c35221d +112, 0x72d1c01d6b6bd176 +113, 0xed0d5d536d32ac13 +114, 0xe954ce02b26a6059 +115, 0xde62023001249b9c +116, 0x841f789718400085 +117, 0xeec06a70d8c0621f +118, 0xd291a59fc833590b +119, 0xc6376fd2243fb8b +120, 0x28a87d88893881ce +121, 0x98d049b96c67da8a +122, 0x1aa980a3f10e9bbf +123, 0xe659d1a052cfa2f7 +124, 0xda413dc6222914da +125, 0x661e049b99b2056e +126, 0xe288cd7c76014e5e +127, 0x865d98946f3ca341 +128, 0xfd4a9504dc3c9481 +129, 0x68821b878bea1073 +130, 0x98a9ae702cca6f4d +131, 0xb02c218bd6ecf7be +132, 0xad9f2cc45e9f71b8 +133, 0x1a73edfde94ac922 +134, 0xad6e36771e49599b +135, 0x33132de3eae3b26b +136, 0xe38bf29f74c219c8 +137, 0x9a7d1bd6d6954dc +138, 0xfa0504aa41d2da3 +139, 0x18c2c0a825aa8c77 +140, 0x4575d335c5a52fee +141, 0xf8e12f4237ad2574 +142, 0x4da2b3d1a4b207a5 +143, 0xd483ee8735b0cd0e +144, 0x9b92d7e5650dce24 +145, 0x2e85af91423bab47 +146, 0xec285fc870875add +147, 0xc049f35180d0b26 +148, 0xbf9d3486b1510d3e +149, 0x6136b10aa8cd75a +150, 0xf4a468c92c6b01c7 +151, 0xe6d7ac00bee004aa +152, 0x5a060bd23d3d6a16 +153, 0xaf68b049fb08130 +154, 0x188cde6b2e6d18fb +155, 0x913aa1123363a9d +156, 0xb35a584b6899fbb +157, 0x1a0b2cfcc7002419 +158, 0x51a6f914a1436297 +159, 0xae5af7e12493c9fa +160, 0xd5a4a33453104298 +161, 0xd46c795e6ced12dd +162, 0x24578f112e9896e5 +163, 0x3879bc9d1d1c79df +164, 0x38d21818a9044427 +165, 0x1489a65967bbd74c +166, 0xf004d910e27d5453 +167, 0xacae738e2b4a1b7c +168, 0xee8dfe42955be33 +169, 0xd9d5d1ecb7524335 +170, 0xaceab4d48e8eb2a0 +171, 0x7747bb87ea6f47e5 +172, 0xfd1b1bab29e1a5b1 +173, 0x2f4b6b0f9300b44 +174, 0xdab086094510e334 +175, 0xa571c54824e95668 +176, 0xfc5108b22f0c15e +177, 0x9989597611a00527 +178, 0x6ef24f0f951b29c8 +179, 0x5824eef87de85c1a +180, 0x78a35def7f709c63 +181, 0xfdfac9f100645cef +182, 0x1f0027accbd50b57 +183, 0xf4379eb0e470a43 +184, 0xe108523693012b4d +185, 0x1dbcaa15e104e367 +186, 0x91a01715bfa8f4a2 +187, 0x90b12f2dc6612875 +188, 0x3a0c81439df90067 +189, 0x92bcce47af32a0cb +190, 0xf1f8ec01579f0749 +191, 0x656fe00e45f73d01 +192, 0x66b3ce57b8a63a03 +193, 0x7f711c6efceb22f6 +194, 0xcf6c2d639062aea0 +195, 0xddc95dcbe9455707 +196, 0xe24dbe6495077239 +197, 0x7d02e17fba62ea00 +198, 0x84d60e07638b79c5 +199, 0x767bd78a1e45e41f +200, 0xfe3fe1d74008b0c6 +201, 0x4b98deab82ab23a9 +202, 0xdb104f1846592508 +203, 0x23086e881366ad53 +204, 0x64c16b00fbf72cd6 +205, 0xb19eb55587ad61e3 +206, 0xfdb8caa9ab6dfe07 +207, 0x125b0675253c081b +208, 0xbd8ca76e7797a1d5 +209, 0x6fa2177be1444f15 +210, 0x23c4388e40529ab0 +211, 0xf3ad977faf5aee04 +212, 0xb1ca87d8c64c3bf2 +213, 0xa68ee8636f7a4f7 +214, 0xa40199a2bec23e46 +215, 0x5fcae2801e7e0b4e +216, 0x2e1260c7c7afef8a +217, 0xaeb347f6912b9cf3 +218, 0x2702e2510b9b4e4e +219, 0xd281ab9c087c1401 +220, 0x7d73d1c89ec1ecc3 +221, 0xfaf594c2b9bd6355 +222, 0x78641e1415fadd6f +223, 0x6bcbc45443f34f98 +224, 0xc5ea1bbd7ad47fc1 +225, 0x21a6bde64e7934f0 +226, 0xe48d5c1eac30eae +227, 0x7645dd59feeee713 +228, 0x236dc6e399a0f8b +229, 0x7d47bb3105e270d0 +230, 0x5c30af0f8e670624 +231, 0xd77864a3d3eedbaf +232, 0xa8ce734357f09a67 +233, 0xa5848bf5de97769a +234, 0x197e3bd0511be793 +235, 0xf1797421fced9f11 +236, 0xab395568cdb296d5 +237, 0x2c163053937c4e5c +238, 0x88aab0204548c66c +239, 0x59e43e9ee50ccf47 +240, 0x5646ec79dc2b8717 +241, 0xdd21d5fe2594e739 +242, 0xe3b36b715e030f2c +243, 0x72b9c7dc781ee215 +244, 0x3928edaa51d23161 +245, 0x18072b29ad229306 +246, 0x5a6e1a7146df0219 +247, 0x44fa2420a3a521e5 +248, 0x26c8c4d7e48e49c7 +249, 0x19829824d9ab3d0f +250, 0x208e2308990de3ca +251, 0x644d4c7725308bb +252, 0xbcd356813965c89e +253, 0x7cc4a5d0629a09c6 +254, 0x78ecec3f9f660e71 +255, 0x4c5017c2cc05d260 +256, 0x1a630b52a53d5d4c +257, 0xaad6058d6091bddb +258, 0x42310f01d0dec7ba +259, 0x352501f1bf98692c +260, 0x5b32220790b2eef9 +261, 0x9cec92f85a3ad24a +262, 0x392bed113812b6a7 +263, 0x2c4a91bc9a27b61d +264, 0xa3ddb8a73a00331 +265, 0x71564f4cc1ff38b6 +266, 0x3bf1cdb52f7d6121 +267, 0x317f2427d4ece2ff +268, 0x61b510f62d30c1d1 +269, 0xf3118eb3bc72b4db +270, 0x6cf9e03844d59394 +271, 0x9a48891e9593372c +272, 0xe6f07884178198e2 +273, 0xdb8d7ffb3f7b48e7 +274, 0xd843287403436ab2 +275, 0x281067329d659944 +276, 0xa9be89389e933e98 +277, 0xa559f1b2c64d698b +278, 0x177c147eecc213a0 +279, 0xb60d1b8907f932b6 +280, 0xbf3dfd3933f22dde +281, 0xc97688e8fc9e974a +282, 0xf10b069f84d5a0bb +283, 0x30aef0a063e9948e +284, 0x149d4526e4606eef +285, 0x3d47374e3f68d21d +286, 0xa8ec81fb5259d900 +287, 0xa8a2f4cdf3ea7a0 +288, 0x15bcdb63f1092d6b +289, 0xec827b483fa8d1f0 +290, 0x31fa9b0586f00970 +291, 0xdbe7d320cf2931a3 +292, 0x1b11cccdc34368d1 +293, 0x1fe27662861788f4 +294, 0xf709d76eb49bd879 +295, 0x2450c5dc16476c8 +296, 0x7a0a7d863198b16d +297, 0x5d1f6c9563f68aa5 +298, 0x36c7d7757e74eb02 +299, 0xc0656a90d456269c +300, 0xeff66ab0f6d035d0 +301, 0x27afcd4b473c8f6e +302, 0xadfc46fa3ee6ce03 +303, 0xd8096465daf41c99 +304, 0x602ddafb5eaa9460 +305, 0xd731e659599d021d +306, 0x33c3a32355ab4e63 +307, 0x974e3554d7bcc0c3 +308, 0x249dceb9428a7bd4 +309, 0x378eb9b47abb256f +310, 0xedbce8679ab00480 +311, 0xd1746d7de7777fdb +312, 0x14a30aa451c0f7b7 +313, 0x1d28baed82fd8b04 +314, 0x714174c401e78e26 +315, 0xf1788905ecb84469 +316, 0x22eff71d89f9be8c +317, 0x6b2819eb724b4e74 +318, 0x1636191b8000b39e +319, 0x73ea3d60587f3cfe +320, 0xe7ed97702c468226 +321, 0xe10824982050c4f2 +322, 0xfc2749ffbc81d160 +323, 0x5cdf3c2d78f56706 +324, 0xc01c94db79631370 +325, 0xc5f5776c2840747a +326, 0xada78ed21449a7f9 +327, 0xe987713c3d87e4f2 +328, 0x7b8e12fcf69b7ab +329, 0xd596a488c255523e +330, 0x9e9b813baca7c51e +331, 0xa624b911e58175a2 +332, 0x3c832b46e35fa5c7 +333, 0x515825156be5fb3b +334, 0xe91c83a0fc6c7f4d +335, 0x907e8ed6e7d67004 +336, 0x7de3df361f634d83 +337, 0x1ccf96f2394200c2 +338, 0x845175395e3598e1 +339, 0x4905098c8b06775a +340, 0x4424d6e6a10c0c02 +341, 0x820010ef3887713f +342, 0x2d918fc9225aaa82 +343, 0x32eba0dd41ce9092 +344, 0x1b66fe6dbc525c20 +345, 0x394b67ad8a323e4a +346, 0x5e696185a5c86bd9 +347, 0x69b12c2752514602 +348, 0x1ff9214a510255cb +349, 0x2bc5a0ca899aad12 +350, 0xb57d6e14b16a7718 +351, 0x79beb7612a6fd6e7 +352, 0xbc79c45b1f8e7f8d +353, 0x44d32a278b964fcd +354, 0x2e483a22ca7de50b +355, 0xf5ceabc566b350f1 +356, 0x7b582ffc4b9d5e43 +357, 0x42ab9492574ac3ab +358, 0x3a8a1fec1ab3e71d +359, 0x75478c52e0efb094 +360, 0xaf1377c197c720e7 +361, 0xd1be85afc6bd298e +362, 0x9a4e6e8660a4d81 +363, 0x1a4bb91a268e65be +364, 0x3a10b0755792f8dd +365, 0xe95153d3eec0c19d +366, 0xf3036b6f8e02be83 +367, 0xdffc9d3fdc293619 +368, 0xfad8ee79745a8a9a +369, 0xa9a8062d64f3dc61 +370, 0x7ddb3f6012d81dd8 +371, 0x623856260cae9962 +372, 0x35d0e6eb91622fa5 +373, 0xe3fcfa2208a3b5a8 +374, 0xcc8ec36185748ebf +375, 0x762cd35896ae6777 +376, 0x5e529053ce500de2 +377, 0x6545fcfc0da9a2c +378, 0x8cb156892a6669be +379, 0x96f80d4770f396a7 +380, 0xbd99a1ca2c8d3e41 +381, 0xd6297cf0b8e5eb63 +382, 0xb522d18d7b34c41e +383, 0x4c76d7b243817c1 +384, 0x733337cba2e74d55 +385, 0x769ee9acdce2279a +386, 0x158fe92000a829d6 +387, 0x2de70d67481a26ee +388, 0x481a32f89f48bbf +389, 0x7910c1fd5b66cbcb +390, 0x40e915445d6794ba +391, 0x694dd31fc3616af4 +392, 0xf66a0f17f6ca78a +393, 0xd09055d52155dd27 +394, 0xd0e4a5654cb1f0d3 +395, 0x27a33f6e7976580 +396, 0x2bc002e93ea14a88 +397, 0x8163bbc9277dfc50 +398, 0xd74612f9829a45e4 +399, 0x492779facb39266a +400, 0x2b4a269c9d211e86 +401, 0xdc88f4805b8abb5c +402, 0xdb8cb18b5beef640 +403, 0x14effaf6271aeae5 +404, 0x133fdf95232daaf4 +405, 0x9811dd5ee80ef423 +406, 0xe80815ce0f365122 +407, 0xe5a983ff40008d1 +408, 0xc22f3249a950a7a3 +409, 0x2d6a29c7daeebc71 +410, 0x7271a3a40d1734d5 +411, 0xb5efee15c4c99160 +412, 0x7d7c2efe86ddaf7c +413, 0x928ad499a4d85e9e +414, 0xddcef9fd941e988a +415, 0xb57daba38cc70276 +416, 0x164b60673494c318 +417, 0x2af60e897eae1cb3 +418, 0x74181074bff82452 +419, 0xe7afe1452aca2b1e +420, 0xbcee4075ee5e82f9 +421, 0xdeb277d596122a61 +422, 0xad4ec522ed5fcbca +423, 0x7ae8d97528caa837 +424, 0x96f5bcd5902002ba +425, 0x77127d87f69da6f3 +426, 0x5ebf71761fcb9e16 +427, 0x79c817f24b4acca9 +428, 0x21ad1662937a31a5 +429, 0x69e3ea5a65934f93 +430, 0x1b96b0d05b7f12f9 +431, 0xf1a68375ae6e350 +432, 0xbce495ba788c1f93 +433, 0x35281fc46a1ed6e4 +434, 0x38db141e96c2fb20 +435, 0x55d11f14ea71953f +436, 0x2c00398cffff67e8 +437, 0xb16dabaa263e92a2 +438, 0x9f21e025912c81a7 +439, 0x67865a4fd348f4e3 +440, 0x8b37f5aa1d953557 +441, 0xf972409a9231da99 +442, 0xdceb2001f7ae4f3 +443, 0x8f840ed0e94b642 +444, 0x7fb486ac9cf23354 +445, 0xbf0731eb9fb2f26f +446, 0x64f6a87eb3ad3997 +447, 0x2efaf458ab38b3af +448, 0xb0a84922ae63a985 +449, 0xa6e4ad47f5a8bed +450, 0x78ea04257180c6ea +451, 0xdab32fcc7935f61f +452, 0x81c51b7fc2702c1c +453, 0x63fb80362df72986 +454, 0xb672007383cbe435 +455, 0x3c2795c9fd489191 +456, 0x382fba5fdbbd0d1d +457, 0x5b7c398dd14c7819 +458, 0x62f0b67bf107ac7d +459, 0xe064c5f9f54201e9 +460, 0x176eba949b66b75c +461, 0x82678f7ce2748a4f +462, 0x43ea9b0b4852476e +463, 0xa7f9cf3569313631 +464, 0xc0833878700008d7 +465, 0x140e34c3d600d7f8 +466, 0xe0bfa1eba68fec03 +467, 0x4e3ae5e387d3f283 +468, 0xb799c08bac503857 +469, 0x217b43c04870ab8e +470, 0xe5e845d2fd3bcfc5 +471, 0xb335c469515e740e +472, 0xc2e3c4de7a47050c +473, 0x817b2e6751cfc87b +474, 0x59eb6cd8266ed00f +475, 0x61719b760716f1af +476, 0xc632bab8a5379b7d +477, 0x3fd80526456a4087 +478, 0xce5ef34e009a09a4 +479, 0x4da72557a2c81e6d +480, 0x45035c138cf0a07f +481, 0x2e0e2c65cf2fd15a +482, 0x5526e0f129feb1bc +483, 0xf970fd5e145bb284 +484, 0x4ca7ada616378b04 +485, 0xa8f8ccaf6fe721f3 +486, 0x1b69aca028dec51a +487, 0xc646b9db8f01cde6 +488, 0x77d8bc4b328434e9 +489, 0x5b8c1bd76c5d361 +490, 0x998199eb58998641 +491, 0xacae79454a30f83a +492, 0xd1456bd45a42152c +493, 0x1a7aee80e3e170f +494, 0x5d611e45c9446edf +495, 0x8c681b0c3daa09bf +496, 0x91affbbcf9c1e020 +497, 0x7fa4f3756b231b2a +498, 0xd2c13c5a29826810 +499, 0x993830f7fa0d51ae +500, 0x80636484c971d447 +501, 0xbe32c99bfecf878c +502, 0xf1880b2dc3e4f7e1 +503, 0x4b8fa1cc8fe57b65 +504, 0xdebafe0f90ad1b5a +505, 0x1d11dd9200f8b4b8 +506, 0x75042aaa397d9a99 +507, 0xc9ee367b527e2a09 +508, 0xdecdd82920560b63 +509, 0x64dfc74fd7f2bfe +510, 0x6ab0b966bc6fcb9b +511, 0xeb0199bf8f8a3816 +512, 0x7d603f5a0fdf7616 +513, 0xbf0177f27b06e799 +514, 0x83a5a1dd75b536c0 +515, 0xf898601d81b9d989 +516, 0x264944efd59443dd +517, 0x8e93bfdffb880aba +518, 0x697561a56735dd59 +519, 0x4377f57af134b8cd +520, 0xb84884431d02a53d +521, 0xfcf3b5efbdf216c8 +522, 0xbca95d7a8ad81290 +523, 0x3320c204d5e92a49 +524, 0x5e19b0ec2072b07e +525, 0x3ac2c56483ec19fd +526, 0xbccad8ee0f613b5d +527, 0xd351c964ab750837 +528, 0x4b46de746194625a +529, 0xbcc0a7cbaca03293 +530, 0xe35955fded6f2276 +531, 0x21aef4fb23229559 +532, 0x38c67966f1aa2296 +533, 0x2313034e68aad3a6 +534, 0xe79c154be56b5576 +535, 0xe8313f229a85e811 +536, 0x32ce60d1f50fd321 +537, 0x47713272c46d00b +538, 0x16c9165c6f10d24a +539, 0x30e39109e3275951 +540, 0x885b243b1a057c75 +541, 0xea6743a2c6a384af +542, 0x4a7270162f8329c8 +543, 0x6ecbc6ad90ade794 +544, 0x8f5e8dd3a37e94e0 +545, 0x91d2ad50e044c382 +546, 0x8b6bb0b7f6ac61db +547, 0x324b36acdaab4457 +548, 0x59ed97721860509d +549, 0xc45924166bfb2ea2 +550, 0x7cbb46bd01b1ca53 +551, 0xa41d17a5456d70f7 +552, 0x22d26eb275d0440f +553, 0x74bc05ce1bb10c2e +554, 0xd4ed1084eb81c707 +555, 0x75e936d690b1c4e9 +556, 0x94dca2299e381e0f +557, 0x7f7ae722fe2f3642 +558, 0xa72d301ef5d62837 +559, 0x1bc5cde83663d558 +560, 0x36d21d07bf182d05 +561, 0x37bf7daa7282720b +562, 0xa8f37c56dac3d1fe +563, 0x8a973e5fdca1418a +564, 0x3e4fa296626fc6eb +565, 0xb00b0d0baa75d0a8 +566, 0x2bbf9c70cdf0f0b2 +567, 0x41a8ca894eb8dae5 +568, 0xfaf4d210bddc32d9 +569, 0x1e317a055a699e1f +570, 0xc01d715dc83689b7 +571, 0x32008479d35b9d3f +572, 0x16bfea67573f8517 +573, 0xdd1418e1ca46d5a5 +574, 0xb3f330c663a20f9a +575, 0x5bd1c898e9611e78 +576, 0xf6df66445155ec97 +577, 0xc905ee3a15b83c9d +578, 0x50797ef789745157 +579, 0x1330d937a4856523 +580, 0x1001c0e08524c59d +581, 0x95b258cac211f178 +582, 0x2e61f6778ba53029 +583, 0x7e35c5afb3b67215 +584, 0x4a966942b4ce407e +585, 0x63c0fa981400623d +586, 0x2788e6c96c1826bb +587, 0x1d58691c7e579526 +588, 0x554a15ef02ac25be +589, 0x310310aa113cd278 +590, 0x932347c64ef37cfd +591, 0x3480e6062a9de198 +592, 0x3df126e84fed6094 +593, 0xeb1b2d9f2f7faab4 +594, 0x79305ff41717170e +595, 0xd16dd9d121ed79a6 +596, 0x380bf103a818f05c +597, 0x6d4ead6c20945455 +598, 0x358c06a132638a3c +599, 0x8a31c49306807c4f +600, 0x8348dcc031129070 +601, 0xadf66bfd4278f38a +602, 0xcd95d2350db96365 +603, 0x81d71916ebbefa43 +604, 0x1a0623944ba56e2c +605, 0xd1bcefa9d4e7bfd3 +606, 0xdbdefc03acdec398 +607, 0xfde9fa4617ef7ddd +608, 0xfb1e9e696648bb26 +609, 0xbf88b7580d5927e9 +610, 0x4da178dcc3a89aea +611, 0x94db8b1d876087e4 +612, 0xecfcf60f47c79854 +613, 0x9ef7d0d251da35a7 +614, 0x453f774fa09a8d10 +615, 0x8c31c57925b239fd +616, 0x8e580a43a3bff5ff +617, 0x9af792c383b7395d +618, 0x9df36c3bbcd3bf55 +619, 0x93579179eb304881 +620, 0x2502bfcd7d85a7fc +621, 0x7145b93f7f91133c +622, 0x24d943ff68afb6a2 +623, 0x7ed7322e9d26161e +624, 0x98d58e67dc211d3f +625, 0x606e6eda3d49e928 +626, 0x91ff5582f2e126bc +627, 0x32c18cbe9f068fa1 +628, 0x158fb0b7b1cbb0f +629, 0xb8efba4e9e18aa84 +630, 0x73042bf5836dae0e +631, 0xb08db72716e1547a +632, 0xa77c6291e0bc43cf +633, 0xc32a216129c65832 +634, 0x9ba8c3a6e28320c3 +635, 0x68a860b0460f4d7a +636, 0xb2d6acaad96ad2b8 +637, 0x7e99ec06a1b12969 +638, 0x4e73072434778be5 +639, 0x45c738380472436f +640, 0xacc1dc0cb1671a1d +641, 0xe2b3a601c8028dd2 +642, 0x4f9011640c0cb086 +643, 0xc6424d085d77f7d8 +644, 0x4be1e01ddc4931ab +645, 0x7cc90d0d28c27c95 +646, 0x74769cbb87388666 +647, 0xd09b8c57ab2ab780 +648, 0x9e37e07f5b413afb +649, 0xe2a4dfc86e985dd4 +650, 0xbcebd68950a62876 +651, 0xe61186758e286164 +652, 0x5be83633e0653215 +653, 0x60f5f3346f1e7a63 +654, 0x90be5b5bd3e71f3c +655, 0xd873686587fbaf23 +656, 0x56a78bdda770ffb9 +657, 0x10ac45a16daa49f3 +658, 0xb8df2a1dd5781cc2 +659, 0x7b2ed0fc9abf7e9b +660, 0xbea9373bd4d879ec +661, 0x130c660f2edbf5b +662, 0x5d3f614bbf3204f +663, 0xf328a315e9d0b932 +664, 0x7cbe580281817508 +665, 0x3b7ae752ef5de9ea +666, 0xd88a2f398c8e195d +667, 0x2db535bba7ba7358 +668, 0x762e4bf7fe733a9e +669, 0x126f629c46663b0 +670, 0x91bb6e238a5a9669 +671, 0xeea8827b9c3f2e5 +672, 0xe86738844c67fe4 +673, 0xed15fd801bb9d73f +674, 0x157517cf2091af44 +675, 0xa73e89c3d7bbf546 +676, 0xb56f610a41176770 +677, 0xeb33707d25578bf6 +678, 0x1b89e1301a46663f +679, 0x75ddc343b67f1ea7 +680, 0xe2da07af36f0448d +681, 0xb5567854075a0f6 +682, 0x6247afc791977380 +683, 0x824b342ef7df201e +684, 0xd72654ce78b69f06 +685, 0xa81b601c56d7cb9c +686, 0x721c4b5d80932ead +687, 0xc99bba379d154c88 +688, 0xb12e74cabfb084de +689, 0x182d98bf2d14d5b6 +690, 0xabd6445ca6180320 +691, 0x61bd348533393374 +692, 0x8b24cce3636ee185 +693, 0x9d9092316dbb7960 +694, 0x46b005f6176cea5d +695, 0xf07c167b80eeb610 +696, 0x589f0fa902170da5 +697, 0x96cb5756946a309c +698, 0x8a8eaeb00cc65201 +699, 0xb283c55de49423be +700, 0x67f5595dcba6dbb1 +701, 0xd9776bfbf6065931 +702, 0x6e10ca882deba83a +703, 0x6102d62102809372 +704, 0xdfeeeb5a115e8703 +705, 0x9b2320c4d818be3e +706, 0x9168936a8d01a485 +707, 0x22d3744fea4f78dc +708, 0xd40b836aa128a062 +709, 0x6c61a41c6d65f12d +710, 0x55730397d9510398 +711, 0x7dee61ad38acc6d9 +712, 0xda1912bf3de3e557 +713, 0xbfe6c019850006f3 +714, 0xe845fb0710682483 +715, 0xcdf60b34c368e5d7 +716, 0xd6e7dc0e6c3df1b1 +717, 0xfeb190e94f30088d +718, 0x4476cfcd6c9bca02 +719, 0x2977673195da3490 +720, 0x96c568ec008e2df4 +721, 0x817d59faea6f872c +722, 0x2bc4e7547b5e1381 +723, 0x25c7680da190b93f +724, 0x2dd815c2e3716198 +725, 0x85bbefcc5b6d1f6d +726, 0x5ec31ffbefc3056 +727, 0xc29d2756e13c1449 +728, 0x25b61ddfdeaa3182 +729, 0x2365b4967dc141de +730, 0xe275f2a9be026689 +731, 0xf30d1c218692aff5 +732, 0xb48fe560af269c01 +733, 0x9852c4e3dfa37603 +734, 0xe5a1de23fcc3f727 +735, 0x22fdaf11989cd063 +736, 0xe397e17c8392a847 +737, 0x7529eaad7a530992 +738, 0x5f3f32fd3dfb3320 +739, 0xfc9f4b0bfb548db9 +740, 0x1471cf6df6e134ab +741, 0x873db4bb386fc282 +742, 0xbc94c6a3780f79ba +743, 0x4bd508d98988c251 +744, 0xd1a817a879c8923 +745, 0x12a350db356edaab +746, 0xd3257e02fe6faddf +747, 0xdc09eecdbc32c2b5 +748, 0xde18b15a13a8dc6 +749, 0x753c4c30f7c35e2e +750, 0x596d3436a834d6a0 +751, 0xf3319db462c1b9c7 +752, 0xb73715d61ffdb26d +753, 0x5330c9d08115e44 +754, 0xc008a119c220cfa9 +755, 0x1f624f431b83ed39 +756, 0x6d1130e066efd112 +757, 0xfd3eff082f54c839 +758, 0x1b31da85da96c5a0 +759, 0x849e94a219c2b71b +760, 0xe1b772ea1fb31ec4 +761, 0x67db72a68f2ced9e +762, 0x99426581623fba83 +763, 0x7a6b306ed67cb4dc +764, 0xc18f42740fa62dd9 +765, 0xce90428779eeed7d +766, 0x9d1c7db3d6c3491 +767, 0xb26a8c31ab6f277b +768, 0xd31845885962e222 +769, 0x83aaeff5e24f551c +770, 0x5a73fbc17f10d179 +771, 0x5cc19c3807d48a2f +772, 0xc8e6f01324d0bf9e +773, 0x404f95c06aacef62 +774, 0xfbd0e7a11580e337 +775, 0xe35a206927cad6e4 +776, 0x79a7b1b6c80142e5 +777, 0x81a28a97d7110959 +778, 0xa22d612df01a16b +779, 0xbed9dbcaf3d82bd9 +780, 0xd3e5b22df6fcca95 +781, 0xcf4626d3739b65d2 +782, 0x3bea29bf8bcb3439 +783, 0x3e8f7021bb137dcc +784, 0x2fdd4faa44a68574 +785, 0xbd830ac3f0be7750 +786, 0x7a3e6f39eb05d5c4 +787, 0xaf229fb1db175bc5 +788, 0x7295e47bfccfb76e +789, 0x62695e99d0a25e7b +790, 0x30cd8850c858838d +791, 0xaff09ffcea838e89 +792, 0x4e9d0b99386dbf42 +793, 0x9eac0e6b0025bfb8 +794, 0x383465e3b1a6fffe +795, 0x5b6c0c45aaf4ce5d +796, 0xe5cfe9da80e4348e +797, 0xb1157c89a7d97df +798, 0x1c27501515138d47 +799, 0xd4f4a083e3d14728 +800, 0xdf69ff0a7982ab61 +801, 0xc376eafe88dc182e +802, 0xf93ab7882723b2dd +803, 0x89b8a08615a7aaf6 +804, 0x2b6cdf2f80adbdef +805, 0x2d57a9420550aa14 +806, 0xe9c1ad378ee6612d +807, 0xb48e3b9ca52568c9 +808, 0x9e67310a9b7ad7c2 +809, 0x24f74c637b7fd180 +810, 0x8956247efecfb1db +811, 0xc0a17f81a8a93104 +812, 0xaa2226f0ff5ef2b9 +813, 0x6aac7d569a285253 +814, 0x642982be37a0a179 +815, 0x1da6f2b46c5eb14b +816, 0x146eb12f17563cb7 +817, 0x490e0fe4d69695db +818, 0x50f6bb32abf00166 +819, 0xc78be77c8e1a7b3f +820, 0x130b147b093c659a +821, 0x8a28c321e9df8c19 +822, 0xbd81ea9f26c58a93 +823, 0x786c73446361dc31 +824, 0xfeb7d2a60d500f73 +825, 0x84b0e0368a98bd73 +826, 0xc944c636fb4f2ad1 +827, 0x64dff6c2acc378b +828, 0xe26a5b23e5f2bf96 +829, 0x86dee0cf9f52dedc +830, 0x13f40d996945e7cb +831, 0x9965d35d76866320 +832, 0x55169e779bc4403f +833, 0x5453e9e5d6399943 +834, 0x7ae5cce348460939 +835, 0x206be2007941abff +836, 0x59a1fc9441a2c060 +837, 0xd65e845fdc736883 +838, 0x2d9411da47dc596f +839, 0x3f8bcba4fd0f03d +840, 0x533895c1b19c6262 +841, 0x9cc38eac5006493 +842, 0x2244a1f903232422 +843, 0x8c7eba4b9893e04f +844, 0x8b669e0537581368 +845, 0x48aa4ce1b62dea35 +846, 0x98a789136697266f +847, 0xf087571d08796c39 +848, 0xeff986fba7345e0f +849, 0xd0d667be7bb85237 +850, 0xe83dbf0bc699feb1 +851, 0x8501ff412116d9ae +852, 0x4d2c06d690a13e80 +853, 0xf64b077cba13b5d0 +854, 0xb166fee2ada390fa +855, 0x3bc475043c332873 +856, 0xe21b6d7da7e9ee13 +857, 0xac6c3264958b1f6b +858, 0x701c1df185e6fddd +859, 0xaf7e8501f7445559 +860, 0xe34e79719b3c2367 +861, 0xa75d03f5b049c044 +862, 0x7b1fed41fbb62155 +863, 0xdc98215140275e6a +864, 0xb593660fe8bf00df +865, 0x499f416dfea8a062 +866, 0x2463b217bffaf042 +867, 0xde955f615e68a961 +868, 0x9db7cab1b500249 +869, 0xc4e0c255193f8d3c +870, 0x3a220f4068fe8189 +871, 0x310f311d1151affd +872, 0x9d2723448ff8a1bc +873, 0x219c5f555182f8ad +874, 0xcc6a54b756154997 +875, 0xa9894b81e72d03b4 +876, 0x1c489f42758b4008 +877, 0xc57737e1fff628da +878, 0x752e08a04dbb3654 +879, 0x397ef980659aeefe +880, 0x6da11abffcbf51df +881, 0xb28f6931d8425ccc +882, 0xb2589acc6764a5a4 +883, 0x6e7caeb3edf4c9ae +884, 0x3333bef1c33d3648 +885, 0x50b975012e7f0d58 +886, 0x4c24195a5576d9e5 +887, 0x5fb697e515523d4c +888, 0x4c25e6146105725c +889, 0xcade882dd4674db0 +890, 0xe0f1cba246c94df6 +891, 0xc7ccf728811bf9a2 +892, 0xce2b631b55492ed6 +893, 0x9ca2e1c4fd5080d1 +894, 0x5c99b44ca03cba57 +895, 0xc12a90a937b45e7b +896, 0xd97f8d5d4c44db88 +897, 0x54077ccf8ba0193b +898, 0xe1ce544f328b8d8d +899, 0x8a322880b5237d01 +900, 0x286a178d86ff3d49 +901, 0x211a8e5021074880 +902, 0x3be20d7210e4a91 +903, 0xb7c35a62c4f646dc +904, 0x2b409ad4e03b7290 +905, 0xac3087c5382e7e58 +906, 0xa3748972b982ce4a +907, 0xb340ca0dcdd4fc46 +908, 0x92a567cc37525316 +909, 0x32ab0e108dd31e1a +910, 0x9cc564c8306fe4d4 +911, 0x2f30238d788e4aa4 +912, 0x5d7b2d5a1cfb3ca6 +913, 0x3d7c7cfb5c3dac2a +914, 0x68a2fcc7c90bc67c +915, 0x93c931b07c7bcaaa +916, 0xb07e858c5f6804fa +917, 0xf34487568770d540 +918, 0x92d0c14ac66fc693 +919, 0x1df3edf3172dbe1f +920, 0x99dd6452e5beb2a3 +921, 0xe38aa3644a74fde1 +922, 0xc049af84d1206652 +923, 0x45ac2398eaf40225 +924, 0xd12607b558ef0006 +925, 0x1e7381c46a70f619 +926, 0xdb7c30532160e472 +927, 0x73ef892949f375f6 +928, 0x19ffd06c4ab2173f +929, 0x5d36078951fde0ab +930, 0xa1dd5b24e3e82ebe +931, 0xa007a426d0f94cb +932, 0x927ab34a8d844365 +933, 0x8a3e93aae579f9c9 +934, 0xfab14d979a048f4f +935, 0x91a360f46855dcf2 +936, 0x76466996b49f4705 +937, 0x12d4f323c1a88644 +938, 0x5505395519967856 +939, 0xfa64fc82da5d6486 +940, 0x1bd1dc97bd219e89 +941, 0xaf41e0011c68d69c +942, 0xf1851e78d15d95a0 +943, 0xc00178a6f4449839 +944, 0xf74517746fee73d0 +945, 0x14e21fb6693e2dd5 +946, 0x30fe5c4d988342c4 +947, 0x9981d1554e52001c +948, 0x164e36540569db94 +949, 0x711c12fa1f32de8d +950, 0xe43201111f3e1990 +951, 0xd3f5395b84e4d93d +952, 0x40319e5870e18ea +953, 0x7a45fee8655d707f +954, 0x3610639f0564fd3a +955, 0xac97da399634ec25 +956, 0x5cc8615a764d8cee +957, 0x82463c24e8b3e5a1 +958, 0x3af60e152b97a91d +959, 0xefcaa0964723b3ff +960, 0xd5979b8da2b0875b +961, 0xd718909a9cfd5aef +962, 0x985995c251b18b56 +963, 0x2c7c126f9a0eabe2 +964, 0xb4ebcd9ab305d7e1 +965, 0x28fd69e0a7bb4846 +966, 0x2af7b43ea9164e56 +967, 0x9f72bdc5fe1ec72b +968, 0xf1a884206bb1559c +969, 0x5caea3abafc00777 +970, 0x2e5901b394a13b22 +971, 0xdd4281ace415ef7b +972, 0x1e421afa2c23a9ee +973, 0x64942a448f2a61f7 +974, 0x32475573b78af5e0 +975, 0x348602ab7221 +976, 0xda1cf48b3c778ac9 +977, 0x202730803de016c +978, 0x7f07500a97253303 +979, 0x912df89c5702453b +980, 0x7a483f96506f7e2e +981, 0xb0331694db0d3557 +982, 0x244b924fd11c49ac +983, 0x5d1097770b6f4740 +984, 0xb227f8cb5f5ae045 +985, 0xc66e1b71c02fb86a +986, 0xe08b547dbee66315 +987, 0x4e7e2986cce8bbff +988, 0x96f7bfe16d59aa73 +989, 0x82f97f418750013e +990, 0x1329bc356103905b +991, 0x82183603b406408d +992, 0x3818107e93ac9397 +993, 0x3b477193a3f61669 +994, 0xf4e443832f9e886f +995, 0x466becfe7debd82c +996, 0xe32937bc5daaf7c7 +997, 0x90bd4530b0e0574a +998, 0xb78055db48f56255 +999, 0x78829570b3775e14 diff --git a/_randomgen/core_prng/tests/data/threefry-testset-1.csv b/_randomgen/core_prng/tests/data/threefry-testset-1.csv new file mode 100644 index 000000000000..ddfa736dc398 --- /dev/null +++ b/_randomgen/core_prng/tests/data/threefry-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 0xdeadbeaf +0, 0x8dfd999efc587d2e +1, 0x3bf6c47ed872597f +2, 0xd82537743662be19 +3, 0x46103c1408067361 +4, 0x7346b65b404eb9fe +5, 0x4b83687af205cda8 +6, 0xc9cccc1fc1c330 +7, 0xf1998771158a2109 +8, 0xda5dc10ad259dbda +9, 0x4646e487520d8e1 +10, 0x159fc0e3e691e0af +11, 0xe2776a537d1a14db +12, 0xc1c7a9c84e1ebeae +13, 0x884ac2384b510f2 +14, 0x4884b09c9a60131 +15, 0xb13a1cda0d508af4 +16, 0xc3d21a2f212bfce4 +17, 0xa3b801d11d523597 +18, 0x1032f052626e5c62 +19, 0xd3b97f4372f6b7d8 +20, 0xd2982ca1c2af2372 +21, 0x13be3d71202f619 +22, 0xdace9f84ef1ddfa6 +23, 0x111bf9b9cd36c31a +24, 0x1ccc5e5be7281a26 +25, 0xa4cd1aa57030bafd +26, 0x99e30fc07a8990a3 +27, 0x9bfa5257d8e64ba2 +28, 0xfab6cdc7f1ed5221 +29, 0x85a4cf41ee744f97 +30, 0x1bfa09917b2906ae +31, 0xda161ec1288b8909 +32, 0x6b1b3ca2bd91573 +33, 0xcef3a71775de82e9 +34, 0xe8ca72781abf1c22 +35, 0x5b8b673b060631ad +36, 0x6658737a84dfe2a7 +37, 0x65a2254b602bb09f +38, 0x5ee6bfeadda0b432 +39, 0x8f3e8af494aeb36f +40, 0xd1c29d016aa72890 +41, 0xfd96891840f0e51d +42, 0x6103cebcf8398a46 +43, 0x7d899055702823a0 +44, 0xf9597bb3dce6d7e0 +45, 0x85b3bf105f26219 +46, 0xedfe4b32a28e4386 +47, 0x74f2415ce2908181 +48, 0x7de6c2f16372ca16 +49, 0xe2b29d517e17feb5 +50, 0x30d7ffc292038441 +51, 0xad4522ce80cf4c1b +52, 0xa9c79bfa1f31b5d +53, 0xc2f17eaf6c6fb057 +54, 0x27938c6a95a6663b +55, 0x239db1ec714acc17 +56, 0x8df60daf4949f4bd +57, 0xb2f6b97d127209d4 +58, 0xad58961f74c8596b +59, 0x6e920c60d6460627 +60, 0xc3839f29e9ce8be0 +61, 0x339161e608237aa3 +62, 0xf148b8d4fef7386d +63, 0x2cf8bd6438b2a52 +64, 0xa1e432e4a618e741 +65, 0x56e1e56517151ed5 +66, 0x61e528b5a3f6d4ce +67, 0xcddea3f49d6ded23 +68, 0xf966618d29452959 +69, 0x5d4fb65eb30e8f28 +70, 0x4a913ea38620fee5 +71, 0xa00f4c5528a3b760 +72, 0x1ac5a2ce0486d8ab +73, 0x521ca18c998b8d5 +74, 0xb0779142f4d0bd69 +75, 0x22f054d9131f1fe8 +76, 0x8c45b6c48016430d +77, 0xbefe70d6c6f8727e +78, 0xc581436cc4c2c0ea +79, 0x5864d0268e18ee15 +80, 0xca47fe47d22aa5e6 +81, 0xdffdbbc0db7ad425 +82, 0x2ae423bd73de5d15 +83, 0xb83b4651838308bc +84, 0x16fa5f72b53c5d6 +85, 0xa0b6cb353724ac01 +86, 0x64d4dc2db97a7d36 +87, 0x79ccd3dd98b33cdb +88, 0xadda2d6132e73ebe +89, 0x7d1a82eff9dba6ce +90, 0xc27defdc4f9c42a7 +91, 0xe12bcf2300cc0585 +92, 0xdbc65c0ee8511e31 +93, 0xaa9a1edff55c22cc +94, 0xc007f355f38dc50c +95, 0x4fbed1aca4bf4222 +96, 0xf137a501255f8852 +97, 0x416ce22d2c6b8e4d +98, 0x5f9fc6ca7a7e9000 +99, 0x9133f67a9222cbf +100, 0xb5fad01321365bfe +101, 0xe3e971e5481249d1 +102, 0xb2950204c847bc0a +103, 0x7ea97815ffa7d45a +104, 0x482c5be26c8bdf3b +105, 0xe42e7e3114197d0a +106, 0x3b74ae3e10f20ae7 +107, 0x92a5e6eca6ce4c38 +108, 0x951ef146ac76378 +109, 0x282f71a81cf08455 +110, 0x3f267412ad1483a5 +111, 0xa5b91846efa301ef +112, 0xaa31cdcfd08603b5 +113, 0x2e16b10730082c4f +114, 0xbdf14631f750e96 +115, 0xd008abe07ede91b6 +116, 0x994ee56c08ff60bd +117, 0x53f0ce17c7c350b9 +118, 0x4c6f01008b3f93 +119, 0x575ee5e7fa184714 +120, 0x83ef0302e14bdc0d +121, 0x5bf2a34323954dab +122, 0xb489e8c4c51a8683 +123, 0x4c9e9801a6acaa07 +124, 0xe9d2e19c20612fe0 +125, 0x2ee2ca0a4d83aa46 +126, 0x19d3a90895d7773c +127, 0x4130367c3abf9b1a +128, 0x1163968e394a67a1 +129, 0x67ffcbbfe478276c +130, 0xd57b578ec019ce0c +131, 0xb455156a987ea010 +132, 0xa9b429ce5f337432 +133, 0xff84cf0f673cc4c4 +134, 0xf034b32b302d0953 +135, 0x9bb6bc59375bbf53 +136, 0x44a2d4bc278da710 +137, 0x78023c9fc08e6247 +138, 0x6b27a1397bd5d278 +139, 0x193758c805b28105 +140, 0x28b88044af4b5313 +141, 0xdf32108c3da9cbc9 +142, 0x6cdb5ffbc5b589e1 +143, 0x702d9691e509de76 +144, 0x405cba179f3db3b5 +145, 0x73d44e0be3ac8048 +146, 0xf9d578eed861f37d +147, 0x9d04541aaacab238 +148, 0xce4507880b30adca +149, 0xaec02613164bec9a +150, 0x346180904e9beade +151, 0x624adb9e18bf4dca +152, 0x3ad2ab92b1f11b23 +153, 0x7d5ae064eee4f228 +154, 0x4e2bb6e3851953c2 +155, 0x55bedadf90ddfa04 +156, 0x4f9422b9142c837b +157, 0xeb5592fb0a763ead +158, 0x3ecb85424422c74a +159, 0x119bbfa61eb2222d +160, 0x6505a8c9e46616bf +161, 0x57bb55ae533b24c5 +162, 0xd6cee34b85233f67 +163, 0x7ea146f8a6edccf3 +164, 0x76615fab897424c1 +165, 0x6d79fe83053e2769 +166, 0xa2759466a39a899d +167, 0xc71216f7edc5fa52 +168, 0xbad1fec86d6684f6 +169, 0xd461ed7882597a5b +170, 0xa437d1518e84a43d +171, 0x5f7d08235e202553 +172, 0xdd87bf84dd2ee070 +173, 0xf2be8b7cda72f89d +174, 0xb221c206f95bb237 +175, 0xbf0643fe5b908171 +176, 0x6bf7c1606a106580 +177, 0xdb356bbb10ea4eda +178, 0xe237835dd0d4690 +179, 0xe6c2fff624891ed0 +180, 0xe08936b04987ce88 +181, 0x2837dbe9582a2658 +182, 0x51d176aba32aba6b +183, 0x5e84cf73553b7d65 +184, 0x65ae1e2bfd16072a +185, 0xf1e5ba1a331380bc +186, 0xd635cc846b72af5 +187, 0x5b0ebda48c952d27 +188, 0x5e05122799559b71 +189, 0x58636876eda68987 +190, 0xbd7af40a48bec96e +191, 0x85c640b51a9f45f1 +192, 0x204a037b8e6e312c +193, 0x961e7967c267be6f +194, 0xa638d40cdc30c59c +195, 0x5a39715f059bdc4d +196, 0x672b41e8c97af455 +197, 0xd30fed911bba090f +198, 0x491a830b50c133b5 +199, 0xa17c651d10ef18d4 +200, 0x18c5ed30299ca860 +201, 0x422b896bb244bf22 +202, 0xc5f46ffd55ef2588 +203, 0x709cc6441b029ef2 +204, 0xf253dfa120c336c1 +205, 0xecaa82e7fbe74f55 +206, 0x2fd810efb17f6736 +207, 0xe7a25ab84fb25ed2 +208, 0xaf7193b55b4f2c68 +209, 0x2a759a4ee4a1ce66 +210, 0x16996f2d902284bb +211, 0x87d8c6d1879f76fd +212, 0xdc966392468278dc +213, 0xe41e4051d267adfe +214, 0x381a17ee5c0be0bf +215, 0x92f27f7e4d3316a8 +216, 0xcfc791e85c47d026 +217, 0xd3fdbf29fc4b3b9a +218, 0x42e5919e80dbe10 +219, 0xab84a06c93add70a +220, 0x4f09d5438a9cf6ed +221, 0x60e5a77f3e81cc62 +222, 0x86e0c8b80336e771 +223, 0x899c3c4372b18cd8 +224, 0x8e4b3213708a89e1 +225, 0x265ed6061b84ce2 +226, 0x80770e2169b55299 +227, 0x39fccaaf318d18b2 +228, 0xf1b996ca0a6b8dcb +229, 0x2d5a2497533e1bbf +230, 0x82e8bdbea5fd4825 +231, 0x96beae4bc404d6a3 +232, 0x6bd730a492452ec8 +233, 0xb64ebc3e1342d159 +234, 0xb1632475806f1236 +235, 0x2e753cfda372774b +236, 0xa071f3cfac5af1c2 +237, 0x2cf0268115fca199 +238, 0x79255186612c0e7b +239, 0x2ddda40d56bcea5d +240, 0xcae06b8e382dc2f3 +241, 0x4c4eeb5a29713cb9 +242, 0x9094b57b8a7d48e0 +243, 0xc770e33c1203b229 +244, 0x86d82971c2c93900 +245, 0x890e721300b7c4d3 +246, 0x3060aab5f8cac918 +247, 0xbe1eb72ed892942e +248, 0x7c9dd3cb08d8b96c +249, 0x5fd00ae5885d5de9 +250, 0x4417cce0c28a8c3f +251, 0x43cd3a2dc30b89de +252, 0xc2cb18532d9530fe +253, 0x28abfd68d23173ec +254, 0xc4d76303811fce07 +255, 0x59bd12a60ec03a +256, 0x34d7ccec03c71605 +257, 0x8b75d9264501f015 +258, 0x7cd57fab83c4a0a0 +259, 0x8da871dc3cbc9eab +260, 0xb584498a027618eb +261, 0xc6e40e951710b610 +262, 0x41178da78714af7e +263, 0xd23bf6c5d4f72956 +264, 0x96a7e56e7cd445aa +265, 0x9a0c33f1026bc110 +266, 0xa9e827283fabfb28 +267, 0xc5db920653ca6532 +268, 0x7d7c2798440bf4fa +269, 0x29c67ba6461f747a +270, 0xb8714cd0b123302c +271, 0xd3dbfaad42155417 +272, 0xbf7a42afb38e35b2 +273, 0xc68987e460f75e2b +274, 0xc1870d0d8b3749d1 +275, 0xedd865f6c4742810 +276, 0x97257a657fb3cabe +277, 0x7481e43145a8d41 +278, 0xd5bf38b5e9dafc7f +279, 0xd79afc7b1005e7a +280, 0x6ad40d65e9b5a5ad +281, 0x65075c2e32fff49d +282, 0xd1be9510a7f3b969 +283, 0xd07acc1e3f6eb257 +284, 0x41dfff9ffb08776b +285, 0x2521ba1b48ef458c +286, 0x178fdba8b65a61c5 +287, 0xf72679d974b82e5b +288, 0x723c29de610d0b12 +289, 0x84726f3e749c0c1 +290, 0x7316136529dbbb9d +291, 0x62d5c6fcfdd7b104 +292, 0x5ed0a981f49819f +293, 0xedc777d4f5085908 +294, 0xd1758061e06720f3 +295, 0xccdf37b1a089e664 +296, 0x4c7eccdfcc38b22e +297, 0x3af579b044760f54 +298, 0x4ebb096a5a14053d +299, 0xf84f1e6aea913534 +300, 0xab8187a201171f +301, 0x2fdd889a5b23ab70 +302, 0xae0894fe8c9356ce +303, 0x3c98be30e5ac171f +304, 0x566953af2a7a305d +305, 0xb15bb69ebd40f8bf +306, 0xeefca1ec57e47780 +307, 0x88e3d9a3377cd873 +308, 0x39ed63117f8e1ba5 +309, 0xeee20fabef374e5f +310, 0x836c24fbfe91a231 +311, 0x9de79447cb2301de +312, 0x8e3028226501f563 +313, 0xede195f88a8976fe +314, 0xfa67e7f210a9ea65 +315, 0x33a9286c9cc0519c +316, 0xf293cfc77d255e0 +317, 0xcfd8e6a385302439 +318, 0xf801e78f6bad9935 +319, 0x831bb783f70bac85 +320, 0xb85b9b1e1dcdf06 +321, 0xa41009e83579efac +322, 0x9095c71cf018e4d +323, 0x2ec789714277148c +324, 0x46067636a9ed2f33 +325, 0xd9385c2b49db3d95 +326, 0x69102374c36463aa +327, 0x94dec24132bb3042 +328, 0x81c5ff32132d8a4b +329, 0xa9cf7ef654a14c5c +330, 0xcea3e704414db905 +331, 0x9b8ad73d3cecbe73 +332, 0x59c3613f1f59c91f +333, 0x96becdd5d3d6eb7e +334, 0xe532174a0e32c691 +335, 0x52f9ef72eb3a0e0 +336, 0xc47812f381b1034d +337, 0x112ff07cbc1d95d7 +338, 0x8af49fc2e11d14e9 +339, 0x5f0bb0c8e6d38f37 +340, 0x5c92bc8be957afbd +341, 0xe8f175d0f89fd52c +342, 0x76223aa3b45638b3 +343, 0x3e68dc64b3402203 +344, 0x7a1da1d307e31444 +345, 0xd0eb8f54e2fab68c +346, 0x44182e518700331f +347, 0xf149093ac30a395c +348, 0xfd23f8f75c25fcfb +349, 0xfcf727ca90f9e4b7 +350, 0x85dc5c47fd81b61d +351, 0x72b726cf22d2f20e +352, 0x3f57ccd8f6a33bce +353, 0xe363ae312c97ec06 +354, 0xfde8b0a33423ee87 +355, 0xe8c89d34bb501e9d +356, 0xbd4d8774ebaf9046 +357, 0x40333dcde4e889d0 +358, 0x5c31d5695aaf7a18 +359, 0xc168172eafb6021b +360, 0x1bed01cec3613e8d +361, 0xdeb623f4effcfd6 +362, 0xd02f73c698f24935 +363, 0xbae9cb97df30d4b +364, 0x2c8dfe769edc25ee +365, 0x768041adc56396be +366, 0xf11f31e14bcc8f86 +367, 0x1cc1ac84b5a5eef8 +368, 0x7cd911d41054b0f8 +369, 0x60228e0c35106ce9 +370, 0xa92ac07cfd218b7a +371, 0x6e0ce56984fd6817 +372, 0x780b1c87423fef3f +373, 0x677be089b5bd8fd9 +374, 0x2454954f7e5c8c0d +375, 0xea1d3e8e67934975 +376, 0xd0199f2ad1c5b0bc +377, 0xa7961b7893a67372 +378, 0x28517fd857003446 +379, 0x69cfc7298d4f2aab +380, 0x14e673667c3a9c31 +381, 0x3d2326c751b57454 +382, 0x323f62bc000f68f6 +383, 0x58c1b8561f61d24 +384, 0xf4cb934358649f62 +385, 0xa4268dd0327460a4 +386, 0x922dcda4b4062a54 +387, 0xe1c77cc9775004a5 +388, 0x4d6648be23d1aae3 +389, 0x36e66b76d509f22f +390, 0x98a79de81ada9683 +391, 0x911308910ad0d0e6 +392, 0xa78a75232eb9c534 +393, 0xd1620acff1293f3b +394, 0xc2564f1312d27a65 +395, 0x70d5a4d369a56e95 +396, 0xa27a741994153da7 +397, 0x3fd84f4095c66967 +398, 0x8370c9ea207fa4dc +399, 0xffef37922d7c15d3 +400, 0x10bc39f6a7575b21 +401, 0x6ae92a96b97e1f1f +402, 0x8adfba7ab6ca7a72 +403, 0xdf1b40629ce3a3b +404, 0x55d0451d15de716f +405, 0x2bd54462ff147e0 +406, 0x676723dc7af24d1c +407, 0xc3a7f70b34988a83 +408, 0xe716a0967a8c69d6 +409, 0xaf124e06fc7cac59 +410, 0x7951c1b7294d532a +411, 0x543e87364c521abc +412, 0xff5c44c50d4ee584 +413, 0x4a20724584833ef2 +414, 0xf605912a8c86b52e +415, 0x58e76b9dfd4da8db +416, 0x2279cf8b4a4f8894 +417, 0x99e4535e58af23e3 +418, 0x98b357e92d197aec +419, 0xb665faf7ec3c5892 +420, 0x74ff68056822f96c +421, 0x2443b541f675a9fd +422, 0x2ddb1042d52c00ae +423, 0x53bce4d472853bbd +424, 0xddd12064af825de +425, 0xd9e451ebb7871b0b +426, 0x284e8b62b5140d39 +427, 0x392f6f741ec18b5c +428, 0x53c1471d27c62d28 +429, 0x957c668aaa12dcab +430, 0x905899dcc9c8d748 +431, 0x85b9cdbb0195492 +432, 0x3285475338298b0 +433, 0x362aec5454354816 +434, 0xaffcafd1179a163c +435, 0xe7303efbbc4f41fc +436, 0xe5bef7dc443e92f4 +437, 0xc30a00527a65fcad +438, 0x10f35ee768a411c5 +439, 0x46ab523cfd6f019f +440, 0xf96997ee80420b3c +441, 0xd6bd882bc6334bce +442, 0xce8082585fcccb74 +443, 0x10a585df3e216780 +444, 0x8bef43483e7359bb +445, 0xb88fc9f0de92ebab +446, 0x8f9f9ec7e1bcdc7f +447, 0xec0da8b08dbf8ab7 +448, 0x8967d7116f0ca59b +449, 0x3ec612e1c87c23ff +450, 0x5f4c5e66476f3c37 +451, 0x536d0ddad6830a22 +452, 0xce05b606110b2ff2 +453, 0xbc06b0392b8db2f4 +454, 0x109feccc811d2237 +455, 0x1c6d58cbd3717d5e +456, 0x4bf990f210d7046 +457, 0x98c0e58f2e655da2 +458, 0xe71155da62d7207f +459, 0xe619955157476acd +460, 0x5484ce353c85962d +461, 0x4f30e140971d815e +462, 0x1aee57fec03675c1 +463, 0x9d6ac96b29e5236d +464, 0xa8bc59565b8d58f9 +465, 0x888f185056d1ef52 +466, 0x32bf6f97834d5f3e +467, 0x4fda3ca53a0aad5e +468, 0xb06670f7d65dc538 +469, 0x3394e29fd0a067d1 +470, 0x29f7c702dcaa4d6b +471, 0xafc0eb498bafddbe +472, 0x5002c13e14be570 +473, 0x11b62a54a56e7468 +474, 0x15ae967503c5b445 +475, 0xa1282117755e25e4 +476, 0x247ae0993e30d491 +477, 0x328f519e2974c09d +478, 0x963e0c8c57e3a4e1 +479, 0xfd2d1a916eb9def2 +480, 0xa4625165c4cd23b6 +481, 0x935663b351deb205 +482, 0x4ec13ee6fd28c2ce +483, 0x57365950d55bcfeb +484, 0x36d56e4c073cb9a2 +485, 0xa3deb42d6419e3c7 +486, 0xc0a6b68eadab9a81 +487, 0xf99a94679e32a1e5 +488, 0xc42d64e664eb0375 +489, 0x323de13c4da53f9e +490, 0x548e4376950c3229 +491, 0x5d53452624beda53 +492, 0xdb8dbdc4d06fcbde +493, 0xcfae0fedb5744805 +494, 0x8d093170690f3ac5 +495, 0x31ad2ff1c80c20ac +496, 0x40c7570d7660805e +497, 0xdfc383cd341cc5fe +498, 0xa571fa523e56de7e +499, 0x5fe751124076e6aa +500, 0x6696c91142c1a338 +501, 0x5c2295e731cc37e4 +502, 0xea4759143aeafa7f +503, 0xf51103c2360f23d8 +504, 0x58a0e754c23434a0 +505, 0xc81291121fdac698 +506, 0x8679b3dc92d444dd +507, 0x9ec6662d4aecb616 +508, 0xb508daa350249f07 +509, 0xdaf489538ed15145 +510, 0xcb6bd65b1c81a90c +511, 0x7f5492214c7c11e8 +512, 0x875effe96d081ca9 +513, 0x1e35d4b75f19369 +514, 0x49029232ba45725b +515, 0xa73202231bebe958 +516, 0x8011e084a420d3fa +517, 0xe7ff845074367c35 +518, 0x3a9e9ddb2ff812c +519, 0x6f5e47f4aa71a356 +520, 0x91e5a3a77e5b008c +521, 0xad173c173829519f +522, 0xadf0a51b9dfe9e97 +523, 0xa8fb30c571be5e92 +524, 0xb78e79d25ff80064 +525, 0x120eeaa9accedc7c +526, 0x81020045a1ff2669 +527, 0x66a50f790048fefc +528, 0x933c1efb74bbabfd +529, 0xc5fc20f210302719 +530, 0x8151dec3094fabde +531, 0xd2213b923bf407aa +532, 0x78da0fc0b44771eb +533, 0xd3a628d7eaf1f5d0 +534, 0xf7e444d35eaaaea4 +535, 0x2e5a8469332422c0 +536, 0xc4e9e4166203bdc0 +537, 0x68b11509577357cc +538, 0x1c22ba556358f1a5 +539, 0x1130c889b5c71f31 +540, 0x68fd0def61e6a4d3 +541, 0xd91797bb9243ba7e +542, 0xa2230c8c22e607b4 +543, 0x777331fadde75233 +544, 0x5a10baebd665287c +545, 0xc6e37c206f8ef53f +546, 0x2153e16620a7a26f +547, 0x7c044870163ebd66 +548, 0x2a78dbc7b40026b5 +549, 0xe1b372326f13f738 +550, 0x1bd9ed17eb120bf8 +551, 0xd69aa5ce828d6f6a +552, 0xedb21795bc2fe078 +553, 0x9424cee925d04cb0 +554, 0x1487a67127236306 +555, 0xbb04e7bc49c9e892 +556, 0x7d2cb1fef10eb638 +557, 0xb2165be14331dfee +558, 0x608b006694436407 +559, 0xde51a803f31ecf58 +560, 0x2baad9e91021165 +561, 0xc5fdebb7bfe058d6 +562, 0x7d70f942899e39d0 +563, 0x6125c0830f211474 +564, 0x2b63c71b5e2257b0 +565, 0x38162d3452ce5a43 +566, 0x47d92f8500ecfe89 +567, 0xb4b0e8e986835907 +568, 0x64024e226440fdd3 +569, 0xef14e5e470056074 +570, 0xbd98e6483f249d13 +571, 0xb772dcbc1a4c59f3 +572, 0x39f88aee50df9b +573, 0xe1284ee3b725f8bc +574, 0x30b997b194c75fe4 +575, 0xcb8830869e416d6d +576, 0x96dda63deae7dd5f +577, 0x250cbc3004548474 +578, 0xd386e14eb6612f48 +579, 0x516613a018bc41ec +580, 0x3d38173562501913 +581, 0x8f95bbd2fe704484 +582, 0xeea5bc9616a584ec +583, 0x35a6ab8de8843dac +584, 0x9df0a94962efbd1 +585, 0xfdb0bd56c87735c2 +586, 0x8cfc1e372a8368f5 +587, 0x8b23d5fd3b5591d5 +588, 0xa67e55c12bf454d5 +589, 0xc1de05db8c87c9a7 +590, 0xc922075e71b9a176 +591, 0xb8411ab83c539350 +592, 0x6e3e5390e04bf51f +593, 0x265f5f4efd50c24b +594, 0xda4a0b190ed7e4bb +595, 0xe3b9badfb5f149f1 +596, 0x96b3c82ae413d007 +597, 0x6f0ad7739a6c754a +598, 0x8356ae17125221d +599, 0x7f54dbfd1bed2149 +600, 0x1db3446564c48acf +601, 0xeab66293c35e8bb3 +602, 0xec71de5e82111496 +603, 0x307d1ffb851f3ea3 +604, 0xe7763576290aa70a +605, 0xb54df18f36ec2901 +606, 0x1274c4c6b71070dc +607, 0xd5427bfaa1046f0 +608, 0x779d99339f644b2f +609, 0x408c3b4b6a634b96 +610, 0x1735ee7f87bb6851 +611, 0xa5780777c5f4d916 +612, 0x5bf9f4d091ee8ac +613, 0x72a16b375faacbed +614, 0x1cbcdedec43afe95 +615, 0x969f6bb71211f0d6 +616, 0x16205de04f90e353 +617, 0x3d8383b3ebca6fb0 +618, 0x10fdeba49ed28dc7 +619, 0x7db0d19d648a705b +620, 0x58e3c21bdcabf3d +621, 0x62a3082250cb2532 +622, 0xb253b1030f0b10ee +623, 0x83050c560043946 +624, 0xde988add6676546 +625, 0x40ff1d99d7afa3e5 +626, 0x2949dcd8f797c0d0 +627, 0x85b3588ea7d06109 +628, 0xe6158241a7818a08 +629, 0x874c0e4d8f133e8a +630, 0x802ef6fade0787ff +631, 0xc8f4c96631fd13bd +632, 0x1cc53ceabaae0621 +633, 0xa3a8215bac5844d0 +634, 0x3e9a46365495fca9 +635, 0x5b1a8b67d0cfff39 +636, 0xa4c00a256a7528d8 +637, 0xdb0dcabfeec2f50c +638, 0xb4b11e407e0ce53d +639, 0xf0290a216960acb5 +640, 0x647c256bc27149c1 +641, 0xa4c65fa3a1b3a384 +642, 0xcfc3a91aabff01f5 +643, 0x56af49b0be94e98d +644, 0x78192db16ba970bf +645, 0x8be6ab828ca60453 +646, 0xaec8783f7b08389f +647, 0xbf60b1a0a05822e9 +648, 0x773dcad583ad616a +649, 0x66c7c2accfe05b5e +650, 0xeaf428e3f8a86013 +651, 0xbafafbbea503ca83 +652, 0x12fbfe395a53b22 +653, 0x5b0803a9835dc747 +654, 0x6c104a7da8b0bb27 +655, 0xa8b88e467c4c4264 +656, 0xaf921baa5bf05a3b +657, 0x65ba0568bee94c6f +658, 0x20e4f7d26ae8126b +659, 0x1a21cdcb32a11571 +660, 0xb54cc85ddabf7169 +661, 0x7a96f253742c7ad +662, 0x6232ed42c7776d82 +663, 0x28617c73281c3332 +664, 0xdeb63b98b7f96fc0 +665, 0xa99b062863e06102 +666, 0xebf044bcefed86f0 +667, 0x6e3c394a7dcf0654 +668, 0xa8010615532d4185 +669, 0x7a848c300193a6c0 +670, 0x24cd4460125dc3ac +671, 0xcb7855b33cca6b82 +672, 0xcec13cf78f398d29 +673, 0x8ad170d6a9b257dd +674, 0x974e175bcd30d07d +675, 0xd354ce50f8f40865 +676, 0x4b28bba40a25dde4 +677, 0x6e7e9d53b8842846 +678, 0xa1a7effae10190df +679, 0xd04d564e0c0df5d5 +680, 0xffde7841dc21b687 +681, 0x9b1860198d2e41aa +682, 0x24a7d92cbcd7782d +683, 0xe87352efade1fe66 +684, 0x5f302e85b504b68f +685, 0xee93d343f09d8749 +686, 0xbfd683a06d5944ca +687, 0x325743a5a7dc38c7 +688, 0x7e96fe56f6884304 +689, 0x9bee81fb0adafed4 +690, 0x35e5b7dabf13f87f +691, 0xecb4fe689d3f2d62 +692, 0xc98df0a573051cca +693, 0x31344816b051aba +694, 0x6b74db489de2aeac +695, 0xbae6b717869cd684 +696, 0x9dbd5b6a5263c332 +697, 0xd2a84a6af9dd66dd +698, 0x6ec0ed649d6c0423 +699, 0x4fb425d69c495aa6 +700, 0x5f3c4bb82c849352 +701, 0xf936695a6db83ecf +702, 0x1850bca22a80a0e5 +703, 0xd682f6ac9f78d35f +704, 0x739ed6e0627599b8 +705, 0x2d1c3113339984bc +706, 0x1677a16b08764c69 +707, 0x1a46fe6b943eb342 +708, 0x45bc46da8e1ae218 +709, 0x6b899e934ca545d3 +710, 0xa49c7d04a14f01a +711, 0xf6cc946f76aee8f9 +712, 0xd57765ce52bc2626 +713, 0x9d5a611be45e54f8 +714, 0xc4e943fd1d93c8e8 +715, 0xf8bf900e053ae678 +716, 0x35fd93a2d3ca3ad0 +717, 0x28da11b273ad9626 +718, 0x4046bf1292aa4736 +719, 0xad2edd82a440e376 +720, 0x2d2e469cc5815e02 +721, 0x2bbdb981bd3477e1 +722, 0xf7e1ab492ae78b50 +723, 0xd8e8a2f1deb35bd3 +724, 0x38648d4e5ef1f775 +725, 0x66db82d34d00b6f +726, 0x29d9f8ee57bc77b0 +727, 0xdbd37997c9496231 +728, 0x99da76ed64137b55 +729, 0x41e94018a92a92af +730, 0xe9444b859466bc63 +731, 0x139ea8ec0363ec81 +732, 0xe5573db463b521eb +733, 0x91ee2c97612ff6ab +734, 0x17038e62d8d5547e +735, 0xdae84fda26485133 +736, 0xf32ca23f5fb0a2d9 +737, 0x874a456ee5fb95c2 +738, 0xdd0e839b975e3475 +739, 0x1d45382adaf65c68 +740, 0xe98fb57275e4f06b +741, 0x5680ec280f703935 +742, 0xeddec081cf938ff4 +743, 0xf6e156698ddc7f3f +744, 0x5653fb5f9493628d +745, 0x31128e4f1bb7abbc +746, 0x966392eb3ab3d294 +747, 0xc18f506c9bd5727f +748, 0x33f3861681488c3 +749, 0x88eea94d91f3ec4f +750, 0xc07df01a897cfcbe +751, 0x1273a8b06bb1a271 +752, 0x92eceeb94ee16b54 +753, 0x2372a2660388f673 +754, 0x12f0f9c80ae16123 +755, 0x192880a152ad8fd3 +756, 0x67ddde771ec9e527 +757, 0x29ef5b708626c4fa +758, 0xdf65824bc7e2f5d1 +759, 0xed186a843266c66d +760, 0x82bcae004f3c0011 +761, 0x3a00ac4e2aa8f1b8 +762, 0x14542fa617647e91 +763, 0xab833973b418a788 +764, 0xfff24c07ee1e1a8e +765, 0xc9483de3fa539f39 +766, 0x3ac2fe43b2865dd0 +767, 0x3fa95781cd250f59 +768, 0x306e75a4e686b37d +769, 0x6590018fe7123137 +770, 0x29fa6de7fe953978 +771, 0x235a7778eb3defcb +772, 0x4866fd1cbb1de581 +773, 0x66294fb38c3a4d1b +774, 0x2eba0e0b6a16a3a +775, 0xc416b8fce537f10e +776, 0x11b40b753610cf +777, 0xa800cb9afe30a55d +778, 0xc7843d545c02d7ae +779, 0x19d74191419fd649 +780, 0xed8d718b6f8c05bf +781, 0x321b3469a3b9f8dc +782, 0x558799f6b55c0ae0 +783, 0xb289b9140c769381 +784, 0xc96bb650d7a5d3e0 +785, 0xc2e92e33b8559b77 +786, 0xf4f5f6ae13188205 +787, 0x2ee80f197ec22d18 +788, 0x6d87c2241c3e6d63 +789, 0xd145a7a0a2e7b011 +790, 0xc62cd586690015a0 +791, 0x9f58724c6bb22eb5 +792, 0x1f4d76cccba65f65 +793, 0x2c8ef48d0ed3f00a +794, 0x4100357f24318944 +795, 0x99f50ea3b1e806b7 +796, 0x80b0b55abef2e2ba +797, 0x728eaa6f3dea3ff2 +798, 0xb9fe60138d05628a +799, 0x4670c98cb3b1c59a +800, 0xed88e42657806925 +801, 0xa5f002df4a0fccb8 +802, 0xec8c1a342c98136f +803, 0xa356077ed340cc9c +804, 0xe87cc8ce72c844df +805, 0x663b6b98d1b215f5 +806, 0xe8ad0986f0a51b9f +807, 0xf77e0dd6396d98ca +808, 0x16d0284cc96530d2 +809, 0x21dca6308157182d +810, 0x4e80e0e6a0023ddd +811, 0xec147ee76408744f +812, 0x7772e8a51336d259 +813, 0x5e951007cd864259 +814, 0x9921dd15ebef245d +815, 0xa094b493f836ae35 +816, 0xd7fab52dd503383 +817, 0x2b7f2d67820bfedf +818, 0x15a2ab3bb9a269eb +819, 0x92f10dfb889b32af +820, 0x38fd566d1787da48 +821, 0x2b1f206adf06f0f2 +822, 0x998729e56a03596b +823, 0x9caa4041b8b8284e +824, 0xfe10ef8016e923f2 +825, 0x5181ba35c1a28b42 +826, 0xeb61ed1495837bcc +827, 0x3a320559880e1a29 +828, 0xac1edb5359dd9260 +829, 0xd2ce3b57da95c407 +830, 0x4375b7b9f6fbba1d +831, 0x446ec944796ff6bb +832, 0xaec4b78b5e828092 +833, 0x58004da5a0c153e8 +834, 0x5a2a2fad35215a5b +835, 0xeaf28165ff768948 +836, 0xc082d63ddad8c91f +837, 0x283d10a4300609d2 +838, 0xd2b4552391560573 +839, 0x4fdbefb9e342f858 +840, 0xa43906a7198f7ef4 +841, 0xcef94695a5d3cd88 +842, 0x8296bafa49c5cea3 +843, 0x351e0421b7ce8812 +844, 0x81d394848a445647 +845, 0xbfda8ffeba72599d +846, 0x823c00f90918421d +847, 0x2bad7eceb840b4b3 +848, 0xed9ca1321e8475f2 +849, 0x33ca86b7634608f7 +850, 0x3351c775ea252a18 +851, 0x6ad518a58bbb6469 +852, 0x2114c295e612cd6 +853, 0x18ba78ee3c710e1b +854, 0xfef3c2f9abae434a +855, 0x2f2033652e9eeeb5 +856, 0xfa5baabf35fa10fc +857, 0x38f160d51e3019b +858, 0x455cbd400f87e960 +859, 0x942f1352c9b1445c +860, 0xc61f0edd263951da +861, 0xa447110dcc7921fd +862, 0x4c811f5af4e0cbb0 +863, 0xe997fff7a5939781 +864, 0x1224dbad82b23c97 +865, 0x65cdec93d671a0cd +866, 0x22990c95303470c8 +867, 0x40e6e0c576b97f56 +868, 0x53bf25c3c12b43fd +869, 0x1992bafa30093644 +870, 0xc80b6626b1b3084d +871, 0x46e018183031721c +872, 0x10b23bc65323effb +873, 0x176c121f9bd81f23 +874, 0x19047376d9ddd242 +875, 0x47c0b554263ae3d4 +876, 0x7d6c14c2e40bf7ce +877, 0xeb3c30a640d082fe +878, 0x5155bd10f1818c38 +879, 0x24ca5ce343390351 +880, 0xb9d7a5dfc4f89d34 +881, 0x1b8f0b8c3a3bd8b7 +882, 0x708ab95c219a2ffa +883, 0x1cf3befb2776fec4 +884, 0xece471e68eb13a0a +885, 0xcd9e646295c6ad1f +886, 0x63a5a97e805b58c3 +887, 0x6bdd3bc818330ba5 +888, 0x642a2e1992d481d9 +889, 0x60362b11bbb1cc44 +890, 0x5c10e85acb9ad8f5 +891, 0xb8ceba6af37425d6 +892, 0x855bdea1d7415466 +893, 0x108bec5b41275d30 +894, 0xb0fce44c3caed15e +895, 0x6e1d44a82e34b3f4 +896, 0x698ed735e1db5220 +897, 0xe4d427dcfba23857 +898, 0x85ad0edc6ebbccc7 +899, 0x7c9cd7bc58fa5ff6 +900, 0xc2f19c0d76f53615 +901, 0x773385c16db8f379 +902, 0x2bb9120cfa435e1f +903, 0x295961649184169e +904, 0x20de31c807978633 +905, 0xd36701dbda31b982 +906, 0x5551feb741996e9a +907, 0xf8aaad4d0c52434b +908, 0xce6f4b0dcaef6cfd +909, 0xdacbbb33921fd85c +910, 0x587a5cb0cf051eda +911, 0x42124bd99d594fa9 +912, 0x9ad4a203e1ba3c84 +913, 0x775b758d4944c2e5 +914, 0xa7276e35b33e62a2 +915, 0xf5657d537c6271fc +916, 0x69b45cfd145b352d +917, 0x8672a0e552f7dfaa +918, 0xd5c0b8f929f63c84 +919, 0x1062b14c01bf1560 +920, 0x3ae6927a61dc70e6 +921, 0x2ed5f06dc3ceef22 +922, 0xf79f417a63f1dbf2 +923, 0xf6a74c03f7ab1744 +924, 0xf2a8523818bb492a +925, 0x8db8ec62b7262a19 +926, 0x4ac507b9aa8ac0d6 +927, 0xe1db6db360091041 +928, 0x97205197883ee213 +929, 0xc83c6265be4a8612 +930, 0x99e84f3f743ec327 +931, 0x931ab84b78b922f +932, 0x900ebb02329a6201 +933, 0xdb720a24d6d93400 +934, 0xdd0de802d3780399 +935, 0x177fac072d4ff0d3 +936, 0x95f5688bd75ec33d +937, 0xce19d334b40b7c45 +938, 0x780c71636ca880c7 +939, 0xf8188c0626e3ddbb +940, 0x32ef96e74be5a76e +941, 0x8f9adc11e6ee08c7 +942, 0x860a6c1d95bd01f3 +943, 0xb19d517b4a3054d7 +944, 0x196cb745dc3a674b +945, 0xf611c20fecc9b445 +946, 0xdb0f8f14fbb237c4 +947, 0xfafc6fc52d7b483e +948, 0xcffd5779f52badef +949, 0x8a626e983ccfd9e8 +950, 0x8f2ccac91dfaaad0 +951, 0xbda4bdb3cc57689d +952, 0x2a8af26a1d17c1c3 +953, 0x9feab9b49105010f +954, 0xe2a9046372fe5c04 +955, 0xd55195108d63dd4d +956, 0x4702e92922745d80 +957, 0x423c590b3ef222da +958, 0x2b56e611f1272bbe +959, 0x90d65326f9c21b6d +960, 0x56777609cd5360db +961, 0xa35a55eabfc4d9c0 +962, 0xf6134f2e8cf2a92f +963, 0xfe7864a5510c499f +964, 0xb205f42b43d89001 +965, 0x2618c3eb687e9050 +966, 0x1c85ebb7eafb6c1b +967, 0xfe47cb43ba8f5e02 +968, 0xceed09f98fe493b4 +969, 0xe7e51b4e51c5e0bf +970, 0x53343be07ce85327 +971, 0x816a17136951159c +972, 0x92adfb8807d45418 +973, 0xd6eaf3cef3390e14 +974, 0x6d7c2adefcdd411f +975, 0xdcde0a6376ecb43f +976, 0x47d162d5a140ea78 +977, 0xf55fdc7283476df5 +978, 0x2f66d5d029982dfe +979, 0x56a94f1fdf81fb24 +980, 0x46eeed06237aa921 +981, 0xb5f585d18b026038 +982, 0x29e12cba3b5a03a1 +983, 0xb8433a70685341e3 +984, 0x4e86f031c2bf4939 +985, 0x7167c51db1d096e1 +986, 0xa300693a1ce05ff7 +987, 0xddf7f5ef8994b6f6 +988, 0x5c99ebf9a1eff32 +989, 0x441bbc76e92979b5 +990, 0x7724f07eaaf30a94 +991, 0xd9946d64346a0d59 +992, 0x3d49489a6a952877 +993, 0x2b4846d1c8f4bc56 +994, 0x1d5f7891a6caaf50 +995, 0x7f9f458f479c6677 +996, 0x9177526a634cac18 +997, 0x82b316c3ba3cea55 +998, 0x84d769b6ffd7a5d6 +999, 0xa1230c54cf6f4b5e diff --git a/_randomgen/core_prng/tests/data/threefry-testset-2.csv b/_randomgen/core_prng/tests/data/threefry-testset-2.csv new file mode 100644 index 000000000000..275604557279 --- /dev/null +++ b/_randomgen/core_prng/tests/data/threefry-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 0x0 +0, 0x6dc04d22e096eea4 +1, 0xb8c023f98cd7ada0 +2, 0xa7efe930de644973 +3, 0xe05ea045a0add077 +4, 0x404ab9dfd366d169 +5, 0x4d42fb74611bbd30 +6, 0x9343a758211b6d70 +7, 0x4dab40877197665c +8, 0xaa7b143cf838b109 +9, 0xcad1f00ed5cea835 +10, 0xf7c7d7d6c9a824a8 +11, 0xf20b64a5b42100f3 +12, 0xe155fec329e4ff46 +13, 0xe9db5c878d78e4c5 +14, 0xe96ecf5f3d8434fb +15, 0xa4a5369e8b676159 +16, 0x26f540900462fdc3 +17, 0x805e684c0bf0600d +18, 0x950c55250dcb9322 +19, 0x1df00ab0d9a5f9fb +20, 0x2e75b8e9fb48b88f +21, 0x8982e680b983b07e +22, 0x7c730288ec003204 +23, 0x8d4a42efba070902 +24, 0xcae4317a285d026e +25, 0x587af8ba811a8883 +26, 0x236cb94da85e9409 +27, 0xf4d25c2e0d7b2bd4 +28, 0xd51e53d74420f649 +29, 0x29f9ad48909f580d +30, 0x39e2a46d5962fc7e +31, 0xd40bb4045f9288fc +32, 0x86d6d29c0a126484 +33, 0x198289c6d8589ec8 +34, 0x5c4ffb186e8f69c2 +35, 0xeaa9fe626ca6f961 +36, 0x58816ea059f6b7ef +37, 0x9a636de4086ed493 +38, 0xe5a2b327a52f6500 +39, 0xa6d200345a8c4135 +40, 0x8ad50053fae7c70c +41, 0x1afd6de09771e167 +42, 0x7372d8a4cfe85c9d +43, 0xe2a99f3770165e93 +44, 0x193e99ffd7b45a30 +45, 0x4af13faae1f4ee8f +46, 0xe799ae38aea2a54a +47, 0x19bc5efb105b9b55 +48, 0x428799856ed8d2b5 +49, 0xc7e1c76dfb93b581 +50, 0x1c8000fb2afbe108 +51, 0x5d217734dc6fdcb2 +52, 0x4f9b436f2fa7b5d +53, 0x6c6a8e841f5f7f2b +54, 0xf7af258a895489e7 +55, 0xd4afe725c6deee +56, 0x11959dd7c1a0e56e +57, 0xa82b5a575ba9234d +58, 0x356bb807c17fe67f +59, 0x4113ba7ea9234d28 +60, 0x87c7fef17934c764 +61, 0xed5d2e29701db2ce +62, 0x4b4bf08b62160f5f +63, 0x32057a60eda862a5 +64, 0x446b5409b56a9311 +65, 0x31e84acfaf48c9f7 +66, 0x8951479289443c2c +67, 0xff84ec0fff1b3d23 +68, 0x3db2e8a284e2cee5 +69, 0x2c8aca76f7caab8e +70, 0xfe8ff095676417ee +71, 0xbb7d6ed0c641e84a +72, 0xd862d2552159e272 +73, 0xd320d329cd2b0419 +74, 0x41bd59f68a0fc99a +75, 0x1adb5cf5cc0462d9 +76, 0xaa152c0b16d38826 +77, 0x1358fc52142b5523 +78, 0xdc29465d24a25fc2 +79, 0xda86700b570eaa33 +80, 0x461c6b79f1aea5da +81, 0x4dcbf7406497da6b +82, 0x5f9d552eef82e555 +83, 0x27261b525e6c02df +84, 0x75076fe041440603 +85, 0x7cb47c620018a06 +86, 0xd7b7d17c3d1ee39a +87, 0xbc7eada7c2ebc70 +88, 0xcac816c1d36ebb7e +89, 0xbe1fd6bcb3d795a9 +90, 0xbd822d8f1edd205b +91, 0x5c0ebf018ade95fb +92, 0x9c6ee7cca010ad02 +93, 0xa210e3829a0b1b62 +94, 0xf5b25b53e25dba71 +95, 0xa4a69d9d6e73b9a2 +96, 0x2718cf614f82e185 +97, 0xf5aaf0eefd4f29cc +98, 0x343f41179d6056be +99, 0xc897506f84b7a9bc +100, 0x547ce04e8810e66f +101, 0xf61f6f95782be285 +102, 0x522e0fa1964a631f +103, 0x500fe922b3a102ca +104, 0xd39b38e1ae6f8218 +105, 0xce6079eafb932dc9 +106, 0x2896e00f1fdb8c46 +107, 0xe5719f1535cd23b4 +108, 0xc4d4dc27f6393389 +109, 0x95b3c17025e7ea85 +110, 0xcea3f280dae8ebbe +111, 0x6d91c862fbf2fda2 +112, 0x99c5197b21f1f444 +113, 0x9ddb59c15db5411d +114, 0xd6ed4ec1b494f92e +115, 0x3270a479f7e1fcd7 +116, 0x79e8d185e02ad6e +117, 0xe548786a4c6309fc +118, 0x1dd3bf9d9f3fc9ed +119, 0xe52ba084f8713b48 +120, 0xbd6c473054430deb +121, 0xaedf39aa96279c3e +122, 0xaa3a7bbe2fd381cb +123, 0xa087544796e01cef +124, 0x6596602a719be04c +125, 0x282a96eaaa790ee1 +126, 0x313b3f42aa9ce4 +127, 0x9998a73e798ea881 +128, 0xf51dc8e618571e13 +129, 0x1df638afa23f4d8d +130, 0x26385330319db8d5 +131, 0x1e1912386c519544 +132, 0x46c42a55ab556cdd +133, 0xc049b83a6f04efa2 +134, 0xecd2d18baafa8af3 +135, 0xc1108f82d1765b42 +136, 0x7dcd72d9f729db44 +137, 0xfa73627c9a20cf11 +138, 0x9ac69ccfda0ee7a8 +139, 0xd02f2c2c1776c62c +140, 0x75b4da786706ddeb +141, 0xeebe6ece4a516bdf +142, 0xf274b3ee4fb7ff3d +143, 0xd4b1093bd35d25c8 +144, 0xc341c37b9cfe28c9 +145, 0x32c4fb8e8e6aea6 +146, 0x4adefc5712ca8606 +147, 0x750302d8f108d3f +148, 0x76e6e3259264f240 +149, 0x31c6db85c206dc2d +150, 0xda47cf5e8d07c49 +151, 0xc5939dd565786002 +152, 0xa02e5128b7f04e77 +153, 0xea2e5fa9ffdad0fe +154, 0x7b1f9bcb5578cc5e +155, 0x3fe776dc8398e6a3 +156, 0x31b97c4a0973fc4d +157, 0x29a985a2bb602d89 +158, 0xe6a76cfb1a5c0faf +159, 0x4f9f62edb1e6d19a +160, 0xa589097a26f2b615 +161, 0x6bca21ae81e149ad +162, 0xa6570f8fdbf98af4 +163, 0xa740f226d53bc40f +164, 0xf0a4fe08ab331d24 +165, 0xdc1eaaff2c67c65d +166, 0xf227a9a3e89a7271 +167, 0x1f539a105ac9a7dc +168, 0xdf2fc18d2f4004ba +169, 0xc36711f5ef877b67 +170, 0x29e30f4b30ad39a9 +171, 0x3af92a16534fad9e +172, 0xf66e30d65df7faf1 +173, 0x2594f6d925228c49 +174, 0x8b8b3d9f20fa8a67 +175, 0x88e8d38366cb411b +176, 0xe881af89393b5a8d +177, 0x2f190890e152d243 +178, 0xbca3c2b43bd2e2ce +179, 0xaecb17f2dceb2ed1 +180, 0xa07f556a40d4dab4 +181, 0x59c729c94cb2b4c1 +182, 0x5364cee304495a05 +183, 0xa628681d16e0c604 +184, 0x40e2f3e0d9124851 +185, 0xb3da737ef7918179 +186, 0xb946e59c4905271d +187, 0xc079b7dd74752ccd +188, 0xfce4f9ef02e73130 +189, 0x86baa280d2d9aff6 +190, 0x778ae7465aca2696 +191, 0xcb1f60b74f32078b +192, 0x71bf826587c2c1f3 +193, 0x7ad5d51794ccc972 +194, 0x4b6ae15708464071 +195, 0x86c6829137a4110 +196, 0xc002aa2f64a5283b +197, 0xcef3ae65b916b6bb +198, 0x1e691414155bd2ad +199, 0x9fc613bcc3a961a0 +200, 0xf55caa38c2b7866f +201, 0x3aa6008a705ea431 +202, 0xc1587b4c3d3e6146 +203, 0x56e5eb96d0556293 +204, 0x796730a5bde01777 +205, 0xf4b5de3097e501a3 +206, 0xb5a2d840b9e7737 +207, 0x9059674f6dc9db07 +208, 0xddaa8f7b09773c74 +209, 0xce2e4850507c2b27 +210, 0x2d1dc2977de11249 +211, 0x335e7ef86408ea2d +212, 0xde7bc6f22af7ad0e +213, 0x4a36bd6edb976e6d +214, 0x8eaef966a64aeb94 +215, 0x7689476d2572797a +216, 0x4635219f62159d76 +217, 0xfe9958903e4d4ae6 +218, 0x288d7f77642371c4 +219, 0x2f17b9477da7c2e4 +220, 0x4a987e3814cbcb5 +221, 0xcc2ddf12905e9c9f +222, 0xf5cba7330c86853 +223, 0xc646ecb698e336ce +224, 0xc05d862c10b83e50 +225, 0xa673040049fdc79d +226, 0x52871df3f523fb29 +227, 0xeae829e337d8a5cc +228, 0xb17d70979ea53cd4 +229, 0x253a9e29eef246dc +230, 0xdc09f4831946ef53 +231, 0x15a4034a8917e29 +232, 0x57246ff6c9594b8 +233, 0xd80620e906fd1cf4 +234, 0x861bec5cd30c08ad +235, 0xc58f38b68714ccf0 +236, 0xd21c19157efdd920 +237, 0x51e1b8f40b8045a5 +238, 0xfd56fa4ceebbd2e3 +239, 0xcee1959a7f9d12be +240, 0x75f22e1dfb5ade8c +241, 0x3b87a61bcd763482 +242, 0x4018fbdbadcc95e7 +243, 0x3ff57380e846b8ab +244, 0x7e44c8a4005515ed +245, 0x824c847c6767640e +246, 0x2b34ef279cdcf5d1 +247, 0xfd0bfc2786afed92 +248, 0x7faeff889a39834a +249, 0x37a6cbda4f00e6c7 +250, 0x4214fd32c40b0894 +251, 0x4320e334bfd18ed6 +252, 0x74b1f0c2812db646 +253, 0xf48232c0988ea643 +254, 0x5841c46c56967a29 +255, 0xb08204c4c9e83fca +256, 0x2a0bbd0b42a4a708 +257, 0xfe76573ec821c87f +258, 0xbd2e46ac0feeb0d9 +259, 0x3552a2cfc1bdca32 +260, 0xfbdc96046c1020a5 +261, 0xd5d79356b52560d4 +262, 0xaffee5796b293a6b +263, 0x5ef4dd67d2cc9042 +264, 0x7204094f6053ba36 +265, 0x1a89384fd317d01a +266, 0x68129e5eaa1d4a28 +267, 0xcd2a9c8b6938cb65 +268, 0x434bb1bd9872647a +269, 0xeaa17b0b5fa27832 +270, 0x442e1c5fa8113c44 +271, 0x38bcc81ea8386d97 +272, 0xa653c2f1f13a54f8 +273, 0x82d74e165850f5a6 +274, 0xf4b9d5dce18bd047 +275, 0x2666dba219ea409e +276, 0x8ada69aa37a215b1 +277, 0x2cdaa0dc42ba5b64 +278, 0xfa7b44675ef531ad +279, 0xd87d4bc750795b22 +280, 0x562fa1b77f3c52b0 +281, 0xaec092b6afa4b7f2 +282, 0xc2dcf8735598f14f +283, 0xc65a4e439f790832 +284, 0x73fca9d888e184f0 +285, 0xaf38a6918896df93 +286, 0xeddbfe61d62902db +287, 0x2e8e831abd28891b +288, 0xdfea332c8ba5e7c7 +289, 0xb980b3ea4806e11 +290, 0x37f771e71cd26079 +291, 0x65b880af5cf288c3 +292, 0x69bef58494777df0 +293, 0x207706d3b013c1c6 +294, 0xe9b4014efb64e6e7 +295, 0xece0298dfad7da0b +296, 0xcfed2f0d392af845 +297, 0xfbb1407059436788 +298, 0x74e9d65370ea5662 +299, 0x6e8bce550b2c36a2 +300, 0xf38d767f77abe8de +301, 0xc6befbfbf4c57ddb +302, 0x9fffced31abe51b8 +303, 0x761beb850b4659e7 +304, 0x5af78afae250836b +305, 0xbe64a1bb37c08d0 +306, 0x5dd328d85327ba3d +307, 0xa43238b39aae76ec +308, 0x1f58743f079a14a +309, 0x8f2b1a8cbe77f565 +310, 0x47526c74521adf72 +311, 0x542062d916e30f3d +312, 0x2f3f86a12c7561eb +313, 0x725a6f82106fd202 +314, 0x5939d692a6203676 +315, 0xcd607e13aeae5717 +316, 0x12a76dd01d4e46d +317, 0xddc96ae023be007e +318, 0x71341b774bace597 +319, 0xf69db6a379f38d34 +320, 0x87cd1ea3a6629c70 +321, 0xadc8798060e39c27 +322, 0x532982fe9d77655b +323, 0x1c49d24a1bb2fb83 +324, 0xdcba3b57f87cf725 +325, 0x62b96a90dcaa0a3 +326, 0x89d704a4512cefe0 +327, 0x41685667b144aec0 +328, 0x49395424e7982bce +329, 0xb493878ae98f87f +330, 0x2b2a23e3696a5588 +331, 0x2bbb82d12da62157 +332, 0x98092e701b17da7 +333, 0xb55d717ca8a4d039 +334, 0xf4547583b84a03a6 +335, 0x9609c10b7e68759a +336, 0x2a60eea68cdb7812 +337, 0x15146ffa8acbe5ed +338, 0x521e3b2ca6e16844 +339, 0x27528ffae94c01c2 +340, 0xc5df652e08db6be8 +341, 0xba1275ce0594c2f4 +342, 0x9c66fc6882ac8cf1 +343, 0xfcc5c3e413a7dad6 +344, 0x8309532dc68a36c1 +345, 0x7f9351a45e66c50b +346, 0xa70e6b123bdbad47 +347, 0xad49d29da3a694b0 +348, 0xf198452973eefdaf +349, 0x53b7951ab7b24800 +350, 0xb226c827c5cf8233 +351, 0xea184af7dc0cece3 +352, 0x77d5dc22579d919a +353, 0x583ec0e8d8295fa3 +354, 0xac35b75b4dd17e0d +355, 0x7d273f1ef4ec8df2 +356, 0x85665ea56b49b5e3 +357, 0x7cc0ee21b59ec57a +358, 0xae595b1cf72dc292 +359, 0x4eaf57e8e6880fb5 +360, 0xe51931811683e382 +361, 0xdb29479871fc8dc9 +362, 0x9b2f9c40c6506d91 +363, 0x35ee0dbbf239bb06 +364, 0x40aa630242bc7e2d +365, 0xf3a3d9b2f5839a26 +366, 0x17e920c38a2e329 +367, 0xae28a796412706f9 +368, 0x3327dbcbf0cee5e +369, 0xdbca13ee810f8546 +370, 0x390f9a7560cd1a23 +371, 0x444085fe4b30b123 +372, 0x4a1dea59c8ffa505 +373, 0xc12708a6534b7424 +374, 0xc331d65b7dd17bdc +375, 0x4d1a64113fb84526 +376, 0x7af40a24916e7ba9 +377, 0xefc466d746e83001 +378, 0x631fb61962533374 +379, 0x355629ff71ec6c69 +380, 0x89e5c7e5a2b6b82b +381, 0x307fc816d73c725e +382, 0x3c7c2fad16ee2808 +383, 0x3db362fd0d93dc47 +384, 0x7c7d9b1ecc6bbc7e +385, 0xcdab8413e0b594bd +386, 0x3e45d66baf972abd +387, 0xbd8bdc23f1926e70 +388, 0xfbc61c9f0b6c1a71 +389, 0x68b9e52b65d64f9c +390, 0x5b371b49f49af63 +391, 0xdab60623156c1ebc +392, 0x14ed99c617db324b +393, 0x5c7f7b5f6db77c0e +394, 0xeae562127e55128 +395, 0xf5ff71155fca2c5c +396, 0x8271b2d1ad93bd4c +397, 0x1ca96341dd5b034 +398, 0x49265a39bf18e8d6 +399, 0x5bbe70cdacf51f1 +400, 0xbf198a70b59ff062 +401, 0x41058370f356a21 +402, 0x47e8c7127044ea +403, 0x3a031703f1e98d83 +404, 0x63db42df128a9d7b +405, 0x67360bba6d058db6 +406, 0x2cb06097a2bdcc21 +407, 0x9e69d402ec5ce471 +408, 0xef55f0fa21cde5b0 +409, 0x2ce15bd742eb7acc +410, 0x2f29a82fc4076787 +411, 0x312992a6d3fb93ec +412, 0xd9abccb15b2535bb +413, 0xdfcc55a43bad4c90 +414, 0x51ca5637dd4ea18e +415, 0x9be4b1911b1ae9f7 +416, 0xb835b284b26d4057 +417, 0xca26765b4414729f +418, 0x211fd5e340cd6f9a +419, 0x64984a44077081d2 +420, 0x859ea6fc92cbf37d +421, 0x99f190ca3756084b +422, 0x38549b8f8b5a7201 +423, 0xc3940c2807d34ed8 +424, 0xbcbcf498fa77d02e +425, 0x2c24b6360e1033d2 +426, 0x9602edbde8d9a850 +427, 0xbf4ce69ab0e00203 +428, 0xd479d334b0c716f3 +429, 0xeebd6ba9a827a3e1 +430, 0xea0b5cec6b42e089 +431, 0xded6e289584813bc +432, 0x9894568e6a3f4ab8 +433, 0x73ee7a9acd6f667 +434, 0x4c849a0da094f2f5 +435, 0x4fe6f5fe0f90f786 +436, 0x9887c17ea5f92327 +437, 0x318df65aa9a53d5 +438, 0x70a7bc8178292fd1 +439, 0x612a38a535b8e3d2 +440, 0x15a79aa16d0228e1 +441, 0xd3288c336eb0b33a +442, 0xf84e2fd1e4db070c +443, 0xa2efb0e34d0114d5 +444, 0xc528e890e7fa6409 +445, 0x4b837fde84319af1 +446, 0x632edec918b02d23 +447, 0xce980f566494c149 +448, 0xe54e204d31452188 +449, 0x9ca51e2e7fe3a3b0 +450, 0xb0a7183126df963c +451, 0x2de5fd96c125669a +452, 0x17ab43849b96549e +453, 0x49850d9bb767cfd8 +454, 0x632d44d7add93bf0 +455, 0x3fba66506af7b132 +456, 0xc06c6bdeaec6d733 +457, 0x3e7795ace33e8cd1 +458, 0x8f522c2f76ae3bd7 +459, 0xec883650a2d2b2d1 +460, 0xccb11ad5bff431bf +461, 0x936d66262607c537 +462, 0x3102298a92f643fc +463, 0x76078e8357fd5e15 +464, 0xf22a64a885d7e7ac +465, 0xe111261b30caa160 +466, 0xed2c2d728a8ced12 +467, 0x64e659163f8d1d71 +468, 0x8c7c5f696f55dbe7 +469, 0xf0bdb7e3168a82d4 +470, 0x1eea602c6df9464f +471, 0xa10d1d8502d43304 +472, 0x824245afbf95950c +473, 0x7b4a64e619e29d10 +474, 0x73d4d21a8f412218 +475, 0x3ee5be3d8af0bc17 +476, 0x78979eebb7bb7b9c +477, 0xe2acf9a6f17cb00d +478, 0x77d8f02baea98694 +479, 0xba80648f6872987a +480, 0x1cc1fa8be28d090c +481, 0x9df7f91ded8fb4d9 +482, 0xd5bc13c3dad13991 +483, 0xa57c268e5153f06d +484, 0x662f2e1fdc97ca36 +485, 0x1242a97a1148c369 +486, 0xa85178a88b821450 +487, 0x32fa270cddccdc1 +488, 0xd52af3c8d3d9ccbf +489, 0x105d4ee4420a2035 +490, 0x8ccec92b29bb6f3a +491, 0x7330a89b0ec713b8 +492, 0x712f7f946a661b8c +493, 0xdd11f248be047eab +494, 0x15aab9e558d04865 +495, 0x791b42bd188d3042 +496, 0x571a03a98b08d2c2 +497, 0xe8362e466304c2e0 +498, 0x690bcf82d6f7e815 +499, 0xf387d12b216e039e +500, 0xa1a0e6721cadf720 +501, 0xc238cd658c3c48b6 +502, 0x303d33d956cd19b7 +503, 0xb91002fb2c06523c +504, 0x3fd6c979ecc9e53a +505, 0xe709a011bbd9684c +506, 0x9f9730e4466b178a +507, 0x5d6a951a17dea6de +508, 0x8ad48c770be7ff5c +509, 0x840349738f1840ef +510, 0x62b71fa4d4713278 +511, 0xb54bc131be88e301 +512, 0xcd360f29092f1b48 +513, 0x51e2d80a7974e018 +514, 0x4716923492cb7c11 +515, 0xc5a3426512ccf92e +516, 0xa29da51d76692ec2 +517, 0x7760e22a2a966fa6 +518, 0x17027bb9ebea4f10 +519, 0x1cbfeb90083c7472 +520, 0x21df956d73e46 +521, 0x3d3f98cec3a0f9c5 +522, 0xcbb44f6843e8f84b +523, 0x5387cf5c8dc08f09 +524, 0x9874b020a7cd16eb +525, 0xb26656f3d0e54b45 +526, 0xf7535314e62cc2b1 +527, 0x9d98c18c8b832a78 +528, 0x4782e4a90afa6bb0 +529, 0x98a5b50793977e75 +530, 0x699bfd767f3c1fb6 +531, 0x2b0c137df6bff06d +532, 0x1dcf680df83ac493 +533, 0x41433da3b84a308e +534, 0xaa5b2dab82fd7a7c +535, 0xd35f4a2331f962c +536, 0xfed4b74303c0ee4d +537, 0xf9a9dcb35118765a +538, 0x4d09906765751e55 +539, 0x96f997988dbaa2ba +540, 0x761968dfdcee7a25 +541, 0x942f82665a09c18e +542, 0xa630ee4197ab0e0b +543, 0x68bfe324bbe3b7b1 +544, 0x8613dd09e8566784 +545, 0x3738178b0a67bae9 +546, 0x78678e656aa91115 +547, 0x6d182cdb34ba7a53 +548, 0x46749ef4e5670d88 +549, 0x2cddc1808c4018e +550, 0x22b2aae091c52f90 +551, 0xa4709bcfefd0d6fd +552, 0xade8916af4dd85f +553, 0x763c7e7df0416c26 +554, 0x78b365ba6d6416e5 +555, 0xadba0adf9c5b5e3a +556, 0x5a146cb126d32c3d +557, 0xa5f2f65ef03145c4 +558, 0x2708930e062a88a5 +559, 0xfc94da4d17e4d4fa +560, 0x78b500b283574f39 +561, 0xdb657f35be884f22 +562, 0x1de17d2450338525 +563, 0xc602ad9d8fe83980 +564, 0xc731d0497705a493 +565, 0xc3e443ea6c794843 +566, 0xb946fc377698953d +567, 0x98ad8f7f193cee5c +568, 0xa8da8ecd4301cb4f +569, 0x99ff5cc72e206b24 +570, 0x2422ef61bb3c9be4 +571, 0xea62c83986a29b61 +572, 0xcbcfb5a9953d1a6a +573, 0x229f258aac962310 +574, 0x8730e2f36b1fbf6b +575, 0xc3d6ddbe26ead961 +576, 0x814fc47c7edcbae0 +577, 0x23af1859cb36c99d +578, 0xeadfaf827ee1de0c +579, 0x15ac2339684c36d2 +580, 0x54c617fd9b17d56f +581, 0x8b88689c24920b0d +582, 0x5294092543a1f59b +583, 0xbcf7fadb518fad77 +584, 0x8e784c0359e6349d +585, 0xa45831bb0c97d3d7 +586, 0x1d0b8d79ab84847e +587, 0xd7f23d7e384fb139 +588, 0x8fc7ee55f1d37f0d +589, 0xc44dc853b1913765 +590, 0x20d40baab760366a +591, 0x6067cee1fc99a47b +592, 0x7927a7b24ecb93bc +593, 0x26819db47e3cd94 +594, 0x236853cd14a54aec +595, 0x36e7a2f60284be9b +596, 0xb11accb3a708d6e0 +597, 0x98c7651be6436342 +598, 0xaf27f94af527010 +599, 0x4ad2ef538542349c +600, 0x63becd7dc3d6fc6a +601, 0x8dfd8f874d18f093 +602, 0x2401cad63eaeaff3 +603, 0x7be4a82015531b1e +604, 0xfca36bc859cff476 +605, 0xbd3f9383a20e1fac +606, 0xee9e7e4bf1c444f6 +607, 0x4ad8b91ea66cd1fe +608, 0x85ffa6d1cafcc553 +609, 0x665f66043e6bf320 +610, 0x4d409c2d9cb23e6a +611, 0x1815b94fcb2e85bd +612, 0xbbb8439e003579a2 +613, 0x16dbe31fced48255 +614, 0xf4f7079142a17040 +615, 0x96df1c5c35e5c231 +616, 0x41fc7faaa1bd8cd4 +617, 0x6a51ef3658d4bd38 +618, 0x31e64c6ff2d1598e +619, 0x20f2f339395fec58 +620, 0xf329aaa477f87f9f +621, 0xfe461c3073c63ad4 +622, 0xa60ce6531c0ab64a +623, 0x527eff919a0305ac +624, 0x7708978a5d010a53 +625, 0x2ab687dab81f0ca +626, 0xa7af71e850497d34 +627, 0x8edba42a07e35155 +628, 0x45b4f3ae5e07472e +629, 0x29e3636e047b7c5e +630, 0x6ddd57807c1830a3 +631, 0x800e6743648c9cb5 +632, 0x921389557585d720 +633, 0xf2fa96f5bbdcafbd +634, 0x4f1634ad80d0bdcf +635, 0x7125668667218b0d +636, 0x23373d9919906087 +637, 0xa27ea3fbff83bd41 +638, 0x871cbab37176d63c +639, 0xe6939db32970f816 +640, 0xf3484c2ce0dd0481 +641, 0x76e8298b27b9d68e +642, 0xf966f9fb426c1950 +643, 0x4066c4f62c307e4d +644, 0x187ddce6f94afb2 +645, 0x656f00e6a70fbfef +646, 0x2ef17886ec419448 +647, 0xbd748ea59342e5d2 +648, 0x1f204c5d3c9428a1 +649, 0xc08854fa8992794c +650, 0x17d0f325121fc218 +651, 0x34c63c258a663b88 +652, 0x60f94e4cf248344c +653, 0xf9ffcbcdce936a7a +654, 0x93ac50ca4456c69d +655, 0xb9039b4d7dd82c9a +656, 0x117e3c6d6891e836 +657, 0xff6289aedb2ab5f0 +658, 0xd5f695f19d6786f6 +659, 0x8bab970181c86e97 +660, 0xee6be4ee832333fa +661, 0x648ea0623082ae36 +662, 0x972b001b4b4d4431 +663, 0x92fb47b9ff9b1ee4 +664, 0x792ed2bd14f8896a +665, 0xc98e2723d55b08d7 +666, 0x2a4f0b7da6210c89 +667, 0x19a1fb785fec7a64 +668, 0x937a44924b337455 +669, 0x26802ce94caeaefa +670, 0x604539849b56a532 +671, 0xccf6eeb0a664d39a +672, 0x545584db524a2307 +673, 0x8ce4edbc37515d8e +674, 0x1d548ba9281312b5 +675, 0xd0c51f891244ed57 +676, 0x3b464ba79600dd6c +677, 0xc28ae0f8c4db373 +678, 0x938e49fcbbe8941 +679, 0xf084e4c8d9799dcd +680, 0x61ca52d24bdd1083 +681, 0x536d617222724841 +682, 0x506cd8085d16a6bb +683, 0x422158a96747781d +684, 0xbd13ded440c16bb6 +685, 0x97913b1b8c2077ca +686, 0x5ab588aab438e8b4 +687, 0xf4c6831523402b4f +688, 0x91e962c39ccbbac6 +689, 0x861c95ffeeb7b7ad +690, 0x6b318a9abb0eb7a2 +691, 0xac4164b45978ce20 +692, 0x71d64942f1d72b40 +693, 0x1675fe85018ea357 +694, 0xe19ef9073183417f +695, 0x3e057316b3a37a7c +696, 0xaccd00b688c8fb36 +697, 0x8c2d1b84d24b89d5 +698, 0x4cc97086400b2631 +699, 0x38c2cb4daafa93b5 +700, 0xd44e889f968a38af +701, 0x53cf738410523792 +702, 0x487b1b84bd6f0ee3 +703, 0x1824ae549bfadd6b +704, 0x7b6654bfe0f085d2 +705, 0xa289e4fa5b2f971b +706, 0x24c971b485491f26 +707, 0x8827b700bb7136a +708, 0xe2871794cd6f7a2b +709, 0xa21bfa8e0e237703 +710, 0x8447f083c77d1be +711, 0x1b1d926efb334728 +712, 0x8dd2d4fed543c38d +713, 0xe69ba3c162cd489f +714, 0x3f9659c66b35acc3 +715, 0x45ac347675850ebe +716, 0x8e572a9ea7ec6b12 +717, 0xd3a11284b37761b9 +718, 0x8e276c1c9616b7ee +719, 0x7a03569e90501954 +720, 0x4ddd0afb9d3f2605 +721, 0x9342896d66482c8c +722, 0x9edca50722c69db6 +723, 0x3dff88b2257e3ae0 +724, 0xad92c2d56ccd8d11 +725, 0x81e6dc441c0b6df4 +726, 0x1a8a0d10f7326b8d +727, 0x8382991eb90958b +728, 0x9570d9b1a0527ba7 +729, 0xa1820138d6f96490 +730, 0x1c8c678ebb2aeb4c +731, 0xd782fddd578fc4ec +732, 0xc78d60cf41e509fa +733, 0x82dfbe4d435f747e +734, 0xd9a410610e4b3dca +735, 0x2d687c7a90220751 +736, 0x6838c5d233cff81c +737, 0xe2e64ef24f7b004b +738, 0x65c11d97293f0da1 +739, 0x53e2016d79145a35 +740, 0x3ebd6882b1de3c7c +741, 0xb1b47458c2b31ac5 +742, 0x4321907da2d2df2e +743, 0x57f211e1521e0eb9 +744, 0x25798e7fa3227f0 +745, 0x9e696273f7255ec6 +746, 0x784755cb23c3190 +747, 0xd4e82b43d8eb119a +748, 0x894047215bf58241 +749, 0x71545bb714d43bba +750, 0x3eb48187007c99a2 +751, 0xd3a03fe5a57dde89 +752, 0xe336d1bfc90141f +753, 0x13e5b11c8ab27b7f +754, 0x476e5d1c3f5ddb41 +755, 0x7e0987fb7ea434ca +756, 0xa7af6d90f6868d59 +757, 0x16be8514db2ba69b +758, 0x9358b7eb6b64161d +759, 0xc6e6e49346403b75 +760, 0xb8738eaf21cb369c +761, 0x65a2a7d3ad804624 +762, 0xf49f135e789969d4 +763, 0xf20a963cbeeaae3a +764, 0xd17e058559753d56 +765, 0x8e8bf41d9c4916ec +766, 0xe48ef68e5aa23dd3 +767, 0xe2f0001eda60c8bc +768, 0x5b99e00b24f1aa8f +769, 0x4ad710b2a99b14c8 +770, 0xd3aa3920af73ddd7 +771, 0x3d76e216667d1382 +772, 0xa8c330ec75317940 +773, 0x12534fc207bb29a9 +774, 0xd15c55c83b4a35e6 +775, 0x535e26026622714d +776, 0xb56782cf34123bc1 +777, 0xbd925db7098d6155 +778, 0x682df0f1e54e2d9d +779, 0xb330167f33195b63 +780, 0xe9658f089aea3987 +781, 0x2b095fe8bc8fb610 +782, 0x204269c3aa0af463 +783, 0xd1c858c4a6b68013 +784, 0xe2f281cf9ef91e34 +785, 0xc29a55f11e4479c6 +786, 0x12a8e1df7d6166 +787, 0xfa0b4dd7d67c578 +788, 0x6db2b74e2e42db1 +789, 0x478694b16b033d71 +790, 0x47a79614736e8c3f +791, 0x247e0e4d132cf874 +792, 0x22845b7634d0e71f +793, 0x9942faa26a68bb81 +794, 0x381aeeee89549313 +795, 0x2052200f6ff0d6ba +796, 0x5c9f92b675b2f641 +797, 0xe6b34f7a1e196039 +798, 0xe1b77d497bef7516 +799, 0xc59d1b80b7b3b30b +800, 0x819f5098375913b2 +801, 0xca0f73cffdaa9370 +802, 0x2f5bf935c691c5f4 +803, 0xecbd8bb256d09c58 +804, 0x43406aa69a99ecf4 +805, 0xf05f8b2ee179651d +806, 0xb7c70142a0228f54 +807, 0xfc2db144bec4b245 +808, 0x2abce886e1a45ebc +809, 0xaf58b72a59bca78e +810, 0xa52b038f4d4541bf +811, 0xc0d14bf583b241aa +812, 0xc8a1abd7115cf8a7 +813, 0xe02e5a30a769d474 +814, 0x56acfdbd29796da9 +815, 0xe7387234b8b03889 +816, 0xf1227dd110b8f9c1 +817, 0x8b124ad0cb62d460 +818, 0x97b7c747f3b13887 +819, 0x216f43a8fc2314bf +820, 0xaec316edaf92f3 +821, 0x10186bef157d36fe +822, 0xf37a7ddce615aca1 +823, 0x9b5b913d16158f6c +824, 0x59be9a31bf90f02a +825, 0x24170e196a66a0a0 +826, 0x589a9527086fc354 +827, 0xc5990d0f438d434a +828, 0x90eee29b52e7a094 +829, 0xb703a0dc266849dd +830, 0x6d0bff0ad3ad2faa +831, 0x91f7fc0cd9e78804 +832, 0xe86041baf693528d +833, 0x1efabed627bb50a6 +834, 0xb59397e5f2895f58 +835, 0xd07f3b88397416dd +836, 0x340f1719b497c11e +837, 0x284e6cb714f9b6 +838, 0x185fc6ffc0b68229 +839, 0xfa2deec9e6c26b24 +840, 0x62c6578b4b262188 +841, 0xad4109b1cc118f48 +842, 0xa395d493b26d6f0e +843, 0x325b4fe3d0dd4338 +844, 0xf91410de49c18d30 +845, 0xf07bf8b60923ce02 +846, 0x1423fe617d564876 +847, 0xc077f782126eb9cf +848, 0x2fcb2f20910e89ae +849, 0xc2bd451afd2e6816 +850, 0x77fb4184cb7d54b7 +851, 0x3f179aed62349343 +852, 0xd9186ae032d49425 +853, 0xb5eb57360137bdf8 +854, 0x3e4be92a340c6331 +855, 0x8429236eb3127098 +856, 0xdef72542e2b2b80 +857, 0x63a489df51948c4 +858, 0x8a7e00c797fde2b4 +859, 0xaf0ecdb100a40c24 +860, 0x5861013d27e2e75b +861, 0x755b9daf64e225f3 +862, 0x3d2df8752fc1f0a5 +863, 0x603430c7044c9cc1 +864, 0x861421e1eacce08f +865, 0x617e02ea4d46a34c +866, 0xb5a65006a14421c6 +867, 0xb0f80b679b414c72 +868, 0x9906164388248865 +869, 0xc9c844ffa4051128 +870, 0xca9d7bf3530f5c33 +871, 0xab16e556b494c5ee +872, 0x7221a1b8ef1aa54d +873, 0xc271845c7d1a4e37 +874, 0x6a76797104475a2 +875, 0x908e423fb8735430 +876, 0xb5bb58134b1677c +877, 0x9ffdd2ae9c3118c6 +878, 0x7e180fcd6840b8cc +879, 0xf94537df07d2fdc4 +880, 0x5cc348554d45bb14 +881, 0x3d4daf3c2b6664b9 +882, 0xfd04db3f786791ad +883, 0xc493d37c83bb96d2 +884, 0xbc9faef5435f86f1 +885, 0xbc65cb3d3f6e9d9e +886, 0x9cbf2ffa56e6ecd1 +887, 0x9250836b7c20ad40 +888, 0x4f5c0071a0db9a4f +889, 0xdc3f0522b1445aef +890, 0x7506e5599b850a1f +891, 0x81ed2abe0e2de08d +892, 0x240490146352067a +893, 0x3c77af13f5eea2cb +894, 0xa7f4cdb8ff827eb4 +895, 0x1417242e31ad2476 +896, 0x76016b03999f9478 +897, 0xf94521fac0306668 +898, 0x8269175893be1d41 +899, 0xfc753632a234f285 +900, 0xf612755268cace8d +901, 0xa14828c9024be019 +902, 0xfa70c71b9d1eaf55 +903, 0xdf1b71a62e31de5d +904, 0x5501951e0e1edc8a +905, 0x2f8f803b8df69cde +906, 0x574f363439f7da1 +907, 0xfb10c35585727813 +908, 0x749b3c2837397d13 +909, 0xf3cdd1febe8cfdc7 +910, 0xe394963ee5056211 +911, 0x577d7d7b18de73af +912, 0x47ab5d83b0c59c10 +913, 0x9dc8a3fadd1e6f9 +914, 0x83fe8257e75854d6 +915, 0x2e43cb3aa0046160 +916, 0x1dc475fcab4ac1dc +917, 0xf0bc49e0566ce0ec +918, 0xb603cdcf1f30fa6d +919, 0x526760cc6bb6babe +920, 0x7c1da274cfc404cc +921, 0x1e7f5020e4872eb0 +922, 0x5810d9ce7b4eb5d8 +923, 0x5ddd35b6fdc8ccf1 +924, 0x3384120a60586e91 +925, 0xbea2bd919e0f3ce9 +926, 0x5a5e242545609467 +927, 0x4bde47bcf26eb4f6 +928, 0xb0a735deefec6c20 +929, 0x68a22c177454e398 +930, 0x8c9bdb2d15db7858 +931, 0xcf3748c5ce8663d9 +932, 0x4815c2a33d2e0b89 +933, 0x8ccabff1a06d51a8 +934, 0x9a5ac9d5cd9bde72 +935, 0x1dc5a9d71a51705e +936, 0xbcdb2971a66f27a8 +937, 0x31b0cd0bd56e4640 +938, 0xf7efe6b1f1f5dabf +939, 0xc5c99d9b4fb22013 +940, 0x1ba119bae4d4fba4 +941, 0xf65a6d9da77cc4bd +942, 0x25cd9545d90e715b +943, 0xb7477672a3531ea3 +944, 0xcf247ec31abeebc4 +945, 0x7e057e2450496fbd +946, 0x38ef5e25d359c979 +947, 0x4c19225c27c2eace +948, 0x2f0a528453e09547 +949, 0x59c8f78eba33f6bb +950, 0xfc8e46c35ef2fd53 +951, 0xad32d2fb43958df0 +952, 0xa4925809889d9dec +953, 0x91511a8ded719be9 +954, 0x8bafdd3b61b109d +955, 0xedc9854399b02ea8 +956, 0xa50a9ba9d3f10ac3 +957, 0xbd94acf2d2a1833b +958, 0xcdefa8e500cb91d6 +959, 0x95d64c722dd9ce9c +960, 0x2593274b7561d701 +961, 0x9d5854a252f7d4ee +962, 0xd799bae55a43bac4 +963, 0xd56a4f738e03f65 +964, 0x9c100f2599fe70cf +965, 0x1fb9b7564fd6984a +966, 0x16ca3ffcfbc77ab5 +967, 0x3a98bb3993bfe243 +968, 0x7fc4a69a94fc389e +969, 0xf4adfc0494731b85 +970, 0xd691ed499cd189f2 +971, 0x7207391cf3664115 +972, 0xae2186bf1bb2773 +973, 0x5f10cea41eee2bd0 +974, 0x35f3303dba442fce +975, 0x41f7580460af8f7d +976, 0x6f92dcae967f8045 +977, 0xf8a23d127dfb64da +978, 0xca2955a095bfa56d +979, 0xf5f9a75318e0b668 +980, 0x94eabcf4d9fffbc1 +981, 0xfb5f2b3c85a44eb +982, 0x1edb77bc0d4ceef1 +983, 0x98bbacdb3bbbfc39 +984, 0xeeb6d6bc48b6156e +985, 0xc9c56b8f2fa29b0e +986, 0x22f31ccb223886d0 +987, 0xbb7f3e16bc706aaa +988, 0xe38c1e50cd965c52 +989, 0xb15aa0b68271c538 +990, 0x1c0dba1cfa587e61 +991, 0x70f267cd2d88e846 +992, 0xa439b7443ffebc10 +993, 0xd586c99b86177873 +994, 0xb05ff9807bdcb212 +995, 0xd7c08bd208fc8e05 +996, 0xd11063113d01ac5 +997, 0xd4c9beffc525f0b8 +998, 0x3d7303181643bc80 +999, 0xd75ef9b19286142 diff --git a/_randomgen/core_prng/tests/data/xoroshiro128-testset-1.csv b/_randomgen/core_prng/tests/data/xoroshiro128-testset-1.csv new file mode 100644 index 000000000000..8289ff27eb96 --- /dev/null +++ b/_randomgen/core_prng/tests/data/xoroshiro128-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 0xdeadbeaf +0, 0x86f9f4feeebed928 +1, 0xcd2c9d2d1dc1c071 +2, 0x94741e0555641979 +3, 0x81eed88d38a9138e +4, 0x54b9f49cd0035507 +5, 0x8c112b85821a173a +6, 0x51f4c2eabf05c192 +7, 0xefa6a9ad4ca56d94 +8, 0xd3bd969b3aeb5457 +9, 0xcd4f28af5618e25a +10, 0xa20fd197fb60aad +11, 0x796b5146f61afc52 +12, 0xf6fe619effce6d62 +13, 0x763ed6613d00e8bd +14, 0x333d357571b249c +15, 0xc2a39f35ba8f4ce6 +16, 0xae35d916c6cf8a2b +17, 0xfdfaa6b7eb9591d3 +18, 0x52668584489de943 +19, 0xca982b4b760effb8 +20, 0x32c7256797c26f09 +21, 0x3115b9539d722cc +22, 0x5183f1d23dd2f56e +23, 0xa0a2a2c524e6650c +24, 0x3191f4b5260e5a2d +25, 0x1eebe2655fb4f190 +26, 0x5781c6b75a253a88 +27, 0xae45a39543b4140d +28, 0xfc62724b20d2df78 +29, 0x3770290ba157dc9c +30, 0xc4731569807dbff4 +31, 0xd42ec771a7a0a08f +32, 0x743276e0eb868d75 +33, 0x37f95d1ba1faebc6 +34, 0x3b4800b089a323cf +35, 0x437fa9c71af61839 +36, 0x1cab936dd28c6f1c +37, 0xe9d60347286dd9f0 +38, 0x716625cbd57bbd63 +39, 0xbd6c0f5e6aea7288 +40, 0x7c782d5b111a89f3 +41, 0xaeb1b9478b99970 +42, 0xbdffccb6a96cb533 +43, 0x9423e6ea789f29f1 +44, 0x53df9a7a0ea73fe6 +45, 0x7d9bec5c15c7e349 +46, 0xd1fc83fcf223aea5 +47, 0xd1dce35338ad3bab +48, 0x297bd5f1cf79e758 +49, 0x19ec39a6191419da +50, 0x45e57323ad58071b +51, 0x395bcbebe1ddf611 +52, 0x22d9065efb013222 +53, 0x4ea2d534fd9fecb3 +54, 0x9b9779e1edeb2e27 +55, 0x1ba777ba576a236e +56, 0x23cf95e34d62dd3f +57, 0x6d1689730795e6bd +58, 0x24e510f9d2f65379 +59, 0x1e12d607e78701e8 +60, 0x3347fe3ddc50a23e +61, 0x331754f825305d97 +62, 0xf21a675c0344709c +63, 0xcc9bd2062ae5fb39 +64, 0xd2dcd3a1ee6afe9e +65, 0xbdb0388382c408d1 +66, 0x19476497aaef64ad +67, 0x906dfff3b1181dd7 +68, 0x47edd3c528f4c753 +69, 0xba2a0f289279aec2 +70, 0x710bc73fd1c732a9 +71, 0xe0238b1ab604610d +72, 0x10f68d7eb0d19e19 +73, 0xc13654f8b8f3d9b7 +74, 0x112c76bf71ad04a9 +75, 0x4b9d965062e9a0fd +76, 0xe0b13496fec19aa8 +77, 0x999493dababe73c8 +78, 0x87104db5240f12fb +79, 0x8fc8dff016c96a13 +80, 0x3eff4853e8b167a8 +81, 0x438b6f5c3d10b85d +82, 0xc2f94a0707d949f5 +83, 0x87981b13beefb01f +84, 0x1718db5072923bb2 +85, 0xbe7ae4310234b5f1 +86, 0x3ad4306f2b2b3b47 +87, 0x9de166baaf152f81 +88, 0xebca2cf057a00802 +89, 0x99bfd19b5e0a87b2 +90, 0x5ae7b3ab9d2623c0 +91, 0x8de5811587a53d2e +92, 0x629a57a87d068ee4 +93, 0xfd80a82607740601 +94, 0x5758bfc8610d0b8b +95, 0x8f0c00fab932c1f5 +96, 0x3d49bd296a34582d +97, 0xc99c1bb8319ce526 +98, 0x1dd5ba47ac1443ba +99, 0xb5a40a33c9ca1cf9 +100, 0xa1025156b711394c +101, 0xdb3ef94ee8bc71a4 +102, 0x6d3292123ffa9bc9 +103, 0x4b9683ebf2f98d1f +104, 0x4d1a4709b547bfe7 +105, 0x3623a9c4054355b1 +106, 0xed15f8852d329b4d +107, 0x60ef76852f40e346 +108, 0xe64c2bfc6d0ef2dc +109, 0xf286f874cfb68ee2 +110, 0xb1b07a7ca9268329 +111, 0xf618a9bfe00b7cdd +112, 0x54a40c4f52cab527 +113, 0x5007a4d41eaf0af1 +114, 0x6fa7f2210a7b7f3a +115, 0x7b448faa473ad765 +116, 0x901b6276232cb3c2 +117, 0xd69d06b85d118dfd +118, 0xf8fb03c5dfef937a +119, 0x5a53e96d5ebc4689 +120, 0xe24e81bbd9772b3c +121, 0xa996ed94405e1811 +122, 0x7d8712833a4cbd96 +123, 0xd8b81a509f392481 +124, 0x76b52a270551424b +125, 0x4c854325eaa4ef23 +126, 0xc8823e5a74757b2f +127, 0x9ac8deb0aa215a3f +128, 0x89641160b3eeafdd +129, 0x17781aba3d908856 +130, 0xd12e5f215de0a3b4 +131, 0xd94cd412b8bef057 +132, 0x40e85ebd5844b9e8 +133, 0xa581cf7ef62e70a2 +134, 0x74953df639f8a9a2 +135, 0xaa92c9804434caa6 +136, 0xf186398542a15448 +137, 0xa0888e1233d64da3 +138, 0x277d14f22bc64c91 +139, 0x2851b3b5fc49ad5 +140, 0x68182666788909 +141, 0x5ea068625e49839 +142, 0x63bac5a5d225e8db +143, 0x2dd9db0ad24aff05 +144, 0x3f637e71528ad6ad +145, 0xe3b7ba911c4fe47 +146, 0xe4bcf50c8ada7ab6 +147, 0x4470ffb01cd6980c +148, 0x377cfdbe8e810731 +149, 0xdb33ff37954849c7 +150, 0xb622ead14010ad64 +151, 0x6c44d65c7a81a5cb +152, 0xd99a3fca5a5d9fce +153, 0x24e7360e1ee2efd4 +154, 0xbd927a3fb576d81 +155, 0x1ea3f2b7c909ffb7 +156, 0x48aedb2bec244a7e +157, 0xc17d9539cf53a5f7 +158, 0xe4ea45fcf4de590b +159, 0xe1d863ebb77cb7de +160, 0x8ecf0bc8d88fefe4 +161, 0xa881cef3b3209e05 +162, 0x8f34a14a6978afb6 +163, 0xed4e2e5e1f4966fe +164, 0xede897e11cbe230d +165, 0xd344af5e50042d6 +166, 0xb2739594ba906c81 +167, 0x83c0bbde6d95b632 +168, 0x6b7ae9d1c4af98b2 +169, 0xc4b8f6816eae17f +170, 0xf8e3a6bf7855bd3b +171, 0x9f64ff72d6357488 +172, 0x50b6a304f9543f58 +173, 0x330e8281e591cc6e +174, 0x15dfdd5af7b421e3 +175, 0x8d3224e62524222c +176, 0x90d89d139a75b44f +177, 0xf6efb68e15639dce +178, 0x98cf64777861f844 +179, 0xa031e78e4b3a7b3a +180, 0xa3647dbd85c538eb +181, 0x73656c8c77d9c56 +182, 0x88840b683d4fdb72 +183, 0x3b84749774eac55 +184, 0xb9b753a86ec15b39 +185, 0x31ab026ace06b686 +186, 0x4fd37ef5b5b1d284 +187, 0x7cc6c46fb114a76 +188, 0x463ff22f392dbd4c +189, 0x188c3718f2068889 +190, 0x769892f97d895302 +191, 0x9838246e76757b6f +192, 0x546a68f394c391ee +193, 0xc9e32a7d2a7fb559 +194, 0xd84ac91984217239 +195, 0x82ef273042519aaf +196, 0x79650a2c9bf2a812 +197, 0xb7aa6dc1c23eaecb +198, 0x60326b9e25b055d +199, 0x6b17c296feac0e6a +200, 0x7813f405baa0d85 +201, 0xb9d52400dcb399d2 +202, 0xfb588178727e0012 +203, 0x448763bafa3d9095 +204, 0xd63fd1757e94e19f +205, 0x2bc98e05f296e73 +206, 0x9e05ff0a641889cb +207, 0x1e1716c76c9a8990 +208, 0x9e2f67e555f5389 +209, 0x430a8a612033934b +210, 0xd49a74a4d8743bf +211, 0x7b08085a0b4aee34 +212, 0x2c0482984960e7c1 +213, 0xae26bcde5d8fe8fa +214, 0x8f40022b951f98c9 +215, 0xcc59b599dd0383a6 +216, 0xb6833d7a5e00c373 +217, 0x3e025759aba46bdb +218, 0x2558a3dd775dee09 +219, 0xdcd8370368d091a8 +220, 0x9e55348e5734fa9f +221, 0x1061a08056830eea +222, 0xdca96b36adc5ed23 +223, 0x8563d7d016fe5d7b +224, 0xa3fb6b79b0095ee3 +225, 0xb887cd180ae6f882 +226, 0x670e10186fda74a9 +227, 0xa25f08a01b69032e +228, 0x5d90bfde7e21c0c8 +229, 0xb1b154f328250786 +230, 0xe0050135775487f3 +231, 0xbd7001fa00656593 +232, 0xcb6136e259180b69 +233, 0xf7480387c0872215 +234, 0x2e478a3efc5a7ec4 +235, 0xeb1cad9cb7d82f45 +236, 0x5d4c127c6c060ca3 +237, 0x1f9efe7a0bc11db5 +238, 0x59b9712ac8f24207 +239, 0xb94edcfe7b8e7ded +240, 0x474b672b27aef61b +241, 0xc2150760d3da0859 +242, 0x1146d26c90b6becb +243, 0x52926b0e9e820413 +244, 0x24f2b065f78bdaa5 +245, 0xf94b5372ca68e5e +246, 0xfdf3e645313db1fa +247, 0x181af7ab689d2ec7 +248, 0x1e275b8f25520a3 +249, 0x1f287f3ff3d55dc8 +250, 0xa035801d4747cae9 +251, 0xba6ed878f55ebd +252, 0x74d6598302a5c786 +253, 0xe92ce6198f39ded4 +254, 0x7b811ab7cda273c9 +255, 0x9d17fb60483addd4 +256, 0xf2b457f77ba326f +257, 0x32e5956d2a580c90 +258, 0xcba559493cdd2b6 +259, 0x59276c178ca0e7a6 +260, 0x509681deb2f0160b +261, 0x1bc2df48eb8f2a3a +262, 0xbe7f17f92c808cd8 +263, 0xebbcd3a312ab80b7 +264, 0xef85e7595c591a83 +265, 0x914028c61432c620 +266, 0x7d8f67244eb3ea9e +267, 0xa0512684d8ca4355 +268, 0x5a12209ada976a9c +269, 0xfa0cf430c33df55c +270, 0xd514dc8064688736 +271, 0xc5020a78e10201f7 +272, 0x9df7e30707f4591b +273, 0xbc41eeb3c45f4ba2 +274, 0x2b5605d64a470e5d +275, 0x77753b9a125af99a +276, 0x7ba925c3af8e2a4 +277, 0x46c1dadcd05c1165 +278, 0xcb64cd52411f993 +279, 0xa6c3c1f065f7c758 +280, 0xad68088813a0068a +281, 0x6dd039e4b9d4631a +282, 0x528f220f2f54270e +283, 0xfe565ea36805959e +284, 0x3f2edbdc64385933 +285, 0xf0ea2fe07768bf3a +286, 0xd120fe046bfafc74 +287, 0x85c1b029a6d56aa1 +288, 0xb03c986da026593d +289, 0xd126fed2a4ca68a7 +290, 0x7e63d8216bc42201 +291, 0xadbfd88dcf50e179 +292, 0x6c1c1308ee42ca66 +293, 0xf5415a024cbf5458 +294, 0x4e50d4d388352815 +295, 0x38949c203a1a34ab +296, 0x3a35d5ff38274f23 +297, 0xc96c009af2982c00 +298, 0x581691437bf0b1e7 +299, 0x793d1a61f0b0dcf8 +300, 0xa36a3b1c3e39c61e +301, 0xff2938c1b78db0fc +302, 0x1e82a7fc6b7c4725 +303, 0xd91883febcf4672e +304, 0x22c55d5c95f1d985 +305, 0x3fc97236c50bfce1 +306, 0x28a3e0c7a4380bcb +307, 0x2c072113ce5f2570 +308, 0x9c816b6af1d912a3 +309, 0x83698f6af8e41daa +310, 0xa7b1b189d398eae5 +311, 0xb5b44ce05dd0867e +312, 0x5ceaebf68b501f84 +313, 0xdf384c2545db9168 +314, 0xa75eae42ad85396f +315, 0x88273ff551afa924 +316, 0xda2c47046eabd9f0 +317, 0x18d83b83988fa9bb +318, 0xeed5ad076674a6ac +319, 0x28d969bd36a0d5e8 +320, 0x9259eebb564cfd98 +321, 0xdc2e175377ffcd6a +322, 0xcdb19c84396bc51d +323, 0xeaa3a7674b5e5da8 +324, 0x9bd54f94110b36a +325, 0x88d96179c0a35528 +326, 0xea1536654ceee668 +327, 0xdd1cc9d40ad3ea60 +328, 0xe9106bddc3221293 +329, 0xe096d5b5acd9ff46 +330, 0x4cb27170156f9265 +331, 0xd0d3e5b9edadb2bb +332, 0xf75347484f2af9b4 +333, 0x6170333a4e6885d5 +334, 0x99a50b6b702b80ba +335, 0x10629a67c9781899 +336, 0x374a33743030da9d +337, 0x289fdbd0bc89f257 +338, 0xa67c56d1bc5dc5dc +339, 0x38e90cd1dd6d64f2 +340, 0xcc5ed5dc4955655e +341, 0x723d33bae999723d +342, 0x46af17f0c981605a +343, 0xd1d3a915f899b0ff +344, 0x9a60c9bee03dcb43 +345, 0x11753a29a1d9201 +346, 0x491c99adde4e0a73 +347, 0x634437d6dc4388ea +348, 0x5f4cf58d810069e0 +349, 0x8d950ed29ac1703d +350, 0xa6330099182b17e3 +351, 0xfc9bf9a5cd4ea35d +352, 0x4560dc5769ff741b +353, 0x374a9ff29ee966ba +354, 0x16a9bd5c9214e40d +355, 0x46fdfb2899af3e80 +356, 0xe2eff8b6ad57da07 +357, 0xa67c709690485024 +358, 0x87551c8907b62ead +359, 0xde03a75e08382365 +360, 0x6744ad2be09ed2c1 +361, 0xb34ec9f71efb1f48 +362, 0x4fb71847ea9a525a +363, 0x10ffcd51ebb2f5b9 +364, 0x489431753bfacc7b +365, 0x7a9cc00b29aa7802 +366, 0x8017011d2285ce9d +367, 0xd54d90e061d61b87 +368, 0xa41a40e4a81526a +369, 0x47b5ba075adc3b4c +370, 0xb8cbbc5498cc428b +371, 0x6165fcf1ef4795b +372, 0x57926a7aebb26866 +373, 0x226ec9794dd0714f +374, 0x2759cca87ce9a2ed +375, 0xb41a74ac376c84d3 +376, 0x3e8101b52e2518a6 +377, 0xc8f18bb165e3db1d +378, 0x187f3ef2ff1093d2 +379, 0xb5c1069cdbe57e46 +380, 0xd3f342f3104a5902 +381, 0xf32e59c6c7b8458 +382, 0xfdb39f79b5b1f574 +383, 0x526dce2fc3115682 +384, 0x1a2e8128c0180ae +385, 0x5eead6a0e587e4c6 +386, 0x450e7d15d282c580 +387, 0x931a6cd04be42fe5 +388, 0xb4d321f03fb71277 +389, 0x32479d856fd9bdfa +390, 0xa28dc713e419022a +391, 0x6c8dcea6b5adbb14 +392, 0x4ae7b8d58ef7aa3d +393, 0x49903e3fbd56493e +394, 0x5238b0c9ee856f3b +395, 0x77deab4c733cb2 +396, 0xea5d74aec663c8dc +397, 0x899afbc707b0899 +398, 0x56a9418f18219182 +399, 0xb42801a6445d852a +400, 0xd8462e581c7cd53b +401, 0x802701332acff0c8 +402, 0x309618a5c049ddaf +403, 0x66f6d281cd986fa +404, 0x53f089859dd3e861 +405, 0x497078aabbed67cd +406, 0x9cdc9d89a2e1cc9 +407, 0x871b1721c6f463c4 +408, 0xe9f8872d8f113d84 +409, 0x48e03acc1ff301b +410, 0x79d5f73993eb02ef +411, 0x5ac76f9f2329e39b +412, 0x878c2c8d84a9643a +413, 0xd1d0786d40a7391d +414, 0xf024ad81eea63787 +415, 0x9f96b1146e5354b3 +416, 0xa85fd9a5bc0fc195 +417, 0xafd0522c28edfd2f +418, 0x6c1aa508159a1fcd +419, 0x873f632373719c87 +420, 0x5db129eaa27ff3d1 +421, 0xd81037e5b49f399d +422, 0xa40a347abfc43a81 +423, 0x314452aabf5a95b1 +424, 0x6f8642230a3edee8 +425, 0x2aaa01f7cc73fb09 +426, 0xa0ebf15ee345343 +427, 0x19fddca117f16f35 +428, 0x111be87b23ca2143 +429, 0x46de5fd13663c896 +430, 0x2dacbe0fca5e4efe +431, 0xd534f9dce19043c7 +432, 0x7a548f9a35a6759b +433, 0x3c6f046dd15b6fe3 +434, 0x1f7a17cbfc090519 +435, 0xd8a282357a83d2ce +436, 0x96a8a5cfb5be2843 +437, 0xce416b54c95c6006 +438, 0xcda9d6127cb716cb +439, 0xb062a607b35aef78 +440, 0x141e913718707191 +441, 0xef829605cf4aa346 +442, 0xb9555c4c76d6a7c4 +443, 0xd41bd4a1593170ca +444, 0x2e00143ad3d88b4d +445, 0x1afa722d16ac1d47 +446, 0xa22530a5d53159c8 +447, 0x17f76921e5633a50 +448, 0x8e3ed4b11072799f +449, 0xedb6ace0cb513a05 +450, 0x8dbf3d235449385e +451, 0xd01fb688b01b798f +452, 0x8e3aa7aa93ab0436 +453, 0x8b18ef4c8cc20636 +454, 0xf40181de15f5029a +455, 0xfcf54366f31c924b +456, 0x7b16e64f5c3a1d71 +457, 0x6b5f96df49784c48 +458, 0xcb5914727615bb07 +459, 0xf228f7b32ec2d237 +460, 0x37c51a8a1b854a84 +461, 0x63484491b02c7fac +462, 0x526a9f0a571e170a +463, 0xeb8d59e7fbbe583a +464, 0x4fd1fa3bd32b8c84 +465, 0x825ba1ed08b31e1f +466, 0x644d2cadd8ddeeb2 +467, 0x3874924732d3c6d7 +468, 0xd2679fee287a403a +469, 0x17ddb27712b6cdb9 +470, 0xcce6bed3fa81f460 +471, 0x8a2df0f2ccb3f028 +472, 0x85d166e4456aae72 +473, 0x5dc4ce3fab56777 +474, 0x555b2c69b6eabb7 +475, 0x873bc152fdb3717d +476, 0x5670068eb7d52805 +477, 0x7f776ca61f79e219 +478, 0xa8b51d2bd8c8c939 +479, 0x50345828de969faa +480, 0xbefa083bfbd71b60 +481, 0x883809b883dffdca +482, 0x49ccf930ea76fce8 +483, 0x97cc45c4c2dcf12b +484, 0x4d3aef2e2a4a450b +485, 0xc7ed768e40efd44d +486, 0x5530c69ecdc47b2c +487, 0x2fbb8ad65b3e777a +488, 0x45234e14d9fd969d +489, 0xb6a758912ec87c9d +490, 0xb35f335efeac2d3b +491, 0x21efc82b1e65a1cf +492, 0x897db9fe20a2702f +493, 0x444042b714793c27 +494, 0x37356cc844e57cb7 +495, 0x602ecce617309266 +496, 0x4ea323a5d93363b7 +497, 0x2c2f0344303d7067 +498, 0x983de14baf7a9234 +499, 0xc4edde0900601361 +500, 0x12574e754cf862a8 +501, 0x82eb774465a3a83b +502, 0x115fd6ada32ab10 +503, 0xce23f43213ea118a +504, 0x912e289389130f18 +505, 0x977464bbb2fc0cd9 +506, 0xeb944201e2747c79 +507, 0xa41dae77205e05ee +508, 0x66c91981aba16d08 +509, 0xbd4aefbeb385af57 +510, 0xd7c7d36c0ec75862 +511, 0x492e43720ebee40c +512, 0xf44861d4636833df +513, 0xb9fb92c7203e2a1a +514, 0xd75f7f48e860938b +515, 0x8235d433d3e773f8 +516, 0x36cc65bb70a32774 +517, 0x3898d9516512bffa +518, 0x4f5c36707161dc35 +519, 0xa35e3d81512f0a8e +520, 0x4ae50933ef7bd3b9 +521, 0x641dc03f71dc81f3 +522, 0xc6002d833e1d768e +523, 0x6c7d94f79b7a1956 +524, 0x4027405ac3c6e666 +525, 0xab69f022928e86d8 +526, 0x90272e57839563ab +527, 0x56e78769f743d98 +528, 0xb5c7931145b93a39 +529, 0x253fbe3201939650 +530, 0x5325825cbe56c3a9 +531, 0x159aa2be6163c7bf +532, 0x56b8d5a5ed375c9 +533, 0xbd4b45a7cce10f56 +534, 0x2f799de5fd80339e +535, 0x40232bd30ebb82d2 +536, 0xc10e2198616b20a6 +537, 0x6a13ecc0b52813f +538, 0xfafd5d5b466ee59e +539, 0x810cbf398208d400 +540, 0x7137dc6f08e5b6d3 +541, 0xfe59d9caf7564d0c +542, 0x3117cae7c6ee6927 +543, 0x89e83cf15785a430 +544, 0x386b6daed57236e1 +545, 0xc2e6fb38df98a4dc +546, 0x496513da22e1e53e +547, 0x57efdf29edd94aab +548, 0x3433ac46ce163ef3 +549, 0x296565c39cba14f3 +550, 0x1ce89ad8ff370a6f +551, 0xcb12c5a7db52fd27 +552, 0x8125373ad475530a +553, 0x75ed8dda02fd5bbc +554, 0xaf2c279596340f93 +555, 0x18c7f80478479a56 +556, 0x14edf2ed871d9c41 +557, 0xf35731f0b8d26e4a +558, 0x2cace2d1996272bd +559, 0x84c3b017f5b12bb8 +560, 0x441c286a303c81c8 +561, 0x92a7c594c92b2353 +562, 0xb175a7a7e0cab31f +563, 0x501d7003cb9e530d +564, 0x1e9d3dea32bb5d6 +565, 0x60756fd6e4b239d2 +566, 0xf979b4c7ddf4bb22 +567, 0x1e5c0ba3d2797a7a +568, 0x94590d4209c70c70 +569, 0xc5dbc6ef6fd8c203 +570, 0x46a0eb4fc61727f2 +571, 0xe3ddaa7f4033fcb0 +572, 0x4fc177555a6b2f9b +573, 0xce0f6ab675596a18 +574, 0xe11a08478844ecec +575, 0x47054780433de44 +576, 0x89a3be9609dc2a34 +577, 0x9ea612c49a4c170f +578, 0x8212e9db2df9ca7d +579, 0xdf1cedac92affa7c +580, 0xc21b0ff068580e5a +581, 0x49168be340b1ade +582, 0xce3a5fd54225a6a9 +583, 0x80ecff24ec6cdb9f +584, 0xd14429e950a1a21e +585, 0xc66a1ad3cad8f9a6 +586, 0xcc76bdca3ded453c +587, 0x748165a5cb8b6bd +588, 0xcc77eb3966db7c5d +589, 0xbaceadcc1db342d6 +590, 0x33b42e3dc005fc38 +591, 0x43b5661eead65675 +592, 0x356821fd43c46e5 +593, 0x4efdd2444e0c5ffa +594, 0xf84ce60e2c0de959 +595, 0x14a4b1dd26583f04 +596, 0x6ffb885f5fe18b87 +597, 0x8233b6a95b1af132 +598, 0x7e2e9c449dd06b71 +599, 0x736bc96174cd4d97 +600, 0x86591ab3ab385777 +601, 0xb7696e3909a91039 +602, 0xda363e1a90c99d9c +603, 0x793cd7e1855b9a43 +604, 0xa9dbce0ccacd24c2 +605, 0x5d9a1d9b06fcf2f2 +606, 0xa7db7fd7c2b50d55 +607, 0x13c85aaefd37bf77 +608, 0xcba5689a383aa436 +609, 0x7dcbc3e297d2bd31 +610, 0x9860da13006164e8 +611, 0xda3be955750ba8a6 +612, 0x57f6a78ac6d2cb3 +613, 0x861ed21955702cef +614, 0x3cfdfb6fa0763186 +615, 0xd075f803b072f140 +616, 0x6b1622638e94a714 +617, 0x6f4b177c0213a295 +618, 0x26c113226bbfa72 +619, 0xbcb962e03d008ba7 +620, 0x1e50555d6e75d9b9 +621, 0xd67082f15ff0086 +622, 0x20766d0fc6bd729b +623, 0xeea24b2ecc4db639 +624, 0x3136637be559ec83 +625, 0xd3f2c641faccfcf8 +626, 0xe43f5bfe95bfb2c2 +627, 0xbc801108984335e3 +628, 0x19ff6b0c435e06a1 +629, 0x7b8f28c44eb5195d +630, 0x375460c52c467757 +631, 0x534f4697a2a2f0d3 +632, 0xbd1aed6c1a94e586 +633, 0x9dec33a59dd000e1 +634, 0x4611fc38e6902126 +635, 0x1296da2fca821b09 +636, 0xce4684ac8861a6b7 +637, 0x16bdaa7a0563d3c8 +638, 0x22a6a8b6de1fcd10 +639, 0xeed5c457b2d2a399 +640, 0xb66c697c0e328f69 +641, 0xe678d6d573b2dc21 +642, 0xd0a78328399774d2 +643, 0x7fee339fadd44eaa +644, 0x32c2da48753c8818 +645, 0x691f87af10bc6f5c +646, 0xe382722ac6ebdbb3 +647, 0x28bb87557931a39f +648, 0xc3aba948d7d22fa6 +649, 0x3ce7016f24e2f50b +650, 0x863b408ab8161d28 +651, 0x1e3d2d6746c16b31 +652, 0xe5a21dc5843a37d6 +653, 0x8ecb559ea375c81d +654, 0xff2681b83a599f98 +655, 0xcd9893140d02b725 +656, 0x80294d390a4e1a08 +657, 0x254166d362613f84 +658, 0xd2c336ba5b4ae618 +659, 0xef79a05286b75aaf +660, 0x704140e00e02ea9f +661, 0xa2623b124bb92365 +662, 0x2225846e393c249b +663, 0x95676d7c7aae81a3 +664, 0xe0cbe12ba194b3d9 +665, 0xda8ca3d800ea6152 +666, 0x8b2c2f63db05c887 +667, 0xf14012751ef435e9 +668, 0x33820fbd9a06d78 +669, 0xf37375a008192ae8 +670, 0xaa2c34f4b405589e +671, 0xd26bbda155ac158b +672, 0x418b108b101ea70d +673, 0xb9648a82ca0617d7 +674, 0xae6e2213c8c0d3e3 +675, 0xda7335c158d64615 +676, 0x78f175a4a89cdf5b +677, 0xac7a07b66a84f751 +678, 0x266019228d3bdb87 +679, 0x3a7798913c66d5a +680, 0x2aa9c173879dc048 +681, 0x67453dc96c3642da +682, 0xbe9ea095f8333cda +683, 0x10998be0d5702361 +684, 0x77a4e1af57a6b02e +685, 0x66356334d32ab0fe +686, 0x2df9585cb5ea1b34 +687, 0x51159b44acaa000f +688, 0xbc433d2fbb8a4953 +689, 0x5a533a3838335feb +690, 0xd57ffb6f839fc89d +691, 0xe7cd85b8d026e706 +692, 0xdd4acea5a81530e7 +693, 0xd7af04b51606fa0f +694, 0xe31e683c116deb37 +695, 0x4e2adf78e2a88fd1 +696, 0xc58b907a61dee8f +697, 0x673e1a4b00b0a2de +698, 0x36b639fa8091f63 +699, 0x7782c303339e2f0a +700, 0xfd84e0fb7774b0be +701, 0x2a6ac41e094d6e25 +702, 0xcf221a0187c8ca32 +703, 0x4e457ef8a6a528dd +704, 0x9a7714c8913ac3a2 +705, 0x5a6513aaec56ddf0 +706, 0x254fc4d74dc56a5 +707, 0x93e1bd37d16ee5f2 +708, 0xd1a16a2aa652c2ce +709, 0xa66ab34e5262848 +710, 0x5e6f429f482e4a2d +711, 0x198eeff9e36608ec +712, 0x3bea433a42228c7b +713, 0x1a85a30f51e1ad8 +714, 0xe80b6a4fdb0d0482 +715, 0xc3e8d0c13f8879e +716, 0xbaa3c52bb9413a89 +717, 0xc2d4614798d79e2e +718, 0xbbd3f6abc551b6a3 +719, 0x282e112e6bdf2de8 +720, 0x615cc8613f4d4518 +721, 0x53b2627138d76555 +722, 0x1b19126726fd77a1 +723, 0x915c0a108cd2d357 +724, 0x1061822da93d9907 +725, 0xe79aee77f55dc17a +726, 0x7b367a3165fbeba7 +727, 0x1894d6a0059bc074 +728, 0x876235ba0475437c +729, 0x2b8f64a5357907dd +730, 0xadabbbf775f4c3a2 +731, 0xf70d7e73e0914757 +732, 0x50c1494071662c91 +733, 0xae3cc90ade2512c8 +734, 0xd73f9d2b66333aa8 +735, 0x46342e130d23dc94 +736, 0x6c8307abda3d568a +737, 0x235d9a334f4eae0c +738, 0x33d0ccce19e66c93 +739, 0xd83559cfbc7acb8 +740, 0x430f65543bfcfad6 +741, 0x5dbe2eb34c5b25cd +742, 0xdcad606d1b515392 +743, 0x6376bc62812519c9 +744, 0xf292cdcbab076b52 +745, 0x5b6669c53c3e9b1 +746, 0xbd5a95d4d51f18ec +747, 0xf71d40c0b07b0a16 +748, 0xa51966e8052a050d +749, 0x7fd18ced5be2d350 +750, 0x82727df4050382b7 +751, 0x7c10a4e48f664caa +752, 0x3712f2d7d2e6bdba +753, 0x2535b833ad6b4ef6 +754, 0x420577375164ff95 +755, 0x68c40b08f579888f +756, 0x8922d2a586203dcd +757, 0xf317b95e3aff246a +758, 0xbbd1c166e380207d +759, 0x9303601189dfdda1 +760, 0xef342abd93377a47 +761, 0x499773d085e7de1a +762, 0xd204bb687ac202ea +763, 0x19ffb5b90619622a +764, 0xc59bff0531dfbe98 +765, 0x8c6d480a717445db +766, 0x8c3c030ca187e2f4 +767, 0x53f0740df18d7b6a +768, 0x1a5eed54662e3c6e +769, 0xbb29a94e32f03c3c +770, 0xdb0df407c4bbc009 +771, 0x6c0a9f4598ac0ba8 +772, 0x2e0ac7251648f892 +773, 0xb4555f7c1e3fe8ac +774, 0x2cd8ce106d8e441d +775, 0x608e38e439a239d5 +776, 0x1bb66d4c2a2ca5a8 +777, 0xc32ec47253591fa6 +778, 0xd3974f6f2b8b038a +779, 0xdcbfd9eb4a9b1626 +780, 0x8589b3e6fc1ba06b +781, 0x81f34f1da9f27f9a +782, 0xd3bdd7496dcc21bd +783, 0x7c963559e1c47305 +784, 0x5817e571d2fcc113 +785, 0x4f35fea60a0582c8 +786, 0xb851f167a0bda1c2 +787, 0xf57e13249380eddb +788, 0x570e69bf38151a56 +789, 0x117feac919f19d69 +790, 0x49ce46af93025c96 +791, 0x4220f6c18e8e1f9a +792, 0xf082699d8fd5070b +793, 0xccd31756abff1928 +794, 0xbf9d4ab46de14d1 +795, 0xf2e0be2c2bbbc823 +796, 0x6e9b495ef22563ed +797, 0x9a609cdcff6e3152 +798, 0xbbd2e5dafc83fcd4 +799, 0xac153055d6c5770c +800, 0x312bbcdd6b681016 +801, 0x3ed60c24fd5a2f3a +802, 0xc7f3b2948dcdf5c9 +803, 0x8cc631df1fac1c1d +804, 0x77f4aab62a657d61 +805, 0x2f43e30323829573 +806, 0x5b7d20ab0ef901b6 +807, 0x7fa99ec817785705 +808, 0x5c95cf94241f1e3c +809, 0xafa2d371f8f579e1 +810, 0xe4c314c4017e2e77 +811, 0xf672b575a585c0b3 +812, 0x6600a50a45d6ecdb +813, 0xe06c0d7edb63485b +814, 0xf1b45b82f4d0e8f1 +815, 0x41581d87cc1b759b +816, 0x8807b689eddf602e +817, 0x9e11d2949076d4c0 +818, 0x9f3b430319e48bb1 +819, 0xb27fa37d89396b64 +820, 0xd930a0cc6723c8b0 +821, 0x935fe6e9c7a57eaf +822, 0x184f5dba2f19591a +823, 0x513f86165d0adb73 +824, 0x4f2cd09cb85aef51 +825, 0xda66728c1901a11c +826, 0x2445b8938b33db42 +827, 0x98fd86e4b89be5e8 +828, 0x2f752d8769747705 +829, 0x2cb9b42b98ce0c0a +830, 0xf3314e0e0c57d31b +831, 0xf9c382d55868b2df +832, 0x83264a41539ec2c6 +833, 0xa2b3674f0adc1d0f +834, 0x2dd7ad1d92001e7e +835, 0xee210f6047a94713 +836, 0x71a18140729bbcfa +837, 0x415058c01e01384b +838, 0x6cc2e2079c9de72a +839, 0x8561a9093d2b5d72 +840, 0xd6c276d566895b2 +841, 0x57cb2804836f4867 +842, 0x78becdfda7fd91d6 +843, 0x4046a94c8377a3 +844, 0xadaaaa0d558d261a +845, 0x56ef182050db8865 +846, 0xbc28289519f6ebe5 +847, 0xbe7b95e4334540fe +848, 0x384b9838c105f8c8 +849, 0xecfb823fc8815c7e +850, 0xafdbbb2bfa8bdff8 +851, 0xed33653dbeb638b8 +852, 0xf4164289a7a6dc1 +853, 0x6e5cc51c2a3a8b20 +854, 0xdd59a99d16116f34 +855, 0xd48f95ba89787b5 +856, 0xacf9753586b8be7d +857, 0xc0430da7c73bf373 +858, 0x25320aec467ee989 +859, 0x5108e8f4be4f8d8 +860, 0x69b1c7d23ff502c1 +861, 0x7c08bd62caea3313 +862, 0x4285d5b8ce1d19fc +863, 0xbe03dc19cc3be0ad +864, 0x182cdb615e4d4147 +865, 0xf75270e6096d5d1a +866, 0x467b7ac524d17060 +867, 0xb0960b398a111ec3 +868, 0x126c099178f50090 +869, 0x19980d353ddb289d +870, 0xd4b394e2c0305403 +871, 0x5972d7c748938602 +872, 0x276461c9da39bec4 +873, 0x6b3a2046d6ebdce3 +874, 0x4c55d74597c27388 +875, 0x363bf469f4f673be +876, 0x9b26d4e69d36f584 +877, 0x21d441f573e56b6f +878, 0xc29509f2a1e9c4c8 +879, 0x5178088ff6e62d5e +880, 0x902f8ecd57128a7 +881, 0x479fddd275330bae +882, 0xf56ac8b6f6364526 +883, 0x4904060a896d759f +884, 0x1c0f1f4e800bbfe6 +885, 0x9b03bcb77880240d +886, 0x2f35904d9867379d +887, 0xf88a05a4dd6928e7 +888, 0xb5341282b6781021 +889, 0x225910a217522b71 +890, 0xa76bac3bf3675285 +891, 0xf19973940d9a57d +892, 0x9f6ef608ed4291d6 +893, 0xec63cdbf5911fb10 +894, 0x8a359dd4ec3b41ec +895, 0x8373d0d4e6af7261 +896, 0xfc6a14169335e7d5 +897, 0xf06ff499b6856cda +898, 0x71f5ce76943ec9e8 +899, 0x9417034d7879b92b +900, 0xfa0e3c78f47c0276 +901, 0xea9ebf817a3e3b93 +902, 0x7c08ff3d42e19a10 +903, 0x8697e5798f9bab52 +904, 0x10eb4dab88e4ce59 +905, 0xbd11bc073298b46c +906, 0xf46483b5fea2427b +907, 0xafed38960dd33a59 +908, 0xf7a00b0413eb47f6 +909, 0x4233464f10e7666c +910, 0x7ce6db32b60aba3a +911, 0xf9ae9414469308da +912, 0xf5c4e8e04c008924 +913, 0xb89c735c89bdafde +914, 0x8b815ec319546463 +915, 0xdd57dedbf1fa66e +916, 0xdc0bba0705548598 +917, 0x1ed685fb6c966b2f +918, 0xd9afc3ac4319d72a +919, 0xed7c7e9407e71351 +920, 0x585b44a509258719 +921, 0xdf9eac3020de19aa +922, 0x102102d94b983d57 +923, 0x85dbeaa806a02e79 +924, 0x4bacf4194786b961 +925, 0x32bf2fed8ab9b611 +926, 0xce94384eb215dd1f +927, 0xfd1da2a7795c4801 +928, 0x149b31c0a14f7d02 +929, 0x4e01962d69248840 +930, 0x41d509a1c742473c +931, 0x46105403c2b4e56d +932, 0xe6fca820341c56e4 +933, 0xf1982bf03572ac79 +934, 0x9f99e2fb3cc2715e +935, 0x6e3bd2ca3d50faf2 +936, 0xd0aea8d0fee1014 +937, 0xda0ededd067cc72b +938, 0x56c42899c5af28b7 +939, 0x8c4883568ff28ba2 +940, 0xad9019516b75c1d3 +941, 0x3aa1b33682aaf348 +942, 0x31187b962cf65f58 +943, 0x7f2cc27ce4c8459a +944, 0xb75ee9bbf97014c3 +945, 0x8eb8f42b9a9c3024 +946, 0x5b7dcf683a3c14c5 +947, 0xa258b18ccb7cb3c4 +948, 0x7587bc7015c145f5 +949, 0x7536427aff38edd3 +950, 0x437b33489ef425b7 +951, 0x22febd7e96538bfd +952, 0x9fefcc49d567b35e +953, 0xfd756268183d7d6d +954, 0x480df3a7112b2eea +955, 0xfd02a24b1eed9e6a +956, 0xcb3b6c96d65ab879 +957, 0x19f8b328f365f6c8 +958, 0x7d5d20e6328ef6cd +959, 0x8d74057415768152 +960, 0xcba11867467079a2 +961, 0xf86138cf35f091fb +962, 0xdb3204b36a02eb61 +963, 0x8974a7786d5f6894 +964, 0xc8445cca1175a023 +965, 0x1523bfeb2f088c15 +966, 0x4e39bb650d7c4de0 +967, 0x91c9e9ff5b823702 +968, 0x7c3a6850a7c143e7 +969, 0x131999c480253f47 +970, 0x3ac336af37f6a4e7 +971, 0xb057ae911b406d5a +972, 0xde0b70c5f9d5be60 +973, 0x93fd54e75618a86a +974, 0x3955e207acb1f65c +975, 0xa33450c2890b0b61 +976, 0xc6294720e971cd52 +977, 0x89cb13a5b1364169 +978, 0xa6fbc61118b44104 +979, 0xba0651279f93958b +980, 0x6995c30cf06ed3dd +981, 0xd75cd3472c5f86a9 +982, 0xb18d90ce11dfe2ad +983, 0xd69200ae86d53222 +984, 0xe73fc25107e53e90 +985, 0xc1edc96f67bcb096 +986, 0x587cc0fc53992abe +987, 0x2139d74bc6f3edff +988, 0x1b4609bbfa08b543 +989, 0x564e5d7acb190539 +990, 0x1099ce214921efbf +991, 0x7764cd537ccb1b55 +992, 0x4232db7dbdad3998 +993, 0x54c970b3ca338f24 +994, 0xf28c8f460244de6a +995, 0xbd37dcd3829c5a4b +996, 0xefbfe21ef1ab13ae +997, 0x6df8dfc0a865d4a3 +998, 0x5e65a5bfa3f4d555 +999, 0xf6affb932cc9f3f2 diff --git a/_randomgen/core_prng/tests/data/xoroshiro128-testset-2.csv b/_randomgen/core_prng/tests/data/xoroshiro128-testset-2.csv new file mode 100644 index 000000000000..6c513476bbef --- /dev/null +++ b/_randomgen/core_prng/tests/data/xoroshiro128-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 0x0 +0, 0x509946a41cd733a3 +1, 0x885667b1934bfa +2, 0x1061f9ad258fd5d5 +3, 0x3f8be44897a4317c +4, 0x60da683bea50e6ab +5, 0xd6b52f5379de1de0 +6, 0x2608bc9fedc5b750 +7, 0xb9fac9c7ec9de02a +8, 0xc1942c64262d8742 +9, 0xc2c334fa4c2214b4 +10, 0xe53cfba26ba5ce93 +11, 0xf01f0c9d5398a979 +12, 0x1bfa2ef194eeb86d +13, 0xc9df57572868239 +14, 0x728e35871474105a +15, 0xdc7b1e93de9e112a +16, 0xc4d930cafb32002b +17, 0xf18b0bd68577e055 +18, 0x4929ceed7e690239 +19, 0x3b7a547b356b29d8 +20, 0x660f1cebb7affd72 +21, 0xf850e6052cc5f5c3 +22, 0x931512b017c71f1 +23, 0x8d88b7af3b8731e7 +24, 0x3050de537e8e84e0 +25, 0xc917230b8bd3d552 +26, 0xf58da0814356b478 +27, 0xcfc06b804972be32 +28, 0xe3892682eff28645 +29, 0x55bc734a03ca4fa6 +30, 0xe2f7700a020152b9 +31, 0xcba5a308a8d40969 +32, 0x928b63592b6b2f55 +33, 0xa372b4e0293d90c1 +34, 0xd73e00b1c0fdbb6 +35, 0x43c712d398019cad +36, 0x295d994760c6501b +37, 0xe94236abdd256f1d +38, 0xed4566687d847ec0 +39, 0xd3a838dfcbcb5df1 +40, 0xf4ac54b3d79aae61 +41, 0xcabd8f089de74dc8 +42, 0xd58e132a2cd64b6d +43, 0x4eb8bc55f8993dd2 +44, 0x8e4ee152013579ca +45, 0x1aa7c7e058e02a75 +46, 0x5038184ea8f1dfbe +47, 0xa9af7da9879e99ed +48, 0x267567fe1128a585 +49, 0x3a3d637084865189 +50, 0x35179207577f3a88 +51, 0xc323e40ec505a4a7 +52, 0xd2ff171e3203c51f +53, 0xf524706a4db15f35 +54, 0xbff297a90126dd1c +55, 0xec7517f97c47dbf7 +56, 0xf56604fd9a8a7f3e +57, 0x2a63c3bb1635de13 +58, 0x9c22f64a9b9acfc +59, 0x6fc94c63f4e1b311 +60, 0x955820d474d00924 +61, 0x5a4d25256934ab74 +62, 0x95ea0cf2b73da09e +63, 0x8e21647894c89a8d +64, 0xa6ffd9037f6627ae +65, 0xca5d03082b0007fd +66, 0x2ee116ac7bdd65ce +67, 0xa9e6e172042fa80e +68, 0x4763c82d6e7c3d8d +69, 0x325169a3ff49a8fe +70, 0xe0be054ea126080c +71, 0x4ccc1794542607ba +72, 0x58c480dddafc29d4 +73, 0xedab421340a8d4d +74, 0xd28d8f3c2ab241cc +75, 0xb2a89fabba9566c3 +76, 0x1b12fc8b30a80b49 +77, 0x65e178e0065959ef +78, 0x4adc931b03e25f55 +79, 0xefb7b250b854feff +80, 0xe024be0a14bf3da2 +81, 0x60c2285324a5a642 +82, 0x280dfcde16655ff +83, 0x18c2cbf4c0ba9bb0 +84, 0xcbeea642049c68c +85, 0xa1b19b0b60833fa9 +86, 0x10f72a22ef81e27f +87, 0x5cc3db165dde75b2 +88, 0x947a3c40223e6bd0 +89, 0x5d469f487abb870f +90, 0x1b1f4fea711c039d +91, 0x63b22d9e9616b06c +92, 0x689aa9d9808ffa7c +93, 0x2164f59dcc5f3e03 +94, 0xbdfc99e1f2c1193b +95, 0xdc9e85a6a6b8f61e +96, 0x11ad0ede8657e961 +97, 0x73a69427c838bafa +98, 0xfa4b98f49849cc62 +99, 0x5ccb852e4e18aad9 +100, 0xae102d1e06ad3569 +101, 0x4be41a104f8d8463 +102, 0x723f50acab4314fc +103, 0xd3b7b694a6bb6c38 +104, 0x8bfd1fbedfb8f092 +105, 0x3d5d9aea4d80f37f +106, 0x28cd19af64bfc553 +107, 0xceba7e81e5ec8edc +108, 0xd8c0513fca3ca719 +109, 0xfefef4fd2a0896f0 +110, 0x1aa7320084a97662 +111, 0xf63c0bb8fdae24ea +112, 0x497a5e9d0a13c0d5 +113, 0x37fabc943a07639 +114, 0xb5be9f1d19096cc1 +115, 0x4385acd2ed447c52 +116, 0x8e146c6874b731fd +117, 0x553c3c72c9e05a64 +118, 0xb9cca017a8d4be34 +119, 0x8f8e09bbd56564ef +120, 0xcf6da1a96df67f67 +121, 0x5882a27646d3189e +122, 0x1554cc47896d846f +123, 0x105600be06e72171 +124, 0x95a04162a7ec3791 +125, 0xadeb00515f0d6be0 +126, 0x22ed3d1ca5ebc008 +127, 0x312629837e981334 +128, 0xca916e4cef410dd2 +129, 0x18556a16bdff0e5 +130, 0xfab80417581d6927 +131, 0x40f7ecce118881b5 +132, 0x6a12fe0d0c5f3ca2 +133, 0xd3e2ba4104a669f5 +134, 0xdeb3d714e1fd921b +135, 0x32cc61dc107d240a +136, 0x1a79efae30dbd860 +137, 0xebd6029e65fcefa9 +138, 0x94289c890d17c9b4 +139, 0xd91bbe374cb9f243 +140, 0x3352bdd3eccaa300 +141, 0x5cc9a4bf3127b238 +142, 0xebd9f454d96adb59 +143, 0xd5f61261bb7089ff +144, 0xa743f21be20ce5f2 +145, 0x3d2a78d45bfb1da9 +146, 0x9ebbad453112c987 +147, 0xff48b7b97e3f597b +148, 0x2b57be29ae160a9f +149, 0x90df488fada68e76 +150, 0x785b4250ae46cc0 +151, 0x1c4fdcb6c66db255 +152, 0x3567f33a12172e96 +153, 0xc173a5f010dbe48c +154, 0x859eac8b59dd2bc0 +155, 0x532809d8c8b5378b +156, 0x656f93a00428ed0e +157, 0xd4ee7e2199473a09 +158, 0x9bc701f16ecf35a4 +159, 0xcea39cb296d32304 +160, 0x43fbb2333d392310 +161, 0xc9d66a1062247d +162, 0x271a83a113c42b2f +163, 0xee17f7585ab05734 +164, 0x5e98cde55d0b8ae9 +165, 0x488cc07f036165b3 +166, 0xd78481d7416f6724 +167, 0x681436c7434b6260 +168, 0xc53bd2c997a04ce5 +169, 0x61b5951080b80e26 +170, 0x48f285546280fec1 +171, 0x87ff976327bf74ce +172, 0xc10c08c9bc8b05ee +173, 0xa62f879a73bf12a2 +174, 0x31d7cbb6f9c1acf +175, 0x3e522645e518ee29 +176, 0xb85967a95e811cf8 +177, 0x99f8643751545edd +178, 0x3f962076f920dd9 +179, 0xc92abe52da7ed89c +180, 0xc1fe02e7dba484c9 +181, 0x7904149975239b19 +182, 0x5bfaad7ac409b74b +183, 0xb915e6eba7685946 +184, 0x8b2291b29fd71d66 +185, 0xe57e5709ad0bd967 +186, 0x3fe55bb3338f0f1d +187, 0xf41f8f7a981c05d6 +188, 0x80d3d9160712aa45 +189, 0x2da872bdd8bbffe7 +190, 0x6698441241fe0a4e +191, 0x4870fc969dc6676c +192, 0xd420fc68814fe867 +193, 0x6aa0500b9d8bacb5 +194, 0x55078d31633dcd47 +195, 0x6d758a56c80bd405 +196, 0x122149ae571cb397 +197, 0x22d1134c99ac507b +198, 0xe7d9e27ae05a47d1 +199, 0xd18a73dc45e5a290 +200, 0xb5bc1909e08803e2 +201, 0xe9a1e3ee93f2e109 +202, 0xf040a8f79841c101 +203, 0x9a705a608899152d +204, 0x4f7783a0dab4290f +205, 0x11c5bad24bb23af3 +206, 0x58545a19a22fb881 +207, 0xeeaf5ab573077828 +208, 0x9e036466fd858142 +209, 0xef70bf26fdd6bc94 +210, 0xcc3a2971056cb9f7 +211, 0xef120c86e84d643f +212, 0xa499226ab42f6d7a +213, 0xa85cae4acfa0a29d +214, 0xc8280371e2c25d89 +215, 0x246336f7e63ac4e6 +216, 0x76561f7777c7b915 +217, 0x704f83c71583f0b8 +218, 0x489db8592a76cd3b +219, 0x268d584af17550c3 +220, 0x350e989762428fe +221, 0x6857adc12d13f1bb +222, 0xde62c7d9517260e2 +223, 0xc1f37ee8baac988e +224, 0x714732f71cdd5374 +225, 0x56f01487bfa58c5 +226, 0x5163b23d41d95f14 +227, 0x745150434b747a38 +228, 0xdcf7cd6c6b14b1b +229, 0xd853cc6bc2580f81 +230, 0x693562e66b579775 +231, 0x8f15d6369dbe6678 +232, 0x464c1791098ad19d +233, 0xeeba6610f16ac2b9 +234, 0x3b307cc3c5bf5859 +235, 0x7e82177c4dcb75e0 +236, 0xae5978c33dd3e817 +237, 0xec3c0128360b0b2 +238, 0x2c325b630e904749 +239, 0x237ff1d19b4e7ead +240, 0x3c82e47b67a33956 +241, 0xf38b46203355a168 +242, 0x4df09cfda8d5774c +243, 0x4b06980b33ad6226 +244, 0x7afc1e940df03034 +245, 0xaa093355c596ecb7 +246, 0xbbb5100165d1445f +247, 0x599c0f30608a36d +248, 0xd35999534e29986d +249, 0xd0cae757abc97c36 +250, 0x9ec9f2c24bbe3b70 +251, 0x76b96e93352c2960 +252, 0x4dd3acf1c01ae06c +253, 0x71ebb829cb09312a +254, 0x3234f4c24cdbb897 +255, 0x9b0930936363bc6 +256, 0x2ede98b9aacc3672 +257, 0x7388672bfb4c92c8 +258, 0x53011e6a80763bca +259, 0x69eb6ca56f23129a +260, 0x59d98a723f847ad5 +261, 0x234af2de04ba218 +262, 0x589b028bf0830748 +263, 0x525da4a281c641e5 +264, 0x47ceb48568778c5f +265, 0xa2d73af3a884d972 +266, 0xdc6fab52b39bfe68 +267, 0x7f1a5e5ea6139484 +268, 0x70571bee802a1fa1 +269, 0x489f1d18d9c61c4a +270, 0xd781c38aa8aafbc +271, 0x5aa610ad2539aa57 +272, 0xd71a2a69974ae4a0 +273, 0xe4479465870487bb +274, 0xf714dacd7fc4475b +275, 0x5cb9c32e10d39249 +276, 0x746650ada73de1a3 +277, 0xbdd059359907cd53 +278, 0x38352adeaf41c72a +279, 0x330a370593019b35 +280, 0xc75ff9305bdaf3c3 +281, 0xc64723389b0bd56e +282, 0xbafccbf3fae88f31 +283, 0x3fc2c4b1d35da1fc +284, 0xd9414b4382f59e69 +285, 0xec31e6d32a58f7e1 +286, 0x4763fb9ad6cadb98 +287, 0x5e9817762a380e57 +288, 0x9a670c79b387ff5b +289, 0x467beb71ab258339 +290, 0x23cafda15a336768 +291, 0xe42ebf79e2d170e0 +292, 0xced716e4bbfe75ea +293, 0x1057597f33a23633 +294, 0x563d3fb59a847744 +295, 0x1a3f85cf84ea5e0a +296, 0x7630855876b41b32 +297, 0xb59e3eecb52851b2 +298, 0x26aed463d3769fd2 +299, 0x530d3898b8d043c6 +300, 0x28fa6b7cdc76ae94 +301, 0x99591569d7464343 +302, 0xa46da7d9e275579a +303, 0x30f6e5979a92bcfe +304, 0xaf345d66f7e756d6 +305, 0xdfad061213a92b33 +306, 0x2843134719ff646 +307, 0xbc8699b6d3f04313 +308, 0xacb08fbaeaedce6 +309, 0xe8fd50dc65724bc7 +310, 0x956d0436e93242fd +311, 0xa9c3e3eee8a80b9 +312, 0x9bf71b03710af171 +313, 0xbd61bd65edf3d9ad +314, 0x531b6865fc4f810d +315, 0x58ca69e7da1ea2f2 +316, 0x4946f99ec03e8adf +317, 0x3b9d4f48b1eb484b +318, 0x605be28093b8144a +319, 0xa7a4c6c8f2ade7af +320, 0x729f97c8057a21f6 +321, 0xc97d9d778a4e2932 +322, 0xc173b6c3d0c5168f +323, 0xd400c6f451c927fa +324, 0x611d96eb9e70ecdf +325, 0x3ad1a1709255cd86 +326, 0xf85d02d9fd5678eb +327, 0x495bd5eb58af79ab +328, 0x977bc4282d97381e +329, 0x9a5b1811cde9f133 +330, 0x49b2b9d26ba0977b +331, 0xf6c4e846b99bb87a +332, 0xc399d5f8661b0c8 +333, 0xaf9a91415ddeb79f +334, 0xb93df0259e6f3c5e +335, 0x80ad075b109611b5 +336, 0xf3004a806f25186b +337, 0x89a86842ef14b472 +338, 0xba53e5942ca79cdd +339, 0xc4cd49237032e3a0 +340, 0xb39700c89fc1109d +341, 0xc35fd5106aa40bf7 +342, 0xa0ff3091df2010c7 +343, 0xd4970cd890097774 +344, 0x39e7db9319a17976 +345, 0x56306e9316a184b7 +346, 0xe4d218267f28a145 +347, 0xbaa24a30caf53ebe +348, 0xf4811ee0d51ce11d +349, 0xccb9ece4a25b129d +350, 0x132b2d1c4f092d60 +351, 0x7d5e7a59f14dd113 +352, 0x8ed30762f02d3098 +353, 0x8a92bb806bf9a4c0 +354, 0xd1957618db32f95 +355, 0x3ae37701b1db294a +356, 0xc29e705f675713ad +357, 0x3d12dc6fc3dcc569 +358, 0x7bc096e1e2ca2e43 +359, 0xf58f4f816e71b16d +360, 0x23e6f93c7d0f1050 +361, 0xacaf403b80890da3 +362, 0x7a5e19bf92de04ec +363, 0x72b3638076a857e8 +364, 0xb87601882acb1f3d +365, 0xb51d157f2576ac70 +366, 0x7ef0c2f1ae02af0f +367, 0xd519f6224fb2866 +368, 0xe00a80d729843eab +369, 0x3c95b55c523d0871 +370, 0x81dcfef1772a151f +371, 0xa5b20337760a602d +372, 0xf36049e3e0f98eac +373, 0x21bc3e0f1083016a +374, 0xd8f295098597530f +375, 0x78a2582906003e78 +376, 0x1c5cf0f434493262 +377, 0x2228d56b7da9cc80 +378, 0xc3d7eaedd0f36349 +379, 0xc9ca575c3b6dfe54 +380, 0xb5f03d2d974c91b3 +381, 0xb2f7ce70c56a865c +382, 0x98f33d64e66602ec +383, 0x559904911cb8b69c +384, 0x19c426ae3d196913 +385, 0x818fcd24869feeec +386, 0xf4c52f4b00f4295e +387, 0xbdb808d5fe34cb3f +388, 0x5014922c0ca80ee9 +389, 0x9f7e4c8068fb96d2 +390, 0xec99128e620a2df8 +391, 0xfcbb4fc594857a59 +392, 0x6aebf62bc7c79e4f +393, 0xde8cba80e35ed831 +394, 0x55bb9ced0fcb6fd7 +395, 0xbe7534a18c050ef7 +396, 0xed2e6d1767c7ed5c +397, 0xc88e18ac1064dd88 +398, 0xf71fbae1105d8324 +399, 0xb4431f0a4b807ea4 +400, 0x78de56556e1272d7 +401, 0x34d3e7e84ceed376 +402, 0x72f0ca866b3b182b +403, 0x4747a9b5faaa6dfe +404, 0x5a0f85d879e90288 +405, 0xbecbea458ec061f1 +406, 0x5e0bcff71b1911e3 +407, 0xc2e32dc60548a6ca +408, 0xfa76a9a3d449b8c2 +409, 0x81303b7e225dea8b +410, 0x4aa42b413ca5c63c +411, 0x4d7372d31df5b70d +412, 0x2a408f03bb0499d1 +413, 0xd75529b610d56d9c +414, 0xa6e9d1356654ffbd +415, 0xe10bdb510c440754 +416, 0x8fce6a25abf05e69 +417, 0x21aaf272093d6081 +418, 0xcc18cf69f0f0b2bd +419, 0xbb4e0a1cda31a035 +420, 0x70128e6522fe238d +421, 0xaaeae87b79d223da +422, 0x6882e6705d12bc8f +423, 0x8e110abf1ccb274e +424, 0xb7ebac3cfca55a39 +425, 0x909705e2a6e584ce +426, 0x3b54f18e8f7708cf +427, 0xcac28674d5caa98e +428, 0xdde0e042ad4107a5 +429, 0xfc2ca3a740f903ac +430, 0x9aae84ca64051770 +431, 0x858a0d2d879442e +432, 0x75b3e7d29e357b39 +433, 0x9f6f5487d5ec5ac1 +434, 0xfd95986f2765eed4 +435, 0x2899b60770693140 +436, 0xb8ab9650b7300ee8 +437, 0xaa772209ef643b16 +438, 0x9c98fb4b5946fc61 +439, 0x6f614d64e4a38b84 +440, 0xbe0099b53347a13f +441, 0xe8d05eabf7db8a0e +442, 0x4c849670c59692d5 +443, 0x421d2e32838ebba6 +444, 0x1fb1f7427466dd6b +445, 0xd79d9987fd12fa15 +446, 0xc195d5fedaa613c1 +447, 0xfecdf6c6fb6c4924 +448, 0xd8536233459d6d65 +449, 0xaed30f22454f593c +450, 0x14d427078bb818c1 +451, 0xf7235f42e291617a +452, 0xb1fc436bdb2efb83 +453, 0x21cc3fd0fb82e07b +454, 0x2df968f572e077bb +455, 0xe1b76c513528f8c3 +456, 0x955681442083db83 +457, 0x2e009197f295008c +458, 0x2c258d6b1935587a +459, 0xd10fda2d14ce8e70 +460, 0xd21cdc7f5db09825 +461, 0xe39168a7b3a080cc +462, 0xc82c2a353a812026 +463, 0x6adc63d4bb7f26b0 +464, 0x5d2acdd2deaed807 +465, 0x47c39719b79aee01 +466, 0x5b6351daac993e69 +467, 0x1e2d2cf25d029df +468, 0x671c43218ccc62b +469, 0x783093122682b9c8 +470, 0x8055e091219d2263 +471, 0xa6e7f6bc43717757 +472, 0x91855fe232480a87 +473, 0x554030e74824042 +474, 0xd0c14f8ff34b1a30 +475, 0x13aa852fdea8bca8 +476, 0x27ed292b1a4fa598 +477, 0x3e56548b7095af08 +478, 0x47432aa82a4bfcfc +479, 0xadddde35537dc4c8 +480, 0xadb0d103d29faa1f +481, 0x14818cb71d4cdaf9 +482, 0x31507bcc3d46a5d +483, 0x7407577173399611 +484, 0xac03706bbe4da972 +485, 0x4efb0cae8499469c +486, 0xc6d4bcbc4396a20b +487, 0xd7581757d38762c3 +488, 0x6308e217f7e69120 +489, 0x6931392a2fcf3756 +490, 0xb5a5b36744f09886 +491, 0x8da8292d0bf2ed08 +492, 0x13e0aa8d5a24bd3d +493, 0x1131dbe7a2b97139 +494, 0x2098efd4a1e7108c +495, 0x9c470e15e690e574 +496, 0xe60e3aeb65560eb8 +497, 0x4ae5444669ffc65f +498, 0x911fc7e6820923b8 +499, 0x25b3fbb125c1ae19 +500, 0xa8b6c812471f37f0 +501, 0xe6d9aec89655113e +502, 0x59d24e18c48dd532 +503, 0xc9b320756e0d6c35 +504, 0xb70a2316319c8e2a +505, 0x328a0b16ff39152c +506, 0xc2088e4c8a3298 +507, 0x10bce05ac0971264 +508, 0xe26b5b7655fd4ad5 +509, 0xfb1d818177211481 +510, 0x98d83c41a7196f86 +511, 0x45801b77072aace8 +512, 0x563268328ebfb870 +513, 0x4d26e320a51123fa +514, 0xf531c63a3438f527 +515, 0xd94525fda256c193 +516, 0x883de65d7957b025 +517, 0x7be095e05de1599b +518, 0xd27792977b3a11dd +519, 0xfd179d3c4a5f06fe +520, 0xfbe066b302e09da2 +521, 0xb841424fbd2c7249 +522, 0x566dc3e3f2345fc1 +523, 0x14e8cfa0ee0ab392 +524, 0xf1e11e1841884ad7 +525, 0xc895b028b3b7df26 +526, 0x70f727baee1dc909 +527, 0xc2f4bcd3f8c7905a +528, 0x6d294a99118f9f47 +529, 0x18a723a0ddcf902e +530, 0xac36efa0258143c4 +531, 0xc558a61c40490895 +532, 0x430341fd196a18e7 +533, 0x27fea5b52f4178c7 +534, 0xd0d628d45d51e088 +535, 0xc016cdc47158510a +536, 0x925a6cdd446f0555 +537, 0x5e5a30a2f1d9bd08 +538, 0x918ad9cea082da5b +539, 0x23bb26bfaa0e79d8 +540, 0xf667bd79197706ca +541, 0x9ae3d6e8290fa1d5 +542, 0x20a15e60e0007e64 +543, 0x7d88beb1713a320b +544, 0x2d8b1728e392a6c3 +545, 0xb4cc0ae2c22afad3 +546, 0x749fe3524435e61f +547, 0x137bc8f57e7060a3 +548, 0x8070ee0def7571b +549, 0x2d5cacc36c121329 +550, 0x8408aeea38281006 +551, 0xc05e54af2206ce49 +552, 0xd547b24a26ebd3c2 +553, 0xc66d83645d95b57d +554, 0x8f4187e81ac31f25 +555, 0xe2878187a7ffa7e2 +556, 0xf7802760e1a8b9e9 +557, 0xd7f135ce1d83b5d +558, 0x4e2d5eee2bbad34c +559, 0x9b73503bcada0bcc +560, 0xc3fb41b2fdd2b56e +561, 0xc5958ed587dca76f +562, 0x1029b90ef3fa1e44 +563, 0xeb52236cba057b2f +564, 0xd411396dfa523c6d +565, 0xccb05527609c690f +566, 0xe73e27fd2c6295e0 +567, 0x363628b4f2a7bd3a +568, 0x443bcaaab9b67c72 +569, 0x1142926c0ff02a91 +570, 0x6d7fe0d6fbcb7265 +571, 0xea31775a5191e8a2 +572, 0xc44a633ed2339375 +573, 0x261bfdb83fc7a23b +574, 0x4cb967260869e0e7 +575, 0xf3b7134ffac658c0 +576, 0x97b266a6b95e219a +577, 0x18a5be54082669aa +578, 0x9adbdbfe1ad667c +579, 0x6fd02995faae35b0 +580, 0x9e62832c534ef39f +581, 0xb89e8229d7a85aec +582, 0xa46c8670446a0539 +583, 0x6960eeea3b3a4c70 +584, 0x27901b708cbb4f97 +585, 0xde1abdbbffa9cf6c +586, 0xcadb304d56e1ad33 +587, 0x579b5110955d30c9 +588, 0x77b57f59d61ebdbb +589, 0x900adb153a8037c0 +590, 0x1f5200f1f8be5a4a +591, 0xc491a76e1cefe1f1 +592, 0x6724370243b5d0c9 +593, 0x6cc8e3b9fbb98c87 +594, 0xca1722c5183b2b57 +595, 0xe9a61a3f20c59fec +596, 0x91723ba5418ed1b5 +597, 0x4299a43bd28daf49 +598, 0x8dc266e15f1f32b1 +599, 0x91a22c16ad09703b +600, 0xfe36e6cd32ebd06c +601, 0x30c0d9f9a60a11ae +602, 0xfad538e8bf1a0f03 +603, 0x47c2a0261dc808f6 +604, 0x9148743d0cdc81a +605, 0x17c3f4257197c037 +606, 0xdc8b06b5220c01a7 +607, 0xf9ad586eb09e30f4 +608, 0x702600c123b400c6 +609, 0x9218eef469b0db7e +610, 0xce16c9bac0969bb4 +611, 0xa758408742a37457 +612, 0x2eb094509e812e4a +613, 0x28440b87ce1e0e21 +614, 0xab48eb01ee07e56a +615, 0x85e69345a3649100 +616, 0x517927d4a415e569 +617, 0xd02de9b703206f93 +618, 0x5cae9cf67b9d62a9 +619, 0x8b0e1e0c2623250d +620, 0xce893eb84c72510b +621, 0xd97bdcd1e00f8c3d +622, 0x106c1721a5e8546 +623, 0xb4fc0554e61e059a +624, 0x5fad1bc4c54c3136 +625, 0xd09dc05514ba4ad3 +626, 0xc934e2153df00372 +627, 0x3cff94fa0fa2967a +628, 0x4e7ca152c113e934 +629, 0xc5ccf2350fb82ffc +630, 0x10aa453d349b70df +631, 0xf8270070253de14 +632, 0x412b14bc12ef4538 +633, 0xaf83140fc27938c2 +634, 0xf342d1c8c97c7e74 +635, 0x693b4b07b79cfdc2 +636, 0xe859c76fde1be4aa +637, 0x90ac4aa1c012a971 +638, 0xeca381124c9bf23b +639, 0x1f544598d356ab2f +640, 0xbcd78485f20f8339 +641, 0x6b8eb4bf854dcdf5 +642, 0xdb231419a9323609 +643, 0xb2f0167ca051a61a +644, 0x9806e89e8d3ebd15 +645, 0x69ce87797a14c206 +646, 0x143ecc33c23e61f5 +647, 0x3be37d8fbcfc396f +648, 0x2a4336f50c851387 +649, 0xe665ed14a40c6400 +650, 0xc229fc93c03a6a24 +651, 0xb7f27088c74af74 +652, 0x8a8da4fbf5fb90a6 +653, 0x8c54684d5db6a600 +654, 0x11ef0e952c8ad4ec +655, 0x928a518e677b87a6 +656, 0x6b6c8ebe9db7253e +657, 0x9feecd8eaf8a8101 +658, 0x4f270f30f3ad2d0b +659, 0x23798146bff58d75 +660, 0x7d9134e4005b9246 +661, 0x18b5eb6833bb921e +662, 0xff0ef41f6c734814 +663, 0x388b18f678774f4e +664, 0xa51646467be5785e +665, 0x9f96bbe291c9361 +666, 0xce39cac00148c7b1 +667, 0x69d41ab8914f944f +668, 0x579ca60b75dbf4e5 +669, 0x352f2b89c968d81 +670, 0x181d45a561c05553 +671, 0x5a6aeaa048d6a494 +672, 0xd7938433b99408ca +673, 0x13bd6696806f0800 +674, 0x2ca8e35e87037dbb +675, 0x70d9d33ef79088a1 +676, 0xcdcb45940c9ba3e7 +677, 0x2546f21a69a29dc +678, 0xc674c5afa1f9abdf +679, 0x856dfa52fdff93b5 +680, 0x614b66daa02187bb +681, 0x55ce165aee2e205e +682, 0xf34d6cf856f941e3 +683, 0xa4a0ec51b4f25b25 +684, 0x83e6bf89bfe39762 +685, 0xb559b9a68edf3381 +686, 0x9259778b54c31479 +687, 0x4e4e21e81138cacd +688, 0xbbb990cd25c2fb2d +689, 0x38a85ad84d9e31e +690, 0x5b4f4081ffba398d +691, 0xfb12eb300dada910 +692, 0x6975328f3eebcb34 +693, 0x3db017218a6478f0 +694, 0x9397aca7eaa5de14 +695, 0x6f7318d0d9ffed6 +696, 0x40cf276103c34010 +697, 0xeacef8ae2095ec8a +698, 0x80f7593e9ddaa152 +699, 0x8d4bc01f7e5c6520 +700, 0xbbc9606e7518e199 +701, 0xfe71ef90abbaca29 +702, 0x528edfe3e467ed43 +703, 0x52b322c36f60627d +704, 0x9946be5ea3beac73 +705, 0x890745d71a02c404 +706, 0x5570d1bde8bb7993 +707, 0x563fceeff8466dcc +708, 0x62a9ca23db6e4d62 +709, 0x89d6038410c92e8 +710, 0x16bc3b1ea7b90a89 +711, 0x12ff3e9c30d8dde6 +712, 0xe78cb53e8dd40a77 +713, 0x643722181b85d5a +714, 0x73e26524635d78e3 +715, 0x941ccfc41d47c53b +716, 0xadbedec82c31e57c +717, 0x2addd39e7a36aad6 +718, 0xe64d81fa432bb65d +719, 0x1e2e63d01399ca82 +720, 0x760a3c0edbbef3a6 +721, 0x801131e88419a79c +722, 0xa2a75136213dbb6 +723, 0x83e576905753c3ff +724, 0xdbbdab8007c4ea0 +725, 0xbb73b13358898c2d +726, 0x5818372d8fe036f7 +727, 0x3aa052cd647e29d1 +728, 0x235219635ff4abb6 +729, 0xe24e07311fa76b65 +730, 0x4967574b62c3efb8 +731, 0xb04b4c210022e795 +732, 0x3d48e77713ef3fda +733, 0xf4ec1050775fd3b1 +734, 0x38953c604d35190d +735, 0xf731a6450c1e23fe +736, 0xac66ae73ecc6b9dd +737, 0x442e2bcbca5bbaa8 +738, 0xa74a741bd02570bf +739, 0xa85473cbf3b4c45e +740, 0x24d43199c69cdda +741, 0x59f78fa87f895d36 +742, 0x78f5513621dc1813 +743, 0x226c2606635698c9 +744, 0xea39babbad3df384 +745, 0x2f178b076f08f80d +746, 0xaee482470bd9acb5 +747, 0x48571d8c4235c1f6 +748, 0x6569395eec2df1d7 +749, 0xa9b7408c1d67a372 +750, 0x3b9c5ba01aecae9d +751, 0xb047b26325765767 +752, 0x9bb1968c8b6149d4 +753, 0xbba4038fdd341986 +754, 0xc1d23b5b89beaa88 +755, 0xaa9a341db334c8ac +756, 0xaa9337dd1fddf923 +757, 0x9fdf160ed939d68b +758, 0xbf48cdd432d0f148 +759, 0x2a01743f1f7b581b +760, 0xb68d5c631e9fb70a +761, 0xe9ab844ec026cc7b +762, 0x1fabd46f0d5266f0 +763, 0x29e53ae817eec5b +764, 0xeffbebc07500ad4d +765, 0x432ae3b596c1589b +766, 0x48d44f3895d6dc23 +767, 0xcc3a5576e24ec2bf +768, 0xc8f4a042462e95d9 +769, 0x24c12cd6ef57b6 +770, 0xa7896ae26675f69 +771, 0xb98a1790d429c90b +772, 0x71f7ac96dea8ffb6 +773, 0x7878c64cad319f72 +774, 0x65586d63156e1a05 +775, 0xa70ef198e61e2a11 +776, 0xf5a84f622d490449 +777, 0x7789e1c1927e82c6 +778, 0xfe053fdbb586b8fd +779, 0x59a94b735df951c3 +780, 0xdf5e72909ff2bfbd +781, 0x34dc2bd8876a92e5 +782, 0x7e408900bfa3b282 +783, 0x844176cb62d5008b +784, 0x7406e9e156cddc9c +785, 0x6a6d87de33056193 +786, 0x20c388365359e4c +787, 0xdbda2eee6499be64 +788, 0x3574cf8bc4840b47 +789, 0xc2d904ac50e44ee3 +790, 0xb9edf042b0d96102 +791, 0x2ac087f3922dd11e +792, 0xeaf244df29c2a8ae +793, 0xb4243528d8d0649c +794, 0xed67e39d9217e6cd +795, 0xcbdcd1620727437 +796, 0xcc00dec8485d0dfb +797, 0x2e5411679d89f548 +798, 0xdd355c299c05131e +799, 0x6fc81e1e9beb2c8 +800, 0x205ac04eedc0085c +801, 0x8bf73a08c5240640 +802, 0xec6f8daf06673cae +803, 0x6e29f78f0a59638e +804, 0x8c530fd613aeccda +805, 0x58b99ce19626ee04 +806, 0xb16f71c11f209bb9 +807, 0xea1d7ee0e82f9146 +808, 0x5641482551d357fa +809, 0x13fb8eff6efa4b89 +810, 0xca4bdfac87e46ce0 +811, 0x9e2babf08f33b6ad +812, 0x482633792e270729 +813, 0xd5c17bce83e146e9 +814, 0xf8df8169c7ff4df6 +815, 0xad974ea8b3bb7e7d +816, 0x8ad356322d6c0a26 +817, 0x5ba5a24cff70d235 +818, 0xb604ea125e469d44 +819, 0xecb90d0ca42445d9 +820, 0x9c499d3f441e6eb3 +821, 0x2aed9e67fc701d26 +822, 0xb3476334028bed9 +823, 0xba079723415a89fd +824, 0x8684b0e124ebd181 +825, 0x6effee2741402b37 +826, 0x15e734115d68f8a4 +827, 0xafc15b8a9fa93205 +828, 0x9749e35360fcd91 +829, 0x8ffbf6ba4b02bacd +830, 0x2f107b6a820f44ba +831, 0x230cdb06c5f7422b +832, 0x2149918883f7c858 +833, 0x3e8eb9dbfb832b71 +834, 0x871f0b4369d3dbc3 +835, 0x3553e06132e55fa4 +836, 0x1ec19fd1ce7a5823 +837, 0xf3908fc23446b3a2 +838, 0xe300b55305c8d7f3 +839, 0x61e4ab3372dce7dc +840, 0xb50f68be3632604f +841, 0xd6d2993fa6d155b9 +842, 0xf9c8d0fed0c90246 +843, 0xdd1b49530387141f +844, 0xd1db9818546e095c +845, 0xb91885ccff43ee8c +846, 0x8d704dca3b7fdb63 +847, 0x8309c9077939df4 +848, 0x6536739d7ae608f7 +849, 0xdab8a503cb9b94a6 +850, 0xc504248b8f69f733 +851, 0xb0ccfb81eb67e3e4 +852, 0x45ac4f949c418493 +853, 0x7763a70137c01376 +854, 0x7f08d6362b17c470 +855, 0xb190bb422946ad46 +856, 0xdafe7dfcb0d71320 +857, 0xec415ea4c54398f5 +858, 0x5955b81204c5657c +859, 0xff1f983c56d6d7cb +860, 0xb25b4a0de0bf393d +861, 0x3a90222bef45f3fc +862, 0xf0eb0903e3695f44 +863, 0x405ecabf26817b33 +864, 0xccf01a062f2351eb +865, 0xa62a5f63e31545b1 +866, 0x673d1baf237668d3 +867, 0xd15db3cddfb0a161 +868, 0xa8adebfc9b5351f6 +869, 0xc297fae49f0b2d08 +870, 0xe5ed1156ab569225 +871, 0xf4aa4bab70aa8c11 +872, 0x8e32dd1eb44c6363 +873, 0xc7aa250f1492e86d +874, 0xc645795d705914cf +875, 0xfdd8a48c0fb81c53 +876, 0x6ad1401f539799fe +877, 0xa157e71b6bdd4254 +878, 0x4cc09814465a6c9e +879, 0xed1f66bd824e39ec +880, 0x6b74f7f6f2d4c16b +881, 0xa3391c0100010ae4 +882, 0xe0f384530c0e7eb +883, 0xf6aeb9f0d64c7159 +884, 0x3d7f6bd980e07a17 +885, 0x8b4e1bd3e782ea4e +886, 0x7b005009d95b7d38 +887, 0xf43f001d5e7326c0 +888, 0x16600ff7361a1721 +889, 0x13778aceafd72087 +890, 0x85d3359c37907c58 +891, 0x7374f768c968d0f +892, 0x2373d89b9b8f9e9a +893, 0x21a3fe7e4dc5cc35 +894, 0xb02abcad4f4ae60 +895, 0xb9eb579582666e3b +896, 0x9c12186973b91695 +897, 0x1bd25ac6911295e7 +898, 0x9f5a90e0fc16ffa2 +899, 0xe3e8f10ce7fbb9e1 +900, 0x5867e566887d2d16 +901, 0xd569aaf2ffead057 +902, 0x678359b93dfd07f1 +903, 0x9fb73a4f1b777d94 +904, 0x5c6b0bcc70df3a54 +905, 0x66fd71a67ed5e59d +906, 0x62f21a6fe936b212 +907, 0x86922151e4b251c4 +908, 0xbfdee56cdeabe8bd +909, 0xbe3bc7c4c2380ffc +910, 0xd09ebebb0e786d49 +911, 0x4951a83005aa22de +912, 0xc1b7da6cf08630c4 +913, 0x8b294b5fef04b0af +914, 0xaca7a47f7fda4d5f +915, 0x70bbddc64b4b1a91 +916, 0xad306a764087085c +917, 0x19b9f11c14adb74a +918, 0xbf1a7d2c83fbbbe +919, 0xb78da8a53fa857 +920, 0x5b614c5060a543b7 +921, 0xb6f32557404d475f +922, 0x9fc53dfe5281f084 +923, 0x43ad9d302c10a475 +924, 0xa4575be2c10fbc13 +925, 0xe58c4c02d5b2bc8a +926, 0xaa838a3e5a16bb55 +927, 0x95c39373858011e1 +928, 0x17a6be18c1801fa +929, 0x835e6c3d99898c27 +930, 0x9af26334bd726505 +931, 0x7addf56712a22afb +932, 0xf619281f6d4d37d0 +933, 0x310c6b1e29ca7eaa +934, 0xe8106bbe1ea0f3c9 +935, 0xc89add421cfe7bb9 +936, 0xe01b7a6885180236 +937, 0xda8cd608ee0eee61 +938, 0x3bb2f5f40a8f4880 +939, 0xd434cddc85946350 +940, 0x6390806f8d1465f +941, 0x2a5f0150c8362cf3 +942, 0xcc6980e968b75f37 +943, 0xd86756899b2c95d2 +944, 0x95ab76b54f439605 +945, 0x1e0d6f6a99569ffc +946, 0xd47b20b72c0f02e3 +947, 0xcd9fff1462fe8a25 +948, 0x71867c57f009bc8b +949, 0x85238c818139a22b +950, 0x58247991b6447ce7 +951, 0x3b41a627153bcc9f +952, 0xa3ddf05f18153e13 +953, 0x21a3d47762fbdbe4 +954, 0x8ee55f20e5c5b14 +955, 0xc3ed8e23589b365f +956, 0xbd12efde1b5e8afc +957, 0x35b81175f738edc8 +958, 0x16b2627c28c952c0 +959, 0xb16a5009047b002b +960, 0x5e4c769bd80bed26 +961, 0x96174863aa73bf6b +962, 0xb3bfe6a2d7d05881 +963, 0x5c0a1757302c3fb6 +964, 0xfcc52e2da058ae67 +965, 0x12b26055c0ea26e8 +966, 0x87d8126b14b8417b +967, 0xc87745c58eaa597f +968, 0xb38b4b4b579ab55 +969, 0x559ece2bb0ca0b32 +970, 0xecbf6af7914a6435 +971, 0xd994b534e3f46c42 +972, 0x67301d5555cbaf1 +973, 0x4b2222c098aecb6a +974, 0x2f1b7acadaa10ffc +975, 0x4c48c65a542d56f4 +976, 0xf3fbde71409cd64c +977, 0xb32e3ef1dc24a7cb +978, 0x229321ce5bcd85 +979, 0xcad7e7dfee447d7a +980, 0x7fddd28936d166a5 +981, 0x928bfb0027da2715 +982, 0x97b17752c6aaa82b +983, 0x3eaca529c941d7c1 +984, 0x91937555520265e +985, 0x8e7e5c3786ee3588 +986, 0x27162348b08a9aca +987, 0x302165a3d76eab04 +988, 0x94111b7672c6bd95 +989, 0x7a471169035fc35a +990, 0xe850ed94b0be86e1 +991, 0xf7a3721d6c85c1cc +992, 0x6727a68e16268dfc +993, 0x65433e82f0e19d29 +994, 0x6109fd616c977544 +995, 0x7068ef83a29cdc70 +996, 0xcef2deae0fccb574 +997, 0xee2a2ee021a6ad5a +998, 0x5195005fba78706c +999, 0x31364d630d333f34 diff --git a/_randomgen/core_prng/tests/data/xorshift1024-testset-1.csv b/_randomgen/core_prng/tests/data/xorshift1024-testset-1.csv new file mode 100644 index 000000000000..661b157b155a --- /dev/null +++ b/_randomgen/core_prng/tests/data/xorshift1024-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 0xdeadbeaf +0, 0x2968fec4616d9509 +1, 0xe82b10da7bd80ac4 +2, 0xa876e84316e70643 +3, 0x888c2d982b27d7ea +4, 0xd47d3d65778ed02f +5, 0x25af25e8c1c544c9 +6, 0x8e6f9814c92f661b +7, 0x3e71ea4e4046b05d +8, 0x9e1b58fa0207d9c0 +9, 0xc0393d91a0decbd +10, 0xd47df476d2f67dd6 +11, 0xf8a1b120acb29876 +12, 0x54d2351fff4b408d +13, 0x9321d56bc4bef94a +14, 0x12cb604007aac05f +15, 0xdabe30bab4e9a876 +16, 0x31962560988e567 +17, 0x53c8c00896fb249a +18, 0x9168b213fa8b49d2 +19, 0xe826ed57af7757c6 +20, 0x44084ca88c61d0e1 +21, 0x8a447ca13984034f +22, 0xea56bca7496a1192 +23, 0x38e40233ed1cbbdf +24, 0x826a5efdb65df22 +25, 0xe08ec869c2a206ad +26, 0x20bf847ba6e1475c +27, 0x268e99dc93ac3518 +28, 0x214e2263efcc56f8 +29, 0x4e62968a99e00539 +30, 0x2a12a52c634607b4 +31, 0xb0341a4f4a44ee46 +32, 0xaef66935a23e89bd +33, 0xe73d009165d10070 +34, 0x9d29bca8937c1712 +35, 0xac3450f789a44382 +36, 0x443eaafc99628e70 +37, 0x48609ba2fdc6814a +38, 0x6e01d53af8a01099 +39, 0x1b725df253d832a0 +40, 0x68ead3c52c36b98e +41, 0x36ba072b471d0dc8 +42, 0xac1fb808b1d93c3c +43, 0x2c36d9080979be7d +44, 0xcb9b374317b668c9 +45, 0x3c960912b44d56e +46, 0x657454550f8d9c1d +47, 0xbf072badce6c2737 +48, 0x6ee018e5c5cdd2ae +49, 0x609301623d936f60 +50, 0x35b40c58a518a941 +51, 0xf7d24a9c7d57564c +52, 0x7e4845b8f0374310 +53, 0x2a8223e03ac4cc2e +54, 0x1dc81758070ebd3d +55, 0x1320cd7c3abce6ca +56, 0xe95f5f03abd4731e +57, 0x90b6a7ee72f350f3 +58, 0x55e452037c949ad5 +59, 0x78d987c7609b326f +60, 0x9bff2e52746449e8 +61, 0x72cbc26a9b57c406 +62, 0xb8959ab6826ac35a +63, 0x59fe539c62ff9483 +64, 0x8c4cde1d65563241 +65, 0xe95ac9f2113f1be8 +66, 0x2846aa0dff366b9a +67, 0x39c3e61f5dc795cf +68, 0xf2b9b55af6b6b5b0 +69, 0x733951a107450c51 +70, 0x936dd0f66530a3a5 +71, 0xd55b63e0b5b6ae46 +72, 0xaa1035d6d371b80c +73, 0xf4f3719e466df564 +74, 0xece7d9e23f0a45bf +75, 0x95934ea577a81777 +76, 0x976a1776f73c1dac +77, 0x18029546eafd78b5 +78, 0xbb3ab35668fd6e65 +79, 0xb6915972b96a5b95 +80, 0x850ad09ba84b49c0 +81, 0xdb4a551245fcd15f +82, 0xbc2d21640007eacf +83, 0xba298f635a1645c2 +84, 0xa4aa6afabb88bb5d +85, 0xebcfc388cf8b1367 +86, 0xef6be3c48d331077 +87, 0x19132af4445e429d +88, 0x2f76a37bc0e45ced +89, 0x13f96ad00878df48 +90, 0xb8fdad62c4f0c365 +91, 0xf95de6a5528ec985 +92, 0x481aa24b342ffcfa +93, 0x132ccc5c3747112c +94, 0xb196b0efd2d09259 +95, 0xcf62746a3bcdec2c +96, 0x996325bf949590b5 +97, 0x305700d04fa07df1 +98, 0xaeab52bb4902e669 +99, 0x80068435ef98181f +100, 0xf3246828280d675d +101, 0xf59f61b26f5caffe +102, 0x15b7df7abf1d8759 +103, 0x3ff43423d8680a02 +104, 0xafbaaadfeb8ec37e +105, 0xf8be84cb4cbfedbd +106, 0x9e797d3b952a645e +107, 0xb9ff208124efc7a +108, 0x2e2ea03051b1d3f4 +109, 0xf059946cd8062ef5 +110, 0x5dfaa02e1c1c33a7 +111, 0xb938008377468bc2 +112, 0x29bd7ba26ddb5cfd +113, 0x8599e95956955b5b +114, 0x9674aa92fdbbaf2b +115, 0x6927290eba39179b +116, 0x48a4b594b063fc01 +117, 0x12cb99682cc95ca8 +118, 0xd0198db4fe06e935 +119, 0xe2efc92564cd6d78 +120, 0xf29e3401fe800978 +121, 0x3a45b04622a1918d +122, 0xc7d986f6cee748a +123, 0x18fe46fe75a1d8b7 +124, 0x94b0e9c83192d269 +125, 0x381890e6c4a10efd +126, 0x42305bef9a1eb0e7 +127, 0xd2e8f910b5a96bd3 +128, 0xa7343b2938ef16a9 +129, 0xe432fca6a883a22c +130, 0xd923cd3bb0c77a46 +131, 0x771440156f17d440 +132, 0x3a103372ad5c822b +133, 0xd65317c76a70e0b6 +134, 0x6bf5a7df9ddcbbea +135, 0x8a62bfb4bd7ee1cc +136, 0x14c564aeddaa9842 +137, 0x111d23185c329a25 +138, 0x80066727b94859b0 +139, 0xe76f847614409d35 +140, 0x61330b492b389f64 +141, 0xde2a98a5a181fb20 +142, 0x50ffc4f594291ec0 +143, 0xe766de7529bff4a +144, 0x440629959a350415 +145, 0x6e6f7cc6e501d547 +146, 0xb31b8eb4db5cd9e5 +147, 0x32e8e659bbfa3651 +148, 0xa3bcfee564006c60 +149, 0x71563f2f89f0da28 +150, 0x83dee9a700a53a62 +151, 0x4f3cf79d558883cf +152, 0x6a3f3d752b3ef555 +153, 0x92582ef4c19a74da +154, 0x6dd33c13eb4103a2 +155, 0x63e7310213e9f7fa +156, 0x9ce3c17c6b9a076c +157, 0x5e3f2d4d07b42014 +158, 0x109589489e174134 +159, 0xaf51d807c1140a71 +160, 0xd5223c84c2425bec +161, 0x6ba4d7869f4259b3 +162, 0x597067c2bfcf3489 +163, 0xf9c59e81f49883a9 +164, 0x5e4a60775ded4b74 +165, 0xba6535ab12b07bf4 +166, 0x9922d0b7a853d36d +167, 0x9059571a67c9bd7a +168, 0x55c0b45bc5687a44 +169, 0x22b726e1a977463f +170, 0xd3467ec3e6888b9e +171, 0x420d1f2b5a3db74f +172, 0x87ac3bbf7ead0f24 +173, 0x6eefc0436f3199b2 +174, 0xe862c445add78a8f +175, 0xe2408382341cc1ef +176, 0x759152fe96db65ae +177, 0x58a46b8ee63f95f5 +178, 0xc2b639beacfb790c +179, 0x50f35b69ec430636 +180, 0xb565cc1acac8a8dd +181, 0xe2a379d5edc2ff2f +182, 0xd0abfb8ff3c76c0f +183, 0xaacb26508bf52c62 +184, 0xece254ff3e0fdb97 +185, 0xc41bf846cdd6b3a1 +186, 0xef03f2c371e3a12b +187, 0x1ce74e57ba14f001 +188, 0x9b5dc37c48907b32 +189, 0x6312b7a3c0e0d71 +190, 0xde51fea867eac892 +191, 0xa09af6cd2a5e2703 +192, 0x173416b34c78e921 +193, 0x892a28ab1909ba26 +194, 0xc77a69b6885a8f89 +195, 0x3d508e62c2feee2f +196, 0x5119ad966235eea2 +197, 0x67f0222ecb886bea +198, 0xa9c1bdae30c4e60a +199, 0x2d518b070541cb10 +200, 0xadc88b8fb3d0345b +201, 0xaa8e0549c3d8081a +202, 0xf6922301b0234292 +203, 0x57c61f02f871f052 +204, 0xb68b57425ec40f26 +205, 0x64e6bc6cdeb78a38 +206, 0x1dc5e9141a3e0118 +207, 0xdb5c616c4b112874 +208, 0xccaa45b96144a599 +209, 0x3c2570670361fba5 +210, 0xab63b1345fee697a +211, 0x2cbcf6518ca555f5 +212, 0x4b84780b234494f3 +213, 0x934519ac136d696a +214, 0xdf19065ede5d9033 +215, 0xc4f240f01a18c940 +216, 0x51799f4eb478267e +217, 0x22bdaa06e7ced71f +218, 0xc42a003cdaa32e09 +219, 0xa3746906fac5abc8 +220, 0x6ff7b8a74c61d8cc +221, 0x48fa29ab00d2e849 +222, 0x1409a2bdc81c923 +223, 0x50d00ad328c1fe85 +224, 0xab79bc5db01d9a6e +225, 0x3fbcfd2cebabc23e +226, 0x1814a2065f9efbcc +227, 0xbeaa8ece82351ba7 +228, 0x391ad79ff0512dfa +229, 0xad5babcb6318a0a5 +230, 0x2cf1ae641d54b7c5 +231, 0xca32becbaabf2e9c +232, 0x8ba3d47914242362 +233, 0xf1a764b81ffcf79c +234, 0x91f20f4ba933dbbf +235, 0x88ac060061f0363f +236, 0xda21e847fc8e1aab +237, 0xdc7f4d3e6cf0baa6 +238, 0xd85c1d81dc96ee90 +239, 0xba23e43a6b5051ea +240, 0x90a0939eea412d8b +241, 0x12ce33d77b029fec +242, 0x5fbfb6a87d6357d2 +243, 0xa7597dd027f65afb +244, 0x8ebb6b8b8b185239 +245, 0x45e89426a0d04436 +246, 0x4a5383818bb40ec8 +247, 0x919b5b80a43bda4e +248, 0xf9b8d22461280026 +249, 0xe13ad8f7ab5ee8f3 +250, 0x39c8d72628967129 +251, 0x6de22f7a2fbf9e40 +252, 0xc6c5744d174deb7b +253, 0x626e5f3a50df3c90 +254, 0x62f8e30ba24dd13 +255, 0xd72dc4febe774cf4 +256, 0xd200b1afb0a73c25 +257, 0x65c7563901c2fc64 +258, 0x30e9818e85515f7c +259, 0x8643ffb0bb71293a +260, 0x3abe1c4ea7de258c +261, 0x45084bb1f370c75e +262, 0xed89ee41dc8c95a0 +263, 0x99bb56fb1279d194 +264, 0x217d6c46d7d50ea4 +265, 0x42dae06f1ca3c2be +266, 0x3103af8d85ea50a8 +267, 0x7cbd22f30fc047c +268, 0x9b981290c7de08b4 +269, 0xb0d2dbe062abbbfa +270, 0x2de6fdb8df120a87 +271, 0xffd5f46e69d4f755 +272, 0xee735a0f05dc71fd +273, 0xe079ecc2224d9a64 +274, 0xbf400cdc00cd920d +275, 0xa2757efb078c65dc +276, 0x3a0d632515afc842 +277, 0x164dfab63dafc317 +278, 0xcb7a3131d97eaa24 +279, 0x3ce938f6a615ad07 +280, 0x8e23c8155a33858 +281, 0x26ffdf8d6b4312a5 +282, 0xa73c99c8f5a2efff +283, 0xb622fba6a1cca389 +284, 0x933a270fee14587c +285, 0x97684114e2320ae4 +286, 0x585ba967f0b16324 +287, 0xb0b3306cd44abac0 +288, 0x6ca0f5ef7c106cde +289, 0x995d51989aa1c417 +290, 0xc9f2c923fe4455a5 +291, 0x643815429f7eb3b2 +292, 0x62ea9ec7264da11c +293, 0x447d0b45dd80f0c6 +294, 0x28f4cfd3070a7954 +295, 0xe489352888499c52 +296, 0x8052cbc99a85e051 +297, 0xb8f3cb6026cc90ad +298, 0x912584210563a88d +299, 0x6d4d13a07f86a423 +300, 0xfa4d51b338c3b5ae +301, 0xa03ef23eb024427e +302, 0x6f7f11baaa5687bd +303, 0x408d5fb68881b088 +304, 0x29e51d59129fc75c +305, 0xcdec3ff5975e02f7 +306, 0x6008150d8694fb00 +307, 0x1716a8dc698523b0 +308, 0x5630cb8b8291ffa +309, 0x5fd5da716e1a78da +310, 0xb1a6db0fce436d0 +311, 0x57e1d30fd93a3c37 +312, 0x72757a0a3321ea6d +313, 0xcc76c5afc421e56d +314, 0x16190b05f0b40caf +315, 0xf78a3f994c913ad +316, 0x7e1a1b1c5d24c00b +317, 0xa1e2fb1ff0b9d6db +318, 0xfc498b8039b54f0f +319, 0xe53a07e1d2eaea28 +320, 0x78fb2fe5aead5931 +321, 0xc88e3c02e3dc1785 +322, 0x1316793c718709cc +323, 0x87ee50ee2442393d +324, 0xfaed744d0586ef7f +325, 0xb421ca20f3f36511 +326, 0x167a97dae8220873 +327, 0xd1923f827aaa2686 +328, 0xdabb838e2156893c +329, 0xef5035dbb60a0e43 +330, 0x4eb59086d683c897 +331, 0xf53508888be59fda +332, 0x6c901a026863b64f +333, 0x533e9b2905812820 +334, 0x5995efd0f86f0247 +335, 0x85407d7c71a8519c +336, 0x4ec365075d3107de +337, 0x2ef189e758ccac93 +338, 0x94965c831e00c74a +339, 0xc703660168ee5f1e +340, 0xb299ff5db8adc89 +341, 0xf016bd3198c82f20 +342, 0xb547315812240a6a +343, 0x2615627e3eba8870 +344, 0xb78e0f43405b7898 +345, 0xa9d14916e9b7efb8 +346, 0x112d9ae68e8904d9 +347, 0x3dd1e5d8d87a2a00 +348, 0xe72d6f0971f538dc +349, 0xa39e9d3bb475c18b +350, 0xe8e4c1e4d8c6a8d8 +351, 0xbd79ba7f0ad62765 +352, 0xc385792825aa00a8 +353, 0xb6d7f610d9c4d243 +354, 0x4335b0eb532176f1 +355, 0xc0a2e5238b8e0677 +356, 0x16c65023c679608b +357, 0x4d994626744b8f46 +358, 0xcb0b2741af2df9ca +359, 0xe4a7e3fe75a1aaab +360, 0xe32a45741e898d8d +361, 0xe67a3f4fd4b2b6d2 +362, 0xa0ea8adc980fb9df +363, 0x22677c7e716dff46 +364, 0x61a419a44db57308 +365, 0x2450dd931ff2ec3f +366, 0xce84c6e8acfad7fc +367, 0x760e778b2e193a05 +368, 0x8eae9f11a89be32 +369, 0xa4e9d719935d50f6 +370, 0xd5b566b0369a52a2 +371, 0x42fc4fca6052ff0e +372, 0x54bdc983732078bd +373, 0x2a34b26ece1a4a1f +374, 0x4a6c02709bf62226 +375, 0xe764d4869ca86a88 +376, 0x3b55160e0eccab3d +377, 0x6298740e7a75206b +378, 0xf5dfabfaf966966a +379, 0xb69af13f6a58df15 +380, 0x40d98d1218870fd0 +381, 0xd31db917ad090d36 +382, 0xa0f51d92105470eb +383, 0xd49a359996308801 +384, 0x9c0a51cf0afe4987 +385, 0x3c5139c9bde54e2f +386, 0x3d8764a94f3910f0 +387, 0x72c022834f060c6e +388, 0xfc1bdf8001e68e68 +389, 0x99fe3ed21088ad60 +390, 0x53d270e055960efa +391, 0xace8c828bb806861 +392, 0x281e3aeb0a9c4834 +393, 0x449b247a025d9c17 +394, 0x9d348001ba4afbbf +395, 0x287d8e15971d6c94 +396, 0x95f6b9856848aa36 +397, 0x7ad4738f43ec445c +398, 0xf5dc701c62cb0707 +399, 0xf85fba15e2f3af47 +400, 0x339c4e96a86d310a +401, 0x8ce140d016eff7fa +402, 0x65edfc5c5c98dbd9 +403, 0x1d0a87d9af90f167 +404, 0x203dc34e1e9ee146 +405, 0x1660fbddaca7a089 +406, 0xa4595cfc69627ae6 +407, 0xf5c6c28fdf65db44 +408, 0x73cc91643c51bf0e +409, 0x56d5ec5f4df77ef1 +410, 0x238903979a24cf65 +411, 0x96268de7413313b8 +412, 0x28a3c908362a9bad +413, 0x728d68bc8b6496d0 +414, 0xbfb6a39f37f22189 +415, 0x9c1e845d3b060423 +416, 0x11962b88cf841c42 +417, 0x5d91b9809053bfcb +418, 0x854693772fd6c780 +419, 0xba2a80b61299b067 +420, 0xc167859290090b3a +421, 0xd8ebc6acc7fdc96 +422, 0x5840dddbfb862b08 +423, 0x5202ea8acba4faa8 +424, 0x49d3bbda86413c0e +425, 0x32be126f76f93277 +426, 0x89663ff83ea2de5b +427, 0x80f40ad26cb40dd2 +428, 0xf766a092380d8ebd +429, 0xa4487b65fe0744ca +430, 0x322eb186046a4a94 +431, 0xc02a504c09a45a1c +432, 0xdb7ee621ffff440e +433, 0xfc0dfc9f26c858eb +434, 0x69c4fe6af18bcd7c +435, 0xefe02edb24d56ea4 +436, 0xa50a14ad0e9eef00 +437, 0xe423d1c202ef28a6 +438, 0x7afd0f5d320da389 +439, 0xdc08b10bf5eb2150 +440, 0x2725a6e6b0d16c3c +441, 0x4ebc9a86ad70a406 +442, 0xe5b234e726949788 +443, 0x61895444577fa683 +444, 0x579bb863c9c0f4d4 +445, 0xf57472f1c2186e40 +446, 0xe20f9e4dd18b7a86 +447, 0xdd874db6f18ad18d +448, 0xd33a6863b26e7e0f +449, 0xfbb06768ee299508 +450, 0xa698449c04c6dac7 +451, 0xef8956f00b0b93b6 +452, 0x50187c36dcbb27b5 +453, 0xe183c93b50fc5db2 +454, 0xeff4e91a9f691af5 +455, 0xfeb0c53b5f79d85f +456, 0xcdf64cb7aa9e77b8 +457, 0x92c7e1c5d0cf8545 +458, 0x2364334169a8777c +459, 0xbb59d00220215aa6 +460, 0xf0e84db1ba5e485c +461, 0x32eadec20b527e69 +462, 0x40a8c172ae43ffe9 +463, 0xef1bede2c2ded35a +464, 0x92db9273d1c956a3 +465, 0x6c9cb922edb2d4b +466, 0x5a679c0c94b3f39f +467, 0xe6a5221838453419 +468, 0x66de19b420c14ee1 +469, 0x8c2bd98ad9467af1 +470, 0xa147d5f399568982 +471, 0x9e8aae9d332472be +472, 0xdefb07cadadfbd88 +473, 0x444a202d1b2edd27 +474, 0x319c8773f6a754fc +475, 0x36606ba635cfced5 +476, 0x31504a5b044d1808 +477, 0x806e09994bdacb17 +478, 0x9427e77e577af871 +479, 0xb59d548f5aff715b +480, 0xf52251410861803d +481, 0x38e43e9d0e116362 +482, 0x4193f31faf42df63 +483, 0x220bc4765445a54c +484, 0xa70017472927b966 +485, 0x7df2a19540ba70f7 +486, 0x312517443864a8a6 +487, 0x5b3050b6e7369529 +488, 0x7d78902a459de6bc +489, 0xb55cc03b010496e2 +490, 0x4b5e70c18d90afe8 +491, 0xa25c9282539ffa39 +492, 0xb3634844d85ca854 +493, 0xd70f1ba5cb23f155 +494, 0xa7164bd3ba66fd13 +495, 0xe8fa24efc28e0b35 +496, 0x53cffa8448fa39a3 +497, 0xda1963ccf029a46d +498, 0xab159eb294b3b2ed +499, 0xa3a837503c32174a +500, 0x83b5e56c63ca910d +501, 0x77174c7925c01bc4 +502, 0xd9723ab7a9b06742 +503, 0x407fc7b87e1b3301 +504, 0x3067a710c13076ae +505, 0xf490b50ae1c760c0 +506, 0x3984834f76388042 +507, 0x8f61a75763eebcc6 +508, 0x5526d22e2c18bfca +509, 0xbd1f2ed9006893e5 +510, 0x751810cfad06bf24 +511, 0xf21af6042e4b3618 +512, 0xc159c3b878206376 +513, 0x1f40d0561588b836 +514, 0x84e387cbeefc8370 +515, 0xef8378b1b551cf8b +516, 0x501934cdd42db314 +517, 0x2671bd3b0b8edb35 +518, 0xe08db954f218bf8b +519, 0x6e2daf982de67f0d +520, 0xa07c0f0c4958d787 +521, 0xd7fe2217582a0977 +522, 0x8c4b91a83a7dd84e +523, 0xb0f97b4621d12984 +524, 0xccb5ea2b6fc4d012 +525, 0x65fd9271c2cdf119 +526, 0xedad88bbdb81bc5d +527, 0x3d744a2bba50afd +528, 0xf30a4cc4a9a02eae +529, 0x1ec08d6b2a3aae18 +530, 0x93fc3ba3fda6076d +531, 0x1a51f49322a2a528 +532, 0xa9f55a607051835e +533, 0xce3bccb15f94a155 +534, 0xc7e0428cc4a6cd37 +535, 0x24707a92b8e71cd8 +536, 0x443fe1ef6689de4d +537, 0xe5610bdfa3bc3809 +538, 0x1c684dfabc1a719f +539, 0x3e41dff1948ab65a +540, 0xa58cb5d77eed149f +541, 0xc589c050bea7760 +542, 0xe4b8316d7455d38d +543, 0x3ad6140f84f0c0dd +544, 0xdf7deca619fedeb9 +545, 0x5fcb5d0ea1b1e47a +546, 0xc602267112df1d8f +547, 0x91f44054fac54920 +548, 0xd740c0213fdac4a0 +549, 0x677a64717564c678 +550, 0x733009a5e9360091 +551, 0xa50ee09f5b7f8854 +552, 0x2b7a9cb61c3de26d +553, 0x23349b2382903734 +554, 0xb498a233184e1c0e +555, 0xb44201ef4443deae +556, 0x6daca8c5a6647612 +557, 0x36f4b7e94bfd7b50 +558, 0x8ca5d0a0098bea0e +559, 0x5bfa417533e65be3 +560, 0xb2b7ca005d530c22 +561, 0x780136e2cf6fc471 +562, 0x874a13ef938027a5 +563, 0x1e855317eaf4937d +564, 0xe9e122ade32fc335 +565, 0xf24661d4287b8f5f +566, 0x6113a640f6a23e6a +567, 0xa5d681ea6fd4538d +568, 0x2f5afe3fa42ac6f8 +569, 0x924ace74f2200a67 +570, 0x2860af7bdc0a1328 +571, 0xc18d7e42dbe8defa +572, 0xd565ccbc02300ca1 +573, 0xe2c425203673bc87 +574, 0xe7cc4d62fcb1b7a5 +575, 0x4736a2fc73e0408 +576, 0x8b63d58d06bf6f4f +577, 0x2fe82ed95c103404 +578, 0x9d6458914f301d00 +579, 0xe6dbde6799cb0c2d +580, 0x437153bd57359448 +581, 0x91cca254d0b51be1 +582, 0x4b5618013971476 +583, 0xf7a30620ebd70ebd +584, 0x3170e9eba79c8fea +585, 0x8983fb74dc098ba3 +586, 0xe597a911134d02ee +587, 0xc1bf7730780802cd +588, 0x1ac341a0343abe36 +589, 0x877addb61c4f6d53 +590, 0xaa6326c5c9f7dfc3 +591, 0x2176da3fa9450570 +592, 0xb9086e2124d7db1a +593, 0x75b150a1ad48736 +594, 0x72361f3255bb1c6c +595, 0xe77633cc35d21649 +596, 0x7fe0c14523deda1e +597, 0xbed948a006ab7ae +598, 0x5deecc48e391cc9e +599, 0x1c60216cb5b769be +600, 0xeb3158cd91cefbfe +601, 0x8ff0059d384b3482 +602, 0xc270fdcdf1b27054 +603, 0xcbda49df540f7bee +604, 0x9569dad154192b1 +605, 0x626b1d9dc5af9355 +606, 0x1f2e390fb9f72c34 +607, 0xb5da34db64cb3c12 +608, 0x91bc689a0a76f72a +609, 0x722e70eb16c2883f +610, 0x4e3e4ffd2dbc23eb +611, 0x530b6cc8da38189d +612, 0xcc1e8a97bc9f7f3 +613, 0x8606896c6384df29 +614, 0xf12057ea9246c3a6 +615, 0xa36176adf40ed649 +616, 0xbd41dd899b1e7e1e +617, 0xee6b4a30cfc1705a +618, 0xecaf8b48645b1a1d +619, 0x45b9d22e4b67d526 +620, 0xf4633b7932f7b231 +621, 0x3d110c58b9d3af76 +622, 0x5476134f5a62c65c +623, 0x8b8c459aebedbcfd +624, 0x85438a06efcf7244 +625, 0x4093cff6b13d0235 +626, 0x3441e41c4240a04a +627, 0x7d2ddfcef9e1502a +628, 0xb103bf1629052a4e +629, 0xc7b6242cd4b0ac6 +630, 0xca90bbd3896e5cef +631, 0x475a4f194b2efc95 +632, 0x40b7befb56e87d9c +633, 0x6cad487ce5b9fab7 +634, 0xfea988ecd11b1e48 +635, 0xeae1a787969dd6a +636, 0xca61203919f24b59 +637, 0x4fbb1b7da2ed1eae +638, 0x2293875acfb13bce +639, 0x83bdb0d855f80904 +640, 0xc6cb9af3dc51663c +641, 0x3670a82bf259af61 +642, 0xad19636327ae2f9 +643, 0x1e3c9eda8aa86f0e +644, 0x9bf0294f709db9c8 +645, 0x82634a2a6f68d88b +646, 0xd28459865ee6ba06 +647, 0xdca0589a37b686bc +648, 0x6d599e666b676946 +649, 0x532da8f80b2ab6fe +650, 0xd04c13960c6ada57 +651, 0x6b6be861eaa20840 +652, 0x7bee96f844d8af14 +653, 0x5262b1b291404b11 +654, 0x7c2e76df26ec97a5 +655, 0x200a74e9d28af98f +656, 0x4c524db7ac5bdae0 +657, 0x7220e9ce3b2bd645 +658, 0x253c92bd314da1e1 +659, 0x61c99004de5ee6ad +660, 0x1a8b45e7a2b8a09b +661, 0x8210afa2eb0147e6 +662, 0x275f3a56f6ec8ba8 +663, 0x882e054db980aee2 +664, 0xa2a4f61060588c1d +665, 0x7c4cfbadd5d38529 +666, 0xee8a9c0ae89de452 +667, 0x3a1e9d46843f2574 +668, 0xd076b0d7f2e7dd81 +669, 0x16c1e3acf3b45fbe +670, 0x182de2922f0e2a0c +671, 0x9ae8e92260ea419a +672, 0xe07af4e2b7b48d7d +673, 0x600e3ec66ee20ec2 +674, 0xf7036d1caeacf4b8 +675, 0xc147ed61fcd4f647 +676, 0x7f9e195665802bba +677, 0xfed9db42c4ab22eb +678, 0xaef24cde91dbcab4 +679, 0xf84b896fabe3218a +680, 0xc99a2b2725700ca1 +681, 0x8e9e3242ed539a42 +682, 0xd68f96459b7d4eda +683, 0x3519bfc85e559ae1 +684, 0x6837e68bef1bac4a +685, 0xa09f0e34eb061e55 +686, 0xbf9ad807ad35e4e9 +687, 0x5a5d949c5bc4a894 +688, 0xc5c44dae5464903a +689, 0xca5b2b8c8ea7b8a8 +690, 0xa55ff2894f125040 +691, 0x9f6ff13eae26b16f +692, 0x584babe068e32d0b +693, 0x675701bb344f15d8 +694, 0xc7cf1a1ae4965137 +695, 0xcbd397007200464 +696, 0x441dbbbc178e9f1f +697, 0x68de3be524e615d0 +698, 0xeeefd0ae2953fde1 +699, 0xf3f25710aac6e8dc +700, 0xa6e739afd86491f8 +701, 0x788b33d85140da94 +702, 0x93e31f17b30996bf +703, 0xe339877de36dc99b +704, 0xab8d1922e63a81a7 +705, 0x2fdec0bc47274e3b +706, 0x46fac763279a6456 +707, 0xcf43d49178b7e2c8 +708, 0x6c97160d52f7541 +709, 0x338082733f40fe0f +710, 0xaaa7adedc68075fc +711, 0xf6be5a0983c7e38e +712, 0x23704a0305bb6e4f +713, 0x863b4177c8b4b645 +714, 0x49d46155cd596ed4 +715, 0x9c3aff0f8f51e7aa +716, 0x818d564029593dd6 +717, 0xf86d183be4f9bc67 +718, 0x2913f9929b732227 +719, 0x70170b1cd3a3ac54 +720, 0xb8a80aa5e5a049ab +721, 0xc11837b6e5d05914 +722, 0xac4e428e8179ffd0 +723, 0x365ae1ad260341a2 +724, 0xdeb434fa400c659a +725, 0x301e5022964913a7 +726, 0x9b5353184587e65c +727, 0xe87952dcff2bb94b +728, 0x38018ea9168498f +729, 0x5329faa0a9b31518 +730, 0x4e9826e7a5309cc6 +731, 0x8c8b3902b3fb31cb +732, 0x51fa6eb8243361a7 +733, 0xf83033cee6066488 +734, 0xb5bfa21e11d0084a +735, 0x5dea1df773d5472c +736, 0x8df2cd3cf75596ea +737, 0x927d1c793c8cea03 +738, 0xf1c36260836e102d +739, 0x1359f6c8df89970d +740, 0xa6d259498334bc +741, 0xa6e07155f17c845f +742, 0x10deac98d78f615e +743, 0x82dd4e3ebd26fe73 +744, 0xa38711f23c38a1af +745, 0x2fdcd69782301538 +746, 0x216d402e19d85877 +747, 0xac673ce673285122 +748, 0x7875f10741c5d847 +749, 0x68c40a47711addc5 +750, 0x2993772e15b714ab +751, 0x7e98b5fb52c5fa95 +752, 0x4bbf5c436cc0ae +753, 0x18b9dd31c535817f +754, 0xb461f16678918bed +755, 0x3c036fc204d6af40 +756, 0x97a7f1ee6acbac2d +757, 0xe14fd6e30c86a58d +758, 0x88573c172e1f841b +759, 0xc34525268445a76a +760, 0xd87d260c104a3640 +761, 0xe4e89f8d92a8d78a +762, 0xa8ddfdacfdb10b31 +763, 0xa4afe400345727fe +764, 0xc86d9a624d1c58ec +765, 0xf343ee93309d8a86 +766, 0x3e2e1a0436b09535 +767, 0x6d43bc645ed9ac6c +768, 0x851c37fabf29f39b +769, 0xc3426e0cb4dd3941 +770, 0x497fc67d26f9c0eb +771, 0x763f57a1e7b7c7f2 +772, 0x6d17c1946432276a +773, 0x8eb40863a03a9f6 +774, 0xb4d2efaf434f99e +775, 0x3b7362a21b09a974 +776, 0x8346f15db661117d +777, 0x935d7f4718c0b76b +778, 0xebecf09e8cd66494 +779, 0x6488514887be6d6e +780, 0x8967e6482106a9b1 +781, 0x1027a9c65d640f4b +782, 0x616ac0c09e0c0424 +783, 0x370fd6f501ee434e +784, 0x64656b86647db284 +785, 0x1e75f13e5710fe36 +786, 0x6f707be9595741f3 +787, 0x36005270b95cedb2 +788, 0xef4d96d7855c072e +789, 0xe00dd4df241aa017 +790, 0xb7636a7a39dbec9d +791, 0x55f0089bed163558 +792, 0xbc2629bb08892645 +793, 0x7972323d3b65070a +794, 0x6d034ae888e1dde3 +795, 0xe3746defc543a1fc +796, 0xe21f07f7946046e5 +797, 0xb4a1beab89060010 +798, 0x7599da8e80780a1f +799, 0x2c9a6831a67fac80 +800, 0xd96d4d3e81ba74d5 +801, 0xb9945639961e680a +802, 0xd8a540ebd9244a95 +803, 0xa083f2ced29445e6 +804, 0x8be65673106fa2dc +805, 0x9896bf42455914ee +806, 0x12143e7988bb5799 +807, 0x53c754030fa4a756 +808, 0x1737b69502b0aa59 +809, 0x2ddf23fe48a62247 +810, 0x3841e493ee590199 +811, 0x912f09f5d33d43b8 +812, 0x19229c58ff93efb4 +813, 0xf1779404e2983aaa +814, 0xe83633e2c248d359 +815, 0xc717450be4d4874 +816, 0x96c7e09c87a882d3 +817, 0xf7de965536666dea +818, 0x8500552659716f4e +819, 0xa325745ddbd5991d +820, 0x646a7720bf41f124 +821, 0xfcb2de34a2319f8c +822, 0xa5cb25a06e56c96e +823, 0xc2098ced3a1d7f16 +824, 0x4e0c42ddc545e1ec +825, 0x1a81a4072bc8c70d +826, 0x33c8c26ee5f2a8a8 +827, 0xfa73293671dcdea2 +828, 0xdfcef95a123b6e75 +829, 0x1be31c104c2f8884 +830, 0xa3a38df49047b410 +831, 0x927d2d9fcfd5e906 +832, 0xacd1b5febc723579 +833, 0xdb3ae10ff6179edc +834, 0x83034561e2390270 +835, 0xbd9316c92698ccde +836, 0xaa17f5dc651ba328 +837, 0x21fda6d3c574a13 +838, 0x5510e62023ec3b60 +839, 0x8d939254ae548157 +840, 0x10f3d1f467526a1 +841, 0xb86c845b5fc5248a +842, 0x8545fc74955c82d1 +843, 0x394de00459610bf5 +844, 0xb98e7648d039f546 +845, 0xec2c9942f392b082 +846, 0x63fb45dc65abb87c +847, 0xa293317b6f87fbe7 +848, 0xeec10eee4880bdab +849, 0x7e0a96d7a639db96 +850, 0xeafa162cdb08dcb3 +851, 0x816e68da04ed4bf6 +852, 0xa4700cf2444147a6 +853, 0x5538ff41c87380bf +854, 0xe7e18e47273372ad +855, 0x6b9344f90332664a +856, 0x38f37af3a5ecf737 +857, 0x51e7197547bae5f2 +858, 0x417b49ddbd5c8ac1 +859, 0x7aefd1477efa2b53 +860, 0x3760d5701bf49440 +861, 0x710be29a267e823e +862, 0xf4c6d8607df3e45e +863, 0x452230b3ed570aa8 +864, 0x6f99237e35b6950b +865, 0x6abf4caea61cecdf +866, 0xd43740daec5c5a5f +867, 0xa7f576b3fd5d5d05 +868, 0xb076d89b96a33c88 +869, 0xa39c1bcd83b190b2 +870, 0x7618d27a72b13ce1 +871, 0xaf93ae79c6dac995 +872, 0xc837ce1ec14feacd +873, 0x1606184f9270d69b +874, 0x98a0d302ec1868fb +875, 0x8e4010b8c6ba8b85 +876, 0x91fabe97c826be7c +877, 0x69bd7d8486501178 +878, 0x15008364e9a58f51 +879, 0xa51ab44e26267b7 +880, 0x85ee973bc9e19ee9 +881, 0xfb39b02ce57899 +882, 0xc0f80d8e1f5c890e +883, 0x3f229a821ba4bff2 +884, 0xe9d4c6ff69970580 +885, 0x83e9ccaa3d5ff548 +886, 0xc6554c73cb94447c +887, 0x56d094f66000a7ba +888, 0x2180ce39c7ba63a2 +889, 0x70b47bf5afc29d65 +890, 0x976a3290e523061a +891, 0x3950058fb90fe132 +892, 0x76da108a69799048 +893, 0x42699b4c4f7d1866 +894, 0xf281a11c6bb173ef +895, 0x700b4d769e2f5ef +896, 0xf0e0ce96a60102f9 +897, 0x77b92c4fee413da6 +898, 0xe5dbad4fd50d56fd +899, 0xa240bb500fda3852 +900, 0xa2ace5d55a2f4da0 +901, 0xca519e0c48a53c8c +902, 0x5451834c28b0ed25 +903, 0xf8b83e1f7de31f36 +904, 0x9c8c416b9a1091b0 +905, 0x25884ab7529ae96 +906, 0x6097e452343a4525 +907, 0xff30584230d3f39e +908, 0x56d383168357ba28 +909, 0xca95d287a8895aa6 +910, 0x1820536c986a151f +911, 0x8bb62b7c25dfdf4b +912, 0x46ea14775124a4d9 +913, 0x2424a64e4d04bb9c +914, 0x17738043edc89d31 +915, 0xdba93bd6dc35fba9 +916, 0xf4d84f1396123324 +917, 0xd3afb0d529380864 +918, 0xfa9b0888c037d6f1 +919, 0x5978537bec8f972a +920, 0x8fa9926a080affd4 +921, 0xd5d0b7419c2c0a6b +922, 0x5218c0d0da166bf8 +923, 0x113766ed52074b0a +924, 0xcb3cb49751a8ed51 +925, 0x76f4964c1369cfb8 +926, 0x248ef6f6a0b7987c +927, 0x124962f6cd30d2a4 +928, 0x3ac9098b45d56fcd +929, 0x9db9dc39098adf0b +930, 0x281d775a9aabe3e1 +931, 0xade94768d752f284 +932, 0x2916418b2780283c +933, 0xf6842d520f056828 +934, 0x644f905ae21dee4c +935, 0xb33624d20348f897 +936, 0xe10430135a63b21d +937, 0xe4f73ae0a126d8f6 +938, 0xbe6ba34486dbfea9 +939, 0xd4ee40812332dd9 +940, 0x4ee8a69b86449ad5 +941, 0xb1a298727256af05 +942, 0xa3e558c4f12d9f59 +943, 0x645703828b4d5fbe +944, 0xdf4223058118c420 +945, 0x251dcdba6d3ded09 +946, 0xb2d84c99dcbf9318 +947, 0x8dc95fe1c9863322 +948, 0xfdc6ad87458a50e4 +949, 0x4cf57028f4f133cd +950, 0x5a13d134a30830f9 +951, 0xa550bddcdb0804a +952, 0x8f50b20e973d1ad9 +953, 0x5d8fd8547fbb25a2 +954, 0x57fb0001fd795ae7 +955, 0x80a847e957440201 +956, 0x12e25c663b26ed6e +957, 0x8a3793d5204fdc1a +958, 0xa7e782709f666612 +959, 0xf08d5b5e3e6fe48c +960, 0x226c01d4c843035b +961, 0xde70ce6a314b4a5b +962, 0x2b3f4c7488c346ca +963, 0xda121178e4f987ea +964, 0x9c39f51596ab15d4 +965, 0x56b363742c0401e9 +966, 0x791873978c61e53d +967, 0x703acd4c93373bc1 +968, 0xfa9d1ce6b783d3f5 +969, 0x1dc0a81be853fe40 +970, 0x95a2eff6de671578 +971, 0x49bffaacb5073f9a +972, 0x4f5875882fc088a1 +973, 0xb2cb0e0a7684f052 +974, 0xc8a96b8e988aee2f +975, 0x906c865a40447872 +976, 0x9713e82964a3e5eb +977, 0xa0d4766ce887c073 +978, 0x7375bbdc687fd720 +979, 0x4edbab65f44b6dd7 +980, 0x77d3db5253bac0ca +981, 0x8fd1b3db8997a7df +982, 0x7977905089848b28 +983, 0x60d769441eaa0ceb +984, 0x17eef7b60f4f9f5 +985, 0xdffd2e0b4deff6e0 +986, 0x6c07d6c0eab9583d +987, 0xb6d0c41c540524e8 +988, 0xa5f74648efa213b0 +989, 0xccf793ee870c7483 +990, 0xcb057091573dd7d5 +991, 0x572507949b0a9d22 +992, 0x51bfc469fa3bbb0c +993, 0xc0e35708c36e3969 +994, 0xee22a97b146d408 +995, 0x5b4049f83503ef66 +996, 0xf0bcba04dba7bc72 +997, 0xd27a0dff278d071f +998, 0x9b7eaff14d464db6 +999, 0xfe5f490518b254cf diff --git a/_randomgen/core_prng/tests/data/xorshift1024-testset-2.csv b/_randomgen/core_prng/tests/data/xorshift1024-testset-2.csv new file mode 100644 index 000000000000..ef10e6872219 --- /dev/null +++ b/_randomgen/core_prng/tests/data/xorshift1024-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 0x0 +0, 0x3f76833568b96fd6 +1, 0x49701b0dcd023e7e +2, 0x5f266f1686d3bb85 +3, 0x4df1723af9a5a67d +4, 0x2fb393fa5be2f6bd +5, 0xf7212425ebb2ea96 +6, 0x3f02cec25804b60e +7, 0x7f3a0fa3228a48a1 +8, 0x79d9baad4538be8b +9, 0x4ae9b98e9c834b48 +10, 0x39b5728e47ba6016 +11, 0x9f1d986c6dced8f +12, 0x90e883bb0ca1a839 +13, 0x98995f729732f4ec +14, 0x26b741189221c8e3 +15, 0x293ae8b010a6b556 +16, 0x30180d5248809a52 +17, 0x3edc6105a838a0a1 +18, 0x315e9f489399aa35 +19, 0xd2c7f9142fc59292 +20, 0xe9f6c92674f1e75b +21, 0x785fdf1bf2633d4e +22, 0xbffdf9ac080cf1f7 +23, 0x29c63dce8aca1786 +24, 0x1e16e12f382e3f58 +25, 0x1509b2db378308f8 +26, 0x2f82c24732d9ab17 +27, 0x94feeee6b53644bb +28, 0xea274cb2e3a714ee +29, 0xbe0a718ad2dcb289 +30, 0x3c8ab9a7bb57e51e +31, 0x7eca590bacfdcca4 +32, 0xfcf259b0ee0f33a1 +33, 0x6323e00217e9bb03 +34, 0xbeba78e81e3e1e11 +35, 0xdc83427163d46eae +36, 0xc93193975a686b2e +37, 0x8984b33e2993452d +38, 0x98f329f05f37585d +39, 0x76ce85b5532f566 +40, 0x87bda8155b05a2f1 +41, 0xd949bf037a42d942 +42, 0x9f4021daa72f983c +43, 0x184bff5390deca78 +44, 0x4588bd90c642a4ab +45, 0x907886ff47abc57c +46, 0x7d5edf3810ac69a1 +47, 0xa22a609f3af5f287 +48, 0x6b40ffc40ebcc7b7 +49, 0xebdc35de8c34aef6 +50, 0x27f55c4ed36bd7b3 +51, 0xcb5680ca28b93c4 +52, 0xde59d0be040aeafe +53, 0xcb98df139b6ffb67 +54, 0xe5f29ae79bc3fbd2 +55, 0xf594a05f7d5c2cf4 +56, 0xbf9c12fce3be883b +57, 0xab1ae13d69b39529 +58, 0x421d72f4cc8f996b +59, 0x1e11487c7c5c80e5 +60, 0x3735d17439eec8c8 +61, 0x4b45af31c2a90a7f +62, 0x30a2cb0b8f4effc5 +63, 0x1d9c11ce9ed98912 +64, 0x459938610b8c056e +65, 0xcf8dc26a419b01cb +66, 0x6811a148c58a4b2e +67, 0xb524fbb0a1f9364e +68, 0xba973b1bafcafc8e +69, 0xa5ddb20be4f0ffdb +70, 0xc454734347f3ebc +71, 0x4712b34f7bc603ca +72, 0xcfd5fc37f5f96d64 +73, 0xd9376e1384a016dc +74, 0xd3e2e66d7522c11 +75, 0x143e2e7ceb65246b +76, 0xec0c92eb1c04628 +77, 0x45748e2648e1cf23 +78, 0xe0a78e265aed478d +79, 0x1ade12b47bff7af9 +80, 0x7df63a29c36980b1 +81, 0x1244bbc2c3b55d5b +82, 0x71dafa1fcd09e981 +83, 0x6da5bfe009eb025b +84, 0x446e999577098c05 +85, 0x4e740791bd030e0c +86, 0xeb81a0c4b7411481 +87, 0x78fb5228d162578a +88, 0x22e0adc5d0865c85 +89, 0x161f0870dc2730c8 +90, 0x55cd2b4204fc7021 +91, 0xa3f7032a1b14b9ca +92, 0x854f738869897eec +93, 0x6034a7deeec8a32e +94, 0xa65fdd6da09fcb69 +95, 0xad33713fcb48206e +96, 0xd3dbaad174c43ae9 +97, 0x96dd91e508c447f +98, 0x1a3340c5f67ac6c7 +99, 0xea0c47871d675b88 +100, 0x54bacdff7e665368 +101, 0x9bcc294b0224dc44 +102, 0x61ab987c7f6f44e0 +103, 0xa889ce8426a089e9 +104, 0xb3fbf7d9d2693b82 +105, 0xa034bba7212e9bcd +106, 0xf5b9ceb0347e27ec +107, 0x21a294cdc75fe066 +108, 0xdefd61a8423cc66b +109, 0x8bb34afc4238ac28 +110, 0x123125a26fec35fb +111, 0x12264435308f2e02 +112, 0x3040dc41d9d44a7f +113, 0xc0afa8f0419dd5c9 +114, 0xb104cc03806dbcc1 +115, 0xfee1222b5504c5e4 +116, 0xbd030f4ee7c7bb42 +117, 0xd9ae404361851df3 +118, 0xa152dc8b4829587f +119, 0xbe098e4fc3244521 +120, 0x962610a22b49f5f8 +121, 0x332846cf38524603 +122, 0x50df3207fc830c79 +123, 0xf3f3f1e7e4dc35e6 +124, 0x84a45b323586ee98 +125, 0xd081c30746cd1271 +126, 0x2f8a32f0bab99b4 +127, 0x10b35b4eaaa85d37 +128, 0x544e543d7301f095 +129, 0x7d4eb1f6620b0e8b +130, 0x8fc9da866e9f7d9d +131, 0xad4fc278afffcefe +132, 0x6ec8f6e385d52ba3 +133, 0xe373d4e2c67e1eac +134, 0xb66c7a0aafeb8bdf +135, 0x9c2861000abb6a04 +136, 0xd7ac7033ba369609 +137, 0xa89efcd43ddff9e1 +138, 0x8691faea965fab39 +139, 0x4706b127c3c60cb0 +140, 0x1f2bb20c07eee57 +141, 0x75de540960f2d73c +142, 0xa7d357a7588a06e2 +143, 0xc2fb0569e2deefcf +144, 0x2daa6fdc86ed6b5e +145, 0x8d22e7f3ddb473d2 +146, 0x4bfb1c145aa187ff +147, 0x4072049cc0ac3535 +148, 0x33aff50fd4fbd9a6 +149, 0x3b6b44b730ccbf99 +150, 0x6c642c48d77b70d9 +151, 0x5d906e071f55e4cd +152, 0xd2339209bf1902f6 +153, 0xe83a2462b66f9630 +154, 0x99b0e7998ef43ae3 +155, 0x10f9fed156fa7a40 +156, 0x916d7fe56fac3286 +157, 0x3300c38652e68e29 +158, 0x567d9b4b64e1b06c +159, 0x84760e41f897468d +160, 0xe20a22b206efe5ae +161, 0xcf62d03b167564a8 +162, 0x84154af6fd23be10 +163, 0xe598e0d0794d9418 +164, 0xf8aae24ab57b3e2c +165, 0xd32964005491aef8 +166, 0x227d2b64377a4129 +167, 0xa72ddc508c67727a +168, 0x2e2d60c022c700ec +169, 0x69fa3d4d34fbe852 +170, 0x756111547c3d3310 +171, 0xd462579cae5de843 +172, 0xe6cffa31860e71d8 +173, 0x3b63062bbcf07c93 +174, 0x25a83fddb4d2a4c0 +175, 0xe6b93ed6ee5b01a8 +176, 0x4ce86cf8224d215c +177, 0xe700f73f958137d5 +178, 0xeedce56e96870b8b +179, 0x3a03a241098f72b1 +180, 0xe066b4e17c9e7591 +181, 0x73b18bbd4b75ee0d +182, 0xe2b966c36c34d2c5 +183, 0x11f5a749521edf76 +184, 0x8f865c02ebed5bc7 +185, 0xcb93fe0bce57f9f7 +186, 0xe380b5ddf23dda17 +187, 0x98b03716d02f2dd9 +188, 0x9594e9b56cd3a8de +189, 0x6aa30fb660591e99 +190, 0x1e35c2dd1fcf24be +191, 0x1af2e84dbaae951a +192, 0x7fa337d7cd70b8d7 +193, 0xd0a270c39990acae +194, 0xcabf237235574a17 +195, 0xdf8219166c76b423 +196, 0x7ee41851de09d1c3 +197, 0xd444c75128a3aead +198, 0x595291e15ace95b1 +199, 0x3f96f0a33493d662 +200, 0x524c9f003c2d74aa +201, 0x30e4b6855164d763 +202, 0xd2cc4597098a4500 +203, 0x9a11cf7e7d856ddd +204, 0x6f71b7f4da0728ab +205, 0xa4f4b90919184391 +206, 0xc420d20c06ddc291 +207, 0x40bd7102c1406163 +208, 0x3e0ffda5947e78b2 +209, 0x2b283f6394d08786 +210, 0xea1381e7f22269e2 +211, 0xd9af6fb63feb67ab +212, 0xe65d7ada4c0ed57d +213, 0x29390a105449ba95 +214, 0xb714f9a216f85022 +215, 0x99761fbf534d3253 +216, 0x8bee9140cc17f8ad +217, 0x119bf94d69993284 +218, 0xca34608a9dad7608 +219, 0x6f85cf613b771566 +220, 0xa5d41c9378efd4e2 +221, 0x1189d8ac0d41087d +222, 0x9cc77851a3d6256a +223, 0x363a1ed11a7bceab +224, 0x3e20c00dde9ac9b4 +225, 0xbf1033cb123038ac +226, 0x748824fc5d57ae8d +227, 0x29c6f3b0f34acaca +228, 0x89336ff6ffb38204 +229, 0x367634fdf6f5e062 +230, 0x17dada74ad118131 +231, 0x77fa722a7b7758c4 +232, 0x8ab624aa783988dd +233, 0xbb1a2d574226dd4b +234, 0x1367c3ee11cc302c +235, 0xe303b78053ea7d45 +236, 0x57692f8f470748db +237, 0x88117a25910baa9c +238, 0x67945be555ef710b +239, 0xf78d697319517706 +240, 0xc624069abacab039 +241, 0x406c99876ee0014b +242, 0xc268f98bb4187961 +243, 0x34c1fe6d9a249a66 +244, 0x7b229f23ed186b48 +245, 0x813447c8c6b3a02f +246, 0x7dd08df945ce95fa +247, 0xe8439c737db475cf +248, 0xa060ed8d264bb4e9 +249, 0xfec7390334233d46 +250, 0xc786d08ab50aa0b5 +251, 0x8f8f5f96fc6d877e +252, 0x2ef7ccf97c1c4568 +253, 0x27a14053814966b +254, 0x2ea6f6167c4ce2e5 +255, 0xe45bdc101c584e71 +256, 0x7927f5ac670f2125 +257, 0x51d140214f8fb611 +258, 0x96eba70b12dc9642 +259, 0x30c35af279a715c2 +260, 0x5e6f1fef8babd762 +261, 0x3d84a3c7012aa1ed +262, 0xfaa23aae7c57a141 +263, 0x4f91d0308ab5ccd +264, 0x9ba4c6fb766b1d71 +265, 0xc3bb36fe1a75b832 +266, 0x9c41667dc9637d7c +267, 0x18e7228d28293b69 +268, 0x1d6b71e7e87d5950 +269, 0xbfc7e99d1eea3c7c +270, 0xda9afc08f8b7bbea +271, 0x3ff5761b30c8bb43 +272, 0x81df41076e62f613 +273, 0x7e0a93b2112863a +274, 0x2aded22e3c3505d3 +275, 0xac8708ce5ef15377 +276, 0x273889f29f88382a +277, 0x5f74810e09927568 +278, 0x6e10e51a892a9da8 +279, 0xe6eefe4463d9038d +280, 0xfe194822bf0b3419 +281, 0xcf98d3b3f7701024 +282, 0x3b68bfc20c696612 +283, 0xef06d708e6327398 +284, 0x115d9132577f4566 +285, 0xb0247d0045c6524 +286, 0x1ffb63669817b448 +287, 0x10954c02bb530f75 +288, 0x3e7c1076a5e89acc +289, 0x239b3401cd7e8056 +290, 0x9f8df322b64c4962 +291, 0xbe9539d72df565d7 +292, 0x7ebdf0839712cee9 +293, 0x72f59054c80879ab +294, 0x78cf26fdca1e23bf +295, 0x7f53ea01601034e2 +296, 0xac0e9524b4043f55 +297, 0x1bb323be19e1b898 +298, 0x381e9a0b43ba368b +299, 0xbcbc8ff4b598c9ab +300, 0xa453f6680a2eb4d7 +301, 0x91ffe27309f97963 +302, 0x91c516cace3203be +303, 0x3224f64f8714d361 +304, 0x4f6d6f775c7a2b32 +305, 0x7b84b4d40a2177ce +306, 0x81bbcc7123cbc6e1 +307, 0x97a72d7f8b0d2dd4 +308, 0x21bd4232adf86e98 +309, 0xec4ab4065e523a75 +310, 0x420dfc4bc490cc07 +311, 0xb8bfb45dce69f9c5 +312, 0x6d0459f3cfc48a26 +313, 0xad9c1dea5e333a1a +314, 0x256625ac14326b06 +315, 0x396ea8de20ed603e +316, 0x7419c2884aa94922 +317, 0xd9eeb9a53cb471ae +318, 0xa0aac8233b2d27f3 +319, 0xdecb4cc4c1fd518d +320, 0x5ddd5eb974b7183b +321, 0xdcaf4600c6f236b2 +322, 0x6a7fa0a9ab5dfe2c +323, 0x91608b5fb33fd9e4 +324, 0x934bc1e6635f93f1 +325, 0xcda9674329048f55 +326, 0x7db603137ab31c62 +327, 0x788842593a8a36ed +328, 0xc1144ce4e0cfc1b6 +329, 0xca0da06301356dee +330, 0x2e609e408dc6d488 +331, 0x2c910b390a076ccb +332, 0xcdad30b1f4c3aa7 +333, 0xe5f2803b739851ac +334, 0x9f8ea3daa1c36e56 +335, 0x47ed39920178a5a +336, 0x4cef4092c54e9c51 +337, 0x12ebdfeb4847b6bf +338, 0xebc3f046a004670 +339, 0xce66c4aab5ea2aa2 +340, 0x27088642c863fd4 +341, 0xd7729cf6e92fd77f +342, 0x5a736a0216708ed6 +343, 0xfb49b5fd93f2c041 +344, 0x3e72423a05badd91 +345, 0x7c71eb29547e7bc8 +346, 0xcb40d0049872cf15 +347, 0xa284b7e30ca1145 +348, 0x592d91e0d87f9123 +349, 0xfa4db97733a8d46a +350, 0x33e0188f9b5d5a15 +351, 0xcef2c9a938c4b632 +352, 0x7b0e7bb55e2de88a +353, 0x154509b3c6ccf5e7 +354, 0xd9f168c6562843cb +355, 0x5774a6c2f1870f6c +356, 0xcf61f03f990d2fa8 +357, 0xeebff250f37ba8a2 +358, 0x6e5cda9f932e1052 +359, 0x4d305d91b590a85f +360, 0x26d083f26c6f0962 +361, 0x193d7cf4666a62d6 +362, 0x16d5f99e8a5b06a8 +363, 0x7b0b84b314572d8f +364, 0xc2b5d8f73da78be2 +365, 0x997e699bbdc0e646 +366, 0x720e559e24126bcd +367, 0x46b281355d2f486e +368, 0x6fe30651b885494c +369, 0x5736ed3979ae2d1e +370, 0x3298bf38f1185e64 +371, 0x33c4cf1fd1c9f0e1 +372, 0x84c8acaa32f4972 +373, 0x203d97007f3eff1d +374, 0x6b0b1b27d8fd7c84 +375, 0xc791ed0eed40ddbe +376, 0x13863752048fe702 +377, 0xc5ad8abd0b55c285 +378, 0x1ff361677761ec1d +379, 0x50630e4db5d26a0f +380, 0x1d874f4f175bfaaf +381, 0xf9a772934d22937a +382, 0x33e35f9ec8f608e3 +383, 0xc0953e273301c556 +384, 0x722fa1dbd45e5ae7 +385, 0x937eff91f242e7a5 +386, 0xa1a9e58a6c492813 +387, 0x5a72e88472ea3927 +388, 0xb5267cbdb4e014fc +389, 0xcdaa66f2de7c5ec4 +390, 0x64435583f46235cd +391, 0x95d31d5b002ce32e +392, 0xbfb014b274a6c503 +393, 0x74e839390843cd16 +394, 0xac6949cbf5d364ef +395, 0x1479db78d333bb8e +396, 0x2c7c11dda1f4905a +397, 0xb96f093c2e1b7e20 +398, 0x975acd07a18de87e +399, 0x812358a90bc79d95 +400, 0x76cdee04f004fb29 +401, 0x5e3b3481faf2bb49 +402, 0x890a8a9d41bae44 +403, 0xb7be0ca619af0890 +404, 0x4acb36efb0d6b770 +405, 0x71f80306003ade01 +406, 0x6fecdbb899af55d0 +407, 0x8314c0048baaddca +408, 0x534b12b2f7f0cc76 +409, 0xd9355306b6cb3f52 +410, 0xb0f97ca0e0ab1d93 +411, 0x89d153e37f98ea2b +412, 0x12e68f2795d4f051 +413, 0x906e397219a1ace +414, 0xd4727951a949b01c +415, 0xd33e3ff226ae285e +416, 0xfca4fa59e21a1dd1 +417, 0xec3fe6b91647b696 +418, 0x63d7aa385795076c +419, 0x55ebe0e2765d55af +420, 0xed70c55156b6944b +421, 0x2e65098d479e0006 +422, 0x5311ac9e79d145c8 +423, 0xaca7a78c96a8901a +424, 0xcb38f5f6a6992d08 +425, 0x9c144477c018fb03 +426, 0x216b3b13e04a6495 +427, 0x8e4d521ab71f367 +428, 0xa17063caaccda60 +429, 0x23900aaa25cf3bc8 +430, 0x1889209510603108 +431, 0xc8f99af9d0de76a7 +432, 0xc6fad82edb65f52c +433, 0x9f382a97ae383143 +434, 0xbb4596f5e389ede6 +435, 0xdfbb3da5441e6923 +436, 0x35bf9ee561580153 +437, 0x3c401b162f4a4479 +438, 0xbba8e9feab108d71 +439, 0x78c15ec1926e3d40 +440, 0x24c54d5604a9fb4d +441, 0x3d65e97ac30dd152 +442, 0x3ff106c26e925fa1 +443, 0x994d0fc4273e547f +444, 0x9348554463808d14 +445, 0x16a8f20bbdd24edb +446, 0xcb20c09774c4ce20 +447, 0x83f1b14f2bab7fe1 +448, 0x5b03859915c40093 +449, 0xc578aeb49ce9ecf9 +450, 0xb51d25e52cfa85f1 +451, 0x58781d91ce35247 +452, 0xcd4222374d4e7eb8 +453, 0xbe7bc2cd6690b2e9 +454, 0x2f56338457305032 +455, 0xa5e696a2c3010178 +456, 0x249bb58b22f4bfb0 +457, 0xf439f41bd99cf89a +458, 0xff4987ee68c91e95 +459, 0x496a634e8032a27d +460, 0x8571dd7ba26413d5 +461, 0xec112e9e23f14e63 +462, 0xcff790437f3c20ed +463, 0xa67b9fa0db0aa231 +464, 0x765cc90556d15624 +465, 0x8683c3dd207422ab +466, 0xff2d139be6499b33 +467, 0x72d02be5b40ad6aa +468, 0x8f6d1c4265a58b12 +469, 0x9f0cb4e8a53cb479 +470, 0x85d4cd253510301b +471, 0x3ef6422a20e34ec9 +472, 0x2b510e1f5ec6f97e +473, 0x46a2e5b35fb78706 +474, 0x506a027d4e2205f5 +475, 0x36de7c336f2c9a05 +476, 0x86fbe1c3ea00a2de +477, 0xeec25bddc61238c9 +478, 0xf02b9c043c956a05 +479, 0x6b13b95622a9807b +480, 0x2a9e68f100ee409 +481, 0x41d3ad00d81683f1 +482, 0x8a4b386910e89455 +483, 0x7ab9f9fa2285614b +484, 0x359c0b462d735de9 +485, 0x3b4cc9b3c45ff686 +486, 0x36efe94862f105a1 +487, 0x8b425f27f3996c8c +488, 0x396750b5141990c0 +489, 0x95e8016fd8be3b03 +490, 0x76fc07ca93fa58d9 +491, 0x846bb14c645b0c75 +492, 0xa605cfb398297aac +493, 0x19e42af61faaefcd +494, 0x8fbc9c5be2370b9 +495, 0xfabb6a708b774c92 +496, 0x24e23045a7ccb7e6 +497, 0x84caca37453c53a7 +498, 0x9fbe0deda0ab217a +499, 0xf41cce8970ac144b +500, 0x8e8a33acaab17e59 +501, 0x846608d05c9b73fe +502, 0xb32c80a1c82fcc1b +503, 0x89c4d0ea85766f75 +504, 0x99405647ddcb348c +505, 0x1e831b51204b7a63 +506, 0xfd8bf1b743791185 +507, 0xde489c75cda83196 +508, 0xd579f8a2c70628f1 +509, 0x60e4bb07af5ace5d +510, 0x262843c44883481d +511, 0x992a22735ab308c9 +512, 0x74de79ece0a914b0 +513, 0xd4a3ff83127baf97 +514, 0x23dc69bcc5fe770d +515, 0x58f3497d5a9ad653 +516, 0x58ed53ecb7a64cb0 +517, 0x6ee92d9763d37f9e +518, 0x7f6f9fbf877b0164 +519, 0x7139eeb4b3c482bd +520, 0x197316b659bf8834 +521, 0xc28a627d979022f6 +522, 0x85ae4049d8ad47fb +523, 0x11c9516d4ae13e22 +524, 0xaccdffbd16f33d28 +525, 0x68882afaea90ca13 +526, 0x7e6c6fe98874f58 +527, 0xa2aac5489c8ab7cc +528, 0x3978eabb2543d737 +529, 0xa17c62e45a3fe296 +530, 0x6eb109d81c9224d8 +531, 0x49e550d7a5f68291 +532, 0x550c48610a266785 +533, 0x717df8f6f8c4c714 +534, 0x6c9171ae4c97ebc5 +535, 0x9248555f2e938277 +536, 0xeee197be9a685e21 +537, 0x23b10d152729c79e +538, 0xd99a0e35e22c02c5 +539, 0xb2a229086a71360a +540, 0xb53ad493eca7e4d8 +541, 0xdce4c80cc7b59a25 +542, 0x1d0f7a0a78f628bd +543, 0xebf4133a6b4da324 +544, 0x1c6a43aaa8a28e82 +545, 0x417512b9c8c332fe +546, 0xb82c515788d7474e +547, 0x58d8b6d62366b9a9 +548, 0x417383f667b82e5d +549, 0x5065df19d5156876 +550, 0x45f7a177dce0ae19 +551, 0x51bb2b6e4b99b7d0 +552, 0x607a99fb8d715e92 +553, 0x5f8ae53d33601b03 +554, 0x555a8aa2cf4dbe8c +555, 0x5fe3af983f2dd205 +556, 0x340b495f8d7f771d +557, 0x5b1efc807762ee26 +558, 0xbe0f72f3f2b2529c +559, 0xec1b0691d58149a7 +560, 0x97e7874c9af94cf1 +561, 0x7da8f0dca84401eb +562, 0xc4c0f0da6a25bdfa +563, 0x1d1b16f1a51b9535 +564, 0x805482e682b26d71 +565, 0x2b6f9a35fee36ca1 +566, 0x57ef4cb20da96729 +567, 0x261932d0691874e6 +568, 0x314883c0836ac0e3 +569, 0x1f831417a3c49289 +570, 0xaded4280fb377fa3 +571, 0x43bc2d0eb4fe43c7 +572, 0xc1d71eefdfe9cea4 +573, 0xa876eba383515868 +574, 0x994d9fcf3142f08 +575, 0x8f10d482bda9d35c +576, 0xd4a386334c346cc3 +577, 0x410ea73faef00896 +578, 0x2b19d1288b764b7c +579, 0x73d80efec82579b6 +580, 0x79fe50849dd6db16 +581, 0x99d073390884e5b5 +582, 0xb656c4f5b7d8c251 +583, 0x265f1a55f456463 +584, 0x3ca410702fe4f733 +585, 0x838c4431205583ff +586, 0x1223f9eca84c7513 +587, 0x68ab8b0bde2f7e5c +588, 0x6ea394530b224537 +589, 0x9ef5afd2667e6cf0 +590, 0x3f6ea8a19a50ba0c +591, 0x5f279dd237a1e3a9 +592, 0x7c4cee031b6361c6 +593, 0x9646a6547ac7b2b9 +594, 0x3ff18f84973f81aa +595, 0x9ddf4b58616f4374 +596, 0xd484e12a4d9c6c08 +597, 0xf6df9d6cbbfacdfb +598, 0xa55f08713250cbbe +599, 0xdcbc45f59afd73e3 +600, 0xa6c1b651ac0b5b8 +601, 0xdb57ae1da9226710 +602, 0x2a825af2f9016875 +603, 0x5634e077906a70f5 +604, 0xcfe76fb8a918b9af +605, 0x96a65ede52b0f259 +606, 0x3b1ea564eaf66326 +607, 0x42ecb562ebd36e80 +608, 0xeefe615d1df23980 +609, 0xd6c79be5c011e807 +610, 0x22e39b0698f93131 +611, 0xa5d5cafff6e1dc41 +612, 0x8f2b02fe6f4a3c06 +613, 0x207edba6a1336b20 +614, 0x363262b62a0d36c7 +615, 0x295ec0d93e112449 +616, 0x83c1f7c6b1b985e5 +617, 0xc02a5c40cdb4d615 +618, 0x23a73f3c52eb8f32 +619, 0x62cc20f4d6e11dd8 +620, 0x766166e1da546d7c +621, 0x9d16d9030c9cfb84 +622, 0xaefc85375fa75d91 +623, 0xba77a56d0ea4ba13 +624, 0x39a31a730e0687d7 +625, 0xe3a57f64109f562d +626, 0x1d74491bd9d29388 +627, 0xa6c5f561a185dfb +628, 0x633992b1c0d3fe44 +629, 0xee814a1280651a2c +630, 0xe2f2b54ae6a45ded +631, 0xf391217301365d25 +632, 0xbb76dda0270a6006 +633, 0x3b48ecebee5b9bce +634, 0x6d06438edf209241 +635, 0x357ba920e8b1997d +636, 0x6041cf82c985d9e1 +637, 0x26e199481a8f8370 +638, 0x402bef99c898c7ad +639, 0xaf537688258ece78 +640, 0x8bd65a5e42349fc1 +641, 0x966d6db227125e56 +642, 0x1c2bf537dbdf6a18 +643, 0xf882d51b88effda7 +644, 0x7934750e1ff84314 +645, 0x5d3a2ef7b201a299 +646, 0x43a1c0074fc7f3b2 +647, 0xe4ac4fa8e80ea889 +648, 0x7edcb91435ab94e4 +649, 0xbfc1dd08ddf7a0f +650, 0x14952561bbe706d6 +651, 0x76ff2246de9054bb +652, 0x164e716d44262e2 +653, 0xa2f0f0863f249aaa +654, 0x306df43087c5eab3 +655, 0x9e082542ffd2eac6 +656, 0x15371e1c1c88ef39 +657, 0x88380af1bbcb80bb +658, 0x6970f2d4e27e8997 +659, 0x7852aa8ba9e1d9bd +660, 0x353e12a671e73337 +661, 0xad43311c6ad719de +662, 0xb650a6d41913f4b0 +663, 0x1970174855d8058d +664, 0x8bb04033e9ae7065 +665, 0xac845cd23eeaf4ae +666, 0x75a264443291a7d4 +667, 0xab2b59c9ff6a40ca +668, 0x55733ca31b6413f6 +669, 0x6646ece8a89f9a74 +670, 0x318b0f83763269b1 +671, 0x285718955e9e5eda +672, 0xbe635b7f41321ba5 +673, 0x5208b1776231474b +674, 0x77f3df408394f208 +675, 0xd65a9dd028a3be77 +676, 0xb870f9a5a396b5de +677, 0x171038f25bc6ac14 +678, 0x99080d183e6246a5 +679, 0xe6260240b3509008 +680, 0xa0d3d2b8e1e5c4ff +681, 0x361a2692ef38fc0d +682, 0x907f5f272f8cc40a +683, 0x69fe3e0760201193 +684, 0x376118679943bc68 +685, 0xb137d0ab55d55d9d +686, 0x93f13b625502297 +687, 0xa49ed908d712453f +688, 0xbc215abe4adbf771 +689, 0x6a8e285265915d23 +690, 0xb838f15249c88f2d +691, 0xfd0fe93ee175e160 +692, 0xa86c8a70a0f1efb +693, 0xe2385851319e2d35 +694, 0xa0109f10353a584d +695, 0x63d54fde29ca316f +696, 0x6101dbcb043a06f9 +697, 0xceaa0b0a69440ce5 +698, 0x33e883a6b04e5103 +699, 0xee1b5ff43e231092 +700, 0xb427baf113599501 +701, 0x12b2317e71c6f9e8 +702, 0x1e3b122a92d24b36 +703, 0xc48ac99bd429a525 +704, 0xb07d638ce8aa1535 +705, 0x84c65dcac2b974ca +706, 0xdb4c47b0ec83241c +707, 0xed92b08dcb8c8bdb +708, 0xc9ea8ecb281d5a28 +709, 0xfa0b3e63ea37fd67 +710, 0x228ff7b873098379 +711, 0x77d6f7cf9c6e7bda +712, 0x8fe3f2b9ace02ffd +713, 0x2384ac4a406dcbe2 +714, 0x1fdce3138708f093 +715, 0xd34e85210c534b21 +716, 0xf8916e32dbfabbda +717, 0xb86418c0e2a753f2 +718, 0x98aaf36286e26ede +719, 0x66167e59c5d5a36b +720, 0x4c4d4c520ab6ae3a +721, 0xe83dcbe740d700cf +722, 0xafdbf579b9bfd667 +723, 0x2ae659b5e10ed7c4 +724, 0x7aa4d22f99423301 +725, 0x62c315f474195042 +726, 0x7c9212e3389c5959 +727, 0xa1f58e637d2c5a05 +728, 0xa0bb57dfd563a2ea +729, 0xb1ba41472dc9907a +730, 0x4355e0abae1b4e2b +731, 0x7831551c86ba472c +732, 0x6377246eb9c563c1 +733, 0xc33cca358031cd73 +734, 0x1a3df433adc587b9 +735, 0x959e58590ac04430 +736, 0x551713647091eb40 +737, 0xf15b81000b87a230 +738, 0x3c73394683730b04 +739, 0xc5ecf4d9c0d365a6 +740, 0x3cf3bb6f48141888 +741, 0xebd1e9e53e18117a +742, 0xa61d9146dcf3de9 +743, 0x9f64cf0611d26ff5 +744, 0xbea8440eee55a206 +745, 0x77426a4854f7dc77 +746, 0x415be11a6b4b34f8 +747, 0xbea05b3645aaf507 +748, 0x57d73bee3328d944 +749, 0x96c76260dae635b7 +750, 0xbbac81463c836e7a +751, 0x687822e5d4be6aed +752, 0xe3a0256c9e82d869 +753, 0x87efe94616042e3b +754, 0x127ecd55502079e0 +755, 0xdeed29e6ad9d3e5e +756, 0xd0f2b4d2fff9819f +757, 0x2c8ae834d48257d0 +758, 0x1f3aa79b5cd2cf52 +759, 0x693344b041cd0a74 +760, 0xe274c86488294f4 +761, 0x6a72fe61886a1d90 +762, 0xf7ec995387d51db +763, 0xc8f89ee89a223b6f +764, 0xc18a8258219c435b +765, 0xd2b83efbe2cb4fb3 +766, 0xf641b18d7ac141bc +767, 0x749d69c6371218c3 +768, 0x9435604b36073ca2 +769, 0x108bef88ea3a207 +770, 0x755776561f260626 +771, 0x4427e10b7c01c9da +772, 0xe503a94f8c3736bb +773, 0x4af8b8388166989e +774, 0xded90567abb2ee96 +775, 0x2337907e762a4f7 +776, 0x281fbe8330c24237 +777, 0x9d05969f770ba3b6 +778, 0x5b14db87a3978c1f +779, 0x1aca424488742d16 +780, 0xea3d971ce98124af +781, 0x5a45029209753fc5 +782, 0x551db2424e7892d +783, 0x55c5e85b29fa995b +784, 0x6f9b5885dae0bb3b +785, 0x40c269f378668751 +786, 0x31db833ffc89d7b4 +787, 0x54360752ef548928 +788, 0xde47ece2daf0f4c4 +789, 0x705c2f3be27845a9 +790, 0xdddd3a82ef299df0 +791, 0x24f914ca137e58c1 +792, 0xf737cd929f8a0b74 +793, 0x61642bf1f0f67553 +794, 0xf8876f5d9aaef9e2 +795, 0x766d2cb707ad74f2 +796, 0xf44c1e3d1083a1 +797, 0x996635c0d00e9fe0 +798, 0xefebf35270fa64c5 +799, 0x7db96619def7e9c0 +800, 0xf331b2e18b743845 +801, 0x62a2f25ec518575e +802, 0x31c3681a727de50f +803, 0xf98c015a5a1c54fb +804, 0x743bd3b5fbec0062 +805, 0xf3dc863a7f8b7ab6 +806, 0x839b8142fa0abd9f +807, 0xa641d1b43d37b18a +808, 0xb71faae321765fd +809, 0x2ec5a90aa7b571f0 +810, 0x89764721520044c0 +811, 0xf231a2e03edf49ba +812, 0xa1579465ebb9cdd +813, 0xfcb73c83c8438163 +814, 0x1aecf871e3e78339 +815, 0xe4466ba1de623b9a +816, 0xfab6458b9a8b7425 +817, 0xd08a56b73b9c289e +818, 0x821d2fcc13b84a8f +819, 0xbfb8842df2e876f1 +820, 0x94682890433e1e78 +821, 0x6a06072528ac8590 +822, 0xc408544d50b3b450 +823, 0x808753793fb29a6e +824, 0xabf989d4fa6b4087 +825, 0x796eacee17b0dc9b +826, 0xf6a77ae26e88dbac +827, 0x2fa97a02950c054f +828, 0xc711f4f82d4a6bb5 +829, 0x9caf50bbb28c3998 +830, 0x3bb92e640c99b657 +831, 0xbd888a8215f757f7 +832, 0xb75989e611a773b2 +833, 0x566399962d08ee5 +834, 0xf71d630e51443477 +835, 0xa0e3179e50dca26a +836, 0xebaf61a44eacc2c +837, 0xd5a358ff51aba185 +838, 0x3ea9c5e748d7ef7d +839, 0x897d6f8d03cd8cfe +840, 0xbedff90968cc3d94 +841, 0x87c5d60ba0e32b94 +842, 0x77898f21c70aa1a5 +843, 0xf02536e75c4381a4 +844, 0x4846df09787df4b0 +845, 0x4228b5bbc1e7137b +846, 0x87591acaee0d2b2a +847, 0x1094db803d6a2294 +848, 0x351bd6517744343d +849, 0xc6b66f7b4ab87e27 +850, 0xa138357faf31fffa +851, 0x3412ebb334d67bf9 +852, 0x831e1dbb632ff45d +853, 0xb008f6fa331ac5c4 +854, 0x9e22b7aef7223f2c +855, 0xc460a6aa5002f154 +856, 0xf353a66ff09b0a26 +857, 0xd5254e93c6a14abe +858, 0x4f72ff6246201214 +859, 0x10c1343f8a78f3e9 +860, 0x33b25deced647ff3 +861, 0x1a1f8abfd8907972 +862, 0x5a6278a9f7ed8433 +863, 0x7a40269035528530 +864, 0x7ef16d32772d58ce +865, 0x8252729ff8c33aed +866, 0x436c4d77c6bf0e2e +867, 0x5fd97535df293b19 +868, 0x8fde6dc6be9469b2 +869, 0xfaba1ba4fdb254d2 +870, 0x1d517806e45f2257 +871, 0xa040c894d9b0d308 +872, 0x48f32da1e1f879fb +873, 0xba444bb3081a8225 +874, 0x51e174f14631ce31 +875, 0x4b0eade95134975c +876, 0x5189f935656f29ab +877, 0x30c58e655faafb4f +878, 0x371996d1e3ac1806 +879, 0x953ae118b4e7385a +880, 0x7169becb6a7701a7 +881, 0x65c138388881dd6a +882, 0x9facc10f2cde5ac8 +883, 0xd80e3d6e2a953134 +884, 0xd410f904163c2a4a +885, 0x73a836e050f95de8 +886, 0x1a03a8183edcd8cd +887, 0x46ae001eec388186 +888, 0xeea3aa51afca2103 +889, 0x7af3b7ac380c934e +890, 0x7ca100978bbea8a8 +891, 0x8231c46ea318f711 +892, 0xe848e769f59373d4 +893, 0xae4823022d3452a7 +894, 0xc8bd326d8092a1a6 +895, 0x9e0ae695cae65d4b +896, 0x95e760a060655036 +897, 0x6fb7c9035c3ad544 +898, 0xcade3a08dea3432f +899, 0xad47f39e3fdb2ece +900, 0x41cdb1fb154826f6 +901, 0xb55de258f6727990 +902, 0x1c547ad05236f8da +903, 0xb6d373042359f1d +904, 0xdb9aad9d0f6549e2 +905, 0x6f09843e435c9d18 +906, 0x4b15fdd5f152bbc0 +907, 0xe9423d09f9d91535 +908, 0x8eb6dd3e2e87aebc +909, 0x7a8583a8124b1741 +910, 0xe6d5ce1819791a58 +911, 0x5d362b7f66fccbec +912, 0xc737676690fa26ea +913, 0x832aa877e040d398 +914, 0xe1aab8a68d879f2b +915, 0x8939c5616a219730 +916, 0x7e2ebccbd4019680 +917, 0xd86f3e4cb2a2f76 +918, 0xd82d4bb2eb375edc +919, 0x737d7bdf10e00e90 +920, 0x3764d163ed0a417f +921, 0xe06f90beaefb963a +922, 0xa74d750318857241 +923, 0xf804ecbcb5c25c8 +924, 0xbf9b027357f99374 +925, 0x2e5b2d58d1144a08 +926, 0xfa7ce04633c5cac2 +927, 0x4eb7775c4e9ee4e5 +928, 0x65457f52533039f0 +929, 0x5182d68bf085853c +930, 0xdcf362534f2b4616 +931, 0xee7ccedf18c95a68 +932, 0x691f8ff9750b925 +933, 0x3d82b8e8d8fc31fb +934, 0x85c0bb0f4b4a112f +935, 0xe95df77752e5e173 +936, 0x3605e7d61fb76af5 +937, 0x60335d8c6cbf6988 +938, 0x2b5a314000327ed5 +939, 0xca0cffe76d1778e6 +940, 0xd6033f0b2e789355 +941, 0x8f90a41a4fdfcc53 +942, 0xcb2b7cfc32976d3f +943, 0xce14afa2b8fb65b2 +944, 0x94a561aba9fe7cf +945, 0xf1c0bc3b71900acf +946, 0x47d384605f859409 +947, 0xb2becb4cb5ebb62f +948, 0x6080faf5ce884092 +949, 0x870ba05eb5ae8340 +950, 0x32116515ddc7e7cd +951, 0xc40857c60e3dba4a +952, 0x4e1e70e385c9c86e +953, 0xa8a36df8f9ec77b8 +954, 0x7ae475e0af4c4883 +955, 0xf60a62a9b8e92e66 +956, 0x9b4fb6700726b37f +957, 0xf30871c82b621163 +958, 0x87fa839419a1b038 +959, 0x7c70f09e12e5c9c6 +960, 0x2a55a6b0700f191e +961, 0xc5319239b1cb6247 +962, 0x5b3d7daa4da4d79d +963, 0xc845b957a849bf3e +964, 0x8ab82092c3b8ea4e +965, 0xe4d3330f64e85823 +966, 0x8b4359b012bf4ec7 +967, 0x94f2ae8fc8a645c2 +968, 0xe1c16a64d7ccb7d5 +969, 0xf7ab947c49dd9053 +970, 0x3ffe0e57136f4933 +971, 0x8378e36e4fdda387 +972, 0xbb3e9622b0527aa2 +973, 0x754dfcf2de3400df +974, 0x73b47f3626ed9d1b +975, 0xe056dc83a126f693 +976, 0xf9c646b99afe77f +977, 0x20d89f4d3b7ea72a +978, 0x82d8b24230c46c2a +979, 0x9ba818f53341aad3 +980, 0x4a0e781a1646ea64 +981, 0xc7d87a350ff43d7a +982, 0xc396afe3eab47776 +983, 0x6a61f73b628e8892 +984, 0x60e383f172e15eeb +985, 0x9722fdbd2a03b13e +986, 0xfd634049374a2628 +987, 0xf9863806fbc39457 +988, 0xc83f2fc42eca9f +989, 0x16d1bfdf49fc98f0 +990, 0xa28f80d5c410cd30 +991, 0xe94f58e03cbdf4ee +992, 0xe5ad5ccde4a99bb3 +993, 0x482c3dfa3bc71d3b +994, 0x75fee65a654d5c0a +995, 0x6aa16a97c454a20d +996, 0xfbe5549c65d74c76 +997, 0xa2292c465994cb9b +998, 0x5d1d10d51694d4d1 +999, 0x40e57b3aa1059716 diff --git a/_randomgen/core_prng/tests/test_against_numpy.py b/_randomgen/core_prng/tests/test_against_numpy.py new file mode 100644 index 000000000000..abe7cdb75c34 --- /dev/null +++ b/_randomgen/core_prng/tests/test_against_numpy.py @@ -0,0 +1,533 @@ +import numpy as np +import numpy.random +import pytest +from numpy.testing import assert_allclose, assert_array_equal, assert_equal + +from core_prng import RandomGenerator, MT19937 + + +def compare_0_input(f1, f2): + inputs = [(tuple([]), {}), (tuple([]), {'size': 10}), + (tuple([]), {'size': (20, 31)}), + (tuple([]), {'size': (20, 31, 5)})] + + +def compare_1_input(f1, f2, is_small=False, core_prng_kwargs=None): + if core_prng_kwargs is None: + core_prng_kwargs = {} + a = 0.3 if is_small else 10 + inputs = [((a,), {}), + ((a,), {'size': 10}), + ((np.array([a] * 10),), {}), + ((np.array([a] * 10),), {'size': 10}), + ((np.array([a] * 10),), {'size': (100, 10)})] + for i in inputs: + v1 = f1(*i[0], **i[1]) + v2 = f2(*i[0], **i[1], **core_prng_kwargs) + assert_allclose(v1, v2) + + +def compare_2_input(f1, f2, is_np=False, is_scalar=False, core_prng_kwargs=None): + if core_prng_kwargs is None: + core_prng_kwargs = {} + if is_np: + a, b = 10, 0.3 + dtype = np.int + else: + a, b = 2, 3 + dtype = np.double + inputs = [((a, b), {}), + ((a, b), {'size': 10}), + ((a, b), {'size': (23, 7)}), + ((np.array([a] * 10), b), {}), + ((a, np.array([b] * 10)), {}), + ((a, np.array([b] * 10)), {'size': 10}), + ((np.reshape(np.array([[a] * 100]), (100, 1)), np.array([b] * 10)), {'size': (100, 10)}), + ((np.ones((7, 31), dtype=dtype) * a, np.array([b] * 31)), {'size': (7, 31)}), + ((np.ones((7, 31), dtype=dtype) * a, np.array([b] * 31)), {'size': (10, 7, 31)})] + + if is_scalar: + inputs = inputs[:3] + + for i in inputs: + v1 = f1(*i[0], **i[1]) + v2 = f2(*i[0], **i[1], **core_prng_kwargs) + assert_allclose(v1, v2) + + +def compare_3_input(f1, f2, is_np=False): + a, b, c = 10, 20, 25 + inputs = [((a, b, c), {}), + ((a, b, c), {'size': 10}), + ((a, b, c), {'size': (23, 7)}), + ((np.array([a] * 10), b, c), {}), + ((a, np.array([b] * 10), c), {}), + ((a, b, np.array([c] * 10)), {}), + ((a, np.array([b] * 10), np.array([c] * 10)), {}), + ((a, np.array([b] * 10), c), {'size': 10}), + ((np.ones((1, 37), dtype=np.int) * a, + np.ones((23, 1), dtype=np.int) * [b], + c * np.ones((7, 1, 1), dtype=np.int)), + {}), + ((np.ones((1, 37), dtype=np.int) * a, + np.ones((23, 1), dtype=np.int) * [b], + c * np.ones((7, 1, 1), dtype=np.int)), + {'size': (7, 23, 37)}) + ] + + for i in inputs: + v1 = f1(*i[0], **i[1]) + v2 = f2(*i[0], **i[1]) + assert_allclose(v1, v2) + + +class TestAgainstNumPy(object): + @classmethod + def setup_class(cls): + cls.np = numpy.random + cls.prng = MT19937 + cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] + cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.nprs = cls.np.RandomState(*cls.seed) + cls.initial_state = cls.rg.state + cls._set_common_state() + + @classmethod + def _set_common_state(cls): + state = cls.rg.state + st = [[]] * 5 + st[0] = 'MT19937' + st[1] = state['state']['key'] + st[2] = state['state']['pos'] + st[3] = state['has_gauss'] + st[4] = state['gauss'] + cls.nprs.set_state(st) + + def _is_state_common(self): + state = self.nprs.get_state() + state2 = self.rg.state + assert (state[1] == state2['state']['key']).all() + assert (state[2] == state2['state']['pos']) + assert (state[3] == state2['has_gauss']) + assert_allclose(state[4], state2['gauss']) + + def test_common_seed(self): + self.rg.seed(1234) + self.nprs.seed(1234) + self._is_state_common() + self.rg.seed(23456) + self.nprs.seed(23456) + self._is_state_common() + + def test_numpy_state(self): + nprs = np.random.RandomState() + nprs.standard_normal(99) + state = nprs.get_state() + self.rg.state = state + state2 = self.rg.state + assert (state[1] == state2['state']['key']).all() + assert (state[2] == state2['state']['pos']) + assert (state[3] == state2['has_gauss']) + assert (state[4] == state2['gauss']) + + def test_random_sample(self): + self._set_common_state() + self._is_state_common() + v1 = self.nprs.random_sample(10) + v2 = self.rg.random_sample(10) + + assert_array_equal(v1, v2) + + def test_standard_normal(self): + self._set_common_state() + self._is_state_common() + compare_0_input(self.nprs.standard_normal, + self.rg.standard_normal) + self._is_state_common() + + def test_standard_cauchy(self): + self._set_common_state() + self._is_state_common() + compare_0_input(self.nprs.standard_cauchy, + self.rg.standard_cauchy) + self._is_state_common() + + def test_standard_exponential(self): + self._set_common_state() + self._is_state_common() + compare_0_input(self.nprs.standard_exponential, + self.rg.standard_exponential) + self._is_state_common() + + def test_tomaxint(self): + self._set_common_state() + self._is_state_common() + compare_0_input(self.nprs.tomaxint, + self.rg.tomaxint) + self._is_state_common() + + def test_chisquare(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.chisquare, + self.rg.chisquare) + self._is_state_common() + + def test_standard_gamma(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.standard_gamma, + self.rg.standard_gamma, + core_prng_kwargs={'method':'inv'}) + self._is_state_common() + + def test_standard_t(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.standard_t, + self.rg.standard_t) + self._is_state_common() + + def test_pareto(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.pareto, + self.rg.pareto) + self._is_state_common() + + def test_poisson(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.poisson, + self.rg.poisson) + self._is_state_common() + + def test_power(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.power, + self.rg.power) + self._is_state_common() + + def test_rayleigh(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.rayleigh, + self.rg.rayleigh) + self._is_state_common() + + def test_weibull(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.weibull, + self.rg.weibull) + self._is_state_common() + + def test_zipf(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.zipf, + self.rg.zipf) + self._is_state_common() + + def test_logseries(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.logseries, + self.rg.logseries, + is_small=True) + self._is_state_common() + + def test_zipf(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.geometric, + self.rg.geometric, + is_small=True) + self._is_state_common() + + def test_beta(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.beta, + self.rg.beta) + self._is_state_common() + + def test_exponential(self): + self._set_common_state() + self._is_state_common() + compare_1_input(self.nprs.exponential, + self.rg.exponential) + self._is_state_common() + + def test_f(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.f, + self.rg.f) + self._is_state_common() + + def test_gamma(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.gamma, + self.rg.gamma) + self._is_state_common() + + def test_logistic(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.logistic, + self.rg.logistic) + self._is_state_common() + + def test_gumbel(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.gumbel, + self.rg.gumbel) + self._is_state_common() + + def test_laplace(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.laplace, + self.rg.laplace) + self._is_state_common() + + def test_lognormal(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.lognormal, + self.rg.lognormal) + self._is_state_common() + + def test_noncentral_chisquare(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.noncentral_chisquare, + self.rg.noncentral_chisquare) + self._is_state_common() + + def test_normal(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.normal, + self.rg.normal, + core_prng_kwargs={'method':'bm'}) + self._is_state_common() + + def test_uniform(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.uniform, + self.rg.uniform) + self._is_state_common() + + def test_vonmises(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.vonmises, + self.rg.vonmises) + self._is_state_common() + + def test_wald(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.wald, + self.rg.wald) + self._is_state_common() + + def test_random_integers(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.random_integers, + self.rg.random_integers, + is_scalar=True) + self._is_state_common() + + def test_binomial(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.binomial, + self.rg.binomial, + is_np=True) + self._is_state_common() + + def test_negative_binomial(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.nprs.negative_binomial, + self.rg.negative_binomial, + is_np=True) + self._is_state_common() + + def test_randn(self): + f = self.rg.randn + g = self.nprs.randn + assert_allclose(f(10, method='bm'), g(10)) + assert_allclose(f(3, 4, 5, method='bm'), g(3, 4, 5)) + + def test_rand(self): + f = self.rg.rand + g = self.nprs.rand + assert_allclose(f(10), g(10)) + assert_allclose(f(3, 4, 5), g(3, 4, 5)) + + @pytest.mark.xfail + def test_poisson_lam_max(self): + assert_allclose(self.rg.poisson_lam_max, self.nprs.poisson_lam_max) + + def test_dirichlet(self): + f = self.rg.dirichlet + g = self.nprs.dirichlet + a = [3, 4, 5, 6, 7, 10] + assert_allclose(f(a), g(a)) + assert_allclose(f(np.array(a), 10), g(np.array(a), 10)) + assert_allclose(f(np.array(a), (3, 37)), g(np.array(a), (3, 37))) + + def test_noncentral_f(self): + self._set_common_state() + self._is_state_common() + compare_3_input(self.nprs.noncentral_f, + self.rg.noncentral_f) + self._is_state_common() + + def test_triangular(self): + self._set_common_state() + self._is_state_common() + compare_3_input(self.nprs.triangular, + self.rg.triangular) + self._is_state_common() + + def test_hypergeometric(self): + self._set_common_state() + self._is_state_common() + compare_3_input(self.nprs.hypergeometric, + self.rg.hypergeometric) + self._is_state_common() + + def test_bytes(self): + self._set_common_state() + self._is_state_common() + assert_equal(self.rg.bytes(8), self.nprs.bytes(8)) + self._is_state_common() + assert_equal(self.rg.bytes(103), self.nprs.bytes(103)) + self._is_state_common() + assert_equal(self.rg.bytes(8), self.nprs.bytes(8)) + self._is_state_common() + + def test_multinomial(self): + self._set_common_state() + self._is_state_common() + f = self.rg.multinomial + g = self.nprs.multinomial + p = [.1, .3, .4, .2] + assert_equal(f(100, p), g(100, p)) + assert_equal(f(100, np.array(p)), g(100, np.array(p))) + assert_equal(f(100, np.array(p), size=(7, 23)), g(100, np.array(p), size=(7, 23))) + self._is_state_common() + + def test_choice(self): + self._set_common_state() + self._is_state_common() + f = self.rg.choice + g = self.nprs.choice + a = np.arange(100) + size = 25 + for replace in (True, False): + assert_equal(f(a, size, replace), g(a, size, replace)) + assert_equal(f(100, size, replace), g(100, size, replace)) + self._is_state_common() + + def test_permutation(self): + self._set_common_state() + self._is_state_common() + f = self.rg.permutation + g = self.nprs.permutation + a = np.arange(100) + assert_equal(f(a), g(a)) + assert_equal(f(23), g(23)) + self._is_state_common() + + def test_shuffle(self): + self._set_common_state() + self._is_state_common() + f = self.rg.shuffle + g = self.nprs.shuffle + a = np.arange(100) + fa = a.copy() + ga = a.copy() + g(ga) + f(fa) + assert_equal(fa, ga) + self._is_state_common() + + def test_multivariate_normal(self): + self._set_common_state() + self._is_state_common() + mu = [1, 2, 3] + cov = [[1, .2, .3], [.2, 4, 1], [.3, 1, 10]] + f = self.rg.multivariate_normal + g = self.nprs.multivariate_normal + assert_allclose(f(mu, cov, method='bm'), g(mu, cov)) + assert_allclose(f(np.array(mu), cov, method='bm'), g(np.array(mu), cov)) + assert_allclose(f(np.array(mu), np.array(cov), method='bm'), + g(np.array(mu), np.array(cov))) + assert_allclose(f(np.array(mu), np.array(cov), size=(7, 31), method='bm'), + g(np.array(mu), np.array(cov), size=(7, 31))) + self._is_state_common() + + def test_randint(self): + self._set_common_state() + self._is_state_common() + compare_2_input(self.rg.randint, + self.nprs.randint, + is_scalar=True) + self._is_state_common() + + def test_scalar(self): + s = RandomGenerator(MT19937(0)) + assert_equal(s.randint(1000), 684) + s1 = np.random.RandomState(0) + assert_equal(s1.randint(1000), 684) + assert_equal(s1.randint(1000), s.randint(1000)) + + s = RandomGenerator(MT19937(4294967295)) + assert_equal(s.randint(1000), 419) + s1 = np.random.RandomState(4294967295) + assert_equal(s1.randint(1000), 419) + assert_equal(s1.randint(1000), s.randint(1000)) + + self.rg.seed(4294967295) + self.nprs.seed(4294967295) + self._is_state_common() + + def test_array(self): + s = RandomGenerator(MT19937(range(10))) + assert_equal(s.randint(1000), 468) + s = np.random.RandomState(range(10)) + assert_equal(s.randint(1000), 468) + + s = RandomGenerator(MT19937(np.arange(10))) + assert_equal(s.randint(1000), 468) + s = RandomGenerator(MT19937([0])) + assert_equal(s.randint(1000), 973) + s = RandomGenerator(MT19937([4294967295])) + assert_equal(s.randint(1000), 265) + + def test_dir(self): + nprs_d = set(dir(self.nprs)) + rs_d = dir(self.rg) + excluded = {'get_state', 'poisson_lam_max','set_state'} + nprs_d.difference_update(excluded) + assert (len(nprs_d.difference(rs_d)) == 0) + + # npmod = dir(numpy.random) + # mod = dir(randomstate) + # known_exlcuded = ['__all__', 'Tester', 'info', 'bench', + # '__RandomState_ctor', 'mtrand', 'test', + # '__warningregistry__', '_numpy_tester'] + # mod += known_exlcuded + # diff = set(npmod).difference(mod) + # assert_equal(len(diff), 0) diff --git a/_randomgen/core_prng/tests/test_direct.py b/_randomgen/core_prng/tests/test_direct.py new file mode 100644 index 000000000000..54ce706a2e19 --- /dev/null +++ b/_randomgen/core_prng/tests/test_direct.py @@ -0,0 +1,337 @@ +import os +import sys +from os.path import join + +import numpy as np +from numpy.testing import assert_equal, assert_allclose, assert_array_equal, \ + assert_raises + +from core_prng import * + +if (sys.version_info > (3, 0)): + long = int + +pwd = os.path.dirname(os.path.abspath(__file__)) + + +def uniform32_from_uint64(x): + x = np.uint64(x) + upper = np.array(x >> np.uint64(32), dtype=np.uint32) + lower = np.uint64(0xffffffff) + lower = np.array(x & lower, dtype=np.uint32) + joined = np.column_stack([lower, upper]).ravel() + out = (joined >> np.uint32(9)) * (1.0 / 2 ** 23) + return out.astype(np.float32) + + +def uniform32_from_uint63(x): + x = np.uint64(x) + x = np.uint32(x >> np.uint64(32)) + out = (x >> np.uint32(9)) * (1.0 / 2 ** 23) + return out.astype(np.float32) + + +def uniform32_from_uint53(x): + x = np.uint64(x) + x = np.uint32(x & np.uint64(0xffffffff)) + out = (x >> np.uint32(9)) * (1.0 / 2 ** 23) + return out.astype(np.float32) + + +def uniform32_from_uint32(x): + return (x >> np.uint32(9)) * (1.0 / 2 ** 23) + + +def uniform32_from_uint(x, bits): + if bits == 64: + return uniform32_from_uint64(x) + elif bits == 63: + return uniform32_from_uint63(x) + elif bits == 53: + return uniform32_from_uint53(x) + elif bits == 32: + return uniform32_from_uint32(x) + else: + raise NotImplementedError + + +def uniform_from_uint(x, bits): + if bits in (64, 63, 53): + return uniform_from_uint64(x) + elif bits == 32: + return uniform_from_uint32(x) + + +def uniform_from_uint64(x): + return (x >> np.uint64(11)) * (1.0 / 9007199254740992.0) + + +def uniform_from_uint32(x): + out = np.empty(len(x) // 2) + for i in range(0, len(x), 2): + a = x[i] >> 5 + b = x[i + 1] >> 6 + out[i // 2] = (a * 67108864.0 + b) / 9007199254740992.0 + return out + + +def uint64_from_uint63(x): + out = np.empty(len(x) // 2, dtype=np.uint64) + for i in range(0, len(x), 2): + a = x[i] & np.uint64(0xffffffff00000000) + b = x[i + 1] >> np.uint64(32) + out[i // 2] = a | b + return out + + +def uniform_from_dsfmt(x): + return x.view(np.double) - 1.0 + + +def gauss_from_uint(x, n, bits): + if bits in (64, 63): + doubles = uniform_from_uint64(x) + elif bits == 32: + doubles = uniform_from_uint32(x) + elif bits == 'dsfmt': + doubles = uniform_from_dsfmt(x) + gauss = [] + loc = 0 + x1 = x2 = 0.0 + while len(gauss) < n: + r2 = 2 + while r2 >= 1.0 or r2 == 0.0: + x1 = 2.0 * doubles[loc] - 1.0 + x2 = 2.0 * doubles[loc + 1] - 1.0 + r2 = x1 * x1 + x2 * x2 + loc += 2 + + f = np.sqrt(-2.0 * np.log(r2) / r2) + gauss.append(f * x2) + gauss.append(f * x1) + + return gauss[:n] + + +class Base(object): + dtype = np.uint64 + data2 = data1 = {} + + @classmethod + def setup_class(cls): + cls.prng = Xoroshiro128 + cls.bits = 64 + cls.dtype = np.uint64 + cls.seed_error_type = TypeError + + @classmethod + def _read_csv(cls, filename): + with open(filename) as csv: + seed = csv.readline() + seed = seed.split(',') + seed = [long(s.strip(), 0) for s in seed[1:]] + data = [] + for line in csv: + data.append(long(line.split(',')[-1].strip(), 0)) + return {'seed': seed, 'data': np.array(data, dtype=cls.dtype)} + + def test_raw(self): + rs = RandomGenerator(self.prng(*self.data1['seed'])) + uints = rs.random_raw(1000) + assert_equal(uints, self.data1['data']) + + rs = RandomGenerator(self.prng(*self.data2['seed'])) + uints = rs.random_raw(1000) + assert_equal(uints, self.data2['data']) + + def test_gauss_inv(self): + n = 25 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + gauss = rs.standard_normal(n, method='bm') + assert_allclose(gauss, + gauss_from_uint(self.data1['data'], n, self.bits)) + + rs = RandomGenerator(self.prng(*self.data2['seed'])) + gauss = rs.standard_normal(25, method='bm') + assert_allclose(gauss, + gauss_from_uint(self.data2['data'], n, self.bits)) + + def test_uniform_double(self): + rs = RandomGenerator(self.prng(*self.data1['seed'])) + vals = uniform_from_uint(self.data1['data'], self.bits) + uniforms = rs.random_sample(len(vals)) + assert_allclose(uniforms, vals) + assert_equal(uniforms.dtype, np.float64) + + rs = RandomGenerator(self.prng(*self.data2['seed'])) + vals = uniform_from_uint(self.data2['data'], self.bits) + uniforms = rs.random_sample(len(vals)) + assert_allclose(uniforms, vals) + assert_equal(uniforms.dtype, np.float64) + + def test_uniform_float(self): + rs = RandomGenerator(self.prng(*self.data1['seed'])) + vals = uniform32_from_uint(self.data1['data'], self.bits) + uniforms = rs.random_sample(len(vals), dtype=np.float32) + assert_allclose(uniforms, vals) + assert_equal(uniforms.dtype, np.float32) + + rs = RandomGenerator(self.prng(*self.data2['seed'])) + vals = uniform32_from_uint(self.data2['data'], self.bits) + uniforms = rs.random_sample(len(vals), dtype=np.float32) + assert_allclose(uniforms, vals) + assert_equal(uniforms.dtype, np.float32) + + def test_seed_float(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(self.seed_error_type, rs.seed, np.pi) + assert_raises(self.seed_error_type, rs.seed, -np.pi) + + def test_seed_float_array(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(self.seed_error_type, rs.seed, np.array([np.pi])) + assert_raises(self.seed_error_type, rs.seed, np.array([-np.pi])) + assert_raises(self.seed_error_type, rs.seed, np.array([np.pi, -np.pi])) + assert_raises(self.seed_error_type, rs.seed, np.array([0, np.pi])) + assert_raises(self.seed_error_type, rs.seed, [np.pi]) + assert_raises(self.seed_error_type, rs.seed, [0, np.pi]) + + def test_seed_out_of_range(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(ValueError, rs.seed, 2 ** (2 * self.bits + 1)) + assert_raises(ValueError, rs.seed, -1) + + def test_seed_out_of_range_array(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(ValueError, rs.seed, [2 ** (2 * self.bits + 1)]) + assert_raises(ValueError, rs.seed, [-1]) + + +class TestXoroshiro128(Base): + @classmethod + def setup_class(cls): + cls.prng = Xoroshiro128 + cls.bits = 64 + cls.dtype = np.uint64 + cls.data1 = cls._read_csv( + join(pwd, './data/xoroshiro128-testset-1.csv')) + cls.data2 = cls._read_csv( + join(pwd, './data/xoroshiro128-testset-2.csv')) + cls.seed_error_type = TypeError + + +class TestXorshift1024(Base): + @classmethod + def setup_class(cls): + cls.prng = Xorshift1024 + cls.bits = 64 + cls.dtype = np.uint64 + cls.data1 = cls._read_csv( + join(pwd, './data/xorshift1024-testset-1.csv')) + cls.data2 = cls._read_csv( + join(pwd, './data/xorshift1024-testset-2.csv')) + cls.seed_error_type = TypeError + + +class TestThreeFry(Base): + @classmethod + def setup_class(cls): + cls.prng = ThreeFry + cls.bits = 64 + cls.dtype = np.uint64 + cls.data1 = cls._read_csv( + join(pwd, './data/threefry-testset-1.csv')) + cls.data2 = cls._read_csv( + join(pwd, './data/threefry-testset-2.csv')) + cls.seed_error_type = TypeError + + +class TestPhilox(Base): + @classmethod + def setup_class(cls): + cls.prng = Philox + cls.bits = 64 + cls.dtype = np.uint64 + cls.data1 = cls._read_csv( + join(pwd, './data/philox-testset-1.csv')) + cls.data2 = cls._read_csv( + join(pwd, './data/philox-testset-2.csv')) + cls.seed_error_type = TypeError + + +class TestMT19937(Base): + @classmethod + def setup_class(cls): + cls.prng = MT19937 + cls.bits = 32 + cls.dtype = np.uint32 + cls.data1 = cls._read_csv(join(pwd, './data/mt19937-testset-1.csv')) + cls.data2 = cls._read_csv(join(pwd, './data/mt19937-testset-2.csv')) + cls.seed_error_type = ValueError + + def test_seed_out_of_range(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(ValueError, rs.seed, 2 ** (self.bits + 1)) + assert_raises(ValueError, rs.seed, -1) + assert_raises(ValueError, rs.seed, 2 ** (2 * self.bits + 1)) + + def test_seed_out_of_range_array(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(ValueError, rs.seed, [2 ** (self.bits + 1)]) + assert_raises(ValueError, rs.seed, [-1]) + assert_raises(TypeError, rs.seed, [2 ** (2 * self.bits + 1)]) + + def test_seed_float(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(TypeError, rs.seed, np.pi) + assert_raises(TypeError, rs.seed, -np.pi) + + def test_seed_float_array(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(TypeError, rs.seed, np.array([np.pi])) + assert_raises(TypeError, rs.seed, np.array([-np.pi])) + assert_raises(TypeError, rs.seed, np.array([np.pi, -np.pi])) + assert_raises(TypeError, rs.seed, np.array([0, np.pi])) + assert_raises(TypeError, rs.seed, [np.pi]) + assert_raises(TypeError, rs.seed, [0, np.pi]) + + +class TestDSFMT(Base): + @classmethod + def setup_class(cls): + cls.prng = DSFMT + cls.bits = 53 + cls.dtype = np.uint64 + cls.data1 = cls._read_csv(join(pwd, './data/dSFMT-testset-1.csv')) + cls.data2 = cls._read_csv(join(pwd, './data/dSFMT-testset-2.csv')) + cls.seed_error_type = TypeError + + def test_uniform_double(self): + rs = RandomGenerator(self.prng(*self.data1['seed'])) + aa = uniform_from_dsfmt(self.data1['data']) + assert_array_equal(uniform_from_dsfmt(self.data1['data']), + rs.random_sample(1000)) + + rs = RandomGenerator(self.prng(*self.data2['seed'])) + assert_equal(uniform_from_dsfmt(self.data2['data']), + rs.random_sample(1000)) + + def test_gauss_inv(self): + n = 25 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + gauss = rs.standard_normal(n, method='bm') + assert_allclose(gauss, + gauss_from_uint(self.data1['data'], n, 'dsfmt')) + + rs = RandomGenerator(self.prng(*self.data2['seed'])) + gauss = rs.standard_normal(25, method='bm') + assert_allclose(gauss, + gauss_from_uint(self.data2['data'], n, 'dsfmt')) diff --git a/_randomgen/core_prng/tests/test_numpy_mt19937.py b/_randomgen/core_prng/tests/test_numpy_mt19937.py new file mode 100644 index 000000000000..7893c0da40b2 --- /dev/null +++ b/_randomgen/core_prng/tests/test_numpy_mt19937.py @@ -0,0 +1,1754 @@ +from __future__ import division, absolute_import, print_function + +import sys +import warnings + +import numpy as np +import randomstate as random +from numpy.testing import ( + run_module_suite, assert_, assert_raises, assert_equal, + assert_warns, assert_no_warnings, assert_array_equal, + assert_array_almost_equal) +from numpy.testing import suppress_warnings + +import pytest +from core_prng import RandomGenerator, MT19937 + +mt19937 = RandomGenerator(MT19937()) + + +class TestSeed(object): + def test_scalar(self): + s = RandomGenerator(MT19937(0)) + assert_equal(s.randint(1000), 684) + s = RandomGenerator(MT19937(4294967295)) + assert_equal(s.randint(1000), 419) + + def test_array(self): + s = RandomGenerator(MT19937(range(10))) + assert_equal(s.randint(1000), 468) + s = RandomGenerator(MT19937(np.arange(10))) + assert_equal(s.randint(1000), 468) + s = RandomGenerator(MT19937([0])) + assert_equal(s.randint(1000), 973) + s = RandomGenerator(MT19937([4294967295])) + assert_equal(s.randint(1000), 265) + + def test_invalid_scalar(self): + # seed must be an unsigned 32 bit integer + assert_raises(TypeError, MT19937, -0.5) + assert_raises(ValueError, MT19937, -1) + + def test_invalid_array(self): + # seed must be an unsigned 32 bit integer + assert_raises(TypeError, MT19937, [-0.5]) + assert_raises(ValueError, MT19937, [-1]) + assert_raises(ValueError, MT19937, [4294967296]) + assert_raises(ValueError, MT19937, [1, 2, 4294967296]) + assert_raises(ValueError, MT19937, [1, -2, 4294967296]) + + +class TestBinomial(object): + def test_n_zero(self): + # Tests the corner case of n == 0 for the binomial distribution. + # binomial(0, p) should be zero for any p in [0, 1]. + # This test addresses issue #3480. + zeros = np.zeros(2, dtype='int') + for p in [0, .5, 1]: + assert_(random.binomial(0, p) == 0) + assert_array_equal(random.binomial(zeros, p), zeros) + + def test_p_is_nan(self): + # Issue #4571. + assert_raises(ValueError, random.binomial, 1, np.nan) + + +class TestMultinomial(object): + def test_basic(self): + random.multinomial(100, [0.2, 0.8]) + + def test_zero_probability(self): + random.multinomial(100, [0.2, 0.8, 0.0, 0.0, 0.0]) + + def test_int_negative_interval(self): + assert_(-5 <= random.randint(-5, -1) < -1) + x = random.randint(-5, -1, 5) + assert_(np.all(-5 <= x)) + assert_(np.all(x < -1)) + + def test_size(self): + # gh-3173 + p = [0.5, 0.5] + assert_equal(mt19937.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(mt19937.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(mt19937.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(mt19937.multinomial(1, p, [2, 2]).shape, (2, 2, 2)) + assert_equal(mt19937.multinomial(1, p, (2, 2)).shape, (2, 2, 2)) + assert_equal(mt19937.multinomial(1, p, np.array((2, 2))).shape, + (2, 2, 2)) + + assert_raises(TypeError, mt19937.multinomial, 1, p, + float(1)) + + +class TestSetState(object): + def setup(self): + self.seed = 1234567890 + self.prng = RandomGenerator(MT19937(self.seed)) + self.state = self.prng.state + self.legacy_state = (self.state['prng'], + self.state['state']['key'], + self.state['state']['pos'], + self.state['has_gauss'], + self.state['gauss']) + + def test_basic(self): + old = self.prng.tomaxint(16) + self.prng.state = self.state + new = self.prng.tomaxint(16) + assert_(np.all(old == new)) + + def test_gaussian_reset(self): + # Make sure the cached every-other-Gaussian is reset. + old = self.prng.standard_normal(size=3) + self.prng.state = self.state + new = self.prng.standard_normal(size=3) + assert_(np.all(old == new)) + + def test_gaussian_reset_in_media_res(self): + # When the state is saved with a cached Gaussian, make sure the + # cached Gaussian is restored. + + self.prng.standard_normal() + state = self.prng.state + old = self.prng.standard_normal(size=3) + self.prng.state = state + new = self.prng.standard_normal(size=3) + assert_(np.all(old == new)) + + def test_backwards_compatibility(self): + # Make sure we can accept old state tuples that do not have the + # cached Gaussian value. + old_state = self.legacy_state[:-2] + x1 = self.prng.standard_normal(size=16) + self.prng.state = old_state + x2 = self.prng.standard_normal(size=16) + self.prng.state = self.state + x3 = self.prng.standard_normal(size=16) + assert_(np.all(x1 == x2)) + assert_(np.all(x1 == x3)) + + def test_negative_binomial(self): + # Ensure that the negative binomial results take floating point + # arguments without truncation. + self.prng.negative_binomial(0.5, 0.5) + + +class TestRandint(object): + rfunc = mt19937.randint + + # valid integer/boolean types + itype = [bool, np.int8, np.uint8, np.int16, np.uint16, + np.int32, np.uint32, np.int64, np.uint64] + + def test_unsupported_type(self): + assert_raises(TypeError, self.rfunc, 1, dtype=float) + + def test_bounds_checking(self): + for dt in self.itype: + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + assert_raises(ValueError, self.rfunc, lbnd - 1, ubnd, dtype=dt) + assert_raises(ValueError, self.rfunc, lbnd, ubnd + 1, dtype=dt) + assert_raises(ValueError, self.rfunc, ubnd, lbnd, dtype=dt) + assert_raises(ValueError, self.rfunc, 1, 0, dtype=dt) + + assert_raises(ValueError, self.rfunc, [lbnd - 1], ubnd, dtype=dt) + assert_raises(ValueError, self.rfunc, [lbnd], [ubnd + 1], dtype=dt) + assert_raises(ValueError, self.rfunc, [ubnd], [lbnd], dtype=dt) + assert_raises(ValueError, self.rfunc, 1, [0], dtype=dt) + + def test_bounds_checking_array(self): + for dt in self.itype: + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + assert_raises(ValueError, self.rfunc, [lbnd - 1] * 2, [ubnd] * 2, dtype=dt) + assert_raises(ValueError, self.rfunc, [lbnd] * 2, [ubnd + 1] * 2, dtype=dt) + assert_raises(ValueError, self.rfunc, ubnd, [lbnd] * 2, dtype=dt) + assert_raises(ValueError, self.rfunc, [1] * 2, 0, dtype=dt) + + def test_rng_zero_and_extremes(self): + for dt in self.itype: + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + + tgt = ubnd - 1 + assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt) + assert_equal(self.rfunc([tgt], tgt + 1, size=1000, dtype=dt), tgt) + + tgt = lbnd + assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt) + assert_equal(self.rfunc(tgt, [tgt + 1], size=1000, dtype=dt), tgt) + + tgt = (lbnd + ubnd) // 2 + assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt) + assert_equal(self.rfunc([tgt], [tgt + 1], size=1000, dtype=dt), tgt) + + def test_rng_zero_and_extremes_array(self): + size = 1000 + for dt in self.itype: + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + + tgt = ubnd - 1 + assert_equal(self.rfunc([tgt], [tgt + 1], size=size, dtype=dt), tgt) + assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, dtype=dt), tgt) + assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, size=size, dtype=dt), tgt) + + tgt = lbnd + assert_equal(self.rfunc([tgt], [tgt + 1], size=size, dtype=dt), tgt) + assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, dtype=dt), tgt) + assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, size=size, dtype=dt), tgt) + + tgt = (lbnd + ubnd) // 2 + assert_equal(self.rfunc([tgt], [tgt + 1], size=size, dtype=dt), tgt) + assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, dtype=dt), tgt) + assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, size=size, dtype=dt), tgt) + + def test_full_range(self): + # Test for ticket #1690 + + for dt in self.itype: + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + + try: + self.rfunc(lbnd, ubnd, dtype=dt) + except Exception as e: + raise AssertionError("No error should have been raised, " + "but one was with the following " + "message:\n\n%s" % str(e)) + + def test_full_range_array(self): + # Test for ticket #1690 + + for dt in self.itype: + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + + try: + self.rfunc([lbnd] * 2, [ubnd], dtype=dt) + except Exception as e: + raise AssertionError("No error should have been raised, " + "but one was with the following " + "message:\n\n%s" % str(e)) + + def test_in_bounds_fuzz(self): + # Don't use fixed seed + mt19937.seed() + + for dt in self.itype[1:]: + for ubnd in [4, 8, 16]: + vals = self.rfunc(2, ubnd, size=2 ** 16, dtype=dt) + assert_(vals.max() < ubnd) + assert_(vals.min() >= 2) + + vals = self.rfunc(0, 2, size=2 ** 16, dtype=bool) + + assert_(vals.max() < 2) + assert_(vals.min() >= 0) + + def test_scalar_array_equiv(self): + for dt in self.itype: + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + + size = 1000 + mt19937.seed(1234) + scalar = self.rfunc(lbnd, ubnd, size=size, dtype=dt) + + mt19937.seed(1234) + scalar_array = self.rfunc([lbnd], [ubnd], size=size, dtype=dt) + + mt19937.seed(1234) + array = self.rfunc([lbnd] * size, [ubnd] * size, size=size, dtype=dt) + assert_array_equal(scalar, scalar_array) + assert_array_equal(scalar, array) + + def test_repeatability(self): + import hashlib + # We use a md5 hash of generated sequences of 1000 samples + # in the range [0, 6) for all but bool, where the range + # is [0, 2). Hashes are for little endian numbers. + tgt = {'bool': '7dd3170d7aa461d201a65f8bcf3944b0', + 'int16': '1b7741b80964bb190c50d541dca1cac1', + 'int32': '4dc9fcc2b395577ebb51793e58ed1a05', + 'int64': '17db902806f448331b5a758d7d2ee672', + 'int8': '27dd30c4e08a797063dffac2490b0be6', + 'uint16': '1b7741b80964bb190c50d541dca1cac1', + 'uint32': '4dc9fcc2b395577ebb51793e58ed1a05', + 'uint64': '17db902806f448331b5a758d7d2ee672', + 'uint8': '27dd30c4e08a797063dffac2490b0be6'} + + for dt in self.itype[1:]: + mt19937.seed(1234) + + # view as little endian for hash + if sys.byteorder == 'little': + val = self.rfunc(0, 6, size=1000, dtype=dt) + else: + val = self.rfunc(0, 6, size=1000, dtype=dt).byteswap() + + res = hashlib.md5(val.view(np.int8)).hexdigest() + print(tgt[np.dtype(dt).name] == res) + # TODO + # assert_(tgt[np.dtype(dt).name] == res) + + # bools do not depend on endianess + mt19937.seed(1234) + val = self.rfunc(0, 2, size=1000, dtype=bool).view(np.int8) + res = hashlib.md5(val).hexdigest() + print(tgt[np.dtype(bool).name] == res) + # TODO + # assert_(tgt[np.dtype(bool).name] == res) + + def test_repeatability_broadcasting(self): + + for dt in self.itype: + lbnd = 0 if dt in (np.bool, bool, np.bool_) else np.iinfo(dt).min + ubnd = 2 if dt in (np.bool, bool, np.bool_) else np.iinfo(dt).max + 1 + + # view as little endian for hash + mt19937.seed(1234) + val = self.rfunc(lbnd, ubnd, size=1000, dtype=dt) + + mt19937.seed(1234) + val_bc = self.rfunc([lbnd] * 1000, ubnd, dtype=dt) + + assert_array_equal(val, val_bc) + + mt19937.seed(1234) + val_bc = self.rfunc([lbnd] * 1000, [ubnd] * 1000, dtype=dt) + + assert_array_equal(val, val_bc) + + def test_int64_uint64_corner_case(self): + # When stored in Numpy arrays, `lbnd` is casted + # as np.int64, and `ubnd` is casted as np.uint64. + # Checking whether `lbnd` >= `ubnd` used to be + # done solely via direct comparison, which is incorrect + # because when Numpy tries to compare both numbers, + # it casts both to np.float64 because there is + # no integer superset of np.int64 and np.uint64. However, + # `ubnd` is too large to be represented in np.float64, + # causing it be round down to np.iinfo(np.int64).max, + # leading to a ValueError because `lbnd` now equals + # the new `ubnd`. + + dt = np.int64 + tgt = np.iinfo(np.int64).max + lbnd = np.int64(np.iinfo(np.int64).max) + ubnd = np.uint64(np.iinfo(np.int64).max + 1) + + # None of these function calls should + # generate a ValueError now. + actual = mt19937.randint(lbnd, ubnd, dtype=dt) + assert_equal(actual, tgt) + + def test_respect_dtype_singleton(self): + # See gh-7203 + for dt in self.itype: + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + dt = np.bool_ if dt is bool else dt + + sample = self.rfunc(lbnd, ubnd, dtype=dt) + assert_equal(sample.dtype, dt) + + for dt in (bool, int, np.long): + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + + # gh-7284: Ensure that we get Python data types + sample = self.rfunc(lbnd, ubnd, dtype=dt) + assert not hasattr(sample, 'dtype') + assert_equal(type(sample), dt) + + def test_respect_dtype_array(self): + # See gh-7203 + for dt in self.itype: + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + dt = np.bool_ if dt is bool else dt + + sample = self.rfunc([lbnd], [ubnd], dtype=dt) + assert_equal(sample.dtype, dt) + sample = self.rfunc([lbnd] * 2, [ubnd] * 2, dtype=dt) + assert_equal(sample.dtype, dt) + + def test_zero_size(self): + # See gh-7203 + for dt in self.itype: + sample = self.rfunc(0, 0, (3, 0, 4), dtype=dt) + assert sample.shape == (3, 0, 4) + assert sample.dtype == dt + assert self.rfunc(0, -10, 0, dtype=dt).shape == (0,) + + +class TestRandomDist(object): + # Make sure the random distribution returns the correct value for a + # given seed + + def setup(self): + self.seed = 1234567890 + + def test_rand(self): + mt19937.seed(self.seed) + actual = mt19937.rand(3, 2) + desired = np.array([[0.61879477158567997, 0.59162362775974664], + [0.88868358904449662, 0.89165480011560816], + [0.4575674820298663, 0.7781880808593471]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_randn(self): + mt19937.seed(self.seed) + actual = mt19937.randn(3, 2, method='bm') + desired = np.array([[1.34016345771863121, 1.73759122771936081], + [1.498988344300628, -0.2286433324536169], + [2.031033998682787, 2.17032494605655257]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_randint(self): + mt19937.seed(self.seed) + actual = mt19937.randint(-99, 99, size=(3, 2)) + desired = np.array([[31, 3], + [-52, 41], + [-48, -66]]) + assert_array_equal(actual, desired) + + def test_random_integers(self): + mt19937.seed(self.seed) + with suppress_warnings() as sup: + w = sup.record(DeprecationWarning) + actual = mt19937.random_integers(-99, 99, size=(3, 2)) + assert_(len(w) == 1) + desired = np.array([[31, 3], + [-52, 41], + [-48, -66]]) + assert_array_equal(actual, desired) + + def test_random_integers_max_int(self): + # Tests whether random_integers can generate the + # maximum allowed Python int that can be converted + # into a C long. Previous implementations of this + # method have thrown an OverflowError when attempting + # to generate this integer. + with suppress_warnings() as sup: + w = sup.record(DeprecationWarning) + actual = mt19937.random_integers(np.iinfo('l').max, + np.iinfo('l').max) + assert_(len(w) == 1) + + desired = np.iinfo('l').max + assert_equal(actual, desired) + + def test_random_integers_deprecated(self): + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + + # DeprecationWarning raised with high == None + assert_raises(DeprecationWarning, + mt19937.random_integers, + np.iinfo('l').max) + + # DeprecationWarning raised with high != None + assert_raises(DeprecationWarning, + mt19937.random_integers, + np.iinfo('l').max, np.iinfo('l').max) + + def test_random_sample(self): + mt19937.seed(self.seed) + actual = mt19937.random_sample((3, 2)) + desired = np.array([[0.61879477158567997, 0.59162362775974664], + [0.88868358904449662, 0.89165480011560816], + [0.4575674820298663, 0.7781880808593471]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_choice_uniform_replace(self): + mt19937.seed(self.seed) + actual = mt19937.choice(4, 4) + desired = np.array([2, 3, 2, 3]) + assert_array_equal(actual, desired) + + def test_choice_nonuniform_replace(self): + mt19937.seed(self.seed) + actual = mt19937.choice(4, 4, p=[0.4, 0.4, 0.1, 0.1]) + desired = np.array([1, 1, 2, 2]) + assert_array_equal(actual, desired) + + def test_choice_uniform_noreplace(self): + mt19937.seed(self.seed) + actual = mt19937.choice(4, 3, replace=False) + desired = np.array([0, 1, 3]) + assert_array_equal(actual, desired) + + def test_choice_nonuniform_noreplace(self): + mt19937.seed(self.seed) + actual = mt19937.choice(4, 3, replace=False, + p=[0.1, 0.3, 0.5, 0.1]) + desired = np.array([2, 3, 1]) + assert_array_equal(actual, desired) + + def test_choice_noninteger(self): + mt19937.seed(self.seed) + actual = mt19937.choice(['a', 'b', 'c', 'd'], 4) + desired = np.array(['c', 'd', 'c', 'd']) + assert_array_equal(actual, desired) + + def test_choice_exceptions(self): + sample = mt19937.choice + assert_raises(ValueError, sample, -1, 3) + assert_raises(ValueError, sample, 3., 3) + assert_raises(ValueError, sample, [[1, 2], [3, 4]], 3) + assert_raises(ValueError, sample, [], 3) + assert_raises(ValueError, sample, [1, 2, 3, 4], 3, + p=[[0.25, 0.25], [0.25, 0.25]]) + assert_raises(ValueError, sample, [1, 2], 3, p=[0.4, 0.4, 0.2]) + assert_raises(ValueError, sample, [1, 2], 3, p=[1.1, -0.1]) + assert_raises(ValueError, sample, [1, 2], 3, p=[0.4, 0.4]) + assert_raises(ValueError, sample, [1, 2, 3], 4, replace=False) + assert_raises(ValueError, sample, [1, 2, 3], 2, + replace=False, p=[1, 0, 0]) + + def test_choice_return_shape(self): + p = [0.1, 0.9] + # Check scalar + assert_(np.isscalar(mt19937.choice(2, replace=True))) + assert_(np.isscalar(mt19937.choice(2, replace=False))) + assert_(np.isscalar(mt19937.choice(2, replace=True, p=p))) + assert_(np.isscalar(mt19937.choice(2, replace=False, p=p))) + assert_(np.isscalar(mt19937.choice([1, 2], replace=True))) + assert_(mt19937.choice([None], replace=True) is None) + a = np.array([1, 2]) + arr = np.empty(1, dtype=object) + arr[0] = a + assert_(mt19937.choice(arr, replace=True) is a) + + # Check 0-d array + s = tuple() + assert_(not np.isscalar(mt19937.choice(2, s, replace=True))) + assert_(not np.isscalar(mt19937.choice(2, s, replace=False))) + assert_(not np.isscalar(mt19937.choice(2, s, replace=True, p=p))) + assert_(not np.isscalar(mt19937.choice(2, s, replace=False, p=p))) + assert_(not np.isscalar(mt19937.choice([1, 2], s, replace=True))) + assert_(mt19937.choice([None], s, replace=True).ndim == 0) + a = np.array([1, 2]) + arr = np.empty(1, dtype=object) + arr[0] = a + assert_(mt19937.choice(arr, s, replace=True).item() is a) + + # Check multi dimensional array + s = (2, 3) + p = [0.1, 0.1, 0.1, 0.1, 0.4, 0.2] + assert_(mt19937.choice(6, s, replace=True).shape, s) + assert_(mt19937.choice(6, s, replace=False).shape, s) + assert_(mt19937.choice(6, s, replace=True, p=p).shape, s) + assert_(mt19937.choice(6, s, replace=False, p=p).shape, s) + assert_(mt19937.choice(np.arange(6), s, replace=True).shape, s) + + def test_bytes(self): + mt19937.seed(self.seed) + actual = mt19937.bytes(10) + desired = b'\x82Ui\x9e\xff\x97+Wf\xa5' + assert_equal(actual, desired) + + def test_shuffle(self): + # Test lists, arrays (of various dtypes), and multidimensional versions + # of both, c-contiguous or not: + for conv in [lambda x: np.array([]), + lambda x: x, + lambda x: np.asarray(x).astype(np.int8), + lambda x: np.asarray(x).astype(np.float32), + lambda x: np.asarray(x).astype(np.complex64), + lambda x: np.asarray(x).astype(object), + lambda x: [(i, i) for i in x], + lambda x: np.asarray([[i, i] for i in x]), + lambda x: np.vstack([x, x]).T, + # gh-4270 + lambda x: np.asarray([(i, i) for i in x], + [("a", object, 1), + ("b", np.int32, 1)])]: + mt19937.seed(self.seed) + alist = conv([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) + mt19937.shuffle(alist) + actual = alist + desired = conv([0, 1, 9, 6, 2, 4, 5, 8, 7, 3]) + assert_array_equal(actual, desired) + + def test_shuffle_masked(self): + # gh-3263 + a = np.ma.masked_values(np.reshape(range(20), (5, 4)) % 3 - 1, -1) + b = np.ma.masked_values(np.arange(20) % 3 - 1, -1) + a_orig = a.copy() + b_orig = b.copy() + for i in range(50): + mt19937.shuffle(a) + assert_equal( + sorted(a.data[~a.mask]), sorted(a_orig.data[~a_orig.mask])) + mt19937.shuffle(b) + assert_equal( + sorted(b.data[~b.mask]), sorted(b_orig.data[~b_orig.mask])) + + def test_beta(self): + mt19937.seed(self.seed) + actual = mt19937.beta(.1, .9, size=(3, 2)) + desired = np.array( + [[1.45341850513746058e-02, 5.31297615662868145e-04], + [1.85366619058432324e-06, 4.19214516800110563e-03], + [1.58405155108498093e-04, 1.26252891949397652e-04]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_binomial(self): + mt19937.seed(self.seed) + actual = mt19937.binomial(100.123, .456, size=(3, 2)) + desired = np.array([[37, 43], + [42, 48], + [46, 45]]) + assert_array_equal(actual, desired) + + def test_chisquare(self): + mt19937.seed(self.seed) + actual = mt19937.chisquare(50, size=(3, 2)) + desired = np.array([[63.87858175501090585, 68.68407748911370447], + [65.77116116901505904, 47.09686762438974483], + [72.3828403199695174, 74.18408615260374006]]) + assert_array_almost_equal(actual, desired, decimal=13) + + def test_dirichlet(self): + mt19937.seed(self.seed) + alpha = np.array([51.72840233779265162, 39.74494232180943953]) + actual = mt19937.dirichlet(alpha, size=(3, 2)) + desired = np.array([[[0.54539444573611562, 0.45460555426388438], + [0.62345816822039413, 0.37654183177960598]], + [[0.55206000085785778, 0.44793999914214233], + [0.58964023305154301, 0.41035976694845688]], + [[0.59266909280647828, 0.40733090719352177], + [0.56974431743975207, 0.43025568256024799]]]) + assert_array_almost_equal(actual, desired, decimal=15) + bad_alpha = np.array([5.4e-01, -1.0e-16]) + assert_raises(ValueError, mt19937.dirichlet, bad_alpha) + + def test_dirichlet_size(self): + # gh-3173 + p = np.array([51.72840233779265162, 39.74494232180943953]) + assert_equal(mt19937.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(mt19937.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(mt19937.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(mt19937.dirichlet(p, [2, 2]).shape, (2, 2, 2)) + assert_equal(mt19937.dirichlet(p, (2, 2)).shape, (2, 2, 2)) + assert_equal(mt19937.dirichlet(p, np.array((2, 2))).shape, (2, 2, 2)) + + assert_raises(TypeError, mt19937.dirichlet, p, float(1)) + + def test_dirichlet_bad_alpha(self): + # gh-2089 + alpha = np.array([5.4e-01, -1.0e-16]) + assert_raises(ValueError, mt19937.dirichlet, alpha) + + def test_exponential(self): + mt19937.seed(self.seed) + actual = mt19937.exponential(1.1234, size=(3, 2)) + desired = np.array([[1.08342649775011624, 1.00607889924557314], + [2.46628830085216721, 2.49668106809923884], + [0.68717433461363442, 1.69175666993575979]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_exponential_0(self): + assert_equal(mt19937.exponential(scale=0), 0) + assert_raises(ValueError, mt19937.exponential, scale=-0.) + + def test_f(self): + mt19937.seed(self.seed) + actual = mt19937.f(12, 77, size=(3, 2)) + desired = np.array([[1.21975394418575878, 1.75135759791559775], + [1.44803115017146489, 1.22108959480396262], + [1.02176975757740629, 1.34431827623300415]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_gamma(self): + mt19937.seed(self.seed) + actual = mt19937.gamma(5, 3, size=(3, 2)) + desired = np.array([[24.60509188649287182, 28.54993563207210627], + [26.13476110204064184, 12.56988482927716078], + [31.71863275789960568, 33.30143302795922011]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_gamma_0(self): + assert_equal(mt19937.gamma(shape=0, scale=0), 0) + assert_raises(ValueError, mt19937.gamma, shape=-0., scale=-0.) + + def test_geometric(self): + mt19937.seed(self.seed) + actual = mt19937.geometric(.123456789, size=(3, 2)) + desired = np.array([[8, 7], + [17, 17], + [5, 12]]) + assert_array_equal(actual, desired) + + def test_gumbel(self): + mt19937.seed(self.seed) + actual = mt19937.gumbel(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[0.19591898743416816, 0.34405539668096674], + [-1.4492522252274278, -1.47374816298446865], + [1.10651090478803416, -0.69535848626236174]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_gumbel_0(self): + assert_equal(mt19937.gumbel(scale=0), 0) + assert_raises(ValueError, mt19937.gumbel, scale=-0.) + + def test_hypergeometric(self): + mt19937.seed(self.seed) + actual = mt19937.hypergeometric(10.1, 5.5, 14, size=(3, 2)) + desired = np.array([[10, 10], + [10, 10], + [9, 9]]) + assert_array_equal(actual, desired) + + # Test nbad = 0 + actual = mt19937.hypergeometric(5, 0, 3, size=4) + desired = np.array([3, 3, 3, 3]) + assert_array_equal(actual, desired) + + actual = mt19937.hypergeometric(15, 0, 12, size=4) + desired = np.array([12, 12, 12, 12]) + assert_array_equal(actual, desired) + + # Test ngood = 0 + actual = mt19937.hypergeometric(0, 5, 3, size=4) + desired = np.array([0, 0, 0, 0]) + assert_array_equal(actual, desired) + + actual = mt19937.hypergeometric(0, 15, 12, size=4) + desired = np.array([0, 0, 0, 0]) + assert_array_equal(actual, desired) + + def test_laplace(self): + mt19937.seed(self.seed) + actual = mt19937.laplace(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[0.66599721112760157, 0.52829452552221945], + [3.12791959514407125, 3.18202813572992005], + [-0.05391065675859356, 1.74901336242837324]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_laplace_0(self): + assert_equal(mt19937.laplace(scale=0), 0) + assert_raises(ValueError, mt19937.laplace, scale=-0.) + + def test_logistic(self): + mt19937.seed(self.seed) + actual = mt19937.logistic(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[1.09232835305011444, 0.8648196662399954], + [4.27818590694950185, 4.33897006346929714], + [-0.21682183359214885, 2.63373365386060332]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_lognormal(self): + mt19937.seed(self.seed) + actual = mt19937.lognormal(mean=.123456789, sigma=2.0, size=(3, 2)) + desired = np.array([[16.50698631688883822, 36.54846706092654784], + [22.67886599981281748, 0.71617561058995771], + [65.72798501792723869, 86.84341601437161273]]) + assert_array_almost_equal(actual, desired, decimal=13) + + def test_lognormal_0(self): + assert_equal(mt19937.lognormal(sigma=0), 1) + assert_raises(ValueError, mt19937.lognormal, sigma=-0.) + + def test_logseries(self): + mt19937.seed(self.seed) + actual = mt19937.logseries(p=.923456789, size=(3, 2)) + desired = np.array([[2, 2], + [6, 17], + [3, 6]]) + assert_array_equal(actual, desired) + + def test_multinomial(self): + mt19937.seed(self.seed) + actual = mt19937.multinomial(20, [1 / 6.] * 6, size=(3, 2)) + desired = np.array([[[4, 3, 5, 4, 2, 2], + [5, 2, 8, 2, 2, 1]], + [[3, 4, 3, 6, 0, 4], + [2, 1, 4, 3, 6, 4]], + [[4, 4, 2, 5, 2, 3], + [4, 3, 4, 2, 3, 4]]]) + assert_array_equal(actual, desired) + + def test_multivariate_normal(self): + mt19937.seed(self.seed) + mean = (.123456789, 10) + cov = [[1, 0], [0, 1]] + size = (3, 2) + actual = mt19937.multivariate_normal(mean, cov, size, method='bm') + desired = np.array([[[1.463620246718631, 11.73759122771936], + [1.622445133300628, 9.771356667546383]], + [[2.154490787682787, 12.170324946056553], + [1.719909438201865, 9.230548443648306]], + [[0.689515026297799, 9.880729819607714], + [-0.023054015651998, 9.201096623542879]]]) + + assert_array_almost_equal(actual, desired, decimal=15) + + # Check for default size, was raising deprecation warning + actual = mt19937.multivariate_normal(mean, cov, method='bm') + desired = np.array([0.895289569463708, 9.17180864067987]) + assert_array_almost_equal(actual, desired, decimal=15) + + # Check that non positive-semidefinite covariance warns with + # RuntimeWarning + mean = [0, 0] + cov = [[1, 2], [2, 1]] + assert_warns(RuntimeWarning, mt19937.multivariate_normal, mean, cov, method='bm') + + # and that it doesn't warn with RuntimeWarning check_valid='ignore' + assert_no_warnings(mt19937.multivariate_normal, mean, cov, + check_valid='ignore', method='bm') + + # and that it raises with RuntimeWarning check_valid='raises' + assert_raises(ValueError, mt19937.multivariate_normal, mean, cov, + check_valid='raise', method='bm') + + def test_negative_binomial(self): + mt19937.seed(self.seed) + actual = mt19937.negative_binomial(n=100, p=.12345, size=(3, 2)) + desired = np.array([[848, 841], + [892, 611], + [779, 647]]) + assert_array_equal(actual, desired) + + def test_noncentral_chisquare(self): + mt19937.seed(self.seed) + actual = mt19937.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) + desired = np.array([[23.91905354498517511, 13.35324692733826346], + [31.22452661329736401, 16.60047399466177254], + [5.03461598262724586, 17.94973089023519464]]) + assert_array_almost_equal(actual, desired, decimal=14) + + actual = mt19937.noncentral_chisquare(df=.5, nonc=.2, size=(3, 2)) + desired = np.array([[1.47145377828516666, 0.15052899268012659], + [0.00943803056963588, 1.02647251615666169], + [0.332334982684171, 0.15451287602753125]]) + assert_array_almost_equal(actual, desired, decimal=14) + + mt19937.seed(self.seed) + actual = mt19937.noncentral_chisquare(df=5, nonc=0, size=(3, 2)) + desired = np.array([[9.597154162763948, 11.725484450296079], + [10.413711048138335, 3.694475922923986], + [13.484222138963087, 14.377255424602957]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_noncentral_f(self): + mt19937.seed(self.seed) + actual = mt19937.noncentral_f(dfnum=5, dfden=2, nonc=1, + size=(3, 2)) + desired = np.array([[1.40598099674926669, 0.34207973179285761], + [3.57715069265772545, 7.92632662577829805], + [0.43741599463544162, 1.1774208752428319]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_normal(self): + mt19937.seed(self.seed) + actual = mt19937.normal(loc=.123456789, scale=2.0, size=(3, 2), method='bm') + desired = np.array([[2.80378370443726244, 3.59863924443872163], + [3.121433477601256, -0.33382987590723379], + [4.18552478636557357, 4.46410668111310471]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_normal_0(self): + assert_equal(mt19937.normal(scale=0), 0) + assert_raises(ValueError, mt19937.normal, scale=-0.) + + def test_pareto(self): + mt19937.seed(self.seed) + actual = mt19937.pareto(a=.123456789, size=(3, 2)) + desired = np.array( + [[2.46852460439034849e+03, 1.41286880810518346e+03], + [5.28287797029485181e+07, 6.57720981047328785e+07], + [1.40840323350391515e+02, 1.98390255135251704e+05]]) + # For some reason on 32-bit x86 Ubuntu 12.10 the [1, 0] entry in this + # matrix differs by 24 nulps. Discussion: + # http://mail.scipy.org/pipermail/numpy-discussion/2012-September/063801.html + # Consensus is that this is probably some gcc quirk that affects + # rounding but not in any important way, so we just use a looser + # tolerance on this test: + np.testing.assert_array_almost_equal_nulp(actual, desired, nulp=30) + + def test_poisson(self): + mt19937.seed(self.seed) + actual = mt19937.poisson(lam=.123456789, size=(3, 2)) + desired = np.array([[0, 0], + [1, 0], + [0, 0]]) + assert_array_equal(actual, desired) + + def test_poisson_exceptions(self): + lambig = np.iinfo('l').max + lamneg = -1 + assert_raises(ValueError, mt19937.poisson, lamneg) + assert_raises(ValueError, mt19937.poisson, [lamneg] * 10) + assert_raises(ValueError, mt19937.poisson, lambig) + assert_raises(ValueError, mt19937.poisson, [lambig] * 10) + + def test_power(self): + mt19937.seed(self.seed) + actual = mt19937.power(a=.123456789, size=(3, 2)) + desired = np.array([[0.02048932883240791, 0.01424192241128213], + [0.38446073748535298, 0.39499689943484395], + [0.00177699707563439, 0.13115505880863756]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_rayleigh(self): + mt19937.seed(self.seed) + actual = mt19937.rayleigh(scale=10, size=(3, 2)) + desired = np.array([[13.8882496494248393, 13.383318339044731], + [20.95413364294492098, 21.08285015800712614], + [11.06066537006854311, 17.35468505778271009]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_rayleigh_0(self): + assert_equal(mt19937.rayleigh(scale=0), 0) + assert_raises(ValueError, mt19937.rayleigh, scale=-0.) + + def test_standard_cauchy(self): + mt19937.seed(self.seed) + actual = mt19937.standard_cauchy(size=(3, 2)) + desired = np.array([[0.77127660196445336, -6.55601161955910605], + [0.93582023391158309, -2.07479293013759447], + [-4.74601644297011926, 0.18338989290760804]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_standard_exponential(self): + mt19937.seed(self.seed) + actual = mt19937.standard_exponential(size=(3, 2), method='inv') + desired = np.array([[0.96441739162374596, 0.89556604882105506], + [2.1953785836319808, 2.22243285392490542], + [0.6116915921431676, 1.50592546727413201]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_standard_gamma(self): + mt19937.seed(self.seed) + actual = mt19937.standard_gamma(shape=3, size=(3, 2), method='inv') + desired = np.array([[5.50841531318455058, 6.62953470301903103], + [5.93988484943779227, 2.31044849402133989], + [7.54838614231317084, 8.012756093271868]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_standard_gamma_0(self): + assert_equal(mt19937.standard_gamma(shape=0), 0) + assert_raises(ValueError, mt19937.standard_gamma, shape=-0.) + + def test_standard_normal(self): + mt19937.seed(self.seed) + actual = mt19937.standard_normal(size=(3, 2), method='bm') + desired = np.array([[1.34016345771863121, 1.73759122771936081], + [1.498988344300628, -0.2286433324536169], + [2.031033998682787, 2.17032494605655257]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_standard_t(self): + mt19937.seed(self.seed) + actual = mt19937.standard_t(df=10, size=(3, 2)) + desired = np.array([[0.97140611862659965, -0.08830486548450577], + [1.36311143689505321, -0.55317463909867071], + [-0.18473749069684214, 0.61181537341755321]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_triangular(self): + mt19937.seed(self.seed) + actual = mt19937.triangular(left=5.12, mode=10.23, right=20.34, + size=(3, 2)) + desired = np.array([[12.68117178949215784, 12.4129206149193152], + [16.20131377335158263, 16.25692138747600524], + [11.20400690911820263, 14.4978144835829923]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_uniform(self): + mt19937.seed(self.seed) + actual = mt19937.uniform(low=1.23, high=10.54, size=(3, 2)) + desired = np.array([[6.99097932346268003, 6.73801597444323974], + [9.50364421400426274, 9.53130618907631089], + [5.48995325769805476, 8.47493103280052118]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_uniform_range_bounds(self): + fmin = np.finfo('float').min + fmax = np.finfo('float').max + + func = mt19937.uniform + assert_raises(OverflowError, func, -np.inf, 0) + assert_raises(OverflowError, func, 0, np.inf) + assert_raises(OverflowError, func, fmin, fmax) + assert_raises(OverflowError, func, [-np.inf], [0]) + assert_raises(OverflowError, func, [0], [np.inf]) + + # (fmax / 1e17) - fmin is within range, so this should not throw + # account for i386 extended precision DBL_MAX / 1e17 + DBL_MAX > + # DBL_MAX by increasing fmin a bit + mt19937.uniform(low=np.nextafter(fmin, 1), high=fmax / 1e17) + + def test_scalar_exception_propagation(self): + # Tests that exceptions are correctly propagated in distributions + # when called with objects that throw exceptions when converted to + # scalars. + # + # Regression test for gh: 8865 + + class ThrowingFloat(np.ndarray): + def __float__(self): + raise TypeError + + throwing_float = np.array(1.0).view(ThrowingFloat) + assert_raises(TypeError, mt19937.uniform, throwing_float, throwing_float) + + class ThrowingInteger(np.ndarray): + def __int__(self): + raise TypeError + + throwing_int = np.array(1).view(ThrowingInteger) + assert_raises(TypeError, mt19937.hypergeometric, throwing_int, 1, 1) + + def test_vonmises(self): + mt19937.seed(self.seed) + actual = mt19937.vonmises(mu=1.23, kappa=1.54, size=(3, 2)) + desired = np.array([[2.28567572673902042, 2.89163838442285037], + [0.38198375564286025, 2.57638023113890746], + [1.19153771588353052, 1.83509849681825354]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_vonmises_small(self): + # check infinite loop, gh-4720 + mt19937.seed(self.seed) + r = mt19937.vonmises(mu=0., kappa=1.1e-8, size=10 ** 6) + assert_(np.isfinite(r).all()) + + def test_wald(self): + mt19937.seed(self.seed) + actual = mt19937.wald(mean=1.23, scale=1.54, size=(3, 2)) + desired = np.array([[3.82935265715889983, 5.13125249184285526], + [0.35045403618358717, 1.50832396872003538], + [0.24124319895843183, 0.22031101461955038]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_weibull(self): + mt19937.seed(self.seed) + actual = mt19937.weibull(a=1.23, size=(3, 2)) + desired = np.array([[0.97097342648766727, 0.91422896443565516], + [1.89517770034962929, 1.91414357960479564], + [0.67057783752390987, 1.39494046635066793]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_weibull_0(self): + assert_equal(mt19937.weibull(a=0), 0) + assert_raises(ValueError, mt19937.weibull, a=-0.) + + def test_zipf(self): + mt19937.seed(self.seed) + actual = mt19937.zipf(a=1.23, size=(3, 2)) + desired = np.array([[66, 29], + [1, 1], + [3, 13]]) + assert_array_equal(actual, desired) + + +class TestBroadcast(object): + # tests that functions that broadcast behave + # correctly when presented with non-scalar arguments + def setup(self): + self.seed = 123456789 + + def set_seed(self): + random.seed(self.seed) + + # TODO: Include test for randint once it can broadcast + # Can steal the test written in PR #6938 + + def test_uniform(self): + low = [0] + high = [1] + uniform = random.uniform + desired = np.array([0.53283302478975902, + 0.53413660089041659, + 0.50955303552646702]) + + self.set_seed() + actual = uniform(low * 3, high) + assert_array_almost_equal(actual, desired, decimal=14) + + self.set_seed() + actual = uniform(low, high * 3) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_normal(self): + loc = [0] + scale = [1] + bad_scale = [-1] + normal = random.normal + desired = np.array([2.2129019979039612, + 2.1283977976520019, + 1.8417114045748335]) + + self.set_seed() + actual = normal(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, normal, loc * 3, bad_scale) + + self.set_seed() + actual = normal(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, normal, loc, bad_scale * 3) + + def test_beta(self): + a = [1] + b = [2] + bad_a = [-1] + bad_b = [-2] + beta = random.beta + desired = np.array([0.19843558305989056, + 0.075230336409423643, + 0.24976865978980844]) + + self.set_seed() + actual = beta(a * 3, b) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, beta, bad_a * 3, b) + assert_raises(ValueError, beta, a * 3, bad_b) + + self.set_seed() + actual = beta(a, b * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, beta, bad_a, b * 3) + assert_raises(ValueError, beta, a, bad_b * 3) + + def test_exponential(self): + scale = [1] + bad_scale = [-1] + exponential = random.exponential + desired = np.array([0.76106853658845242, + 0.76386282278691653, + 0.71243813125891797]) + + self.set_seed() + actual = exponential(scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, exponential, bad_scale * 3) + + def test_standard_gamma(self): + shape = [1] + bad_shape = [-1] + std_gamma = random.standard_gamma + desired = np.array([0.76106853658845242, + 0.76386282278691653, + 0.71243813125891797]) + + self.set_seed() + actual = std_gamma(shape * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, std_gamma, bad_shape * 3) + + def test_gamma(self): + shape = [1] + scale = [2] + bad_shape = [-1] + bad_scale = [-2] + gamma = random.gamma + desired = np.array([1.5221370731769048, + 1.5277256455738331, + 1.4248762625178359]) + + self.set_seed() + actual = gamma(shape * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gamma, bad_shape * 3, scale) + assert_raises(ValueError, gamma, shape * 3, bad_scale) + + self.set_seed() + actual = gamma(shape, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gamma, bad_shape, scale * 3) + assert_raises(ValueError, gamma, shape, bad_scale * 3) + + def test_f(self): + dfnum = [1] + dfden = [2] + bad_dfnum = [-1] + bad_dfden = [-2] + f = random.f + desired = np.array([0.80038951638264799, + 0.86768719635363512, + 2.7251095168386801]) + + self.set_seed() + actual = f(dfnum * 3, dfden) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, f, bad_dfnum * 3, dfden) + assert_raises(ValueError, f, dfnum * 3, bad_dfden) + + self.set_seed() + actual = f(dfnum, dfden * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, f, bad_dfnum, dfden * 3) + assert_raises(ValueError, f, dfnum, bad_dfden * 3) + + def test_noncentral_f(self): + dfnum = [2] + dfden = [3] + nonc = [4] + bad_dfnum = [0] + bad_dfden = [-1] + bad_nonc = [-2] + nonc_f = random.noncentral_f + desired = np.array([9.1393943263705211, + 13.025456344595602, + 8.8018098359100545]) + + self.set_seed() + actual = nonc_f(dfnum * 3, dfden, nonc) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_f, bad_dfnum * 3, dfden, nonc) + assert_raises(ValueError, nonc_f, dfnum * 3, bad_dfden, nonc) + assert_raises(ValueError, nonc_f, dfnum * 3, dfden, bad_nonc) + + self.set_seed() + actual = nonc_f(dfnum, dfden * 3, nonc) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_f, bad_dfnum, dfden * 3, nonc) + assert_raises(ValueError, nonc_f, dfnum, bad_dfden * 3, nonc) + assert_raises(ValueError, nonc_f, dfnum, dfden * 3, bad_nonc) + + self.set_seed() + actual = nonc_f(dfnum, dfden, nonc * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_f, bad_dfnum, dfden, nonc * 3) + assert_raises(ValueError, nonc_f, dfnum, bad_dfden, nonc * 3) + assert_raises(ValueError, nonc_f, dfnum, dfden, bad_nonc * 3) + + def test_chisquare(self): + df = [1] + bad_df = [-1] + chisquare = random.chisquare + desired = np.array([0.57022801133088286, + 0.51947702108840776, + 0.1320969254923558]) + + self.set_seed() + actual = chisquare(df * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, chisquare, bad_df * 3) + + def test_noncentral_chisquare(self): + df = [1] + nonc = [2] + bad_df = [-1] + bad_nonc = [-2] + nonc_chi = random.noncentral_chisquare + desired = np.array([9.0015599467913763, + 4.5804135049718742, + 6.0872302432834564]) + + self.set_seed() + actual = nonc_chi(df * 3, nonc) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_chi, bad_df * 3, nonc) + assert_raises(ValueError, nonc_chi, df * 3, bad_nonc) + + self.set_seed() + actual = nonc_chi(df, nonc * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_chi, bad_df, nonc * 3) + assert_raises(ValueError, nonc_chi, df, bad_nonc * 3) + + def test_standard_t(self): + df = [1] + bad_df = [-1] + t = random.standard_t + desired = np.array([3.0702872575217643, + 5.8560725167361607, + 1.0274791436474273]) + + self.set_seed() + actual = t(df * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, t, bad_df * 3) + + def test_vonmises(self): + mu = [2] + kappa = [1] + bad_kappa = [-1] + vonmises = random.vonmises + desired = np.array([2.9883443664201312, + -2.7064099483995943, + -1.8672476700665914]) + + self.set_seed() + actual = vonmises(mu * 3, kappa) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, vonmises, mu * 3, bad_kappa) + + self.set_seed() + actual = vonmises(mu, kappa * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, vonmises, mu, bad_kappa * 3) + + def test_pareto(self): + a = [1] + bad_a = [-1] + pareto = random.pareto + desired = np.array([1.1405622680198362, + 1.1465519762044529, + 1.0389564467453547]) + + self.set_seed() + actual = pareto(a * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, pareto, bad_a * 3) + + def test_weibull(self): + a = [1] + bad_a = [-1] + weibull = random.weibull + desired = np.array([0.76106853658845242, + 0.76386282278691653, + 0.71243813125891797]) + + self.set_seed() + actual = weibull(a * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, weibull, bad_a * 3) + + def test_power(self): + a = [1] + bad_a = [-1] + power = random.power + desired = np.array([0.53283302478975902, + 0.53413660089041659, + 0.50955303552646702]) + + self.set_seed() + actual = power(a * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, power, bad_a * 3) + + def test_laplace(self): + loc = [0] + scale = [1] + bad_scale = [-1] + laplace = random.laplace + desired = np.array([0.067921356028507157, + 0.070715642226971326, + 0.019290950698972624]) + + self.set_seed() + actual = laplace(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, laplace, loc * 3, bad_scale) + + self.set_seed() + actual = laplace(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, laplace, loc, bad_scale * 3) + + def test_gumbel(self): + loc = [0] + scale = [1] + bad_scale = [-1] + gumbel = random.gumbel + desired = np.array([0.2730318639556768, + 0.26936705726291116, + 0.33906220393037939]) + + self.set_seed() + actual = gumbel(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gumbel, loc * 3, bad_scale) + + self.set_seed() + actual = gumbel(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gumbel, loc, bad_scale * 3) + + def test_logistic(self): + loc = [0] + scale = [1] + bad_scale = [-1] + logistic = random.logistic + desired = np.array([0.13152135837586171, + 0.13675915696285773, + 0.038216792802833396]) + + self.set_seed() + actual = logistic(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, logistic, loc * 3, bad_scale) + + self.set_seed() + actual = logistic(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, logistic, loc, bad_scale * 3) + + def test_lognormal(self): + mean = [0] + sigma = [1] + bad_sigma = [-1] + lognormal = random.lognormal + desired = np.array([9.1422086044848427, + 8.4013952870126261, + 6.3073234116578671]) + + self.set_seed() + actual = lognormal(mean * 3, sigma) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, lognormal, mean * 3, bad_sigma) + + self.set_seed() + actual = lognormal(mean, sigma * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, lognormal, mean, bad_sigma * 3) + + def test_rayleigh(self): + scale = [1] + bad_scale = [-1] + rayleigh = random.rayleigh + desired = np.array([1.2337491937897689, + 1.2360119924878694, + 1.1936818095781789]) + + self.set_seed() + actual = rayleigh(scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, rayleigh, bad_scale * 3) + + def test_wald(self): + mean = [0.5] + scale = [1] + bad_mean = [0] + bad_scale = [-2] + wald = random.wald + desired = np.array([0.11873681120271318, + 0.12450084820795027, + 0.9096122728408238]) + + self.set_seed() + actual = wald(mean * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, wald, bad_mean * 3, scale) + assert_raises(ValueError, wald, mean * 3, bad_scale) + + self.set_seed() + actual = wald(mean, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, wald, bad_mean, scale * 3) + assert_raises(ValueError, wald, mean, bad_scale * 3) + + def test_triangular(self): + left = [1] + right = [3] + mode = [2] + bad_left_one = [3] + bad_mode_one = [4] + bad_left_two, bad_mode_two = right * 2 + triangular = random.triangular + desired = np.array([2.03339048710429, + 2.0347400359389356, + 2.0095991069536208]) + + self.set_seed() + actual = triangular(left * 3, mode, right) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, triangular, bad_left_one * 3, mode, right) + assert_raises(ValueError, triangular, left * 3, bad_mode_one, right) + assert_raises(ValueError, triangular, bad_left_two * 3, bad_mode_two, right) + + self.set_seed() + actual = triangular(left, mode * 3, right) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, triangular, bad_left_one, mode * 3, right) + assert_raises(ValueError, triangular, left, bad_mode_one * 3, right) + assert_raises(ValueError, triangular, bad_left_two, bad_mode_two * 3, right) + + self.set_seed() + actual = triangular(left, mode, right * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, triangular, bad_left_one, mode, right * 3) + assert_raises(ValueError, triangular, left, bad_mode_one, right * 3) + assert_raises(ValueError, triangular, bad_left_two, bad_mode_two, right * 3) + + def test_binomial(self): + n = [1] + p = [0.5] + bad_n = [-1] + bad_p_one = [-1] + bad_p_two = [1.5] + binom = random.binomial + desired = np.array([1, 1, 1]) + + self.set_seed() + actual = binom(n * 3, p) + assert_array_equal(actual, desired) + assert_raises(ValueError, binom, bad_n * 3, p) + assert_raises(ValueError, binom, n * 3, bad_p_one) + assert_raises(ValueError, binom, n * 3, bad_p_two) + + self.set_seed() + actual = binom(n, p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, binom, bad_n, p * 3) + assert_raises(ValueError, binom, n, bad_p_one * 3) + assert_raises(ValueError, binom, n, bad_p_two * 3) + + def test_negative_binomial(self): + n = [1] + p = [0.5] + bad_n = [-1] + bad_p_one = [-1] + bad_p_two = [1.5] + neg_binom = random.negative_binomial + desired = np.array([1, 0, 1]) + + self.set_seed() + actual = neg_binom(n * 3, p) + assert_array_equal(actual, desired) + assert_raises(ValueError, neg_binom, bad_n * 3, p) + assert_raises(ValueError, neg_binom, n * 3, bad_p_one) + assert_raises(ValueError, neg_binom, n * 3, bad_p_two) + + self.set_seed() + actual = neg_binom(n, p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, neg_binom, bad_n, p * 3) + assert_raises(ValueError, neg_binom, n, bad_p_one * 3) + assert_raises(ValueError, neg_binom, n, bad_p_two * 3) + + @pytest.mark.xfail + def test_poisson(self): + max_lam = random.RandomState().poisson_lam_max + + lam = [1] + bad_lam_one = [-1] + bad_lam_two = [max_lam * 2] + poisson = random.poisson + desired = np.array([1, 1, 0]) + + self.set_seed() + actual = poisson(lam * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, poisson, bad_lam_one * 3) + assert_raises(ValueError, poisson, bad_lam_two * 3) + + def test_zipf(self): + a = [2] + bad_a = [0] + zipf = random.zipf + desired = np.array([2, 2, 1]) + + self.set_seed() + actual = zipf(a * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, zipf, bad_a * 3) + + def test_geometric(self): + p = [0.5] + bad_p_one = [-1] + bad_p_two = [1.5] + geom = random.geometric + desired = np.array([2, 2, 2]) + + self.set_seed() + actual = geom(p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, geom, bad_p_one * 3) + assert_raises(ValueError, geom, bad_p_two * 3) + + def test_hypergeometric(self): + ngood = [1] + nbad = [2] + nsample = [2] + bad_ngood = [-1] + bad_nbad = [-2] + bad_nsample_one = [0] + bad_nsample_two = [4] + hypergeom = random.hypergeometric + desired = np.array([1, 1, 1]) + + self.set_seed() + actual = hypergeom(ngood * 3, nbad, nsample) + assert_array_equal(actual, desired) + assert_raises(ValueError, hypergeom, bad_ngood * 3, nbad, nsample) + assert_raises(ValueError, hypergeom, ngood * 3, bad_nbad, nsample) + assert_raises(ValueError, hypergeom, ngood * 3, nbad, bad_nsample_one) + assert_raises(ValueError, hypergeom, ngood * 3, nbad, bad_nsample_two) + + self.set_seed() + actual = hypergeom(ngood, nbad * 3, nsample) + assert_array_equal(actual, desired) + assert_raises(ValueError, hypergeom, bad_ngood, nbad * 3, nsample) + assert_raises(ValueError, hypergeom, ngood, bad_nbad * 3, nsample) + assert_raises(ValueError, hypergeom, ngood, nbad * 3, bad_nsample_one) + assert_raises(ValueError, hypergeom, ngood, nbad * 3, bad_nsample_two) + + self.set_seed() + actual = hypergeom(ngood, nbad, nsample * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, hypergeom, bad_ngood, nbad, nsample * 3) + assert_raises(ValueError, hypergeom, ngood, bad_nbad, nsample * 3) + assert_raises(ValueError, hypergeom, ngood, nbad, bad_nsample_one * 3) + assert_raises(ValueError, hypergeom, ngood, nbad, bad_nsample_two * 3) + + def test_logseries(self): + p = [0.5] + bad_p_one = [2] + bad_p_two = [-1] + logseries = random.logseries + desired = np.array([1, 1, 1]) + + self.set_seed() + actual = logseries(p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, logseries, bad_p_one * 3) + assert_raises(ValueError, logseries, bad_p_two * 3) + + +class TestThread(object): + # make sure each state produces the same sequence even in threads + + def setup(self): + self.seeds = range(4) + + def check_function(self, function, sz): + from threading import Thread + + out1 = np.empty((len(self.seeds),) + sz) + out2 = np.empty((len(self.seeds),) + sz) + + # threaded generation + t = [Thread(target=function, args=(RandomGenerator(MT19937(s)), o)) + for s, o in zip(self.seeds, out1)] + [x.start() for x in t] + [x.join() for x in t] + + # the same serial + for s, o in zip(self.seeds, out2): + function(RandomGenerator(MT19937(s)), o) + + # these platforms change x87 fpu precision mode in threads + if np.intp().dtype.itemsize == 4 and sys.platform == "win32": + assert_array_almost_equal(out1, out2) + else: + assert_array_equal(out1, out2) + + def test_normal(self): + def gen_random(state, out): + out[...] = state.normal(size=10000) + + self.check_function(gen_random, sz=(10000,)) + + def test_exp(self): + def gen_random(state, out): + out[...] = state.exponential(scale=np.ones((100, 1000))) + + self.check_function(gen_random, sz=(100, 1000)) + + def test_multinomial(self): + def gen_random(state, out): + out[...] = state.multinomial(10, [1 / 6.] * 6, size=10000) + + self.check_function(gen_random, sz=(10000, 6)) + + +# See Issue #4263 +class TestSingleEltArrayInput(object): + def setup(self): + self.argOne = np.array([2]) + self.argTwo = np.array([3]) + self.argThree = np.array([4]) + self.tgtShape = (1,) + + def test_one_arg_funcs(self): + funcs = (mt19937.exponential, mt19937.standard_gamma, + mt19937.chisquare, mt19937.standard_t, + mt19937.pareto, mt19937.weibull, + mt19937.power, mt19937.rayleigh, + mt19937.poisson, mt19937.zipf, + mt19937.geometric, mt19937.logseries) + + probfuncs = (mt19937.geometric, mt19937.logseries) + + for func in funcs: + if func in probfuncs: # p < 1.0 + out = func(np.array([0.5])) + + else: + out = func(self.argOne) + + assert_equal(out.shape, self.tgtShape) + + def test_two_arg_funcs(self): + funcs = (mt19937.uniform, mt19937.normal, + mt19937.beta, mt19937.gamma, + mt19937.f, mt19937.noncentral_chisquare, + mt19937.vonmises, mt19937.laplace, + mt19937.gumbel, mt19937.logistic, + mt19937.lognormal, mt19937.wald, + mt19937.binomial, mt19937.negative_binomial) + + probfuncs = (mt19937.binomial, mt19937.negative_binomial) + + for func in funcs: + if func in probfuncs: # p <= 1 + argTwo = np.array([0.5]) + + else: + argTwo = self.argTwo + + out = func(self.argOne, argTwo) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne[0], argTwo) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne, argTwo[0]) + assert_equal(out.shape, self.tgtShape) + + def test_randint(self): + itype = [np.bool, np.int8, np.uint8, np.int16, np.uint16, + np.int32, np.uint32, np.int64, np.uint64] + func = mt19937.randint + high = np.array([1]) + low = np.array([0]) + + for dt in itype: + out = func(low, high, dtype=dt) + assert_equal(out.shape, self.tgtShape) + + out = func(low[0], high, dtype=dt) + assert_equal(out.shape, self.tgtShape) + + out = func(low, high[0], dtype=dt) + assert_equal(out.shape, self.tgtShape) + + def test_three_arg_funcs(self): + funcs = [mt19937.noncentral_f, mt19937.triangular, + mt19937.hypergeometric] + + for func in funcs: + out = func(self.argOne, self.argTwo, self.argThree) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne[0], self.argTwo, self.argThree) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne, self.argTwo[0], self.argThree) + assert_equal(out.shape, self.tgtShape) + + +if __name__ == "__main__": + run_module_suite() diff --git a/_randomgen/core_prng/tests/test_numpy_mt19937_regressions.py b/_randomgen/core_prng/tests/test_numpy_mt19937_regressions.py new file mode 100644 index 000000000000..37ca9aa77f00 --- /dev/null +++ b/_randomgen/core_prng/tests/test_numpy_mt19937_regressions.py @@ -0,0 +1,140 @@ +from __future__ import division, absolute_import, print_function + +import sys +from numpy.testing import (run_module_suite, assert_, + assert_array_equal, assert_raises) +from numpy.compat import long +import numpy as np +import pytest +from core_prng import RandomGenerator, MT19937 + +mt19937 = RandomGenerator(MT19937()) + +class TestRegression(object): + + def test_VonMises_range(self): + # Make sure generated random variables are in [-pi, pi]. + # Regression test for ticket #986. + for mu in np.linspace(-7., 7., 5): + r = mt19937.vonmises(mu, 1, 50) + assert_(np.all(r > -np.pi) and np.all(r <= np.pi)) + + def test_hypergeometric_range(self): + # Test for ticket #921 + assert_(np.all(mt19937.hypergeometric(3, 18, 11, size=10) < 4)) + assert_(np.all(mt19937.hypergeometric(18, 3, 11, size=10) > 0)) + + # Test for ticket #5623 + args = [ + (2**20 - 2, 2**20 - 2, 2**20 - 2), # Check for 32-bit systems + ] + is_64bits = sys.maxsize > 2**32 + if is_64bits and sys.platform != 'win32': + args.append((2**40 - 2, 2**40 - 2, 2**40 - 2)) # Check for 64-bit systems + for arg in args: + assert_(mt19937.hypergeometric(*arg) > 0) + + def test_logseries_convergence(self): + # Test for ticket #923 + N = 1000 + mt19937.seed(0) + rvsn = mt19937.logseries(0.8, size=N) + # these two frequency counts should be close to theoretical + # numbers with this large sample + # theoretical large N result is 0.49706795 + freq = np.sum(rvsn == 1) / float(N) + msg = "Frequency was %f, should be > 0.45" % freq + assert_(freq > 0.45, msg) + # theoretical large N result is 0.19882718 + freq = np.sum(rvsn == 2) / float(N) + msg = "Frequency was %f, should be < 0.23" % freq + assert_(freq < 0.23, msg) + + def test_permutation_longs(self): + mt19937.seed(1234) + a = mt19937.permutation(12) + mt19937.seed(1234) + b = mt19937.permutation(long(12)) + assert_array_equal(a, b) + + def test_shuffle_mixed_dimension(self): + # Test for trac ticket #2074 + for t in [[1, 2, 3, None], + [(1, 1), (2, 2), (3, 3), None], + [1, (2, 2), (3, 3), None], + [(1, 1), 2, 3, None]]: + mt19937.seed(12345) + shuffled = list(t) + mt19937.shuffle(shuffled) + assert_array_equal(shuffled, [t[0], t[3], t[1], t[2]]) + + def test_call_within_randomstate(self): + # Check that custom RandomState does not call into global state + m = RandomGenerator(MT19937()) # mt19937.RandomState() + res = np.array([0, 8, 7, 2, 1, 9, 4, 7, 0, 3]) + for i in range(3): + mt19937.seed(i) + m.seed(4321) + # If m.state is not honored, the result will change + assert_array_equal(m.choice(10, size=10, p=np.ones(10)/10.), res) + + def test_multivariate_normal_size_types(self): + # Test for multivariate_normal issue with 'size' argument. + # Check that the multivariate_normal size argument can be a + # numpy integer. + mt19937.multivariate_normal([0], [[0]], size=1) + mt19937.multivariate_normal([0], [[0]], size=np.int_(1)) + mt19937.multivariate_normal([0], [[0]], size=np.int64(1)) + + def test_beta_small_parameters(self): + # Test that beta with small a and b parameters does not produce + # NaNs due to roundoff errors causing 0 / 0, gh-5851 + mt19937.seed(1234567890) + x = mt19937.beta(0.0001, 0.0001, size=100) + assert_(not np.any(np.isnan(x)), 'Nans in mt19937.beta') + + def test_choice_sum_of_probs_tolerance(self): + # The sum of probs should be 1.0 with some tolerance. + # For low precision dtypes the tolerance was too tight. + # See numpy github issue 6123. + mt19937.seed(1234) + a = [1, 2, 3] + counts = [4, 4, 2] + for dt in np.float16, np.float32, np.float64: + probs = np.array(counts, dtype=dt) / sum(counts) + c = mt19937.choice(a, p=probs) + assert_(c in a) + with pytest.raises(ValueError): + mt19937.choice(a, p=probs*0.9) + + def test_shuffle_of_array_of_different_length_strings(self): + # Test that permuting an array of different length strings + # will not cause a segfault on garbage collection + # Tests gh-7710 + mt19937.seed(1234) + + a = np.array(['a', 'a' * 1000]) + + for _ in range(100): + mt19937.shuffle(a) + + # Force Garbage Collection - should not segfault. + import gc + gc.collect() + + def test_shuffle_of_array_of_objects(self): + # Test that permuting an array of objects will not cause + # a segfault on garbage collection. + # See gh-7719 + mt19937.seed(1234) + a = np.array([np.arange(1), np.arange(4)]) + + for _ in range(1000): + mt19937.shuffle(a) + + # Force Garbage Collection - should not segfault. + import gc + gc.collect() + +if __name__ == "__main__": + run_module_suite() From 2a0d37ef462db075272619930a3822aec5d1ddb0 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 11 Mar 2018 21:21:28 +0000 Subject: [PATCH 058/279] TST: Finish direct testing Fix seeding Finish direct testing Enable travis --- _randomgen/.travis.yml | 59 +++++++++++++++++++ _randomgen/core_prng/entropy.pyx | 35 ++++++----- .../src/distributions/distributions.h | 1 + .../core_prng/tests/test_against_numpy.py | 6 +- _randomgen/core_prng/tests/test_direct.py | 46 +++++++++++++-- .../core_prng/tests/test_numpy_mt19937.py | 10 ++-- 6 files changed, 131 insertions(+), 26 deletions(-) create mode 100644 _randomgen/.travis.yml diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml new file mode 100644 index 000000000000..e30030a4bb39 --- /dev/null +++ b/_randomgen/.travis.yml @@ -0,0 +1,59 @@ +# Travis script that uses miniconda in place of the system installed python +# versions. Allows substantial flexability for choosing versions of +# required packages and is simpler to use to test up-to-date scientific Python +# stack +group: edge +dist: trusty +sudo: required +language: python + +matrix: + fast_finish: true + include: + - env: + - PYTHON=2.7 + - NUMPY=1.10 + - CYTHON=0.24 + - env: + - PYTHON=3.5 + - NUMPY=1.11 + - env: + - PYTHON=3.6 + - NUMPY=1.13 + - CYTHON=0.25 + - env: + - PYTHON=3.6 + - NUMPY=1.13 + - CYTHON=0.26 + - env: + - PYTHON=3.6 + +before_install: + - if [ ${TRAVIS_OS_NAME} = "osx" ]; then wget https://repo.continuum.io/miniconda/Miniconda-latest-MacOSX-x86_64.sh -O miniconda.sh; fi + - if [ ${TRAVIS_OS_NAME} = "linux" ]; then wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh; fi + - chmod +x miniconda3.sh + - ./miniconda3.sh -b + - export PATH=/home/travis/miniconda3/bin:$PATH + - conda config --set always_yes true + # Disable until fixed + # - conda update --all --quiet + - PKGS="python=${PYTHON}" + - PKGS="${PKGS} numpy"; if [ ${NUMPY} ]; then PKGS="${PKGS}=${NUMPY}"; fi + - PKGS="${PKGS} Cython"; if [ ${CYTHON} ]; then PKGS="${PKGS}=${CYTHON}"; fi + - PKGS="${PKGS} pandas"; if [ ${PANDAS} ]; then PKGS="${PKGS}=${PANDAS}"; fi + - export BUILD_DIR=$PWD + - conda create -n core-prng-test ${PKGS} pytest setuptools nose --quiet + - source activate core-prng-test + - pip install tempita -q + +install: + - python setup.py develop + +script: + - set -e + - pytest core_prng + - | + if [ -z ${NUMPY} ]; then + cd ${BUILD_DIR} + python benchmark.py; + fi diff --git a/_randomgen/core_prng/entropy.pyx b/_randomgen/core_prng/entropy.pyx index a4747f36b0fd..19dbb0fd20b2 100644 --- a/_randomgen/core_prng/entropy.pyx +++ b/_randomgen/core_prng/entropy.pyx @@ -44,27 +44,34 @@ cdef np.ndarray seed_by_array(object seed, Py_ssize_t n): cdef Py_ssize_t seed_size, iter_bound cdef int i, loc = 0 - try: - if hasattr(seed, 'squeeze'): - seed = seed.squeeze() - idx = operator.index(seed) - if idx > int(2**64 - 1) or idx < 0: - raise ValueError("Seed must be between 0 and 2**64 - 1") - seed = [seed] - seed_array = np.array(seed, dtype=np.uint64) - except TypeError: - exc_msg = "Seed values must be integers between 0 and 2**64 - 1" - obj = np.asarray(seed).astype(np.object).ravel() + if hasattr(seed, 'squeeze'): + seed = seed.squeeze() + arr = np.asarray(seed) + if arr.shape == (): + err_msg = 'Scalar seeds must be integers between 0 and 2**64 - 1' + if not np.isreal(arr): + raise TypeError(err_msg) + int_seed = int(seed) + if int_seed != seed: + raise TypeError(err_msg) + if int_seed < 0 or int_seed > 2**64 - 1: + raise ValueError(err_msg) + seed_array = np.array([int_seed], dtype=np.uint64) + else: + err_msg = "Seed values must be integers between 0 and 2**64 - 1" + obj = np.asarray(seed).astype(np.object) if obj.ndim != 1: raise ValueError('Array-valued seeds must be 1-dimensional') + if not np.isreal(obj).all(): + raise TypeError(err_msg) if ((obj > int(2**64 - 1)) | (obj < 0)).any(): - raise ValueError(exc_msg) + raise ValueError(err_msg) try: obj_int = obj.astype(np.uint64, casting='unsafe') except ValueError: - raise ValueError(exc_msg) + raise ValueError(err_msg) if not (obj == obj_int).all(): - raise ValueError(exc_msg) + raise TypeError(err_msg) seed_array = obj_int seed_size = seed_array.shape[0] diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index ce24cb11772e..9f368837eaeb 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -14,6 +14,7 @@ typedef int bool; #include #endif +#include "Python.h" #include "numpy/npy_common.h" #include diff --git a/_randomgen/core_prng/tests/test_against_numpy.py b/_randomgen/core_prng/tests/test_against_numpy.py index abe7cdb75c34..6bd4bc0912ac 100644 --- a/_randomgen/core_prng/tests/test_against_numpy.py +++ b/_randomgen/core_prng/tests/test_against_numpy.py @@ -23,7 +23,8 @@ def compare_1_input(f1, f2, is_small=False, core_prng_kwargs=None): ((np.array([a] * 10),), {'size': (100, 10)})] for i in inputs: v1 = f1(*i[0], **i[1]) - v2 = f2(*i[0], **i[1], **core_prng_kwargs) + i[1].update(core_prng_kwargs) + v2 = f2(*i[0], **i[1]) assert_allclose(v1, v2) @@ -51,7 +52,8 @@ def compare_2_input(f1, f2, is_np=False, is_scalar=False, core_prng_kwargs=None) for i in inputs: v1 = f1(*i[0], **i[1]) - v2 = f2(*i[0], **i[1], **core_prng_kwargs) + i[1].update(core_prng_kwargs) + v2 = f2(*i[0], **i[1]) assert_allclose(v1, v2) diff --git a/_randomgen/core_prng/tests/test_direct.py b/_randomgen/core_prng/tests/test_direct.py index 54ce706a2e19..9496cc1916f9 100644 --- a/_randomgen/core_prng/tests/test_direct.py +++ b/_randomgen/core_prng/tests/test_direct.py @@ -32,7 +32,7 @@ def uniform32_from_uint63(x): def uniform32_from_uint53(x): - x = np.uint64(x) + x = np.uint64(x) >> np.uint64(16) x = np.uint32(x & np.uint64(0xffffffff)) out = (x >> np.uint32(9)) * (1.0 / 2 ** 23) return out.astype(np.float32) @@ -193,10 +193,10 @@ def test_seed_float_array(self): rs = RandomGenerator(self.prng(*self.data1['seed'])) assert_raises(self.seed_error_type, rs.seed, np.array([np.pi])) assert_raises(self.seed_error_type, rs.seed, np.array([-np.pi])) - assert_raises(self.seed_error_type, rs.seed, np.array([np.pi, -np.pi])) - assert_raises(self.seed_error_type, rs.seed, np.array([0, np.pi])) - assert_raises(self.seed_error_type, rs.seed, [np.pi]) - assert_raises(self.seed_error_type, rs.seed, [0, np.pi]) + assert_raises(ValueError, rs.seed, np.array([np.pi, -np.pi])) + assert_raises(TypeError, rs.seed, np.array([0, np.pi])) + assert_raises(TypeError, rs.seed, [np.pi]) + assert_raises(TypeError, rs.seed, [0, np.pi]) def test_seed_out_of_range(self): # GH #82 @@ -335,3 +335,39 @@ def test_gauss_inv(self): gauss = rs.standard_normal(25, method='bm') assert_allclose(gauss, gauss_from_uint(self.data2['data'], n, 'dsfmt')) + + def test_seed_out_of_range_array(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(ValueError, rs.seed, [2 ** (self.bits + 1)]) + assert_raises(ValueError, rs.seed, [-1]) + assert_raises(TypeError, rs.seed, [2 ** (2 * self.bits + 1)]) + + def test_seed_float(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(TypeError, rs.seed, np.pi) + assert_raises(TypeError, rs.seed, -np.pi) + + def test_seed_float_array(self): + # GH #82 + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(TypeError, rs.seed, np.array([np.pi])) + assert_raises(TypeError, rs.seed, np.array([-np.pi])) + assert_raises(TypeError, rs.seed, np.array([np.pi, -np.pi])) + assert_raises(TypeError, rs.seed, np.array([0, np.pi])) + assert_raises(TypeError, rs.seed, [np.pi]) + assert_raises(TypeError, rs.seed, [0, np.pi]) + + def test_uniform_float(self): + rs = RandomGenerator(self.prng(*self.data1['seed'])) + vals = uniform32_from_uint(self.data1['data'], self.bits) + uniforms = rs.random_sample(len(vals), dtype=np.float32) + assert_allclose(uniforms, vals) + assert_equal(uniforms.dtype, np.float32) + + rs = RandomGenerator(self.prng(*self.data2['seed'])) + vals = uniform32_from_uint(self.data2['data'], self.bits) + uniforms = rs.random_sample(len(vals), dtype=np.float32) + assert_allclose(uniforms, vals) + assert_equal(uniforms.dtype, np.float32) diff --git a/_randomgen/core_prng/tests/test_numpy_mt19937.py b/_randomgen/core_prng/tests/test_numpy_mt19937.py index 7893c0da40b2..22d2d0b62195 100644 --- a/_randomgen/core_prng/tests/test_numpy_mt19937.py +++ b/_randomgen/core_prng/tests/test_numpy_mt19937.py @@ -4,7 +4,6 @@ import warnings import numpy as np -import randomstate as random from numpy.testing import ( run_module_suite, assert_, assert_raises, assert_equal, assert_warns, assert_no_warnings, assert_array_equal, @@ -14,7 +13,8 @@ import pytest from core_prng import RandomGenerator, MT19937 -mt19937 = RandomGenerator(MT19937()) +random = mt19937 = RandomGenerator(MT19937()) + class TestSeed(object): @@ -1098,12 +1098,12 @@ def test_normal(self): 1.8417114045748335]) self.set_seed() - actual = normal(loc * 3, scale) + actual = normal(loc * 3, scale, method='bm') assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc * 3, bad_scale) self.set_seed() - actual = normal(loc, scale * 3) + actual = normal(loc, scale * 3, method='bm') assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc, bad_scale * 3) @@ -1151,7 +1151,7 @@ def test_standard_gamma(self): 0.71243813125891797]) self.set_seed() - actual = std_gamma(shape * 3) + actual = std_gamma(shape * 3, method='inv') assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, std_gamma, bad_shape * 3) From 1999c3f08440fb1c0ea993d23d136a51fed696a0 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 11 Mar 2018 21:35:53 +0000 Subject: [PATCH 059/279] TST: Enable appveyor Enable appveyor --- _randomgen/appveyor.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 _randomgen/appveyor.yml diff --git a/_randomgen/appveyor.yml b/_randomgen/appveyor.yml new file mode 100644 index 000000000000..1106f48c154e --- /dev/null +++ b/_randomgen/appveyor.yml @@ -0,0 +1,33 @@ +skip_tags: true +clone_depth: 50 + +os: Visual Studio 2015 + +environment: + matrix: + - PY_MAJOR_VER: 2 + PYTHON_ARCH: "x86" + - PY_MAJOR_VER: 3 + PYTHON_ARCH: "x86_64" + - PY_MAJOR_VER: 3 + PYTHON_ARCH: "x86" + +platform: + - x64 + +build_script: + - ps: Start-FileDownload "https://repo.continuum.io/miniconda/Miniconda$env:PY_MAJOR_VER-latest-Windows-$env:PYTHON_ARCH.exe" C:\Miniconda.exe; echo "Finished downloading miniconda" + - cmd: C:\Miniconda.exe /S /D=C:\Py + - SET PATH=C:\Py;C:\Py\Scripts;C:\Py\Library\bin;%PATH% + - conda config --set always_yes yes + - conda update conda --quiet + - conda install numpy cython nose pandas pytest --quiet + - python setup.py develop + - set "GIT_DIR=%cd%" + +test_script: + - pytest core_prng + +on_success: + - cd %GIT_DIR%\ + - IF %PYTHON_ARCH%==x86_64 python benchmark.py \ No newline at end of file From c42dcc04e58a1418cf6f7a952cdfdeae31a99edc Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 11 Mar 2018 21:39:16 +0000 Subject: [PATCH 060/279] TST: Add shim for supporess warnings Add shim module to enable this function to be imported --- _randomgen/core_prng/_testing.py | 311 ++++++++++++++++++ .../core_prng/tests/test_numpy_mt19937.py | 6 +- 2 files changed, 313 insertions(+), 4 deletions(-) create mode 100644 _randomgen/core_prng/_testing.py diff --git a/_randomgen/core_prng/_testing.py b/_randomgen/core_prng/_testing.py new file mode 100644 index 000000000000..2f74d06e7b05 --- /dev/null +++ b/_randomgen/core_prng/_testing.py @@ -0,0 +1,311 @@ +""" +Shim for NumPy's suppress_warnings +""" + + +try: + from numpy.testing import suppress_warnings +except ImportError: + + # The following two classes are copied from python 2.6 warnings module (context + # manager) + class WarningMessage(object): + + """ + Holds the result of a single showwarning() call. + Deprecated in 1.8.0 + Notes + ----- + `WarningMessage` is copied from the Python 2.6 warnings module, + so it can be used in NumPy with older Python versions. + """ + + _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", + "line") + + def __init__(self, message, category, filename, lineno, file=None, + line=None): + local_values = locals() + for attr in self._WARNING_DETAILS: + setattr(self, attr, local_values[attr]) + if category: + self._category_name = category.__name__ + else: + self._category_name = None + + def __str__(self): + return ("{message : %r, category : %r, filename : %r, lineno : %s, " + "line : %r}" % (self.message, self._category_name, + self.filename, self.lineno, self.line)) + + import re + import warnings + from functools import wraps + + class suppress_warnings(object): + """ + Context manager and decorator doing much the same as + ``warnings.catch_warnings``. + However, it also provides a filter mechanism to work around + http://bugs.python.org/issue4180. + This bug causes Python before 3.4 to not reliably show warnings again + after they have been ignored once (even within catch_warnings). It + means that no "ignore" filter can be used easily, since following + tests might need to see the warning. Additionally it allows easier + specificity for testing warnings and can be nested. + Parameters + ---------- + forwarding_rule : str, optional + One of "always", "once", "module", or "location". Analogous to + the usual warnings module filter mode, it is useful to reduce + noise mostly on the outmost level. Unsuppressed and unrecorded + warnings will be forwarded based on this rule. Defaults to "always". + "location" is equivalent to the warnings "default", match by exact + location the warning warning originated from. + Notes + ----- + Filters added inside the context manager will be discarded again + when leaving it. Upon entering all filters defined outside a + context will be applied automatically. + When a recording filter is added, matching warnings are stored in the + ``log`` attribute as well as in the list returned by ``record``. + If filters are added and the ``module`` keyword is given, the + warning registry of this module will additionally be cleared when + applying it, entering the context, or exiting it. This could cause + warnings to appear a second time after leaving the context if they + were configured to be printed once (default) and were already + printed before the context was entered. + Nesting this context manager will work as expected when the + forwarding rule is "always" (default). Unfiltered and unrecorded + warnings will be passed out and be matched by the outer level. + On the outmost level they will be printed (or caught by another + warnings context). The forwarding rule argument can modify this + behaviour. + Like ``catch_warnings`` this context manager is not threadsafe. + Examples + -------- + >>> with suppress_warnings() as sup: + ... sup.filter(DeprecationWarning, "Some text") + ... sup.filter(module=np.ma.core) + ... log = sup.record(FutureWarning, "Does this occur?") + ... command_giving_warnings() + ... # The FutureWarning was given once, the filtered warnings were + ... # ignored. All other warnings abide outside settings (may be + ... # printed/error) + ... assert_(len(log) == 1) + ... assert_(len(sup.log) == 1) # also stored in log attribute + Or as a decorator: + >>> sup = suppress_warnings() + >>> sup.filter(module=np.ma.core) # module must match exact + >>> @sup + >>> def some_function(): + ... # do something which causes a warning in np.ma.core + ... pass + """ + def __init__(self, forwarding_rule="always"): + self._entered = False + + # Suppressions are either instance or defined inside one with block: + self._suppressions = [] + + if forwarding_rule not in {"always", "module", "once", "location"}: + raise ValueError("unsupported forwarding rule.") + self._forwarding_rule = forwarding_rule + + def _clear_registries(self): + if hasattr(warnings, "_filters_mutated"): + # clearing the registry should not be necessary on new pythons, + # instead the filters should be mutated. + warnings._filters_mutated() + return + # Simply clear the registry, this should normally be harmless, + # note that on new pythons it would be invalidated anyway. + for module in self._tmp_modules: + if hasattr(module, "__warningregistry__"): + module.__warningregistry__.clear() + + def _filter(self, category=Warning, message="", module=None, record=False): + if record: + record = [] # The log where to store warnings + else: + record = None + if self._entered: + if module is None: + warnings.filterwarnings( + "always", category=category, message=message) + else: + module_regex = module.__name__.replace('.', '\.') + '$' + warnings.filterwarnings( + "always", category=category, message=message, + module=module_regex) + self._tmp_modules.add(module) + self._clear_registries() + + self._tmp_suppressions.append( + (category, message, re.compile(message, re.I), module, record)) + else: + self._suppressions.append( + (category, message, re.compile(message, re.I), module, record)) + + return record + + def filter(self, category=Warning, message="", module=None): + """ + Add a new suppressing filter or apply it if the state is entered. + Parameters + ---------- + category : class, optional + Warning class to filter + message : string, optional + Regular expression matching the warning message. + module : module, optional + Module to filter for. Note that the module (and its file) + must match exactly and cannot be a submodule. This may make + it unreliable for external modules. + Notes + ----- + When added within a context, filters are only added inside + the context and will be forgotten when the context is exited. + """ + self._filter(category=category, message=message, module=module, + record=False) + + def record(self, category=Warning, message="", module=None): + """ + Append a new recording filter or apply it if the state is entered. + All warnings matching will be appended to the ``log`` attribute. + Parameters + ---------- + category : class, optional + Warning class to filter + message : string, optional + Regular expression matching the warning message. + module : module, optional + Module to filter for. Note that the module (and its file) + must match exactly and cannot be a submodule. This may make + it unreliable for external modules. + Returns + ------- + log : list + A list which will be filled with all matched warnings. + Notes + ----- + When added within a context, filters are only added inside + the context and will be forgotten when the context is exited. + """ + return self._filter(category=category, message=message, module=module, + record=True) + + def __enter__(self): + if self._entered: + raise RuntimeError("cannot enter suppress_warnings twice.") + + self._orig_show = warnings.showwarning + if hasattr(warnings, "_showwarnmsg"): + self._orig_showmsg = warnings._showwarnmsg + self._filters = warnings.filters + warnings.filters = self._filters[:] + + self._entered = True + self._tmp_suppressions = [] + self._tmp_modules = set() + self._forwarded = set() + + self.log = [] # reset global log (no need to keep same list) + + for cat, mess, _, mod, log in self._suppressions: + if log is not None: + del log[:] # clear the log + if mod is None: + warnings.filterwarnings( + "always", category=cat, message=mess) + else: + module_regex = mod.__name__.replace('.', '\.') + '$' + warnings.filterwarnings( + "always", category=cat, message=mess, + module=module_regex) + self._tmp_modules.add(mod) + warnings.showwarning = self._showwarning + if hasattr(warnings, "_showwarnmsg"): + warnings._showwarnmsg = self._showwarnmsg + self._clear_registries() + + return self + + def __exit__(self, *exc_info): + warnings.showwarning = self._orig_show + if hasattr(warnings, "_showwarnmsg"): + warnings._showwarnmsg = self._orig_showmsg + warnings.filters = self._filters + self._clear_registries() + self._entered = False + del self._orig_show + del self._filters + + def _showwarnmsg(self, msg): + self._showwarning(msg.message, msg.category, msg.filename, msg.lineno, + msg.file, msg.line, use_warnmsg=msg) + + def _showwarning(self, message, category, filename, lineno, + *args, **kwargs): + use_warnmsg = kwargs.pop("use_warnmsg", None) + for cat, _, pattern, mod, rec in ( + self._suppressions + self._tmp_suppressions)[::-1]: + if (issubclass(category, cat) and + pattern.match(message.args[0]) is not None): + if mod is None: + # Message and category match, either recorded or ignored + if rec is not None: + msg = WarningMessage(message, category, filename, + lineno, **kwargs) + self.log.append(msg) + rec.append(msg) + return + # Use startswith, because warnings strips the c or o from + # .pyc/.pyo files. + elif mod.__file__.startswith(filename): + # The message and module (filename) match + if rec is not None: + msg = WarningMessage(message, category, filename, + lineno, **kwargs) + self.log.append(msg) + rec.append(msg) + return + + # There is no filter in place, so pass to the outside handler + # unless we should only pass it once + if self._forwarding_rule == "always": + if use_warnmsg is None: + self._orig_show(message, category, filename, lineno, + *args, **kwargs) + else: + self._orig_showmsg(use_warnmsg) + return + + if self._forwarding_rule == "once": + signature = (message.args, category) + elif self._forwarding_rule == "module": + signature = (message.args, category, filename) + elif self._forwarding_rule == "location": + signature = (message.args, category, filename, lineno) + + if signature in self._forwarded: + return + self._forwarded.add(signature) + if use_warnmsg is None: + self._orig_show(message, category, filename, lineno, *args, + **kwargs) + else: + self._orig_showmsg(use_warnmsg) + + def __call__(self, func): + """ + Function decorator to apply certain suppressions to a whole + function. + """ + @wraps(func) + def new_func(*args, **kwargs): + with self: + return func(*args, **kwargs) + + return new_func \ No newline at end of file diff --git a/_randomgen/core_prng/tests/test_numpy_mt19937.py b/_randomgen/core_prng/tests/test_numpy_mt19937.py index 22d2d0b62195..3fa936f2f3c1 100644 --- a/_randomgen/core_prng/tests/test_numpy_mt19937.py +++ b/_randomgen/core_prng/tests/test_numpy_mt19937.py @@ -8,15 +8,13 @@ run_module_suite, assert_, assert_raises, assert_equal, assert_warns, assert_no_warnings, assert_array_equal, assert_array_almost_equal) -from numpy.testing import suppress_warnings - import pytest + +from core_prng._testing import suppress_warnings from core_prng import RandomGenerator, MT19937 random = mt19937 = RandomGenerator(MT19937()) - - class TestSeed(object): def test_scalar(self): s = RandomGenerator(MT19937(0)) From 9dde116361636cfbd6088df854b408bb1cd88c45 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 11 Mar 2018 22:07:49 +0000 Subject: [PATCH 061/279] DOC: Update readme Update readme --- _randomgen/README.md | 240 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 226 insertions(+), 14 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index 0e0bdda72e63..095f897ed306 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -1,30 +1,242 @@ # Core PRNG +[![Travis Build Status](https://travis-ci.org/bashtage/ng-numpy-randomstate.svg?branch=master)](https://travis-ci.org/bashtage/core-prng) +[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true)](https://ci.appveyor.com/project/bashtage/core-prng/branch/master) + Experimental Core Pseudo Random Number Generator interface for future NumPy RandomState evolution. -## Demo +This is a library and generic interface for alternative random +generators in Python and NumPy. + +## Features + +* Replacement for NumPy's RandomState + +```python +# import numpy.random as rnd +from core_prng import RandomGenerator, MT19937 +rnd = RandomGenerator(MT19937()) +x = rnd.standard_normal(100) +y = rnd.random_sample(100) +z = rnd.randn(10,10) +``` + +* Default random generator is a fast generator called Xoroshiro128plus +* Support for random number generators that support independent streams + and jumping ahead so that sub-streams can be generated +* Faster random number generation, especially for normal, standard + exponential and standard gamma using the Ziggurat method + +```python +from core_prng import RandomGenerator +# Use Xoroshiro128 +rnd = RandomGenerator() +w = rnd.standard_normal(10000, method='zig') +x = rnd.standard_exponential(10000, method='zig') +y = rnd.standard_gamma(5.5, 10000, method='zig') +``` + +* Support for 32-bit floating randoms for core generators. + Currently supported: + + * Uniforms (`random_sample`) + * Exponentials (`standard_exponential`, both Inverse CDF and Ziggurat) + * Normals (`standard_normal`, both Box-Muller and Ziggurat) + * Standard Gammas (via `standard_gamma`, both Inverse CDF and Ziggurat) + + **WARNING**: The 32-bit generators are **experimental** and subject + to change. + + **Note**: There are _no_ plans to extend the alternative precision + generation to all random number types. + +* Support for filling existing arrays using `out` keyword argument. Currently + supported in (both 32- and 64-bit outputs) + + * Uniforms (`random_sample`) + * Exponentials (`standard_exponential`) + * Normals (`standard_normal`) + * Standard Gammas (via `standard_gamma`) + +## Included Pseudo Random Number Generators + +This modules includes a number of alternative random +number generators in addition to the MT19937 that is included in NumPy. +The RNGs include: + +* [MT19937](https://github.com/numpy/numpy/blob/master/numpy/random/mtrand/), + the NumPy rng +* [dSFMT](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/) a + SSE2-aware version of the MT19937 generator that is especially fast at + generating doubles +* [xoroshiro128+](http://xoroshiro.di.unimi.it/) and + [xorshift1024*](http://xorshift.di.unimi.it/) +* [PCG64](http:w//www.pcg-random.org/) +* ThreeFry and Philox implementationf from [Random123](https://www.deshawrsearch.com/resources_random123.html) +## Differences from `numpy.random.RandomState` + +### New Features +* `standard_normal`, `normal`, `randn` and `multivariate_normal` all + support an additional `method` keyword argument which can be `bm` or + `zig` where `bm` corresponds to the current method using the Box-Muller + transformation and `zig` uses the much faster (100%+) Ziggurat method. +* `standard_exponential` and `standard_gamma` both support an additional + `method` keyword argument which can be `inv` or + `zig` where `inv` corresponds to the current method using the inverse + CDF and `zig` uses the much faster (100%+) Ziggurat method. +* Core random number generators can produce either single precision + (`np.float32`) or double precision (`np.float64`, the default) using + an the optional keyword argument `dtype` +* Core random number generators can fill existing arrays using the + `out` keyword argument + + +### New Functions + +* `random_entropy` - Read from the system entropy provider, which is +commonly used in cryptographic applications +* `random_raw` - Direct access to the values produced by the underlying +PRNG. The range of the values returned depends on the specifics of the +PRNG implementation. +* `random_uintegers` - unsigned integers, either 32- (`[0, 2**32-1]`) +or 64-bit (`[0, 2**64-1]`) +* `jump` - Jumps RNGs that support it. `jump` moves the state a great +distance. _Only available if supported by the RNG._ +* `advance` - Advanced the core RNG 'as-if' a number of draws were made, +without actually drawing the numbers. _Only available if supported by +the RNG._ + +## Status + +* Replacement for `numpy.random.RandomState`. The + `MT19937` generator is identical to `numpy.random.RandomState`, and + will produce an identical sequence of random numbers for a given seed. +* Builds and passes all tests on: + * Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 (probably works on 2.6 and 3.3) + * PC-BSD (FreeBSD) 64-bit, Python 2.7 + * OSX 64-bit, Python 2.7 + * Windows 32/64 bit (only tested on Python 2.7, 3.5 and 3.6, but + should work on 3.3/3.4) -Basic POC demonstration +## Version +The version matched the latest version of NumPy where +`RandoMGenerator(MT19937())` passes all NumPy test. + +## Documentation + +An occasionally updated build of the documentation is available on +[my github pages](http://bashtage.github.io/core-prng/). + +## Plans +This module is essentially complete. There are a few rough edges that +need to be smoothed. + +* Creation of additional streams from a RandomState where supported + (i.e. a `next_stream()` method) + +## Requirements +Building requires: + + * Python (2.7, 3.4, 3.5, 3.6) + * NumPy (1.9, 1.10, 1.11, 1.12) + * Cython (0.22, **not** 0.23, 0.24, 0.25) + * tempita (0.5+), if not provided by Cython + +Testing requires pytest (3.0+). + +**Note:** it might work with other versions but only tested with these +versions. + +## Development and Testing + +All development has been on 64-bit Linux, and it is regularly tested on +Travis-CI (Linux) and Appveyor (Windows). The library is occasionally +tested on Linux 32-bit, OSX 10.13, Free BSD 11.1. + +Basic tests are in place for all RNGs. The MT19937 is tested against +NumPy's implementation for identical results. It also passes NumPy's +test suite. + +## Installing + +```bash +python setup.py install +``` + +### SSE2 +`dSFTM` makes use of SSE2 by default. If you have a very old computer +or are building on non-x86, you can install using: ```bash -python setup.py develop +python setup.py install --no-sse2 ``` -```ipython -In [1]: import core_prng.generator +### Windows +Either use a binary installer, or if building from scratch, use +Python 3.6 with Visual Studio 2015 Community Edition. It can also be +build using Microsoft Visual C++ Compiler for Python 2.7 and Python 2.7, +although some modifications may be needed to `distutils` to find the +compiler. + +## Using + +The separate generators are importable from `core_prng` -# Default generator is Splitmix64 -In [2]: rg = core_prng.generator.RandomGenerator() +```python +from core_prng import RandomGenerator, ThreeFry, PCG64, MT19937 +rg = RandomGenerator(ThreeFry()) +rg.random_sample(100) -In [3]: rg.random_integer() -Out[3]: 872337561037043212 +rg = RandomGenerator(PCG64()) +rg.random_sample(100) -In [4]: from core_prng.xoroshiro128 import Xoroshiro128 +# Identical to NumPy +rg = RandomGenerator(MT19937()) +rg.random_sample(100) +``` + +## License +Standard NCSA, plus sub licenses for components. -# Swap the generator -In [5]: rg = core_prng.generator.RandomGenerator(Xoroshiro128()) +## Performance +Performance is promising, and even the mt19937 seems to be faster than +NumPy's mt19937. -In [6]: rg.random_integer() -Out[6]: 13370384800127340062 ``` +Speed-up relative to NumPy (Uniform Doubles) +************************************************************ +MT19937 22.9% +PCG64 109.6% +Philox -6.2% +ThreeFry -16.6% +Xoroshiro128 161.0% +Xorshift1024 119.9% + +Speed-up relative to NumPy (64-bit unsigned integers) +************************************************************ +MT19937 6.2% +PCG64 88.2% +Philox -23.0% +ThreeFry -26.5% +Xoroshiro128 142.4% +Xorshift1024 107.5% + +Speed-up relative to NumPy (Standard normals (Box-Muller)) +************************************************************ +MT19937 17.7% +PCG64 35.6% +Philox -26.2% +ThreeFry -16.9% +Xoroshiro128 57.9% +Xorshift1024 40.9% + +Speed-up relative to NumPy (Standard normals (Ziggurat)) +************************************************************ +MT19937 107.9% +PCG64 149.6% +Philox 11.1% +ThreeFry 78.8% +Xoroshiro128 224.7% +Xorshift1024 158.6% +``` \ No newline at end of file From 54a3bf01f0a1a1d9faa3b33e268d6001bc1708f7 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 11 Mar 2018 23:28:43 +0000 Subject: [PATCH 062/279] ENH: Add support for Philon on 32 bit Windows Performance is terrible --- _randomgen/core_prng/src/philox/philox.h | 26 +++++++++++++++++++++++- _randomgen/setup.py | 8 +++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/_randomgen/core_prng/src/philox/philox.h b/_randomgen/core_prng/src/philox/philox.h index d469eabb2adc..f0ca24e6a677 100644 --- a/_randomgen/core_prng/src/philox/philox.h +++ b/_randomgen/core_prng/src/philox/philox.h @@ -28,10 +28,34 @@ _philox4x64bumpkey(struct r123array2x64 key) { } #ifdef _WIN32 -/* TODO: This isn't correct for many platforms */ #include +/* TODO: This isn't correct for many platforms */ +#ifdef _WIN64 #pragma intrinsic(_umul128) +#else +#pragma intrinsic(__emulu) +static INLINE uint64_t _umul128(uint64_t a, uint64_t b, uint64_t *high) { + + uint64_t a_lo, a_hi, b_lo, b_hi, a_x_b_hi, a_x_b_mid, a_x_b_lo, b_x_a_mid, + carry_bit; + a_lo = (uint32_t)a; + a_hi = a >> 32; + b_lo = (uint32_t)b; + b_hi = b >> 32; + + a_x_b_hi = __emulu(a_hi, b_hi); + a_x_b_mid = __emulu(a_hi, b_lo); + b_x_a_mid = __emulu(b_hi, a_lo); + a_x_b_lo = __emulu(a_lo, b_lo); + carry_bit = ((uint64_t)(uint32_t)a_x_b_mid + (uint64_t)(uint32_t)b_x_a_mid + + (a_x_b_lo >> 32)) >> 32; + + *high = a_x_b_hi + (a_x_b_mid >> 32) + (b_x_a_mid >> 32) + carry_bit; + + return a_x_b_lo + ((a_x_b_mid + b_x_a_mid) << 32); +} +#endif static INLINE uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { return _umul128(a, b, hip); } diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 0f48e3f7aa10..9ccb2b8f4c4e 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -30,7 +30,6 @@ PCG_EMULATED_MATH = False EXTRA_INCLUDE_DIRS = [] -EXTRA_COMPILE_ARGS = [] EXTRA_LINK_ARGS = [] EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else ['-std=c99'] if os.name == 'nt': @@ -39,9 +38,10 @@ if DEBUG: EXTRA_LINK_ARGS += ['-debug'] EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] -if os.name == 'nt' and sys.version_info < (3, 0): - EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] + if sys.version_info < (3, 0): + EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] +DSFMT_DEFS = [('DSFMT_MEXP', '19937')] if USE_SSE2: if os.name == 'nt': EXTRA_COMPILE_ARGS += ['/wd4146', '/GL'] @@ -49,8 +49,6 @@ EXTRA_COMPILE_ARGS += ['/arch:SSE2'] else: EXTRA_COMPILE_ARGS += ['-msse2'] -DSFMT_DEFS = [('DSFMT_MEXP', '19937')] -if USE_SSE2: DSFMT_DEFS += [('HAVE_SSE2', '1')] files = glob.glob('./core_prng/*.in') From 6bb7b837dfc99ba0b8cb4d402ab2d71a346f9571 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 12 Mar 2018 10:03:17 +0000 Subject: [PATCH 063/279] ENH: Add support for ThreeFry32x4 Add support for ThreeFry32x4 to benchmark --- _randomgen/appveyor.yml | 2 +- _randomgen/benchmark.py | 3 +- _randomgen/core_prng/__init__.py | 3 +- _randomgen/core_prng/_testing.py | 40 +- _randomgen/core_prng/common.pxd | 2 +- _randomgen/core_prng/common.pyx | 19 +- _randomgen/core_prng/generator.pyx | 1 + _randomgen/core_prng/pcg64.pyx | 17 +- _randomgen/core_prng/philox.pyx | 8 +- _randomgen/core_prng/pickle.py | 2 + .../src/distributions/distributions.c | 33 +- .../core_prng/src/pcg64/pcg64-test-data-gen.c | 23 +- _randomgen/core_prng/src/pcg64/pcg64.orig.c | 4 + .../src/threefry/threefry-test-data-gen.c | 2 + _randomgen/core_prng/src/threefry/threefry.c | 33 - .../src/threefry32/threefry32-test-data-gen.c | 88 ++ .../core_prng/src/threefry32/threefry32.c | 29 + .../core_prng/src/threefry32/threefry32.h | 827 ++++++++++++++ .../core_prng/tests/data/pcg64-testset-1.csv | 1001 +++++++++++++++++ .../core_prng/tests/data/pcg64-testset-2.csv | 1001 +++++++++++++++++ .../tests/data/threefry32-testset-1.csv | 1001 +++++++++++++++++ .../tests/data/threefry32-testset-2.csv | 1001 +++++++++++++++++ .../core_prng/tests/test_against_numpy.py | 3 +- _randomgen/core_prng/tests/test_direct.py | 40 +- .../core_prng/tests/test_numpy_mt19937.py | 3 +- _randomgen/core_prng/tests/test_smoke.py | 72 +- _randomgen/core_prng/threefry.pyx | 9 +- _randomgen/core_prng/threefry32.pyx | 250 ++++ _randomgen/core_prng/xoroshiro128.pyx | 2 +- _randomgen/core_prng/xorshift1024.pyx | 2 +- _randomgen/setup.py | 9 + 31 files changed, 5389 insertions(+), 141 deletions(-) create mode 100644 _randomgen/core_prng/src/threefry32/threefry32-test-data-gen.c create mode 100644 _randomgen/core_prng/src/threefry32/threefry32.c create mode 100644 _randomgen/core_prng/src/threefry32/threefry32.h create mode 100644 _randomgen/core_prng/tests/data/pcg64-testset-1.csv create mode 100644 _randomgen/core_prng/tests/data/pcg64-testset-2.csv create mode 100644 _randomgen/core_prng/tests/data/threefry32-testset-1.csv create mode 100644 _randomgen/core_prng/tests/data/threefry32-testset-2.csv create mode 100644 _randomgen/core_prng/threefry32.pyx diff --git a/_randomgen/appveyor.yml b/_randomgen/appveyor.yml index 1106f48c154e..86d98b2b67aa 100644 --- a/_randomgen/appveyor.yml +++ b/_randomgen/appveyor.yml @@ -30,4 +30,4 @@ test_script: on_success: - cd %GIT_DIR%\ - - IF %PYTHON_ARCH%==x86_64 python benchmark.py \ No newline at end of file + - IF %PY_MAJOR_VER%==3 python benchmark.py \ No newline at end of file diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index e670e72657c5..f828f657d24f 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -27,8 +27,7 @@ scale_64 = 2 PRNGS = ['PCG64', 'MT19937', 'Xoroshiro128', 'Xorshift1024', - 'Philox', 'ThreeFry', 'numpy'] # , 'Xorshift1024', -#'Xoroshiro128', 'DSFMT', 'random'] + 'Philox', 'ThreeFry', 'ThreeFry32', 'numpy'] def timer(code, setup): diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index d5577f3bf3cb..9b7d10631927 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -4,11 +4,12 @@ from .pcg64 import PCG64 from .philox import Philox from .threefry import ThreeFry +from .threefry32 import ThreeFry32 from .xoroshiro128 import Xoroshiro128 from .xorshift1024 import Xorshift1024 __all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'Philox', - 'ThreeFry', 'Xoroshiro128', 'Xorshift1024'] + 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024'] from ._version import get_versions diff --git a/_randomgen/core_prng/_testing.py b/_randomgen/core_prng/_testing.py index 2f74d06e7b05..86c5ea2b157a 100644 --- a/_randomgen/core_prng/_testing.py +++ b/_randomgen/core_prng/_testing.py @@ -7,8 +7,8 @@ from numpy.testing import suppress_warnings except ImportError: - # The following two classes are copied from python 2.6 warnings module (context - # manager) + # The following two classes are copied from python 2.6 warnings module + # (context manager) class WarningMessage(object): """ @@ -20,8 +20,8 @@ class WarningMessage(object): so it can be used in NumPy with older Python versions. """ - _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", - "line") + _WARNING_DETAILS = ("message", "category", "filename", "lineno", + "file", "line") def __init__(self, message, category, filename, lineno, file=None, line=None): @@ -34,7 +34,8 @@ def __init__(self, message, category, filename, lineno, file=None, self._category_name = None def __str__(self): - return ("{message : %r, category : %r, filename : %r, lineno : %s, " + return ("{message : %r, category : %r, " + "filename : %r, lineno : %s, " "line : %r}" % (self.message, self._category_name, self.filename, self.lineno, self.line)) @@ -59,9 +60,9 @@ class suppress_warnings(object): One of "always", "once", "module", or "location". Analogous to the usual warnings module filter mode, it is useful to reduce noise mostly on the outmost level. Unsuppressed and unrecorded - warnings will be forwarded based on this rule. Defaults to "always". - "location" is equivalent to the warnings "default", match by exact - location the warning warning originated from. + warnings will be forwarded based on this rule. Defaults to + "always". "location" is equivalent to the warnings "default", match + by exact location the warning warning originated from. Notes ----- Filters added inside the context manager will be discarded again @@ -105,7 +106,7 @@ class suppress_warnings(object): def __init__(self, forwarding_rule="always"): self._entered = False - # Suppressions are either instance or defined inside one with block: + # Suppressions are instance or defined inside one with block: self._suppressions = [] if forwarding_rule not in {"always", "module", "once", "location"}: @@ -124,7 +125,8 @@ def _clear_registries(self): if hasattr(module, "__warningregistry__"): module.__warningregistry__.clear() - def _filter(self, category=Warning, message="", module=None, record=False): + def _filter(self, category=Warning, message="", module=None, + record=False): if record: record = [] # The log where to store warnings else: @@ -142,10 +144,12 @@ def _filter(self, category=Warning, message="", module=None, record=False): self._clear_registries() self._tmp_suppressions.append( - (category, message, re.compile(message, re.I), module, record)) + (category, message, re.compile(message, re.I), module, + record)) else: self._suppressions.append( - (category, message, re.compile(message, re.I), module, record)) + (category, message, re.compile(message, re.I), module, + record)) return record @@ -193,8 +197,8 @@ def record(self, category=Warning, message="", module=None): When added within a context, filters are only added inside the context and will be forgotten when the context is exited. """ - return self._filter(category=category, message=message, module=module, - record=True) + return self._filter(category=category, message=message, + module=module, record=True) def __enter__(self): if self._entered: @@ -243,8 +247,8 @@ def __exit__(self, *exc_info): del self._filters def _showwarnmsg(self, msg): - self._showwarning(msg.message, msg.category, msg.filename, msg.lineno, - msg.file, msg.line, use_warnmsg=msg) + self._showwarning(msg.message, msg.category, msg.filename, + msg.lineno, msg.file, msg.line, use_warnmsg=msg) def _showwarning(self, message, category, filename, lineno, *args, **kwargs): @@ -254,7 +258,7 @@ def _showwarning(self, message, category, filename, lineno, if (issubclass(category, cat) and pattern.match(message.args[0]) is not None): if mod is None: - # Message and category match, either recorded or ignored + # Message and category match, recorded or ignored if rec is not None: msg = WarningMessage(message, category, filename, lineno, **kwargs) @@ -308,4 +312,4 @@ def new_func(*args, **kwargs): with self: return func(*args, **kwargs) - return new_func \ No newline at end of file + return new_func diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index a6419cfa4958..43981f476f15 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -59,7 +59,7 @@ cdef object float_fill(void *func, prng_t *state, object size, object lock, obje cdef object float_fill_from_double(void *func, prng_t *state, object size, object lock, object out) -cdef np.ndarray int_to_array(object value, object name, object bits) +cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size) cdef object cont(void *func, prng_t *state, object size, object lock, int narg, object a, object a_name, constraint_type a_constraint, diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index 5dedbdbde1e8..fb3e96697bae 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -20,21 +20,28 @@ cdef double kahan_sum(double *darr, np.npy_intp n): sum = t return sum -cdef np.ndarray int_to_array(object value, object name, object bits): - len = bits // 64 +cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size): + len = bits // uint_size value = np.asarray(value) + if uint_size == 32: + dtype = np.uint32 + elif uint_size == 64: + dtype = np.uint64 + else: + raise ValueError('Unknown uint_size') if value.shape == (): value = int(value) upper = int(2)**int(bits) if value < 0 or value >= upper: raise ValueError('{name} must be positive and ' 'less than 2**{bits}.'.format(name=name, bits=bits)) - out = np.empty(len, dtype=np.uint64) + + out = np.empty(len, dtype=dtype) for i in range(len): - out[i] = value % 2**64 - value >>= 64 + out[i] = value % 2**int(uint_size) + value >>= int(uint_size) else: - out = value.astype(np.uint64) + out = value.astype(dtype) if out.shape != (len,): raise ValueError('{name} must have {len} elements when using ' 'array form'.format(name=name, len=len)) diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 0e3bbf0cc799..e5fd47ec4f6f 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -59,6 +59,7 @@ cdef class RandomGenerator: cdef public object __core_prng cdef prng_t *_prng cdef object lock + poisson_lam_max = POISSON_LAM_MAX def __init__(self, prng=None): if prng is None: diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index 7353a77beaf2..70aa57b76610 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -47,7 +47,7 @@ cdef extern from "src/pcg64/pcg64.h": ctypedef s_pcg64_state pcg64_state uint64_t pcg64_next64(pcg64_state *state) nogil - uint64_t pcg64_next32(pcg64_state *state) nogil + uint32_t pcg64_next32(pcg64_state *state) nogil void pcg64_jump(pcg64_state *state) void pcg64_advance(pcg64_state *state, uint64_t *step) void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc) @@ -79,7 +79,7 @@ cdef class PCG64: cdef prng_t *_prng cdef public object capsule - def __init__(self, seed=None, inc=1): + def __init__(self, seed=None, inc=0): self.rng_state = malloc(sizeof(pcg64_state)) self.rng_state.pcg_state = malloc(sizeof(pcg64_random_t)) self._prng = malloc(sizeof(prng_t)) @@ -157,7 +157,7 @@ cdef class PCG64: raise ValueError('Unknown method') - def seed(self, seed=None, inc=1): + def seed(self, seed=None, inc=0): """ seed(seed=None, stream=None) @@ -187,13 +187,16 @@ cdef class PCG64: _seed = random_entropy(4) except RuntimeError: _seed = random_entropy(4, 'fallback') - _seed = _seed.view(np.uint64) else: + err_msg = 'inc must be a scalar integer between 0 and ' \ + '{ub}'.format(ub=ub) if not np.isscalar(seed): - raise TypeError('seed must be a scalar integer between 0 and {ub}'.format(ub=ub)) - if seed < 0 or seed > ub or int(seed) != seed: - raise ValueError('inc must be a scalar integer between 0 and {ub}'.format(ub=ub)) + raise TypeError(err_msg) + if int(seed) != seed: + raise TypeError(err_msg) + if seed < 0 or seed > ub: + raise ValueError(err_msg) _seed = np.empty(2, np.uint64) _seed[0] = int(seed) // 2**64 _seed[1] = int(seed) % 2**64 diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx index 12d69fe6813a..c724e5ee8be0 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/core_prng/philox.pyx @@ -37,7 +37,7 @@ cdef extern from 'src/philox/philox.h': ctypedef s_philox_state philox_state uint64_t philox_next64(philox_state *state) nogil - uint64_t philox_next32(philox_state *state) nogil + uint32_t philox_next32(philox_state *state) nogil void philox_jump(philox_state *state) void philox_advance(uint64_t *step, philox_state *state) @@ -200,11 +200,11 @@ cdef class Philox: for i in range(2): self.rng_state.key.v[i] = state[i] else: - key = int_to_array(key, 'key', 128) + key = int_to_array(key, 'key', 128, 64) for i in range(2): self.rng_state.key.v[i] = key[i] counter = 0 if counter is None else counter - counter = int_to_array(counter, 'counter', 256) + counter = int_to_array(counter, 'counter', 256, 64) for i in range(4): self.rng_state.ctr.v[i] = counter[i] @@ -257,7 +257,7 @@ cdef class Philox: def advance(self, step): """Advance the state as-if a specific number of draws have been made""" cdef np.ndarray step_a - step_a = int_to_array(step, 'step', 256) + step_a = int_to_array(step, 'step', 256, 64) loc = 0 philox_advance( step_a.data, self.rng_state) return self diff --git a/_randomgen/core_prng/pickle.py b/_randomgen/core_prng/pickle.py index 44b7e6b24210..56f4de56240e 100644 --- a/_randomgen/core_prng/pickle.py +++ b/_randomgen/core_prng/pickle.py @@ -4,6 +4,7 @@ from .pcg64 import PCG64 from .philox import Philox from .threefry import ThreeFry +from .threefry32 import ThreeFry32 from .xoroshiro128 import Xoroshiro128 from .xorshift1024 import Xorshift1024 @@ -12,6 +13,7 @@ 'PCG64': PCG64, 'Philox': Philox, 'ThreeFry': ThreeFry, + 'ThreeFry32': ThreeFry32, 'Xorshift1024': Xorshift1024, 'Xoroshiro128': Xoroshiro128} diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 4c2896e888ab..fbdad8f2f669 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -2,15 +2,14 @@ #include "ziggurat.h" #include "ziggurat_constants.h" -static NPY_INLINE float next_float(prng_t *prng_state) { - return (prng_state->next_uint32(prng_state->state) >> 9) * - (1.0f / 8388608.0f); -} - static NPY_INLINE uint32_t random_uint32(prng_t *prng_state) { return prng_state->next_uint32(prng_state->state); } +static NPY_INLINE float next_float(prng_t *prng_state) { + return (random_uint32(prng_state) >> 9) * (1.0f / 8388608.0f); +} + static NPY_INLINE uint64_t random_uint64(prng_t *prng_state) { return prng_state->next_uint64(prng_state->state); } @@ -77,7 +76,7 @@ float random_gauss_f(prng_t *prng_state) { } } -double standard_exponential_zig(prng_t *prng_state); +static NPY_INLINE double standard_exponential_zig(prng_t *prng_state); static double standard_exponential_zig_unlikely(prng_t *prng_state, uint8_t idx, double x) { @@ -93,11 +92,11 @@ static double standard_exponential_zig_unlikely(prng_t *prng_state, uint8_t idx, } } -double standard_exponential_zig(prng_t *prng_state) { +static NPY_INLINE double standard_exponential_zig(prng_t *prng_state) { uint64_t ri; uint8_t idx; double x; - ri = prng_state->next_uint64(prng_state->state); + ri = random_uint64(prng_state); ri >>= 3; idx = ri & 0xFF; ri >>= 8; @@ -131,7 +130,7 @@ static NPY_INLINE float standard_exponential_zig_f(prng_t *prng_state) { uint32_t ri; uint8_t idx; float x; - ri = prng_state->next_uint32(prng_state->state); + ri = random_uint32(prng_state); ri >>= 1; idx = ri & 0xFF; ri >>= 8; @@ -154,7 +153,7 @@ double random_gauss_zig(prng_t *prng_state) { double x, xx, yy; for (;;) { /* r = e3n52sb8 */ - r = prng_state->next_uint64(prng_state->state); + r = random_uint64(prng_state); idx = r & 0xff; r >>= 8; sign = r & 0x1; @@ -190,7 +189,7 @@ float random_gauss_zig_f(prng_t *prng_state) { float x, xx, yy; for (;;) { /* r = n23sb8 */ - r = prng_state->next_uint32(prng_state->state); + r = random_uint32(prng_state); idx = r & 0xff; sign = (r >> 8) & 0x1; rabs = (int32_t)((r >> 9) & 0x0007fffff); @@ -400,26 +399,26 @@ float random_standard_gamma_zig_f(prng_t *prng_state, float shape) { } int64_t random_positive_int64(prng_t *prng_state) { - return prng_state->next_uint64(prng_state->state) >> 1; + return random_uint64(prng_state) >> 1; } int32_t random_positive_int32(prng_t *prng_state) { - return prng_state->next_uint32(prng_state->state) >> 1; + return random_uint32(prng_state) >> 1; } long random_positive_int(prng_t *prng_state) { #if ULONG_MAX <= 0xffffffffUL - return (long)(prng_state->next_uint32(prng_state->state) >> 1); + return (long)(random_uint32(prng_state) >> 1); #else - return (long)(prng_state->next_uint64(prng_state->state) >> 1); + return (long)(random_uint64(prng_state) >> 1); #endif } unsigned long random_uint(prng_t *prng_state) { #if ULONG_MAX <= 0xffffffffUL - return prng_state->next_uint32(prng_state->state); + return random_uint32(prng_state); #else - return prng_state->next_uint64(prng_state->state); + return random_uint64(prng_state); #endif } diff --git a/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c b/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c index cb675346c4c0..0c2b079a3e15 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c +++ b/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c @@ -7,7 +7,6 @@ * pgc64-test-data-gen */ -#include "../splitmix64/splitmix64.h" #include "pcg64.orig.h" #include #include @@ -18,12 +17,16 @@ int main() { pcg64_random_t rng; uint64_t state, seed = 0xDEADBEAF; state = seed; - __uint128_t temp; - rng.state = (__uint128_t)splitmix64_next(&state) << 64; - rng.state |= splitmix64_next(&state); - rng.inc = (__uint128_t)1; + __uint128_t temp, s, inc; int i; uint64_t store[N]; + s = (__uint128_t)seed; + inc = (__uint128_t)0; + pcg64_srandom_r(&rng, s, inc); + printf("0x%" PRIx64, (uint64_t)(rng.state >> 64)); + printf("%" PRIx64 "\n", (uint64_t)rng.state); + printf("0x%" PRIx64, (uint64_t)(rng.inc >> 64)); + printf("%" PRIx64 "\n", (uint64_t)rng.inc); for (i = 0; i < N; i++) { store[i] = pcg64_random_r(&rng); } @@ -44,9 +47,13 @@ int main() { fclose(fp); state = seed = 0; - rng.state = - (__uint128_t)splitmix64_next(&state) << 64 | splitmix64_next(&state); - rng.inc = (__uint128_t)1; + s = (__uint128_t)seed; + i = (__uint128_t)0; + pcg64_srandom_r(&rng, s, i); + printf("0x%" PRIx64, (uint64_t)(rng.state >> 64)); + printf("%" PRIx64 "\n", (uint64_t)rng.state); + printf("0x%" PRIx64, (uint64_t)(rng.inc >> 64)); + printf("%" PRIx64 "\n", (uint64_t)rng.inc); for (i = 0; i < N; i++) { store[i] = pcg64_random_r(&rng); } diff --git a/_randomgen/core_prng/src/pcg64/pcg64.orig.c b/_randomgen/core_prng/src/pcg64/pcg64.orig.c index 24488123edfe..07e97e4b6d97 100644 --- a/_randomgen/core_prng/src/pcg64/pcg64.orig.c +++ b/_randomgen/core_prng/src/pcg64/pcg64.orig.c @@ -1,5 +1,9 @@ #include "pcg64.orig.h" +extern inline void pcg_setseq_128_srandom_r(pcg64_random_t *rng, + pcg128_t initstate, + pcg128_t initseq); + extern uint64_t pcg_rotr_64(uint64_t value, unsigned int rot); extern inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state); extern void pcg_setseq_128_step_r(struct pcg_state_setseq_128 *rng); diff --git a/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c b/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c index 444824c1231a..328eb257589e 100644 --- a/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c +++ b/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c @@ -45,6 +45,7 @@ int main() { printf("Couldn't open file\n"); return -1; } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); for (i = 0; i < N; i++) { fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); if (i == 999) { @@ -71,6 +72,7 @@ int main() { printf("Couldn't open file\n"); return -1; } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); for (i = 0; i < N; i++) { fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); if (i == 999) { diff --git a/_randomgen/core_prng/src/threefry/threefry.c b/_randomgen/core_prng/src/threefry/threefry.c index 56b499bd9dda..6aac7b5256c8 100644 --- a/_randomgen/core_prng/src/threefry/threefry.c +++ b/_randomgen/core_prng/src/threefry/threefry.c @@ -1,36 +1,3 @@ -/* -Adapted from https://github.com/pdebuyl/threefry - -Copyright (c) 2017, Pierre de Buyl - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - #include "threefry.h" extern INLINE uint64_t threefry_next64(threefry_state *state); diff --git a/_randomgen/core_prng/src/threefry32/threefry32-test-data-gen.c b/_randomgen/core_prng/src/threefry32/threefry32-test-data-gen.c new file mode 100644 index 000000000000..0e62299957b1 --- /dev/null +++ b/_randomgen/core_prng/src/threefry32/threefry32-test-data-gen.c @@ -0,0 +1,88 @@ +/* + * Generate testing csv files + * + * cl threefry32-test-data-gen.c /Ox ../splitmix64/splitmix64.c /Ox + * threefry32-test-data-gen.exe + * + * gcc threefry32-test-data-gen.c ../splitmix64/splitmix64.c /Ox -o + * threefry32-test-data-gen + * ./threefry32-test-data-gen + * + * Requires the Random123 directory containing header files to be located in the + * same directory (not included). + * + */ + +#include "../splitmix64/splitmix64.h" +#include "Random123/threefry.h" +#include +#include + +#define N 1000 + +int main() { + threefry4x32_key_t ctr = {{0, 0, 0, 0}}; + uint64_t state, seed = 0xDEADBEAF; + state = seed; + threefry4x32_ctr_t key = {{0}}; + threefry4x32_ctr_t out; + uint64_t store[N]; + uint64_t seed_val; + int i, j; + for (i = 0; i < 4; i++) { + seed_val = splitmix64_next(&state); + key.v[2*i] = (uint32_t)seed_val; + key.v[2*i+1] = (uint32_t)(seed_val >> 32); + } + for (i = 0; i < N / 4UL; i++) { + ctr.v[0]++; + out = threefry4x32_R(threefry4x32_rounds, ctr, key); + for (j = 0; j < 4; j++) { + store[i * 4 + j] = out.v[j]; + } + } + + FILE *fp; + fp = fopen("threefry32-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); + + ctr.v[0] = 0; + state = seed = 0; + for (i = 0; i < 4; i++) { + seed_val = splitmix64_next(&state); + key.v[2*i] = (uint32_t)seed_val; + key.v[2*i+1] = (uint32_t)(seed_val >> 32); + } + for (i = 0; i < N / 4; i++) { + ctr.v[0]++; + out = threefry4x32_R(threefry4x32_rounds, ctr, key); + for (j = 0; j < 4; j++) { + store[i * 4 + j] = out.v[j]; + } + } + + fp = fopen("threefry32-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); +} diff --git a/_randomgen/core_prng/src/threefry32/threefry32.c b/_randomgen/core_prng/src/threefry32/threefry32.c new file mode 100644 index 000000000000..e30d9c5690e8 --- /dev/null +++ b/_randomgen/core_prng/src/threefry32/threefry32.c @@ -0,0 +1,29 @@ +#include "threefry32.h" + +extern INLINE uint64_t threefry32_next64(threefry32_state *state); + +extern INLINE uint64_t threefry32_next32(threefry32_state *state); + +extern void threefry32_jump(threefry32_state *state) { + /* Advances state as-if 2^64 draws were made */ + state->ctr->v[2]++; + if (state->ctr->v[2] == 0) { + state->ctr->v[3]++; + } +} + +extern void threefry32_advance(uint32_t *step, threefry32_state *state) { + int i, carry = 0; + uint32_t v_orig; + for (i = 0; i < 4; i++) { + if (carry == 1) { + state->ctr->v[i]++; + carry = state->ctr->v[i] == 0 ? 1 : 0; + } + v_orig = state->ctr->v[i]; + state->ctr->v[i] += step[i]; + if (state->ctr->v[i] < v_orig && carry == 0) { + carry = 1; + } + } +} diff --git a/_randomgen/core_prng/src/threefry32/threefry32.h b/_randomgen/core_prng/src/threefry32/threefry32.h new file mode 100644 index 000000000000..8e9a1161e4ed --- /dev/null +++ b/_randomgen/core_prng/src/threefry32/threefry32.h @@ -0,0 +1,827 @@ +/* +Adapted from random123's threefry.h +*/ + +#ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/inttypes.h" +#define INLINE __forceinline +#else +#include +#define INLINE __inline __forceinline +#endif +#else +#include +#define INLINE inline +#endif + +#define THREEFRY_BUFFER_SIZE 4L + + +static INLINE uint32_t RotL_32(uint32_t x, unsigned int N); +static INLINE uint32_t RotL_32(uint32_t x, unsigned int N) +{ + return (x << (N & 31)) | (x >> ((32-N) & 31)); +} + +struct r123array4x32{ uint32_t v[4]; }; + +enum r123_enum_threefry32x4 { + + R_32x4_0_0=10, R_32x4_0_1=26, + R_32x4_1_0=11, R_32x4_1_1=21, + R_32x4_2_0=13, R_32x4_2_1=27, + R_32x4_3_0=23, R_32x4_3_1= 5, + R_32x4_4_0= 6, R_32x4_4_1=20, + R_32x4_5_0=17, R_32x4_5_1=11, + R_32x4_6_0=25, R_32x4_6_1=10, + R_32x4_7_0=18, R_32x4_7_1=20 + +}; + +typedef struct r123array4x32 threefry4x32_ctr_t; +typedef struct r123array4x32 threefry4x32_key_t; +typedef struct r123array4x32 threefry4x32_ukey_t; +static INLINE threefry4x32_key_t threefry4x32keyinit(threefry4x32_ukey_t uk) { + return uk; +}; +static INLINE threefry4x32_ctr_t threefry4x32_R(unsigned int Nrounds, threefry4x32_ctr_t in , threefry4x32_key_t k); +static INLINE threefry4x32_ctr_t threefry4x32_R(unsigned int Nrounds, threefry4x32_ctr_t in , threefry4x32_key_t k) { + threefry4x32_ctr_t X; + uint32_t ks[4 + 1]; + int i; + ks[4] = 0x1BD11BDA; + for (i = 0; i < 4; i++) { + ks[i] = k.v[i]; + X.v[i] = in .v[i]; + ks[4] ^= k.v[i]; + } + X.v[0] += ks[0]; + X.v[1] += ks[1]; + X.v[2] += ks[2]; + X.v[3] += ks[3]; + if (Nrounds > 0) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 1) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 2) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 3) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 3) { + X.v[0] += ks[1]; + X.v[1] += ks[2]; + X.v[2] += ks[3]; + X.v[3] += ks[4]; + X.v[4 - 1] += 1; + } + if (Nrounds > 4) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 5) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 6) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 7) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 7) { + X.v[0] += ks[2]; + X.v[1] += ks[3]; + X.v[2] += ks[4]; + X.v[3] += ks[0]; + X.v[4 - 1] += 2; + } + if (Nrounds > 8) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 9) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 10) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 11) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 11) { + X.v[0] += ks[3]; + X.v[1] += ks[4]; + X.v[2] += ks[0]; + X.v[3] += ks[1]; + X.v[4 - 1] += 3; + } + if (Nrounds > 12) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 13) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 14) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 15) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 15) { + X.v[0] += ks[4]; + X.v[1] += ks[0]; + X.v[2] += ks[1]; + X.v[3] += ks[2]; + X.v[4 - 1] += 4; + } + if (Nrounds > 16) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 17) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 18) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 19) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 19) { + X.v[0] += ks[0]; + X.v[1] += ks[1]; + X.v[2] += ks[2]; + X.v[3] += ks[3]; + X.v[4 - 1] += 5; + } + if (Nrounds > 20) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 21) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 22) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 23) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 23) { + X.v[0] += ks[1]; + X.v[1] += ks[2]; + X.v[2] += ks[3]; + X.v[3] += ks[4]; + X.v[4 - 1] += 6; + } + if (Nrounds > 24) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 25) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 26) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 27) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 27) { + X.v[0] += ks[2]; + X.v[1] += ks[3]; + X.v[2] += ks[4]; + X.v[3] += ks[0]; + X.v[4 - 1] += 7; + } + if (Nrounds > 28) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 29) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 30) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 31) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 31) { + X.v[0] += ks[3]; + X.v[1] += ks[4]; + X.v[2] += ks[0]; + X.v[3] += ks[1]; + X.v[4 - 1] += 8; + } + if (Nrounds > 32) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 33) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 34) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 35) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 35) { + X.v[0] += ks[4]; + X.v[1] += ks[0]; + X.v[2] += ks[1]; + X.v[3] += ks[2]; + X.v[4 - 1] += 9; + } + if (Nrounds > 36) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 37) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 38) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 39) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 39) { + X.v[0] += ks[0]; + X.v[1] += ks[1]; + X.v[2] += ks[2]; + X.v[3] += ks[3]; + X.v[4 - 1] += 10; + } + if (Nrounds > 40) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 41) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 42) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 43) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 43) { + X.v[0] += ks[1]; + X.v[1] += ks[2]; + X.v[2] += ks[3]; + X.v[3] += ks[4]; + X.v[4 - 1] += 11; + } + if (Nrounds > 44) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 45) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 46) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 47) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 47) { + X.v[0] += ks[2]; + X.v[1] += ks[3]; + X.v[2] += ks[4]; + X.v[3] += ks[0]; + X.v[4 - 1] += 12; + } + if (Nrounds > 48) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 49) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 50) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 51) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 51) { + X.v[0] += ks[3]; + X.v[1] += ks[4]; + X.v[2] += ks[0]; + X.v[3] += ks[1]; + X.v[4 - 1] += 13; + } + if (Nrounds > 52) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 53) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 54) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 55) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 55) { + X.v[0] += ks[4]; + X.v[1] += ks[0]; + X.v[2] += ks[1]; + X.v[3] += ks[2]; + X.v[4 - 1] += 14; + } + if (Nrounds > 56) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 57) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 58) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 59) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 59) { + X.v[0] += ks[0]; + X.v[1] += ks[1]; + X.v[2] += ks[2]; + X.v[3] += ks[3]; + X.v[4 - 1] += 15; + } + if (Nrounds > 60) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 61) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 62) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 63) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 63) { + X.v[0] += ks[1]; + X.v[1] += ks[2]; + X.v[2] += ks[3]; + X.v[3] += ks[4]; + X.v[4 - 1] += 16; + } + if (Nrounds > 64) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_0_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_0_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 65) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_1_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_1_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 66) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_2_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_2_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 67) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_3_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_3_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 67) { + X.v[0] += ks[2]; + X.v[1] += ks[3]; + X.v[2] += ks[4]; + X.v[3] += ks[0]; + X.v[4 - 1] += 17; + } + if (Nrounds > 68) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_4_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_4_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 69) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_5_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_5_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 70) { + X.v[0] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_6_0); + X.v[1] ^= X.v[0]; + X.v[2] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_6_1); + X.v[3] ^= X.v[2]; + } + if (Nrounds > 71) { + X.v[0] += X.v[3]; + X.v[3] = RotL_32(X.v[3], R_32x4_7_0); + X.v[3] ^= X.v[0]; + X.v[2] += X.v[1]; + X.v[1] = RotL_32(X.v[1], R_32x4_7_1); + X.v[1] ^= X.v[2]; + } + if (Nrounds > 71) { + X.v[0] += ks[3]; + X.v[1] += ks[4]; + X.v[2] += ks[0]; + X.v[3] += ks[1]; + X.v[4 - 1] += 18; + } + return X; +} +enum r123_enum_threefry4x32 { + threefry4x32_rounds = 20 +}; +static INLINE threefry4x32_ctr_t threefry4x32(threefry4x32_ctr_t in , threefry4x32_key_t k); +static INLINE threefry4x32_ctr_t threefry4x32(threefry4x32_ctr_t in , threefry4x32_key_t k) { + return threefry4x32_R(threefry4x32_rounds, in , k); +} + + +typedef struct s_threefry32_state { + threefry4x32_key_t *ctr; + threefry4x32_ctr_t *key; + int buffer_pos; + uint32_t buffer[THREEFRY_BUFFER_SIZE]; +} threefry32_state; + +static INLINE uint32_t threefry32_next(threefry32_state *state) { + int i; + threefry4x32_ctr_t ct; + uint32_t out; + if (state->buffer_pos < THREEFRY_BUFFER_SIZE) { + out = state->buffer[state->buffer_pos]; + state->buffer_pos++; + return out; + } + /* generate 4 new uint64_t */ + state->ctr->v[0]++; + /* Handle carry */ + if (state->ctr->v[0] == 0) { + state->ctr->v[1]++; + if (state->ctr->v[1] == 0) { + state->ctr->v[2]++; + if (state->ctr->v[2] == 0) { + state->ctr->v[3]++; + } + } + } + ct = threefry4x32_R(threefry4x32_rounds, *state->ctr, *state->key); + for (i = 0; i < 4; i++) { + state->buffer[i] = ct.v[i]; + } + state->buffer_pos = 1; + return state->buffer[0]; +} + +static INLINE uint64_t threefry32_next64(threefry32_state *state) { + return ((uint64_t)threefry32_next(state) << 32) | threefry32_next(state); +} + +static INLINE uint64_t threefry32_next32(threefry32_state *state) { + return threefry32_next(state); +} + +static INLINE double threefry32_next_double(threefry32_state *state) { + int32_t a = threefry32_next(state) >> 5, b = threefry32_next(state) >> 6; + return (a * 67108864.0 + b) / 9007199254740992.0; +} + +extern void threefry32_jump(threefry32_state *state); + +extern void threefry32_advance(uint32_t *step, threefry32_state *state); diff --git a/_randomgen/core_prng/tests/data/pcg64-testset-1.csv b/_randomgen/core_prng/tests/data/pcg64-testset-1.csv new file mode 100644 index 000000000000..da6d77d40f19 --- /dev/null +++ b/_randomgen/core_prng/tests/data/pcg64-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 0xdeadbeaf +0, 0xb174ddf3fe597da6 +1, 0xfc217240c1e61e6f +2, 0x20279da26fec9cbf +3, 0xa5f4ee34651f4e1e +4, 0xb254d7901c68b9db +5, 0x6bf2a64e4052c36f +6, 0xbec4c7418c0f61b6 +7, 0xb03e595a4ef2b2bd +8, 0xc8e051957ccb74c6 +9, 0xf5082df7473c6f62 +10, 0xb72aa3dc22752a38 +11, 0x7a941561514bd680 +12, 0x90a95f42834f347b +13, 0x88e17b9d59def797 +14, 0x18f19c86bfe60368 +15, 0x667f89277be8d1d8 +16, 0x63305475e7aeff27 +17, 0xd7e4d5c09fb0fb4c +18, 0x7dd6deab03a8c26a +19, 0x42bbcb746e2d4b26 +20, 0xe91f2ac4fa90689c +21, 0x2f83458da0af3125 +22, 0x49a43537a00fae89 +23, 0xef02111d1ebc16eb +24, 0x32b3b3019875f3e7 +25, 0x89eb15c48cd02774 +26, 0xa9f1b37865752731 +27, 0xe0eff9dadc47fb3 +28, 0xae859b1c54cc90c2 +29, 0x7b7c5e04d5015dec +30, 0x38faeff5ce3266ff +31, 0xd2ddd0d19fbc24ee +32, 0xe0d4f692829a31a9 +33, 0x30a6aa3f408e71c2 +34, 0x298362be21de6d44 +35, 0xb7efab759e691149 +36, 0x2ae1f84bba093d4c +37, 0xf6ab55f78f8b9258 +38, 0x2275d0af583cec95 +39, 0x18cfe066b183ac3c +40, 0xcc0a546d54064cf5 +41, 0x5de027ea3c25c225 +42, 0xdaf31ef489fe71e1 +43, 0xa7a2b1a72a4360e7 +44, 0x678a55d7a0506791 +45, 0x36facd8799ad2b78 +46, 0x32fec94506dca70e +47, 0x34e890d8539871f8 +48, 0xec48b5362b0d7818 +49, 0xe2e58921cf8228d3 +50, 0xd163588ec22730a4 +51, 0x17e2322b6be47d25 +52, 0xe1544989a0c6d24f +53, 0xa3a10fb279cdc347 +54, 0xad4ee318a5853900 +55, 0xc96a185feef4a85d +56, 0x82ec5b3aed6636fb +57, 0x2aac2ef8f25426d7 +58, 0xa81e3114165e0d08 +59, 0xc1d8128f83969da5 +60, 0x157505508eaf50f1 +61, 0x77c175067c9c199c +62, 0x973052089bd7af0 +63, 0x3cd70041e32c1921 +64, 0x7783719f13a254a0 +65, 0x2216485ff502d9ff +66, 0x7dae695d2c7f3b79 +67, 0x809ce710156fea36 +68, 0xb90ac31262460e4e +69, 0xc1afe8019306e7d7 +70, 0x6c57638edba4ca0a +71, 0xbe6133f6ab1e9aeb +72, 0x8f5699ff0bcf341d +73, 0x69d0218df036bcbc +74, 0xf0976fd79735d47d +75, 0x82b36a795e5cc74b +76, 0x263c30766b985686 +77, 0xf7426f94511d5ba0 +78, 0x8b04f9573050ed9e +79, 0x7280d4ec202e8359 +80, 0xa8235fbd1324f172 +81, 0x6dbd5d500a809a8c +82, 0x26c53c69292bca1d +83, 0xe348f657b20305ec +84, 0x562f0e2fbb375421 +85, 0xdf2be07bebfbe447 +86, 0x4275044640683760 +87, 0xad5d68bfe4ab4858 +88, 0x3c0e57df5b3306f0 +89, 0xc9d87622ac847565 +90, 0x83d04fd9e102c311 +91, 0x71996b9c65aaf5c0 +92, 0xe3df32742d6fc446 +93, 0x58d3a6573a39d0cb +94, 0x74dfa090e96d289d +95, 0x7856f45e5416c1ea +96, 0x80a18e88b3e4dff8 +97, 0x60565bbcb04f56ac +98, 0x9f4cf5ec45fae3a6 +99, 0x885d2909fe34e3f0 +100, 0x7a1db9118f60dee0 +101, 0xc4c17dc810746c7e +102, 0x8b954b14effe83b1 +103, 0x4f89fb0940999c86 +104, 0xc62e634bceca1c97 +105, 0x7e06e87dffd1619f +106, 0xd1ccbce841371671 +107, 0xe7f99698c66df1b3 +108, 0x5302c2f0e4e1f4e0 +109, 0xa57d11d3d7ee652e +110, 0x8abe0ed0e5508407 +111, 0x6780588af9f6c2ff +112, 0x8603a9fc73b6a4cd +113, 0x169c13a0b7a166b9 +114, 0x868969fb53578598 +115, 0x6089e0eacbe69039 +116, 0xf82482d424397dc2 +117, 0x11475d20896fc890 +118, 0x7983933df29e2aa0 +119, 0x4889c4780cd8e9cc +120, 0x53ebb258f3ea266b +121, 0x121896059b256fd1 +122, 0x2f9934516b2f8090 +123, 0xbabb9fa1d1efa60c +124, 0xfb0b1370ea044797 +125, 0x782ab293b597bc8e +126, 0x297fc0b3977271f5 +127, 0xa573e4d0674d02fc +128, 0xc7e8ddb6efe8a2db +129, 0xaae8a024e62f6e32 +130, 0x3217a47698c9e439 +131, 0xd7015db847a3de0b +132, 0xbc0b4368776e10a7 +133, 0x69d9ef0178679bfb +134, 0x28fd8f0936b66fab +135, 0x45b1c4d4aa9b5aca +136, 0x28feade39cd3ac00 +137, 0xa7e6515c534520f1 +138, 0x735703b5f4bfd54e +139, 0x798271ae0c91b8d8 +140, 0xf858458f9efa8d2 +141, 0x6a41f5845422a9e +142, 0x7fb0bba5f097aab0 +143, 0xbfaea58fe090e745 +144, 0x84770504bfb15b35 +145, 0x67ae11aa368049b8 +146, 0x846c5e493ee15e4a +147, 0xbbcf3baf029f056c +148, 0xd30c23bde142a356 +149, 0x32cd403edb746a8d +150, 0x40161ab00c636730 +151, 0x3a882c3c60d3e19a +152, 0xca8faab24d826529 +153, 0x241a687288551d04 +154, 0xbbc607fb9b48ac00 +155, 0xa844329d0c2d475a +156, 0x8fa4aa1d7296b9e4 +157, 0x82c7dc1f588ce2fc +158, 0xcbdaa663041e078c +159, 0xec108d219b2b147a +160, 0xcab01864270b334 +161, 0x6d3d08545041621b +162, 0x2aae054b8e5648f +163, 0x1bf5a72fa70e7eab +164, 0x2dddb2050af45a3a +165, 0x2b910b7078021a75 +166, 0xf7160201ede45f4e +167, 0xfaf75ae996f079bb +168, 0x407984a9451e659c +169, 0xbdf9c0a9ea078ac0 +170, 0x1e7717b8345acbb6 +171, 0x25cc2df4c0c8dc4a +172, 0xfda1715b573850db +173, 0x50e5cedad99e2651 +174, 0x9a67673ed73cfc0 +175, 0x802ec4fc9e946805 +176, 0x677cd320e641999f +177, 0xbfeb1b6053fe4f78 +178, 0x220cfc90bd31541 +179, 0xe4fdfae10ae6c86f +180, 0x76c568fd869af80d +181, 0xd17dc57109200bb1 +182, 0xeb96ba01c95382be +183, 0x6a9c7ebea5b5f7ac +184, 0xc1680450532fb8cd +185, 0x26b0829f68888094 +186, 0x98335aa1612d7c70 +187, 0xad8662125bf32ae3 +188, 0x15f18a9025ae26e8 +189, 0x5d065dba0d17c9fc +190, 0xf68e1d59f10ff109 +191, 0xcfbd97901a79f8b0 +192, 0x3e72a9fd1d95f143 +193, 0xe7ee82c1bb740dfd +194, 0x3a0f4ae5db22527b +195, 0xf4d025080ed4ea92 +196, 0x6924a99549b4657 +197, 0xcb83b51552208e2f +198, 0x9f306634214b44e9 +199, 0x4fb3307b0e1a7535 +200, 0x73d202d4225c5394 +201, 0xd5a2fa42f8cc8c5c +202, 0x7b3b3e3f7b948d3c +203, 0xa2dbc4d30d8c148e +204, 0xd1bfc1f05a8f2c5d +205, 0x2b00a4efa2f19262 +206, 0x9d4a05bb18647f48 +207, 0xff21fbaf0b46d13f +208, 0x126f9c5f2132af20 +209, 0xd4b7629b0d9a6b89 +210, 0x2d61949fb3126ecc +211, 0x30d61648763db1ce +212, 0x9c5234d15120bf17 +213, 0x2eb0eccb6cc14c8a +214, 0xcf18eff5ca2af8a4 +215, 0xab5fe599ea68c377 +216, 0xe47a0bb8436af89 +217, 0xd3728a566187c400 +218, 0xb8b54592b62f633e +219, 0xe02b958f9c13a180 +220, 0x9e5f5cc85283f24a +221, 0xbd1ab869878744a +222, 0xb93fd6297a29c8dc +223, 0xf22f06ee61dc2413 +224, 0xc93fe440766cbd8e +225, 0x7459d9b19375a51c +226, 0xd4ec87c57baa4127 +227, 0x1514d0226dc0409e +228, 0xc6b0d7e1bd56b190 +229, 0xc0c61c73c9dbffee +230, 0x2f1154afb48a93e2 +231, 0xd2ca05901bae0117 +232, 0x6263f647273694a0 +233, 0x94a98bf80488205b +234, 0xcb0d63747735bead +235, 0x9cbd4e1659932c5b +236, 0x1807e01931b5ade0 +237, 0x1d9f7721d3067854 +238, 0xb25dbde4ec77e547 +239, 0x4b186592a39adcd6 +240, 0xe8ad5514de72a98f +241, 0x2deac1cb096a09b4 +242, 0x6952f4b82a2c87 +243, 0xaa1590223ed83ffe +244, 0x9baf13d08f572e12 +245, 0x83ec1bca1e724d88 +246, 0x5c61bf2222b4907 +247, 0xd950ff64ad7b956e +248, 0x36bf5e992bf1f211 +249, 0x75ad67249d7a6c35 +250, 0xeb12dcef5c2bfe7d +251, 0xc508da925157e39d +252, 0x91cbd7491ea7f70e +253, 0xf10c018ec0b0e55 +254, 0xeeffb21fef1e87f1 +255, 0xe31692b834d067dd +256, 0xd69bbafdeb5c0d15 +257, 0x41358dadb9260eb1 +258, 0x5fa3c67d353cd6b2 +259, 0xdbb743cac20b2eda +260, 0xe7877ba98b2bfe4 +261, 0xf14d679436fd2dcf +262, 0xa313e39059d62afe +263, 0x7eaa134c761a6183 +264, 0x7719af9ad1fecaec +265, 0x533f921a4702d433 +266, 0xe072f9665ec3a3c8 +267, 0xba89560ab4ba08fa +268, 0xe94f0aa266e56d53 +269, 0x774b84bcb152afc +270, 0x787c9517e589748d +271, 0x3831a5303adfd362 +272, 0x19cb20184a4264f8 +273, 0x9bc5e99e1773700e +274, 0xed323bf38642f651 +275, 0x860868c0eba789f2 +276, 0x8c1602ffd9a5621a +277, 0xe298d8fc74e146ce +278, 0x3181a2083c76037f +279, 0x27942fd6842079c0 +280, 0x38fe8c0406516df +281, 0xd211a4a42857bec3 +282, 0x56002508b351879d +283, 0x2472ed93614c7e99 +284, 0xbcafdaadc0f77b7c +285, 0x86becbd3e5303107 +286, 0x930251d84de72320 +287, 0xea79aa2964954052 +288, 0x6dbc5e63b50b1724 +289, 0xb098535ed4bc7372 +290, 0x6490d6d8541fb656 +291, 0xc738f6ccb4b7076b +292, 0xd69ee4fd6ce63026 +293, 0xfa98e9d78a628338 +294, 0x9c30b63a70d607b6 +295, 0x8d544b5d224a25d9 +296, 0xa051f7fe38445228 +297, 0xf6931861338a00f5 +298, 0xecd71cd64b0b5dcd +299, 0xdbc818e7126193b +300, 0x3aaaa032aad8199a +301, 0x6fd68a3818e0c439 +302, 0xc82a651ba9ede8c9 +303, 0xe6d958e267017187 +304, 0x73a9eab64de651ae +305, 0x5a6757f7f222bb3c +306, 0xe62e7cca6bd17a32 +307, 0xc4f6c31f528dd387 +308, 0xdecd8b663c995773 +309, 0x69a21dedcbfef9c7 +310, 0xb33f8ac00f17b6b2 +311, 0xe32b3c962d613ba3 +312, 0xa9c317d026600d41 +313, 0x901d971c49671213 +314, 0x46c3f3d35db8808b +315, 0x1336297232af9791 +316, 0xed88d9242e11edb3 +317, 0xc70c48843f54af0 +318, 0x611062a0461deedf +319, 0x7e3183514f127f20 +320, 0x7b549d10bace1c47 +321, 0x6db523d19d0a7af3 +322, 0xf6e677e5222a21a4 +323, 0x28e5188ba7055c32 +324, 0xbe7b41d2ce539c4f +325, 0x5c085a18c3b7bbe0 +326, 0x209cf345b3c3b06c +327, 0x79ca5407dd486857 +328, 0x8e07ac4c65338ccd +329, 0x56dd5372249cadad +330, 0x27e0b07863fa27ff +331, 0x78dec95d299a8699 +332, 0xbd5d71253b73d456 +333, 0xbf83b6cedd205e9 +334, 0xee2352ee69aa68e +335, 0x4b14f253d684cfbc +336, 0x12ffa5d5f8a34bec +337, 0x2e38346fbc793f67 +338, 0x2ab5862872b4850b +339, 0xcbc8aec1e2bb6760 +340, 0xd79ef783845cc329 +341, 0xdbdcde91e1685704 +342, 0x29880643aa1095e4 +343, 0xcd5ccc1fe9a616af +344, 0xc7b6cdc4a43c132c +345, 0x7b08597fdec7fc9c +346, 0xa01ab3827e120a16 +347, 0x89ce37de99ca7748 +348, 0xb4644823ea6b90d5 +349, 0xdbe189861c409209 +350, 0xbfeb614759981b60 +351, 0x48c2c3a6d2419755 +352, 0x1aa1df0e99b3417e +353, 0xb9f061bf98c0da28 +354, 0x8bce2755a0b5b8ae +355, 0xc9bb2ff33d60b3e7 +356, 0x6abcbb1ea0d3a575 +357, 0x983a3c16a0e5d6f8 +358, 0xa122e616797ccdbe +359, 0x751dfe60252a01d0 +360, 0x8d1bcbbde84f6a11 +361, 0xb6bc4f2942ba0e57 +362, 0xb298977a4bb20e12 +363, 0xcf658188dd931722 +364, 0x39735757b19c90a3 +365, 0xc2fcf1df99f1b7c4 +366, 0xd42c50f6a912aaea +367, 0x95d0cb8a953965c4 +368, 0x75c7d03289269f25 +369, 0xd8d96184031fb36b +370, 0xb3b34b5ba8bac75 +371, 0xcfbf16d241e46f8c +372, 0xec465e59019b6f6f +373, 0x4051ce0bc2562a63 +374, 0x859f05ce7b75da05 +375, 0xf2661ef2e3c733ef +376, 0x8067f432dd5af0c4 +377, 0x6e8542a346911713 +378, 0xfcda2ac6aa45ca20 +379, 0x571f23fdacb25fe2 +380, 0x2546f5badf7adb8b +381, 0x929ebe6fbd330e2b +382, 0x9d41d6ded9facbeb +383, 0x4cf9d9da6c125106 +384, 0x495d5708443faa36 +385, 0xb0023a41a6057e59 +386, 0x37fa1cd9ce66b20a +387, 0x96a376fca4aff5a8 +388, 0xc22469c4a3e1ea85 +389, 0x5ab79b721966249b +390, 0x2124be452f7d4ca4 +391, 0xe71bb882b954ca11 +392, 0x322bdcaf9c7b0efa +393, 0x4c99c8753878439f +394, 0x3ffd6caec9f9ac49 +395, 0xfba842dd40a3c72e +396, 0xfd93517d31681d77 +397, 0x44c139a74249a128 +398, 0x828a145610684c8 +399, 0xb53696f802522b6 +400, 0xa2da2199474d079a +401, 0x739e508fbbdeb714 +402, 0xe75c4734a7c95f94 +403, 0x5c22c226f2bd8487 +404, 0x7108fa6b99b0d72e +405, 0x3c60b40f6e4bebde +406, 0x395150555d56dd18 +407, 0x13246a6e4d795fe3 +408, 0x27dca990fb678027 +409, 0xc5a92c32724a7373 +410, 0x30fed89f4171a817 +411, 0xf7f7810edea2e7eb +412, 0x46e930eef5351212 +413, 0xe1331cd8a678dc66 +414, 0xd4cc0a5f96a72457 +415, 0x2559f8d286b1da16 +416, 0x73831b2f6e4a4ba +417, 0xd929ccf267504761 +418, 0x8a7a1b357f8bbc38 +419, 0xd5e0d3e200d0d633 +420, 0xc2cc05cc3ac5abb +421, 0x75b8f78a06ca465b +422, 0xeaf1d6aa9c0baef3 +423, 0xa6c9bc3dbe45e62e +424, 0xb1496074b4c338d7 +425, 0xc18ebb892108cec +426, 0xf6cbbf4cd0f8f9ba +427, 0xd73759407ecbdcf6 +428, 0x54dc0805c85a3b0c +429, 0x4ba3936d6be048f3 +430, 0xa3fbea19803cf35 +431, 0x78b1d3a837d4bed +432, 0x6ed09ac2c177453b +433, 0x16134c4e8b30f6ba +434, 0x94718ce4868f01a3 +435, 0x612fa336da82e66d +436, 0x5d8833c9483b235d +437, 0xf5c72d4883bed9a2 +438, 0x2a6e27d1ed337134 +439, 0xfba250d6b9cc0d2b +440, 0x432f8734b61e4366 +441, 0x45e8becd5ccb4f32 +442, 0xffc7d68cb343170a +443, 0x247cb9a6b29b1a35 +444, 0x89876df3681dc65 +445, 0xd1e646c49aac769b +446, 0x4c3cd721635602d0 +447, 0x5139344709c749fc +448, 0xc5130d981e1a6b14 +449, 0xff269bea082608cb +450, 0xf45a5d57a6d4c6a6 +451, 0xc4c9f3e5398db827 +452, 0x2b3a0eacd42665b4 +453, 0x94d847d848a8e65d +454, 0x1a8aff186e1d75d2 +455, 0x6ad986366c54a242 +456, 0xbd832c0607523e7e +457, 0x973064c20c31842d +458, 0x34d0513e6d602f80 +459, 0x91b3c812f83392ed +460, 0x4c49ba38b6a4cf90 +461, 0x82e3370e1c5ad5d4 +462, 0xa29a01fa53250a13 +463, 0xbe8ed1e615a1ee6a +464, 0x17fb15941a9fe6b4 +465, 0x84aea1c0138fb970 +466, 0xab065efb4558003d +467, 0x3345b340257a2551 +468, 0xfd2ebda1048c0dcd +469, 0x2aa72fce0cb23982 +470, 0x9952f9363830ff6d +471, 0xdb240e279cb7f901 +472, 0xb4a1e7b54206aca4 +473, 0xe13bdbb980623f25 +474, 0xd989f009368f8a9a +475, 0x7084b7695149660d +476, 0x55b92a3f139c7f1 +477, 0xdb43c75c633debd0 +478, 0x94e362574c70b9a8 +479, 0x218a1a06d9223f9b +480, 0x82f3c3808f86bb95 +481, 0x63e9de6cee4b77b2 +482, 0x3bc5effa36bb166 +483, 0x8369cbe5fa0ecab +484, 0x2a5808b4d7bc8572 +485, 0x6856e29700de99f5 +486, 0x107e86fcfd4a48d9 +487, 0x15c9ee6528c1c223 +488, 0xbf7318d4206c5e75 +489, 0x15d7a6aa9343c9e8 +490, 0x93419fe0ee3bd5df +491, 0x916c7f75ededdd53 +492, 0xe89d6230690f74f1 +493, 0xf92f96834e0eb27 +494, 0xed5adc06c305adc9 +495, 0xf656fe40e7ecb4d7 +496, 0x32a2d3eda46114b6 +497, 0xb3f17867d23c75e2 +498, 0x2a2cc838c4d89c33 +499, 0x413df7052f8866e7 +500, 0x373bd93e91bbed18 +501, 0x78c8e5aa1e1e2dda +502, 0x6bd362f6be6d572b +503, 0xba1926efd387aeb5 +504, 0x3b826b77ae3e53fd +505, 0x383cf5a66fb6723c +506, 0xf5a4e1dded64d931 +507, 0x76d9843a304729d3 +508, 0x205b8753b6d309f0 +509, 0xd2a68ef67d8e7758 +510, 0x60d517f325411c0c +511, 0x37a3bb4950cf08d5 +512, 0xea3d4f95542ffe2d +513, 0xa88708db07fb1d34 +514, 0xd96555e1194f7ee0 +515, 0xdd046e642b59fa51 +516, 0x18ff34e73582d46b +517, 0x7ed73af03535c5fe +518, 0x8ffd64801d2c5187 +519, 0x7134902903c9cfe2 +520, 0x74fa0b238ad1e1ec +521, 0xa220ff0032395fd5 +522, 0x4ed0a7a2d9c3a064 +523, 0xb02cb878b4c9a04d +524, 0x8437cebea5ae2bec +525, 0xabcc162a0027aefa +526, 0xc8e86ab8f5c09011 +527, 0xc28dfaf764ec07d4 +528, 0xb19127d64ae5db18 +529, 0x857cb1b00ac7fbc7 +530, 0x173a441c4b494aad +531, 0x255af1a4d50952c3 +532, 0x87ff01c7d0139add +533, 0x489b15e4c97cfcde +534, 0xd4abbccecfb67239 +535, 0xa1a2912ad34ac4fb +536, 0x94b7f12e10bf720 +537, 0xdb8840c295333634 +538, 0x5a29aab5b359f2c0 +539, 0x630352d282b695bd +540, 0x399f00854d3fbdf3 +541, 0x19e917e0eb8bf070 +542, 0xa464b4dc93d1fe7d +543, 0xf152d3cdecbd7647 +544, 0x517907b570a6b082 +545, 0xfeb06f4bd978e7bc +546, 0xa22859ad14c0f183 +547, 0x33c11e90be9721e3 +548, 0x8394f642b5a40d7d +549, 0x9525633e7e60ab73 +550, 0xf97401c9b4b96001 +551, 0x3d78ce1ecf900029 +552, 0xa85791d9754a2765 +553, 0x16e77aadd9a30946 +554, 0xc91d4defe72f39f2 +555, 0x2fb67bd91edc4b51 +556, 0x95d635e95b468fa7 +557, 0x28b81869d1739e29 +558, 0x5b098fa22cb1747f +559, 0x6544b8704bd2400a +560, 0x91a64f9ec6e93245 +561, 0x2b46ba92268db263 +562, 0xbb52d7758efd5416 +563, 0x7032adc08e6d39da +564, 0xe9d3bbefdb61feb6 +565, 0x2d603389c757996b +566, 0x5871ed32ce17d042 +567, 0x31d622a6b8438f70 +568, 0xc71af17db6bf7aed +569, 0xe419e3c6fbe86530 +570, 0x648471d670f18dcd +571, 0xd13f9e25078599ed +572, 0xdaf86e56826d07a3 +573, 0x3c9374e4420a8580 +574, 0xcd75b12ad6d8d9fe +575, 0x2d4530f6e2b93ca3 +576, 0x303bb663ad4ca963 +577, 0xf8caecede4436b61 +578, 0x315a8124669a907f +579, 0x1c18d130a4b93836 +580, 0x9e0b83663631562a +581, 0x400059c1ce071c7f +582, 0xb27f7f67e7cbd970 +583, 0x6b446e8c4866f3d0 +584, 0x4ab1755d2734121c +585, 0xb9fc8e017d89edf2 +586, 0x3a9aa7f50355c0c9 +587, 0x899fece06a169b2e +588, 0x19d7d7088db0b27d +589, 0xe4f8862ca8f6b87e +590, 0xceaf0d6ab4ba624d +591, 0x318965c56f79886d +592, 0xb1840d9bb60b720e +593, 0x387427e7549150ca +594, 0x9be3edb621a5d2ef +595, 0x9758993cca6a481 +596, 0x3733c5cd48a1590c +597, 0x9bbe26951c666fb1 +598, 0x74c7e89fefb4ba59 +599, 0x6aa490a23907053f +600, 0xa62febef1e8d7300 +601, 0xdbfb07bbba2fd4cd +602, 0x11ee9e4bbd4f358 +603, 0x6b40912657c7f02f +604, 0x8d56c1a9216714bb +605, 0x7fcd86985949c2f9 +606, 0x706bb172d5677f2c +607, 0xfb657efea1331957 +608, 0x6e3032f72a3fe367 +609, 0x509fb8c5b618a18e +610, 0x3599e957259222e7 +611, 0xaafc78bea53c9102 +612, 0x404addaf7ac55279 +613, 0x97db28b3b0a2dddc +614, 0xd3f5b151a9f5aefb +615, 0x1a6534a9be80a19a +616, 0x78f989eb80e055b7 +617, 0xe0200fe015112dce +618, 0xfbe67decef6204dd +619, 0x662fef92c8e00970 +620, 0x9a7838962250f5d7 +621, 0xac0eabb1621567b3 +622, 0x1874cf715cdc5daa +623, 0xd3281a25a82ceecc +624, 0xd8ac0e497b11156c +625, 0x3c8bf98f8210af89 +626, 0x971973ff9d428a3f +627, 0x1af47276bc157e63 +628, 0x671cd5e661ed0a05 +629, 0x71b8ffba9b976a0 +630, 0x8763f1fa85c5f5d5 +631, 0x61f3c56f3441aad4 +632, 0x86482f5e90362e3c +633, 0x8e9d9aceba401c48 +634, 0x51d916579d19d42b +635, 0x67bdfa28310ad3c7 +636, 0xb9ab819d6a00add8 +637, 0xaa12cb0ed2d507bf +638, 0xc636190dfc7f6d43 +639, 0xf3f1e6c104c5e782 +640, 0xaed0be2f07ad4313 +641, 0x1d782d74661278bf +642, 0x58e6501bc7e61fa2 +643, 0x8ca4ad0e02d7fb42 +644, 0x8afc9e9fe83d4b78 +645, 0x72cb69cf4abf0b1d +646, 0x7601a7b3500d474d +647, 0x97fee7da53b533b0 +648, 0xd6ab646f53c0e19a +649, 0x6480f60992f2fcc0 +650, 0x64ec7590c60a4c00 +651, 0x3ccab37f11acbe91 +652, 0x9ddd546f201299fd +653, 0x9a0dc59d0b545d96 +654, 0x8c5f366bd21664f5 +655, 0xc0af97b445bfc5ee +656, 0x29762536dc00c3fc +657, 0xfc30927fd8f1c257 +658, 0xac9aadfced7d59fb +659, 0x8d039f87658a29cd +660, 0x13a3d73580eacf6f +661, 0x80b80e0adcc11ac5 +662, 0x1e53c21e639f9d08 +663, 0x8a73352dc442bca7 +664, 0xec7cb2fe0e6b0100 +665, 0xfa5e63f403ac3f33 +666, 0x493d9a0018185f8c +667, 0x1b1d1f41c6cf5cb4 +668, 0x95b4caca3e2500a7 +669, 0x4e759e6f89f62f91 +670, 0xd0a76a3198d7c05f +671, 0x86eee6259cab63b5 +672, 0x1daab21067011b59 +673, 0xd02d9236ebc91b38 +674, 0x693e17ac2b70e1b7 +675, 0xceb5899aa14d0f86 +676, 0x59ffc317faf17ab2 +677, 0xce94f02892a0fa30 +678, 0xf7c9d6f9e753737c +679, 0x87258cf7ff6a29b5 +680, 0xb39fc8ea8aa52a0e +681, 0xadd4b4e73af1103f +682, 0x511f423730b25a4e +683, 0x7f673288e53502b2 +684, 0x9aa499e3b6295919 +685, 0x83841ad95e6a7a6 +686, 0x6e549a2457a850c +687, 0x4763220b923113c3 +688, 0x99737bb550aa5049 +689, 0x89eb31b3f707c4 +690, 0xdad5331dda8a58d3 +691, 0x5f1681518d5a21b8 +692, 0x258a0b9b24110918 +693, 0x8854bb025009fa21 +694, 0x7ac331fd885642af +695, 0xe520f0e9bedf0bf6 +696, 0xc9419e8801aa2afb +697, 0x356fdc0fc3702b37 +698, 0x6d6a25f39fbc9524 +699, 0x930f65c4dbf8ae94 +700, 0xa73d7bbf8c19c4b3 +701, 0xe473f700513139fa +702, 0xfef8f0e84c521bae +703, 0x88525351995576a7 +704, 0xa156b646ab95f272 +705, 0x1a46ff3b9ae7e723 +706, 0xf6d82b8bd9f2a80 +707, 0x837b8127d8f39ebf +708, 0x1f8e120ea11fc9bb +709, 0xbd0918421430f8c9 +710, 0x4ef121a688d130c7 +711, 0x3fef66f1cf180b77 +712, 0xa92070bdc6a0100 +713, 0x2444dcbb4853c174 +714, 0xe46b7d6234504df8 +715, 0xe5ac8fd968a5d1fd +716, 0x988828d885f04f30 +717, 0x9730c37b69f3d963 +718, 0xdb9a0d16bf0a2aab +719, 0xe75d00b3681941b9 +720, 0x518421d62db82da0 +721, 0x4da04c94268c1dae +722, 0xdcf2635a55b7da9e +723, 0xb679d8206c55a04c +724, 0x1fbf58865fec1e83 +725, 0x53ca7cc07c0e5785 +726, 0xd18eee3f5b57c813 +727, 0x9fc8d328e41d1299 +728, 0xb2231521e026e15 +729, 0x1a7e2a8df269acde +730, 0xe5f547b160b0a6de +731, 0xab01e7130bd70c14 +732, 0x82a051680f661a75 +733, 0x479da77dd9686ca2 +734, 0x1417cc197738b272 +735, 0xb65b5ced585a8186 +736, 0x40b5a74813e7a05b +737, 0x55481e0f404fc2c5 +738, 0xef1ca09a2640c44a +739, 0xa0f1d37ee2db47cf +740, 0xcabb0c8e551f0587 +741, 0x84227dd83ad941ef +742, 0x7b47691b6e8327d +743, 0x4fe615394f53d6d2 +744, 0x60bca7e568f65c80 +745, 0x8676b74f2d5600f4 +746, 0x70f256171f1eb9b1 +747, 0x6b1d25099f80e1fd +748, 0xd8e77e8a67ff3338 +749, 0x3ec375feb7727aca +750, 0x26b9ad4afd4be26b +751, 0x849e6f9bc5ec636 +752, 0xa34e3fad187c089f +753, 0xe369ba87f04ecc37 +754, 0x83c6e1c3985cab4e +755, 0x6ffc032379a15336 +756, 0x654645504b159afc +757, 0xabc97562087edfad +758, 0x4633765a9f068fe5 +759, 0xa226c586394d348b +760, 0x7034d9fd40133a22 +761, 0x89e1d142a1a20097 +762, 0x7a3e1387a5ecdf70 +763, 0xf0ae75084f0a1bc4 +764, 0xdcf97778ae782977 +765, 0x87996a44dbac128d +766, 0x94b102ac15479072 +767, 0x9d670a01e10c48a0 +768, 0x8f977a03176d0cb1 +769, 0x8522bdbed25653c +770, 0x8f2b64a9cd6b5483 +771, 0x86b2beaa71c92fbc +772, 0x40f896707639f820 +773, 0x40e7df1535fc03ad +774, 0x1d34c491e13debde +775, 0x862d5ad393292476 +776, 0xd33ee4efdd4b14d9 +777, 0x63ce5c7643b85ecd +778, 0xd28a7fe0700fd15 +779, 0x8c3536390f9b7b55 +780, 0xfaf87a9036dd0265 +781, 0x187e261c23b454a5 +782, 0x95362150f08e5f86 +783, 0x6588c21939d9521d +784, 0xc7cee242280b7526 +785, 0xc1b8f83462038485 +786, 0x68c2f342724de8d6 +787, 0x35c283dbca3c62fd +788, 0x556c441e9fdc5cee +789, 0x898ba42c4ad3f5ba +790, 0xc654a072fe9ce540 +791, 0xcc2da7cabdc658d4 +792, 0x518b6badf9c1ba7 +793, 0xd43b259427de48cd +794, 0xfe7e74d4415bea8a +795, 0xdee4cacb454d92c +796, 0xdfb09dde6d6c3000 +797, 0x5c0d4ce2c7a8d426 +798, 0x29ccf2d288f4de4a +799, 0x4106e7f40d2597ad +800, 0x3bc376950bccf69 +801, 0x65b74e149d1066e3 +802, 0x751d008e4f823e5e +803, 0x4a3b9a34d8ece205 +804, 0x372e79ed6d9461fc +805, 0x78e08cab6244f8d2 +806, 0x7d273315b6d9250b +807, 0x26c401cb05f556b2 +808, 0x3324d95fbc93408d +809, 0x14fb55fb83ab0a8a +810, 0x7ea7efcddd0a747f +811, 0x150a110bd5cb1b57 +812, 0x1122b31f5d20ad23 +813, 0xbd996a43507da1 +814, 0x6d11fad057e5a75a +815, 0x22a4d3223d77684b +816, 0x349973b5dda3d3e8 +817, 0xe4dab5aec267e32d +818, 0x371cbd61bbb7858c +819, 0x7e49182abfc0fc68 +820, 0x937722b126a7d173 +821, 0x29604490ccbe6611 +822, 0x6c8b230bdcc8dfaa +823, 0xb1c267c94d4550ee +824, 0x80d1fa6e33cde91f +825, 0xe205a132f35af0a7 +826, 0xe4e8e50899fea5c8 +827, 0x3a6517d09206dfef +828, 0xeff4e4f8efd0a4ba +829, 0xd8df88c992b3df74 +830, 0x5b0df3c40071c0ac +831, 0xd44a062781f833f0 +832, 0xef35653edcb68251 +833, 0x21f879df2bd3cfe0 +834, 0xdb5e837565891932 +835, 0x6da15316efae41e7 +836, 0xd33cdc0d05f8dd6d +837, 0x3c6588502a24be1c +838, 0x3d25da26bee94818 +839, 0x79979979960d383d +840, 0x8a20663424f816ec +841, 0x74c587d5824ee15 +842, 0x145f90c6b342c489 +843, 0xe2c2d15b8de95387 +844, 0xd9deaecc24e84ede +845, 0xce52add2f5c3ea3 +846, 0xd1da2db8cca0014d +847, 0xcbeed544f8791232 +848, 0xb55b421de003edf0 +849, 0xde102a5a87a9a5da +850, 0xd74fc9d34c964bd3 +851, 0xda7e1e271d197070 +852, 0x1167b33a6bad0d13 +853, 0xd35c886fd0e28798 +854, 0xfb3334085bbcef67 +855, 0x88f4957ddc912f99 +856, 0x7c1b0e356835cffa +857, 0x8c737bc009bf5a1c +858, 0x44edc242bfd88b0f +859, 0x391f8b5db15f8b01 +860, 0xd44794c8a4245701 +861, 0xefa90e38ba4a2f6e +862, 0x597f65c886e697b4 +863, 0x28972f6be3ca8677 +864, 0x18a487b5e89a9dbb +865, 0xffb15ebcb8a15fb1 +866, 0xa1f64108b7feeab0 +867, 0x36fc88b440612004 +868, 0x72a723294ba9af87 +869, 0x1a38da0ff8f187d7 +870, 0x529d7f6cd18f664a +871, 0x6a5941953b4732c7 +872, 0xe91243bd8fb27a03 +873, 0xb80c55de03262828 +874, 0xacb9183e5b28a8d0 +875, 0x4c4ca12eb3d5d2e5 +876, 0x758635a20eb18211 +877, 0x211e03e90d6bd001 +878, 0xe36e20fbf0f271b5 +879, 0x4daecb676fc64ebd +880, 0x8f1e82c4dd582eb7 +881, 0x6e3c35a21bca1b8f +882, 0xf3c2a69420f159e8 +883, 0x2cda4d630caba89f +884, 0x4c93f3f96360d308 +885, 0x4192046fb5e9d801 +886, 0x349f2b172f49599c +887, 0x7bbff8dd8b480e6c +888, 0x83b33fafc4388bf +889, 0x9a5440f806d9d1b +890, 0x8d6b62101dcfe51f +891, 0xbc7dd6987af227ca +892, 0x4338e67e0d6ba6a0 +893, 0x4a23deabbb5fc3ce +894, 0x9f8edc91e6356eb8 +895, 0xf6b723dd2dd5f80b +896, 0x35c558dd3443021d +897, 0xa559dd33c2cf594d +898, 0xa50ceeced7a82783 +899, 0x21107b581db4ee9f +900, 0x13e8dd9302e8c97d +901, 0xbd8491f437e57ad6 +902, 0x72f4c2a57c06f35f +903, 0x518fbb95071d8d7d +904, 0xcdbbe8d47f9b13e9 +905, 0xe8152b0f387251cd +906, 0x411070a4f345676 +907, 0xc589c285b962389 +908, 0x8b0eb9e285844319 +909, 0xe2b007f446a21b38 +910, 0x868ffafb958a6c40 +911, 0x19ccccd559408de0 +912, 0xa7666f366db0ae71 +913, 0xd78c5f137da6dbc2 +914, 0xeeecc913fdb9af03 +915, 0x7a5afb2f3d54a396 +916, 0x64fadf73d7ba200b +917, 0xaa1b82c6b4b346aa +918, 0x9a312d9482244a60 +919, 0xadb3c0a30f68d0f4 +920, 0x21eee75a717008c1 +921, 0xcda2779023f54837 +922, 0xea3c577c6d7783e2 +923, 0xdaae89efcd431a13 +924, 0x9a6102d2dafaded8 +925, 0xd29443448e01734e +926, 0x6b968e58c3d5bcd0 +927, 0x13949d0c5c0f9d19 +928, 0x7053eef909932489 +929, 0x49fb97e33c279171 +930, 0xc955e4854e254d03 +931, 0x3300cb752a7834fd +932, 0x8319585b09da0928 +933, 0xd35c64e4ce23a294 +934, 0x9a41d980ba1774dd +935, 0xff570729be1f3f02 +936, 0x3f68ae1c3e690a41 +937, 0x6f58a3e861159e42 +938, 0x111d9975e94f0004 +939, 0x276d3ea0ff1ca6c +940, 0x4209cb1f5ca1c594 +941, 0x71699dc4c58f1bcf +942, 0xe0288bffc5a27a2e +943, 0x6c0962c36163c4f5 +944, 0x3a8ad088b4fd204f +945, 0xb945dc7721092d36 +946, 0x315f4c1738bdf365 +947, 0xe07ddd7121cafb70 +948, 0x626fadaee66f331e +949, 0x6fe3f71dd5e7ebe1 +950, 0xe3cfb6b53bd8713c +951, 0x30f5b732f7070968 +952, 0xce2f941f93b957f2 +953, 0x116897bad7f55bca +954, 0xb9d2c4a98826c3ff +955, 0x9672c28485d1c95c +956, 0xd0656535c3df1e44 +957, 0x15294f18a999528d +958, 0x82a98977ad1e933a +959, 0xddd17b6eeced5f84 +960, 0x9901a04270fa2d5c +961, 0xcd2a8d3ab69a0c62 +962, 0x706bf86127a4597b +963, 0xe614aa96ed708afb +964, 0x7f6361ae8f59987 +965, 0x6a355657b59c4874 +966, 0x5211dca87f30cdd +967, 0xa21cbbc602f58ee4 +968, 0x68dff176c9b02a7b +969, 0x68f89bb7bca83c5a +970, 0x229cb884febc7e56 +971, 0xce4f300cf6b70884 +972, 0x6ad3f343c76c5e0c +973, 0xb059a099f121222e +974, 0x9e990641d81a63b8 +975, 0x5564e79afe160ecb +976, 0x2a9fa9c590511dcb +977, 0xca36751ba40931da +978, 0x23a332a9fe1104aa +979, 0xdfe116c321547662 +980, 0xf484bfbe18f2c1cf +981, 0xf8f2b4adf2d1ad4 +982, 0x4308800511929ba +983, 0xe2773c41e0082a51 +984, 0x6b74adc21bac6b3a +985, 0x1faa6a3704bd1b66 +986, 0x89e3e641298e87cd +987, 0xcb2f118548abcdc3 +988, 0x690e34dfb4153ab9 +989, 0x103d668edb5f7e88 +990, 0xb29d9f22b3b1d4a4 +991, 0xc4ce3be9022b314d +992, 0x1cb3d5af1306da15 +993, 0x8236da372d964cce +994, 0x79188ac299f06c2b +995, 0x953dfd978aad2545 +996, 0x6058e1066e7285cd +997, 0xf47307b50589e391 +998, 0x2923873ecd9c4d32 +999, 0x4c44d61328ac5e4a diff --git a/_randomgen/core_prng/tests/data/pcg64-testset-2.csv b/_randomgen/core_prng/tests/data/pcg64-testset-2.csv new file mode 100644 index 000000000000..779761d0f8a7 --- /dev/null +++ b/_randomgen/core_prng/tests/data/pcg64-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 0x0 +0, 0xd4feb4e5a4bcfe09 +1, 0xe85a7fe071b026e6 +2, 0x3a5b9037fe928c11 +3, 0x7b044380d100f216 +4, 0x1c7850a6b6d83e6a +5, 0x240b82fcc04f0926 +6, 0x7e43df85bf9fba26 +7, 0x43adf3380b1fe129 +8, 0x3f0fb307287219c +9, 0x781f4b84f42a2df +10, 0x36dac886f4232c6f +11, 0xa32006a96a8d46b +12, 0xa56e609a788ce098 +13, 0x75711678fa371144 +14, 0xbcdd4619fa063896 +15, 0x5cb5c9a1594f1a04 +16, 0x799e6cc7d09bf3fd +17, 0xda1a4b52f72a8c6f +18, 0x374b6f698c864e48 +19, 0x96a3e4d45b8d252d +20, 0x5fc89e7cbf7735e4 +21, 0xe0cfe37beef7efe6 +22, 0xc3467c95f4649808 +23, 0x95cbda6a3275f18a +24, 0x3a4dc1e59bdb4172 +25, 0x47f8755023ac78b5 +26, 0xef8e166bf07dfa95 +27, 0x40065cf0fa99882d +28, 0xbaa083ad70102eb6 +29, 0x7c88e9d1a72a8dc +30, 0x1484e44aa83e901e +31, 0xf0f8df78086fdeba +32, 0x5114e38e0cff505d +33, 0x7e04bb9a2828c944 +34, 0xb88c0de9e2af5658 +35, 0xecba992ca7e9178d +36, 0x8b40b65347cfeffb +37, 0xfce9281a9381a55f +38, 0xfde34f9f228fc03f +39, 0x8c46656aa79eba9d +40, 0x1ed0d3f416073189 +41, 0xd7adcc20a26d48d1 +42, 0x2429dcfa355eddba +43, 0xec100f2285aaad68 +44, 0x91a83984506e1ef4 +45, 0x4c10c0f973e3cba5 +46, 0x45d0d0ad9ab6890e +47, 0xa52b22d88ddb6090 +48, 0x63f7e7549bf80c43 +49, 0xfb03f87e5ea7137d +50, 0x822f96594246a4aa +51, 0x42242b1335cd3424 +52, 0xf78652fc51ec76ac +53, 0x24db7314bda69cc5 +54, 0xcce4cf66737c8427 +55, 0xffd70eeca33ed90f +56, 0xc154aff2caddd546 +57, 0x59d47a8ccd59e1bb +58, 0xabf793045ca561f8 +59, 0x3f1486708729b21d +60, 0x76ed98409f3f9abe +61, 0x3f0bb2cd7cedd012 +62, 0x448f78da1713ac85 +63, 0xddbae7151c1578b2 +64, 0xcf94237ec0973cd7 +65, 0x76a0657cedebac81 +66, 0x2b13b564bed7a3b3 +67, 0x47a6fc0f4604c781 +68, 0x22acf016523ae80f +69, 0xf728771b939c13a2 +70, 0xab4aee3986c80ec8 +71, 0x61d8c8c918b3fe52 +72, 0x7a40380c747f9044 +73, 0xfaf974af2e96a882 +74, 0xb8bd56d90c69d42c +75, 0x7cea307dda515497 +76, 0x56d0858a27ded2a3 +77, 0x8717ea17698706b7 +78, 0x6b34d0c0587e8867 +79, 0x387a8142ee80d29a +80, 0xbba414cee59e3194 +81, 0x6d2fe8bec0e51a8 +82, 0x11d5dc961ba15ec5 +83, 0x7af1ae07932b2fb8 +84, 0xb13ea6b28d63b57e +85, 0x7e89a6f060cf59c5 +86, 0xad1f662c4daa4764 +87, 0x929a054dec3e229f +88, 0xf7f41c2a34920f09 +89, 0xf0eac1b75822b72b +90, 0x24f311773d90d399 +91, 0x9c2147da3d098c17 +92, 0xa62963f5bb0f8b9e +93, 0x97f650195285e480 +94, 0x602433fd24fe4125 +95, 0x6f17d6e3b5fd704c +96, 0x3ad6f2cf0ffd6a04 +97, 0x73a6d93edf693e03 +98, 0x467d4e6fecdfdb20 +99, 0x6aadbba2b2f8a2f8 +100, 0xc865bae9d8713526 +101, 0xa94d7c6b462e5acc +102, 0xdcbb47fdacd4d865 +103, 0x80aa6a71fd60cb40 +104, 0xf27ad62910288223 +105, 0x88f93784d309825c +106, 0xf7f9a500b821c886 +107, 0x6cd6e37a5dca4830 +108, 0x57694853b9c75561 +109, 0x9c7ef1aa6b8f2c1 +110, 0x12046439309d6e40 +111, 0xee3d652c43bd35b9 +112, 0x3838110676b26d7a +113, 0x9efd697137fa24c9 +114, 0x1eeaa149a7edd5be +115, 0x17eb32cd212e374a +116, 0x73dd5b7d7fd3b280 +117, 0x788e514de9649f29 +118, 0x6e2fb96fbf87fe8b +119, 0xc736a34c7ea74137 +120, 0xa4d48bb7df0e3c51 +121, 0x25b66ee78063d37f +122, 0x9058e087b9696e7 +123, 0xa2e6397ebdd3d935 +124, 0x394a16ba856e6899 +125, 0xe4aad4f1bc61d046 +126, 0x5e4904686af5c43 +127, 0x4e58956c61a1880a +128, 0x7328c827d6236eff +129, 0x29463809b511cf73 +130, 0xceb2c403cef62247 +131, 0x9ccc00f358aa8346 +132, 0x6fdc1c42421ba33 +133, 0x1111d660460f5300 +134, 0x97a4f922e55a9226 +135, 0xbc2a217152bfbc63 +136, 0x3617700c68d104d9 +137, 0x8eecc63c4a929622 +138, 0xc69cf9d8f8b45df3 +139, 0xa2a8ca8262f8921b +140, 0x4339edf9e292f9e0 +141, 0xfe385e2e7f6e1a1a +142, 0x5f30d1b803abc1d9 +143, 0xf123207050238c3c +144, 0x79e3401200b54b1a +145, 0x858d7ce163d4de92 +146, 0x5803a44cd013b965 +147, 0x17c65b0b01800940 +148, 0xc50b38bb58dcb3c7 +149, 0xe476e9925898603 +150, 0x3972fb0fa748a3a5 +151, 0x93da971efb1036f7 +152, 0x658bab8ef6082bf2 +153, 0xf664abd0de92444f +154, 0xa2145e8039e61d87 +155, 0x28af5560cb0ee0ac +156, 0xc1e43e6a30cefef6 +157, 0x74f61d623cc6965e +158, 0x3ee0139a07b6c130 +159, 0x214992e8a6134c54 +160, 0xaa83b771c9421231 +161, 0x15487762c93cf5c6 +162, 0xa3d37b883fffdfe8 +163, 0xe398d2bd15c1c511 +164, 0x3154f894aedd5938 +165, 0xc7ed5190721ec2b5 +166, 0xca02cf8dcfef83b4 +167, 0xa22c6a2e5460e0f3 +168, 0x2d72e4d264875109 +169, 0xf282e30c8b945616 +170, 0xa1a286624feece2e +171, 0x6f773be8548d3fe +172, 0x8c6dc6f48c83c30f +173, 0x13dc5926122501a1 +174, 0x5537f3d25d126e0d +175, 0xdb654b8409365aa5 +176, 0x55d8f727e066e818 +177, 0x534841122140f9a3 +178, 0x4e4ecc7b2ce8efa0 +179, 0x3655d535028e4044 +180, 0x6c2ad71379f15365 +181, 0xd1f1238395ce193c +182, 0x4ecd9ccc56595a72 +183, 0x3304220c15b60f7a +184, 0x3726fecf394006bf +185, 0x4523e03e39a92ac1 +186, 0x191c97036c0e20a8 +187, 0xbfbcf849ecc37cd5 +188, 0x3c6090d256b1c780 +189, 0xf7e94dd0d3e02fd8 +190, 0x83034fb1c17bb99f +191, 0xa7be8e0eb37c9260 +192, 0x177d2c560b0b55af +193, 0x55da4c839514e82e +194, 0xc9b393b79b0e7617 +195, 0xe9658403d3a140 +196, 0xc86401b988be38e7 +197, 0xe82baf54ee5df9e1 +198, 0x3a562e6572a853a4 +199, 0xcb83facbed1cb364 +200, 0x4db406f08ea62242 +201, 0x9cc816f5376ab97a +202, 0xe65a32f96a78b09 +203, 0x59e7b42c496e2c2f +204, 0x7e3e59a4546b6b33 +205, 0xc51a371516d5adc4 +206, 0x19ba384285a523ca +207, 0x5b998f71002a0912 +208, 0x81ee2f95f53dbce1 +209, 0x966a0c0bbf15492e +210, 0x80f88202ff2d29c2 +211, 0xf827f45274e32733 +212, 0x66a2611b73547490 +213, 0x1b2c3c3ae80997d0 +214, 0x264a86e09c63e4c9 +215, 0x35d4bf9c9d0d89a2 +216, 0x6051e319babb305f +217, 0xdf0d08608262be49 +218, 0xbe7aa9a7697278c2 +219, 0xac531985f79fca17 +220, 0x7ce7de0d95ba34d +221, 0x9a03956d30de1ee0 +222, 0x8106a5873e7950b0 +223, 0x804c06b1fab989fc +224, 0x20d5fe19357e95dd +225, 0xf3e89c08d1841c79 +226, 0xfc93b079bdb323cb +227, 0x8f6eb1dea40eda88 +228, 0x6e7f6b657f6d971e +229, 0xf2b15bb03a49e9bf +230, 0xcf7fed1aff1786b +231, 0xe53366adc5bafe42 +232, 0x89b853ed67fc2387 +233, 0xd13dadf3828f1df7 +234, 0x2f884ffbb83075b9 +235, 0x8efd2baea4771d71 +236, 0x7872e80c946c6bce +237, 0xcc487bc4ea869070 +238, 0x820609347e4fdd75 +239, 0xe939e3c63701a997 +240, 0xf70ed361e42164e9 +241, 0xa9f29046fce9ba8d +242, 0x61edfa750175e868 +243, 0xb7d2424653bde389 +244, 0xdadd225205e74ef4 +245, 0xecfb9a633ee3c774 +246, 0xcbc69459f0634f30 +247, 0xdbcd82538e0785e2 +248, 0x2b272f59ad36e01c +249, 0x601a38897a57cc68 +250, 0xfa012b9e5722d8be +251, 0x5bce8d48277d7338 +252, 0xd1b6ca2b93483dc2 +253, 0x8b94eceb88f55be9 +254, 0x93403aea5df5da18 +255, 0x57b6fcaf351c16b8 +256, 0x70f5e54095404bd8 +257, 0x9124d47160362770 +258, 0x987ed72af8aa305d +259, 0x71e3a8d5156f82c7 +260, 0xf788e966e86f7004 +261, 0xcf0cd5911c4bb0e1 +262, 0x3340b119d3e2f28f +263, 0x9952106be6e3bf95 +264, 0x99a6213e19fe9d1a +265, 0x4f0d3811a8a5d481 +266, 0x62d732ee5f975dd2 +267, 0x3abc8340ab323ebd +268, 0x15da761a2518c843 +269, 0xb453de7d4d15b261 +270, 0x4adc2d7cc2cc0049 +271, 0xcc9b7fa135c7dba4 +272, 0xa14857a738db2b52 +273, 0xce036b49e28c19c7 +274, 0xaee7e9fde421bd4c +275, 0x15dd298915099a9e +276, 0xa3fa6550b639b66b +277, 0x5f27c59b035a6532 +278, 0x2eef2e6292288715 +279, 0xabd211c514e3699e +280, 0x6d7bf9b33f8b09e5 +281, 0x91ff83561361c170 +282, 0x8f8e309797a91e4f +283, 0x2b11ef1cedf1036b +284, 0x6fc36ed305d27972 +285, 0x7e294e03a91eb01f +286, 0xbe16009d8b2f38a4 +287, 0x2bf69c7b54e60cea +288, 0x860079a07fade829 +289, 0x8f0ce6ae4c90d38a +290, 0xab10e5f8ab4835fc +291, 0x49ed43ddd4ca0a76 +292, 0x201eaa53b6df058c +293, 0x2d9a4fdb16f6c1c +294, 0xd3406193e1dd0760 +295, 0xad38857b542ddb6a +296, 0x52ec1e450363aad8 +297, 0x6e65469594331886 +298, 0x4b027ce344dd6660 +299, 0xbc801654b4a1ccad +300, 0x155be4bc51328b2c +301, 0xa9a1965f9b2b5bdb +302, 0x386b8dc34de0889 +303, 0xd60ee4b1b9cbb057 +304, 0x6c1e60b6914c4876 +305, 0xd07bf84dc30bf653 +306, 0x362d5b19b3f4f7e9 +307, 0xd145b8fef9a6a3d2 +308, 0x5c401126b505dd09 +309, 0x8f5d1d4446f9cb4c +310, 0x725618359f1a3e38 +311, 0xaedad9cf455de2e5 +312, 0x7f7e4e549b4bde1b +313, 0x35002b8e995f815 +314, 0x9aecaf8f393cade0 +315, 0xf346a49595886d86 +316, 0x459d5a9e92e9c149 +317, 0x60885682c3d6ff0d +318, 0x90f5e985e08bfc3d +319, 0xbf413a432e1a1b81 +320, 0x789503524aa48aa9 +321, 0x7880e5bb484bd49e +322, 0x7426535c324b7176 +323, 0x190ad37f84acba3 +324, 0xbd52510631d4f5d7 +325, 0x98f794ad565c986d +326, 0xa0ea374e66c0bf56 +327, 0xd683fe7102145335 +328, 0x9b3dac61db2f2930 +329, 0x470d31e3096c2450 +330, 0x1f445f8292f6f3dd +331, 0x1687ff432def56a7 +332, 0x887d4e6617525278 +333, 0xcd81ce8cc70b13ff +334, 0xaadbc4c3525c18e1 +335, 0x96d81490c362b621 +336, 0x128b95092e36796c +337, 0xffeffbed0980cdb7 +338, 0x3bcef6c52b36d07a +339, 0x400879c888eeabe2 +340, 0x373c9978059787d +341, 0x35979fef9e20050a +342, 0xf4581367f3fc43b +343, 0xcec7b91352ed0186 +344, 0xa7b06e92b765203 +345, 0x6713f0b11fb9f296 +346, 0x95c53b86deafbd95 +347, 0x3694844a5eca42df +348, 0xd0f334ea2c650574 +349, 0x5ae6771044110ddf +350, 0x9f61d9087e7d36e5 +351, 0x28f04e48625e3e5e +352, 0x6164d6b5445cf130 +353, 0xa36b5c2de27084be +354, 0xa099a43d5c5f21bb +355, 0x706edfb05fbe8b9e +356, 0x7aacffffc81ebc3b +357, 0x6f49121baebd0e6a +358, 0x41fda7ba6df8f4cb +359, 0x1bea4b596dbac5ac +360, 0x71dd0261d65b02c6 +361, 0xad7f50624c15e9c9 +362, 0xf7c4eeb84d4866b6 +363, 0xa5e23dd382f48bdb +364, 0xe6ffdf875d534bfa +365, 0x40104d8444f75a7c +366, 0x8218a42f24a88364 +367, 0x9d3f9382759cae86 +368, 0x101d7adffbd9ebde +369, 0xf9fe3578d6b739dd +370, 0xd23c47039e882eb2 +371, 0x37fc4fff590191b3 +372, 0x2a672fc8cd3e0cf7 +373, 0x995b8faabb4332c7 +374, 0xabc6117aa665a743 +375, 0x3fc49d11869352ea +376, 0x4ccc3cfa9540797f +377, 0x111c57f059fa3ef4 +378, 0x44a737bac79496bd +379, 0x37924823edfe0774 +380, 0xa4d8ee07ab241d02 +381, 0xbb0bf46c50f349ac +382, 0x4db0a8506e22199c +383, 0x93239f377c85ba51 +384, 0x56f51e3970e409f5 +385, 0xe82d51ebc177609e +386, 0xec866d8b473eaeb +387, 0x42f8018bb955abed +388, 0xf58ba8a916b04fa1 +389, 0xf12d2f0cb0a41cff +390, 0x8102b5f91923cc2a +391, 0x91d95fcb9cb1346d +392, 0x819ccf0d122537ac +393, 0x34646b1c3f9a8527 +394, 0x4a3a7df812ff79cb +395, 0xc3d0b50ed434ad24 +396, 0x3e6cd372b453b5f0 +397, 0x39101f6226c43c8c +398, 0xff41e5b6b7ff540c +399, 0x1e8d77bc3f12e0f4 +400, 0x748d0860be568eee +401, 0x5baac1f743bfeff3 +402, 0x8bdbd895b2eed2d8 +403, 0x5d3a01fa82bd88d4 +404, 0x577271d2de3e06f4 +405, 0xd4fccaeb0db61acb +406, 0xa088377ed2b1d841 +407, 0x6f2e9e1566f37b5b +408, 0xb8d85eef688c049a +409, 0x6b7c06c55078761 +410, 0x223cd94cad1e0c32 +411, 0xbf27c193ae5881e3 +412, 0x5b784893a36d57dc +413, 0xdc9fa53968c262dd +414, 0xd7e820c76855fb61 +415, 0x72260eb94f096e2a +416, 0x49144b5732ca1b94 +417, 0xba8d85a47582d428 +418, 0x558abe242dc84de2 +419, 0xc27b1d54557b9de5 +420, 0x80c1f06559385330 +421, 0x4a5c1d4252675c73 +422, 0x225e3a9f7b2da067 +423, 0x9ac95bac9d2234a1 +424, 0x696e500589e0e490 +425, 0xd0fe548d81c82185 +426, 0x68d8b783037b4743 +427, 0xbe1664f1a8d814f +428, 0x2304308b691ca712 +429, 0x68e680af6b7189c5 +430, 0x13abe6c989949072 +431, 0x4c209f5029a59d0b +432, 0x63361139df6fea7a +433, 0xf07c52d8272cbdb +434, 0x665023146f27fa7 +435, 0x7cb535c55ad7ad0e +436, 0x76e366c7317eb1b0 +437, 0xa7d9b80b51585e9b +438, 0x85f0bd60122198b9 +439, 0x34bc89d7e7827fd5 +440, 0xdfa1167988c85807 +441, 0xe78f45588bfdba02 +442, 0x172a023eba7357b2 +443, 0x7bc4c79e06ea755b +444, 0x8aace6120b766b95 +445, 0x17b43a5a81b0db26 +446, 0xbc2b95819d959ff6 +447, 0x1b8841f2fe9c4622 +448, 0xc094a747ec30d67a +449, 0xf5b93ec01484b937 +450, 0x659bbe8bdfd43f01 +451, 0x9d96c22bcf9c64c9 +452, 0xcf7df324fba052ec +453, 0x5e4acd4f9e048e0b +454, 0xe3a0e7e9869c5dd2 +455, 0x4eb444727e1c346e +456, 0x7f6cda1ca7b3eb67 +457, 0x72fccac63ca649e9 +458, 0x711bfbf79a093651 +459, 0x5d48599fae7fd6a3 +460, 0xcc640119a296b34e +461, 0x39acfb198b2b439 +462, 0xde759b50e2db66f9 +463, 0xe83bf8363827e06 +464, 0x484d50365017de87 +465, 0x4c3b5dbacd68394b +466, 0xbbe47788c079218c +467, 0xd44099290c25fe62 +468, 0x3b7d1bd6f91f3857 +469, 0xe7366a677d2b7eb3 +470, 0xfaa770590b197910 +471, 0x610b7a2fe8c4e80e +472, 0x13451e1bf520a796 +473, 0x7e3d18c47e821077 +474, 0x8fd3a77c86eb9804 +475, 0xf24be740c87eadab +476, 0xd5a52e6d0b58345 +477, 0xae386b5ca037a8d +478, 0xb59fd16baf160f26 +479, 0xd4a05b473f6e0a8a +480, 0x47ede6678c2c6420 +481, 0x8851ed397da6f850 +482, 0x1de775cdb392d89b +483, 0x74e6c8ec9513ea38 +484, 0x30ae39e04187a984 +485, 0x614cfd09d043d601 +486, 0x3e0173138f562ee1 +487, 0x822d415a26bdba96 +488, 0x432f6dec77edd9a8 +489, 0x47a3a179627546b8 +490, 0x845dd7ffb1fe6d78 +491, 0x9778d5782de13a48 +492, 0x760198319b3cacce +493, 0x420ee262d07dd7c +494, 0x847c7424c365df20 +495, 0x56b3b590fb83ba16 +496, 0x7cd2410390a3e797 +497, 0xbb0c21b47aab8857 +498, 0x2743883e70a36a18 +499, 0xff8b29cdc75ebb7 +500, 0xe1e04a0f0379686f +501, 0xcfdf3083b792f281 +502, 0x27392ca026b55e88 +503, 0xeeb195994fd56abb +504, 0x7cf210041345882c +505, 0x3ddca2b8951fea4e +506, 0x21c89d88a3833996 +507, 0xe7128bccc4b25c9b +508, 0xe39b0fb96a4c05ae +509, 0xedf5326550594554 +510, 0x4aa45fe66b575558 +511, 0x2799fc8d3b06f777 +512, 0x2824863087187501 +513, 0xa15fa00818118906 +514, 0x559fc9e9344a310 +515, 0x1682745f8d571671 +516, 0x80b54f29f47a28d0 +517, 0x38e28103ffd9f771 +518, 0xedb5f440dab80945 +519, 0xdb0b8d04cece6091 +520, 0x1f60a7cae5ae8412 +521, 0x6719c0405e92b31d +522, 0x56752def7d642302 +523, 0xa5b0900f93c352dd +524, 0x5b82baf53be8983d +525, 0x7726202ccee5cbb6 +526, 0x1641c84c7f87a765 +527, 0x835ae1a82be4265e +528, 0x5f9ccee69c1d9da +529, 0x3e2a2228e21039b7 +530, 0xa45873582866d005 +531, 0x7fbeffc99401e59e +532, 0xcf66a6a974057890 +533, 0xd53704a96af96fd +534, 0x1a8b5e3460704b64 +535, 0x6939b27bb32ba451 +536, 0x3c39293e637a0115 +537, 0x335a6e6b779b8c4e +538, 0x75235d767dfd3d00 +539, 0xbdf0b36936b17c90 +540, 0x982dc5e4915a3a3a +541, 0x74657ac256407f55 +542, 0x603a724457b796b6 +543, 0xf178694f7a3f98bd +544, 0xe712de12db2aba47 +545, 0x1ca272d99a3355d8 +546, 0x93e7054d3e8dafc7 +547, 0xa29597810eff04c1 +548, 0xade242c0ae4bcea3 +549, 0xbcd226e2bd9d0e64 +550, 0x2e02e5736f889a +551, 0x3622dc09f5fdd576 +552, 0x6e66bd2a10d78705 +553, 0x71d8f19110d5b4d0 +554, 0xacae934ab3d759f0 +555, 0x68d670d5f9272132 +556, 0x571fb09d082e7da7 +557, 0x154540c51b7d8b33 +558, 0x1e2f3710c0b6890 +559, 0xaf26a826ef444b30 +560, 0x9fc9fdbd9342be72 +561, 0x9b33b306d22a35e0 +562, 0xb6d5895f56d4197b +563, 0x92fef06c1353b2e3 +564, 0x804e3eb42e65b938 +565, 0x73d5cd4bb7270902 +566, 0x274b8ac4925da8fd +567, 0xa9a57999f5df2e2f +568, 0xa6000be059e088b +569, 0x57de4fc48c9e9e84 +570, 0x16727392e94ee9bf +571, 0x53c9032f62848c4d +572, 0x8a8ddd8fcf0676dd +573, 0x1436de7c1735087 +574, 0xfa93b7d1425e8667 +575, 0xec34ca5f3f84bb2f +576, 0x489ed44d0880c4c8 +577, 0xb3b6051de7a6f740 +578, 0x2f303cb0f4040f11 +579, 0x302c42a6adbcbcb2 +580, 0x28ed7b87695cd600 +581, 0xee78d3b782a2fcd0 +582, 0xc47a2441a1082032 +583, 0xec9965704a044f33 +584, 0xcb1563e968460dc +585, 0xfecbb4fa2b544f93 +586, 0x3f3d7437a6d29a3d +587, 0xe4bfaccd729414ca +588, 0xb741ed954572d172 +589, 0xf34b49bf10ae47b6 +590, 0x1fbd1f068f1b796d +591, 0xc1d556e64345b226 +592, 0x85bbfa50a899c7be +593, 0x5310045dcf0fea8 +594, 0xbc6f6fb7f00e5960 +595, 0xf8bdf4074f2b5f5e +596, 0x2a5817aa122dc97f +597, 0x6d5ef86d6b8ad0ce +598, 0x96e7ccc235abb79e +599, 0x8d531c4cea492f66 +600, 0xfc124a123b4ce02a +601, 0xc6087ffd9130c2ca +602, 0x3a724c46f0f06175 +603, 0x59980713cfe4fe92 +604, 0xecde418e64a11bd +605, 0x5c9b333a0f0337cc +606, 0xcf014d508fc8e83a +607, 0x83998bb2aa4e16ba +608, 0xde8f5167ac0a40d9 +609, 0xe93b1846914c0dc7 +610, 0x668831ca8fd50c25 +611, 0xec764b87e402c28e +612, 0xd0e1303e56f6b268 +613, 0xa6b9f3c4872dbcd5 +614, 0x12a89c116ad924f0 +615, 0x23857c375ae928c8 +616, 0x29b117f63f2e8c1b +617, 0x64ff6cce272aa46d +618, 0xd40fb15b38d59f70 +619, 0x6e5a6257c4cc0c66 +620, 0x7b54845e6e119a4e +621, 0x9d88bf3dd9fa0f0e +622, 0xb6687fd4980a5d43 +623, 0x4f2e3fef88b640b8 +624, 0xf07ac2f7e2df40fa +625, 0x24059bd0ecb6c6a9 +626, 0x6204a47cbd57453d +627, 0x8477fd1a13ea9678 +628, 0x4555083f5eada49f +629, 0x352443e5d984691c +630, 0x3e904f796a9c5ffa +631, 0x11e182bc43754609 +632, 0x608cdbe03699a5d4 +633, 0x2619146efbf59f0 +634, 0x9b852370063940ee +635, 0xa1d8e7e91e42a52b +636, 0x19179affce38fa3c +637, 0xf68ff1ccce70380c +638, 0x12103cb41741ab38 +639, 0xdca7902fa6d960b2 +640, 0xad46a2fc70025445 +641, 0xac92f0b2d150d716 +642, 0x5de115babb43326e +643, 0xf335366fd69e4bcd +644, 0xe9aecd1f88889cd +645, 0xbce60087987b51d1 +646, 0xcfd395a167103939 +647, 0x2fdcb12826ac806c +648, 0xbd5129970869ccd6 +649, 0x5e922b68030c2698 +650, 0x7ada02a56d17779a +651, 0x7a1254c652b99ccc +652, 0x8be78733623db772 +653, 0xc22439789b68f0a8 +654, 0xee51ad4ab1a9a6ed +655, 0x44b15fa27694d9be +656, 0xc5b93e6c57805153 +657, 0xcf03df495c283a89 +658, 0x5c2a41954bb44bb +659, 0x9e651cb8c650dd +660, 0x73a20ee82570d4a8 +661, 0x5f805cab085e971f +662, 0x5354410872a8f587 +663, 0x1b50ef4e9519338d +664, 0xdeb873412301a1ce +665, 0x3a286bb2f5f8db39 +666, 0xad117a0d4dc7f82e +667, 0xdd880d581169d989 +668, 0x8356be106382a704 +669, 0x7c684ad93e996ff3 +670, 0x6b2d09e61ac02c11 +671, 0x99ad8c074fe046dc +672, 0x4a9b4f0e7c4ffa24 +673, 0x38afdcb5893b466 +674, 0x7ad58ef97c3d35c +675, 0xdd7c17c0d67ab69 +676, 0x61c77caf27938c86 +677, 0x978fc491080c0cee +678, 0x4c1750f8684c1ca4 +679, 0x86b4c683d5fe657e +680, 0x720e2bd8ec76cffc +681, 0x73ca52b4a7dd3b85 +682, 0xeb10a691e12ea3ca +683, 0x90355e369297b259 +684, 0x6c6bc16f639678ca +685, 0xd989f4c724f8fba7 +686, 0xbb1ba7e2ca1c4391 +687, 0x81e4194500a0d267 +688, 0xbb25489c1dcbf93f +689, 0x74d26b75e9f57fd +690, 0x59c085fa99b6493d +691, 0x3359805b0fc3fef9 +692, 0x60ef0f3a85e60650 +693, 0xf1a3692c8591e8d6 +694, 0xd7c8d2e7f3d3546e +695, 0xe8fc8518c11ca881 +696, 0x3380ef12114d1818 +697, 0x87203c98ff21fcaf +698, 0xbc37f8e034002ef8 +699, 0x891b7c3f55d02300 +700, 0x814eec8ff8956f0a +701, 0xa370639852acceae +702, 0x6c566310b6b00f15 +703, 0xd69fe78b9c8a05a6 +704, 0xb7b0df518738419e +705, 0x2a0c1185b29ed965 +706, 0x636c841214c0a8cf +707, 0xbf56297859e9bb72 +708, 0x2b5b9d432d6d008f +709, 0x1ea586cf0f86f542 +710, 0x23a2a1af76cbc988 +711, 0x6c72c799b6ed93f3 +712, 0x2266785315f3bb13 +713, 0xb68cd6e87b94065a +714, 0x5d395704514bb808 +715, 0x334bde59d526ee4 +716, 0xc5a6d87f96f055fa +717, 0xd47001378b4dcf08 +718, 0x7305818a39057557 +719, 0x8f72c128eac6d32 +720, 0x4957ed799339bbdc +721, 0xeb47d505f61dd5fa +722, 0x8ce8817cd6acc93a +723, 0x84ef66e511a52f35 +724, 0xbf5aa34bbaef7e1f +725, 0xadaa5ba2a5ee660e +726, 0x6eec8ac924058eea +727, 0x8af63be4d1a1b202 +728, 0x88eccf85fd9fce32 +729, 0xf19a1122f394af05 +730, 0x8dcd15d1c14f5077 +731, 0x6c0f2e6135e36545 +732, 0xe58f89bec4d929c8 +733, 0x4eea88221d983ef9 +734, 0x51ae3956d53e1a80 +735, 0x40d8a172bf713bb6 +736, 0x3e33536e43ad4fa2 +737, 0xeff9938a179138fa +738, 0x3e372bff1f51df8b +739, 0x59b86a407817c86c +740, 0x947164c2c57f9bd8 +741, 0xd8e67bb799d84475 +742, 0x4d9ed254d8189595 +743, 0xa021d8d181328996 +744, 0xc703e402f8e4688b +745, 0xd1eb104c970dd5fe +746, 0xd5bf4683b9337f8e +747, 0x98f405a2d998f06 +748, 0x59c734ddd208e85c +749, 0xbd167be2d43fde24 +750, 0x70602daab163fbe2 +751, 0xeb2f2b37cbfe13e7 +752, 0x28baa8f3fc4c4666 +753, 0xe212ffe352ea5ce6 +754, 0x538b93d2285eda3a +755, 0x3a9482ac69a39e1b +756, 0x3a98983ed4367767 +757, 0x1dc851c69e35d601 +758, 0xac7f83e4b02e9bb8 +759, 0xa939f99c5615ef7b +760, 0x439437f129076339 +761, 0x79a251bb1d50ce25 +762, 0xaa7b6ff8f13a7424 +763, 0x1b244bd86404327b +764, 0xc84d99185ab2a7d6 +765, 0xf6dcde975493c40b +766, 0xdee46f4346cf6af +767, 0x739b75df1fe18712 +768, 0x3d05cb298311f3e9 +769, 0x1fba9d9c10dc7780 +770, 0x31637fc416267053 +771, 0x46694e36246b8be2 +772, 0x8c67095ae6eaf1e4 +773, 0xebe2a68c27963dca +774, 0x532d344b14306cf2 +775, 0x6a847c8f3ae2ac92 +776, 0x8034bcb5a50cbd6a +777, 0x7544766784261059 +778, 0xe641799652df63ca +779, 0xd8cacad7099c07de +780, 0x429e62da116e4876 +781, 0x4442c8b57a5b7ef5 +782, 0xa7ea9c348cbeebaa +783, 0xce1a34f57bb2a7fa +784, 0xbb29ef457c9509cc +785, 0x1ba1030b19a32c1c +786, 0x412d1eb07cee79b8 +787, 0x3627dd37c6b36848 +788, 0x45432b319f26a2a9 +789, 0xb9a12e188cee2a29 +790, 0xeee69e0f1b1efd66 +791, 0xd4ccd61bc3fb8837 +792, 0x1b600476917cbf62 +793, 0x522950ddce26c142 +794, 0x956d8a5dbe9aa431 +795, 0x31cfba73bb524b7d +796, 0xc3b709a56885a6ac +797, 0x7341d4e32fffcdf8 +798, 0x5ed87c5315e4775 +799, 0x60fa512183e3dad5 +800, 0x4df6df14e9c2935f +801, 0xdec2dc983ab42a9 +802, 0x28265e213fd6de41 +803, 0x2f85d825454add06 +804, 0xf18119191ac41aa +805, 0xf870e36e83f4face +806, 0x2a4b213d973d83c8 +807, 0x2c7094cde18ba8ec +808, 0xb5998e0a1914446b +809, 0xefcb960ff010503a +810, 0xa8d928b99104aef5 +811, 0xe7a6893116e383a8 +812, 0x552dbe180a51b6c9 +813, 0x16b73f3832c9990c +814, 0xfefee9504783e187 +815, 0xc12d3aa0c1f8608b +816, 0xd5232106c7adea7e +817, 0xb207e82667fb71ed +818, 0xe93c50ef54a791cf +819, 0x3099900fdf7b1750 +820, 0xaa2a46c352132ad0 +821, 0xf2414daa174335e4 +822, 0x33080f98c42bbad2 +823, 0x9df24fe0b5b13394 +824, 0x840eedf2eec5fdb6 +825, 0x3715e262efbc907d +826, 0xa70a8cccfbe8a11f +827, 0x4a57a6f16ea4c9f3 +828, 0xe03dbe2f1493e9e1 +829, 0xbd92759a7becd4e4 +830, 0x21a3d87c3766887e +831, 0x6414f570caa74ef1 +832, 0x4e27490fc3fc0234 +833, 0xd4c40310c6ab2eba +834, 0xfbe8acd168ffd62d +835, 0x30b19992f1975ac8 +836, 0xaf93d22a8561f631 +837, 0x4574ebab81bed3b1 +838, 0x5390c6026e3940c7 +839, 0x7a5154d076a8b504 +840, 0x9676f2495f742943 +841, 0x8cfdb9e11bdb4502 +842, 0x36af5c8754d9ca17 +843, 0x61477e76367296ee +844, 0xd6f5f40f66acc700 +845, 0xe62c2462e96af1b8 +846, 0x18029746ac09ef3e +847, 0x871bbe15da7e0176 +848, 0x2443e806f54d179 +849, 0x9103af1634f9d0ac +850, 0xe6e5358eaa0efa2b +851, 0xdff4859198244a67 +852, 0x6e48c357be6042b +853, 0x6bb9e8aeb24d656a +854, 0x1b89fbb05f8438cb +855, 0xe0cea835b4db045d +856, 0x4eafe5c195e29d47 +857, 0xd2f0a452be9163f0 +858, 0xa7ae1d0eee928fe6 +859, 0x42c7a26c82a062c4 +860, 0xa8e93bcd89c5704e +861, 0x73784be379f09c34 +862, 0x91f8e599342d013f +863, 0x79c20bc462215ccc +864, 0x6ee77bc91b3753a6 +865, 0xd2c116d1eb2650d0 +866, 0x388f9767cfe30ebe +867, 0xdde5d5966815e7ae +868, 0x459b838c87ca1dec +869, 0xdf96cdb2bc916a60 +870, 0x215c4195b935d5ca +871, 0x56c9f516528598e5 +872, 0x1d8492a9923640f3 +873, 0x97830ac45234686f +874, 0x67f75117a7c952bb +875, 0xf1939dc69391e65d +876, 0xfc44bb1162cb2868 +877, 0x92b33d9df8fc6925 +878, 0x6c4496920de0d558 +879, 0xa4616bb101e924aa +880, 0xa0afc9701ad83cdb +881, 0x62d555323b0494d2 +882, 0xf18b31447a2dfdc3 +883, 0xb2ece318c128d4f3 +884, 0x29efea45a76b9b8f +885, 0xae05362b365d9cd2 +886, 0x5c4d374ce6aefb44 +887, 0xb9cdc65eec94136e +888, 0xf0212f42e3d4f5dc +889, 0xcde7c5085f95d8d8 +890, 0x9cc3799673a644e8 +891, 0xf878d89199bead01 +892, 0xab684fb9666abf61 +893, 0x3070d399b7a07d3d +894, 0x6d8c51673eeeef73 +895, 0x9bf4062ff5471832 +896, 0x92774cd03c511d00 +897, 0xc1aad7c6980df547 +898, 0x3291e3a234d50cc0 +899, 0x75645079bbe9d34a +900, 0x7f28bab9eba28fae +901, 0xa84415684ed6d765 +902, 0x56d9d67653cd172 +903, 0xa7bfed939db93e91 +904, 0x92940e5162d50470 +905, 0xcd6bf601e08f07a9 +906, 0x2ea9104d785e35cb +907, 0xd771ddd541649214 +908, 0x352554afbf9258d +909, 0x9d855486b77c5bc3 +910, 0xdb03cd71e906e1df +911, 0x7c2621690aabc265 +912, 0x1dd4ac7369a04640 +913, 0x57796cbc93d4d854 +914, 0x42a373d152eca785 +915, 0xbe7389edb8b144d3 +916, 0x8b6245bf01d2e4df +917, 0xacd1f9fcca317652 +918, 0x84545ac79a3eb960 +919, 0x2d2f28e6a8459db3 +920, 0x42b3a2e26ddeccdd +921, 0xe858272777abcef6 +922, 0xd9b5be7340dec08d +923, 0xe991af3579ac4fb6 +924, 0x7c30699b349fa6c1 +925, 0xbb842be14f7b5b9a +926, 0x1d31e1ca791a1cf0 +927, 0xf2bd448ebb878bc0 +928, 0x26a6adf6709863cb +929, 0xb11aa978539e3a34 +930, 0xce554a11bbbedd1d +931, 0x553d3c012682a47b +932, 0xb3c90ed36715903 +933, 0xda3c5c706e39e395 +934, 0x4e7f66006d583c2a +935, 0x6424190e9d28ca3a +936, 0x9916685e7384f3bf +937, 0x1285e17347eb806d +938, 0x877f10baf13e6659 +939, 0x222700ed5086438d +940, 0xd2473d08396634b8 +941, 0xb6b68f3bc883a77d +942, 0x168a489b0b7f5f63 +943, 0xee34dcf1f93ad3fa +944, 0xd25ef824f614f65a +945, 0xe30981905354f477 +946, 0x9463ef623c5eb3f8 +947, 0x46657408ea66980d +948, 0xa2e58d51d6e8e7f9 +949, 0xd80d7df3007e9845 +950, 0xd90fa96f4fc0f7aa +951, 0xd2a6059d171bbb33 +952, 0xb8bacb8f11c65c2d +953, 0x401de84b6a8b1ac +954, 0xf8b6eed644c802d9 +955, 0x30c927749fdd8e6 +956, 0x17c2f4f9c4524e16 +957, 0xa9c677daae4acc7e +958, 0x82c78d9c6b10446f +959, 0x5e544188277da629 +960, 0x7c6e1bd3b861dcd7 +961, 0xd4b00871a7f67d0d +962, 0x6b66ee142821e6d5 +963, 0x176d5e39f3b22474 +964, 0x58ea746f62acf933 +965, 0xc61fabd9961c3a51 +966, 0xb27ce0f87b416e3d +967, 0xd3c82b525b000e70 +968, 0x99578704fb3ff4e4 +969, 0x747da52468875493 +970, 0x5c5bfab7a474465b +971, 0xd82276bdb30e3dbd +972, 0x1d758772eebffe2 +973, 0xfed9d1e3ca887a6e +974, 0x23dd5f7b3ff9472b +975, 0xae2e842b51c9c598 +976, 0xe851bc45531123d7 +977, 0x1a18d2777151c29 +978, 0x9e82f3be14b12a48 +979, 0xdf9fdb3abc3e72cf +980, 0xdbea56e918ccb176 +981, 0x47abbd896eb0ca1a +982, 0xe850ee3cef9334dd +983, 0x3d69fe95275e7f2e +984, 0x4fcb936c048d8812 +985, 0xc98f0f6bb9865a99 +986, 0xc951cdb73514709 +987, 0x3ca839c27ca26de9 +988, 0x1478848a311f9cc5 +989, 0x35d2244064967478 +990, 0xe71df2d9732ffdc0 +991, 0xa12417d7b7b9e0ce +992, 0xa1bb6da3f284f77c +993, 0xf551e1c3171575eb +994, 0x16083ac8a062747d +995, 0x866d6c3a630fd4da +996, 0x8a972ff46b3c5c4c +997, 0x70af3b475e4a3d5d +998, 0x2c143fd5c01d9cf5 +999, 0x68089ffadc8ea2b9 diff --git a/_randomgen/core_prng/tests/data/threefry32-testset-1.csv b/_randomgen/core_prng/tests/data/threefry32-testset-1.csv new file mode 100644 index 000000000000..3aec7304df34 --- /dev/null +++ b/_randomgen/core_prng/tests/data/threefry32-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 0xdeadbeaf +0, 0x6cffcc99 +1, 0x2b7c051c +2, 0x4ab0b74a +3, 0xee73ea3c +4, 0x5b43def8 +5, 0x7e166501 +6, 0xead67c35 +7, 0xa8bd9381 +8, 0x67d79512 +9, 0x18a341e4 +10, 0xd6672c17 +11, 0x40a13b1e +12, 0xcd31ce04 +13, 0x12fdb46d +14, 0xf2fd0ffa +15, 0x4e4fc443 +16, 0x61a53917 +17, 0xff60cc00 +18, 0x51671412 +19, 0xf3a08627 +20, 0x5ba59f45 +21, 0x1a9f5793 +22, 0x3e2a31fe +23, 0xa2242742 +24, 0xcafae297 +25, 0x5eb5a116 +26, 0x23ef9e16 +27, 0x54f01377 +28, 0x47114dcb +29, 0x4ce52425 +30, 0xc898c3a8 +31, 0xf34d52b +32, 0xf05e3aea +33, 0x8e122dd +34, 0x57ed51e5 +35, 0xa949f8c1 +36, 0x6b0c6ca2 +37, 0xeaff706a +38, 0x7ff23d83 +39, 0xb29857d5 +40, 0xbc79b2d3 +41, 0x350e2f98 +42, 0x3deae452 +43, 0x75c70896 +44, 0x8743a85c +45, 0x8c05ccda +46, 0xbb547a23 +47, 0x53f341ee +48, 0xfdf5fe22 +49, 0x6bea4979 +50, 0x1dc06326 +51, 0x58f1fc83 +52, 0x1130e7e5 +53, 0xc434fc00 +54, 0x13acc9b6 +55, 0x198a6356 +56, 0xe59278f7 +57, 0x720ce91c +58, 0xa4587617 +59, 0xa68be124 +60, 0xd54392ab +61, 0x19eeb16a +62, 0x5abac829 +63, 0x2303dcdd +64, 0xaffc0c4c +65, 0xd3757435 +66, 0x8fd204f +67, 0x7f48f1d +68, 0x94512051 +69, 0x4d5d385b +70, 0xd4877f13 +71, 0x834af295 +72, 0xf97fca51 +73, 0x31b766b5 +74, 0xa25a5371 +75, 0x21ae0ebb +76, 0xe5e1066a +77, 0x1633cf01 +78, 0xab411bb9 +79, 0xb2982b5c +80, 0x67cc822b +81, 0x2eabd825 +82, 0x21e0dc17 +83, 0xb9170084 +84, 0x53c52c00 +85, 0x3acc5cec +86, 0x985ce088 +87, 0xf6e2d9b1 +88, 0x37cc5a23 +89, 0x34222cf3 +90, 0xc8f6823a +91, 0x581173b2 +92, 0x300416ea +93, 0x2357d4ad +94, 0x1bfceca9 +95, 0x48e6cdc5 +96, 0xcbf8d214 +97, 0x25c47e6a +98, 0x8a99c824 +99, 0x367c07b6 +100, 0x38643cfb +101, 0x7899c225 +102, 0xefd1c7f9 +103, 0xdfd3d507 +104, 0x7a868d74 +105, 0xac8cfcfa +106, 0x901aac22 +107, 0x52d4f1e5 +108, 0xb8d0b9a3 +109, 0x4d1ac438 +110, 0x1b6995e3 +111, 0xf2b49c8c +112, 0xa4ee5aa9 +113, 0x63f48457 +114, 0x1f092683 +115, 0xe1ffa0c1 +116, 0x64c14ec9 +117, 0x7c86caae +118, 0x96810301 +119, 0xfdeb5934 +120, 0x70636d11 +121, 0x857cc412 +122, 0x83244693 +123, 0xa46e5de7 +124, 0x47406f19 +125, 0x34a31ade +126, 0xb5168ae6 +127, 0xca6e0cc1 +128, 0xb7f612e6 +129, 0x296f0512 +130, 0xe7230082 +131, 0xde6f547f +132, 0xf12bd1cc +133, 0xf51dd599 +134, 0x8a5ab59e +135, 0xd8b1cd87 +136, 0xe81304df +137, 0x3c0ddff1 +138, 0xc6d3a649 +139, 0x2d950bdb +140, 0xafecc338 +141, 0x5b20a006 +142, 0x6d813023 +143, 0xcb698f0f +144, 0xdb7ba980 +145, 0x78942bed +146, 0xb12a3df5 +147, 0xde84510e +148, 0xe99351ee +149, 0xbe5ff58e +150, 0xe0fd9ef +151, 0x1e4b9d22 +152, 0x8bca03a1 +153, 0x7c6377a0 +154, 0x37fbd0a3 +155, 0xe8bef1ba +156, 0xb14651cb +157, 0x3e69d08a +158, 0x56cc688a +159, 0xf86ddf5a +160, 0xd5818aff +161, 0xfe1b8f29 +162, 0x2b505d54 +163, 0xd85caf4 +164, 0x7d360464 +165, 0x276c469 +166, 0xb949fc4a +167, 0xc2bef2ac +168, 0xd07c9118 +169, 0xb0ac2494 +170, 0xbda3bc0f +171, 0xc3fe015d +172, 0x741b443 +173, 0xafd4a887 +174, 0xc3ee9b82 +175, 0x12a16e1b +176, 0x7c3a37f9 +177, 0xee996915 +178, 0x52e7f5a0 +179, 0x1f3880de +180, 0x8735c769 +181, 0x7e51e99b +182, 0xf3c35d4c +183, 0x49f56f0 +184, 0x18c5a61f +185, 0x76a3685f +186, 0xabe0061f +187, 0x9393af8b +188, 0x97fc918b +189, 0xf512e881 +190, 0x2ddd9768 +191, 0x1b7c2e28 +192, 0x5f6a6f1f +193, 0x7960eb61 +194, 0x7805d6c2 +195, 0x20165f7a +196, 0x77490b1c +197, 0xb2cdd255 +198, 0xe6d1bcb5 +199, 0x9687e506 +200, 0x55a213f7 +201, 0xedf9c17d +202, 0xdeec02a8 +203, 0x9d182919 +204, 0x61a1d691 +205, 0xedfa20aa +206, 0x843a4793 +207, 0x56d799cd +208, 0x8535f679 +209, 0x37dbf765 +210, 0x92353041 +211, 0x82532156 +212, 0xa118dd43 +213, 0x198bda1e +214, 0x5d8d60f4 +215, 0xcef238f2 +216, 0x8474c6e0 +217, 0x169a9ab1 +218, 0x50cc819 +219, 0x9b3bda9a +220, 0xd813c3ec +221, 0x8dafb7c4 +222, 0xf3d9ace2 +223, 0x8b9cf3da +224, 0xe9d8fd48 +225, 0xaa7f1866 +226, 0xe8186b07 +227, 0xd6ff13a4 +228, 0xc4a41308 +229, 0xefa359f6 +230, 0x4b257335 +231, 0xffda6c5e +232, 0xc3f7362 +233, 0xe3b123cf +234, 0xe774fc0c +235, 0x4d470897 +236, 0x8930aaf5 +237, 0xa801bc +238, 0x638348ec +239, 0x1002026f +240, 0x196fbcaf +241, 0x422838fa +242, 0xf101e6a1 +243, 0x823e3a7e +244, 0x89efe85c +245, 0x710d363d +246, 0xa96fe815 +247, 0x4b6921c6 +248, 0xe744e488 +249, 0xa0b744a2 +250, 0xac95b93e +251, 0xf820586d +252, 0x9b54d2bc +253, 0x78f663a4 +254, 0xdab3fe37 +255, 0x9212053c +256, 0xa23d60ea +257, 0x82c99bd3 +258, 0x90a9a2d3 +259, 0x80fee31c +260, 0xf14ecf6e +261, 0xde7ce14 +262, 0x9d3cd17c +263, 0x4f07180e +264, 0xa1f53dd2 +265, 0xf7b8f170 +266, 0x4947ceb5 +267, 0x9cc97da3 +268, 0x11e679a7 +269, 0x707ac9f2 +270, 0xa02c05c8 +271, 0xefcd3b07 +272, 0xba998379 +273, 0xf4d1d5b +274, 0xec4d44c0 +275, 0xf9775389 +276, 0xbee26a88 +277, 0x604a69da +278, 0x69dd0436 +279, 0x64ace3c4 +280, 0x74a7effd +281, 0x93a88a8 +282, 0x9d86abd9 +283, 0x2d7c8fd7 +284, 0x2e34bfd1 +285, 0xda5d15ec +286, 0x666c44ea +287, 0x1e97fd34 +288, 0x64fffc5e +289, 0x7d909a49 +290, 0xe5b8a071 +291, 0xc71ecf14 +292, 0x32bc254e +293, 0xe6ffc12e +294, 0x76488aaa +295, 0xfaa24b5d +296, 0x2546a15f +297, 0xd61ec5e +298, 0x5b28529f +299, 0xe9d32272 +300, 0x9937f54e +301, 0x83fcf3cb +302, 0xf57e30df +303, 0x6ed40238 +304, 0x455afea +305, 0x39c1421b +306, 0x97056915 +307, 0xa7fb7b80 +308, 0xe12d4aeb +309, 0xd701e899 +310, 0x191d6f8e +311, 0xb276c998 +312, 0xd5640ed +313, 0xc8607d38 +314, 0xd1f75765 +315, 0x4046f224 +316, 0xf9fa0881 +317, 0x9f835301 +318, 0x70282b9a +319, 0x261420a1 +320, 0x1bace8af +321, 0x6506d84e +322, 0x990ad5b7 +323, 0x63ef0eb7 +324, 0x2dafd32d +325, 0xe119e891 +326, 0x1e163f6f +327, 0x2eb990b2 +328, 0xd9768cf8 +329, 0x93424291 +330, 0xd531428e +331, 0x6d130cb +332, 0xdce0f084 +333, 0x8e7932dd +334, 0xe83a0030 +335, 0xbe046ef8 +336, 0x47d195c2 +337, 0xe2987a93 +338, 0x9c17514e +339, 0xa771c561 +340, 0xcd6ebf92 +341, 0x500e7961 +342, 0x14c5473e +343, 0x45a306b7 +344, 0x21255baa +345, 0xb691678f +346, 0x4131c107 +347, 0x3432699c +348, 0xf5ac1ff3 +349, 0x1e1f80b7 +350, 0xab6004e3 +351, 0xbd693e1f +352, 0x2758f73e +353, 0x7b263738 +354, 0xfed2a560 +355, 0xf7f167d6 +356, 0x34103c7b +357, 0xcf976532 +358, 0xb8b12c25 +359, 0x9d5d119f +360, 0xc9e759fe +361, 0x86d83a5e +362, 0x1552d7c0 +363, 0x797787fe +364, 0xcd07ca28 +365, 0xca65456f +366, 0x534771 +367, 0x47690072 +368, 0x5b9dac8b +369, 0x4cca6876 +370, 0x1568b652 +371, 0x6e5013fd +372, 0xfd62e488 +373, 0xd548844a +374, 0xfa88dff +375, 0xa95def7e +376, 0x34c6113e +377, 0x77d17485 +378, 0xe3177854 +379, 0xef3cf974 +380, 0x4f503249 +381, 0x6cac12b8 +382, 0x93b1b00d +383, 0xe12d8b14 +384, 0x8b7761f6 +385, 0xae579607 +386, 0x12698508 +387, 0xb7cc10cb +388, 0xe3dea112 +389, 0xa0c8aaa3 +390, 0xdff5d91a +391, 0x2b9d97fa +392, 0x666986e4 +393, 0x78362d27 +394, 0x19d29dde +395, 0x204c0a1 +396, 0xf47d5694 +397, 0xab6869c5 +398, 0x48b31962 +399, 0x44d25176 +400, 0xaf7fcc00 +401, 0xa36ce44b +402, 0x2407cd84 +403, 0xd026a2a6 +404, 0x90b84a3d +405, 0x9d603df5 +406, 0x4d967930 +407, 0x5502e782 +408, 0x882554ed +409, 0xcfe11605 +410, 0xbeb03084 +411, 0x603ee8b8 +412, 0xbcac4498 +413, 0x2363e45b +414, 0x7c21d019 +415, 0x4e61e47b +416, 0x67bd2c08 +417, 0xba375f5d +418, 0xa696833e +419, 0xcb34c947 +420, 0xf15f7f3d +421, 0x1a4c69f3 +422, 0x7e4a1b40 +423, 0x9dee5fdd +424, 0x5c147767 +425, 0xe7e03c3f +426, 0x794164c3 +427, 0x5f898b58 +428, 0x88040da8 +429, 0x5e1a8b3 +430, 0x5cb9efed +431, 0xfb1101dd +432, 0xaf9efd69 +433, 0x8290ea8a +434, 0x64f8f010 +435, 0x49807233 +436, 0xeb88e614 +437, 0xba226f1d +438, 0x61210a53 +439, 0x531c4f30 +440, 0x74e22c1a +441, 0x9cae65a6 +442, 0x6e8e3937 +443, 0x96a2bd8c +444, 0xafae3c8f +445, 0xbaf80a8e +446, 0x449afe78 +447, 0x40383d30 +448, 0x3e66c60a +449, 0x2a31d63b +450, 0x48b3969a +451, 0x5775f739 +452, 0xe026f067 +453, 0xbc709fbd +454, 0xde443d0 +455, 0xe6894de7 +456, 0xf52c6863 +457, 0x62467a12 +458, 0xe3e04ed5 +459, 0x20465164 +460, 0xaa776694 +461, 0x6eb049cc +462, 0x9e12645d +463, 0xf2d9811c +464, 0x250cfb6d +465, 0xf0c558a5 +466, 0x1ba68ddc +467, 0xeb613fca +468, 0xf7b3ea83 +469, 0x285856db +470, 0xee7eec5 +471, 0xb29a8957 +472, 0xd53ae176 +473, 0xf6bc1b72 +474, 0x84fcd042 +475, 0xd69b4de +476, 0x64f75919 +477, 0x975dbac4 +478, 0x468516c6 +479, 0x5fc2b6a8 +480, 0x843a7733 +481, 0x8617a7d3 +482, 0x1ae51e88 +483, 0x504cfd60 +484, 0x66370c96 +485, 0xabf2b071 +486, 0x8352d0db +487, 0xa08736a7 +488, 0x1e7aeeed +489, 0xe8c0c560 +490, 0x980f18d8 +491, 0x197e42e3 +492, 0x6e54de4c +493, 0x61ff23b0 +494, 0x73a7e155 +495, 0x6ebf82ca +496, 0xea6877b4 +497, 0xbef6f25d +498, 0x6f184109 +499, 0x60ea6b22 +500, 0xd19f311f +501, 0x936a60d0 +502, 0x6dc64c +503, 0xaa004e58 +504, 0x347ffbb3 +505, 0xb778b487 +506, 0x3c59f9e9 +507, 0xbfef5c8f +508, 0x140797f0 +509, 0x83751722 +510, 0x99ea8dac +511, 0x265e85e7 +512, 0x9888771e +513, 0x55df56b1 +514, 0xb7a38fc0 +515, 0x87b0367d +516, 0xb178bf83 +517, 0xc9cecbae +518, 0xd51a44f8 +519, 0x14ed0be5 +520, 0xcc59258d +521, 0x81d6fb8a +522, 0xb8cf3c7b +523, 0x5181ed39 +524, 0xc600f024 +525, 0xd0cc403a +526, 0x8d30f27e +527, 0x2c2a2d50 +528, 0x253ed4f3 +529, 0x9c60942e +530, 0xe6981fc2 +531, 0xa56bc4c7 +532, 0x982b8be0 +533, 0x7f6bd77c +534, 0x7125b484 +535, 0x583b1e69 +536, 0xd37ffc24 +537, 0x576d6403 +538, 0xd74af7ae +539, 0xe16d3263 +540, 0x317e011c +541, 0x3ce41efe +542, 0x83d23f63 +543, 0x9d2cf991 +544, 0xa4e2a0fa +545, 0xbf4eee6e +546, 0x2569d1ed +547, 0xcc5ad808 +548, 0xb220c85f +549, 0x89f80cc6 +550, 0xe548df1c +551, 0x41ac99ea +552, 0x4e87664a +553, 0xb68e1066 +554, 0xcbeeecf +555, 0xfb1e10a0 +556, 0xebedff9d +557, 0x50228e53 +558, 0xee98ed95 +559, 0xc0f85f66 +560, 0x93cd2127 +561, 0xdbde4239 +562, 0x39ecb5ac +563, 0x8eb7231e +564, 0x887c5d5f +565, 0x2c60e46c +566, 0xbc1ee8e9 +567, 0x58879130 +568, 0x5a96d152 +569, 0x5606b37d +570, 0x34c032dc +571, 0x9c14c594 +572, 0x9906cc61 +573, 0x96af599b +574, 0x1157986c +575, 0xae56ee8d +576, 0x5cfb4b8a +577, 0x1f4cc06 +578, 0x736b8866 +579, 0x9746edbf +580, 0xfec1033e +581, 0xc7c4674a +582, 0xac4d187d +583, 0xfe1a82c +584, 0x5a128715 +585, 0x5ad9dd00 +586, 0xab377c1d +587, 0xf03eccd7 +588, 0xab5f33d0 +589, 0xf45a33ad +590, 0x1d9bbedd +591, 0x9eb804f6 +592, 0x35bd73ca +593, 0xe5d1fbd8 +594, 0x49831b90 +595, 0x15db3cba +596, 0x8f0ead01 +597, 0x6411208 +598, 0x23519624 +599, 0x2b8a7684 +600, 0x150a66df +601, 0x1e795760 +602, 0xabf9d64e +603, 0xcccae49c +604, 0x5f3f8b4f +605, 0x603e684c +606, 0x3845d5d8 +607, 0x7391be20 +608, 0xbeaccb8c +609, 0x2d13a52e +610, 0x84f2af52 +611, 0xa2bbde3d +612, 0x4ce5614f +613, 0x7ae9b8da +614, 0xf6106be4 +615, 0xe7e1285 +616, 0xba30e483 +617, 0x83d280ed +618, 0x21f2c5d2 +619, 0x55e9ba2f +620, 0x207e76e2 +621, 0x5ebc56cf +622, 0xd729163f +623, 0xcc23cc38 +624, 0x670da835 +625, 0xbc773681 +626, 0x898775db +627, 0x82a10cd0 +628, 0x427f744 +629, 0xe6cea8b4 +630, 0x204e288e +631, 0x1cbe370e +632, 0x3b5dedc1 +633, 0x6bb98282 +634, 0x1a91857b +635, 0xaa19bacd +636, 0xfc6f1648 +637, 0x635f80 +638, 0x4fd9e77f +639, 0x44fec088 +640, 0x99c56a90 +641, 0xb2ea52cc +642, 0xc470432b +643, 0x530429ac +644, 0xdca36aad +645, 0x49a809ef +646, 0xb482c9 +647, 0x23d6b0ae +648, 0xa04bb8db +649, 0xe152bead +650, 0x712cd313 +651, 0xdd8884 +652, 0x878d5dd8 +653, 0xc07b6349 +654, 0x1756faf7 +655, 0xad018b +656, 0xdc43b58b +657, 0xf85bdb52 +658, 0xc122a040 +659, 0x82fe93e0 +660, 0x1d96963 +661, 0x10c3c58e +662, 0xfb2cbb70 +663, 0x4b791df8 +664, 0x809955ab +665, 0x9c953fbc +666, 0xa5cccc3c +667, 0x64da4f2f +668, 0xac3e0846 +669, 0x80a4e88b +670, 0xc8294a38 +671, 0x9edbd52d +672, 0xf1c197f1 +673, 0xd94a32d8 +674, 0x221a2152 +675, 0x7fd4186 +676, 0x1f571e9b +677, 0x3af1d0c +678, 0x2c43e1b +679, 0x45e08358 +680, 0xe5b95a08 +681, 0x65c7ff38 +682, 0xb7e9408d +683, 0x35be615c +684, 0xd3a51e78 +685, 0xa043073e +686, 0x1dac1ad8 +687, 0xcd20bbf4 +688, 0x3ab08692 +689, 0x3d31363b +690, 0x5617339c +691, 0x2f329775 +692, 0x63ba0912 +693, 0xd09e248c +694, 0x3bc83bb7 +695, 0xc9348e84 +696, 0x488f5f0d +697, 0xb3458148 +698, 0x98e67262 +699, 0xb36e3560 +700, 0x929127c7 +701, 0x91e3d3f1 +702, 0xc6116448 +703, 0xd6422c05 +704, 0xbd483f8b +705, 0x10063cee +706, 0x2807588f +707, 0xa69116b4 +708, 0xd7ca402c +709, 0x246046be +710, 0xeb6d6a28 +711, 0x8f6a3400 +712, 0xd6bf311d +713, 0x6c351a62 +714, 0xedcdcdcf +715, 0x59c4a3bf +716, 0xcd30992 +717, 0x7fc3aa6f +718, 0xe0d1366 +719, 0xa7c21e2c +720, 0xbf08babf +721, 0xfe06a4d5 +722, 0xd6928489 +723, 0xb05a6b77 +724, 0xe24da592 +725, 0x670f8cab +726, 0xf9f7bc1b +727, 0xd947c6a1 +728, 0x5ecb738a +729, 0x7205a778 +730, 0xd3ec7582 +731, 0x3a4193b4 +732, 0xe886eae +733, 0xdfe36b6b +734, 0x3c60bd41 +735, 0x2df8d216 +736, 0xd6cd52dc +737, 0x62349c08 +738, 0xedc081d7 +739, 0x64b8b994 +740, 0x1dce9981 +741, 0x3a79907 +742, 0xb32a0cf0 +743, 0xc03eef19 +744, 0x8bb7c178 +745, 0xcd1b5db +746, 0x7321faf0 +747, 0x19e68294 +748, 0x839c6c14 +749, 0xdd5a50b +750, 0xe2d86a23 +751, 0xa569857a +752, 0xd65ae947 +753, 0x46b31b8d +754, 0x48972e1c +755, 0x78fadb27 +756, 0x628cd86e +757, 0x6deaa2fb +758, 0x27f03380 +759, 0xbe85ea45 +760, 0x3c756834 +761, 0x4c23f1b1 +762, 0x2fe19c7d +763, 0x440f4bce +764, 0x476f20a +765, 0x36ddd49 +766, 0x8045684e +767, 0x86f4929c +768, 0xb59d7fb5 +769, 0xa27493e6 +770, 0x6f138746 +771, 0x65f4c3e7 +772, 0xea8b35ca +773, 0xfedf7607 +774, 0x370a4ea6 +775, 0xa169c840 +776, 0xa5027aee +777, 0x4eb8e8bb +778, 0xeaf37f83 +779, 0xea132a33 +780, 0x69cb7c2f +781, 0xde8bf9d5 +782, 0x5130d59a +783, 0x35b0ea82 +784, 0xaa6caf17 +785, 0x6b32b3ac +786, 0x2e93d09f +787, 0x8caa797e +788, 0x2ac7a457 +789, 0xd14ef094 +790, 0xecd60b04 +791, 0x7ff2f29f +792, 0x2573aeec +793, 0x7dabab04 +794, 0x198ec9c5 +795, 0x4a06b4d1 +796, 0xdbffff88 +797, 0xa2590396 +798, 0x31f42c16 +799, 0xe17aa6a +800, 0x354d8dcf +801, 0xc85f2d16 +802, 0x73784c21 +803, 0x56f1fbd7 +804, 0x1e3bf2a8 +805, 0x6f05ca05 +806, 0xa3710020 +807, 0xc0b0f694 +808, 0x30e9a497 +809, 0x3ff37729 +810, 0xe3f1b68f +811, 0xce718921 +812, 0xa9074ee2 +813, 0xdeb2b4a2 +814, 0x26eb212b +815, 0x5e87a111 +816, 0xc41c4197 +817, 0xbc48ed4e +818, 0x1de24c29 +819, 0x59dc549a +820, 0x6b4399d5 +821, 0xb9860ac5 +822, 0xdf2fc014 +823, 0x260aaa8d +824, 0xdabad253 +825, 0x12e71787 +826, 0x5664c1db +827, 0x6d495c83 +828, 0x79e0b310 +829, 0x368f29e +830, 0x3acdb5bb +831, 0xcbf13e70 +832, 0x6278dc5c +833, 0xd1e6cb57 +834, 0x706e951c +835, 0xa7cfc951 +836, 0x8704efc3 +837, 0xf7800daf +838, 0x5fb19c1b +839, 0x78112b3b +840, 0xdac745fd +841, 0x47df196b +842, 0x4f88a4a2 +843, 0x7e6baeff +844, 0xac2ea7f2 +845, 0x25c3b636 +846, 0xc4d965ee +847, 0x7b69c478 +848, 0xedd5c411 +849, 0x3657cccd +850, 0xbc9445 +851, 0x543d022e +852, 0xd730178b +853, 0x77ab0476 +854, 0xaad88906 +855, 0x30e20b4f +856, 0x6b22eac5 +857, 0x546b82d0 +858, 0xf929bc3a +859, 0xd0b0b99f +860, 0x514df63a +861, 0xfbc7e698 +862, 0xee55f095 +863, 0xda24f02a +864, 0x5ff2707c +865, 0x89827981 +866, 0xb9cc9888 +867, 0x650869c8 +868, 0x4fd63ace +869, 0xd39d2f37 +870, 0xa679e9d8 +871, 0x41704f94 +872, 0xd805ec68 +873, 0xa8c5b428 +874, 0x8da67e50 +875, 0xfd9a0b2d +876, 0x4dad37db +877, 0x5e96adc2 +878, 0xb6def746 +879, 0xc0f62686 +880, 0x48b3cfbc +881, 0xb37fc4b9 +882, 0xa7cf842 +883, 0x6507dc6d +884, 0x6196b146 +885, 0x43c5d8aa +886, 0x60f33402 +887, 0x4414f4ba +888, 0x10e28315 +889, 0xe186ea71 +890, 0xf8b720f6 +891, 0xc91596da +892, 0xcb08553a +893, 0x70089537 +894, 0x8b04e96b +895, 0x3916b464 +896, 0xc6dc1c6 +897, 0x14a76f2f +898, 0xdb04c528 +899, 0xbea612a5 +900, 0xe3676fe5 +901, 0x8a375532 +902, 0x79b1094a +903, 0x82d1bb88 +904, 0xaff5eefd +905, 0x1cb16caf +906, 0x86e420d7 +907, 0x6a84d295 +908, 0xbb861954 +909, 0x8a07d8c4 +910, 0x123ee917 +911, 0x754c2657 +912, 0x740340d9 +913, 0xd59bad68 +914, 0xd64f4821 +915, 0x6f462234 +916, 0x6897df5 +917, 0xc96399fa +918, 0x2d4b464a +919, 0x54b49a +920, 0x3b1ba328 +921, 0x37a28fb3 +922, 0xb870be13 +923, 0xb6f2eca +924, 0x75b05373 +925, 0x7c6ebdde +926, 0x7b6fc55a +927, 0xe386aee +928, 0xbcd168a7 +929, 0x51f8affa +930, 0x284a497b +931, 0xa0b5e79c +932, 0x1f6ae589 +933, 0xb16f5bba +934, 0x98d750d6 +935, 0xe2ecc0fd +936, 0xa73276c4 +937, 0x6a25d164 +938, 0x4f074d9a +939, 0x8daed6a0 +940, 0x505cbbde +941, 0x2abf25b7 +942, 0x6aea0f39 +943, 0x142efd1f +944, 0x8f668dd4 +945, 0xda98e857 +946, 0xb74b0c57 +947, 0x843da941 +948, 0x80c9c03e +949, 0x9dcc37a7 +950, 0xc09b0037 +951, 0x32d52326 +952, 0xe4c9f6bf +953, 0xde872120 +954, 0x2e7b2957 +955, 0xe17b7baa +956, 0x6d32aad0 +957, 0xdfe6c604 +958, 0xc4e497c9 +959, 0xb6208fef +960, 0x88d8f15d +961, 0x9b8b48d5 +962, 0x591c1666 +963, 0xb974dfd4 +964, 0xb880e0dd +965, 0x4a2774ef +966, 0x3a735723 +967, 0x5b580f75 +968, 0x9a988e56 +969, 0x2ea12bfc +970, 0x11995890 +971, 0x48525745 +972, 0xe9d12a00 +973, 0x7dc73054 +974, 0xa2701b3e +975, 0xcc9b116b +976, 0xc438f3ec +977, 0xfe61e77d +978, 0xed2afc8c +979, 0x9468ca59 +980, 0x8d9c84fb +981, 0x4fe77716 +982, 0x39bb1634 +983, 0x4b1e04bb +984, 0xf0dcc50b +985, 0x109f398d +986, 0xd9f23761 +987, 0x348cb388 +988, 0x2c9b1a0f +989, 0x911041ad +990, 0x282e5df9 +991, 0x575a1995 +992, 0x7204304e +993, 0x797d6d3 +994, 0xae7d37c +995, 0x5521a6cf +996, 0x712c3e19 +997, 0x8fb8dbd5 +998, 0x7ded12a7 +999, 0x50a92df2 diff --git a/_randomgen/core_prng/tests/data/threefry32-testset-2.csv b/_randomgen/core_prng/tests/data/threefry32-testset-2.csv new file mode 100644 index 000000000000..b7753638fd04 --- /dev/null +++ b/_randomgen/core_prng/tests/data/threefry32-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 0x0 +0, 0x96bf21c6 +1, 0xa0fe05c7 +2, 0xe1fe280e +3, 0xf35055dc +4, 0x4ec871e3 +5, 0x3bc86276 +6, 0x17a5b958 +7, 0xf49e5388 +8, 0xf7374019 +9, 0x917691a0 +10, 0x448e864 +11, 0x6d3821bc +12, 0x4db62dea +13, 0x4ea93fd4 +14, 0x8a2981e0 +15, 0x6db52782 +16, 0x1391de47 +17, 0x8cbe2e34 +18, 0x6001fa10 +19, 0xa38115ee +20, 0x14199363 +21, 0x934fcba +22, 0xb240df72 +23, 0x6ab87661 +24, 0x60b9d9f5 +25, 0xdbd34621 +26, 0x526af21d +27, 0x1a6b4bf5 +28, 0xd7173663 +29, 0xdce2b053 +30, 0x62080540 +31, 0xe1c3dd3e +32, 0x33ae037a +33, 0xe602063e +34, 0x5ea0ec41 +35, 0xf0313701 +36, 0xa41e72c +37, 0x291889ad +38, 0x6eb6b020 +39, 0x4d623617 +40, 0x5a1574d7 +41, 0x78d45c73 +42, 0xeb9e4d3c +43, 0xe4775f83 +44, 0x89f67a5 +45, 0xcaa0ac99 +46, 0x6caee87b +47, 0x5cafd04e +48, 0x9717a3a0 +49, 0xd6be9166 +50, 0x1288e672 +51, 0x6dfe4ec3 +52, 0x3bb56a74 +53, 0x58582a09 +54, 0x44c7519a +55, 0x17500801 +56, 0xdddc251 +57, 0xc32bf7a8 +58, 0x6f79b324 +59, 0x8a6f971d +60, 0x246d519e +61, 0xda4d3a03 +62, 0x9bed7502 +63, 0xe3dc760a +64, 0x35eb67da +65, 0x717b6e2c +66, 0xe540553b +67, 0xa8ffd00e +68, 0xc7f801c2 +69, 0x2b762e33 +70, 0x420e2c94 +71, 0x8c339dfa +72, 0x99f694f8 +73, 0x217f423a +74, 0x1fd8e09f +75, 0xb3f76cd2 +76, 0x1cee1308 +77, 0xc83f9c45 +78, 0xd48e24a1 +79, 0xb779cf03 +80, 0x1e042002 +81, 0x8f18d559 +82, 0x9d5e185d +83, 0xe2ca5f65 +84, 0x13f56ff3 +85, 0x20fd0f05 +86, 0x201f99ab +87, 0x331c3df5 +88, 0xbaba8549 +89, 0xc6f7306 +90, 0x2b360412 +91, 0x31043048 +92, 0x959c617f +93, 0xadf28e64 +94, 0xfc5b23e6 +95, 0x70e6b601 +96, 0x6bb34693 +97, 0x1fddbf26 +98, 0x7cd372db +99, 0x695ed6f3 +100, 0xc5a37f9a +101, 0x575aba37 +102, 0x74ae0700 +103, 0x8443b8e9 +104, 0x4157dfc0 +105, 0x150dc093 +106, 0x3f7d86 +107, 0x5a11d745 +108, 0x26e3530b +109, 0x2700974b +110, 0x3f395b3c +111, 0x32dc070 +112, 0x7816fd58 +113, 0xf11f39b0 +114, 0xb1bdb3ae +115, 0x933c37a +116, 0x9621e2b +117, 0x6aa61ac8 +118, 0xea05ee84 +119, 0x9e481f10 +120, 0xbc5f31b4 +121, 0x4c29115c +122, 0xcc492bf4 +123, 0xe8f67fb +124, 0xcf9ef4d6 +125, 0xde0d0e81 +126, 0x7b673c75 +127, 0xad3fe9ed +128, 0xbee239e9 +129, 0x1e087877 +130, 0x912eee8a +131, 0x2f55f5ee +132, 0xd0fa0da0 +133, 0xa14fb442 +134, 0xd86b0234 +135, 0x7b1d72db +136, 0x919aa862 +137, 0xfa0196ec +138, 0x30e35f2d +139, 0xa907b642 +140, 0x537204fa +141, 0x8ef7f10d +142, 0x3625e260 +143, 0x5b4d7d73 +144, 0x436729fd +145, 0x8c52723 +146, 0xcde668bd +147, 0xe1d74aa2 +148, 0x73e380e2 +149, 0x19d2f3b4 +150, 0x693d2c4d +151, 0xf1ee106 +152, 0x110b4a39 +153, 0x367df2b2 +154, 0x603b9495 +155, 0xf1fe7afb +156, 0xe77de62d +157, 0xfb68fae5 +158, 0x235b3ef5 +159, 0xc4bdad24 +160, 0xb57f08f3 +161, 0x195a8e95 +162, 0x29f1a9de +163, 0x8d4c905f +164, 0x1419c72e +165, 0x8944437d +166, 0x13587ab7 +167, 0x8c2c89f0 +168, 0xc5446300 +169, 0x7d4dbbd1 +170, 0xb4ce733 +171, 0x2e106d +172, 0x1aecbeb2 +173, 0xd6e885e3 +174, 0x8a0969e0 +175, 0x402a5a80 +176, 0x963d7b5f +177, 0x366051e9 +178, 0x9221f52e +179, 0x3922be06 +180, 0x3f3ea09c +181, 0xb4c67478 +182, 0xa582bfad +183, 0xd8190211 +184, 0x1a5bdcca +185, 0x438d1ac +186, 0x91e68cc7 +187, 0xb584a426 +188, 0x248e2953 +189, 0xff061284 +190, 0x14204e87 +191, 0x41be6ee6 +192, 0xd28c68e9 +193, 0x7c1a6cb2 +194, 0x3dfb5acc +195, 0x9350bf13 +196, 0x633a5ea +197, 0x4e2d241b +198, 0x5a4878f1 +199, 0x775a7a87 +200, 0x7d1538fa +201, 0x43f49533 +202, 0xafc96ab9 +203, 0xe08e3b31 +204, 0xe5f234ff +205, 0x91953358 +206, 0x45cf4358 +207, 0x8070f40f +208, 0x61140fa4 +209, 0xb56542bc +210, 0x3def3833 +211, 0x3afcb202 +212, 0x9ddad97e +213, 0x364f535a +214, 0x722d4445 +215, 0x292e4364 +216, 0x708a1fda +217, 0x9ddb0c16 +218, 0xf3a27c5e +219, 0x18acae39 +220, 0x93e92f61 +221, 0x3e2fa33 +222, 0x878d11f3 +223, 0x61a220a9 +224, 0x4a649d1f +225, 0x394c9f4b +226, 0x9e7c84ad +227, 0xf7fd62c4 +228, 0xcbb4ba39 +229, 0x5eadd8c1 +230, 0x720fa83c +231, 0x64c36bf9 +232, 0x574d17c3 +233, 0x8cdf6eec +234, 0x7638f112 +235, 0xa9c131ce +236, 0x4466a7e0 +237, 0x5e932445 +238, 0xe504370f +239, 0xed84b1c +240, 0x216bd3f5 +241, 0xe8068a58 +242, 0xa15bcde9 +243, 0xee5dbcce +244, 0x413e0b5e +245, 0xfe3255f6 +246, 0x5d9816d0 +247, 0xbcd5a8a0 +248, 0x49ef0ff6 +249, 0x872570c1 +250, 0x3ca3bb8b +251, 0xc4b4d57d +252, 0x25d109b5 +253, 0x5c750b00 +254, 0xc46b7428 +255, 0x2484eda +256, 0xd4c33354 +257, 0x38bb7d44 +258, 0x113da842 +259, 0xb86e73d7 +260, 0x134b9007 +261, 0x672857a +262, 0x7e1f4f33 +263, 0x6c562447 +264, 0x8e592c4b +265, 0x32d2c0b9 +266, 0x5c734488 +267, 0x52acf2d5 +268, 0xfcb64a7f +269, 0xe2ab9d6a +270, 0x18dde6a7 +271, 0xa518ca9c +272, 0x12c92fce +273, 0x9bed83a6 +274, 0x8a78b026 +275, 0x946d9163 +276, 0xddddd15e +277, 0x4d80628c +278, 0x4c6feb7f +279, 0x8f775fbc +280, 0xb1a8e3b +281, 0x3809bc2d +282, 0xd2c72be8 +283, 0x4b481760 +284, 0xc2e72e75 +285, 0x8f37c5ea +286, 0x7307ed25 +287, 0xdc14b350 +288, 0xb2c286f2 +289, 0xa050d102 +290, 0x2f114a3a +291, 0xc27c7a7b +292, 0xdea01eb +293, 0x932cf59d +294, 0xcf4d5b30 +295, 0x86b6bbbf +296, 0x2b290705 +297, 0xabebd181 +298, 0x702ddf78 +299, 0xf4ca859d +300, 0x2020e833 +301, 0x217f3e4 +302, 0x7f0e8cbd +303, 0x7904900 +304, 0x77cb8b6 +305, 0x5daffd7 +306, 0xb6f1a28c +307, 0xfc3a016f +308, 0x61c54f36 +309, 0x27061341 +310, 0xcff54873 +311, 0x4e9690f9 +312, 0x4836fd91 +313, 0x17166086 +314, 0x5bee87b9 +315, 0x1824513f +316, 0x2e121297 +317, 0xeb6700d +318, 0x131ba5ed +319, 0xadef4e19 +320, 0x6b4f51ad +321, 0x35361ab8 +322, 0x5663d841 +323, 0xb2f164a2 +324, 0x402d76f +325, 0xafbd20c0 +326, 0xf8876253 +327, 0x2bf3b986 +328, 0x9f91ddf8 +329, 0xf2b9da4c +330, 0xaa14c7e4 +331, 0xe15cf29b +332, 0x357f2012 +333, 0x4561ab12 +334, 0x1bc5dff3 +335, 0xf07dad88 +336, 0xdd3cc715 +337, 0xe560ac91 +338, 0x8b9475e3 +339, 0xd181c80f +340, 0x55d1cd2c +341, 0x11d425f6 +342, 0x2ca6b58f +343, 0x21b3ad57 +344, 0x1754cd75 +345, 0x90a8050e +346, 0x72e84c22 +347, 0x96dd5f3d +348, 0x6044db23 +349, 0x63434074 +350, 0x6bd5b611 +351, 0xd72ae77c +352, 0xc82da625 +353, 0x7e98cda9 +354, 0x276e09ff +355, 0x24a72915 +356, 0xac1f8749 +357, 0x8c5d96fc +358, 0x322933ef +359, 0x6e8fd47 +360, 0x931acda0 +361, 0x6a714821 +362, 0xfa5ee5c +363, 0x48e64ef0 +364, 0xd8e3e670 +365, 0x4b30496f +366, 0x56959138 +367, 0x121fa62a +368, 0x927f7b6e +369, 0xdee500 +370, 0x38fb7e0c +371, 0x17708fb1 +372, 0xd55c07be +373, 0x2e18a475 +374, 0x431d85a7 +375, 0xa405d3f8 +376, 0x5de38b47 +377, 0x96f6b788 +378, 0xd0f84145 +379, 0xd2392752 +380, 0x44a6566c +381, 0xb3d46be3 +382, 0xc8c9dc5f +383, 0xa952122d +384, 0x197d11c9 +385, 0xa135e6e2 +386, 0xd9d91bbb +387, 0xf4b56186 +388, 0x3cb621ba +389, 0xb572252f +390, 0x8668224e +391, 0x44cb5619 +392, 0xa68bb5c8 +393, 0x224639d9 +394, 0xde35e870 +395, 0x3df1148 +396, 0x21fe35fa +397, 0xccfaffb5 +398, 0x18add490 +399, 0x8126b15e +400, 0xbfd69b4e +401, 0x216fd33a +402, 0x932589c0 +403, 0xabbdd53 +404, 0x1ded816b +405, 0xad0c1ff0 +406, 0x6a5f7a8d +407, 0xcb3e1d5e +408, 0xa8559680 +409, 0xfad440ef +410, 0xdc3e4a27 +411, 0xd1606be4 +412, 0x9e8b03ea +413, 0xf3a38fb8 +414, 0x9cab22b +415, 0x4d25b615 +416, 0xc46114c6 +417, 0xa2726196 +418, 0x65ecb782 +419, 0x79439d3c +420, 0x69ab8d82 +421, 0x216184d2 +422, 0xab262a47 +423, 0xecee9422 +424, 0xa3c1674e +425, 0x357992aa +426, 0x44278f94 +427, 0x4c12fab +428, 0x7740f7fc +429, 0x944222fd +430, 0xc251348 +431, 0x83b629f8 +432, 0x4b594fa0 +433, 0x51d6a9ab +434, 0x830bef86 +435, 0xe250fac1 +436, 0xfde9e381 +437, 0x9e22470a +438, 0x8653c37 +439, 0xd7ec4710 +440, 0xa698bf59 +441, 0x4bf8a5fe +442, 0xbb9fd26 +443, 0xd3cc40d +444, 0xcc1d24da +445, 0x8100b99c +446, 0x199a71bd +447, 0x77464e71 +448, 0x65556a05 +449, 0x1c713ff +450, 0x99c9edc3 +451, 0xa1a0a60d +452, 0x4cf77f1e +453, 0x407ffa53 +454, 0xcebf9b42 +455, 0x2228074e +456, 0x29332ee0 +457, 0x66b2c926 +458, 0x8c7b4df3 +459, 0xd1968179 +460, 0xde7124c9 +461, 0x6d8abf4e +462, 0x25d0af4c +463, 0x65e6fbf4 +464, 0xf8c9d76a +465, 0x5b39bce9 +466, 0x1e9dda4f +467, 0x99dfa42 +468, 0x11531373 +469, 0x5e387ef +470, 0xb474e29a +471, 0xff1d322d +472, 0x3de7e402 +473, 0xb3e2a619 +474, 0xac6f3b84 +475, 0x32650d1d +476, 0x854d9bd7 +477, 0x177d6cf2 +478, 0x64cbb5f7 +479, 0x9a86778 +480, 0x6e1277ef +481, 0xfb4c2f35 +482, 0x1e1931a8 +483, 0x8c66d53 +484, 0xb60870e0 +485, 0xb27759f3 +486, 0x525bfba8 +487, 0xea4b4ac0 +488, 0xb8d944a3 +489, 0xee27be58 +490, 0x506d723f +491, 0x5ceb9607 +492, 0x91efc140 +493, 0x799cb2c5 +494, 0x30c9a8a0 +495, 0x5f03f36 +496, 0xed6ade24 +497, 0xfaaa5117 +498, 0x9174a363 +499, 0x4eef8150 +500, 0x1eec4b8e +501, 0x39901de7 +502, 0xf92f40a3 +503, 0xaa1d14 +504, 0xb9313106 +505, 0xb68676ea +506, 0x6f11d728 +507, 0x66c59d63 +508, 0xb09e79f9 +509, 0x68d29514 +510, 0x9deedf1d +511, 0xfd972780 +512, 0x9bf1cbbd +513, 0x18c1f79 +514, 0x5fed1afe +515, 0xd7a51fc6 +516, 0x2eae8dbb +517, 0xf293e112 +518, 0x1e437bbb +519, 0x5e3d390e +520, 0xbcced217 +521, 0x55d23765 +522, 0xa02aa678 +523, 0xec96a24a +524, 0x29e500a8 +525, 0x98b8a4d2 +526, 0x8c2d9136 +527, 0xe65dec90 +528, 0x3eba15de +529, 0x3c25ef33 +530, 0xdbca90a6 +531, 0x4f09311d +532, 0x990e05c6 +533, 0x54679cf9 +534, 0x8d0ae2b3 +535, 0xa33b8506 +536, 0xf5437070 +537, 0x887fe2ad +538, 0x906a30e0 +539, 0xb2b464f4 +540, 0x415c3577 +541, 0x6057c5c0 +542, 0x70cc0f44 +543, 0x9b2fb077 +544, 0x7336a7f3 +545, 0x9068d9ec +546, 0xc5057d25 +547, 0x705d52e7 +548, 0x6a4aca4c +549, 0x2dadbe60 +550, 0x9c59fba4 +551, 0x791bd0ac +552, 0x11299194 +553, 0xb21a9f2d +554, 0x30aa87c3 +555, 0xede7a398 +556, 0xeece9bb0 +557, 0x38f46a57 +558, 0xb69cd5a8 +559, 0xa04d6d8e +560, 0x42db338f +561, 0x933948d9 +562, 0xb8c1b512 +563, 0x9915f7a2 +564, 0xf0467ab7 +565, 0xc43a5426 +566, 0x53e1470c +567, 0x60c764c7 +568, 0x676c6da5 +569, 0xace51d51 +570, 0x240628e7 +571, 0x3f0c776 +572, 0x7185d397 +573, 0x4209e930 +574, 0xcd75c0db +575, 0x3917fb29 +576, 0x3c95c879 +577, 0x10e9bb04 +578, 0x63a072ce +579, 0x39401a04 +580, 0x6ea9edc1 +581, 0xe4008fe0 +582, 0xebf2bf0d +583, 0x760c3233 +584, 0x7b8edd5f +585, 0xfd632b63 +586, 0x863a8155 +587, 0x9e5dcf41 +588, 0x374dc183 +589, 0xe6279dcf +590, 0x3a802f +591, 0xa17e7cb5 +592, 0x773a8161 +593, 0xda344f6a +594, 0x86a50b9 +595, 0x2defa7cb +596, 0x87b49d8 +597, 0x2169b33c +598, 0x2e1f1748 +599, 0x7d10a959 +600, 0x86fe64a6 +601, 0x9fd5b948 +602, 0xaad08122 +603, 0x1a2a52a3 +604, 0xeede4a8f +605, 0x17117e8 +606, 0xa4650709 +607, 0x2ce293d1 +608, 0x5d1cf4ee +609, 0x94b23094 +610, 0x150f50ff +611, 0x7beeeefa +612, 0xa0baf1db +613, 0x363a69f2 +614, 0x5a67965 +615, 0x9e014734 +616, 0xb7313d3e +617, 0x6e070b62 +618, 0x4fc9b70f +619, 0x455a5d8b +620, 0x21c94a8a +621, 0x203853dc +622, 0x79e0dde1 +623, 0x68b11257 +624, 0x888bb806 +625, 0xa7e9178e +626, 0x8022be3 +627, 0xc550db7b +628, 0xa8f3f180 +629, 0xd28c1484 +630, 0x955445a5 +631, 0xc84c1609 +632, 0x71463ea6 +633, 0x20962712 +634, 0xf9a074 +635, 0xae59fb67 +636, 0x5bf0a427 +637, 0x165146c2 +638, 0xb08ec935 +639, 0x20cfa297 +640, 0x8492faa8 +641, 0xa1f3cf65 +642, 0x646479a9 +643, 0xb035174e +644, 0xb3b039f8 +645, 0x7780d61b +646, 0x63754f94 +647, 0x286565d0 +648, 0x10e13878 +649, 0x145f546f +650, 0xd857539 +651, 0xd8db00e8 +652, 0xc092dc9e +653, 0xb835b8bf +654, 0xe207b116 +655, 0x7961075d +656, 0x5e50116b +657, 0x355bf5c1 +658, 0x897dde54 +659, 0xc505a279 +660, 0x729aaf7c +661, 0xdfb9f60c +662, 0xdb75db2e +663, 0x520f947d +664, 0x6847c154 +665, 0x69a24a1a +666, 0xecf825c7 +667, 0x8b4da35b +668, 0x71e73004 +669, 0xaa594a1c +670, 0x70f6260e +671, 0x73b565a +672, 0xf050bb33 +673, 0xd9409845 +674, 0x32354d60 +675, 0xabed3745 +676, 0x1995883 +677, 0x6418b501 +678, 0x6a96c78c +679, 0xece6bffc +680, 0xc3892389 +681, 0xf1fa0e62 +682, 0x59a93622 +683, 0xac1d1798 +684, 0x8b1984b4 +685, 0x2603f602 +686, 0x4fdd2d48 +687, 0xaa57c8af +688, 0x49735a97 +689, 0x73075464 +690, 0x75647208 +691, 0xe88930a0 +692, 0x4c51d399 +693, 0x86904118 +694, 0x62af2995 +695, 0x4c62090e +696, 0x7319e53 +697, 0xb11c255c +698, 0xa9fb903f +699, 0xc602439b +700, 0x447eb0a4 +701, 0x9b602006 +702, 0xa6583b9a +703, 0xc33d5e64 +704, 0xf945c9be +705, 0x1199ecfc +706, 0x58ca9756 +707, 0xc0f98006 +708, 0x7694cb6e +709, 0x537b5f33 +710, 0x5ad022df +711, 0xc23ae783 +712, 0xf27d584c +713, 0x3410e1d4 +714, 0xc69867f2 +715, 0x239cb4fc +716, 0xedeffd68 +717, 0x9cc9e0be +718, 0xb44585c7 +719, 0xf811df78 +720, 0x32e3779c +721, 0x495830a7 +722, 0xb5c7ecb2 +723, 0x8583521a +724, 0x26cd0f3f +725, 0x7f79bf6e +726, 0xf63c2afa +727, 0xabbf2df3 +728, 0x90cead53 +729, 0xdac401a +730, 0x76d10bb8 +731, 0xa7a6a87e +732, 0x3f7783c1 +733, 0x2cdf71e0 +734, 0xb7e5ebfb +735, 0xa5eb1c64 +736, 0xfa462a94 +737, 0x92e33c33 +738, 0xb1f5f201 +739, 0xb58b1587 +740, 0x212b9bbf +741, 0x63938326 +742, 0xd7562019 +743, 0x9e1974ea +744, 0x670c615b +745, 0x62460641 +746, 0x9be46c7e +747, 0x34421fab +748, 0xe722475c +749, 0x8e6170aa +750, 0xfa68a479 +751, 0xb77324b0 +752, 0xa64c0f97 +753, 0x5183720b +754, 0xf3160e77 +755, 0x23a3b269 +756, 0x9d7b11d1 +757, 0x3cfbefd4 +758, 0x1fe0e235 +759, 0x910ebbce +760, 0x84eae93d +761, 0xe390b082 +762, 0xce29298f +763, 0xe7e718c7 +764, 0x7adc4e73 +765, 0xc3c5dae4 +766, 0x685c0b9b +767, 0xa5ed9a8 +768, 0x5a2ccb4a +769, 0x3c94fa33 +770, 0xdc8726ef +771, 0x92121728 +772, 0xe2c57ec6 +773, 0x522712e1 +774, 0xec5e6145 +775, 0xe486d06c +776, 0x1ef7fa3a +777, 0xd3e8ac09 +778, 0xca770944 +779, 0xd490c429 +780, 0x5b626100 +781, 0x973f8555 +782, 0x5b690d01 +783, 0x3ba958c1 +784, 0xa4b3f08c +785, 0x6760f219 +786, 0x59bac764 +787, 0xb1c54d52 +788, 0xcb4aa641 +789, 0x2d6c9a4e +790, 0xebd48ef +791, 0xee3109d4 +792, 0xd286c88e +793, 0xfd26fd0f +794, 0x450825c5 +795, 0xaa1a4313 +796, 0xb07511ed +797, 0xb2836487 +798, 0x900cd63b +799, 0x2345cfa0 +800, 0xc6de4d20 +801, 0xf57de173 +802, 0x24890b60 +803, 0x522ce8c2 +804, 0xb70a8eb2 +805, 0x358ee7a +806, 0x6a29365c +807, 0x402f9666 +808, 0x6889332c +809, 0x21e55b7e +810, 0x8c886218 +811, 0x943ce0c2 +812, 0x637f3dcc +813, 0x336ceaef +814, 0x65d94c0d +815, 0x2e07516c +816, 0x7b03d97a +817, 0x5d0dd1ce +818, 0x98e27a9f +819, 0x329e3e00 +820, 0xa758619e +821, 0xf2401413 +822, 0xc73c21d2 +823, 0xa7f97da5 +824, 0x397c2e9c +825, 0x9511ed82 +826, 0x824760e6 +827, 0x2391d3c2 +828, 0x7ca7092c +829, 0xbb63f94 +830, 0xa7370c1d +831, 0x61a44ce8 +832, 0xfdf08bf1 +833, 0x5dba1ae3 +834, 0x72a21633 +835, 0x2239c7fe +836, 0xfbcc7e2 +837, 0xe2f724d7 +838, 0x69223ca3 +839, 0xd7759240 +840, 0xbdeda501 +841, 0x413c2cf0 +842, 0xbc7e5c63 +843, 0x339f3ef9 +844, 0x95749faf +845, 0xb1ac835 +846, 0x866fb03a +847, 0x90873b55 +848, 0x59c09bd6 +849, 0x180f8d78 +850, 0x729bf2a0 +851, 0x13a32fe6 +852, 0x62dd49a5 +853, 0x9eecb212 +854, 0x258d30e8 +855, 0x2153d968 +856, 0xaba5083a +857, 0x726aaf8e +858, 0x512c3192 +859, 0x62414d +860, 0x48fa16b8 +861, 0xf761e7e4 +862, 0xf6012be7 +863, 0x77dff028 +864, 0xd21abf72 +865, 0xed2f995f +866, 0x69cee22 +867, 0x54200535 +868, 0xd883594c +869, 0x28b475e6 +870, 0xe0a2038c +871, 0x1b56c6e1 +872, 0x7220704 +873, 0xf842418 +874, 0x90aa400 +875, 0x941b5975 +876, 0x576d964d +877, 0x93ef2176 +878, 0xd9562201 +879, 0xf7433ac +880, 0x23ede5c7 +881, 0xfadf3362 +882, 0x769830d1 +883, 0x21ee4b1e +884, 0x6c60a5f8 +885, 0xf42ec278 +886, 0x5ac46157 +887, 0xc527c639 +888, 0xdbbbb7bc +889, 0xcbf79715 +890, 0x26384600 +891, 0x9cdfad11 +892, 0x60815d7a +893, 0x20bcf98a +894, 0x4652d4ba +895, 0x7ea46112 +896, 0x7c560e8d +897, 0xbeb3e89d +898, 0xb861dd4 +899, 0xe1d4189c +900, 0xe83ea3e5 +901, 0x92393c2b +902, 0xdd6bbf3d +903, 0x620a691a +904, 0xdb64b940 +905, 0x5fbadf2d +906, 0x1ce81d5f +907, 0x4b20d0d7 +908, 0x53ea3105 +909, 0xf350f9fc +910, 0xd04736d8 +911, 0x358e8630 +912, 0x18fb3a7d +913, 0x8633154e +914, 0xf48a9fec +915, 0x98c40cb2 +916, 0x98596dac +917, 0xb5e16a27 +918, 0x1834670b +919, 0x3e8cf415 +920, 0x6e6ba2b8 +921, 0xfa5cddae +922, 0x77032bac +923, 0x97b9e6c +924, 0x3ffc2aa1 +925, 0x879b53a +926, 0xbbf693b5 +927, 0x971efbd3 +928, 0x9ab6ad89 +929, 0x160d498a +930, 0x66cebdce +931, 0x4fb855c0 +932, 0x68558584 +933, 0xa695f564 +934, 0xebea0104 +935, 0xb349d0b1 +936, 0xb27c5871 +937, 0xd4965433 +938, 0x3b48325d +939, 0x816851ad +940, 0xa7328098 +941, 0x307cdf7c +942, 0xfacb2352 +943, 0xac2ded57 +944, 0xd01efb86 +945, 0x9e039163 +946, 0xb9e02f +947, 0xd18c1916 +948, 0xef4380f0 +949, 0x1c578bcf +950, 0x737f6c89 +951, 0x47dd10af +952, 0x459bbd41 +953, 0xf0c0a4ff +954, 0xc2166f81 +955, 0x4ffabd22 +956, 0x89731a04 +957, 0x989a031a +958, 0x941ed188 +959, 0xa77ec4d9 +960, 0x3e6ca8e5 +961, 0x238e5fe7 +962, 0x2ac9b71b +963, 0x95a0d1be +964, 0xfc56dbaf +965, 0xbb5a4378 +966, 0x4cc6e834 +967, 0x36175364 +968, 0xb097fbe3 +969, 0xea1466d4 +970, 0x317733fc +971, 0xeb88ef75 +972, 0xb82570c6 +973, 0x2b8adfa2 +974, 0xd7a86699 +975, 0x6d13d28f +976, 0x6dd2c41b +977, 0x92d733e6 +978, 0x928f31a5 +979, 0xfe7c01bd +980, 0x62a1bc47 +981, 0x47d9b6e1 +982, 0xae6f97a4 +983, 0xbdaed100 +984, 0xbb24138 +985, 0xa6f1819 +986, 0xdc5f99a +987, 0xc5b5b978 +988, 0xdfb7fc81 +989, 0xc82744ca +990, 0xbdd30239 +991, 0x6c11d175 +992, 0x3910ed7a +993, 0x6b9efa62 +994, 0x29a9dd01 +995, 0x492afa85 +996, 0x151b62e8 +997, 0x2546c48d +998, 0x3cb52c7c +999, 0x8fc96435 diff --git a/_randomgen/core_prng/tests/test_against_numpy.py b/_randomgen/core_prng/tests/test_against_numpy.py index 6bd4bc0912ac..9f0cfe054fa0 100644 --- a/_randomgen/core_prng/tests/test_against_numpy.py +++ b/_randomgen/core_prng/tests/test_against_numpy.py @@ -240,7 +240,7 @@ def test_logseries(self): is_small=True) self._is_state_common() - def test_zipf(self): + def test_geometric(self): self._set_common_state() self._is_state_common() compare_1_input(self.nprs.geometric, @@ -376,7 +376,6 @@ def test_rand(self): assert_allclose(f(10), g(10)) assert_allclose(f(3, 4, 5), g(3, 4, 5)) - @pytest.mark.xfail def test_poisson_lam_max(self): assert_allclose(self.rg.poisson_lam_max, self.nprs.poisson_lam_max) diff --git a/_randomgen/core_prng/tests/test_direct.py b/_randomgen/core_prng/tests/test_direct.py index 9496cc1916f9..61dafdcaa924 100644 --- a/_randomgen/core_prng/tests/test_direct.py +++ b/_randomgen/core_prng/tests/test_direct.py @@ -6,7 +6,8 @@ from numpy.testing import assert_equal, assert_allclose, assert_array_equal, \ assert_raises -from core_prng import * +from core_prng import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ + PCG64, Philox, Xoroshiro128, Xorshift1024 if (sys.version_info > (3, 0)): long = int @@ -250,6 +251,31 @@ def setup_class(cls): cls.seed_error_type = TypeError +class TestPCG64(Base): + @classmethod + def setup_class(cls): + cls.prng = PCG64 + cls.bits = 64 + cls.dtype = np.uint64 + cls.data1 = cls._read_csv(join(pwd, './data/pcg64-testset-1.csv')) + cls.data2 = cls._read_csv(join(pwd, './data/pcg64-testset-2.csv')) + cls.seed_error_type = TypeError + + def test_seed_float_array(self): + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(self.seed_error_type, rs.seed, np.array([np.pi])) + assert_raises(self.seed_error_type, rs.seed, np.array([-np.pi])) + assert_raises(self.seed_error_type, rs.seed, np.array([np.pi, -np.pi])) + assert_raises(self.seed_error_type, rs.seed, np.array([0, np.pi])) + assert_raises(self.seed_error_type, rs.seed, [np.pi]) + assert_raises(self.seed_error_type, rs.seed, [0, np.pi]) + + def test_seed_out_of_range_array(self): + rs = RandomGenerator(self.prng(*self.data1['seed'])) + assert_raises(self.seed_error_type, rs.seed, [2 ** (2 * self.bits + 1)]) + assert_raises(self.seed_error_type, rs.seed, [-1]) + + class TestPhilox(Base): @classmethod def setup_class(cls): @@ -316,7 +342,6 @@ def setup_class(cls): def test_uniform_double(self): rs = RandomGenerator(self.prng(*self.data1['seed'])) - aa = uniform_from_dsfmt(self.data1['data']) assert_array_equal(uniform_from_dsfmt(self.data1['data']), rs.random_sample(1000)) @@ -371,3 +396,14 @@ def test_uniform_float(self): uniforms = rs.random_sample(len(vals), dtype=np.float32) assert_allclose(uniforms, vals) assert_equal(uniforms.dtype, np.float32) + + +class TestThreeFry32(Base): + @classmethod + def setup_class(cls): + cls.prng = ThreeFry32 + cls.bits = 32 + cls.dtype = np.uint32 + cls.data1 = cls._read_csv(join(pwd, './data/threefry32-testset-1.csv')) + cls.data2 = cls._read_csv(join(pwd, './data/threefry32-testset-2.csv')) + cls.seed_error_type = TypeError diff --git a/_randomgen/core_prng/tests/test_numpy_mt19937.py b/_randomgen/core_prng/tests/test_numpy_mt19937.py index 3fa936f2f3c1..5097f82bd355 100644 --- a/_randomgen/core_prng/tests/test_numpy_mt19937.py +++ b/_randomgen/core_prng/tests/test_numpy_mt19937.py @@ -1526,9 +1526,8 @@ def test_negative_binomial(self): assert_raises(ValueError, neg_binom, n, bad_p_one * 3) assert_raises(ValueError, neg_binom, n, bad_p_two * 3) - @pytest.mark.xfail def test_poisson(self): - max_lam = random.RandomState().poisson_lam_max + max_lam = random.poisson_lam_max lam = [1] bad_lam_one = [-1] diff --git a/_randomgen/core_prng/tests/test_smoke.py b/_randomgen/core_prng/tests/test_smoke.py index a5678dbaa406..929fd1e9f0ca 100644 --- a/_randomgen/core_prng/tests/test_smoke.py +++ b/_randomgen/core_prng/tests/test_smoke.py @@ -1,18 +1,21 @@ +import os import pickle -import time import sys -import os +import time + import numpy as np import pytest +from numpy.testing import assert_almost_equal, assert_equal, assert_, \ + assert_array_equal -from core_prng import * +from core_prng import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ + PCG64, Philox, Xoroshiro128, Xorshift1024 from core_prng import entropy -from numpy.testing import assert_almost_equal, assert_equal, assert_raises, assert_, assert_array_equal - -@pytest.fixture(scope='module', params=(np.bool, np.int8, np.int16, np.int32, np.int64, - np.uint8, np.uint16, np.uint32, np.uint64)) +@pytest.fixture(scope='module', + params=(np.bool, np.int8, np.int16, np.int32, np.int64, + np.uint8, np.uint16, np.uint32, np.uint64)) def dtype(request): return request.param @@ -71,7 +74,8 @@ def comp_state(state1, state2): elif type(state1) != type(state2): identical &= type(state1) == type(state2) else: - if (isinstance(state1, (list, tuple, np.ndarray)) and isinstance(state2, (list, tuple, np.ndarray))): + if (isinstance(state1, (list, tuple, np.ndarray)) and isinstance( + state2, (list, tuple, np.ndarray))): for s1, s2 in zip(state1, state2): identical &= comp_state(s1, s2) else: @@ -128,7 +132,7 @@ def test_jump(self): self.rg.jump() jumped_state = self.rg.state assert_(not comp_state(state, jumped_state)) - self.rg.random_sample(2*3*5*7*11*13*17) + self.rg.random_sample(2 * 3 * 5 * 7 * 11 * 13 * 17) self.rg.state = state self.rg.jump() rejumped_state = self.rg.state @@ -206,8 +210,6 @@ def test_reset_state(self): def test_entropy_init(self): rg = RandomGenerator(self.prng()) rg2 = RandomGenerator(self.prng()) - s1 = rg.state - s2 = rg2.state assert_(not comp_state(rg.state, rg2.state)) def test_seed(self): @@ -270,7 +272,7 @@ def test_tomaxint(self): else: try: maxsize = sys.maxint - except: + except AttributeError: maxsize = sys.maxsize if maxsize < 2 ** 32: assert_((vals < sys.maxsize).all()) @@ -311,7 +313,8 @@ def test_complex_normal(self): self.rg.state = st vals3 = self.rg.complex_normal( - 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j, method='zig') + 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j, + method='zig') np.testing.assert_allclose(vals, vals3) self.rg.state = st @@ -322,7 +325,8 @@ def test_complex_normal(self): v_imag = 2.5 rho = cov / np.sqrt(v_real * v_imag) imag = 7 + np.sqrt(v_imag) * (rho * - norms[:, 0] + np.sqrt(1 - rho ** 2) * norms[:, 1]) + norms[:, 0] + np.sqrt(1 - rho ** 2) * + norms[:, 1]) real = 2 + np.sqrt(v_real) * norms[:, 0] vals4 = [re + im * (0 + 1.0j) for re, im in zip(real, imag)] @@ -341,7 +345,8 @@ def test_complex_normal_bm(self): self.rg.state = st vals3 = self.rg.complex_normal( - 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j, method='bm') + 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j, + method='bm') np.testing.assert_allclose(vals, vals3) def test_complex_normal_zero_variance(self): @@ -541,12 +546,6 @@ def test_pickle(self): assert_((type(self.rg) == type(unpick))) assert_(comp_state(self.rg.state, unpick.state)) - @pytest.mark.xfail - def test_version(self): - state = self.rg.state - assert_('version' in state) - assert_(state['version'] == 0) - def test_seed_array(self): if self.seed_vector_bits is None: pytest.skip() @@ -790,11 +789,13 @@ def test_randint_broadcast(self, dtype): assert_equal(a, c) self._reset_state() d = self.rg.randint(np.array( - [lower] * 10), np.array([upper], dtype=np.object), size=10, dtype=dtype) + [lower] * 10), np.array([upper], dtype=np.object), size=10, + dtype=dtype) assert_equal(a, d) self._reset_state() e = self.rg.randint( - np.array([lower] * 10), np.array([upper] * 10), size=10, dtype=dtype) + np.array([lower] * 10), np.array([upper] * 10), size=10, + dtype=dtype) assert_equal(a, e) self._reset_state() @@ -846,18 +847,16 @@ def setup_class(cls): cls._extra_setup() cls.seed_error = ValueError - @pytest.mark.xfail def test_numpy_state(self): - # TODO: Do we want lagacy state support nprg = np.random.RandomState() nprg.standard_normal(99) - state = nprg.state + state = nprg.get_state() self.rg.state = state state2 = self.rg.state - assert_((state[1] == state2['state'][0]).all()) - assert_((state[2] == state2['state'][1])) - assert_((state[3] == state2['gauss']['has_gauss'])) - assert_((state[4] == state2['gauss']['gauss'])) + assert_((state[1] == state2['state']['key']).all()) + assert_((state[2] == state2['state']['pos'])) + assert_((state[3] == state2['has_gauss'])) + assert_((state[4] == state2['gauss'])) class TestPCG64(RNG): @@ -957,6 +956,19 @@ def setup_class(cls): cls.seed_vector_bits = 32 +class TestThreeFry32(RNG): + @classmethod + def setup_class(cls): + cls.prng = ThreeFry32 + cls.advance = [2 ** 96 + 2 ** 16 + 2 ** 5 + 1] + cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] + cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = 64 + cls._extra_setup() + cls.seed_error = ValueError + + class TestEntropy(object): def test_entropy(self): e1 = entropy.random_entropy() diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index 99c7027734a3..4cf50e3e7669 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -33,7 +33,7 @@ cdef extern from 'src/threefry/threefry.h': ctypedef s_threefry_state threefry_state uint64_t threefry_next64(threefry_state *state) nogil - uint64_t threefry_next32(threefry_state *state) nogil + uint32_t threefry_next32(threefry_state *state) nogil void threefry_jump(threefry_state *state) void threefry_advance(uint64_t *step, threefry_state *state) @@ -181,7 +181,6 @@ cdef class ThreeFry: """ if seed is not None and key is not None: raise ValueError('seed and key cannot be both used') - ub = 2 ** 64 if key is None: if seed is None: try: @@ -194,12 +193,12 @@ cdef class ThreeFry: for i in range(4): self.rng_state.key.v[i] = state[i] else: - key = int_to_array(key, 'key', 256) + key = int_to_array(key, 'key', 256, 64) for i in range(4): self.rng_state.key.v[i] = key[i] counter = 0 if counter is None else counter - counter = int_to_array(counter, 'counter', 256) + counter = int_to_array(counter, 'counter', 256, 64) for i in range(4): self.rng_state.ctr.v[i] = counter[i] @@ -248,7 +247,7 @@ cdef class ThreeFry: def advance(self, step): """Advance the state as-if a specific number of draws have been made""" cdef np.ndarray step_a - step_a = int_to_array(step, 'step', 256) + step_a = int_to_array(step, 'step', 256, 64) loc = 0 threefry_advance(step_a.data, self.rng_state) return self diff --git a/_randomgen/core_prng/threefry32.pyx b/_randomgen/core_prng/threefry32.pyx new file mode 100644 index 000000000000..3a5bc92d62ac --- /dev/null +++ b/_randomgen/core_prng/threefry32.pyx @@ -0,0 +1,250 @@ +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + +import numpy as np + +from common cimport * +from distributions cimport prng_t, binomial_t +from core_prng.entropy import random_entropy +import core_prng.pickle +cimport entropy + +np.import_array() + +DEF THREEFRY_BUFFER_SIZE=4 + +cdef extern from 'src/threefry32/threefry32.h': + struct s_r123array4x32: + uint32_t v[4] + + ctypedef s_r123array4x32 r123array4x32 + + ctypedef r123array4x32 threefry4x32_key_t + ctypedef r123array4x32 threefry4x32_ctr_t + + struct s_threefry32_state: + threefry4x32_ctr_t *ctr; + threefry4x32_key_t *key; + int buffer_pos; + uint32_t buffer[THREEFRY_BUFFER_SIZE]; + + ctypedef s_threefry32_state threefry32_state + + uint64_t threefry32_next64(threefry32_state *state) nogil + uint32_t threefry32_next32(threefry32_state *state) nogil + double threefry32_next_double(threefry32_state *state) nogil + void threefry32_jump(threefry32_state *state) + void threefry32_advance(uint32_t *step, threefry32_state *state) + + +cdef uint64_t threefry32_uint64(void* st) nogil: + return threefry32_next64(st) + +cdef uint32_t threefry32_uint32(void *st) nogil: + return threefry32_next32( st) + +cdef double threefry32_double(void* st) nogil: + return threefry32_next_double(st) + +cdef uint64_t threefry32_raw(void *st) nogil: + return threefry32_next32( st) + + +cdef class ThreeFry32: + """ + Prototype Core PRNG using threefry + + Parameters + ---------- + seed : int, array of int + Integer or array of integers between 0 and 2**64 - 1 + + Notes + ----- + Exposes no user-facing API except `state`. Designed for use in + a `RandomGenerator` object. + """ + cdef threefry32_state *rng_state + cdef prng_t *_prng + cdef public object capsule + + def __init__(self, seed=None, counter=None, key=None): + self.rng_state = malloc(sizeof(threefry32_state)) + self.rng_state.ctr = malloc(sizeof(threefry4x32_ctr_t)) + self.rng_state.key = malloc(sizeof(threefry4x32_key_t)) + self._prng = malloc(sizeof(prng_t)) + self._prng.binomial = malloc(sizeof(binomial_t)) + self.seed(seed, counter, key) + + self._prng.state = self.rng_state + self._prng.next_uint64 = &threefry32_uint64 + self._prng.next_uint32 = &threefry32_uint32 + self._prng.next_double = &threefry32_double + self._prng.next_raw = &threefry32_raw + + cdef const char *name = 'CorePRNG' + self.capsule = PyCapsule_New(self._prng, name, NULL) + + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__prng_ctor, + (self.state['prng'],), + self.state) + + def __dealloc__(self): + free(self.rng_state.ctr) + free(self.rng_state.key) + free(self.rng_state) + free(self._prng.binomial) + free(self._prng) + + cdef _reset_state_variables(self): + self._prng.has_gauss = 0 + self._prng.has_gauss_f = 0 + self._prng.gauss = 0.0 + self._prng.gauss_f = 0.0 + self.rng_state.buffer_pos = THREEFRY_BUFFER_SIZE + for i in range(THREEFRY_BUFFER_SIZE): + self.rng_state.buffer[i] = 0 + + def __random_integer(self, bits=64): + """ + 64-bit Random Integers from the PRNG + + Parameters + ---------- + bits : {32, 64} + Number of random bits to return + + Returns + ------- + rv : int + Next random value + + Notes + ----- + Testing only + """ + if bits == 64: + return self._prng.next_uint64(self._prng.state) + elif bits == 32: + return self._prng.next_uint32(self._prng.state) + else: + raise ValueError('bits must be 32 or 64') + + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): + cdef Py_ssize_t i + if method==u'uint64': + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + elif method==u'double': + for i in range(cnt): + self._prng.next_double(self._prng.state) + else: + raise ValueError('Unknown method') + + def seed(self, seed=None, counter=None, key=None): + """ + seed(seed=None, counter=None, key=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + counter : {int array}, optional + Positive integer less than 2**128 containing the counter position + or a 4 element array of uint32 containing the counter + key : {int, array}, options + Positive integer less than 2**128 containing the key + or a 4 element array of uint32 containing the key + + Raises + ------ + ValueError + If values are out of range for the PRNG. + + Notes + ----- + The two representation of the counter and key are related through + array[i] = (value // 2**(32*i)) % 2**32. + """ + if seed is not None and key is not None: + raise ValueError('seed and key cannot be both used') + if key is None: + if seed is None: + try: + state = random_entropy(4) + except RuntimeError: + state = random_entropy(4, 'fallback') + else: + state = entropy.seed_by_array(seed, 2) + state = state.view(np.uint32) + for i in range(4): + self.rng_state.key.v[i] = state[i] + else: + key = int_to_array(key, 'key', 128, 32) + for i in range(4): + self.rng_state.key.v[i] = key[i] + + counter = 0 if counter is None else counter + counter = int_to_array(counter, 'counter', 128, 32) + for i in range(4): + self.rng_state.ctr.v[i] = counter[i] + + self._reset_state_variables() + + @property + def state(self): + """Get or set the PRNG state""" + ctr = np.empty(4, dtype=np.uint32) + key = np.empty(4, dtype=np.uint32) + buffer = np.empty(THREEFRY_BUFFER_SIZE, dtype=np.uint32) + for i in range(4): + ctr[i] = self.rng_state.ctr.v[i] + key[i] = self.rng_state.key.v[i] + for i in range(THREEFRY_BUFFER_SIZE): + buffer[i] = self.rng_state.buffer[i] + state = {'counter':ctr,'key':key} + return {'prng': self.__class__.__name__, + 'state': state, + 'buffer': buffer, + 'buffer_pos': self.rng_state.buffer_pos} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + prng = value.get('prng', '') + if prng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + for i in range(4): + self.rng_state.ctr.v[i] = value['state']['counter'][i] + self.rng_state.key.v[i] = value['state']['key'][i] + for i in range(THREEFRY_BUFFER_SIZE): + self.rng_state.buffer[i] = value['buffer'][i] + self.rng_state.buffer_pos = value['buffer_pos'] + + def jump(self): + """Jump the state as-if 2**64draws have been made""" + return self.advance(2**64) + + def advance(self, step): + """Advance the state as-if a specific number of draws have been made""" + cdef np.ndarray step_a + step_a = int_to_array(step, 'step', 128, 32) + loc = 0 + threefry32_advance(step_a.data, self.rng_state) + return self diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 34f88859d1c1..fa623382f832 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -26,7 +26,7 @@ cdef extern from "src/xoroshiro128/xoroshiro128.h": ctypedef s_xoroshiro128_state xoroshiro128_state uint64_t xoroshiro128_next64(xoroshiro128_state *state) nogil - uint64_t xoroshiro128_next32(xoroshiro128_state *state) nogil + uint32_t xoroshiro128_next32(xoroshiro128_state *state) nogil void xoroshiro128_jump(xoroshiro128_state *state) cdef uint64_t xoroshiro128_uint64(void* st) nogil: diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index effc2b3d0538..939dc702b557 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -23,7 +23,7 @@ cdef extern from "src/xorshift1024/xorshift1024.h": ctypedef s_xorshift1024_state xorshift1024_state uint64_t xorshift1024_next64(xorshift1024_state *state) nogil - uint64_t xorshift1024_next32(xorshift1024_state *state) nogil + uint32_t xorshift1024_next32(xorshift1024_state *state) nogil void xorshift1024_jump(xorshift1024_state *state) cdef uint64_t xorshift1024_uint64(void* st) nogil: diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 9ccb2b8f4c4e..1e922550dc7e 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -122,6 +122,15 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), + Extension("core_prng.threefry32", + ["core_prng/threefry32.pyx", + join(MOD_DIR, 'src', 'threefry32', 'threefry32.c')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join(MOD_DIR, 'src', + 'threefry32')], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("core_prng.xoroshiro128", ["core_prng/xoroshiro128.pyx", join(MOD_DIR, 'src', 'xoroshiro128', From b6c75ad21cf134a2244d151e48ed01fe1fa2e822 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 12 Mar 2018 13:44:03 +0000 Subject: [PATCH 064/279] BUG: Enable build to run on 32-bit Linux Enable 32-bit Linux support --- _randomgen/appveyor.yml | 2 +- _randomgen/benchmark.py | 4 ++-- _randomgen/core_prng/src/philox/philox.h | 27 ++++++++++++++++++++++++ _randomgen/setup.py | 2 ++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/_randomgen/appveyor.yml b/_randomgen/appveyor.yml index 86d98b2b67aa..25b2f0c54337 100644 --- a/_randomgen/appveyor.yml +++ b/_randomgen/appveyor.yml @@ -30,4 +30,4 @@ test_script: on_success: - cd %GIT_DIR%\ - - IF %PY_MAJOR_VER%==3 python benchmark.py \ No newline at end of file + - python benchmark.py \ No newline at end of file diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index f828f657d24f..c0082cfc8ac0 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -26,8 +26,8 @@ else: scale_64 = 2 -PRNGS = ['PCG64', 'MT19937', 'Xoroshiro128', 'Xorshift1024', - 'Philox', 'ThreeFry', 'ThreeFry32', 'numpy'] +PRNGS = ['DSFMT', 'MT19937', 'PCG64', 'Philox', 'ThreeFry', 'ThreeFry32', + 'Xoroshiro128', 'Xorshift1024', 'numpy'] def timer(code, setup): diff --git a/_randomgen/core_prng/src/philox/philox.h b/_randomgen/core_prng/src/philox/philox.h index f0ca24e6a677..e0545bce3540 100644 --- a/_randomgen/core_prng/src/philox/philox.h +++ b/_randomgen/core_prng/src/philox/philox.h @@ -60,11 +60,38 @@ static INLINE uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { return _umul128(a, b, hip); } #else +#if __SIZEOF_INT128__ static INLINE uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { __uint128_t product = ((__uint128_t)a) * ((__uint128_t)b); *hip = product >> 64; return (uint64_t)product; } +#else +static INLINE uint64_t _umul128(uint64_t a, uint64_t b, uint64_t *high) { + + uint64_t a_lo, a_hi, b_lo, b_hi, a_x_b_hi, a_x_b_mid, a_x_b_lo, b_x_a_mid, + carry_bit; + a_lo = (uint32_t)a; + a_hi = a >> 32; + b_lo = (uint32_t)b; + b_hi = b >> 32; + + a_x_b_hi = a_hi * b_hi; + a_x_b_mid = a_hi * b_lo; + b_x_a_mid = b_hi * a_lo; + a_x_b_lo = a_lo * b_lo; + + carry_bit = ((uint64_t)(uint32_t)a_x_b_mid + (uint64_t)(uint32_t)b_x_a_mid + + (a_x_b_lo >> 32)) >> 32; + + *high = a_x_b_hi + (a_x_b_mid >> 32) + (b_x_a_mid >> 32) + carry_bit; + + return a_x_b_lo + ((a_x_b_mid + b_x_a_mid) << 32); +} +static INLINE uint64_t mulhilo64(uint64_t a, uint64_t b, uint64_t *hip) { + return _umul128(a, b, hip); +} +#endif #endif static INLINE struct r123array4x64 _philox4x64round(struct r123array4x64 ctr, diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 1e922550dc7e..0eb997c05d36 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -50,6 +50,8 @@ else: EXTRA_COMPILE_ARGS += ['-msse2'] DSFMT_DEFS += [('HAVE_SSE2', '1')] +if struct.calcsize('P') < 8: + PCG_EMULATED_MATH = True files = glob.glob('./core_prng/*.in') for templated_file in files: From 0659b168e82e84ac5b42605150600ec437ab9f9b Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 12 Mar 2018 17:43:20 +0000 Subject: [PATCH 065/279] ENH: Add PCG32 Add PCG32 for benchmarking --- _randomgen/benchmark.py | 4 +- _randomgen/core_prng/__init__.py | 3 +- _randomgen/core_prng/pcg32.pyx | 216 ++ _randomgen/core_prng/pcg64.pyx | 2 +- _randomgen/core_prng/pickle.py | 2 + _randomgen/core_prng/src/dsfmt/dSFMT.h | 30 +- .../core_prng/src/pcg32/pcg-advance-64.c | 62 + .../core_prng/src/pcg32/pcg32-test-data-gen.c | 59 + _randomgen/core_prng/src/pcg32/pcg32.c | 30 + _randomgen/core_prng/src/pcg32/pcg32.h | 86 + _randomgen/core_prng/src/pcg32/pcg_variants.h | 2210 +++++++++++++++++ .../core_prng/tests/data/pcg32-testset-1.csv | 1001 ++++++++ .../core_prng/tests/data/pcg32-testset-2.csv | 1001 ++++++++ _randomgen/core_prng/tests/test_direct.py | 15 +- _randomgen/core_prng/tests/test_smoke.py | 15 +- _randomgen/setup.py | 12 +- 16 files changed, 4726 insertions(+), 22 deletions(-) create mode 100644 _randomgen/core_prng/pcg32.pyx create mode 100644 _randomgen/core_prng/src/pcg32/pcg-advance-64.c create mode 100644 _randomgen/core_prng/src/pcg32/pcg32-test-data-gen.c create mode 100644 _randomgen/core_prng/src/pcg32/pcg32.c create mode 100644 _randomgen/core_prng/src/pcg32/pcg32.h create mode 100644 _randomgen/core_prng/src/pcg32/pcg_variants.h create mode 100644 _randomgen/core_prng/tests/data/pcg32-testset-1.csv create mode 100644 _randomgen/core_prng/tests/data/pcg32-testset-2.csv diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index c0082cfc8ac0..852773f2bd22 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -26,8 +26,8 @@ else: scale_64 = 2 -PRNGS = ['DSFMT', 'MT19937', 'PCG64', 'Philox', 'ThreeFry', 'ThreeFry32', - 'Xoroshiro128', 'Xorshift1024', 'numpy'] +PRNGS = ['DSFMT', 'PCG64', 'PCG32', 'MT19937', 'Xoroshiro128', 'Xorshift1024', + 'Philox', 'ThreeFry', 'ThreeFry32', 'numpy'] def timer(code, setup): diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index 9b7d10631927..9a4b0a1b19a6 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -1,6 +1,7 @@ from .dsfmt import DSFMT from .generator import RandomGenerator from .mt19937 import MT19937 +from .pcg32 import PCG32 from .pcg64 import PCG64 from .philox import Philox from .threefry import ThreeFry @@ -8,7 +9,7 @@ from .xoroshiro128 import Xoroshiro128 from .xorshift1024 import Xorshift1024 -__all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'Philox', +__all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'PCG32', 'Philox', 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024'] from ._version import get_versions diff --git a/_randomgen/core_prng/pcg32.pyx b/_randomgen/core_prng/pcg32.pyx new file mode 100644 index 000000000000..316dc81d9087 --- /dev/null +++ b/_randomgen/core_prng/pcg32.pyx @@ -0,0 +1,216 @@ +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + +import numpy as np +cimport numpy as np + +from common cimport * +from distributions cimport prng_t, binomial_t +from core_prng.entropy import random_entropy +import core_prng.pickle +cimport entropy + +np.import_array() + + +cdef extern from "src/pcg32/pcg32.h": + + cdef struct pcg_state_setseq_64: + uint64_t state + uint64_t inc + + ctypedef pcg_state_setseq_64 pcg32_random_t + + struct s_pcg32_state: + pcg32_random_t *pcg_state + + ctypedef s_pcg32_state pcg32_state + + uint64_t pcg32_next64(pcg32_state *state) nogil + uint32_t pcg32_next32(pcg32_state *state) nogil + double pcg32_next_double(pcg32_state *state) nogil + void pcg32_jump(pcg32_state *state) + void pcg32_advance_state(pcg32_state *state, uint64_t step) + void pcg32_set_seed(pcg32_state *state, uint64_t seed, uint64_t inc) + +cdef uint64_t pcg32_uint64(void* st) nogil: + return pcg32_next64(st) + +cdef uint32_t pcg32_uint32(void *st) nogil: + return pcg32_next32( st) + +cdef double pcg32_double(void* st) nogil: + return pcg32_next_double(st) + +cdef uint64_t pcg32_raw(void* st) nogil: + return pcg32_next32( st) + + +cdef class PCG32: + """ + Prototype Core PRNG using pcg64 + + Parameters + ---------- + seed : int, array of int + Integer or array of integers between 0 and 2**64 - 1 + + Notes + ----- + Exposes no user-facing API except `get_state` and `set_state`. Designed + for use in a `RandomGenerator` object. + """ + cdef pcg32_state *rng_state + cdef prng_t *_prng + cdef public object capsule + + def __init__(self, seed=None, inc=0): + self.rng_state = malloc(sizeof(pcg32_state)) + self.rng_state.pcg_state = malloc(sizeof(pcg32_random_t)) + self._prng = malloc(sizeof(prng_t)) + self._prng.binomial = malloc(sizeof(binomial_t)) + self.seed(seed, inc) + + self._prng.state = self.rng_state + self._prng.next_uint64 = &pcg32_uint64 + self._prng.next_uint32 = &pcg32_uint32 + self._prng.next_double = &pcg32_double + self._prng.next_raw = &pcg32_raw + + cdef const char *name = "CorePRNG" + self.capsule = PyCapsule_New(self._prng, name, NULL) + + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (core_prng.pickle.__prng_ctor, + (self.state['prng'],), + self.state) + + def __dealloc__(self): + free(self.rng_state) + free(self._prng.binomial) + free(self._prng) + + cdef _reset_state_variables(self): + self._prng.has_gauss = 0 + self._prng.has_gauss_f = 0 + self._prng.gauss = 0.0 + self._prng.gauss_f = 0.0 + + def __random_integer(self, bits=64): + """ + 64-bit Random Integers from the PRNG + + Parameters + ---------- + bits : {32, 64} + Number of random bits to return + + Returns + ------- + rv : int + Next random value + + Notes + ----- + Testing only + """ + if bits == 64: + return self._prng.next_uint64(self._prng.state) + elif bits == 32: + return self._prng.next_uint32(self._prng.state) + else: + raise ValueError('bits must be 32 or 64') + + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): + cdef Py_ssize_t i + if method==u'uint64': + for i in range(cnt): + self._prng.next_uint64(self._prng.state) + elif method==u'double': + for i in range(cnt): + self._prng.next_double(self._prng.state) + else: + raise ValueError('Unknown method') + + + def seed(self, seed=None, inc=0): + """ + seed(seed=None, stream=None) + + Seed the generator. + + This method is called when ``RandomState`` is initialized. It can be + called again to re-seed the generator. For details, see + ``RandomState``. + + Parameters + ---------- + seed : int, optional + Seed for ``RandomState``. + inc : int, optional + Increment to use for PCG stream + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + + """ + ub = 2 ** 64 + if seed is None: + try: + seed = random_entropy(2) + except RuntimeError: + seed = random_entropy(2, 'fallback') + seed = seed.view(np.uint64).squeeze() + else: + err_msg = 'seed must be a scalar integer between 0 and ' \ + '{ub}'.format(ub=ub) + if not np.isscalar(seed): + raise TypeError(err_msg) + if int(seed) != seed: + raise TypeError(err_msg) + if seed < 0 or seed > ub: + raise ValueError(err_msg) + + if not np.isscalar(inc): + raise TypeError('inc must be a scalar integer between 0 ' + 'and {ub}'.format(ub=ub)) + if inc < 0 or inc > ub or int(inc) != inc: + raise ValueError('inc must be a scalar integer between 0 ' + 'and {ub}'.format(ub=ub)) + + pcg32_set_seed(self.rng_state, seed, inc) + self._reset_state_variables() + + @property + def state(self): + """Get or set the PRNG state""" + return {'prng': self.__class__.__name__, + 'state': {'state': self.rng_state.pcg_state.state, + 'inc':self.rng_state.pcg_state.inc}} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + prng = value.get('prng', '') + if prng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + self.rng_state.pcg_state.state = value['state']['state'] + self.rng_state.pcg_state.inc = value['state']['inc'] + + def advance(self, step): + pcg32_advance_state(self.rng_state, step) + return self + + def jump(self): + return self.advance(2**32) diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index 70aa57b76610..c01156d72f37 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -189,7 +189,7 @@ cdef class PCG64: _seed = random_entropy(4, 'fallback') _seed = _seed.view(np.uint64) else: - err_msg = 'inc must be a scalar integer between 0 and ' \ + err_msg = 'seed must be a scalar integer between 0 and ' \ '{ub}'.format(ub=ub) if not np.isscalar(seed): raise TypeError(err_msg) diff --git a/_randomgen/core_prng/pickle.py b/_randomgen/core_prng/pickle.py index 56f4de56240e..40557d63edbd 100644 --- a/_randomgen/core_prng/pickle.py +++ b/_randomgen/core_prng/pickle.py @@ -1,6 +1,7 @@ from .generator import RandomGenerator from .dsfmt import DSFMT from .mt19937 import MT19937 +from .pcg32 import PCG32 from .pcg64 import PCG64 from .philox import Philox from .threefry import ThreeFry @@ -10,6 +11,7 @@ PRNGS = {'MT19937': MT19937, 'DSFMT': DSFMT, + 'PCG32': PCG32, 'PCG64': PCG64, 'Philox': Philox, 'ThreeFry': ThreeFry, diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.h b/_randomgen/core_prng/src/dsfmt/dSFMT.h index fa608cd758f1..0ae8a016d871 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT.h +++ b/_randomgen/core_prng/src/dsfmt/dSFMT.h @@ -633,6 +633,11 @@ inline static void fill_array_close1_open2(double array[], int size) { #endif /* DSFMT_H */ +union random_val_t { + double d; + uint64_t u64; +}; + typedef struct s_dsfmt_state { dsfmt_t *state; int has_uint32; @@ -660,28 +665,27 @@ static inline double dsfmt_next_double(dsfmt_state *state) { static inline uint64_t dsfmt_next64(dsfmt_state *state) { /* Discard bottom 16 bits */ - double d = dsfmt_next_buffer(state); + union random_val_t rv; + rv.d = dsfmt_next_buffer(state); uint64_t out; - uint64_t *tmp; - tmp = (uint64_t *)&d; - out = (*tmp >> 16) << 32; - d = dsfmt_next_buffer(state); - tmp = (uint64_t *)&d; - out |= (*tmp >> 16) & 0xffffffff; + out = (rv.u64 >> 16) << 32; + rv.d = dsfmt_next_buffer(state); + out |= (rv.u64 >> 16) & 0xffffffff; return out; } static inline uint32_t dsfmt_next32(dsfmt_state *state) { /* Discard bottom 16 bits */ - double d = dsfmt_next_buffer(state); - uint64_t *out = (uint64_t *)&d; - return (uint32_t)((*out >> 16) & 0xffffffff); + union random_val_t rv; + rv.d = dsfmt_next_buffer(state); + // uint64_t *out = (uint64_t *)&d; + return (uint32_t)((rv.u64 >> 16) & 0xffffffff); } static inline uint64_t dsfmt_next_raw(dsfmt_state *state) { - double d; - d = dsfmt_next_buffer(state); - return *((uint64_t *)&d); + union random_val_t rv; + rv.d = dsfmt_next_buffer(state); + return rv.u64; } void dsfmt_jump(dsfmt_state *state); \ No newline at end of file diff --git a/_randomgen/core_prng/src/pcg32/pcg-advance-64.c b/_randomgen/core_prng/src/pcg32/pcg-advance-64.c new file mode 100644 index 000000000000..8210e75650eb --- /dev/null +++ b/_randomgen/core_prng/src/pcg32/pcg-advance-64.c @@ -0,0 +1,62 @@ +/* + * PCG Random Number Generation for C. + * + * Copyright 2014 Melissa O'Neill + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + +/* + * This code is derived from the canonical C++ PCG implementation, which + * has many additional features and is preferable if you can use C++ in + * your project. + * + * Repetative C code is derived using C preprocessor metaprogramming + * techniques. + */ + +#include "pcg_variants.h" + +/* Multi-step advance functions (jump-ahead, jump-back) + * + * The method used here is based on Brown, "Random Number Generation + * with Arbitrary Stride,", Transactions of the American Nuclear + * Society (Nov. 1994). The algorithm is very similar to fast + * exponentiation. + * + * Even though delta is an unsigned integer, we can pass a + * signed integer to go backwards, it just goes "the long way round". + */ + +uint64_t pcg_advance_lcg_64(uint64_t state, uint64_t delta, uint64_t cur_mult, + uint64_t cur_plus) +{ + uint64_t acc_mult = 1u; + uint64_t acc_plus = 0u; + while (delta > 0) { + if (delta & 1) { + acc_mult *= cur_mult; + acc_plus = acc_plus * cur_mult + cur_plus; + } + cur_plus = (cur_mult + 1) * cur_plus; + cur_mult *= cur_mult; + delta /= 2; + } + return acc_mult * state + acc_plus; +} + diff --git a/_randomgen/core_prng/src/pcg32/pcg32-test-data-gen.c b/_randomgen/core_prng/src/pcg32/pcg32-test-data-gen.c new file mode 100644 index 000000000000..cccaf84b9948 --- /dev/null +++ b/_randomgen/core_prng/src/pcg32/pcg32-test-data-gen.c @@ -0,0 +1,59 @@ +/* + * Generate testing csv files + * + * + * gcc pcg32-test-data-gen.c pcg32.orig.c ../splitmix64/splitmix64.c -o + * pgc64-test-data-gen + */ + +#include "pcg_variants.h" +#include +#include + +#define N 1000 + +int main() { + pcg32_random_t rng; + uint64_t inc, seed = 0xDEADBEAF; + inc = 0; + int i; + uint64_t store[N]; + pcg32_srandom_r(&rng, seed, inc); + for (i = 0; i < N; i++) { + store[i] = pcg32_random_r(&rng); + } + + FILE *fp; + fp = fopen("pcg32-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); + + seed = 0; + pcg32_srandom_r(&rng, seed, inc); + for (i = 0; i < N; i++) { + store[i] = pcg32_random_r(&rng); + } + fp = fopen("pcg32-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); +} diff --git a/_randomgen/core_prng/src/pcg32/pcg32.c b/_randomgen/core_prng/src/pcg32/pcg32.c new file mode 100644 index 000000000000..5fbf6759f1a3 --- /dev/null +++ b/_randomgen/core_prng/src/pcg32/pcg32.c @@ -0,0 +1,30 @@ +#include "pcg32.h" + +extern inline uint64_t pcg32_next64(pcg32_state *state); +extern inline uint32_t pcg32_next32(pcg32_state *state); +extern inline double pcg32_next_double(pcg32_state *state); + +uint64_t pcg_advance_lcg_64(uint64_t state, uint64_t delta, uint64_t cur_mult, + uint64_t cur_plus) { + uint64_t acc_mult, acc_plus; + acc_mult = 1u; + acc_plus = 0u; + while (delta > 0) { + if (delta & 1) { + acc_mult *= cur_mult; + acc_plus = acc_plus * cur_mult + cur_plus; + } + cur_plus = (cur_mult + 1) * cur_plus; + cur_mult *= cur_mult; + delta /= 2; + } + return acc_mult * state + acc_plus; +} + +extern void pcg32_advance_state(pcg32_state *state, uint64_t step) { + pcg32_advance_r(state->pcg_state, step); +} + +extern void pcg32_set_seed(pcg32_state *state, uint64_t seed, uint64_t inc) { + pcg32_srandom_r(state->pcg_state, seed, inc); +} diff --git a/_randomgen/core_prng/src/pcg32/pcg32.h b/_randomgen/core_prng/src/pcg32/pcg32.h new file mode 100644 index 000000000000..5ab59cc85105 --- /dev/null +++ b/_randomgen/core_prng/src/pcg32/pcg32.h @@ -0,0 +1,86 @@ + +#ifdef _WIN32 +#ifndef _INTTYPES +#include "../common/stdint.h" +#endif +#define inline __inline __forceinline +#else +#include +#endif + +#define PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL + +struct pcg_state_setseq_64 { + uint64_t state; + uint64_t inc; +}; + +inline uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) { +#if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) + asm("rorl %%cl, %0" : "=r"(value) : "0"(value), "c"(rot)); + return value; +#else + return (value >> rot) | (value << ((-rot) & 31)); +#endif +} + +inline void pcg_setseq_64_step_r(struct pcg_state_setseq_64 *rng) { + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64 + rng->inc; +} + +inline uint32_t pcg_output_xsh_rr_64_32(uint64_t state) { + return pcg_rotr_32(((state >> 18u) ^ state) >> 27u, state >> 59u); +} + +inline uint32_t +pcg_setseq_64_xsh_rr_32_random_r(struct pcg_state_setseq_64 *rng) { + uint64_t oldstate; + oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline void pcg_setseq_64_srandom_r(struct pcg_state_setseq_64 *rng, + uint64_t initstate, uint64_t initseq) { + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_64_step_r(rng); + rng->state += initstate; + pcg_setseq_64_step_r(rng); +} + +extern uint64_t pcg_advance_lcg_64(uint64_t state, uint64_t delta, + uint64_t cur_mult, uint64_t cur_plus); + +inline void pcg_setseq_64_advance_r(struct pcg_state_setseq_64 *rng, + uint64_t delta) { + rng->state = pcg_advance_lcg_64(rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, + rng->inc); +} + +typedef struct pcg_state_setseq_64 pcg32_random_t; +#define pcg32_random_r pcg_setseq_64_xsh_rr_32_random_r +#define pcg32_srandom_r pcg_setseq_64_srandom_r +#define pcg32_advance_r pcg_setseq_64_advance_r + +typedef struct s_pcg32_state { + pcg32_random_t *pcg_state; +} pcg32_state; + +static inline uint64_t pcg32_next64(pcg32_state *state) { + return (uint64_t)(pcg32_random_r(state->pcg_state)) << 32 | + pcg32_random_r(state->pcg_state); +} + +static inline uint32_t pcg32_next32(pcg32_state *state) { + return pcg32_random_r(state->pcg_state); +} + +static inline double pcg32_next_double(pcg32_state *state) { + int32_t a = pcg32_random_r(state->pcg_state) >> 5, + b = pcg32_random_r(state->pcg_state) >> 6; + return (a * 67108864.0 + b) / 9007199254740992.0; +} + +void pcg32_advance_state(pcg32_state *state, uint64_t step); +void pcg32_set_seed(pcg32_state *state, uint64_t seed, uint64_t inc); diff --git a/_randomgen/core_prng/src/pcg32/pcg_variants.h b/_randomgen/core_prng/src/pcg32/pcg_variants.h new file mode 100644 index 000000000000..32daac1ce4f5 --- /dev/null +++ b/_randomgen/core_prng/src/pcg32/pcg_variants.h @@ -0,0 +1,2210 @@ +/* + * PCG Random Number Generation for C. + * + * Copyright 2014 Melissa O'Neill + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + +/* + * This code is derived from the canonical C++ PCG implementation, which + * has many additional features and is preferable if you can use C++ in + * your project. + * + * Much of the derivation was performed mechanically. In particular, the + * output functions were generated by compiling the C++ output functions + * into LLVM bitcode and then transforming that using the LLVM C backend + * (from https://github.com/draperlaboratory/llvm-cbe), and then + * postprocessing and hand editing the output. + * + * Much of the remaining code was generated by C-preprocessor metaprogramming. + */ + +#ifndef PCG_VARIANTS_H_INCLUDED +#define PCG_VARIANTS_H_INCLUDED 1 + +#include + +#if __SIZEOF_INT128__ + typedef __uint128_t pcg128_t; + #define PCG_128BIT_CONSTANT(high,low) \ + ((((pcg128_t)high) << 64) + low) + #define PCG_HAS_128BIT_OPS 1 +#endif + +#if __GNUC_GNU_INLINE__ && !defined(__cplusplus) + #error Nonstandard GNU inlining semantics. Compile with -std=c99 or better. + // We could instead use macros PCG_INLINE and PCG_EXTERN_INLINE + // but better to just reject ancient C code. +#endif + +#if __cplusplus +extern "C" { +#endif + +/* + * Rotate helper functions. + */ + +inline uint8_t pcg_rotr_8(uint8_t value, unsigned int rot) +{ +/* Unfortunately, clang is kinda pathetic when it comes to properly + * recognizing idiomatic rotate code, so for clang we actually provide + * assembler directives (enabled with PCG_USE_INLINE_ASM). Boo, hiss. + */ +#if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) + asm ("rorb %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +#else + return (value >> rot) | (value << ((- rot) & 7)); +#endif +} + +inline uint16_t pcg_rotr_16(uint16_t value, unsigned int rot) +{ +#if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) + asm ("rorw %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +#else + return (value >> rot) | (value << ((- rot) & 15)); +#endif +} + +inline uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) +{ +#if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) + asm ("rorl %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +#else + return (value >> rot) | (value << ((- rot) & 31)); +#endif +} + +inline uint64_t pcg_rotr_64(uint64_t value, unsigned int rot) +{ +#if 0 && PCG_USE_INLINE_ASM && __clang__ && __x86_64__ + // For whatever reason, clang actually *does* generate rotq by + // itself, so we don't need this code. + asm ("rorq %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +#else + return (value >> rot) | (value << ((- rot) & 63)); +#endif +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_rotr_128(pcg128_t value, unsigned int rot) +{ + return (value >> rot) | (value << ((- rot) & 127)); +} +#endif + +/* + * Output functions. These are the core of the PCG generation scheme. + */ + +// XSH RS + +inline uint8_t pcg_output_xsh_rs_16_8(uint16_t state) +{ + return (uint8_t)(((state >> 7u) ^ state) >> ((state >> 14u) + 3u)); +} + +inline uint16_t pcg_output_xsh_rs_32_16(uint32_t state) +{ + return (uint16_t)(((state >> 11u) ^ state) >> ((state >> 30u) + 11u)); +} + +inline uint32_t pcg_output_xsh_rs_64_32(uint64_t state) +{ + + return (uint32_t)(((state >> 22u) ^ state) >> ((state >> 61u) + 22u)); +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_output_xsh_rs_128_64(pcg128_t state) +{ + return (uint64_t)(((state >> 43u) ^ state) >> ((state >> 124u) + 45u)); +} +#endif + +// XSH RR + +inline uint8_t pcg_output_xsh_rr_16_8(uint16_t state) +{ + return pcg_rotr_8(((state >> 5u) ^ state) >> 5u, state >> 13u); +} + +inline uint16_t pcg_output_xsh_rr_32_16(uint32_t state) +{ + return pcg_rotr_16(((state >> 10u) ^ state) >> 12u, state >> 28u); +} + +inline uint32_t pcg_output_xsh_rr_64_32(uint64_t state) +{ + return pcg_rotr_32(((state >> 18u) ^ state) >> 27u, state >> 59u); +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_output_xsh_rr_128_64(pcg128_t state) +{ + return pcg_rotr_64(((state >> 29u) ^ state) >> 58u, state >> 122u); +} +#endif + +// RXS M XS + +inline uint8_t pcg_output_rxs_m_xs_8_8(uint8_t state) +{ + uint8_t word = ((state >> ((state >> 6u) + 2u)) ^ state) * 217u; + return (word >> 6u) ^ word; +} + +inline uint16_t pcg_output_rxs_m_xs_16_16(uint16_t state) +{ + uint16_t word = ((state >> ((state >> 13u) + 3u)) ^ state) * 62169u; + return (word >> 11u) ^ word; +} + +inline uint32_t pcg_output_rxs_m_xs_32_32(uint32_t state) +{ + uint32_t word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +inline uint64_t pcg_output_rxs_m_xs_64_64(uint64_t state) +{ + uint64_t word = ((state >> ((state >> 59u) + 5u)) ^ state) + * 12605985483714917081ull; + return (word >> 43u) ^ word; +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_output_rxs_m_xs_128_128(pcg128_t state) +{ + pcg128_t word = ((state >> ((state >> 122u) + 6u)) ^ state) + * (PCG_128BIT_CONSTANT(17766728186571221404ULL, + 12605985483714917081ULL)); + // 327738287884841127335028083622016905945 + return (word >> 86u) ^ word; +} +#endif + +// XSL RR (only defined for >= 64 bits) + +inline uint32_t pcg_output_xsl_rr_64_32(uint64_t state) +{ + return pcg_rotr_32(((uint32_t)(state >> 32u)) ^ (uint32_t)state, + state >> 59u); +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) +{ + return pcg_rotr_64(((uint64_t)(state >> 64u)) ^ (uint64_t)state, + state >> 122u); +} +#endif + +// XSL RR RR (only defined for >= 64 bits) + +inline uint64_t pcg_output_xsl_rr_rr_64_64(uint64_t state) +{ + uint32_t rot1 = (uint32_t)(state >> 59u); + uint32_t high = (uint32_t)(state >> 32u); + uint32_t low = (uint32_t)state; + uint32_t xored = high ^ low; + uint32_t newlow = pcg_rotr_32(xored, rot1); + uint32_t newhigh = pcg_rotr_32(high, newlow & 31u); + return (((uint64_t)newhigh) << 32u) | newlow; +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_output_xsl_rr_rr_128_128(pcg128_t state) +{ + uint32_t rot1 = (uint32_t)(state >> 122u); + uint64_t high = (uint64_t)(state >> 64u); + uint64_t low = (uint64_t)state; + uint64_t xored = high ^ low; + uint64_t newlow = pcg_rotr_64(xored, rot1); + uint64_t newhigh = pcg_rotr_64(high, newlow & 63u); + return (((pcg128_t)newhigh) << 64u) | newlow; +} +#endif + +#define PCG_DEFAULT_MULTIPLIER_8 141U +#define PCG_DEFAULT_MULTIPLIER_16 12829U +#define PCG_DEFAULT_MULTIPLIER_32 747796405U +#define PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL + +#define PCG_DEFAULT_INCREMENT_8 77U +#define PCG_DEFAULT_INCREMENT_16 47989U +#define PCG_DEFAULT_INCREMENT_32 2891336453U +#define PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL + +#if PCG_HAS_128BIT_OPS +#define PCG_DEFAULT_MULTIPLIER_128 \ + PCG_128BIT_CONSTANT(2549297995355413924ULL,4865540595714422341ULL) +#define PCG_DEFAULT_INCREMENT_128 \ + PCG_128BIT_CONSTANT(6364136223846793005ULL,1442695040888963407ULL) +#endif + +/* + * Static initialization constants (if you can't call srandom for some + * bizarre reason). + */ + +#define PCG_STATE_ONESEQ_8_INITIALIZER { 0xd7U } +#define PCG_STATE_ONESEQ_16_INITIALIZER { 0x20dfU } +#define PCG_STATE_ONESEQ_32_INITIALIZER { 0x46b56677U } +#define PCG_STATE_ONESEQ_64_INITIALIZER { 0x4d595df4d0f33173ULL } +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_ONESEQ_128_INITIALIZER \ + { PCG_128BIT_CONSTANT(0xb8dc10e158a92392ULL, 0x98046df007ec0a53ULL) } +#endif + +#define PCG_STATE_UNIQUE_8_INITIALIZER PCG_STATE_ONESEQ_8_INITIALIZER +#define PCG_STATE_UNIQUE_16_INITIALIZER PCG_STATE_ONESEQ_16_INITIALIZER +#define PCG_STATE_UNIQUE_32_INITIALIZER PCG_STATE_ONESEQ_32_INITIALIZER +#define PCG_STATE_UNIQUE_64_INITIALIZER PCG_STATE_ONESEQ_64_INITIALIZER +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_UNIQUE_128_INITIALIZER PCG_STATE_ONESEQ_128_INITIALIZER +#endif + +#define PCG_STATE_MCG_8_INITIALIZER { 0xe5U } +#define PCG_STATE_MCG_16_INITIALIZER { 0xa5e5U } +#define PCG_STATE_MCG_32_INITIALIZER { 0xd15ea5e5U } +#define PCG_STATE_MCG_64_INITIALIZER { 0xcafef00dd15ea5e5ULL } +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_MCG_128_INITIALIZER \ + { PCG_128BIT_CONSTANT(0x0000000000000000ULL, 0xcafef00dd15ea5e5ULL) } +#endif + +#define PCG_STATE_SETSEQ_8_INITIALIZER { 0x9bU, 0xdbU } +#define PCG_STATE_SETSEQ_16_INITIALIZER { 0xe39bU, 0x5bdbU } +#define PCG_STATE_SETSEQ_32_INITIALIZER { 0xec02d89bU, 0x94b95bdbU } +#define PCG_STATE_SETSEQ_64_INITIALIZER \ + { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL } +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_SETSEQ_128_INITIALIZER \ + { PCG_128BIT_CONSTANT(0x979c9a98d8462005ULL, 0x7d3e9cb6cfe0549bULL), \ + PCG_128BIT_CONSTANT(0x0000000000000001ULL, 0xda3e39cb94b95bdbULL) } +#endif + +/* Representations for the oneseq, mcg, and unique variants */ + +struct pcg_state_8 { + uint8_t state; +}; + +struct pcg_state_16 { + uint16_t state; +}; + +struct pcg_state_32 { + uint32_t state; +}; + +struct pcg_state_64 { + uint64_t state; +}; + +#if PCG_HAS_128BIT_OPS +struct pcg_state_128 { + pcg128_t state; +}; +#endif + +/* Representations setseq variants */ + +struct pcg_state_setseq_8 { + uint8_t state; + uint8_t inc; +}; + +struct pcg_state_setseq_16 { + uint16_t state; + uint16_t inc; +}; + +struct pcg_state_setseq_32 { + uint32_t state; + uint32_t inc; +}; + +struct pcg_state_setseq_64 { + uint64_t state; + uint64_t inc; +}; + +#if PCG_HAS_128BIT_OPS +struct pcg_state_setseq_128 { + pcg128_t state; + pcg128_t inc; +}; +#endif + +/* Multi-step advance functions (jump-ahead, jump-back) */ + +extern uint8_t pcg_advance_lcg_8(uint8_t state, uint8_t delta, uint8_t cur_mult, + uint8_t cur_plus); +extern uint16_t pcg_advance_lcg_16(uint16_t state, uint16_t delta, + uint16_t cur_mult, uint16_t cur_plus); +extern uint32_t pcg_advance_lcg_32(uint32_t state, uint32_t delta, + uint32_t cur_mult, uint32_t cur_plus); +extern uint64_t pcg_advance_lcg_64(uint64_t state, uint64_t delta, + uint64_t cur_mult, uint64_t cur_plus); + +#if PCG_HAS_128BIT_OPS +extern pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, + pcg128_t cur_mult, pcg128_t cur_plus); +#endif + +/* Functions to advance the underlying LCG, one version for each size and + * each style. These functions are considered semi-private. There is rarely + * a good reason to call them directly. + */ + +inline void pcg_oneseq_8_step_r(struct pcg_state_8* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8 + + PCG_DEFAULT_INCREMENT_8; +} + +inline void pcg_oneseq_8_advance_r(struct pcg_state_8* rng, uint8_t delta) +{ + rng->state = pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, + PCG_DEFAULT_INCREMENT_8); +} + +inline void pcg_mcg_8_step_r(struct pcg_state_8* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8; +} + +inline void pcg_mcg_8_advance_r(struct pcg_state_8* rng, uint8_t delta) +{ + rng->state + = pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, 0u); +} + +inline void pcg_unique_8_step_r(struct pcg_state_8* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8 + + (uint8_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_8_advance_r(struct pcg_state_8* rng, uint8_t delta) +{ + rng->state = pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, + (uint8_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_8_step_r(struct pcg_state_setseq_8* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8 + rng->inc; +} + +inline void pcg_setseq_8_advance_r(struct pcg_state_setseq_8* rng, + uint8_t delta) +{ + rng->state = pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, + rng->inc); +} + +inline void pcg_oneseq_16_step_r(struct pcg_state_16* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_16 + + PCG_DEFAULT_INCREMENT_16; +} + +inline void pcg_oneseq_16_advance_r(struct pcg_state_16* rng, uint16_t delta) +{ + rng->state = pcg_advance_lcg_16( + rng->state, delta, PCG_DEFAULT_MULTIPLIER_16, PCG_DEFAULT_INCREMENT_16); +} + +inline void pcg_mcg_16_step_r(struct pcg_state_16* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_16; +} + +inline void pcg_mcg_16_advance_r(struct pcg_state_16* rng, uint16_t delta) +{ + rng->state + = pcg_advance_lcg_16(rng->state, delta, PCG_DEFAULT_MULTIPLIER_16, 0u); +} + +inline void pcg_unique_16_step_r(struct pcg_state_16* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_16 + + (uint16_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_16_advance_r(struct pcg_state_16* rng, uint16_t delta) +{ + rng->state + = pcg_advance_lcg_16(rng->state, delta, PCG_DEFAULT_MULTIPLIER_16, + (uint16_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_16_step_r(struct pcg_state_setseq_16* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_16 + rng->inc; +} + +inline void pcg_setseq_16_advance_r(struct pcg_state_setseq_16* rng, + uint16_t delta) +{ + rng->state = pcg_advance_lcg_16(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_16, rng->inc); +} + +inline void pcg_oneseq_32_step_r(struct pcg_state_32* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_32 + + PCG_DEFAULT_INCREMENT_32; +} + +inline void pcg_oneseq_32_advance_r(struct pcg_state_32* rng, uint32_t delta) +{ + rng->state = pcg_advance_lcg_32( + rng->state, delta, PCG_DEFAULT_MULTIPLIER_32, PCG_DEFAULT_INCREMENT_32); +} + +inline void pcg_mcg_32_step_r(struct pcg_state_32* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_32; +} + +inline void pcg_mcg_32_advance_r(struct pcg_state_32* rng, uint32_t delta) +{ + rng->state + = pcg_advance_lcg_32(rng->state, delta, PCG_DEFAULT_MULTIPLIER_32, 0u); +} + +inline void pcg_unique_32_step_r(struct pcg_state_32* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_32 + + (uint32_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_32_advance_r(struct pcg_state_32* rng, uint32_t delta) +{ + rng->state + = pcg_advance_lcg_32(rng->state, delta, PCG_DEFAULT_MULTIPLIER_32, + (uint32_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_32_step_r(struct pcg_state_setseq_32* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_32 + rng->inc; +} + +inline void pcg_setseq_32_advance_r(struct pcg_state_setseq_32* rng, + uint32_t delta) +{ + rng->state = pcg_advance_lcg_32(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_32, rng->inc); +} + +inline void pcg_oneseq_64_step_r(struct pcg_state_64* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64 + + PCG_DEFAULT_INCREMENT_64; +} + +inline void pcg_oneseq_64_advance_r(struct pcg_state_64* rng, uint64_t delta) +{ + rng->state = pcg_advance_lcg_64( + rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, PCG_DEFAULT_INCREMENT_64); +} + +inline void pcg_mcg_64_step_r(struct pcg_state_64* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64; +} + +inline void pcg_mcg_64_advance_r(struct pcg_state_64* rng, uint64_t delta) +{ + rng->state + = pcg_advance_lcg_64(rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, 0u); +} + +inline void pcg_unique_64_step_r(struct pcg_state_64* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64 + + (uint64_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_64_advance_r(struct pcg_state_64* rng, uint64_t delta) +{ + rng->state + = pcg_advance_lcg_64(rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, + (uint64_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_64_step_r(struct pcg_state_setseq_64* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64 + rng->inc; +} + +inline void pcg_setseq_64_advance_r(struct pcg_state_setseq_64* rng, + uint64_t delta) +{ + rng->state = pcg_advance_lcg_64(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_64, rng->inc); +} + +#if PCG_HAS_128BIT_OPS +inline void pcg_oneseq_128_step_r(struct pcg_state_128* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + + PCG_DEFAULT_INCREMENT_128; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_oneseq_128_advance_r(struct pcg_state_128* rng, pcg128_t delta) +{ + rng->state + = pcg_advance_lcg_128(rng->state, delta, PCG_DEFAULT_MULTIPLIER_128, + PCG_DEFAULT_INCREMENT_128); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_mcg_128_step_r(struct pcg_state_128* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_mcg_128_advance_r(struct pcg_state_128* rng, pcg128_t delta) +{ + rng->state = pcg_advance_lcg_128(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_128, 0u); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_unique_128_step_r(struct pcg_state_128* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + + (pcg128_t)(((intptr_t)rng) | 1u); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_unique_128_advance_r(struct pcg_state_128* rng, pcg128_t delta) +{ + rng->state + = pcg_advance_lcg_128(rng->state, delta, PCG_DEFAULT_MULTIPLIER_128, + (pcg128_t)(((intptr_t)rng) | 1u)); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_setseq_128_step_r(struct pcg_state_setseq_128* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + rng->inc; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_setseq_128_advance_r(struct pcg_state_setseq_128* rng, + pcg128_t delta) +{ + rng->state = pcg_advance_lcg_128(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_128, rng->inc); +} +#endif + +/* Functions to seed the RNG state, one version for each size and each + * style. Unlike the step functions, regular users can and should call + * these functions. + */ + +inline void pcg_oneseq_8_srandom_r(struct pcg_state_8* rng, uint8_t initstate) +{ + rng->state = 0U; + pcg_oneseq_8_step_r(rng); + rng->state += initstate; + pcg_oneseq_8_step_r(rng); +} + +inline void pcg_mcg_8_srandom_r(struct pcg_state_8* rng, uint8_t initstate) +{ + rng->state = initstate | 1u; +} + +inline void pcg_unique_8_srandom_r(struct pcg_state_8* rng, uint8_t initstate) +{ + rng->state = 0U; + pcg_unique_8_step_r(rng); + rng->state += initstate; + pcg_unique_8_step_r(rng); +} + +inline void pcg_setseq_8_srandom_r(struct pcg_state_setseq_8* rng, + uint8_t initstate, uint8_t initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_8_step_r(rng); + rng->state += initstate; + pcg_setseq_8_step_r(rng); +} + +inline void pcg_oneseq_16_srandom_r(struct pcg_state_16* rng, + uint16_t initstate) +{ + rng->state = 0U; + pcg_oneseq_16_step_r(rng); + rng->state += initstate; + pcg_oneseq_16_step_r(rng); +} + +inline void pcg_mcg_16_srandom_r(struct pcg_state_16* rng, uint16_t initstate) +{ + rng->state = initstate | 1u; +} + +inline void pcg_unique_16_srandom_r(struct pcg_state_16* rng, + uint16_t initstate) +{ + rng->state = 0U; + pcg_unique_16_step_r(rng); + rng->state += initstate; + pcg_unique_16_step_r(rng); +} + +inline void pcg_setseq_16_srandom_r(struct pcg_state_setseq_16* rng, + uint16_t initstate, uint16_t initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_16_step_r(rng); + rng->state += initstate; + pcg_setseq_16_step_r(rng); +} + +inline void pcg_oneseq_32_srandom_r(struct pcg_state_32* rng, + uint32_t initstate) +{ + rng->state = 0U; + pcg_oneseq_32_step_r(rng); + rng->state += initstate; + pcg_oneseq_32_step_r(rng); +} + +inline void pcg_mcg_32_srandom_r(struct pcg_state_32* rng, uint32_t initstate) +{ + rng->state = initstate | 1u; +} + +inline void pcg_unique_32_srandom_r(struct pcg_state_32* rng, + uint32_t initstate) +{ + rng->state = 0U; + pcg_unique_32_step_r(rng); + rng->state += initstate; + pcg_unique_32_step_r(rng); +} + +inline void pcg_setseq_32_srandom_r(struct pcg_state_setseq_32* rng, + uint32_t initstate, uint32_t initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_32_step_r(rng); + rng->state += initstate; + pcg_setseq_32_step_r(rng); +} + +inline void pcg_oneseq_64_srandom_r(struct pcg_state_64* rng, + uint64_t initstate) +{ + rng->state = 0U; + pcg_oneseq_64_step_r(rng); + rng->state += initstate; + pcg_oneseq_64_step_r(rng); +} + +inline void pcg_mcg_64_srandom_r(struct pcg_state_64* rng, uint64_t initstate) +{ + rng->state = initstate | 1u; +} + +inline void pcg_unique_64_srandom_r(struct pcg_state_64* rng, + uint64_t initstate) +{ + rng->state = 0U; + pcg_unique_64_step_r(rng); + rng->state += initstate; + pcg_unique_64_step_r(rng); +} + +inline void pcg_setseq_64_srandom_r(struct pcg_state_setseq_64* rng, + uint64_t initstate, uint64_t initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_64_step_r(rng); + rng->state += initstate; + pcg_setseq_64_step_r(rng); +} + +#if PCG_HAS_128BIT_OPS +inline void pcg_oneseq_128_srandom_r(struct pcg_state_128* rng, + pcg128_t initstate) +{ + rng->state = 0U; + pcg_oneseq_128_step_r(rng); + rng->state += initstate; + pcg_oneseq_128_step_r(rng); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_mcg_128_srandom_r(struct pcg_state_128* rng, pcg128_t initstate) +{ + rng->state = initstate | 1u; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_unique_128_srandom_r(struct pcg_state_128* rng, + pcg128_t initstate) +{ + rng->state = 0U; + pcg_unique_128_step_r(rng); + rng->state += initstate; + pcg_unique_128_step_r(rng); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_setseq_128_srandom_r(struct pcg_state_setseq_128* rng, + pcg128_t initstate, pcg128_t initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_128_step_r(rng); + rng->state += initstate; + pcg_setseq_128_step_r(rng); +} +#endif + +/* Now, finally we create each of the individual generators. We provide + * a random_r function that provides a random number of the appropriate + * type (using the full range of the type) and a boundedrand_r version + * that provides + * + * Implementation notes for boundedrand_r: + * + * To avoid bias, we need to make the range of the RNG a multiple of + * bound, which we do by dropping output less than a threshold. + * Let's consider a 32-bit case... A naive scheme to calculate the + * threshold would be to do + * + * uint32_t threshold = 0x100000000ull % bound; + * + * but 64-bit div/mod is slower than 32-bit div/mod (especially on + * 32-bit platforms). In essence, we do + * + * uint32_t threshold = (0x100000000ull-bound) % bound; + * + * because this version will calculate the same modulus, but the LHS + * value is less than 2^32. + * + * (Note that using modulo is only wise for good RNGs, poorer RNGs + * such as raw LCGs do better using a technique based on division.) + * Empricical tests show that division is preferable to modulus for + * reducting the range of an RNG. It's faster, and sometimes it can + * even be statistically prefereable. + */ + +/* Generation functions for XSH RS */ + +inline uint8_t pcg_oneseq_16_xsh_rs_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_oneseq_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t pcg_oneseq_16_xsh_rs_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_oneseq_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_oneseq_32_xsh_rs_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_oneseq_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t pcg_oneseq_32_xsh_rs_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_oneseq_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_oneseq_64_xsh_rs_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t pcg_oneseq_64_xsh_rs_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_xsh_rs_64_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_oneseq_128_xsh_rs_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_unique_16_xsh_rs_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_unique_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t pcg_unique_16_xsh_rs_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_unique_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_unique_32_xsh_rs_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_unique_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t pcg_unique_32_xsh_rs_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_unique_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_unique_64_xsh_rs_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t pcg_unique_64_xsh_rs_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_xsh_rs_64_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_unique_128_xsh_rs_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_setseq_16_xsh_rs_8_random_r(struct pcg_state_setseq_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_setseq_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t +pcg_setseq_16_xsh_rs_8_boundedrand_r(struct pcg_state_setseq_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_setseq_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t +pcg_setseq_32_xsh_rs_16_random_r(struct pcg_state_setseq_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_setseq_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t +pcg_setseq_32_xsh_rs_16_boundedrand_r(struct pcg_state_setseq_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_setseq_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t +pcg_setseq_64_xsh_rs_32_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t +pcg_setseq_64_xsh_rs_32_boundedrand_r(struct pcg_state_setseq_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rs_64_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rs_64_boundedrand_r(struct pcg_state_setseq_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_mcg_16_xsh_rs_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_mcg_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t pcg_mcg_16_xsh_rs_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_mcg_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_mcg_32_xsh_rs_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_mcg_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t pcg_mcg_32_xsh_rs_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_mcg_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_mcg_64_xsh_rs_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_mcg_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t pcg_mcg_64_xsh_rs_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_mcg_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rs_64_random_r(struct pcg_state_128* rng) +{ + pcg_mcg_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rs_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_mcg_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for XSH RR */ + +inline uint8_t pcg_oneseq_16_xsh_rr_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_oneseq_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t pcg_oneseq_16_xsh_rr_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_oneseq_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_oneseq_32_xsh_rr_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_oneseq_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t pcg_oneseq_32_xsh_rr_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_oneseq_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_oneseq_64_xsh_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t pcg_oneseq_64_xsh_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_xsh_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_oneseq_128_xsh_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_unique_16_xsh_rr_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_unique_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t pcg_unique_16_xsh_rr_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_unique_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_unique_32_xsh_rr_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_unique_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t pcg_unique_32_xsh_rr_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_unique_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_unique_64_xsh_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t pcg_unique_64_xsh_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_xsh_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_unique_128_xsh_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_setseq_16_xsh_rr_8_random_r(struct pcg_state_setseq_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_setseq_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t +pcg_setseq_16_xsh_rr_8_boundedrand_r(struct pcg_state_setseq_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_setseq_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t +pcg_setseq_32_xsh_rr_16_random_r(struct pcg_state_setseq_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_setseq_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t +pcg_setseq_32_xsh_rr_16_boundedrand_r(struct pcg_state_setseq_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_setseq_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t +pcg_setseq_64_xsh_rr_32_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t +pcg_setseq_64_xsh_rr_32_boundedrand_r(struct pcg_state_setseq_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rr_64_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rr_64_boundedrand_r(struct pcg_state_setseq_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_mcg_16_xsh_rr_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_mcg_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t pcg_mcg_16_xsh_rr_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_mcg_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_mcg_32_xsh_rr_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_mcg_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t pcg_mcg_32_xsh_rr_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_mcg_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_mcg_64_xsh_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_mcg_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t pcg_mcg_64_xsh_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_mcg_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_mcg_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_mcg_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for RXS M XS (no MCG versions because they + * don't make sense when you want to use the entire state) + */ + +inline uint8_t pcg_oneseq_8_rxs_m_xs_8_random_r(struct pcg_state_8* rng) +{ + uint8_t oldstate = rng->state; + pcg_oneseq_8_step_r(rng); + return pcg_output_rxs_m_xs_8_8(oldstate); +} + +inline uint8_t pcg_oneseq_8_rxs_m_xs_8_boundedrand_r(struct pcg_state_8* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_oneseq_8_rxs_m_xs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_oneseq_16_rxs_m_xs_16_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_oneseq_16_step_r(rng); + return pcg_output_rxs_m_xs_16_16(oldstate); +} + +inline uint16_t +pcg_oneseq_16_rxs_m_xs_16_boundedrand_r(struct pcg_state_16* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_oneseq_16_rxs_m_xs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_oneseq_32_rxs_m_xs_32_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_oneseq_32_step_r(rng); + return pcg_output_rxs_m_xs_32_32(oldstate); +} + +inline uint32_t +pcg_oneseq_32_rxs_m_xs_32_boundedrand_r(struct pcg_state_32* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_32_rxs_m_xs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint64_t pcg_oneseq_64_rxs_m_xs_64_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_rxs_m_xs_64_64(oldstate); +} + +inline uint64_t +pcg_oneseq_64_rxs_m_xs_64_boundedrand_r(struct pcg_state_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_64_rxs_m_xs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_oneseq_128_rxs_m_xs_128_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_rxs_m_xs_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_oneseq_128_rxs_m_xs_128_boundedrand_r(struct pcg_state_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_oneseq_128_rxs_m_xs_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint16_t pcg_unique_16_rxs_m_xs_16_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_unique_16_step_r(rng); + return pcg_output_rxs_m_xs_16_16(oldstate); +} + +inline uint16_t +pcg_unique_16_rxs_m_xs_16_boundedrand_r(struct pcg_state_16* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_unique_16_rxs_m_xs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_unique_32_rxs_m_xs_32_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_unique_32_step_r(rng); + return pcg_output_rxs_m_xs_32_32(oldstate); +} + +inline uint32_t +pcg_unique_32_rxs_m_xs_32_boundedrand_r(struct pcg_state_32* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_32_rxs_m_xs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint64_t pcg_unique_64_rxs_m_xs_64_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_rxs_m_xs_64_64(oldstate); +} + +inline uint64_t +pcg_unique_64_rxs_m_xs_64_boundedrand_r(struct pcg_state_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_64_rxs_m_xs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_unique_128_rxs_m_xs_128_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_rxs_m_xs_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_unique_128_rxs_m_xs_128_boundedrand_r(struct pcg_state_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_unique_128_rxs_m_xs_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_setseq_8_rxs_m_xs_8_random_r(struct pcg_state_setseq_8* rng) +{ + uint8_t oldstate = rng->state; + pcg_setseq_8_step_r(rng); + return pcg_output_rxs_m_xs_8_8(oldstate); +} + +inline uint8_t +pcg_setseq_8_rxs_m_xs_8_boundedrand_r(struct pcg_state_setseq_8* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_setseq_8_rxs_m_xs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t +pcg_setseq_16_rxs_m_xs_16_random_r(struct pcg_state_setseq_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_setseq_16_step_r(rng); + return pcg_output_rxs_m_xs_16_16(oldstate); +} + +inline uint16_t +pcg_setseq_16_rxs_m_xs_16_boundedrand_r(struct pcg_state_setseq_16* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_setseq_16_rxs_m_xs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t +pcg_setseq_32_rxs_m_xs_32_random_r(struct pcg_state_setseq_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_setseq_32_step_r(rng); + return pcg_output_rxs_m_xs_32_32(oldstate); +} + +inline uint32_t +pcg_setseq_32_rxs_m_xs_32_boundedrand_r(struct pcg_state_setseq_32* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_32_rxs_m_xs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint64_t +pcg_setseq_64_rxs_m_xs_64_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_rxs_m_xs_64_64(oldstate); +} + +inline uint64_t +pcg_setseq_64_rxs_m_xs_64_boundedrand_r(struct pcg_state_setseq_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_64_rxs_m_xs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_rxs_m_xs_128_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_rxs_m_xs_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_rxs_m_xs_128_boundedrand_r(struct pcg_state_setseq_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_setseq_128_rxs_m_xs_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for XSL RR (only defined for "large" types) */ + +inline uint32_t pcg_oneseq_64_xsl_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t pcg_oneseq_64_xsl_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_xsl_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_oneseq_128_xsl_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint32_t pcg_unique_64_xsl_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t pcg_unique_64_xsl_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_xsl_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_unique_128_xsl_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint32_t +pcg_setseq_64_xsl_rr_32_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t +pcg_setseq_64_xsl_rr_32_boundedrand_r(struct pcg_state_setseq_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsl_rr_64_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsl_rr_64_boundedrand_r(struct pcg_state_setseq_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint32_t pcg_mcg_64_xsl_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_mcg_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t pcg_mcg_64_xsl_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_mcg_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsl_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_mcg_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsl_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_mcg_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for XSL RR RR (only defined for "large" types) */ + +inline uint64_t pcg_oneseq_64_xsl_rr_rr_64_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsl_rr_rr_64_64(oldstate); +} + +inline uint64_t +pcg_oneseq_64_xsl_rr_rr_64_boundedrand_r(struct pcg_state_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_64_xsl_rr_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_oneseq_128_xsl_rr_rr_128_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_xsl_rr_rr_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_oneseq_128_xsl_rr_rr_128_boundedrand_r(struct pcg_state_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_oneseq_128_xsl_rr_rr_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint64_t pcg_unique_64_xsl_rr_rr_64_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsl_rr_rr_64_64(oldstate); +} + +inline uint64_t +pcg_unique_64_xsl_rr_rr_64_boundedrand_r(struct pcg_state_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_64_xsl_rr_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_unique_128_xsl_rr_rr_128_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_xsl_rr_rr_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_unique_128_xsl_rr_rr_128_boundedrand_r(struct pcg_state_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_unique_128_xsl_rr_rr_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint64_t +pcg_setseq_64_xsl_rr_rr_64_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsl_rr_rr_64_64(oldstate); +} + +inline uint64_t +pcg_setseq_64_xsl_rr_rr_64_boundedrand_r(struct pcg_state_setseq_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_64_xsl_rr_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_xsl_rr_rr_128_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_xsl_rr_rr_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_xsl_rr_rr_128_boundedrand_r(struct pcg_state_setseq_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_setseq_128_xsl_rr_rr_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +//// Typedefs +typedef struct pcg_state_setseq_64 pcg32_random_t; +typedef struct pcg_state_64 pcg32s_random_t; +typedef struct pcg_state_64 pcg32u_random_t; +typedef struct pcg_state_64 pcg32f_random_t; +//// random_r +#define pcg32_random_r pcg_setseq_64_xsh_rr_32_random_r +#define pcg32s_random_r pcg_oneseq_64_xsh_rr_32_random_r +#define pcg32u_random_r pcg_unique_64_xsh_rr_32_random_r +#define pcg32f_random_r pcg_mcg_64_xsh_rs_32_random_r +//// boundedrand_r +#define pcg32_boundedrand_r pcg_setseq_64_xsh_rr_32_boundedrand_r +#define pcg32s_boundedrand_r pcg_oneseq_64_xsh_rr_32_boundedrand_r +#define pcg32u_boundedrand_r pcg_unique_64_xsh_rr_32_boundedrand_r +#define pcg32f_boundedrand_r pcg_mcg_64_xsh_rs_32_boundedrand_r +//// srandom_r +#define pcg32_srandom_r pcg_setseq_64_srandom_r +#define pcg32s_srandom_r pcg_oneseq_64_srandom_r +#define pcg32u_srandom_r pcg_unique_64_srandom_r +#define pcg32f_srandom_r pcg_mcg_64_srandom_r +//// advance_r +#define pcg32_advance_r pcg_setseq_64_advance_r +#define pcg32s_advance_r pcg_oneseq_64_advance_r +#define pcg32u_advance_r pcg_unique_64_advance_r +#define pcg32f_advance_r pcg_mcg_64_advance_r + +#if PCG_HAS_128BIT_OPS +//// Typedefs +typedef struct pcg_state_setseq_128 pcg64_random_t; +typedef struct pcg_state_128 pcg64s_random_t; +typedef struct pcg_state_128 pcg64u_random_t; +typedef struct pcg_state_128 pcg64f_random_t; +//// random_r +#define pcg64_random_r pcg_setseq_128_xsl_rr_64_random_r +#define pcg64s_random_r pcg_oneseq_128_xsl_rr_64_random_r +#define pcg64u_random_r pcg_unique_128_xsl_rr_64_random_r +#define pcg64f_random_r pcg_mcg_128_xsl_rr_64_random_r +//// boundedrand_r +#define pcg64_boundedrand_r pcg_setseq_128_xsl_rr_64_boundedrand_r +#define pcg64s_boundedrand_r pcg_oneseq_128_xsl_rr_64_boundedrand_r +#define pcg64u_boundedrand_r pcg_unique_128_xsl_rr_64_boundedrand_r +#define pcg64f_boundedrand_r pcg_mcg_128_xsl_rr_64_boundedrand_r +//// srandom_r +#define pcg64_srandom_r pcg_setseq_128_srandom_r +#define pcg64s_srandom_r pcg_oneseq_128_srandom_r +#define pcg64u_srandom_r pcg_unique_128_srandom_r +#define pcg64f_srandom_r pcg_mcg_128_srandom_r +//// advance_r +#define pcg64_advance_r pcg_setseq_128_advance_r +#define pcg64s_advance_r pcg_oneseq_128_advance_r +#define pcg64u_advance_r pcg_unique_128_advance_r +#define pcg64f_advance_r pcg_mcg_128_advance_r +#endif + +//// Typedefs +typedef struct pcg_state_8 pcg8si_random_t; +typedef struct pcg_state_16 pcg16si_random_t; +typedef struct pcg_state_32 pcg32si_random_t; +typedef struct pcg_state_64 pcg64si_random_t; +//// random_r +#define pcg8si_random_r pcg_oneseq_8_rxs_m_xs_8_random_r +#define pcg16si_random_r pcg_oneseq_16_rxs_m_xs_16_random_r +#define pcg32si_random_r pcg_oneseq_32_rxs_m_xs_32_random_r +#define pcg64si_random_r pcg_oneseq_64_rxs_m_xs_64_random_r +//// boundedrand_r +#define pcg8si_boundedrand_r pcg_oneseq_8_rxs_m_xs_8_boundedrand_r +#define pcg16si_boundedrand_r pcg_oneseq_16_rxs_m_xs_16_boundedrand_r +#define pcg32si_boundedrand_r pcg_oneseq_32_rxs_m_xs_32_boundedrand_r +#define pcg64si_boundedrand_r pcg_oneseq_64_rxs_m_xs_64_boundedrand_r +//// srandom_r +#define pcg8si_srandom_r pcg_oneseq_8_srandom_r +#define pcg16si_srandom_r pcg_oneseq_16_srandom_r +#define pcg32si_srandom_r pcg_oneseq_32_srandom_r +#define pcg64si_srandom_r pcg_oneseq_64_srandom_r +//// advance_r +#define pcg8si_advance_r pcg_oneseq_8_advance_r +#define pcg16si_advance_r pcg_oneseq_16_advance_r +#define pcg32si_advance_r pcg_oneseq_32_advance_r +#define pcg64si_advance_r pcg_oneseq_64_advance_r + +#if PCG_HAS_128BIT_OPS +typedef struct pcg_state_128 pcg128si_random_t; +#define pcg128si_random_r pcg_oneseq_128_rxs_m_xs_128_random_r +#define pcg128si_boundedrand_r pcg_oneseq_128_rxs_m_xs_128_boundedrand_r +#define pcg128si_srandom_r pcg_oneseq_128_srandom_r +#define pcg128si_advance_r pcg_oneseq_128_advance_r +#endif + +//// Typedefs +typedef struct pcg_state_setseq_8 pcg8i_random_t; +typedef struct pcg_state_setseq_16 pcg16i_random_t; +typedef struct pcg_state_setseq_32 pcg32i_random_t; +typedef struct pcg_state_setseq_64 pcg64i_random_t; +//// random_r +#define pcg8i_random_r pcg_setseq_8_rxs_m_xs_8_random_r +#define pcg16i_random_r pcg_setseq_16_rxs_m_xs_16_random_r +#define pcg32i_random_r pcg_setseq_32_rxs_m_xs_32_random_r +#define pcg64i_random_r pcg_setseq_64_rxs_m_xs_64_random_r +//// boundedrand_r +#define pcg8i_boundedrand_r pcg_setseq_8_rxs_m_xs_8_boundedrand_r +#define pcg16i_boundedrand_r pcg_setseq_16_rxs_m_xs_16_boundedrand_r +#define pcg32i_boundedrand_r pcg_setseq_32_rxs_m_xs_32_boundedrand_r +#define pcg64i_boundedrand_r pcg_setseq_64_rxs_m_xs_64_boundedrand_r +//// srandom_r +#define pcg8i_srandom_r pcg_setseq_8_srandom_r +#define pcg16i_srandom_r pcg_setseq_16_srandom_r +#define pcg32i_srandom_r pcg_setseq_32_srandom_r +#define pcg64i_srandom_r pcg_setseq_64_srandom_r +//// advance_r +#define pcg8i_advance_r pcg_setseq_8_advance_r +#define pcg16i_advance_r pcg_setseq_16_advance_r +#define pcg32i_advance_r pcg_setseq_32_advance_r +#define pcg64i_advance_r pcg_setseq_64_advance_r + +#if PCG_HAS_128BIT_OPS +typedef struct pcg_state_setseq_128 pcg128i_random_t; +#define pcg128i_random_r pcg_setseq_128_rxs_m_xs_128_random_r +#define pcg128i_boundedrand_r pcg_setseq_128_rxs_m_xs_128_boundedrand_r +#define pcg128i_srandom_r pcg_setseq_128_srandom_r +#define pcg128i_advance_r pcg_setseq_128_advance_r +#endif + +extern uint32_t pcg32_random(); +extern uint32_t pcg32_boundedrand(uint32_t bound); +extern void pcg32_srandom(uint64_t seed, uint64_t seq); +extern void pcg32_advance(uint64_t delta); + +#if PCG_HAS_128BIT_OPS +extern uint64_t pcg64_random(); +extern uint64_t pcg64_boundedrand(uint64_t bound); +extern void pcg64_srandom(pcg128_t seed, pcg128_t seq); +extern void pcg64_advance(pcg128_t delta); +#endif + +/* + * Static initialization constants (if you can't call srandom for some + * bizarre reason). + */ + +#define PCG32_INITIALIZER PCG_STATE_SETSEQ_64_INITIALIZER +#define PCG32U_INITIALIZER PCG_STATE_UNIQUE_64_INITIALIZER +#define PCG32S_INITIALIZER PCG_STATE_ONESEQ_64_INITIALIZER +#define PCG32F_INITIALIZER PCG_STATE_MCG_64_INITIALIZER + +#if PCG_HAS_128BIT_OPS +#define PCG64_INITIALIZER PCG_STATE_SETSEQ_128_INITIALIZER +#define PCG64U_INITIALIZER PCG_STATE_UNIQUE_128_INITIALIZER +#define PCG64S_INITIALIZER PCG_STATE_ONESEQ_128_INITIALIZER +#define PCG64F_INITIALIZER PCG_STATE_MCG_128_INITIALIZER +#endif + +#define PCG8SI_INITIALIZER PCG_STATE_ONESEQ_8_INITIALIZER +#define PCG16SI_INITIALIZER PCG_STATE_ONESEQ_16_INITIALIZER +#define PCG32SI_INITIALIZER PCG_STATE_ONESEQ_32_INITIALIZER +#define PCG64SI_INITIALIZER PCG_STATE_ONESEQ_64_INITIALIZER +#if PCG_HAS_128BIT_OPS +#define PCG128SI_INITIALIZER PCG_STATE_ONESEQ_128_INITIALIZER +#endif + +#define PCG8I_INITIALIZER PCG_STATE_SETSEQ_8_INITIALIZER +#define PCG16I_INITIALIZER PCG_STATE_SETSEQ_16_INITIALIZER +#define PCG32I_INITIALIZER PCG_STATE_SETSEQ_32_INITIALIZER +#define PCG64I_INITIALIZER PCG_STATE_SETSEQ_64_INITIALIZER +#if PCG_HAS_128BIT_OPS +#define PCG128I_INITIALIZER PCG_STATE_SETSEQ_128_INITIALIZER +#endif + +#if __cplusplus +} +#endif + +#endif // PCG_VARIANTS_H_INCLUDED diff --git a/_randomgen/core_prng/tests/data/pcg32-testset-1.csv b/_randomgen/core_prng/tests/data/pcg32-testset-1.csv new file mode 100644 index 000000000000..6bddc8d5ccc2 --- /dev/null +++ b/_randomgen/core_prng/tests/data/pcg32-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 0xdeadbeaf +0, 0xbeb77374 +1, 0x75cad014 +2, 0xabc6773e +3, 0xe99a034e +4, 0x1e3f5c6d +5, 0x513d3c5b +6, 0x4a378bad +7, 0xba5b3488 +8, 0x21e96448 +9, 0x5197a3d3 +10, 0x84bbcc90 +11, 0x674fce76 +12, 0xd1dd9879 +13, 0x1625afd4 +14, 0x4bb5e330 +15, 0x3f4b8f74 +16, 0xf0a7c00b +17, 0xecdb92d0 +18, 0xf069232c +19, 0x56dbeaa2 +20, 0x70c62231 +21, 0x6c68e57e +22, 0x3829213c +23, 0x9b8bc5e6 +24, 0x45abd553 +25, 0xf5991ce7 +26, 0xb4aff20a +27, 0x677a5785 +28, 0x108f180d +29, 0x2b3f1001 +30, 0x838fdfcb +31, 0x8ad3c2a0 +32, 0x596268fa +33, 0xee6bcc56 +34, 0x46810af0 +35, 0x1648a587 +36, 0x7265a926 +37, 0xed0f3acc +38, 0x72a1ac0 +39, 0xb3f7109f +40, 0x6ddd75f2 +41, 0xa968127f +42, 0x40df20fd +43, 0xde835b80 +44, 0xe453cd68 +45, 0x26ad68eb +46, 0x23a052d2 +47, 0x17881c5c +48, 0x785d41b9 +49, 0x61b4530a +50, 0x5ee92c84 +51, 0x4cad7358 +52, 0x843db584 +53, 0x3576368b +54, 0x14db6b2b +55, 0xb6e8b042 +56, 0x6323e866 +57, 0x9a709e25 +58, 0xae594bdc +59, 0x4be9ec1b +60, 0x77b4fd05 +61, 0x4421667 +62, 0x24bf98f7 +63, 0xfb202aed +64, 0x2f01b05f +65, 0xac766e69 +66, 0xc1572ce2 +67, 0xb26354d6 +68, 0x4db5f193 +69, 0x41a4609b +70, 0x26bbb4cc +71, 0x676b7438 +72, 0x13b2be7d +73, 0x7df521c4 +74, 0x57f770f3 +75, 0x78a8a8 +76, 0x164d46c6 +77, 0xbb29da20 +78, 0x5c262bf9 +79, 0xfd305d0 +80, 0xb500d90b +81, 0xbb7b4e37 +82, 0x5ba2bbfd +83, 0xa9561043 +84, 0xe175c662 +85, 0x3a5c8eec +86, 0xac5e2184 +87, 0x1e1c7de7 +88, 0x46be092a +89, 0x8b82f5be +90, 0xb1c1b591 +91, 0x6f06d957 +92, 0x1d26dc5c +93, 0x158c57e3 +94, 0x6da1ebf8 +95, 0x74501e60 +96, 0x70587043 +97, 0xa19b90fe +98, 0x7d327dff +99, 0x22dc6b90 +100, 0xf48a9ae6 +101, 0x75eeb769 +102, 0x9cdc12cb +103, 0x7fe2cdc6 +104, 0x4fba8066 +105, 0x1a7a0667 +106, 0xd9289d22 +107, 0x3a045bce +108, 0x60e5f71f +109, 0xd81b35dc +110, 0xceae6194 +111, 0xa032a688 +112, 0x7157b327 +113, 0x61c74c80 +114, 0x2d519c39 +115, 0x5b1a352e +116, 0x5ad266da +117, 0x9118352b +118, 0xdd20b6e1 +119, 0xc0d154fa +120, 0x93bbb9c9 +121, 0x91170de2 +122, 0xa3af5e05 +123, 0x1b19ff2f +124, 0xf814c3bf +125, 0x8914a953 +126, 0x5278efb7 +127, 0x3c96d7bd +128, 0xb5422a7 +129, 0x2aee2619 +130, 0x60c6a90c +131, 0xfbec0e9c +132, 0xef794075 +133, 0xda93d22e +134, 0xb956d02a +135, 0xd97cc49b +136, 0x80737244 +137, 0x7c56a95 +138, 0xa5311355 +139, 0x7dcdd592 +140, 0x92add23e +141, 0xb1ba1317 +142, 0x507e5330 +143, 0x2644b95a +144, 0xa1afa519 +145, 0x596c65c0 +146, 0x6f47dd11 +147, 0xfd2fbada +148, 0x98675d7c +149, 0xb9e21413 +150, 0x8bae5eca +151, 0xe1f50018 +152, 0x7dd08715 +153, 0x36a888e1 +154, 0x7fcd6364 +155, 0xb84c093 +156, 0x18e2d58f +157, 0x19fd21ed +158, 0x3c25e3a3 +159, 0x7a0d833b +160, 0x47525b28 +161, 0xba88474 +162, 0xd108e7da +163, 0x32b06660 +164, 0xbce027b3 +165, 0x96b31787 +166, 0x916ab263 +167, 0xa5fa088 +168, 0x3cb9cd59 +169, 0x7a97051f +170, 0x104b6883 +171, 0x6e08c314 +172, 0x33a4c62c +173, 0x14eb854 +174, 0x873f730a +175, 0x8c3f7224 +176, 0x9a41beeb +177, 0xe4e2ab0a +178, 0xfa89ad0e +179, 0x4aa62ac3 +180, 0xb75dc1bf +181, 0x3f4c5131 +182, 0x3fef0f91 +183, 0xffa06655 +184, 0x417d7d38 +185, 0x1e7734df +186, 0x25685235 +187, 0x33fe5b68 +188, 0x68923f72 +189, 0x5da45ff +190, 0xb871df26 +191, 0xd3ffd8c6 +192, 0x1718d862 +193, 0xe127d844 +194, 0xadcdc48a +195, 0x79ee30cb +196, 0x931a6cba +197, 0x9463c42d +198, 0x9f8d2806 +199, 0xa3695a97 +200, 0xfc9587bc +201, 0xb3943573 +202, 0x50ed8901 +203, 0x6891f33 +204, 0xb7a12dfb +205, 0x1245cf5d +206, 0xbc0f73a7 +207, 0x26cbfeb2 +208, 0x774d8e83 +209, 0xa19e9c1 +210, 0xc147a437 +211, 0xe034f2a3 +212, 0xd288b664 +213, 0xdcd0356d +214, 0x2b695901 +215, 0x3bc31736 +216, 0x4a5b1998 +217, 0x18537410 +218, 0x11b40f35 +219, 0xf16f6f89 +220, 0xe844cffe +221, 0xce026166 +222, 0x3770aaba +223, 0xc62566ee +224, 0x6db2d1f8 +225, 0xe4720b6d +226, 0x68321a69 +227, 0x488539ac +228, 0x5e18ab61 +229, 0xb58e598e +230, 0x6f501a91 +231, 0xc4fd3e8d +232, 0x9faa3631 +233, 0x184366b0 +234, 0xecf74d6a +235, 0x3773d622 +236, 0x382ca536 +237, 0x93451381 +238, 0x9f148ed5 +239, 0x2b66f241 +240, 0xa6807c39 +241, 0xbb087446 +242, 0xa18ba432 +243, 0x8e7a6013 +244, 0xab30278e +245, 0xbf457c78 +246, 0xb24814b1 +247, 0x710f99d5 +248, 0xbcb84762 +249, 0x4913a7e7 +250, 0x90a31a0c +251, 0x6d4b1673 +252, 0x18873994 +253, 0x1efd517a +254, 0x99b499d1 +255, 0x2d488776 +256, 0x1cded201 +257, 0xa53b02e4 +258, 0xcb20d0fd +259, 0x72bfaae3 +260, 0x858c865b +261, 0x2e2d3e96 +262, 0x8bc5b0b9 +263, 0x8980346a +264, 0xa8e47fba +265, 0x2a39fe16 +266, 0x9f34eeeb +267, 0x7baebcc9 +268, 0xbc0b8d74 +269, 0x37373c8 +270, 0xe128cfc4 +271, 0x49cdb150 +272, 0x5965c726 +273, 0xfc326226 +274, 0x53a3e8e +275, 0xa99d89f7 +276, 0x33ac111c +277, 0x143fe678 +278, 0x96212281 +279, 0x6a83bffd +280, 0x529852f7 +281, 0x97fef4 +282, 0x303ce151 +283, 0x4f8c7b83 +284, 0xd5ef9c82 +285, 0xede9d572 +286, 0xc03e2c38 +287, 0x89d7f886 +288, 0x21e998b0 +289, 0x58d505cf +290, 0x5c42089 +291, 0x9a01dcab +292, 0x83d8cc17 +293, 0x7d6aacf +294, 0xa1cbdced +295, 0x47365e25 +296, 0xbb61e976 +297, 0xfeafd0a6 +298, 0x760d82b4 +299, 0x9ffb351d +300, 0x28e19ac0 +301, 0x891131c6 +302, 0xc1656522 +303, 0x4536d90 +304, 0x956b1b84 +305, 0xf9ff54f6 +306, 0xb0050d88 +307, 0x7d7fafa2 +308, 0x430e670b +309, 0x18ad450d +310, 0xd5a1d6b6 +311, 0x390a6da4 +312, 0xc70d557d +313, 0xd8fadb5e +314, 0xfb4b4cb6 +315, 0xce707f8b +316, 0x4c18d350 +317, 0x8dc0d200 +318, 0x228d9e85 +319, 0xd6485ba3 +320, 0x37c4a70a +321, 0x9d7cc5f5 +322, 0x889a9b9 +323, 0x41d2f942 +324, 0x4c13b3bd +325, 0x70e58147 +326, 0x4a0e1270 +327, 0x3cdc1b73 +328, 0x7a4e56f3 +329, 0xd8350406 +330, 0x46068108 +331, 0xfc4da48 +332, 0xf6111245 +333, 0x40a15167 +334, 0x38a591ac +335, 0x3e97e682 +336, 0x5c515d2d +337, 0x45023a37 +338, 0xacb0ed6a +339, 0x899f0ebb +340, 0x2054df01 +341, 0x6d629607 +342, 0x79ced597 +343, 0xba0a3a12 +344, 0xde63b611 +345, 0x228cb776 +346, 0x61f10dba +347, 0x9a1095d3 +348, 0xf08dcb3 +349, 0x88e58009 +350, 0x131880aa +351, 0xc55002ee +352, 0xcf556f47 +353, 0x17b6dd76 +354, 0x6110ba20 +355, 0x74a91935 +356, 0xe83cf9ed +357, 0x3138e936 +358, 0x103bfb72 +359, 0x2084abe4 +360, 0xf3a05dd9 +361, 0x9213f3a4 +362, 0xe7674dd7 +363, 0xcd09d629 +364, 0x260461f2 +365, 0x411c2428 +366, 0xbb5f6f2e +367, 0x6feb8c93 +368, 0x3cde3ece +369, 0x7a424d2c +370, 0x808a0948 +371, 0x653c3fdf +372, 0x26f88849 +373, 0xf540b6ae +374, 0x1f82e8ac +375, 0x300f7e39 +376, 0xb6e62e7b +377, 0x970441a1 +378, 0x91f2946c +379, 0xaad281f +380, 0x43be1dcf +381, 0x95a1b4c8 +382, 0x2d956dea +383, 0xc532ca29 +384, 0xc93f1fcf +385, 0x70762aab +386, 0x231a72ef +387, 0xe5bd1b75 +388, 0xfa31468 +389, 0x77e1b7b5 +390, 0x19d80215 +391, 0xd45704b7 +392, 0x33472a0d +393, 0x833a435e +394, 0x2354a326 +395, 0x8af39828 +396, 0x603a7960 +397, 0x288c2d54 +398, 0x75bd7c23 +399, 0xe2dd42e1 +400, 0x9a87b486 +401, 0x32e9bcd1 +402, 0x8630f74f +403, 0x160408ea +404, 0xd2127c63 +405, 0xaf327f8e +406, 0x8d879a61 +407, 0xc5c88f60 +408, 0x53a19fa1 +409, 0x706dacb4 +410, 0xd04ea0f +411, 0x94806c1a +412, 0x941cfe69 +413, 0x956a5562 +414, 0xee1f71c +415, 0xe6ba12d +416, 0x333e31f6 +417, 0x17aee12e +418, 0x20ccfedb +419, 0xd7bb7f92 +420, 0xba7d14f3 +421, 0xb935d4fb +422, 0xbdb8f5e1 +423, 0xb24e7adc +424, 0xc9abef71 +425, 0x3e3d8125 +426, 0x5fc0878b +427, 0x5ba172d9 +428, 0xe28f648c +429, 0x5137f3a7 +430, 0xb57273df +431, 0xe68df236 +432, 0xbc29802b +433, 0xb1419e66 +434, 0x69ecb739 +435, 0x490e8eb6 +436, 0x61e25a6c +437, 0xc1fa0de6 +438, 0x2bf2fbf1 +439, 0x9487e8da +440, 0xce5c5532 +441, 0x75859040 +442, 0x2606bdeb +443, 0x1b77c072 +444, 0xe5fbeed1 +445, 0xea9e1ab3 +446, 0x55cf96ae +447, 0x283ed27d +448, 0xc94067a1 +449, 0x8687b3e5 +450, 0x4031b307 +451, 0xc5790e82 +452, 0x4031ee7f +453, 0x952c4503 +454, 0x379ec606 +455, 0x7c35e19d +456, 0x2d333769 +457, 0xbca36d54 +458, 0xcdc70741 +459, 0xa3ab56fb +460, 0x187a2fd6 +461, 0xdd1f32f1 +462, 0xc007ac56 +463, 0x14c441c1 +464, 0xf290ed47 +465, 0xc833edac +466, 0x13f0a8fe +467, 0x63c10b6e +468, 0x6af1be34 +469, 0x5bd4930e +470, 0xfe56bfbb +471, 0x1b412c8e +472, 0xf0c7712a +473, 0xf3a96226 +474, 0xbd0aaad8 +475, 0xbd00355e +476, 0x8ba9eca1 +477, 0x81f136a0 +478, 0x7de3a327 +479, 0x7be298ea +480, 0xe60e320a +481, 0xaf4373b +482, 0x6eacbf3 +483, 0x1291760f +484, 0xd48ed89b +485, 0x596603d4 +486, 0x53abc8 +487, 0x82123b2f +488, 0x1276dc8 +489, 0xfeb474bb +490, 0x4013da51 +491, 0x111cb9d6 +492, 0x5726df82 +493, 0x45806861 +494, 0x2580801a +495, 0x1326049e +496, 0xb9474bf9 +497, 0x6c5d85ed +498, 0x9c4a9352 +499, 0x9eb915ed +500, 0x914505 +501, 0xd14c5b9a +502, 0x57ef8ffd +503, 0x480d8719 +504, 0xb18d7fce +505, 0xfd29e178 +506, 0x2679f6c9 +507, 0xd94a086e +508, 0x6e46f559 +509, 0xb7c3a2e3 +510, 0x793a4c3b +511, 0x4e5252f9 +512, 0x1bdb53a4 +513, 0xbed5794 +514, 0x31a3ebc7 +515, 0xa6eb54e1 +516, 0xc6ae5d92 +517, 0x392acfc8 +518, 0xb283fb8f +519, 0x80b15ffe +520, 0x763b49a8 +521, 0x3febc1d3 +522, 0x60f2b20 +523, 0xd93aeba9 +524, 0xeddf06bb +525, 0x13992ab3 +526, 0x4521bcf6 +527, 0x5ad82a14 +528, 0xf2bfc79c +529, 0xf664b9b +530, 0xeb9540a2 +531, 0x5641dc50 +532, 0x9282d9c4 +533, 0x5d2443a4 +534, 0x407b5011 +535, 0x84a415d7 +536, 0x5db90eae +537, 0xd2947d4c +538, 0x8bd8856d +539, 0xbc05a99b +540, 0x1c2e0f5 +541, 0xb94d03a2 +542, 0xb8ed5ac1 +543, 0x199943d9 +544, 0x12482e5c +545, 0x20aa7c9f +546, 0x8733e45c +547, 0x277b4f44 +548, 0x673d5a73 +549, 0xabc0aad9 +550, 0xbed6cd98 +551, 0x2943c24b +552, 0x5237d6f9 +553, 0x1cb1a392 +554, 0xc7b69454 +555, 0x4f792707 +556, 0xa32ef400 +557, 0x7a5b6b72 +558, 0xa8683acc +559, 0x418d0491 +560, 0x56e2470e +561, 0xbe385495 +562, 0xe7944341 +563, 0x438abaab +564, 0x82ad2c2 +565, 0x7afc306b +566, 0xfcb88957 +567, 0x530414bd +568, 0x2e3c7d41 +569, 0x633f7573 +570, 0xeffeefb2 +571, 0xf6de11f9 +572, 0x337710f2 +573, 0x88bf46dc +574, 0x6fdaf5dc +575, 0x34229d26 +576, 0x46b0aba0 +577, 0x78e40a29 +578, 0x7f9623cd +579, 0x6cfe8779 +580, 0x1d4af99 +581, 0x78f97244 +582, 0xa198d714 +583, 0x9124883e +584, 0x1cf88a12 +585, 0x69fe0966 +586, 0x78484a68 +587, 0xf9d8718b +588, 0xcbf3ba5b +589, 0xf67fb149 +590, 0xc95977c1 +591, 0x474f57f5 +592, 0x11bb9ec1 +593, 0xe28f21be +594, 0x8ca6e21b +595, 0x2609defc +596, 0x989b6f6b +597, 0x1c87383e +598, 0xacd78f57 +599, 0x8c46cfcb +600, 0xc37cce08 +601, 0x327d196a +602, 0xf63c3572 +603, 0xc56780b5 +604, 0x9ac37d16 +605, 0xe692a39c +606, 0x563938a3 +607, 0x1e80e32f +608, 0x745652af +609, 0xe425c9a8 +610, 0x11c71e82 +611, 0x9c721f6d +612, 0xef89b973 +613, 0x494c7e80 +614, 0xadc29895 +615, 0xc7ee35ad +616, 0x19beeb0c +617, 0x9c25ae3f +618, 0x27bf930f +619, 0x223970a0 +620, 0x7cdb17ca +621, 0xa49054f +622, 0xf8321dcb +623, 0x3f96a9eb +624, 0x4468072a +625, 0xfd7d727 +626, 0xee0af4f1 +627, 0xe6585512 +628, 0x56a6d8a1 +629, 0x40586642 +630, 0xb46bdaa0 +631, 0xe053a140 +632, 0x4de1953d +633, 0xb6cbc718 +634, 0x2ed92c19 +635, 0x9da2840 +636, 0x6ab418b1 +637, 0x179f64cf +638, 0x7c281c0 +639, 0x7015b62a +640, 0x8d31e38e +641, 0xa6de57ca +642, 0xe509c4e1 +643, 0xa010162c +644, 0xf71abd42 +645, 0x3d24ac8b +646, 0xc2deb72f +647, 0xd81570ba +648, 0x17fc7d15 +649, 0xf17997b6 +650, 0xfa2ec5b5 +651, 0xbf7e189b +652, 0xb3d9e761 +653, 0xe1194bd1 +654, 0x8d5280dd +655, 0xdea2d148 +656, 0x6d85e66c +657, 0x37f5fb07 +658, 0x65c1dd1 +659, 0xf52c04f8 +660, 0x4460d846 +661, 0x1729f55f +662, 0xe03a699d +663, 0x9f05ff9f +664, 0x31abe986 +665, 0x64899f61 +666, 0x52fba7 +667, 0x2833ce74 +668, 0xa34d0e57 +669, 0x7203d492 +670, 0x1a63d91e +671, 0x463781b7 +672, 0xf9842e7b +673, 0x809276ad +674, 0x88237b9d +675, 0xaa648b06 +676, 0x9cf916bd +677, 0x3b3068e4 +678, 0x20d6ae7d +679, 0x7855dafd +680, 0x9ebd14ed +681, 0xc5934a1c +682, 0xb3c421a1 +683, 0xa2b709a2 +684, 0x91fa8b34 +685, 0x9009a54 +686, 0xb2c4215f +687, 0x7b294eb1 +688, 0x1802911e +689, 0xa2067de5 +690, 0x5ebd85e9 +691, 0xc4f8e698 +692, 0xd143d368 +693, 0x2ca2b6fb +694, 0xb5d27ebc +695, 0x410146ca +696, 0x9d6948fe +697, 0xfafd0af5 +698, 0x290e9c5f +699, 0x2ff06292 +700, 0x417903d5 +701, 0xc51af07c +702, 0xd2bbaf6b +703, 0xfa3720f1 +704, 0x4a6eb52d +705, 0xed86ad3c +706, 0x72a8676e +707, 0xc3c2bbed +708, 0x62b6a951 +709, 0xe08f9534 +710, 0xe2686ea5 +711, 0x3dbbf99b +712, 0xfec5319f +713, 0xef9c67eb +714, 0x9d69d19b +715, 0xc732ed2 +716, 0xc6e829bd +717, 0xe712e882 +718, 0xd24594ca +719, 0x102b8426 +720, 0xa5145730 +721, 0x62fecd71 +722, 0xe6439ca2 +723, 0x58819419 +724, 0xef722791 +725, 0x5ef6ab17 +726, 0x85ce3714 +727, 0xd4e18303 +728, 0xf91eb9c2 +729, 0x86bae692 +730, 0x6d81c21c +731, 0xd9985982 +732, 0xfdd55f22 +733, 0x72ecd91a +734, 0x4b1cee6 +735, 0xefa672ec +736, 0x3f18114f +737, 0xacae5e62 +738, 0x68369afd +739, 0xff5e6612 +740, 0x3760af8c +741, 0xd8c878bf +742, 0x3945fe59 +743, 0x2cf7f99a +744, 0x2cc59bb4 +745, 0xbba95cd6 +746, 0x6511688d +747, 0xcf326178 +748, 0xf850cc68 +749, 0x4bd2540e +750, 0xa02cf5e5 +751, 0x5546fcb5 +752, 0xe2b289fd +753, 0x960c6ba +754, 0x3a2c9d74 +755, 0x2def7a8f +756, 0x54e57d43 +757, 0xf953c277 +758, 0xd9b414b1 +759, 0x19a25920 +760, 0xaf2691a1 +761, 0x81e88159 +762, 0x49a3eab +763, 0x276a797d +764, 0x98337885 +765, 0x37055fd0 +766, 0x6927effc +767, 0xb6de7fc0 +768, 0x9e920f9a +769, 0xd2dc9145 +770, 0xe2861109 +771, 0xe42e2c1e +772, 0x836fe968 +773, 0x23452a15 +774, 0xd49f0e2b +775, 0x2998f647 +776, 0x94f8c803 +777, 0xf8be479e +778, 0xfd44079f +779, 0x685ab9c1 +780, 0xea8eeab3 +781, 0x580ff5d8 +782, 0x88ad0666 +783, 0x19df5d86 +784, 0xe4862012 +785, 0x3ad25460 +786, 0x677449ce +787, 0x1c7e0b9a +788, 0x287a98d0 +789, 0xed39d094 +790, 0x40501707 +791, 0xb99073a4 +792, 0x31847bd4 +793, 0x91e5b7 +794, 0x46815e56 +795, 0xc823384c +796, 0xdb6fb24 +797, 0xabe50dd8 +798, 0x2a33797b +799, 0x4fb617ec +800, 0x811a36df +801, 0xb6b7a25f +802, 0x8962cd0a +803, 0xc40818fe +804, 0x5dbe4e57 +805, 0x591f6c61 +806, 0x22aa4809 +807, 0xc0e4a72 +808, 0xa8a0e2e7 +809, 0xf91d553a +810, 0x77674da7 +811, 0x196657d6 +812, 0x5ae38c0f +813, 0x8bcf1ed2 +814, 0x9e0a2c8f +815, 0xf94e5215 +816, 0x11299b2b +817, 0xc499eca3 +818, 0x25e58d1b +819, 0xdd722954 +820, 0x816f4c21 +821, 0x2504fd9b +822, 0x722a597a +823, 0x92f80aab +824, 0xe2d7e54d +825, 0xefb26dba +826, 0x9ebf8863 +827, 0xd297ec21 +828, 0xa0ebfbb5 +829, 0xec609873 +830, 0xd079b3d1 +831, 0x920f722d +832, 0xfd58146 +833, 0x5fbb5784 +834, 0x30187f5d +835, 0x887f4ec6 +836, 0x6839a2ed +837, 0x72bccd98 +838, 0x7565903e +839, 0x8d3afaef +840, 0xfb713a03 +841, 0x34216b35 +842, 0xbe0da7e9 +843, 0x4b11764e +844, 0x6666922a +845, 0x3f2dc90d +846, 0xeca8fb8d +847, 0x91579404 +848, 0x8d413df7 +849, 0x2a0f8307 +850, 0x39d5a495 +851, 0x79ba5e62 +852, 0xbb06fd0f +853, 0x47ba4208 +854, 0x4a2efb9c +855, 0xee3a07f0 +856, 0x291a73e0 +857, 0xe42a46c5 +858, 0x203455b2 +859, 0x40545253 +860, 0xa618bb0a +861, 0xd4792a15 +862, 0xd6e62559 +863, 0x8149e2f0 +864, 0x5f6499a9 +865, 0xa63fc585 +866, 0xe33e1c1f +867, 0x36ecb45b +868, 0x267883ca +869, 0x905d98fb +870, 0xfac3512c +871, 0x374d0a0e +872, 0x9920f3e0 +873, 0xfb961c9f +874, 0x70f2d752 +875, 0x69c44d12 +876, 0xcb6075d2 +877, 0xaf802ac8 +878, 0x2c4b792b +879, 0xa2203217 +880, 0xc2c15619 +881, 0xb13af213 +882, 0x759b165c +883, 0x411ecdf2 +884, 0x158e5fba +885, 0x70874450 +886, 0x226a484f +887, 0x87b95ecf +888, 0x45cef22f +889, 0xfaf186bd +890, 0x3544972a +891, 0xb4a2f73 +892, 0x5f5d10de +893, 0xf3d05e29 +894, 0x7616ba85 +895, 0x4d2e198 +896, 0x1f240293 +897, 0x317c2286 +898, 0x3bd97e7b +899, 0xd7e39d6f +900, 0x142ee43c +901, 0x688ada72 +902, 0xad8deac8 +903, 0xf7cc8d5e +904, 0xa84600f5 +905, 0xda6b1b3 +906, 0x5bad09de +907, 0x6f4276c7 +908, 0xa789933f +909, 0xede4329a +910, 0xa31f2df5 +911, 0x869c0c3c +912, 0x6658f5b +913, 0xdb451b7c +914, 0x16ec0b18 +915, 0x2e35872c +916, 0xf7bf3c44 +917, 0xda59c872 +918, 0x1ab63c0c +919, 0x9a361a82 +920, 0xd2e1afcc +921, 0x5c41ac55 +922, 0xd1d761db +923, 0x3639bb85 +924, 0x7a418cfb +925, 0xf0b06b8f +926, 0xa2ef4d47 +927, 0x4fac4d1b +928, 0x47e42283 +929, 0x6ee6a7df +930, 0xfe786975 +931, 0x4475b665 +932, 0xd881e311 +933, 0x6b02224 +934, 0xcba19b84 +935, 0x4efa35f6 +936, 0x3873a72d +937, 0x984d7964 +938, 0xe23cda62 +939, 0xea9949d2 +940, 0x243b83b1 +941, 0x48d1bcc4 +942, 0xe35b6a23 +943, 0x125288f1 +944, 0x72fdd401 +945, 0xa2af6873 +946, 0x7c211096 +947, 0xa00a13dd +948, 0x7b4ce5d6 +949, 0x1e4be120 +950, 0xc771cc00 +951, 0x343ae31 +952, 0xe8e0be50 +953, 0xd9095a3f +954, 0x616b7c17 +955, 0xa96e1580 +956, 0x60501426 +957, 0xeaac50b +958, 0x130c33b5 +959, 0xba30925b +960, 0xf942c440 +961, 0xc52e8e20 +962, 0x5f460318 +963, 0x94e1dadd +964, 0xdfa4f20e +965, 0xc9bbd26a +966, 0x75322ecb +967, 0x3dc3ff18 +968, 0xfa896826 +969, 0xe4ad213c +970, 0x7a0f97c3 +971, 0xd7b7b08f +972, 0x6ebcab4e +973, 0x1a37d816 +974, 0x16299fee +975, 0x89d94a3a +976, 0x11c2f073 +977, 0x4ef27a32 +978, 0xaaf42781 +979, 0x9862c844 +980, 0xaa672e94 +981, 0xba4f2690 +982, 0x1f767d21 +983, 0x157e1a5e +984, 0x5b6de343 +985, 0xc494501e +986, 0xe97b507b +987, 0x98cae4c8 +988, 0xc4a6b036 +989, 0x746f8686 +990, 0xe761c86 +991, 0xefdaaa15 +992, 0xb907b816 +993, 0xe9d05992 +994, 0xed2e1b0e +995, 0xe129d3ee +996, 0xb41bb95f +997, 0xaec36181 +998, 0xdcdcf5f0 +999, 0xf175572a diff --git a/_randomgen/core_prng/tests/data/pcg32-testset-2.csv b/_randomgen/core_prng/tests/data/pcg32-testset-2.csv new file mode 100644 index 000000000000..2d4c8aed1312 --- /dev/null +++ b/_randomgen/core_prng/tests/data/pcg32-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 0x0 +0, 0xe4c14788 +1, 0x379c6516 +2, 0x5c4ab3bb +3, 0x601d23e0 +4, 0x1c382b8c +5, 0xd1faab16 +6, 0x67680a2d +7, 0x92014a6e +8, 0x628ae389 +9, 0xa794034d +10, 0x5cc38cd9 +11, 0xfc913a3b +12, 0x81c851dc +13, 0x90c820e4 +14, 0x60dfa703 +15, 0xd613ae14 +16, 0x38ea1699 +17, 0x51f04d1b +18, 0xc4ef01a1 +19, 0x321eec02 +20, 0x4c37a737 +21, 0x6bfd1aa8 +22, 0x71a28325 +23, 0x4656d6e9 +24, 0x17509653 +25, 0x830bd521 +26, 0x6d35e3aa +27, 0x4ab85020 +28, 0x21c1da2c +29, 0x6a6057a2 +30, 0xf3a90dc1 +31, 0xa1cbdcd9 +32, 0xf70b61bf +33, 0x3b2b09a8 +34, 0xbc2ef54d +35, 0xce07f38f +36, 0xb51bc60b +37, 0x729efb83 +38, 0x7e4a5f66 +39, 0xdd824ead +40, 0x9be85945 +41, 0x57f8779c +42, 0xdb449e87 +43, 0xc0be253f +44, 0x18b4267e +45, 0xff78821 +46, 0xb53e3425 +47, 0x4550b21b +48, 0xefe89a4c +49, 0x74c130b9 +50, 0x1656a3a0 +51, 0x194da2a6 +52, 0x1a6cdb1d +53, 0x7c1fd58e +54, 0x3162d1e9 +55, 0x3e2f2c7d +56, 0xb0ab9b5c +57, 0x79156d4d +58, 0x97b85150 +59, 0x967a02ce +60, 0x1e64548d +61, 0x4196d24a +62, 0xd047eef5 +63, 0x8451cc3c +64, 0x7227eb94 +65, 0xb1191064 +66, 0x82e162d0 +67, 0xb473f07d +68, 0x92ea0426 +69, 0xbf2a25fa +70, 0x9935be52 +71, 0x28baec93 +72, 0xa29368b5 +73, 0xe3d6d97d +74, 0x85ecf1d4 +75, 0x482e4bc8 +76, 0xe4f22219 +77, 0x7531047 +78, 0x3c41ef1f +79, 0x19db5112 +80, 0xc1534caf +81, 0x6c45710a +82, 0xb323c369 +83, 0x2dac53c6 +84, 0xd5dc48b4 +85, 0x1dc6d7a1 +86, 0x3ae2bc10 +87, 0x6a7635e8 +88, 0xdeee7b7f +89, 0xcb705cd3 +90, 0xba11e537 +91, 0xb64a4936 +92, 0xff4b245e +93, 0x39cb1219 +94, 0x64833e10 +95, 0x76b0f975 +96, 0x333d7c7d +97, 0x88ccfb17 +98, 0xad78dace +99, 0xd82fb71 +100, 0x1595d411 +101, 0x47f9d57a +102, 0xd4dad6cb +103, 0x78bf16bd +104, 0x71b053d2 +105, 0xa4bb076e +106, 0xd7c57664 +107, 0x3fbcbf8f +108, 0xc816befc +109, 0x6df46890 +110, 0xd16f271f +111, 0xeeeb1571 +112, 0x58222e89 +113, 0xa55e81d3 +114, 0xafbe7622 +115, 0x938475a8 +116, 0xd8740af2 +117, 0xf937dbd7 +118, 0x7d3940fa +119, 0x694c55f2 +120, 0x2261fb68 +121, 0x6ce39e94 +122, 0xab43634 +123, 0xd92ff7c4 +124, 0xe8db22d +125, 0x52e250b1 +126, 0xaf0f7029 +127, 0xc23dd3a +128, 0xd66dc2b9 +129, 0xea7f01f3 +130, 0x4df54b3f +131, 0xf1eff09c +132, 0x2813663e +133, 0x21ae8115 +134, 0xb00d790d +135, 0x11e6adbb +136, 0x61005f4c +137, 0x3de17bf0 +138, 0x7b2050b9 +139, 0xe20dd275 +140, 0xafa0bdcc +141, 0x9c6d4c6c +142, 0xe938606 +143, 0x8eecdd8f +144, 0xea9a90a9 +145, 0x99cbb123 +146, 0x16fccad1 +147, 0x7e81fdd9 +148, 0x116e6abd +149, 0xdeb9ff4e +150, 0xc589f525 +151, 0x57d701a9 +152, 0xcf05e950 +153, 0x533a2839 +154, 0x12d592e7 +155, 0xae61f43f +156, 0x419ae221 +157, 0x81126e0a +158, 0xc3988c97 +159, 0xb3262eaa +160, 0x3baddf9e +161, 0xf19d8a16 +162, 0x2a8b130f +163, 0xe4c9ccea +164, 0xf5ae2ea +165, 0x75aaa98d +166, 0xdd45ce49 +167, 0x98e0d4f6 +168, 0xb1ec10a1 +169, 0xc9592952 +170, 0x23bb1f45 +171, 0xd0827b45 +172, 0x7a79b800 +173, 0x9d1b8348 +174, 0xe2958863 +175, 0x5143e17e +176, 0x44110af9 +177, 0x49d76858 +178, 0xdba4688e +179, 0x4e4d61dd +180, 0x729b81cc +181, 0xf3576e03 +182, 0x9b028e9d +183, 0x68d8d869 +184, 0xda15e018 +185, 0x5384abb2 +186, 0x1027ed5e +187, 0xaf5401f1 +188, 0x31411375 +189, 0xc75d87be +190, 0xad73f5fd +191, 0xadb3add7 +192, 0x4d5452ee +193, 0xdef42029 +194, 0x89d58a78 +195, 0x464d6b4a +196, 0xd01f533a +197, 0xb9533dd4 +198, 0x55c5d023 +199, 0x3dcf8fef +200, 0x198395ca +201, 0x7cdca51c +202, 0x6f4074f +203, 0xb9f79995 +204, 0xbbe3d9a5 +205, 0x520d417e +206, 0x9a8df0bd +207, 0xe390f486 +208, 0x5b578b3f +209, 0xb4cdf767 +210, 0x12d45034 +211, 0xe661e293 +212, 0x70cd3e91 +213, 0xdbc7f190 +214, 0x49829849 +215, 0x12017fbe +216, 0x1e35bf48 +217, 0x1effc3c7 +218, 0xe1f574cb +219, 0xf613ab7d +220, 0xd09d16fa +221, 0xa58bcf5a +222, 0xac39afdc +223, 0xd611d1ab +224, 0x36edd3b2 +225, 0xd9ea5d98 +226, 0xf6f2fce4 +227, 0x42cb31ce +228, 0xdd1f6530 +229, 0x3e43a7d0 +230, 0x175ec7fc +231, 0x8077af4b +232, 0x37cbcc22 +233, 0x26a89f +234, 0x998c930e +235, 0xb84e5f21 +236, 0x83817130 +237, 0x2ad05d66 +238, 0x48f3b861 +239, 0xd69f626 +240, 0x1d09f12 +241, 0xf207e7f0 +242, 0xcc709acc +243, 0x1b2881d7 +244, 0x7e18cc6c +245, 0xbfd9589c +246, 0xce0d301e +247, 0xc8668b4b +248, 0x584482bd +249, 0x722e14ae +250, 0xd79dfcff +251, 0xcc7e9c21 +252, 0xd081f540 +253, 0x3b49f7fa +254, 0xf23efb2a +255, 0xfd7fe8f8 +256, 0x9abcbf25 +257, 0x5b713674 +258, 0x1300e351 +259, 0xe884f0ad +260, 0x3c290461 +261, 0x4f64c1a1 +262, 0x17c55223 +263, 0xd5953a5f +264, 0xd85e042e +265, 0x75dfc597 +266, 0x379edfb +267, 0x75ebddc9 +268, 0xc19b98e1 +269, 0x1dd1b751 +270, 0xc5760a60 +271, 0x5f6e2f17 +272, 0x29e8610e +273, 0xb2edd7db +274, 0x9233eeca +275, 0xbc02b187 +276, 0xc997bb5b +277, 0x88ad3a98 +278, 0x3d1167ad +279, 0xcea54c9c +280, 0x7ea493eb +281, 0x586e3aa8 +282, 0xe2e027c7 +283, 0xae50ef9e +284, 0xd32e0c38 +285, 0xeba0edf6 +286, 0x980ad22a +287, 0x3b14e644 +288, 0xd7bfbff8 +289, 0xe0af1647 +290, 0x292d72dd +291, 0xb8c421bb +292, 0x114d690e +293, 0x85a86bd +294, 0x39f2b5e2 +295, 0x7c9c6b43 +296, 0xca387767 +297, 0x84f24ecf +298, 0x2aec5804 +299, 0x27d0f2 +300, 0xcd7bb6a9 +301, 0xe925969f +302, 0xc6454099 +303, 0xf7435a9d +304, 0xf7bc998f +305, 0xfa81f361 +306, 0xcba07d00 +307, 0x3e8a8a14 +308, 0xf0e7f785 +309, 0x25aecff +310, 0xe1a90226 +311, 0x4af1339d +312, 0x983f4fb9 +313, 0xbaec847f +314, 0x4e504dbb +315, 0xe7d0be86 +316, 0x73cb80ef +317, 0x336db698 +318, 0x8bf7de05 +319, 0x36e4e6ba +320, 0x47a8239b +321, 0x2a98e1d0 +322, 0x64a6c087 +323, 0x4a8591cb +324, 0x642d5d67 +325, 0x9f4b84b2 +326, 0x6bdf1176 +327, 0x7e2b1639 +328, 0xc90453f5 +329, 0xe72d0b96 +330, 0x5f0e1d0c +331, 0x156af798 +332, 0x6124d8e8 +333, 0xaa2f2ad7 +334, 0x145b30b7 +335, 0xd6582106 +336, 0x203abbad +337, 0x929d8d43 +338, 0x14d5b6dc +339, 0xef0f4eb2 +340, 0x8ff54463 +341, 0x588113a +342, 0x1bc43ba6 +343, 0x44f44097 +344, 0xb84cfdc6 +345, 0x3ee638af +346, 0xdd169321 +347, 0xaaac5f56 +348, 0xbb022bc2 +349, 0xf9ef8bde +350, 0x2829b2fb +351, 0x563368fa +352, 0x82ce66ae +353, 0x6d820e38 +354, 0xb87a080e +355, 0x756469af +356, 0x78086990 +357, 0xa220e762 +358, 0x14ba6bdb +359, 0xfa775c1b +360, 0x65fa7396 +361, 0xbae24370 +362, 0x8e42ddb8 +363, 0x1f46b8ac +364, 0x3c9236c5 +365, 0xd3a2184c +366, 0x308ba74 +367, 0x5638eb84 +368, 0x64076fe6 +369, 0x37fe334f +370, 0x8de24732 +371, 0xf0d0b02b +372, 0x18492b71 +373, 0x848f38ac +374, 0x9b46dc75 +375, 0xf5d3c06a +376, 0x203afe47 +377, 0x19857724 +378, 0x38033528 +379, 0xf7fa640c +380, 0xf1cb86e8 +381, 0x1fcd5b99 +382, 0xb07f1023 +383, 0x3bb9ab75 +384, 0x57f54e78 +385, 0xf5b51d4b +386, 0xe94eba44 +387, 0xa5a39292 +388, 0x50803af +389, 0x34ea9cc5 +390, 0xabf621ca +391, 0xb275f802 +392, 0xf46dffd6 +393, 0xd33e27d1 +394, 0xca9a56e +395, 0x6eda85a4 +396, 0x639b78ba +397, 0x799d1980 +398, 0xf3c09bf1 +399, 0x6d4cdbe +400, 0x112dae8d +401, 0xd97414b1 +402, 0x9499df3d +403, 0xa58ece6c +404, 0xe56bf91b +405, 0x3bdbfd9 +406, 0x91aae1fd +407, 0xec1fce54 +408, 0x60e0eced +409, 0x278d5b22 +410, 0xdee29da2 +411, 0xf1f55d27 +412, 0xd532ab83 +413, 0xb0fe9589 +414, 0x88fcc255 +415, 0xf524359b +416, 0x7270a00b +417, 0x42489eaf +418, 0xc020d6bb +419, 0xf9ed0f78 +420, 0x4bc5cdec +421, 0x55061393 +422, 0x6b84a5a4 +423, 0x826c0471 +424, 0x9e69e30d +425, 0x9dfd9b15 +426, 0xf4014c40 +427, 0xcd04ef4d +428, 0x7376c02c +429, 0xb15a9e3c +430, 0xf76c1fa9 +431, 0xcd51bdd8 +432, 0x99f2859e +433, 0xb62c6a4d +434, 0x52239d8b +435, 0x27fa2869 +436, 0x6dba918c +437, 0x9891e444 +438, 0x71e29f5 +439, 0xa9cd3ac9 +440, 0xf6ec3b80 +441, 0x8c8d3226 +442, 0x7c528725 +443, 0xd543932b +444, 0xf76b3e02 +445, 0xeccaf183 +446, 0x8f757854 +447, 0x785edb62 +448, 0x54397da0 +449, 0xe1fe0557 +450, 0x7a79d418 +451, 0xd2740507 +452, 0xc3561bc7 +453, 0xef7c3f18 +454, 0xecf8effe +455, 0xc7a073ad +456, 0xeb5ea9fd +457, 0x33dade18 +458, 0x89d0e41c +459, 0x7720d298 +460, 0xe912f029 +461, 0x7794462 +462, 0xa436dcf6 +463, 0x55cbb318 +464, 0x7b4a78e0 +465, 0xa8ce0afb +466, 0x7e18bb28 +467, 0x92c4f8f6 +468, 0x6828052c +469, 0xbf619f8 +470, 0x272d1d15 +471, 0xb34e2e52 +472, 0x52158f7f +473, 0x682fb062 +474, 0x52e80435 +475, 0x787e0fb3 +476, 0xe331da39 +477, 0xfad42e58 +478, 0x1bdb3f90 +479, 0xe313ab2 +480, 0xe61af9bb +481, 0x46f03903 +482, 0x926b3d33 +483, 0x2b23ce3b +484, 0xed04d4af +485, 0x34c49faf +486, 0x142f503c +487, 0x47cf6a21 +488, 0x5352250c +489, 0xf5942210 +490, 0xca5950ae +491, 0xc5302422 +492, 0x41a5e9b1 +493, 0x30076390 +494, 0x8951d0e4 +495, 0xebe74e22 +496, 0xfcb7dbf8 +497, 0xd55076e7 +498, 0x88a1165b +499, 0x1a89b5a3 +500, 0xda2c3e2e +501, 0xdc1d606d +502, 0xfda0315c +503, 0x5f5610dd +504, 0x3eba316c +505, 0x72cae07b +506, 0x5336095 +507, 0x6a110322 +508, 0x46cb153b +509, 0xa2b11116 +510, 0xe2543988 +511, 0x51f53bae +512, 0x3b10466d +513, 0x189ddd56 +514, 0x1fd355b6 +515, 0x1230e8d3 +516, 0x2050d313 +517, 0x2fbb5c16 +518, 0x64b03f4f +519, 0xbd6cdc1a +520, 0x9d423316 +521, 0xc71a702f +522, 0xf2254f39 +523, 0xd953728b +524, 0xef3c8bb5 +525, 0x685a2fab +526, 0xcea73dff +527, 0x4a7fa029 +528, 0xa27e8058 +529, 0x561a1413 +530, 0x570fc5bc +531, 0x917e93ee +532, 0x15fdbb15 +533, 0xabee295e +534, 0xc40f5307 +535, 0xba18b087 +536, 0x6ea6e339 +537, 0x7e282248 +538, 0x875062c2 +539, 0xd1520c30 +540, 0xb4cef1a5 +541, 0x55812dd1 +542, 0x9c67743c +543, 0x22fd5992 +544, 0x1dacbfa +545, 0x5b35eab1 +546, 0xfa8c9316 +547, 0x490bc71c +548, 0xe5129bfb +549, 0xe7acb79f +550, 0x87667765 +551, 0x945be067 +552, 0x8acf5c32 +553, 0x466e0ee +554, 0x8fa89be0 +555, 0x4eb4afcc +556, 0x3302055b +557, 0x8f2e3ab9 +558, 0xc5bc175e +559, 0x903a3e85 +560, 0x4055dd04 +561, 0x37873bac +562, 0x2965a951 +563, 0x2206c56a +564, 0xf34dc2db +565, 0x34e43ba2 +566, 0xb61caa44 +567, 0xfd3eb260 +568, 0x9dcdc817 +569, 0x7019df83 +570, 0x6fcd9bea +571, 0x270cba0a +572, 0xd6cc3241 +573, 0x6345c906 +574, 0xd213fb94 +575, 0x6195e5b5 +576, 0x804abab7 +577, 0xb4cace45 +578, 0xded19bbc +579, 0x617db00c +580, 0xafb933d6 +581, 0x8192cae8 +582, 0x45ffd8af +583, 0x13ae0868 +584, 0x840f4541 +585, 0x12cd1a05 +586, 0xbb5b7d6d +587, 0x3907ab3 +588, 0xd77a1582 +589, 0x4e741292 +590, 0x28c60865 +591, 0xbaad11e2 +592, 0xa9d3e364 +593, 0x88a197cb +594, 0xe90f021f +595, 0x2056017a +596, 0xeb0a2fd9 +597, 0x1d3435aa +598, 0xdaa0b802 +599, 0x8121bf09 +600, 0x95a88f55 +601, 0xa8b9c257 +602, 0xb0ab4914 +603, 0xf360b741 +604, 0x5563d4ab +605, 0xad33cf0e +606, 0x397d315a +607, 0x6893767f +608, 0x79dd5b31 +609, 0xa9ea6777 +610, 0xcf48c06 +611, 0xb4cceafc +612, 0xf53cab50 +613, 0x72426c8 +614, 0xd128aa5a +615, 0x511eec88 +616, 0x668ab20a +617, 0xb9b53dbe +618, 0x3b03a0fb +619, 0x8f416a98 +620, 0xaa15b7f6 +621, 0xc7767aba +622, 0xa64d3342 +623, 0x42cf1388 +624, 0xfc3ee7c0 +625, 0x892a2902 +626, 0xdb054bf6 +627, 0x4973223f +628, 0xb9f74682 +629, 0x72f2ece +630, 0xddf94382 +631, 0x67581d86 +632, 0x9cb9cd6f +633, 0xed74731a +634, 0xcca05451 +635, 0x3b21fdc0 +636, 0x9e18e52b +637, 0xa40bb287 +638, 0x8bb05e07 +639, 0xa33555fe +640, 0x4c819ed +641, 0x5373903e +642, 0x611403c2 +643, 0x133e25fb +644, 0x9c7a44e4 +645, 0x67197b8d +646, 0xfa910436 +647, 0xa86a825d +648, 0xfc9b24c1 +649, 0x464a718e +650, 0x7421bc26 +651, 0x3c3186b7 +652, 0xf7304619 +653, 0x7ac7be81 +654, 0xae6adcc4 +655, 0xca96bf8c +656, 0x49711d50 +657, 0x74c51f0 +658, 0x275804c0 +659, 0x228098c5 +660, 0x73a31b94 +661, 0x7f01db79 +662, 0xb36209c8 +663, 0x6ccf8677 +664, 0x70dbcce0 +665, 0xa533d8cd +666, 0xd0b0f097 +667, 0xd9a3b784 +668, 0x80a929fc +669, 0x9708f29a +670, 0x95e1e56f +671, 0xd07a0b45 +672, 0x566acdb6 +673, 0x92663054 +674, 0x3667dc9a +675, 0x80f850ff +676, 0x549dd640 +677, 0xc3ff18ca +678, 0x8c70d392 +679, 0xf5547e3b +680, 0x8dbee1d7 +681, 0x51fe33b8 +682, 0xb1ea480b +683, 0x6646f6d0 +684, 0x4a8e7de9 +685, 0xcb053e32 +686, 0x6311aee8 +687, 0xcc2a411b +688, 0x5330e60b +689, 0x4680e825 +690, 0x96bdd8a2 +691, 0x8cf4268a +692, 0x8445c833 +693, 0xc237eef1 +694, 0x459670e8 +695, 0xedf26624 +696, 0x5713340f +697, 0x5a3e87a3 +698, 0xa24a7c2d +699, 0xfa9fdceb +700, 0x746fd14e +701, 0xc6aef3e5 +702, 0x3d957e9b +703, 0xc1926f7a +704, 0xee717768 +705, 0x101fe323 +706, 0xec0d63ab +707, 0x8b8e6f42 +708, 0x8c3d2286 +709, 0xb573dd68 +710, 0x53b68ec0 +711, 0x696525cf +712, 0xdab65d8e +713, 0xd2c6ed42 +714, 0xa1fc10f6 +715, 0x1554666 +716, 0x6ed42947 +717, 0x87f7e62 +718, 0xaf34733b +719, 0xc55baa8b +720, 0xcbff66f +721, 0x2516c228 +722, 0xec6980fb +723, 0x4f53d66c +724, 0x1be17a32 +725, 0xdcfb31df +726, 0x4b17d04f +727, 0x81e1f54b +728, 0x749eae52 +729, 0x3811c4d5 +730, 0x5d11e6a1 +731, 0x535d5d6c +732, 0xbb74cd20 +733, 0xd1b18b71 +734, 0xfbf7221a +735, 0x817c4279 +736, 0xcef30b85 +737, 0x41dee06c +738, 0x9d340a3a +739, 0x691f0449 +740, 0x363a515d +741, 0x73a1af6c +742, 0x25718271 +743, 0xb4a52d50 +744, 0x1e392f40 +745, 0x3c811345 +746, 0xc9aa8565 +747, 0x357c24e0 +748, 0x19ad7230 +749, 0xed250e20 +750, 0x4acc4824 +751, 0x825d53a +752, 0xcf2f515f +753, 0xb7973ff4 +754, 0xb03ce53f +755, 0x1afad500 +756, 0x39f64ee8 +757, 0x60bea483 +758, 0xedf16817 +759, 0x88beff73 +760, 0x4909868 +761, 0x879a96da +762, 0x52d4ac6b +763, 0x46fabe65 +764, 0x88fa5751 +765, 0x71df4521 +766, 0xfc6eb286 +767, 0xf83e78ad +768, 0x885e5aca +769, 0x77e63e4a +770, 0x2bdf5c02 +771, 0x2528323c +772, 0x5b5d1ce9 +773, 0xf795be8c +774, 0x5e113b2b +775, 0xa993c7aa +776, 0xe5f8560a +777, 0x77e1e8d +778, 0x5e9db88a +779, 0xdac4e96b +780, 0x9126b945 +781, 0x15bf293a +782, 0x1dc9a8f4 +783, 0x909b48b1 +784, 0xb50ce29e +785, 0x21671c87 +786, 0xcda80dec +787, 0xf5aff1a9 +788, 0xd70cdb2e +789, 0xd293139a +790, 0xcbf4f51d +791, 0xb23c6d7a +792, 0x1a06aa33 +793, 0x21880210 +794, 0x92679678 +795, 0x8d5bb26b +796, 0x23304100 +797, 0x8f5d1df4 +798, 0x143b39ff +799, 0x29e97d16 +800, 0xbfad952f +801, 0x257ca1d8 +802, 0x32ad2f8f +803, 0x84d320c3 +804, 0xcc4c59a +805, 0xbb5ae046 +806, 0x3d5fcf1d +807, 0xa0130b0 +808, 0xad86e9de +809, 0x1e422521 +810, 0x6b56a617 +811, 0xbe64d9fc +812, 0xfff31ed0 +813, 0xd1ad616e +814, 0x13486a20 +815, 0x1754613b +816, 0x52c7b9da +817, 0xc05d75aa +818, 0xd719cd98 +819, 0x61890574 +820, 0xc4711a8b +821, 0x9afd5635 +822, 0x4dabed21 +823, 0x94f173 +824, 0xb8b6e708 +825, 0x1d590111 +826, 0x60315dfd +827, 0x7fb8ae79 +828, 0xc69f4f2b +829, 0xcaf1c898 +830, 0x861a0c8b +831, 0x6ed14eaa +832, 0xc77da58 +833, 0x8fd4f29a +834, 0xa38187fb +835, 0x6ed1ee88 +836, 0xf1a9f55a +837, 0x74368cc8 +838, 0xf327e944 +839, 0x97a578af +840, 0x8a5345e5 +841, 0x63ee0a30 +842, 0xa7e4919b +843, 0x51e26930 +844, 0x38dbe017 +845, 0xedace3a9 +846, 0x9cda2ad4 +847, 0x96b1119 +848, 0xff56282a +849, 0x71773edf +850, 0xe41fb69c +851, 0xe7bce539 +852, 0x221ffeed +853, 0x35d3f67f +854, 0x7e089168 +855, 0x6fd47823 +856, 0x43bfb28d +857, 0x9ce49e62 +858, 0xde32120 +859, 0x6eacfe4e +860, 0x116c6128 +861, 0x5f975284 +862, 0xc547361c +863, 0xf48e8251 +864, 0x2ac8a3bd +865, 0x9a0fce5b +866, 0x1764e3d9 +867, 0xa31e6954 +868, 0xb9dca055 +869, 0x1cd35c79 +870, 0x1b502882 +871, 0xf973ab10 +872, 0x8b585146 +873, 0x841fd3f8 +874, 0x4999200f +875, 0x7ad10c4b +876, 0xcf1695bd +877, 0x26c58bc3 +878, 0xdc1f8310 +879, 0x546e1e86 +880, 0x2e39fec8 +881, 0x8c65e2ed +882, 0x6469bac +883, 0xbc4af1ff +884, 0xa1669010 +885, 0x41dabd80 +886, 0x5797e218 +887, 0x9bed24c1 +888, 0xa7552347 +889, 0x4e214099 +890, 0x34d4f986 +891, 0x316cc527 +892, 0xde30c21c +893, 0x4f273c1e +894, 0xc3dd9324 +895, 0xe61fda1c +896, 0x1d0f8076 +897, 0x5570867e +898, 0x289d6062 +899, 0x465b8b26 +900, 0xb72307de +901, 0xe78c8647 +902, 0xfee9723e +903, 0xa1534c9b +904, 0x4d652645 +905, 0xe623b6c2 +906, 0x454cfc8 +907, 0xc5a7fcaf +908, 0x1de804d9 +909, 0xa2501de7 +910, 0xe036c091 +911, 0xa4a55d1d +912, 0x50409892 +913, 0x58fd2731 +914, 0xb6fd3618 +915, 0xa0180bd2 +916, 0xd9bb2fe8 +917, 0x7c8e7a2c +918, 0xd90906fc +919, 0xf8721260 +920, 0x451b372d +921, 0xeeb1c70 +922, 0xc1a18778 +923, 0xd466244a +924, 0x88e4b84a +925, 0x4fc3af63 +926, 0xcf4387e4 +927, 0xb8872734 +928, 0x276eadef +929, 0xd2c164a1 +930, 0xd3c812d9 +931, 0x5a94f176 +932, 0xfba6f632 +933, 0xf7aeba97 +934, 0x9207585f +935, 0x70a41d67 +936, 0xa0b70910 +937, 0xd579fc6b +938, 0xf06a8fca +939, 0x471fd406 +940, 0xb15a0491 +941, 0x2f340f7a +942, 0x3df02de3 +943, 0x6022f8d6 +944, 0xa15b11c2 +945, 0x45715dd6 +946, 0xf293d85e +947, 0x7a2100d +948, 0x7dff786e +949, 0x52c6a183 +950, 0x5fbce2db +951, 0xbc29ec65 +952, 0x3dd14b27 +953, 0x1bedecd1 +954, 0xbfcba31c +955, 0xb911a26d +956, 0x6b6de680 +957, 0x36e8769 +958, 0x908de4a0 +959, 0xe1abee1f +960, 0x83acd7f8 +961, 0x5008c1eb +962, 0xd8bc7a2b +963, 0x6f639c56 +964, 0xe1f2634b +965, 0x267222ec +966, 0x48fa416c +967, 0xfa01e3cb +968, 0x2d28a700 +969, 0x58dcdc97 +970, 0x685ac2e7 +971, 0x9318840b +972, 0x99247a55 +973, 0x8d749b83 +974, 0x403f8415 +975, 0x373eb9c6 +976, 0xb840b6a2 +977, 0x9bb7bfc4 +978, 0xd5800634 +979, 0x3ef4a02d +980, 0x2ffa791f +981, 0x8a671150 +982, 0x40fdfc5e +983, 0xfa4bd35e +984, 0xf4ca1642 +985, 0x17fb231a +986, 0x42a3e57c +987, 0x58cf119d +988, 0x32f19c67 +989, 0xf3e2e153 +990, 0x66fce6fb +991, 0x9d61059b +992, 0x1628eafb +993, 0x9a6cf683 +994, 0x5ff5df3a +995, 0x206fb3c9 +996, 0x1914913c +997, 0x58c002ad +998, 0xd099145f +999, 0x155aab4b diff --git a/_randomgen/core_prng/tests/test_direct.py b/_randomgen/core_prng/tests/test_direct.py index 61dafdcaa924..cada2d58d394 100644 --- a/_randomgen/core_prng/tests/test_direct.py +++ b/_randomgen/core_prng/tests/test_direct.py @@ -7,7 +7,7 @@ assert_raises from core_prng import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ - PCG64, Philox, Xoroshiro128, Xorshift1024 + PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024 if (sys.version_info > (3, 0)): long = int @@ -24,7 +24,7 @@ def uniform32_from_uint64(x): out = (joined >> np.uint32(9)) * (1.0 / 2 ** 23) return out.astype(np.float32) - + def uniform32_from_uint63(x): x = np.uint64(x) x = np.uint32(x >> np.uint64(32)) @@ -407,3 +407,14 @@ def setup_class(cls): cls.data1 = cls._read_csv(join(pwd, './data/threefry32-testset-1.csv')) cls.data2 = cls._read_csv(join(pwd, './data/threefry32-testset-2.csv')) cls.seed_error_type = TypeError + + +class TestPCG32(TestPCG64): + @classmethod + def setup_class(cls): + cls.prng = PCG32 + cls.bits = 32 + cls.dtype = np.uint32 + cls.data1 = cls._read_csv(join(pwd, './data/pcg32-testset-1.csv')) + cls.data2 = cls._read_csv(join(pwd, './data/pcg32-testset-2.csv')) + cls.seed_error_type = TypeError diff --git a/_randomgen/core_prng/tests/test_smoke.py b/_randomgen/core_prng/tests/test_smoke.py index 929fd1e9f0ca..8e184bce1ac8 100644 --- a/_randomgen/core_prng/tests/test_smoke.py +++ b/_randomgen/core_prng/tests/test_smoke.py @@ -9,7 +9,7 @@ assert_array_equal from core_prng import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ - PCG64, Philox, Xoroshiro128, Xorshift1024 + PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024 from core_prng import entropy @@ -986,3 +986,16 @@ def test_fallback(self): time.sleep(0.1) e2 = entropy.random_entropy(source='fallback') assert_((e1 != e2)) + + +class TestPCG32(TestPCG64): + @classmethod + def setup_class(cls): + cls.prng = PCG32 + cls.advance = 2 ** 48 + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1 + cls.seed = [2 ** 48 + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1, + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1] + cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = None + cls._extra_setup() diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 0eb997c05d36..6508bde6473c 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -107,14 +107,22 @@ ), Extension("core_prng.pcg64", ["core_prng/pcg64.pyx", - join(MOD_DIR, 'src', 'pcg64', - 'pcg64.c')], + join(MOD_DIR, 'src', 'pcg64', 'pcg64.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'pcg64')], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), + Extension("core_prng.pcg32", + ["core_prng/pcg32.pyx", + join(MOD_DIR, 'src', 'pcg32', 'pcg32.c')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join(MOD_DIR, 'src', + 'pcg32')], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("core_prng.threefry", ["core_prng/threefry.pyx", join(MOD_DIR, 'src', 'threefry', 'threefry.c')], From ddf71e85221c073850ec90702e7914391f4ff5ec Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 12 Mar 2018 19:54:50 +0000 Subject: [PATCH 066/279] BUG: Fix variable declarations in dsfmt Fix order for VS2008 Improve repr --- _randomgen/core_prng/generator.pyx | 8 +++++++- _randomgen/core_prng/src/dsfmt/dSFMT.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index e5fd47ec4f6f..59a42b603f16 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -69,13 +69,19 @@ cdef class RandomGenerator: capsule = prng.capsule cdef const char *anon_name = "CorePRNG" if not PyCapsule_IsValid(capsule, anon_name): - raise ValueError("Invalid pointer to anon_func_state") + raise ValueError("Invalid prng. The prng must be instantized.") self._prng = PyCapsule_GetPointer(capsule, anon_name) self.lock = Lock() with self.lock: self._prng.has_gauss = 0 self._prng.has_gauss_f = 0 + def __repr__(self): + return self.__str__() + ' at 0x{:X}'.format(id(self)) + + def __str__(self): + return 'RandomGenerator(' + self.__core_prng.__class__.__name__ + ')' + # Pickling support: def __getstate__(self): return self.state diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.h b/_randomgen/core_prng/src/dsfmt/dSFMT.h index 0ae8a016d871..224d0108fbf3 100644 --- a/_randomgen/core_prng/src/dsfmt/dSFMT.h +++ b/_randomgen/core_prng/src/dsfmt/dSFMT.h @@ -665,9 +665,9 @@ static inline double dsfmt_next_double(dsfmt_state *state) { static inline uint64_t dsfmt_next64(dsfmt_state *state) { /* Discard bottom 16 bits */ + uint64_t out; union random_val_t rv; rv.d = dsfmt_next_buffer(state); - uint64_t out; out = (rv.u64 >> 16) << 32; rv.d = dsfmt_next_buffer(state); out |= (rv.u64 >> 16) & 0xffffffff; From b64cebbbeaf1aab4adb0fa0f49ef570d19b13c5b Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 12 Mar 2018 20:08:21 +0000 Subject: [PATCH 067/279] ENH: Enable testing on OSX Enable travis testing on OSX --- _randomgen/.travis.yml | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index e30030a4bb39..ec1035a29f50 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -10,33 +10,29 @@ language: python matrix: fast_finish: true include: - - env: - - PYTHON=2.7 - - NUMPY=1.10 - - CYTHON=0.24 - - env: - - PYTHON=3.5 - - NUMPY=1.11 - - env: - - PYTHON=3.6 - - NUMPY=1.13 - - CYTHON=0.25 - - env: - - PYTHON=3.6 - - NUMPY=1.13 - - CYTHON=0.26 - - env: - - PYTHON=3.6 + - os: linux + env: [PYTHON=2.7, NUMPY=1.10, CYTHON=0.24] + - os: linux + env: [PYTHON=3.5, NUMPY=1.11] + - os: linux + env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.25] + - os: linux + env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.26] + - os: linux + env: [PYTHON=3.6] + - os: osx + language: generic + env: [PYTHON=3.6] + before_install: - - if [ ${TRAVIS_OS_NAME} = "osx" ]; then wget https://repo.continuum.io/miniconda/Miniconda-latest-MacOSX-x86_64.sh -O miniconda.sh; fi - - if [ ${TRAVIS_OS_NAME} = "linux" ]; then wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh; fi + - if [[ ${TRAVIS_OS_NAME} == "osx" ]]; then wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda3.sh; fi + - if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh; fi - chmod +x miniconda3.sh - ./miniconda3.sh -b - - export PATH=/home/travis/miniconda3/bin:$PATH + - export PATH=${HOME}/miniconda3/bin:$PATH - conda config --set always_yes true - # Disable until fixed - # - conda update --all --quiet + - conda update --all --quiet - PKGS="python=${PYTHON}" - PKGS="${PKGS} numpy"; if [ ${NUMPY} ]; then PKGS="${PKGS}=${NUMPY}"; fi - PKGS="${PKGS} Cython"; if [ ${CYTHON} ]; then PKGS="${PKGS}=${CYTHON}"; fi From 2a13162c8372d5f6cd0d85aaeb62070fd9b71b30 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 12 Mar 2018 20:08:21 +0000 Subject: [PATCH 068/279] ENH: Enable testing on OSX Enable travis testing on OSX --- _randomgen/.travis.yml | 44 ++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index e30030a4bb39..7da8cb80b1ab 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -10,38 +10,33 @@ language: python matrix: fast_finish: true include: - - env: - - PYTHON=2.7 - - NUMPY=1.10 - - CYTHON=0.24 - - env: - - PYTHON=3.5 - - NUMPY=1.11 - - env: - - PYTHON=3.6 - - NUMPY=1.13 - - CYTHON=0.25 - - env: - - PYTHON=3.6 - - NUMPY=1.13 - - CYTHON=0.26 - - env: - - PYTHON=3.6 + - os: linux + env: [PYTHON=2.7, NUMPY=1.10, CYTHON=0.24] + - os: linux + env: [PYTHON=3.5, NUMPY=1.11] + - os: linux + env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.25] + - os: linux + env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.26] + - os: linux + env: [PYTHON=3.6] + - os: osx + language: generic + env: [PYTHON=3.6] + before_install: - - if [ ${TRAVIS_OS_NAME} = "osx" ]; then wget https://repo.continuum.io/miniconda/Miniconda-latest-MacOSX-x86_64.sh -O miniconda.sh; fi - - if [ ${TRAVIS_OS_NAME} = "linux" ]; then wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh; fi + - if [[ ${TRAVIS_OS_NAME} == "osx" ]]; then wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda3.sh; fi + - if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh; fi - chmod +x miniconda3.sh - ./miniconda3.sh -b - - export PATH=/home/travis/miniconda3/bin:$PATH + - export PATH=${HOME}/miniconda3/bin:$PATH - conda config --set always_yes true - # Disable until fixed - # - conda update --all --quiet + - conda update --all --quiet - PKGS="python=${PYTHON}" - PKGS="${PKGS} numpy"; if [ ${NUMPY} ]; then PKGS="${PKGS}=${NUMPY}"; fi - PKGS="${PKGS} Cython"; if [ ${CYTHON} ]; then PKGS="${PKGS}=${CYTHON}"; fi - PKGS="${PKGS} pandas"; if [ ${PANDAS} ]; then PKGS="${PKGS}=${PANDAS}"; fi - - export BUILD_DIR=$PWD - conda create -n core-prng-test ${PKGS} pytest setuptools nose --quiet - source activate core-prng-test - pip install tempita -q @@ -53,7 +48,6 @@ script: - set -e - pytest core_prng - | - if [ -z ${NUMPY} ]; then - cd ${BUILD_DIR} + if [[ -z ${NUMPY} ]]; then python benchmark.py; fi From d1d421030b28a9a1a9d94295b8a1faf4d88b8c9f Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 12 Mar 2018 22:45:12 +0000 Subject: [PATCH 069/279] CLN: Remove small bugs and alter variable size Switch from unsigned long to uint64_t Return correct types from PRNGs Simplify benchmarks --- _randomgen/benchmark.py | 16 +++-- _randomgen/core_prng/generator.pyx | 10 ++-- .../src/distributions/distributions.c | 13 +--- .../src/distributions/distributions.h | 3 +- _randomgen/core_prng/src/philox/philox.c | 2 +- _randomgen/core_prng/src/philox/philox.h | 8 ++- _randomgen/core_prng/src/threefry/threefry.c | 2 +- _randomgen/core_prng/src/threefry/threefry.h | 2 +- .../core_prng/src/threefry32/threefry32.c | 2 +- .../core_prng/src/threefry32/threefry32.h | 59 +++++++++++-------- 10 files changed, 65 insertions(+), 52 deletions(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 852773f2bd22..3b489781a3b8 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -119,9 +119,15 @@ def timer_normal_zig(): if __name__ == '__main__': - timer_raw() + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('--full', dest='full', action='store_true') + args = parser.parse_args() + timer_uniform() - timer_32bit() - timer_64bit() - timer_normal() - timer_normal_zig() + if args.full: + timer_raw() + timer_32bit() + timer_64bit() + timer_normal() + timer_normal_zig() diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 59a42b603f16..72d357067047 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -1385,7 +1385,7 @@ cdef class RandomGenerator: cdef double *randoms_data cdef double fgamma_r, fgamma_i, frelation_r, frelation_i, frho, fvar_r , fvar_i, \ floc_r, floc_i, f_real, f_imag, i_r_scale, r_scale, i_scale, f_rho - cdef np.npy_intp i, j, n + cdef np.npy_intp i, j, n, n2 cdef np.broadcast it oloc = np.PyArray_FROM_OTF(loc, np.NPY_COMPLEX128, np.NPY_ALIGNED) @@ -1480,11 +1480,12 @@ cdef class RandomGenerator: it = np.PyArray_MultiIterNew5(randoms, oloc, v_real, v_imag, rho) with self.lock, nogil: + n2 = 2 * n # Avoid compiler noise for cast to long if method == u'zig': - for i in range( 2 * n): + for i in range(n2): randoms_data[i] = random_gauss_zig(self._prng) else: - for i in range( 2 * n): + for i in range(n2): randoms_data[i] = random_gauss(self._prng) with nogil: j = 0 @@ -3967,11 +3968,10 @@ cdef class RandomGenerator: array([100, 0]) """ - cdef np.npy_intp d + cdef np.npy_intp d, i, j, dn, sz cdef np.ndarray parr "arrayObject_parr", mnarr "arrayObject_mnarr" cdef double *pix cdef long *mnix - cdef np.npy_intp i, j, dn, sz cdef double Sum d = len(pvals) diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index fbdad8f2f669..20b4d5d26d5c 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -1134,8 +1134,8 @@ long random_hypergeometric(prng_t *prng_state, long good, long bad, } } -unsigned long random_interval(prng_t *prng_state, unsigned long max) { - unsigned long mask, value; +uint64_t random_interval(prng_t *prng_state, uint64_t max) { + uint64_t mask, value; if (max == 0) { return 0; } @@ -1148,12 +1148,9 @@ unsigned long random_interval(prng_t *prng_state, unsigned long max) { mask |= mask >> 4; mask |= mask >> 8; mask |= mask >> 16; -#if ULONG_MAX > 0xffffffffUL mask |= mask >> 32; -#endif -/* Search a random value in [0..mask] <= max */ -#if ULONG_MAX > 0xffffffffUL + /* Search a random value in [0..mask] <= max */ if (max <= 0xffffffffUL) { while ((value = (random_uint32(prng_state) & mask)) > max) ; @@ -1161,10 +1158,6 @@ unsigned long random_interval(prng_t *prng_state, unsigned long max) { while ((value = (random_uint64(prng_state) & mask)) > max) ; } -#else - while ((value = (random_uint32(prng_state) & mask)) > max) - ; -#endif return value; } diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index 9f368837eaeb..0ca1c1397919 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -129,7 +129,8 @@ DECLDIR long random_geometric(prng_t *prng_state, double p); DECLDIR long random_zipf(prng_t *prng_state, double a); DECLDIR long random_hypergeometric(prng_t *prng_state, long good, long bad, long sample); -DECLDIR unsigned long random_interval(prng_t *prng_state, unsigned long max); + +DECLDIR uint64_t random_interval(prng_t *prng_state, uint64_t max); DECLDIR uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, uint64_t rng, uint64_t mask); DECLDIR uint32_t random_buffered_bounded_uint32(prng_t *prng_state, diff --git a/_randomgen/core_prng/src/philox/philox.c b/_randomgen/core_prng/src/philox/philox.c index ea401e3690d8..3382c60d6acf 100644 --- a/_randomgen/core_prng/src/philox/philox.c +++ b/_randomgen/core_prng/src/philox/philox.c @@ -2,7 +2,7 @@ extern INLINE uint64_t philox_next64(philox_state *state); -extern INLINE uint64_t philox_next32(philox_state *state); +extern INLINE uint32_t philox_next32(philox_state *state); extern void philox_jump(philox_state *state) { /* Advances state as-if 2^128 draws were made */ diff --git a/_randomgen/core_prng/src/philox/philox.h b/_randomgen/core_prng/src/philox/philox.h index e0545bce3540..a130010e626b 100644 --- a/_randomgen/core_prng/src/philox/philox.h +++ b/_randomgen/core_prng/src/philox/philox.h @@ -49,7 +49,8 @@ static INLINE uint64_t _umul128(uint64_t a, uint64_t b, uint64_t *high) { a_x_b_lo = __emulu(a_lo, b_lo); carry_bit = ((uint64_t)(uint32_t)a_x_b_mid + (uint64_t)(uint32_t)b_x_a_mid + - (a_x_b_lo >> 32)) >> 32; + (a_x_b_lo >> 32)) >> + 32; *high = a_x_b_hi + (a_x_b_mid >> 32) + (b_x_a_mid >> 32) + carry_bit; @@ -82,7 +83,8 @@ static INLINE uint64_t _umul128(uint64_t a, uint64_t b, uint64_t *high) { a_x_b_lo = a_lo * b_lo; carry_bit = ((uint64_t)(uint32_t)a_x_b_mid + (uint64_t)(uint32_t)b_x_a_mid + - (a_x_b_lo >> 32)) >> 32; + (a_x_b_lo >> 32)) >> + 32; *high = a_x_b_hi + (a_x_b_mid >> 32) + (b_x_a_mid >> 32) + carry_bit; @@ -227,7 +229,7 @@ static INLINE uint64_t philox_next64(philox_state *state) { return philox_next(state); } -static INLINE uint64_t philox_next32(philox_state *state) { +static INLINE uint32_t philox_next32(philox_state *state) { uint64_t next; if (state->has_uint32) { diff --git a/_randomgen/core_prng/src/threefry/threefry.c b/_randomgen/core_prng/src/threefry/threefry.c index 6aac7b5256c8..19c37df1bf93 100644 --- a/_randomgen/core_prng/src/threefry/threefry.c +++ b/_randomgen/core_prng/src/threefry/threefry.c @@ -2,7 +2,7 @@ extern INLINE uint64_t threefry_next64(threefry_state *state); -extern INLINE uint64_t threefry_next32(threefry_state *state); +extern INLINE uint32_t threefry_next32(threefry_state *state); extern void threefry_jump(threefry_state *state) { /* Advances state as-if 2^128 draws were made */ diff --git a/_randomgen/core_prng/src/threefry/threefry.h b/_randomgen/core_prng/src/threefry/threefry.h index 0b557a00d119..e0e4c21a57b7 100644 --- a/_randomgen/core_prng/src/threefry/threefry.h +++ b/_randomgen/core_prng/src/threefry/threefry.h @@ -319,7 +319,7 @@ static INLINE uint64_t threefry_next64(threefry_state *state) { return threefry_next(state); } -static INLINE uint64_t threefry_next32(threefry_state *state) { +static INLINE uint32_t threefry_next32(threefry_state *state) { uint64_t next; if (state->has_uint32) { state->has_uint32 = 0; diff --git a/_randomgen/core_prng/src/threefry32/threefry32.c b/_randomgen/core_prng/src/threefry32/threefry32.c index e30d9c5690e8..500e9482d906 100644 --- a/_randomgen/core_prng/src/threefry32/threefry32.c +++ b/_randomgen/core_prng/src/threefry32/threefry32.c @@ -2,7 +2,7 @@ extern INLINE uint64_t threefry32_next64(threefry32_state *state); -extern INLINE uint64_t threefry32_next32(threefry32_state *state); +extern INLINE uint32_t threefry32_next32(threefry32_state *state); extern void threefry32_jump(threefry32_state *state) { /* Advances state as-if 2^64 draws were made */ diff --git a/_randomgen/core_prng/src/threefry32/threefry32.h b/_randomgen/core_prng/src/threefry32/threefry32.h index 8e9a1161e4ed..9e4cdf2fc3ac 100644 --- a/_randomgen/core_prng/src/threefry32/threefry32.h +++ b/_randomgen/core_prng/src/threefry32/threefry32.h @@ -17,25 +17,33 @@ Adapted from random123's threefry.h #define THREEFRY_BUFFER_SIZE 4L - static INLINE uint32_t RotL_32(uint32_t x, unsigned int N); -static INLINE uint32_t RotL_32(uint32_t x, unsigned int N) -{ - return (x << (N & 31)) | (x >> ((32-N) & 31)); +static INLINE uint32_t RotL_32(uint32_t x, unsigned int N) { + return (x << (N & 31)) | (x >> ((32 - N) & 31)); } -struct r123array4x32{ uint32_t v[4]; }; +struct r123array4x32 { + uint32_t v[4]; +}; enum r123_enum_threefry32x4 { - R_32x4_0_0=10, R_32x4_0_1=26, - R_32x4_1_0=11, R_32x4_1_1=21, - R_32x4_2_0=13, R_32x4_2_1=27, - R_32x4_3_0=23, R_32x4_3_1= 5, - R_32x4_4_0= 6, R_32x4_4_1=20, - R_32x4_5_0=17, R_32x4_5_1=11, - R_32x4_6_0=25, R_32x4_6_1=10, - R_32x4_7_0=18, R_32x4_7_1=20 + R_32x4_0_0 = 10, + R_32x4_0_1 = 26, + R_32x4_1_0 = 11, + R_32x4_1_1 = 21, + R_32x4_2_0 = 13, + R_32x4_2_1 = 27, + R_32x4_3_0 = 23, + R_32x4_3_1 = 5, + R_32x4_4_0 = 6, + R_32x4_4_1 = 20, + R_32x4_5_0 = 17, + R_32x4_5_1 = 11, + R_32x4_6_0 = 25, + R_32x4_6_1 = 10, + R_32x4_7_0 = 18, + R_32x4_7_1 = 20 }; @@ -45,15 +53,19 @@ typedef struct r123array4x32 threefry4x32_ukey_t; static INLINE threefry4x32_key_t threefry4x32keyinit(threefry4x32_ukey_t uk) { return uk; }; -static INLINE threefry4x32_ctr_t threefry4x32_R(unsigned int Nrounds, threefry4x32_ctr_t in , threefry4x32_key_t k); -static INLINE threefry4x32_ctr_t threefry4x32_R(unsigned int Nrounds, threefry4x32_ctr_t in , threefry4x32_key_t k) { +static INLINE threefry4x32_ctr_t threefry4x32_R(unsigned int Nrounds, + threefry4x32_ctr_t in, + threefry4x32_key_t k); +static INLINE threefry4x32_ctr_t threefry4x32_R(unsigned int Nrounds, + threefry4x32_ctr_t in, + threefry4x32_key_t k) { threefry4x32_ctr_t X; uint32_t ks[4 + 1]; int i; ks[4] = 0x1BD11BDA; for (i = 0; i < 4; i++) { ks[i] = k.v[i]; - X.v[i] = in .v[i]; + X.v[i] = in.v[i]; ks[4] ^= k.v[i]; } X.v[0] += ks[0]; @@ -764,15 +776,14 @@ static INLINE threefry4x32_ctr_t threefry4x32_R(unsigned int Nrounds, threefry4x } return X; } -enum r123_enum_threefry4x32 { - threefry4x32_rounds = 20 -}; -static INLINE threefry4x32_ctr_t threefry4x32(threefry4x32_ctr_t in , threefry4x32_key_t k); -static INLINE threefry4x32_ctr_t threefry4x32(threefry4x32_ctr_t in , threefry4x32_key_t k) { - return threefry4x32_R(threefry4x32_rounds, in , k); +enum r123_enum_threefry4x32 { threefry4x32_rounds = 20 }; +static INLINE threefry4x32_ctr_t threefry4x32(threefry4x32_ctr_t in, + threefry4x32_key_t k); +static INLINE threefry4x32_ctr_t threefry4x32(threefry4x32_ctr_t in, + threefry4x32_key_t k) { + return threefry4x32_R(threefry4x32_rounds, in, k); } - typedef struct s_threefry32_state { threefry4x32_key_t *ctr; threefry4x32_ctr_t *key; @@ -813,7 +824,7 @@ static INLINE uint64_t threefry32_next64(threefry32_state *state) { return ((uint64_t)threefry32_next(state) << 32) | threefry32_next(state); } -static INLINE uint64_t threefry32_next32(threefry32_state *state) { +static INLINE uint32_t threefry32_next32(threefry32_state *state) { return threefry32_next(state); } From 8c6b7ca1f5a7efa652d3c53d56e6436702453760 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 13 Mar 2018 08:44:29 +0000 Subject: [PATCH 070/279] CLN: Simplify distributions Use inline functions to avoid complicated state use --- .../src/distributions/distributions.c | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 20b4d5d26d5c..070a2edfbb5b 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -2,30 +2,38 @@ #include "ziggurat.h" #include "ziggurat_constants.h" +/* Inline generators for internal use */ static NPY_INLINE uint32_t random_uint32(prng_t *prng_state) { return prng_state->next_uint32(prng_state->state); } -static NPY_INLINE float next_float(prng_t *prng_state) { +static NPY_INLINE uint64_t random_uint64(prng_t *prng_state) { + return prng_state->next_uint64(prng_state->state); +} + +static NPY_INLINE float random_float(prng_t *prng_state) { return (random_uint32(prng_state) >> 9) * (1.0f / 8388608.0f); } -static NPY_INLINE uint64_t random_uint64(prng_t *prng_state) { - return prng_state->next_uint64(prng_state->state); +static NPY_INLINE float random_double(prng_t *prng_state) { + return prng_state->next_double(prng_state->state); } -float random_sample_f(prng_t *prng_state) { return next_float(prng_state); } +/* Random generators for external use */ +float random_sample_f(prng_t *prng_state) { + return random_float(prng_state); +} double random_sample(prng_t *prng_state) { - return prng_state->next_double(prng_state->state); + return random_double(prng_state); } double random_standard_exponential(prng_t *prng_state) { - return -log(1.0 - prng_state->next_double(prng_state->state)); + return -log(1.0 - random_double(prng_state)); } float random_standard_exponential_f(prng_t *prng_state) { - return -logf(1.0f - next_float(prng_state)); + return -logf(1.0f - random_float(prng_state)); } double random_gauss(prng_t *prng_state) { @@ -38,8 +46,8 @@ double random_gauss(prng_t *prng_state) { double f, x1, x2, r2; do { - x1 = 2.0 * prng_state->next_double(prng_state->state) - 1.0; - x2 = 2.0 * prng_state->next_double(prng_state->state) - 1.0; + x1 = 2.0 * random_double(prng_state) - 1.0; + x2 = 2.0 * random_double(prng_state) - 1.0; r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); @@ -62,8 +70,8 @@ float random_gauss_f(prng_t *prng_state) { float f, x1, x2, r2; do { - x1 = 2.0f * next_float(prng_state) - 1.0f; - x2 = 2.0f * next_float(prng_state) - 1.0f; + x1 = 2.0f * random_float(prng_state) - 1.0f; + x2 = 2.0f * random_float(prng_state) - 1.0f; r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); @@ -81,9 +89,9 @@ static NPY_INLINE double standard_exponential_zig(prng_t *prng_state); static double standard_exponential_zig_unlikely(prng_t *prng_state, uint8_t idx, double x) { if (idx == 0) { - return ziggurat_exp_r - log(prng_state->next_double(prng_state->state)); + return ziggurat_exp_r - log(random_double(prng_state)); } else if ((fe_double[idx - 1] - fe_double[idx]) * - prng_state->next_double(prng_state->state) + + random_double(prng_state) + fe_double[idx] < exp(-x)) { return x; @@ -116,8 +124,8 @@ static NPY_INLINE float standard_exponential_zig_f(prng_t *prng_state); static float standard_exponential_zig_unlikely_f(prng_t *prng_state, uint8_t idx, float x) { if (idx == 0) { - return ziggurat_exp_r_f - logf(next_float(prng_state)); - } else if ((fe_float[idx - 1] - fe_float[idx]) * next_float(prng_state) + + return ziggurat_exp_r_f - logf(random_float(prng_state)); + } else if ((fe_float[idx - 1] - fe_float[idx]) * random_float(prng_state) + fe_float[idx] < expf(-x)) { return x; @@ -166,15 +174,15 @@ double random_gauss_zig(prng_t *prng_state) { if (idx == 0) { for (;;) { xx = -ziggurat_nor_inv_r * - log(prng_state->next_double(prng_state->state)); - yy = -log(prng_state->next_double(prng_state->state)); + log(random_double(prng_state)); + yy = -log(random_double(prng_state)); if (yy + yy > xx * xx) return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r + xx) : ziggurat_nor_r + xx; } } else { if (((fi_double[idx - 1] - fi_double[idx]) * - prng_state->next_double(prng_state->state) + + random_double(prng_state) + fi_double[idx]) < exp(-0.5 * x * x)) return x; } @@ -200,14 +208,14 @@ float random_gauss_zig_f(prng_t *prng_state) { return x; // # 99.3% of the time return here if (idx == 0) { for (;;) { - xx = -ziggurat_nor_inv_r_f * logf(next_float(prng_state)); - yy = -logf(next_float(prng_state)); + xx = -ziggurat_nor_inv_r_f * logf(random_float(prng_state)); + yy = -logf(random_float(prng_state)); if (yy + yy > xx * xx) return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r_f + xx) : ziggurat_nor_r_f + xx; } } else { - if (((fi_float[idx - 1] - fi_float[idx]) * next_float(prng_state) + + if (((fi_float[idx - 1] - fi_float[idx]) * random_float(prng_state) + fi_float[idx]) < exp(-0.5 * x * x)) return x; } @@ -222,7 +230,7 @@ static NPY_INLINE double standard_gamma(prng_t *prng_state, double shape) { return random_standard_exponential(prng_state); } else if (shape < 1.0) { for (;;) { - U = prng_state->next_double(prng_state->state); + U = random_double(prng_state); V = random_standard_exponential(prng_state); if (U <= 1.0 - shape) { X = pow(U, 1. / shape); From 7cb2ce3a6074b83aae5c935fac41fd051bde2f9b Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 13 Mar 2018 09:15:55 +0000 Subject: [PATCH 071/279] BUG: Fix returned type Return double --- _randomgen/core_prng/src/distributions/distributions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 070a2edfbb5b..6b39763714e3 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -15,7 +15,7 @@ static NPY_INLINE float random_float(prng_t *prng_state) { return (random_uint32(prng_state) >> 9) * (1.0f / 8388608.0f); } -static NPY_INLINE float random_double(prng_t *prng_state) { +static NPY_INLINE double random_double(prng_t *prng_state) { return prng_state->next_double(prng_state->state); } From 1fe73ec97655409b7a2b69e666df06eff6769b87 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 13 Mar 2018 09:11:11 +0000 Subject: [PATCH 072/279] REF: Drop Box-Muller Drop Box-Muller and supported infrastructure --- _randomgen/core_prng/distributions.pxd | 8 - _randomgen/core_prng/dsfmt.pyx | 5 +- _randomgen/core_prng/generator.pyx | 162 ++++-------------- _randomgen/core_prng/mt19937.pyx | 15 +- _randomgen/core_prng/pcg32.pyx | 7 - _randomgen/core_prng/pcg64.pyx | 4 - _randomgen/core_prng/philox.pyx | 4 - .../src/distributions/distributions.c | 54 +++--- .../src/distributions/distributions.h | 27 ++- .../core_prng/tests/test_against_numpy.py | 55 +++--- _randomgen/core_prng/tests/test_direct.py | 11 +- .../core_prng/tests/test_numpy_mt19937.py | 52 ++++-- _randomgen/core_prng/tests/test_smoke.py | 53 +++--- _randomgen/core_prng/threefry.pyx | 4 - _randomgen/core_prng/threefry32.pyx | 4 - _randomgen/core_prng/xoroshiro128.pyx | 4 - _randomgen/core_prng/xorshift1024.pyx | 4 - .../cython/extending_distributions.pyx | 19 -- .../examples/numba/extending_distributions.py | 12 +- 19 files changed, 187 insertions(+), 317 deletions(-) diff --git a/_randomgen/core_prng/distributions.pxd b/_randomgen/core_prng/distributions.pxd index 5359a1be0eaa..e26effa1adaa 100644 --- a/_randomgen/core_prng/distributions.pxd +++ b/_randomgen/core_prng/distributions.pxd @@ -32,10 +32,6 @@ cdef extern from "src/distributions/distributions.h": uint32_t (*next_uint32)(void *st) nogil double (*next_double)(void *st) nogil uint64_t (*next_raw)(void *st) nogil - int has_gauss - double gauss - int has_gauss_f - float gauss_f binomial_t *binomial ctypedef prng prng_t @@ -43,15 +39,12 @@ cdef extern from "src/distributions/distributions.h": double random_sample(prng_t *prng_state) nogil double random_standard_exponential(prng_t *prng_state) nogil double random_standard_exponential_zig(prng_t *prng_state) nogil - double random_gauss(prng_t *prng_state) nogil double random_gauss_zig(prng_t* prng_state) nogil - double random_standard_gamma(prng_t *prng_state, double shape) nogil double random_standard_gamma_zig(prng_t *prng_state, double shape) nogil float random_sample_f(prng_t *prng_state) nogil float random_standard_exponential_f(prng_t *prng_state) nogil float random_standard_exponential_zig_f(prng_t *prng_state) nogil - float random_gauss_f(prng_t *prng_state) nogil float random_gauss_zig_f(prng_t* prng_state) nogil float random_standard_gamma_f(prng_t *prng_state, float shape) nogil float random_standard_gamma_zig_f(prng_t *prng_state, float shape) nogil @@ -61,7 +54,6 @@ cdef extern from "src/distributions/distributions.h": long random_positive_int(prng_t *prng_state) nogil unsigned long random_uint(prng_t *prng_state) nogil - double random_normal(prng_t *prng_state, double loc, double scale) nogil double random_normal_zig(prng_t *prng_state, double loc, double scale) nogil double random_gamma(prng_t *prng_state, double shape, double scale) nogil diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index c95f4f2d3918..4280c22f9b3f 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -118,10 +118,7 @@ cdef class DSFMT: free(self._prng) cdef _reset_state_variables(self): - self._prng.has_gauss = 0 - self._prng.has_gauss_f = 0 - self._prng.gauss = 0.0 - self._prng.gauss_f = 0.0 + pass def __random_integer(self, bits=64): """ diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 72d357067047..d6bda579ba18 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -72,9 +72,6 @@ cdef class RandomGenerator: raise ValueError("Invalid prng. The prng must be instantized.") self._prng = PyCapsule_GetPointer(capsule, anon_name) self.lock = Lock() - with self.lock: - self._prng.has_gauss = 0 - self._prng.has_gauss_f = 0 def __repr__(self): return self.__str__() + ' at 0x{:X}'.format(id(self)) @@ -104,23 +101,11 @@ cdef class RandomGenerator: @property def state(self): """Get or set the underlying PRNG's state""" - state = self.__core_prng.state - state['has_gauss'] = self._prng.has_gauss - state['has_gauss_f'] = self._prng.has_gauss_f - state['gauss'] = self._prng.gauss - state['gauss_f'] = self._prng.gauss_f - return state + return self.__core_prng.state @state.setter def state(self, value): self.__core_prng.state = value - if isinstance(value, tuple): - # Legacy MT19937 state - return - self._prng.has_gauss = value['has_gauss'] - self._prng.has_gauss_f = value['has_gauss_f'] - self._prng.gauss = value['gauss'] - self._prng.gauss_f = value['gauss_f'] def random_uintegers(self, size=None, int bits=64): """ @@ -246,14 +231,6 @@ cdef class RandomGenerator: else: raise ValueError('bits must be 32 or 64') - def random_double(self, bits=64): - if bits == 64: - return self._prng.next_double(self._prng.state) - elif bits == 32: - return random_sample_f(self._prng) - else: - raise ValueError('bits must be 32 or 64') - def random_sample(self, size=None, dtype=np.float64, out=None): """ random_sample(size=None, dtype='d', out=None) @@ -994,9 +971,9 @@ cdef class RandomGenerator: else: return self.random_sample(size=args, dtype=dtype) - def randn(self, *args, method=u'zig', dtype=np.float64): + def randn(self, *args, dtype=np.float64): """ - randn(d0, d1, ..., dn, method='zig', dtype='d') + randn(d0, d1, ..., dn, dtype='d') Return a sample (or samples) from the "standard normal" distribution. @@ -1016,10 +993,6 @@ cdef class RandomGenerator: d0, d1, ..., dn : int, optional The dimensions of the returned array, should be all positive. If no argument is given a single Python float is returned. - method : str, optional - Either 'bm' or 'zig'. 'bm' uses the default Box-Muller - transformations method. 'zig' uses the much faster Ziggurat - method of Marsaglia and Tsang. dtype : {str, dtype}, optional Desired dtype of the result, either 'd' (or 'float64') or 'f' (or 'float32'). All dtypes are determined by their name. The @@ -1055,9 +1028,9 @@ cdef class RandomGenerator: """ if len(args) == 0: - return self.standard_normal(method=method, dtype=dtype) + return self.standard_normal(dtype=dtype) else: - return self.standard_normal(size=args, method=method, dtype=dtype) + return self.standard_normal(size=args, dtype=dtype) def random_integers(self, low, high=None, size=None): """ @@ -1154,9 +1127,9 @@ cdef class RandomGenerator: return self.randint(low, high + 1, size=size, dtype='l') # Complicated, continuous distributions: - def standard_normal(self, size=None, dtype=np.float64, method=u'zig', out=None): + def standard_normal(self, size=None, dtype=np.float64, out=None): """ - standard_normal(size=None, dtype='d', method='zig', out=None) + standard_normal(size=None, dtype='d', out=None) Draw samples from a standard Normal distribution (mean=0, stdev=1). @@ -1170,9 +1143,6 @@ cdef class RandomGenerator: Desired dtype of the result, either 'd' (or 'float64') or 'f' (or 'float32'). All dtypes are determined by their name. The default value is 'd'. - method : str, optional - Either 'bm' or 'zig'. 'bm' uses the Box-Muller transformations - method. 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. out : ndarray, optional Alternative output array in which to place the result. If size is not None, it must have the same shape as the provided size and must match the type of @@ -1198,22 +1168,17 @@ cdef class RandomGenerator: """ key = np.dtype(dtype).name if key == 'float64': - if method == u'zig': - return double_fill(&random_gauss_zig, self._prng, size, self.lock, out) - else: - return double_fill(&random_gauss, self._prng, size, self.lock, out) + return double_fill(&random_gauss_zig, self._prng, size, self.lock, out) elif key == 'float32': - if method == u'zig': - return float_fill(&random_gauss_zig_f, self._prng, size, self.lock, out) - else: - return float_fill(&random_gauss_f, self._prng, size, self.lock, out) + return float_fill(&random_gauss_zig_f, self._prng, size, self.lock, out) + else: raise TypeError('Unsupported dtype "%s" for standard_normal' % key) - def normal(self, loc=0.0, scale=1.0, size=None, method=u'zig'): + def normal(self, loc=0.0, scale=1.0, size=None): """ - normal(loc=0.0, scale=1.0, size=None, method='zig') + normal(loc=0.0, scale=1.0, size=None) Draw random samples from a normal (Gaussian) distribution. @@ -1238,10 +1203,6 @@ cdef class RandomGenerator: ``m * n * k`` samples are drawn. If size is ``None`` (default), a single value is returned if ``loc`` and ``scale`` are both scalars. Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. - method : str, optional - Either 'bm' or 'zig'. 'bm' uses the default Box-Muller transformations - method. 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. - Returns ------- @@ -1304,23 +1265,15 @@ cdef class RandomGenerator: >>> plt.show() """ - if method == 'bm': - return cont(&random_normal, self._prng, size, self.lock, 2, - loc, '', CONS_NONE, - scale, 'scale', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, - None) - else: - return cont(&random_normal_zig, self._prng, size, self.lock, 2, - loc, '', CONS_NONE, - scale, 'scale', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, - None) + return cont(&random_normal_zig, self._prng, size, self.lock, 2, + loc, '', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + None) - def complex_normal(self, loc=0.0, gamma=1.0, relation=0.0, size=None, - method=u'zig'): + def complex_normal(self, loc=0.0, gamma=1.0, relation=0.0, size=None): """ - complex_normal(loc=0.0, gamma=1.0, relation=0.0, size=None, method='zig') + complex_normal(loc=0.0, gamma=1.0, relation=0.0, size=None) Draw random samples from a complex normal (Gaussian) distribution. @@ -1338,10 +1291,6 @@ cdef class RandomGenerator: a single value is returned if ``loc``, ``gamma`` and ``relation`` are all scalars. Otherwise, ``np.broadcast(loc, gamma, relation).size`` samples are drawn. - method : str, optional - Either 'bm' or 'zig'. 'bm' uses the default Box-Muller - transformations method. 'zig' uses the much faster Ziggurat - method of Marsaglia and Tsang. Returns ------- @@ -1379,8 +1328,6 @@ cdef class RandomGenerator: >>> s = np.random.complex_normal(size=1000) """ - if method != u'zig' and method != u'bm': - raise ValueError("method must be either 'bm' or 'zig'") cdef np.ndarray ogamma, orelation, oloc, randoms, v_real, v_imag, rho cdef double *randoms_data cdef double fgamma_r, fgamma_i, frelation_r, frelation_i, frho, fvar_r , fvar_i, \ @@ -1415,12 +1362,8 @@ cdef class RandomGenerator: raise ValueError('Im(relation) ** 2 > Re(gamma ** 2 - relation** 2)') if size is None: - if method == u'zig': - f_real = random_gauss_zig(self._prng) - f_imag = random_gauss_zig(self._prng) - else: - f_real = random_gauss(self._prng) - f_imag = random_gauss(self._prng) + f_real = random_gauss_zig(self._prng) + f_imag = random_gauss_zig(self._prng) compute_complex(&f_real, &f_imag, floc_r, floc_i, fvar_r, fvar_i, f_rho) return PyComplex_FromDoubles(f_real, f_imag) @@ -1434,20 +1377,12 @@ cdef class RandomGenerator: i_scale = sqrt(fvar_i) j = 0 with self.lock, nogil: - if method == u'zig': - for i in range(n): - f_real = random_gauss_zig(self._prng) - f_imag = random_gauss_zig(self._prng) - randoms_data[j+1] = floc_i + i_scale * (f_rho * f_real + i_r_scale * f_imag) - randoms_data[j] = floc_r + r_scale * f_real - j += 2 - else: - for i in range(n): - f_real = random_gauss(self._prng) - f_imag = random_gauss(self._prng) - randoms_data[j+1] = floc_i + i_scale * (f_rho * f_real + i_r_scale * f_imag) - randoms_data[j] = floc_r + r_scale * f_real - j += 2 + for i in range(n): + f_real = random_gauss_zig(self._prng) + f_imag = random_gauss_zig(self._prng) + randoms_data[j+1] = floc_i + i_scale * (f_rho * f_real + i_r_scale * f_imag) + randoms_data[j] = floc_r + r_scale * f_real + j += 2 return randoms @@ -1481,12 +1416,8 @@ cdef class RandomGenerator: it = np.PyArray_MultiIterNew5(randoms, oloc, v_real, v_imag, rho) with self.lock, nogil: n2 = 2 * n # Avoid compiler noise for cast to long - if method == u'zig': - for i in range(n2): - randoms_data[i] = random_gauss_zig(self._prng) - else: - for i in range(n2): - randoms_data[i] = random_gauss(self._prng) + for i in range(n2): + randoms_data[i] = random_gauss_zig(self._prng) with nogil: j = 0 for i in range(n): @@ -1501,10 +1432,9 @@ cdef class RandomGenerator: return randoms - def standard_gamma(self, shape, size=None, dtype=np.float64, method=u'zig', - out=None): + def standard_gamma(self, shape, size=None, dtype=np.float64, out=None): """ - standard_gamma(shape, size=None, dtype='d', method='inv', out=None) + standard_gamma(shape, size=None, dtype='d', out=None) Draw samples from a standard Gamma distribution. @@ -1524,9 +1454,6 @@ cdef class RandomGenerator: Desired dtype of the result, either 'd' (or 'float64') or 'f' (or 'float32'). All dtypes are determined by their name. The default value is 'd'. - method : str, optional - Either 'inv' or 'zig'. 'inv' uses the default inverse CDF method. - 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. out : ndarray, optional Alternative output array in which to place the result. If size is not None, it must have the same shape as the provided size and @@ -1582,25 +1509,15 @@ cdef class RandomGenerator: >>> plt.show() """ cdef void *func - if method != u'zig' and method != u'inv': - raise ValueError("method must be either 'inv' or 'zig'") key = np.dtype(dtype).name if key == 'float64': - if method == 'inv': - func = &random_standard_gamma - else: - func = &random_standard_gamma_zig - return cont(func, self._prng, size, self.lock, 1, + return cont(&random_standard_gamma_zig, self._prng, size, self.lock, 1, shape, 'shape', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, out) if key == 'float32': - if method == 'inv': - func = &random_standard_gamma_f - else: - func = &random_standard_gamma_zig_f - return cont_f(func, self._prng, size, self.lock, + return cont_f(&random_standard_gamma_zig_f, self._prng, size, self.lock, shape, 'shape', CONS_NON_NEGATIVE, out) else: @@ -3242,7 +3159,6 @@ cdef class RandomGenerator: >>> sum(np.random.binomial(9, 0.1, 20000) == 0)/20000. # answer = 0.38885, or 38%. - """ return disc(&random_binomial, self._prng, size, self.lock, 1, 1, p, 'p', CONS_BOUNDED_0_1_NOTNAN, @@ -3729,10 +3645,10 @@ cdef class RandomGenerator: # Multivariate distributions: def multivariate_normal(self, mean, cov, size=None, check_valid='warn', - tol=1e-8, method=u'zig'): + tol=1e-8): """ multivariate_normal(self, mean, cov, size=None, check_valid='warn', - tol=1e-8, method='zig') + tol=1e-8) Draw random samples from a multivariate normal distribution. @@ -3759,9 +3675,6 @@ cdef class RandomGenerator: Behavior when the covariance matrix is not positive semidefinite. tol : float, optional Tolerance when checking the singular values in covariance matrix. - method : str, optional - Either 'bm' or 'zig'. 'bm' uses the default Box-Muller transformations - method. 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang. Returns ------- @@ -3858,7 +3771,7 @@ cdef class RandomGenerator: # form a matrix of shape final_shape. final_shape = list(shape[:]) final_shape.append(mean.shape[0]) - x = self.standard_normal(final_shape, method=method).reshape(-1, mean.shape[0]) + x = self.standard_normal(final_shape).reshape(-1, mean.shape[0]) # Transform matrix of standard normals into matrix where each row # contains multivariate normals with the desired covariance. @@ -4125,7 +4038,8 @@ cdef class RandomGenerator: while i < totsize: acc = 0.0 for j in range(k): - val_data[i+j] = random_standard_gamma(self._prng, alpha_data[j]) + val_data[i+j] = random_standard_gamma_zig(self._prng, + alpha_data[j]) acc = acc + val_data[i + j] invacc = 1/acc for j in range(k): diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index 53a909100727..e755d958d351 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -78,12 +78,6 @@ cdef class MT19937: free(self._prng.binomial) free(self._prng) - cdef _reset_state_variables(self): - self._prng.has_gauss = 0 - self._prng.has_gauss_f = 0 - self._prng.gauss = 0.0 - self._prng.gauss_f = 0.0 - # Pickling support: def __getstate__(self): return self.state @@ -173,7 +167,6 @@ cdef class MT19937: raise ValueError("Seed must be between 0 and 2**32 - 1") obj = obj.astype(np.uint32, casting='unsafe', order='C') mt19937_init_by_array(self.rng_state, obj.data, np.PyArray_DIM(obj, 0)) - self._reset_state_variables() def jump(self): mt19937_jump(self.rng_state) @@ -194,13 +187,9 @@ cdef class MT19937: if isinstance(value, tuple): if value[0] != 'MT19937' or len(value) not in (3,5): raise ValueError('state is not a legacy MT19937 state') - self._reset_state_variables() - if len(value) == 5: - self._prng.has_gauss = value[3] - self._prng.gauss = value[4] value ={'prng': 'MT19937', - 'state':{'key': value[1], 'pos': value[2]} - } + 'state':{'key': value[1], 'pos': value[2]}} + if not isinstance(value, dict): raise TypeError('state must be a dict') diff --git a/_randomgen/core_prng/pcg32.pyx b/_randomgen/core_prng/pcg32.pyx index 316dc81d9087..9e46461c6b1b 100644 --- a/_randomgen/core_prng/pcg32.pyx +++ b/_randomgen/core_prng/pcg32.pyx @@ -97,12 +97,6 @@ cdef class PCG32: free(self._prng.binomial) free(self._prng) - cdef _reset_state_variables(self): - self._prng.has_gauss = 0 - self._prng.has_gauss_f = 0 - self._prng.gauss = 0.0 - self._prng.gauss_f = 0.0 - def __random_integer(self, bits=64): """ 64-bit Random Integers from the PRNG @@ -188,7 +182,6 @@ cdef class PCG32: 'and {ub}'.format(ub=ub)) pcg32_set_seed(self.rng_state, seed, inc) - self._reset_state_variables() @property def state(self): diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index c01156d72f37..d0c3e5f7638d 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -115,10 +115,6 @@ cdef class PCG64: cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - self._prng.has_gauss = 0 - self._prng.has_gauss_f = 0 - self._prng.gauss = 0.0 - self._prng.gauss_f = 0.0 def __random_integer(self, bits=64): """ diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx index c724e5ee8be0..59d6359adb56 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/core_prng/philox.pyx @@ -110,10 +110,6 @@ cdef class Philox: cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - self._prng.has_gauss = 0 - self._prng.has_gauss_f = 0 - self._prng.gauss = 0.0 - self._prng.gauss_f = 0.0 self.rng_state.buffer_pos = PHILOX_BUFFER_SIZE for i in range(PHILOX_BUFFER_SIZE): self.rng_state.buffer[i] = 0 diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 6b39763714e3..aa1284ed0afd 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -2,23 +2,6 @@ #include "ziggurat.h" #include "ziggurat_constants.h" -/* Inline generators for internal use */ -static NPY_INLINE uint32_t random_uint32(prng_t *prng_state) { - return prng_state->next_uint32(prng_state->state); -} - -static NPY_INLINE uint64_t random_uint64(prng_t *prng_state) { - return prng_state->next_uint64(prng_state->state); -} - -static NPY_INLINE float random_float(prng_t *prng_state) { - return (random_uint32(prng_state) >> 9) * (1.0f / 8388608.0f); -} - -static NPY_INLINE double random_double(prng_t *prng_state) { - return prng_state->next_double(prng_state->state); -} - /* Random generators for external use */ float random_sample_f(prng_t *prng_state) { return random_float(prng_state); @@ -36,6 +19,7 @@ float random_standard_exponential_f(prng_t *prng_state) { return -logf(1.0f - random_float(prng_state)); } +/* double random_gauss(prng_t *prng_state) { if (prng_state->has_gauss) { const double temp = prng_state->gauss; @@ -51,9 +35,9 @@ double random_gauss(prng_t *prng_state) { r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); - /* Box-Muller transform */ + // Box-Muller transform f = sqrt(-2.0 * log(r2) / r2); - /* Keep for next call */ + // Keep for next call prng_state->gauss = f * x1; prng_state->has_gauss = true; return f * x2; @@ -75,14 +59,15 @@ float random_gauss_f(prng_t *prng_state) { r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); - /* Box-Muller transform */ + // Box-Muller transform f = sqrtf(-2.0f * logf(r2) / r2); - /* Keep for next call */ + // Keep for next call prng_state->gauss_f = f * x1; prng_state->has_gauss_f = true; return f * x2; } } +*/ static NPY_INLINE double standard_exponential_zig(prng_t *prng_state); @@ -222,6 +207,7 @@ float random_gauss_zig_f(prng_t *prng_state) { } } +/* static NPY_INLINE double standard_gamma(prng_t *prng_state, double shape) { double b, c; double U, V, X, Y; @@ -306,6 +292,7 @@ static NPY_INLINE float standard_gamma_float(prng_t *prng_state, float shape) { } } + double random_standard_gamma(prng_t *prng_state, double shape) { return standard_gamma(prng_state, shape); } @@ -313,6 +300,7 @@ double random_standard_gamma(prng_t *prng_state, double shape) { float random_standard_gamma_f(prng_t *prng_state, float shape) { return standard_gamma_float(prng_state, shape); } +*/ static NPY_INLINE double standard_gamma_zig(prng_t *prng_state, double shape) { double b, c; @@ -469,9 +457,11 @@ static double loggam(double x) { return gl; } +/* double random_normal(prng_t *prng_state, double loc, double scale) { return loc + scale * random_gauss(prng_state); } +*/ double random_normal_zig(prng_t *prng_state, double loc, double scale) { return loc + scale * random_gauss_zig(prng_state); @@ -486,11 +476,11 @@ double random_uniform(prng_t *prng_state, double lower, double range) { } double random_gamma(prng_t *prng_state, double shape, double scale) { - return scale * random_standard_gamma(prng_state, shape); + return scale * random_standard_gamma_zig(prng_state, shape); } float random_gamma_float(prng_t *prng_state, float shape, float scale) { - return scale * random_standard_gamma_f(prng_state, shape); + return scale * random_standard_gamma_zig_f(prng_state, shape); } double random_beta(prng_t *prng_state, double a, double b) { @@ -521,14 +511,14 @@ double random_beta(prng_t *prng_state, double a, double b) { } } } else { - Ga = random_standard_gamma(prng_state, a); - Gb = random_standard_gamma(prng_state, b); + Ga = random_standard_gamma_zig(prng_state, a); + Gb = random_standard_gamma_zig(prng_state, b); return Ga / (Ga + Gb); } } double random_chisquare(prng_t *prng_state, double df) { - return 2.0 * random_standard_gamma(prng_state, df / 2.0); + return 2.0 * random_standard_gamma_zig(prng_state, df / 2.0); } double random_f(prng_t *prng_state, double dfnum, double dfden) { @@ -537,7 +527,7 @@ double random_f(prng_t *prng_state, double dfnum, double dfden) { } double random_standard_cauchy(prng_t *prng_state) { - return random_gauss(prng_state) / random_gauss(prng_state); + return random_gauss_zig(prng_state) / random_gauss_zig(prng_state); } double random_pareto(prng_t *prng_state, double a) { @@ -579,7 +569,7 @@ double random_logistic(prng_t *prng_state, double loc, double scale) { } double random_lognormal(prng_t *prng_state, double mean, double sigma) { - return exp(random_normal(prng_state, mean, sigma)); + return exp(random_normal_zig(prng_state, mean, sigma)); } double random_rayleigh(prng_t *prng_state, double mode) { @@ -589,8 +579,8 @@ double random_rayleigh(prng_t *prng_state, double mode) { double random_standard_t(prng_t *prng_state, double df) { double num, denom; - num = random_gauss(prng_state); - denom = random_standard_gamma(prng_state, df / 2); + num = random_gauss_zig(prng_state); + denom = random_standard_gamma_zig(prng_state, df / 2); return sqrt(df / 2) * num / sqrt(denom); } @@ -867,7 +857,7 @@ double random_noncentral_chisquare(prng_t *prng_state, double df, double nonc) { } if (1 < df) { const double Chi2 = random_chisquare(prng_state, df - 1); - const double n = random_gauss(prng_state) + sqrt(nonc); + const double n = random_gauss_zig(prng_state) + sqrt(nonc); return Chi2 + n * n; } else { const long i = random_poisson(prng_state, nonc / 2.0); @@ -886,7 +876,7 @@ double random_wald(prng_t *prng_state, double mean, double scale) { double mu_2l; mu_2l = mean / (2 * scale); - Y = random_gauss(prng_state); + Y = random_gauss_zig(prng_state); Y = mean * Y * Y; X = mean + mu_2l * (Y - sqrt(4 * scale * Y + Y * Y)); U = random_sample(prng_state); diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index 0ca1c1397919..95e839cb0967 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -59,13 +59,26 @@ typedef struct prng { uint32_t (*next_uint32)(void *st); double (*next_double)(void *st); uint64_t (*next_raw)(void *st); - int has_gauss; - double gauss; - int has_gauss_f; - float gauss_f; binomial_t *binomial; } prng_t; +/* Inline generators for internal use */ +static NPY_INLINE uint32_t random_uint32(prng_t *prng_state) { + return prng_state->next_uint32(prng_state->state); +} + +static NPY_INLINE uint64_t random_uint64(prng_t *prng_state) { + return prng_state->next_uint64(prng_state->state); +} + +static NPY_INLINE float random_float(prng_t *prng_state) { + return (random_uint32(prng_state) >> 9) * (1.0f / 8388608.0f); +} + +static NPY_INLINE double random_double(prng_t *prng_state) { + return prng_state->next_double(prng_state->state); +} + DECLDIR float random_sample_f(prng_t *prng_state); DECLDIR double random_sample(prng_t *prng_state); @@ -79,17 +92,23 @@ DECLDIR float random_standard_exponential_f(prng_t *prng_state); DECLDIR double random_standard_exponential_zig(prng_t *prng_state); DECLDIR float random_standard_exponential_zig_f(prng_t *prng_state); +/* DECLDIR double random_gauss(prng_t *prng_state); DECLDIR float random_gauss_f(prng_t *prng_state); +*/ DECLDIR double random_gauss_zig(prng_t *prng_state); DECLDIR float random_gauss_zig_f(prng_t *prng_state); +/* DECLDIR double random_standard_gamma(prng_t *prng_state, double shape); DECLDIR float random_standard_gamma_f(prng_t *prng_state, float shape); +*/ DECLDIR double random_standard_gamma_zig(prng_t *prng_state, double shape); DECLDIR float random_standard_gamma_zig_f(prng_t *prng_state, float shape); +/* DECLDIR double random_normal(prng_t *prng_state, double loc, double scale); +*/ DECLDIR double random_normal_zig(prng_t *prng_state, double loc, double scale); DECLDIR double random_gamma(prng_t *prng_state, double shape, double scale); diff --git a/_randomgen/core_prng/tests/test_against_numpy.py b/_randomgen/core_prng/tests/test_against_numpy.py index 9f0cfe054fa0..61a7a10206df 100644 --- a/_randomgen/core_prng/tests/test_against_numpy.py +++ b/_randomgen/core_prng/tests/test_against_numpy.py @@ -1,7 +1,7 @@ import numpy as np import numpy.random -import pytest from numpy.testing import assert_allclose, assert_array_equal, assert_equal +import pytest from core_prng import RandomGenerator, MT19937 @@ -12,9 +12,7 @@ def compare_0_input(f1, f2): (tuple([]), {'size': (20, 31, 5)})] -def compare_1_input(f1, f2, is_small=False, core_prng_kwargs=None): - if core_prng_kwargs is None: - core_prng_kwargs = {} +def compare_1_input(f1, f2, is_small=False): a = 0.3 if is_small else 10 inputs = [((a,), {}), ((a,), {'size': 10}), @@ -23,14 +21,11 @@ def compare_1_input(f1, f2, is_small=False, core_prng_kwargs=None): ((np.array([a] * 10),), {'size': (100, 10)})] for i in inputs: v1 = f1(*i[0], **i[1]) - i[1].update(core_prng_kwargs) v2 = f2(*i[0], **i[1]) assert_allclose(v1, v2) -def compare_2_input(f1, f2, is_np=False, is_scalar=False, core_prng_kwargs=None): - if core_prng_kwargs is None: - core_prng_kwargs = {} +def compare_2_input(f1, f2, is_np=False, is_scalar=False): if is_np: a, b = 10, 0.3 dtype = np.int @@ -52,7 +47,6 @@ def compare_2_input(f1, f2, is_np=False, is_scalar=False, core_prng_kwargs=None) for i in inputs: v1 = f1(*i[0], **i[1]) - i[1].update(core_prng_kwargs) v2 = f2(*i[0], **i[1]) assert_allclose(v1, v2) @@ -101,8 +95,8 @@ def _set_common_state(cls): st[0] = 'MT19937' st[1] = state['state']['key'] st[2] = state['state']['pos'] - st[3] = state['has_gauss'] - st[4] = state['gauss'] + st[3] = 0 + st[4] = 0.0 cls.nprs.set_state(st) def _is_state_common(self): @@ -110,8 +104,6 @@ def _is_state_common(self): state2 = self.rg.state assert (state[1] == state2['state']['key']).all() assert (state[2] == state2['state']['pos']) - assert (state[3] == state2['has_gauss']) - assert_allclose(state[4], state2['gauss']) def test_common_seed(self): self.rg.seed(1234) @@ -129,8 +121,6 @@ def test_numpy_state(self): state2 = self.rg.state assert (state[1] == state2['state']['key']).all() assert (state[2] == state2['state']['pos']) - assert (state[3] == state2['has_gauss']) - assert (state[4] == state2['gauss']) def test_random_sample(self): self._set_common_state() @@ -168,6 +158,7 @@ def test_tomaxint(self): self.rg.tomaxint) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_chisquare(self): self._set_common_state() self._is_state_common() @@ -175,14 +166,15 @@ def test_chisquare(self): self.rg.chisquare) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_gamma(self): self._set_common_state() self._is_state_common() compare_1_input(self.nprs.standard_gamma, - self.rg.standard_gamma, - core_prng_kwargs={'method':'inv'}) + self.rg.standard_gamma) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_t(self): self._set_common_state() self._is_state_common() @@ -248,6 +240,7 @@ def test_geometric(self): is_small=True) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_beta(self): self._set_common_state() self._is_state_common() @@ -262,6 +255,7 @@ def test_exponential(self): self.rg.exponential) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_f(self): self._set_common_state() self._is_state_common() @@ -269,6 +263,7 @@ def test_f(self): self.rg.f) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_gamma(self): self._set_common_state() self._is_state_common() @@ -297,6 +292,7 @@ def test_laplace(self): self.rg.laplace) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_lognormal(self): self._set_common_state() self._is_state_common() @@ -304,6 +300,7 @@ def test_lognormal(self): self.rg.lognormal) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_noncentral_chisquare(self): self._set_common_state() self._is_state_common() @@ -311,12 +308,12 @@ def test_noncentral_chisquare(self): self.rg.noncentral_chisquare) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_normal(self): self._set_common_state() self._is_state_common() compare_2_input(self.nprs.normal, - self.rg.normal, - core_prng_kwargs={'method':'bm'}) + self.rg.normal) self._is_state_common() def test_uniform(self): @@ -333,6 +330,7 @@ def test_vonmises(self): self.rg.vonmises) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_wald(self): self._set_common_state() self._is_state_common() @@ -356,6 +354,7 @@ def test_binomial(self): is_np=True) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_negative_binomial(self): self._set_common_state() self._is_state_common() @@ -364,13 +363,16 @@ def test_negative_binomial(self): is_np=True) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_randn(self): f = self.rg.randn g = self.nprs.randn - assert_allclose(f(10, method='bm'), g(10)) - assert_allclose(f(3, 4, 5, method='bm'), g(3, 4, 5)) + assert_allclose(f(10), g(10)) + assert_allclose(f(3, 4, 5), g(3, 4, 5)) def test_rand(self): + self._set_common_state() + self._is_state_common() f = self.rg.rand g = self.nprs.rand assert_allclose(f(10), g(10)) @@ -379,6 +381,7 @@ def test_rand(self): def test_poisson_lam_max(self): assert_allclose(self.rg.poisson_lam_max, self.nprs.poisson_lam_max) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_dirichlet(self): f = self.rg.dirichlet g = self.nprs.dirichlet @@ -387,6 +390,7 @@ def test_dirichlet(self): assert_allclose(f(np.array(a), 10), g(np.array(a), 10)) assert_allclose(f(np.array(a), (3, 37)), g(np.array(a), (3, 37))) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_noncentral_f(self): self._set_common_state() self._is_state_common() @@ -464,6 +468,7 @@ def test_shuffle(self): assert_equal(fa, ga) self._is_state_common() + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_multivariate_normal(self): self._set_common_state() self._is_state_common() @@ -471,11 +476,11 @@ def test_multivariate_normal(self): cov = [[1, .2, .3], [.2, 4, 1], [.3, 1, 10]] f = self.rg.multivariate_normal g = self.nprs.multivariate_normal - assert_allclose(f(mu, cov, method='bm'), g(mu, cov)) - assert_allclose(f(np.array(mu), cov, method='bm'), g(np.array(mu), cov)) - assert_allclose(f(np.array(mu), np.array(cov), method='bm'), + assert_allclose(f(mu, cov), g(mu, cov)) + assert_allclose(f(np.array(mu), cov), g(np.array(mu), cov)) + assert_allclose(f(np.array(mu), np.array(cov)), g(np.array(mu), np.array(cov))) - assert_allclose(f(np.array(mu), np.array(cov), size=(7, 31), method='bm'), + assert_allclose(f(np.array(mu), np.array(cov), size=(7, 31)), g(np.array(mu), np.array(cov), size=(7, 31))) self._is_state_common() diff --git a/_randomgen/core_prng/tests/test_direct.py b/_randomgen/core_prng/tests/test_direct.py index cada2d58d394..1bd5deafebdc 100644 --- a/_randomgen/core_prng/tests/test_direct.py +++ b/_randomgen/core_prng/tests/test_direct.py @@ -5,6 +5,7 @@ import numpy as np from numpy.testing import assert_equal, assert_allclose, assert_array_equal, \ assert_raises +import pytest from core_prng import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024 @@ -145,15 +146,16 @@ def test_raw(self): uints = rs.random_raw(1000) assert_equal(uints, self.data2['data']) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_gauss_inv(self): n = 25 rs = RandomGenerator(self.prng(*self.data1['seed'])) - gauss = rs.standard_normal(n, method='bm') + gauss = rs.standard_normal(n) assert_allclose(gauss, gauss_from_uint(self.data1['data'], n, self.bits)) rs = RandomGenerator(self.prng(*self.data2['seed'])) - gauss = rs.standard_normal(25, method='bm') + gauss = rs.standard_normal(25) assert_allclose(gauss, gauss_from_uint(self.data2['data'], n, self.bits)) @@ -349,15 +351,16 @@ def test_uniform_double(self): assert_equal(uniform_from_dsfmt(self.data2['data']), rs.random_sample(1000)) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_gauss_inv(self): n = 25 rs = RandomGenerator(self.prng(*self.data1['seed'])) - gauss = rs.standard_normal(n, method='bm') + gauss = rs.standard_normal(n) assert_allclose(gauss, gauss_from_uint(self.data1['data'], n, 'dsfmt')) rs = RandomGenerator(self.prng(*self.data2['seed'])) - gauss = rs.standard_normal(25, method='bm') + gauss = rs.standard_normal(25) assert_allclose(gauss, gauss_from_uint(self.data2['data'], n, 'dsfmt')) diff --git a/_randomgen/core_prng/tests/test_numpy_mt19937.py b/_randomgen/core_prng/tests/test_numpy_mt19937.py index 5097f82bd355..9ff45504fdb2 100644 --- a/_randomgen/core_prng/tests/test_numpy_mt19937.py +++ b/_randomgen/core_prng/tests/test_numpy_mt19937.py @@ -96,9 +96,7 @@ def setup(self): self.state = self.prng.state self.legacy_state = (self.state['prng'], self.state['state']['key'], - self.state['state']['pos'], - self.state['has_gauss'], - self.state['gauss']) + self.state['state']['pos']) def test_basic(self): old = self.prng.tomaxint(16) @@ -124,6 +122,7 @@ def test_gaussian_reset_in_media_res(self): new = self.prng.standard_normal(size=3) assert_(np.all(old == new)) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_backwards_compatibility(self): # Make sure we can accept old state tuples that do not have the # cached Gaussian value. @@ -408,9 +407,10 @@ def test_rand(self): [0.4575674820298663, 0.7781880808593471]]) assert_array_almost_equal(actual, desired, decimal=15) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_randn(self): mt19937.seed(self.seed) - actual = mt19937.randn(3, 2, method='bm') + actual = mt19937.randn(3, 2) desired = np.array([[1.34016345771863121, 1.73759122771936081], [1.498988344300628, -0.2286433324536169], [2.031033998682787, 2.17032494605655257]]) @@ -614,6 +614,7 @@ def test_binomial(self): [46, 45]]) assert_array_equal(actual, desired) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_chisquare(self): mt19937.seed(self.seed) actual = mt19937.chisquare(50, size=(3, 2)) @@ -622,6 +623,7 @@ def test_chisquare(self): [72.3828403199695174, 74.18408615260374006]]) assert_array_almost_equal(actual, desired, decimal=13) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_dirichlet(self): mt19937.seed(self.seed) alpha = np.array([51.72840233779265162, 39.74494232180943953]) @@ -665,6 +667,7 @@ def test_exponential_0(self): assert_equal(mt19937.exponential(scale=0), 0) assert_raises(ValueError, mt19937.exponential, scale=-0.) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_f(self): mt19937.seed(self.seed) actual = mt19937.f(12, 77, size=(3, 2)) @@ -673,6 +676,7 @@ def test_f(self): [1.02176975757740629, 1.34431827623300415]]) assert_array_almost_equal(actual, desired, decimal=15) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_gamma(self): mt19937.seed(self.seed) actual = mt19937.gamma(5, 3, size=(3, 2)) @@ -751,6 +755,7 @@ def test_logistic(self): [-0.21682183359214885, 2.63373365386060332]]) assert_array_almost_equal(actual, desired, decimal=15) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_lognormal(self): mt19937.seed(self.seed) actual = mt19937.lognormal(mean=.123456789, sigma=2.0, size=(3, 2)) @@ -782,12 +787,13 @@ def test_multinomial(self): [4, 3, 4, 2, 3, 4]]]) assert_array_equal(actual, desired) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_multivariate_normal(self): mt19937.seed(self.seed) mean = (.123456789, 10) cov = [[1, 0], [0, 1]] size = (3, 2) - actual = mt19937.multivariate_normal(mean, cov, size, method='bm') + actual = mt19937.multivariate_normal(mean, cov, size) desired = np.array([[[1.463620246718631, 11.73759122771936], [1.622445133300628, 9.771356667546383]], [[2.154490787682787, 12.170324946056553], @@ -798,7 +804,7 @@ def test_multivariate_normal(self): assert_array_almost_equal(actual, desired, decimal=15) # Check for default size, was raising deprecation warning - actual = mt19937.multivariate_normal(mean, cov, method='bm') + actual = mt19937.multivariate_normal(mean, cov) desired = np.array([0.895289569463708, 9.17180864067987]) assert_array_almost_equal(actual, desired, decimal=15) @@ -806,16 +812,17 @@ def test_multivariate_normal(self): # RuntimeWarning mean = [0, 0] cov = [[1, 2], [2, 1]] - assert_warns(RuntimeWarning, mt19937.multivariate_normal, mean, cov, method='bm') + assert_warns(RuntimeWarning, mt19937.multivariate_normal, mean, cov) # and that it doesn't warn with RuntimeWarning check_valid='ignore' assert_no_warnings(mt19937.multivariate_normal, mean, cov, - check_valid='ignore', method='bm') + check_valid='ignore') # and that it raises with RuntimeWarning check_valid='raises' assert_raises(ValueError, mt19937.multivariate_normal, mean, cov, - check_valid='raise', method='bm') + check_valid='raise') + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_negative_binomial(self): mt19937.seed(self.seed) actual = mt19937.negative_binomial(n=100, p=.12345, size=(3, 2)) @@ -824,6 +831,7 @@ def test_negative_binomial(self): [779, 647]]) assert_array_equal(actual, desired) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_noncentral_chisquare(self): mt19937.seed(self.seed) actual = mt19937.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) @@ -845,6 +853,7 @@ def test_noncentral_chisquare(self): [13.484222138963087, 14.377255424602957]]) assert_array_almost_equal(actual, desired, decimal=14) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_noncentral_f(self): mt19937.seed(self.seed) actual = mt19937.noncentral_f(dfnum=5, dfden=2, nonc=1, @@ -854,9 +863,10 @@ def test_noncentral_f(self): [0.43741599463544162, 1.1774208752428319]]) assert_array_almost_equal(actual, desired, decimal=14) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_normal(self): mt19937.seed(self.seed) - actual = mt19937.normal(loc=.123456789, scale=2.0, size=(3, 2), method='bm') + actual = mt19937.normal(loc=.123456789, scale=2.0, size=(3, 2)) desired = np.array([[2.80378370443726244, 3.59863924443872163], [3.121433477601256, -0.33382987590723379], [4.18552478636557357, 4.46410668111310471]]) @@ -917,6 +927,7 @@ def test_rayleigh_0(self): assert_equal(mt19937.rayleigh(scale=0), 0) assert_raises(ValueError, mt19937.rayleigh, scale=-0.) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_cauchy(self): mt19937.seed(self.seed) actual = mt19937.standard_cauchy(size=(3, 2)) @@ -933,6 +944,7 @@ def test_standard_exponential(self): [0.6116915921431676, 1.50592546727413201]]) assert_array_almost_equal(actual, desired, decimal=15) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_gamma(self): mt19937.seed(self.seed) actual = mt19937.standard_gamma(shape=3, size=(3, 2), method='inv') @@ -945,14 +957,16 @@ def test_standard_gamma_0(self): assert_equal(mt19937.standard_gamma(shape=0), 0) assert_raises(ValueError, mt19937.standard_gamma, shape=-0.) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_normal(self): mt19937.seed(self.seed) - actual = mt19937.standard_normal(size=(3, 2), method='bm') + actual = mt19937.standard_normal(size=(3, 2)) desired = np.array([[1.34016345771863121, 1.73759122771936081], [1.498988344300628, -0.2286433324536169], [2.031033998682787, 2.17032494605655257]]) assert_array_almost_equal(actual, desired, decimal=15) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_t(self): mt19937.seed(self.seed) actual = mt19937.standard_t(df=10, size=(3, 2)) @@ -1029,6 +1043,7 @@ def test_vonmises_small(self): r = mt19937.vonmises(mu=0., kappa=1.1e-8, size=10 ** 6) assert_(np.isfinite(r).all()) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_wald(self): mt19937.seed(self.seed) actual = mt19937.wald(mean=1.23, scale=1.54, size=(3, 2)) @@ -1086,6 +1101,7 @@ def test_uniform(self): actual = uniform(low, high * 3) assert_array_almost_equal(actual, desired, decimal=14) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_normal(self): loc = [0] scale = [1] @@ -1096,15 +1112,16 @@ def test_normal(self): 1.8417114045748335]) self.set_seed() - actual = normal(loc * 3, scale, method='bm') + actual = normal(loc * 3, scale) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc * 3, bad_scale) self.set_seed() - actual = normal(loc, scale * 3, method='bm') + actual = normal(loc, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc, bad_scale * 3) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_beta(self): a = [1] b = [2] @@ -1140,6 +1157,7 @@ def test_exponential(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, exponential, bad_scale * 3) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_gamma(self): shape = [1] bad_shape = [-1] @@ -1153,6 +1171,7 @@ def test_standard_gamma(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, std_gamma, bad_shape * 3) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_gamma(self): shape = [1] scale = [2] @@ -1175,6 +1194,7 @@ def test_gamma(self): assert_raises(ValueError, gamma, bad_shape, scale * 3) assert_raises(ValueError, gamma, shape, bad_scale * 3) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_f(self): dfnum = [1] dfden = [2] @@ -1197,6 +1217,7 @@ def test_f(self): assert_raises(ValueError, f, bad_dfnum, dfden * 3) assert_raises(ValueError, f, dfnum, bad_dfden * 3) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_noncentral_f(self): dfnum = [2] dfden = [3] @@ -1243,6 +1264,7 @@ def test_chisquare(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, chisquare, bad_df * 3) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_noncentral_chisquare(self): df = [1] nonc = [2] @@ -1265,6 +1287,7 @@ def test_noncentral_chisquare(self): assert_raises(ValueError, nonc_chi, bad_df, nonc * 3) assert_raises(ValueError, nonc_chi, df, bad_nonc * 3) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_t(self): df = [1] bad_df = [-1] @@ -1393,6 +1416,7 @@ def test_logistic(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, logistic, loc, bad_scale * 3) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_lognormal(self): mean = [0] sigma = [1] @@ -1425,6 +1449,7 @@ def test_rayleigh(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, rayleigh, bad_scale * 3) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_wald(self): mean = [0.5] scale = [1] @@ -1503,6 +1528,7 @@ def test_binomial(self): assert_raises(ValueError, binom, n, bad_p_one * 3) assert_raises(ValueError, binom, n, bad_p_two * 3) + @pytest.mark.skip(reason='Box-Muller no longer supported') def test_negative_binomial(self): n = [1] p = [0.5] diff --git a/_randomgen/core_prng/tests/test_smoke.py b/_randomgen/core_prng/tests/test_smoke.py index 8e184bce1ac8..a5f35390da45 100644 --- a/_randomgen/core_prng/tests/test_smoke.py +++ b/_randomgen/core_prng/tests/test_smoke.py @@ -86,10 +86,10 @@ def comp_state(state1, state2): def warmup(rg, n=None): if n is None: n = 11 + np.random.randint(0, 20) - rg.standard_normal(n, method='bm') - rg.standard_normal(n, method='zig') - rg.standard_normal(n, method='bm', dtype=np.float32) - rg.standard_normal(n, method='zig', dtype=np.float32) + rg.standard_normal(n) + rg.standard_normal(n) + rg.standard_normal(n, dtype=np.float32) + rg.standard_normal(n, dtype=np.float32) rg.randint(0, 2 ** 24, n, dtype=np.uint64) rg.randint(0, 2 ** 48, n, dtype=np.uint64) rg.standard_gamma(11.0, n) @@ -112,8 +112,8 @@ def _reset_state(self): def test_init(self): rg = RandomGenerator(self.prng()) state = rg.state - rg.standard_normal(1, method='bm') - rg.standard_normal(1, method='zig') + rg.standard_normal(1) + rg.standard_normal(1) rg.state = state new_state = rg.state assert_(comp_state(state, new_state)) @@ -173,7 +173,7 @@ def test_random_sample(self): params_0(self.rg.random_sample) def test_standard_normal_zig(self): - assert_(len(self.rg.standard_normal(10, method='zig')) == 10) + assert_(len(self.rg.standard_normal(10)) == 10) def test_standard_normal(self): assert_(len(self.rg.standard_normal(10)) == 10) @@ -303,22 +303,21 @@ def test_chisquare(self): def test_complex_normal(self): st = self.rg.state vals = self.rg.complex_normal( - 2.0 + 7.0j, 10.0, 5.0 - 5.0j, size=10, method='zig') + 2.0 + 7.0j, 10.0, 5.0 - 5.0j, size=10) assert_(len(vals) == 10) self.rg.state = st vals2 = [self.rg.complex_normal( - 2.0 + 7.0j, 10.0, 5.0 - 5.0j, method='zig') for _ in range(10)] + 2.0 + 7.0j, 10.0, 5.0 - 5.0j) for _ in range(10)] np.testing.assert_allclose(vals, vals2) self.rg.state = st vals3 = self.rg.complex_normal( - 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j, - method='zig') + 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j) np.testing.assert_allclose(vals, vals3) self.rg.state = st - norms = self.rg.standard_normal(size=20, method='zig') + norms = self.rg.standard_normal(size=20) norms = np.reshape(norms, (10, 2)) cov = 0.5 * (-5.0) v_real = 7.5 @@ -335,18 +334,17 @@ def test_complex_normal(self): def test_complex_normal_bm(self): st = self.rg.state vals = self.rg.complex_normal( - 2.0 + 7.0j, 10.0, 5.0 - 5.0j, size=10, method='bm') + 2.0 + 7.0j, 10.0, 5.0 - 5.0j, size=10) assert_(len(vals) == 10) self.rg.state = st vals2 = [self.rg.complex_normal( - 2.0 + 7.0j, 10.0, 5.0 - 5.0j, method='bm') for _ in range(10)] + 2.0 + 7.0j, 10.0, 5.0 - 5.0j) for _ in range(10)] np.testing.assert_allclose(vals, vals2) self.rg.state = st vals3 = self.rg.complex_normal( - 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j, - method='bm') + 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j) np.testing.assert_allclose(vals, vals3) def test_complex_normal_zero_variance(self): @@ -421,15 +419,14 @@ def test_randn(self): assert_equal(vals.shape, (10, 10, 10)) state = self.rg.state - vals = self.rg.randn(10, 10, 10, method='bm') + vals = self.rg.randn(10, 10, 10) self.rg.state = state - assert_equal(vals, self.rg.standard_normal((10, 10, 10), method='bm')) + assert_equal(vals, self.rg.standard_normal((10, 10, 10))) state = self.rg.state - vals_inv = self.rg.randn(10, 10, 10, method='bm') + vals_inv = self.rg.randn(10, 10, 10) self.rg.state = state - vals_zig = self.rg.randn(10, 10, 10, method='zig') - assert_((vals_zig != vals_inv).any()) + vals_zig = self.rg.randn(10, 10, 10) vals = self.rg.randn(10, 10, 10, dtype=np.float32) assert_(vals.shape == (10, 10, 10)) @@ -519,9 +516,9 @@ def test_multivariate_normal(self): cov = [[1, 0], [0, 100]] # diagonal covariance x = self.rg.multivariate_normal(mean, cov, 5000) assert_(x.shape == (5000, 2)) - x_zig = self.rg.multivariate_normal(mean, cov, 5000, method='zig') + x_zig = self.rg.multivariate_normal(mean, cov, 5000) assert_(x.shape == (5000, 2)) - x_inv = self.rg.multivariate_normal(mean, cov, 5000, method='bm') + x_inv = self.rg.multivariate_normal(mean, cov, 5000) assert_(x.shape == (5000, 2)) assert_((x_zig != x_inv).any()) @@ -635,11 +632,11 @@ def test_normal_floats(self): rg = RandomGenerator(self.prng()) warmup(rg) state = rg.state - r1 = rg.standard_normal(11, method='bm', dtype=np.float32) + r1 = rg.standard_normal(11, dtype=np.float32) rg2 = RandomGenerator(self.prng()) warmup(rg2) rg2.state = state - r2 = rg2.standard_normal(11, method='bm', dtype=np.float32) + r2 = rg2.standard_normal(11, dtype=np.float32) assert_array_equal(r1, r2) assert_equal(r1.dtype, np.float32) assert_(comp_state(rg.state, rg2.state)) @@ -648,11 +645,11 @@ def test_normal_zig_floats(self): rg = RandomGenerator(self.prng()) warmup(rg) state = rg.state - r1 = rg.standard_normal(11, method='zig', dtype=np.float32) + r1 = rg.standard_normal(11, dtype=np.float32) rg2 = RandomGenerator(self.prng()) warmup(rg2) rg2.state = state - r2 = rg2.standard_normal(11, method='zig', dtype=np.float32) + r2 = rg2.standard_normal(11, dtype=np.float32) assert_array_equal(r1, r2) assert_equal(r1.dtype, np.float32) assert_(comp_state(rg.state, rg2.state)) @@ -855,8 +852,6 @@ def test_numpy_state(self): state2 = self.rg.state assert_((state[1] == state2['state']['key']).all()) assert_((state[2] == state2['state']['pos'])) - assert_((state[3] == state2['has_gauss'])) - assert_((state[4] == state2['gauss'])) class TestPCG64(RNG): diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index 4cf50e3e7669..961d2f3be995 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -104,10 +104,6 @@ cdef class ThreeFry: cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - self._prng.has_gauss = 0 - self._prng.has_gauss_f = 0 - self._prng.gauss = 0.0 - self._prng.gauss_f = 0.0 self.rng_state.buffer_pos = THREEFRY_BUFFER_SIZE for i in range(THREEFRY_BUFFER_SIZE): self.rng_state.buffer[i] = 0 diff --git a/_randomgen/core_prng/threefry32.pyx b/_randomgen/core_prng/threefry32.pyx index 3a5bc92d62ac..a001d30c705a 100644 --- a/_randomgen/core_prng/threefry32.pyx +++ b/_randomgen/core_prng/threefry32.pyx @@ -105,10 +105,6 @@ cdef class ThreeFry32: free(self._prng) cdef _reset_state_variables(self): - self._prng.has_gauss = 0 - self._prng.has_gauss_f = 0 - self._prng.gauss = 0.0 - self._prng.gauss_f = 0.0 self.rng_state.buffer_pos = THREEFRY_BUFFER_SIZE for i in range(THREEFRY_BUFFER_SIZE): self.rng_state.buffer[i] = 0 diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index fa623382f832..ba727924d6c8 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -96,10 +96,6 @@ cdef class Xoroshiro128: cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - self._prng.has_gauss = 0 - self._prng.has_gauss_f = 0 - self._prng.gauss = 0.0 - self._prng.gauss_f = 0.0 def __random_integer(self, bits=64): """ diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index 939dc702b557..7fd4d73bafe5 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -88,10 +88,6 @@ cdef class Xorshift1024: cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - self._prng.has_gauss = 0 - self._prng.has_gauss_f = 0 - self._prng.gauss = 0.0 - self._prng.gauss_f = 0.0 def __random_integer(self, bits=64): """ diff --git a/_randomgen/examples/cython/extending_distributions.pyx b/_randomgen/examples/cython/extending_distributions.pyx index 9d16743a6384..65ff44f9320f 100644 --- a/_randomgen/examples/cython/extending_distributions.pyx +++ b/_randomgen/examples/cython/extending_distributions.pyx @@ -5,25 +5,6 @@ from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from core_prng.common cimport * from core_prng.xoroshiro128 import Xoroshiro128 -@cython.boundscheck(False) -@cython.wraparound(False) -def normals_bm(Py_ssize_t n): - cdef Py_ssize_t i - cdef prng_t *rng - cdef const char *capsule_name = "CorePRNG" - cdef double[::1] random_values - - x = Xoroshiro128() - capsule = x.capsule - if not PyCapsule_IsValid(capsule, capsule_name): - raise ValueError("Invalid pointer to anon_func_state") - rng = PyCapsule_GetPointer(capsule, capsule_name) - random_values = np.empty(n) - for i in range(n): - random_values[i] = random_gauss(rng) - randoms = np.asarray(random_values) - return randoms - @cython.boundscheck(False) @cython.wraparound(False) def normals_zig(Py_ssize_t n): diff --git a/_randomgen/examples/numba/extending_distributions.py b/_randomgen/examples/numba/extending_distributions.py index 5c365f338a6c..230362747882 100644 --- a/_randomgen/examples/numba/extending_distributions.py +++ b/_randomgen/examples/numba/extending_distributions.py @@ -28,25 +28,16 @@ raise RuntimeError('Required DLL/so file was not found.') ffi.cdef(""" -double random_gauss(void *prng_state); double random_gauss_zig(void *prng_state); """) x = Xoroshiro128() xffi = x.cffi prng = xffi.prng -random_gauss = lib.random_gauss random_gauss_zig = lib.random_gauss_zig def normals(n, prng): - out = np.empty(n) - for i in range(n): - out[i] = random_gauss(prng) - return out - - -def normals_zig(n, prng): out = np.empty(n) for i in range(n): out[i] = random_gauss_zig(prng) @@ -54,11 +45,10 @@ def normals_zig(n, prng): normalsj = nb.jit(normals, nopython=True) -normals_zigj = nb.jit(normals_zig, nopython=True) + # Numba requires a memory address for void * # Can also get address from x.ctypes.prng.value prng_address = int(ffi.cast('uintptr_t', prng)) norm = normalsj(1000, prng_address) -norm_zig = normals_zigj(1000, prng_address) From 80c585545fd638fe3c9a30316636a3cae5377010 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 13 Mar 2018 10:40:48 +0000 Subject: [PATCH 073/279] REF: Remove binomial_t from prng Remvoe binomial_t from each prng_state and use a single implementation at the level of a RandomGenerator --- _randomgen/README.md | 102 ++++++++-------- _randomgen/benchmark.py | 10 +- _randomgen/core_prng/common.pxd | 3 + _randomgen/core_prng/distributions.pxd | 3 +- _randomgen/core_prng/dsfmt.pyx | 4 +- _randomgen/core_prng/generator.pyx | 76 ++++++++++-- _randomgen/core_prng/mt19937.pyx | 4 +- _randomgen/core_prng/pcg32.pyx | 4 +- _randomgen/core_prng/pcg64.pyx | 4 +- _randomgen/core_prng/philox.pyx | 4 +- .../src/distributions/distributions.c | 110 +++++++++--------- .../src/distributions/distributions.h | 3 +- _randomgen/core_prng/threefry.pyx | 4 +- _randomgen/core_prng/threefry32.pyx | 4 +- _randomgen/core_prng/xoroshiro128.pyx | 24 ++-- _randomgen/core_prng/xorshift1024.pyx | 4 +- 16 files changed, 201 insertions(+), 162 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index 095f897ed306..213a6cf4b1f6 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -7,7 +7,14 @@ Experimental Core Pseudo Random Number Generator interface for future NumPy RandomState evolution. This is a library and generic interface for alternative random -generators in Python and NumPy. +generators in Python and NumPy. + + +### Compatibility Warning +Core PRNG no longer supports Box-Muller normal variates and so it not +100% compatible with NumPy (or randomstate). Box-Muller normals are slow +to generate and all functions which previously relied on Box-Muller +normals now use the faster Ziggurat implementation. ## Features @@ -42,14 +49,14 @@ y = rnd.standard_gamma(5.5, 10000, method='zig') * Uniforms (`random_sample`) * Exponentials (`standard_exponential`, both Inverse CDF and Ziggurat) - * Normals (`standard_normal`, both Box-Muller and Ziggurat) - * Standard Gammas (via `standard_gamma`, both Inverse CDF and Ziggurat) + * Normals (`standard_normal`) + * Standard Gammas (via `standard_gamma`) **WARNING**: The 32-bit generators are **experimental** and subject to change. **Note**: There are _no_ plans to extend the alternative precision - generation to all random number types. + generation to all distributions. * Support for filling existing arrays using `out` keyword argument. Currently supported in (both 32- and 64-bit outputs) @@ -61,7 +68,7 @@ y = rnd.standard_gamma(5.5, 10000, method='zig') ## Included Pseudo Random Number Generators -This modules includes a number of alternative random +This module includes a number of alternative random number generators in addition to the MT19937 that is included in NumPy. The RNGs include: @@ -71,23 +78,22 @@ The RNGs include: SSE2-aware version of the MT19937 generator that is especially fast at generating doubles * [xoroshiro128+](http://xoroshiro.di.unimi.it/) and - [xorshift1024*](http://xorshift.di.unimi.it/) + [xorshift1024*φ](http://xorshift.di.unimi.it/) * [PCG64](http:w//www.pcg-random.org/) -* ThreeFry and Philox implementationf from [Random123](https://www.deshawrsearch.com/resources_random123.html) +* ThreeFry and Philox from [Random123](https://www.deshawrsearch.com/resources_random123.html) ## Differences from `numpy.random.RandomState` ### New Features * `standard_normal`, `normal`, `randn` and `multivariate_normal` all - support an additional `method` keyword argument which can be `bm` or - `zig` where `bm` corresponds to the current method using the Box-Muller - transformation and `zig` uses the much faster (100%+) Ziggurat method. -* `standard_exponential` and `standard_gamma` both support an additional + use the much faster (100%+) Ziggurat method. +* `standard_gamma` and `gamma` both use the much faster Ziggurat method. +* `standard_exponential` `exponential` both support an additional `method` keyword argument which can be `inv` or `zig` where `inv` corresponds to the current method using the inverse CDF and `zig` uses the much faster (100%+) Ziggurat method. * Core random number generators can produce either single precision (`np.float32`) or double precision (`np.float64`, the default) using - an the optional keyword argument `dtype` + the optional keyword argument `dtype` * Core random number generators can fill existing arrays using the `out` keyword argument @@ -126,7 +132,7 @@ The version matched the latest version of NumPy where ## Documentation An occasionally updated build of the documentation is available on -[my github pages](http://bashtage.github.io/core-prng/). +[my GitHub pages](http://bashtage.github.io/core-prng/). ## Plans This module is essentially complete. There are a few rough edges that @@ -139,8 +145,8 @@ need to be smoothed. Building requires: * Python (2.7, 3.4, 3.5, 3.6) - * NumPy (1.9, 1.10, 1.11, 1.12) - * Cython (0.22, **not** 0.23, 0.24, 0.25) + * NumPy (1.10, 1.11, 1.12, 1.13, 1.14) + * Cython (0.25+) * tempita (0.5+), if not provided by Cython Testing requires pytest (3.0+). @@ -151,12 +157,12 @@ versions. ## Development and Testing All development has been on 64-bit Linux, and it is regularly tested on -Travis-CI (Linux) and Appveyor (Windows). The library is occasionally -tested on Linux 32-bit, OSX 10.13, Free BSD 11.1. +Travis-CI (Linux/OSX) and Appveyor (Windows). The library is occasionally +tested on Linux 32-bit and Free BSD 11.1. Basic tests are in place for all RNGs. The MT19937 is tested against NumPy's implementation for identical results. It also passes NumPy's -test suite. +test suite where still relevant. ## Installing @@ -206,37 +212,37 @@ NumPy's mt19937. ``` Speed-up relative to NumPy (Uniform Doubles) ************************************************************ -MT19937 22.9% -PCG64 109.6% -Philox -6.2% -ThreeFry -16.6% -Xoroshiro128 161.0% -Xorshift1024 119.9% +DSFMT 137.1% +MT19937 21.0% +PCG32 101.2% +PCG64 110.7% +Philox -2.7% +ThreeFry -11.4% +ThreeFry32 -62.3% +Xoroshiro128 181.4% +Xorshift1024 141.8% Speed-up relative to NumPy (64-bit unsigned integers) ************************************************************ -MT19937 6.2% -PCG64 88.2% -Philox -23.0% -ThreeFry -26.5% -Xoroshiro128 142.4% -Xorshift1024 107.5% - -Speed-up relative to NumPy (Standard normals (Box-Muller)) -************************************************************ -MT19937 17.7% -PCG64 35.6% -Philox -26.2% -ThreeFry -16.9% -Xoroshiro128 57.9% -Xorshift1024 40.9% - -Speed-up relative to NumPy (Standard normals (Ziggurat)) +DSFMT 24.8% +MT19937 15.0% +PCG32 92.6% +PCG64 99.0% +Philox -20.4% +ThreeFry -21.7% +ThreeFry32 -64.4% +Xoroshiro128 164.2% +Xorshift1024 120.8% + +Speed-up relative to NumPy (Standard normals) ************************************************************ -MT19937 107.9% -PCG64 149.6% -Philox 11.1% -ThreeFry 78.8% -Xoroshiro128 224.7% -Xorshift1024 158.6% -``` \ No newline at end of file +DSFMT 299.4% +MT19937 271.2% +PCG32 364.5% +PCG64 364.2% +Philox 256.9% +ThreeFry 236.0% +ThreeFry32 97.0% +Xoroshiro128 477.4% +Xorshift1024 360.7% +``` diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 3b489781a3b8..462f405fe5cc 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -103,16 +103,9 @@ def timer_64bit(): run_timer(dist, command, command_numpy, SETUP, '64-bit unsigned integers') -def timer_normal(): - dist = 'standard_normal' - command = 'rg.standard_normal(1000000, method="bm")' - command_numpy = 'rg.standard_normal(1000000)' - run_timer(dist, command, command_numpy, SETUP, 'Box-Muller normals') - - def timer_normal_zig(): dist = 'standard_normal' - command = 'rg.standard_normal(1000000, method="zig")' + command = 'rg.standard_normal(1000000)' command_numpy = 'rg.standard_normal(1000000)' run_timer(dist, command, command_numpy, SETUP, 'Standard normals (Ziggurat)') @@ -129,5 +122,4 @@ def timer_normal_zig(): timer_raw() timer_32bit() timer_64bit() - timer_normal() timer_normal_zig() diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index 43981f476f15..c571c57a2950 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -21,6 +21,9 @@ cdef enum ConstraintType: ctypedef ConstraintType constraint_type +cdef int check_constraint(double val, object name, constraint_type cons) except -1 +cdef int check_array_constraint(np.ndarray val, object name, constraint_type cons) except -1 + cdef extern from "src/aligned_malloc/aligned_malloc.h": cdef void *PyArray_realloc_aligned(void *p, size_t n); cdef void *PyArray_malloc_aligned(size_t n); diff --git a/_randomgen/core_prng/distributions.pxd b/_randomgen/core_prng/distributions.pxd index e26effa1adaa..29dc5f114fa3 100644 --- a/_randomgen/core_prng/distributions.pxd +++ b/_randomgen/core_prng/distributions.pxd @@ -32,7 +32,6 @@ cdef extern from "src/distributions/distributions.h": uint32_t (*next_uint32)(void *st) nogil double (*next_double)(void *st) nogil uint64_t (*next_raw)(void *st) nogil - binomial_t *binomial ctypedef prng prng_t @@ -85,7 +84,7 @@ cdef extern from "src/distributions/distributions.h": long random_poisson(prng_t *prng_state, double lam) nogil long random_negative_binomial(prng_t *prng_state, double n, double p) nogil - long random_binomial(prng_t *prng_state, double p, long n) nogil + long random_binomial(prng_t *prng_state, double p, long n, binomial_t *binomial) nogil long random_logseries(prng_t *prng_state, double p) nogil long random_geometric_search(prng_t *prng_state, double p) nogil long random_geometric_inversion(prng_t *prng_state, double p) nogil diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index 4280c22f9b3f..552941b189d1 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -6,7 +6,7 @@ import numpy as np cimport numpy as np from common cimport * -from distributions cimport prng_t, binomial_t +from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy @@ -88,7 +88,6 @@ cdef class DSFMT: self.rng_state.buffered_uniforms = PyArray_calloc_aligned(DSFMT_N64, sizeof(double)) self.rng_state.buffer_loc = DSFMT_N64 self._prng = malloc(sizeof(prng_t)) - self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed) self._prng.state = self.rng_state self._prng.next_uint64 = &dsfmt_uint64 @@ -114,7 +113,6 @@ cdef class DSFMT: PyArray_free_aligned(self.rng_state.state) PyArray_free_aligned(self.rng_state.buffered_uniforms) free(self.rng_state) - free(self._prng.binomial) free(self._prng) cdef _reset_state_variables(self): diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index d6bda579ba18..51cdebc19550 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -3,9 +3,6 @@ import operator import warnings -import numpy as np -cimport numpy as np -cimport cython from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from cpython cimport Py_INCREF, PyComplex_RealAsDouble, PyComplex_ImagAsDouble, PyComplex_FromDoubles from common cimport * @@ -13,9 +10,10 @@ from distributions cimport * from bounded_integers cimport * from libc cimport string from libc.stdlib cimport malloc, free - cimport numpy as np import numpy as np +cimport cython + from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from common cimport * @@ -58,6 +56,7 @@ cdef class RandomGenerator: """ cdef public object __core_prng cdef prng_t *_prng + cdef binomial_t *_binomial cdef object lock poisson_lam_max = POISSON_LAM_MAX @@ -71,8 +70,12 @@ cdef class RandomGenerator: if not PyCapsule_IsValid(capsule, anon_name): raise ValueError("Invalid prng. The prng must be instantized.") self._prng = PyCapsule_GetPointer(capsule, anon_name) + self._binomial = malloc(sizeof(binomial_t)) self.lock = Lock() + def __dealloc__(self): + free(self._binomial) + def __repr__(self): return self.__str__() + ' at 0x{:X}'.format(id(self)) @@ -3160,10 +3163,64 @@ cdef class RandomGenerator: >>> sum(np.random.binomial(9, 0.1, 20000) == 0)/20000. # answer = 0.38885, or 38%. """ - return disc(&random_binomial, self._prng, size, self.lock, 1, 1, - p, 'p', CONS_BOUNDED_0_1_NOTNAN, - n, 'n', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE) + + # Uses a custom implementation since self._binomial is required + cdef double _dp = 0 + cdef long _in = 0 + cdef bint is_scalar = True + cdef np.npy_intp i, cnt + cdef np.ndarray randoms + cdef np.int_t *randoms_data + cdef np.broadcast it + + p_arr = np.PyArray_FROM_OTF(p, np.NPY_DOUBLE, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(p_arr) == 0 + n_arr = np.PyArray_FROM_OTF(n, np.NPY_LONG, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(n_arr) == 0 + + if not is_scalar: + check_array_constraint(p_arr, 'p', CONS_BOUNDED_0_1_NOTNAN) + check_array_constraint(n_arr, 'n', CONS_NON_NEGATIVE) + if size is not None: + randoms = np.empty(size, np.int) + else: + it = np.PyArray_MultiIterNew2(p_arr, n_arr) + randoms = np.empty(it.shape, np.int) + + randoms_data = np.PyArray_DATA(randoms) + cnt = np.PyArray_SIZE(randoms) + + it = np.PyArray_MultiIterNew3(randoms, p_arr, n_arr) + with self.lock, nogil: + for i in range(cnt): + _dp = (np.PyArray_MultiIter_DATA(it, 1))[0] + _in = (np.PyArray_MultiIter_DATA(it, 2))[0] + (np.PyArray_MultiIter_DATA(it, 0))[0] = random_binomial(self._prng, _dp, _in, self._binomial) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + + _dp = PyFloat_AsDouble(p) + _in = PyInt_AsLong(n) + check_constraint(_dp, 'p', CONS_BOUNDED_0_1_NOTNAN) + check_constraint(_in, 'n', CONS_NON_NEGATIVE) + + if size is None: + with self.lock: + return random_binomial(self._prng, _dp, _in, self._binomial) + + randoms = np.empty(size, np.int) + cnt = np.PyArray_SIZE(randoms) + randoms_data = np.PyArray_DATA(randoms) + + with self.lock, nogil: + for i in range(cnt): + randoms_data[i] = random_binomial(self._prng, _dp, _in, + self._binomial) + + return randoms + def negative_binomial(self, n, p, size=None): """ @@ -3913,7 +3970,8 @@ cdef class RandomGenerator: Sum = 1.0 dn = n for j in range(d-1): - mnix[i+j] = random_binomial(self._prng, pix[j]/Sum, dn) + mnix[i+j] = random_binomial(self._prng, pix[j]/Sum, dn, + self._binomial) dn = dn - mnix[i+j] if dn <= 0: break diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/core_prng/mt19937.pyx index e755d958d351..9622b725a236 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/core_prng/mt19937.pyx @@ -7,7 +7,7 @@ import numpy as np cimport numpy as np from common cimport * -from distributions cimport prng_t, binomial_t +from distributions cimport prng_t import core_prng.pickle from core_prng.entropy import random_entropy @@ -61,7 +61,6 @@ cdef class MT19937: def __init__(self, seed=None): self.rng_state = malloc(sizeof(mt19937_state)) self._prng = malloc(sizeof(prng_t)) - self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed) self._prng.state = self.rng_state @@ -75,7 +74,6 @@ cdef class MT19937: def __dealloc__(self): free(self.rng_state) - free(self._prng.binomial) free(self._prng) # Pickling support: diff --git a/_randomgen/core_prng/pcg32.pyx b/_randomgen/core_prng/pcg32.pyx index 9e46461c6b1b..df97e1a815df 100644 --- a/_randomgen/core_prng/pcg32.pyx +++ b/_randomgen/core_prng/pcg32.pyx @@ -5,7 +5,7 @@ import numpy as np cimport numpy as np from common cimport * -from distributions cimport prng_t, binomial_t +from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy @@ -68,7 +68,6 @@ cdef class PCG32: self.rng_state = malloc(sizeof(pcg32_state)) self.rng_state.pcg_state = malloc(sizeof(pcg32_random_t)) self._prng = malloc(sizeof(prng_t)) - self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed, inc) self._prng.state = self.rng_state @@ -94,7 +93,6 @@ cdef class PCG32: def __dealloc__(self): free(self.rng_state) - free(self._prng.binomial) free(self._prng) def __random_integer(self, bits=64): diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index d0c3e5f7638d..1d6b504f8038 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -5,7 +5,7 @@ import numpy as np cimport numpy as np from common cimport * -from distributions cimport prng_t, binomial_t +from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy @@ -83,7 +83,6 @@ cdef class PCG64: self.rng_state = malloc(sizeof(pcg64_state)) self.rng_state.pcg_state = malloc(sizeof(pcg64_random_t)) self._prng = malloc(sizeof(prng_t)) - self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed, inc) self._prng.state = self.rng_state @@ -109,7 +108,6 @@ cdef class PCG64: def __dealloc__(self): free(self.rng_state) - free(self._prng.binomial) free(self._prng) cdef _reset_state_variables(self): diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx index 59d6359adb56..399c95bfad58 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/core_prng/philox.pyx @@ -4,7 +4,7 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np from common cimport * -from distributions cimport prng_t, binomial_t +from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy @@ -76,7 +76,6 @@ cdef class Philox: self.rng_state.key = malloc( sizeof(philox4x64_key_t)) self._prng = malloc(sizeof(prng_t)) - self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed, counter, key) self._prng.state = self.rng_state @@ -104,7 +103,6 @@ cdef class Philox: free(self.rng_state.ctr) free(self.rng_state.key) free(self.rng_state) - free(self._prng.binomial) free(self._prng) cdef _reset_state_variables(self): diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index aa1284ed0afd..3dd83e66d38a 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -653,50 +653,50 @@ long random_negative_binomial(prng_t *prng_state, double n, double p) { return random_poisson(prng_state, Y); } -long random_binomial_btpe(prng_t *prng_state, long n, double p) { +long random_binomial_btpe(prng_t *prng_state, long n, double p, binomial_t* binomial) { double r, q, fm, p1, xm, xl, xr, c, laml, lamr, p2, p3, p4; double a, u, v, s, F, rho, t, A, nrq, x1, x2, f1, f2, z, z2, w, w2, x; long m, y, k, i; - if (!(prng_state->binomial->has_binomial) || - (prng_state->binomial->nsave != n) || - (prng_state->binomial->psave != p)) { + if (!(binomial->has_binomial) || + (binomial->nsave != n) || + (binomial->psave != p)) { /* initialize */ - prng_state->binomial->nsave = n; - prng_state->binomial->psave = p; - prng_state->binomial->has_binomial = 1; - prng_state->binomial->r = r = min(p, 1.0 - p); - prng_state->binomial->q = q = 1.0 - r; - prng_state->binomial->fm = fm = n * r + r; - prng_state->binomial->m = m = (long)floor(prng_state->binomial->fm); - prng_state->binomial->p1 = p1 = + binomial->nsave = n; + binomial->psave = p; + binomial->has_binomial = 1; + binomial->r = r = min(p, 1.0 - p); + binomial->q = q = 1.0 - r; + binomial->fm = fm = n * r + r; + binomial->m = m = (long)floor(binomial->fm); + binomial->p1 = p1 = floor(2.195 * sqrt(n * r * q) - 4.6 * q) + 0.5; - prng_state->binomial->xm = xm = m + 0.5; - prng_state->binomial->xl = xl = xm - p1; - prng_state->binomial->xr = xr = xm + p1; - prng_state->binomial->c = c = 0.134 + 20.5 / (15.3 + m); + binomial->xm = xm = m + 0.5; + binomial->xl = xl = xm - p1; + binomial->xr = xr = xm + p1; + binomial->c = c = 0.134 + 20.5 / (15.3 + m); a = (fm - xl) / (fm - xl * r); - prng_state->binomial->laml = laml = a * (1.0 + a / 2.0); + binomial->laml = laml = a * (1.0 + a / 2.0); a = (xr - fm) / (xr * q); - prng_state->binomial->lamr = lamr = a * (1.0 + a / 2.0); - prng_state->binomial->p2 = p2 = p1 * (1.0 + 2.0 * c); - prng_state->binomial->p3 = p3 = p2 + c / laml; - prng_state->binomial->p4 = p4 = p3 + c / lamr; + binomial->lamr = lamr = a * (1.0 + a / 2.0); + binomial->p2 = p2 = p1 * (1.0 + 2.0 * c); + binomial->p3 = p3 = p2 + c / laml; + binomial->p4 = p4 = p3 + c / lamr; } else { - r = prng_state->binomial->r; - q = prng_state->binomial->q; - fm = prng_state->binomial->fm; - m = prng_state->binomial->m; - p1 = prng_state->binomial->p1; - xm = prng_state->binomial->xm; - xl = prng_state->binomial->xl; - xr = prng_state->binomial->xr; - c = prng_state->binomial->c; - laml = prng_state->binomial->laml; - lamr = prng_state->binomial->lamr; - p2 = prng_state->binomial->p2; - p3 = prng_state->binomial->p3; - p4 = prng_state->binomial->p4; + r = binomial->r; + q = binomial->q; + fm = binomial->fm; + m = binomial->m; + p1 = binomial->p1; + xm = binomial->xm; + xl = binomial->xl; + xr = binomial->xr; + c = binomial->c; + laml = binomial->laml; + lamr = binomial->lamr; + p2 = binomial->p2; + p3 = binomial->p3; + p4 = binomial->p4; } /* sigh ... */ @@ -794,26 +794,26 @@ long random_binomial_btpe(prng_t *prng_state, long n, double p) { return y; } -long random_binomial_inversion(prng_t *prng_state, long n, double p) { +long random_binomial_inversion(prng_t *prng_state, long n, double p, binomial_t* binomial) { double q, qn, np, px, U; long X, bound; - if (!(prng_state->binomial->has_binomial) || - (prng_state->binomial->nsave != n) || - (prng_state->binomial->psave != p)) { - prng_state->binomial->nsave = n; - prng_state->binomial->psave = p; - prng_state->binomial->has_binomial = 1; - prng_state->binomial->q = q = 1.0 - p; - prng_state->binomial->r = qn = exp(n * log(q)); - prng_state->binomial->c = np = n * p; - prng_state->binomial->m = bound = + if (!(binomial->has_binomial) || + (binomial->nsave != n) || + (binomial->psave != p)) { + binomial->nsave = n; + binomial->psave = p; + binomial->has_binomial = 1; + binomial->q = q = 1.0 - p; + binomial->r = qn = exp(n * log(q)); + binomial->c = np = n * p; + binomial->m = bound = (long)min(n, np + 10.0 * sqrt(np * q + 1)); } else { - q = prng_state->binomial->q; - qn = prng_state->binomial->r; - np = prng_state->binomial->c; - bound = prng_state->binomial->m; + q = binomial->q; + qn = binomial->r; + np = binomial->c; + bound = binomial->m; } X = 0; px = qn; @@ -832,21 +832,21 @@ long random_binomial_inversion(prng_t *prng_state, long n, double p) { return X; } -long random_binomial(prng_t *prng_state, double p, long n) { +long random_binomial(prng_t *prng_state, double p, long n, binomial_t * binomial) { double q; if (p <= 0.5) { if (p * n <= 30.0) { - return random_binomial_inversion(prng_state, n, p); + return random_binomial_inversion(prng_state, n, p, binomial); } else { - return random_binomial_btpe(prng_state, n, p); + return random_binomial_btpe(prng_state, n, p, binomial); } } else { q = 1.0 - p; if (q * n <= 30.0) { - return n - random_binomial_inversion(prng_state, n, q); + return n - random_binomial_inversion(prng_state, n, q, binomial); } else { - return n - random_binomial_btpe(prng_state, n, q); + return n - random_binomial_btpe(prng_state, n, q, binomial); } } } diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index 95e839cb0967..9b1a70e9e1fc 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -59,7 +59,6 @@ typedef struct prng { uint32_t (*next_uint32)(void *st); double (*next_double)(void *st); uint64_t (*next_raw)(void *st); - binomial_t *binomial; } prng_t; /* Inline generators for internal use */ @@ -140,7 +139,7 @@ DECLDIR double random_triangular(prng_t *prng_state, double left, double mode, DECLDIR long random_poisson(prng_t *prng_state, double lam); DECLDIR long random_negative_binomial(prng_t *prng_state, double n, double p); -DECLDIR long random_binomial(prng_t *prng_state, double p, long n); +DECLDIR long random_binomial(prng_t *prng_state, double p, long n, binomial_t* binomial); DECLDIR long random_logseries(prng_t *prng_state, double p); DECLDIR long random_geometric_search(prng_t *prng_state, double p); DECLDIR long random_geometric_inversion(prng_t *prng_state, double p); diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index 961d2f3be995..197fe4aaa703 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -4,7 +4,7 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np from common cimport * -from distributions cimport prng_t, binomial_t +from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy @@ -70,7 +70,6 @@ cdef class ThreeFry: self.rng_state.ctr = malloc(sizeof(threefry4x64_ctr_t)) self.rng_state.key = malloc(sizeof(threefry4x64_key_t)) self._prng = malloc(sizeof(prng_t)) - self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed, counter, key) self._prng.state = self.rng_state @@ -98,7 +97,6 @@ cdef class ThreeFry: free(self.rng_state.ctr) free(self.rng_state.key) free(self.rng_state) - free(self._prng.binomial) free(self._prng) cdef _reset_state_variables(self): diff --git a/_randomgen/core_prng/threefry32.pyx b/_randomgen/core_prng/threefry32.pyx index a001d30c705a..ef31bfb1b328 100644 --- a/_randomgen/core_prng/threefry32.pyx +++ b/_randomgen/core_prng/threefry32.pyx @@ -4,7 +4,7 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np from common cimport * -from distributions cimport prng_t, binomial_t +from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy @@ -73,7 +73,6 @@ cdef class ThreeFry32: self.rng_state.ctr = malloc(sizeof(threefry4x32_ctr_t)) self.rng_state.key = malloc(sizeof(threefry4x32_key_t)) self._prng = malloc(sizeof(prng_t)) - self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed, counter, key) self._prng.state = self.rng_state @@ -101,7 +100,6 @@ cdef class ThreeFry32: free(self.rng_state.ctr) free(self.rng_state.key) free(self.rng_state) - free(self._prng.binomial) free(self._prng) cdef _reset_state_variables(self): diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index ba727924d6c8..0301c0ea20f3 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -9,7 +9,7 @@ import numpy as np cimport numpy as np from common cimport * -from distributions cimport prng_t, binomial_t +from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy @@ -55,13 +55,12 @@ cdef class Xoroshiro128: cdef xoroshiro128_state *rng_state cdef prng_t *_prng cdef public object capsule - cdef object ctypes - cdef object cffi + cdef object _ctypes + cdef object _cffi def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoroshiro128_state)) self._prng = malloc(sizeof(prng_t)) - self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed) self._prng.state = self.rng_state @@ -70,8 +69,8 @@ cdef class Xoroshiro128: self._prng.next_double = &xoroshiro128_double self._prng.next_raw = &xoroshiro128_uint64 - self.ctypes = None - self.cffi = None + self._ctypes = None + self._cffi = None cdef const char *name = "CorePRNG" self.capsule = PyCapsule_New(self._prng, name, NULL) @@ -90,7 +89,6 @@ cdef class Xoroshiro128: def __dealloc__(self): free(self.rng_state) - free(self._prng.binomial) free(self._prng) cdef _reset_state_variables(self): @@ -197,12 +195,12 @@ cdef class Xoroshiro128: @property def ctypes(self): - if self.ctypes is not None: - return self.ctypes + if self._ctypes is not None: + return self._ctypes import ctypes - self.ctypes = interface(self.rng_state, + self._ctypes = interface(self.rng_state, ctypes.c_void_p(self.rng_state), ctypes.cast(&xoroshiro128_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, @@ -218,15 +216,15 @@ cdef class Xoroshiro128: @property def cffi(self): - if self.cffi is not None: - return self.cffi + if self._cffi is not None: + return self._cffi try: import cffi except ImportError: raise ImportError('cffi is cannot be imported.') ffi = cffi.FFI() - self.cffi = interface(self.rng_state, + self._cffi = interface(self.rng_state, ffi.cast('void *',self.rng_state), ffi.cast('uint64_t (*)(void *)',self._prng.next_uint64), ffi.cast('uint32_t (*)(void *)',self._prng.next_uint32), diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index 7fd4d73bafe5..73fa052850bb 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -5,7 +5,7 @@ import numpy as np cimport numpy as np from common cimport * -from distributions cimport prng_t, binomial_t +from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle cimport entropy @@ -56,7 +56,6 @@ cdef class Xorshift1024: def __init__(self, seed=None): self.rng_state = malloc(sizeof(xorshift1024_state)) self._prng = malloc(sizeof(prng_t)) - self._prng.binomial = malloc(sizeof(binomial_t)) self.seed(seed) self._prng.state = self.rng_state @@ -82,7 +81,6 @@ cdef class Xorshift1024: def __dealloc__(self): free(self.rng_state) - free(self._prng.binomial) free(self._prng) cdef _reset_state_variables(self): From 00bf69fb47679fe50c8b771a249f33fce4b96aaf Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 13 Mar 2018 12:25:07 +0000 Subject: [PATCH 074/279] ENH: Switch to int64 Switch to int64 to avoid platform-dependencies for integer values randoms --- _randomgen/README.md | 1 + _randomgen/TODO.md | 27 ---- _randomgen/core_prng/common.pxd | 14 +- _randomgen/core_prng/common.pyx | 102 ++++++------- _randomgen/core_prng/distributions.pxd | 30 ++-- _randomgen/core_prng/generator.pyx | 54 ++++--- .../src/distributions/distributions.c | 134 ++++++++---------- .../src/distributions/distributions.h | 45 ++++-- .../core_prng/tests/test_numpy_mt19937.py | 9 +- _randomgen/demo.py | 103 -------------- 10 files changed, 196 insertions(+), 323 deletions(-) delete mode 100644 _randomgen/TODO.md delete mode 100644 _randomgen/demo.py diff --git a/_randomgen/README.md b/_randomgen/README.md index 213a6cf4b1f6..19f216b3eaf4 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -96,6 +96,7 @@ The RNGs include: the optional keyword argument `dtype` * Core random number generators can fill existing arrays using the `out` keyword argument +* Standardizes integer-values random values as int64 for all platforms. ### New Functions diff --git a/_randomgen/TODO.md b/_randomgen/TODO.md deleted file mode 100644 index ed2697d9e826..000000000000 --- a/_randomgen/TODO.md +++ /dev/null @@ -1,27 +0,0 @@ -# TODO -13. Simplify state - -## Done -1. Add PCG64 -2. Add dSFMT -3. Add xorshift2014 -4. Augment state to include has_gauss and gauss -5. Augment state to have binomial structure -6. Port over 0 parameter distributions - * standard normal ziggurat - * standard normal ziggurat float - * standard exponential ziggurat - * standard exponential ziggurat float - * standard exponential float - * standard normal - * standard normal float - * standard gamma - Not implement: This is a 1 param - * standard gamma float - Not implement: This is a 1 param -7. Remove SplitMix64 as an external generator -8. Restore ability to use `out` in core distributions -9. Add correct carry for ThreeFry to allow full set of counters. Important when implemeting jump -10. Seed/Inc for PCG64 -11. Advance/Jump for PCG64 -12. Key/Counter for ThreeFry -0. **NOT IMPLEMENTABLE** due to limits on inheritance in Cython: Use inheritance to simplify CorePRNG structure. The natural base is - xoroshiro128. diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index c571c57a2950..66d961edc4ef 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -38,12 +38,12 @@ ctypedef double (*random_double_3)(prng_t *state, double a, double b, double c) ctypedef float (*random_float_0)(prng_t *state) nogil ctypedef float (*random_float_1)(prng_t *state, float a) nogil -ctypedef long (*random_uint_0)(prng_t *state) nogil -ctypedef long (*random_uint_d)(prng_t *state, double a) nogil -ctypedef long (*random_uint_dd)(prng_t *state, double a, double b) nogil -ctypedef long (*random_uint_di)(prng_t *state, double a, uint64_t b) nogil -ctypedef long (*random_uint_i)(prng_t *state, long a) nogil -ctypedef long (*random_uint_iii)(prng_t *state, long a, long b, long c) nogil +ctypedef int64_t (*random_uint_0)(prng_t *state) nogil +ctypedef int64_t (*random_uint_d)(prng_t *state, double a) nogil +ctypedef int64_t (*random_uint_dd)(prng_t *state, double a, double b) nogil +ctypedef int64_t (*random_uint_di)(prng_t *state, double a, uint64_t b) nogil +ctypedef int64_t (*random_uint_i)(prng_t *state, int64_t a) nogil +ctypedef int64_t (*random_uint_iii)(prng_t *state, int64_t a, int64_t b, int64_t c) nogil ctypedef uint32_t (*random_uint_0_32)(prng_t *state) nogil ctypedef uint32_t (*random_uint_1_i_32)(prng_t *state, uint32_t a) nogil @@ -71,7 +71,7 @@ cdef object cont(void *func, prng_t *state, object size, object lock, int narg, object out) cdef object disc(void *func, prng_t *state, object size, object lock, - int narg_double, int narg_long, + int narg_double, int narg_int64, object a, object a_name, constraint_type a_constraint, object b, object b_name, constraint_type b_constraint, object c, object c_name, constraint_type c_constraint) diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index fb3e96697bae..b25510e1a955 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -407,7 +407,7 @@ cdef object discrete_broadcast_d(void *func, prng_t *state, object size, object np.ndarray a_arr, object a_name, constraint_type a_constraint): cdef np.ndarray randoms - cdef long *randoms_data + cdef int64_t *randoms_data cdef np.broadcast it cdef random_uint_d f = (func) cdef np.npy_intp i, n @@ -416,12 +416,12 @@ cdef object discrete_broadcast_d(void *func, prng_t *state, object size, object check_array_constraint(a_arr, a_name, a_constraint) if size is not None: - randoms = np.empty(size, np.int) + randoms = np.empty(size, np.int64) else: #randoms = np.empty(np.shape(a_arr), np.double) - randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_LONG) + randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_INT64) - randoms_data = np.PyArray_DATA(randoms) + randoms_data = np.PyArray_DATA(randoms) n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew2(randoms, a_arr) @@ -438,7 +438,7 @@ cdef object discrete_broadcast_dd(void *func, prng_t *state, object size, object np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint): cdef np.ndarray randoms - cdef long *randoms_data + cdef int64_t *randoms_data cdef np.broadcast it cdef random_uint_dd f = (func) cdef np.npy_intp i, n @@ -449,13 +449,13 @@ cdef object discrete_broadcast_dd(void *func, prng_t *state, object size, object check_array_constraint(b_arr, b_name, b_constraint) if size is not None: - randoms = np.empty(size, np.int) + randoms = np.empty(size, np.int64) else: it = np.PyArray_MultiIterNew2(a_arr, b_arr) - randoms = np.empty(it.shape, np.int) - # randoms = np.PyArray_SimpleNew(it.nd, np.PyArray_DIMS(it), np.NPY_LONG) + randoms = np.empty(it.shape, np.int64) + # randoms = np.PyArray_SimpleNew(it.nd, np.PyArray_DIMS(it), np.NPY_INT64) - randoms_data = np.PyArray_DATA(randoms) + randoms_data = np.PyArray_DATA(randoms) n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr) @@ -473,7 +473,7 @@ cdef object discrete_broadcast_di(void *func, prng_t *state, object size, object np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint): cdef np.ndarray randoms - cdef long *randoms_data + cdef int64_t *randoms_data cdef np.broadcast it cdef random_uint_di f = (func) cdef np.npy_intp i, n @@ -486,20 +486,20 @@ cdef object discrete_broadcast_di(void *func, prng_t *state, object size, object check_array_constraint(b_arr, b_name, b_constraint) if size is not None: - randoms = np.empty(size, np.int) + randoms = np.empty(size, np.int64) else: it = np.PyArray_MultiIterNew2(a_arr, b_arr) - randoms = np.empty(it.shape, np.int) + randoms = np.empty(it.shape, np.int64) - randoms_data = np.PyArray_DATA(randoms) + randoms_data = np.PyArray_DATA(randoms) n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr) with lock, nogil: for i in range(n): a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] - b_val = (np.PyArray_MultiIter_DATA(it, 2))[0] - (np.PyArray_MultiIter_DATA(it, 0))[0] = f(state, a_val, b_val) + b_val = (np.PyArray_MultiIter_DATA(it, 2))[0] + (np.PyArray_MultiIter_DATA(it, 0))[0] = f(state, a_val, b_val) np.PyArray_MultiIter_NEXT(it) @@ -510,7 +510,7 @@ cdef object discrete_broadcast_iii(void *func, prng_t *state, object size, objec np.ndarray b_arr, object b_name, constraint_type b_constraint, np.ndarray c_arr, object c_name, constraint_type c_constraint): cdef np.ndarray randoms - cdef long *randoms_data + cdef int64_t *randoms_data cdef np.broadcast it cdef random_uint_iii f = (func) cdef np.npy_intp i, n @@ -525,20 +525,20 @@ cdef object discrete_broadcast_iii(void *func, prng_t *state, object size, objec check_array_constraint(c_arr, c_name, c_constraint) if size is not None: - randoms = np.empty(size, np.int) + randoms = np.empty(size, np.int64) else: it = np.PyArray_MultiIterNew3(a_arr, b_arr, c_arr) - randoms = np.empty(it.shape, np.int) + randoms = np.empty(it.shape, np.int64) - randoms_data = np.PyArray_DATA(randoms) + randoms_data = np.PyArray_DATA(randoms) n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew4(randoms, a_arr, b_arr, c_arr) with lock, nogil: for i in range(n): - a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] - b_val = (np.PyArray_MultiIter_DATA(it, 2))[0] - c_val = (np.PyArray_MultiIter_DATA(it, 3))[0] + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + b_val = (np.PyArray_MultiIter_DATA(it, 2))[0] + c_val = (np.PyArray_MultiIter_DATA(it, 3))[0] randoms_data[i] = f(state, a_val, b_val, c_val) np.PyArray_MultiIter_NEXT(it) @@ -548,7 +548,7 @@ cdef object discrete_broadcast_iii(void *func, prng_t *state, object size, objec cdef object discrete_broadcast_i(void *func, prng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint): cdef np.ndarray randoms - cdef long *randoms_data + cdef int64_t *randoms_data cdef np.broadcast it cdef random_uint_i f = (func) cdef np.npy_intp i, n @@ -557,32 +557,32 @@ cdef object discrete_broadcast_i(void *func, prng_t *state, object size, object check_array_constraint(a_arr, a_name, a_constraint) if size is not None: - randoms = np.empty(size, np.int) + randoms = np.empty(size, np.int64) else: - randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_LONG) + randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_INT64) - randoms_data = np.PyArray_DATA(randoms) + randoms_data = np.PyArray_DATA(randoms) n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew2(randoms, a_arr) with lock, nogil: for i in range(n): - a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] + a_val = (np.PyArray_MultiIter_DATA(it, 1))[0] randoms_data[i] = f(state, a_val) np.PyArray_MultiIter_NEXT(it) return randoms -# Needs double , double-double , double-long, long , long-long-long +# Needs double , double-double , double-int64_t, int64_t , int64_t-int64_t-int64_t cdef object disc(void *func, prng_t *state, object size, object lock, - int narg_double, int narg_long, + int narg_double, int narg_int64, object a, object a_name, constraint_type a_constraint, object b, object b_name, constraint_type b_constraint, object c, object c_name, constraint_type c_constraint): cdef double _da = 0, _db = 0 - cdef long _ia = 0, _ib = 0 , _ic = 0 + cdef int64_t _ia = 0, _ib = 0 , _ic = 0 cdef bint is_scalar = True if narg_double > 0: a_arr = np.PyArray_FROM_OTF(a, np.NPY_DOUBLE, np.NPY_ALIGNED) @@ -590,22 +590,22 @@ cdef object disc(void *func, prng_t *state, object size, object lock, if narg_double > 1: b_arr = np.PyArray_FROM_OTF(b, np.NPY_DOUBLE, np.NPY_ALIGNED) is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0 - elif narg_long == 1: - b_arr = np.PyArray_FROM_OTF(b, np.NPY_LONG, np.NPY_ALIGNED) + elif narg_int64 == 1: + b_arr = np.PyArray_FROM_OTF(b, np.NPY_INT64, np.NPY_ALIGNED) is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0 else: - if narg_long > 0: - a_arr = np.PyArray_FROM_OTF(a, np.NPY_LONG, np.NPY_ALIGNED) + if narg_int64 > 0: + a_arr = np.PyArray_FROM_OTF(a, np.NPY_INT64, np.NPY_ALIGNED) is_scalar = is_scalar and np.PyArray_NDIM(a_arr) == 0 - if narg_long > 1: - b_arr = np.PyArray_FROM_OTF(b, np.NPY_LONG, np.NPY_ALIGNED) + if narg_int64 > 1: + b_arr = np.PyArray_FROM_OTF(b, np.NPY_INT64, np.NPY_ALIGNED) is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0 - if narg_long > 2 : - c_arr = np.PyArray_FROM_OTF(c, np.NPY_LONG, np.NPY_ALIGNED) + if narg_int64 > 2 : + c_arr = np.PyArray_FROM_OTF(c, np.NPY_INT64, np.NPY_ALIGNED) is_scalar = is_scalar and np.PyArray_NDIM(c_arr) == 0 if not is_scalar: - if narg_long == 0: + if narg_int64 == 0: if narg_double == 1: return discrete_broadcast_d(func, state, size, lock, a_arr, a_name, a_constraint) @@ -613,7 +613,7 @@ cdef object disc(void *func, prng_t *state, object size, object lock, return discrete_broadcast_dd(func, state, size, lock, a_arr, a_name, a_constraint, b_arr, b_name, b_constraint) - elif narg_long == 1: + elif narg_int64 == 1: if narg_double == 0: return discrete_broadcast_i(func, state, size, lock, a_arr, a_name, a_constraint) @@ -634,34 +634,34 @@ cdef object disc(void *func, prng_t *state, object size, object lock, _db = PyFloat_AsDouble(b) if b_constraint != CONS_NONE and is_scalar: check_constraint(_db, b_name, b_constraint) - elif narg_long == 1: + elif narg_int64 == 1: _ib = PyInt_AsLong(b) if b_constraint != CONS_NONE and is_scalar: check_constraint(_ib, b_name, b_constraint) else: - if narg_long > 0: + if narg_int64 > 0: _ia = PyInt_AsLong(a) if a_constraint != CONS_NONE and is_scalar: check_constraint(_ia, a_name, a_constraint) - if narg_long > 1: + if narg_int64 > 1: _ib = PyInt_AsLong(b) if b_constraint != CONS_NONE and is_scalar: check_constraint(_ib, b_name, b_constraint) - if narg_long > 2 : + if narg_int64 > 2 : _ic = PyInt_AsLong(c) if c_constraint != CONS_NONE and is_scalar: check_constraint(_ic, c_name, c_constraint) if size is None: with lock: - if narg_long == 0: + if narg_int64 == 0: if narg_double == 0: return (func)(state) elif narg_double == 1: return (func)(state, _da) elif narg_double == 2: return (func)(state, _da, _db) - elif narg_long == 1: + elif narg_int64 == 1: if narg_double == 0: return (func)(state, _ia) if narg_double == 1: @@ -670,8 +670,8 @@ cdef object disc(void *func, prng_t *state, object size, object lock, return (func)(state, _ia, _ib, _ic) cdef np.npy_intp i, n - cdef np.ndarray randoms = np.empty(size, np.int) - cdef np.int_t *randoms_data + cdef np.ndarray randoms = np.empty(size, np.int64) + cdef np.int64_t *randoms_data cdef random_uint_0 f0; cdef random_uint_d fd; cdef random_uint_dd fdd; @@ -680,10 +680,10 @@ cdef object disc(void *func, prng_t *state, object size, object lock, cdef random_uint_iii fiii; n = np.PyArray_SIZE(randoms) - randoms_data = np.PyArray_DATA(randoms) + randoms_data = np.PyArray_DATA(randoms) with lock, nogil: - if narg_long == 0: + if narg_int64 == 0: if narg_double == 0: f0 = (func) for i in range(n): @@ -696,7 +696,7 @@ cdef object disc(void *func, prng_t *state, object size, object lock, fdd = (func) for i in range(n): randoms_data[i] = fdd(state, _da, _db) - elif narg_long == 1: + elif narg_int64 == 1: if narg_double == 0: fi = (func) for i in range(n): diff --git a/_randomgen/core_prng/distributions.pxd b/_randomgen/core_prng/distributions.pxd index 29dc5f114fa3..44f3520690ef 100644 --- a/_randomgen/core_prng/distributions.pxd +++ b/_randomgen/core_prng/distributions.pxd @@ -8,11 +8,11 @@ cdef extern from "src/distributions/distributions.h": struct s_binomial_t: int has_binomial double psave - long nsave + int64_t nsave double r double q double fm - long m + int64_t m double p1 double xm double xl @@ -50,8 +50,8 @@ cdef extern from "src/distributions/distributions.h": int64_t random_positive_int64(prng_t *prng_state) nogil int32_t random_positive_int32(prng_t *prng_state) nogil - long random_positive_int(prng_t *prng_state) nogil - unsigned long random_uint(prng_t *prng_state) nogil + int64_t random_positive_int(prng_t *prng_state) nogil + uint64_t random_uint(prng_t *prng_state) nogil double random_normal_zig(prng_t *prng_state, double loc, double scale) nogil @@ -82,17 +82,17 @@ cdef extern from "src/distributions/distributions.h": double random_triangular(prng_t *prng_state, double left, double mode, double right) nogil - long random_poisson(prng_t *prng_state, double lam) nogil - long random_negative_binomial(prng_t *prng_state, double n, double p) nogil - long random_binomial(prng_t *prng_state, double p, long n, binomial_t *binomial) nogil - long random_logseries(prng_t *prng_state, double p) nogil - long random_geometric_search(prng_t *prng_state, double p) nogil - long random_geometric_inversion(prng_t *prng_state, double p) nogil - long random_geometric(prng_t *prng_state, double p) nogil - long random_zipf(prng_t *prng_state, double a) nogil - long random_hypergeometric(prng_t *prng_state, long good, long bad, - long sample) nogil - unsigned long random_interval(prng_t *prng_state, unsigned long max) nogil + int64_t random_poisson(prng_t *prng_state, double lam) nogil + int64_t random_negative_binomial(prng_t *prng_state, double n, double p) nogil + int64_t random_binomial(prng_t *prng_state, double p, int64_t n, binomial_t *binomial) nogil + int64_t random_logseries(prng_t *prng_state, double p) nogil + int64_t random_geometric_search(prng_t *prng_state, double p) nogil + int64_t random_geometric_inversion(prng_t *prng_state, double p) nogil + int64_t random_geometric(prng_t *prng_state, double p) nogil + int64_t random_zipf(prng_t *prng_state, double a) nogil + int64_t random_hypergeometric(prng_t *prng_state, int64_t good, int64_t bad, + int64_t sample) nogil + uint64_t random_interval(prng_t *prng_state, uint64_t max) nogil uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, uint64_t rng, uint64_t mask) nogil uint32_t random_buffered_bounded_uint32(prng_t *prng_state, uint32_t off, diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index 51cdebc19550..ec52a1839f0b 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -487,14 +487,14 @@ cdef class RandomGenerator: """ cdef np.npy_intp n cdef np.ndarray randoms - cdef long *randoms_data + cdef int64_t *randoms_data if size is None: with self.lock: return random_positive_int(self._prng) - randoms = np.empty(size, dtype=np.int) - randoms_data = np.PyArray_DATA(randoms) + randoms = np.empty(size, dtype=np.int64) + randoms_data = np.PyArray_DATA(randoms) n = np.PyArray_SIZE(randoms) for i in range(n): @@ -776,7 +776,7 @@ cdef class RandomGenerator: raise ValueError("Fewer non-zero entries in p than size") n_uniq = 0 p = p.copy() - found = np.zeros(shape, dtype=np.int) + found = np.zeros(shape, dtype=np.int64) flat_found = found.ravel() while n_uniq < size: x = self.rand(size - n_uniq) @@ -1039,13 +1039,11 @@ cdef class RandomGenerator: """ random_integers(low, high=None, size=None) - Random integers of type np.int between `low` and `high`, inclusive. + Random integers of type np.int64 between `low` and `high`, inclusive. - Return random integers of type np.int from the "discrete uniform" + Return random integers of type np.int64 from the "discrete uniform" distribution in the closed interval [`low`, `high`]. If `high` is - None (the default), then results are from [1, `low`]. The np.int - type translates to the C long type used by Python 2 for "short" - integers and its precision is platform dependent. + None (the default), then results are from [1, `low`]. This function has been deprecated. Use randint instead. @@ -1418,7 +1416,7 @@ cdef class RandomGenerator: it = np.PyArray_MultiIterNew5(randoms, oloc, v_real, v_imag, rho) with self.lock, nogil: - n2 = 2 * n # Avoid compiler noise for cast to long + n2 = 2 * n # Avoid compiler noise for cast for i in range(n2): randoms_data[i] = random_gauss_zig(self._prng) with nogil: @@ -3166,36 +3164,36 @@ cdef class RandomGenerator: # Uses a custom implementation since self._binomial is required cdef double _dp = 0 - cdef long _in = 0 + cdef int64_t _in = 0 cdef bint is_scalar = True cdef np.npy_intp i, cnt cdef np.ndarray randoms - cdef np.int_t *randoms_data + cdef np.int64_t *randoms_data cdef np.broadcast it p_arr = np.PyArray_FROM_OTF(p, np.NPY_DOUBLE, np.NPY_ALIGNED) is_scalar = is_scalar and np.PyArray_NDIM(p_arr) == 0 - n_arr = np.PyArray_FROM_OTF(n, np.NPY_LONG, np.NPY_ALIGNED) + n_arr = np.PyArray_FROM_OTF(n, np.NPY_INT64, np.NPY_ALIGNED) is_scalar = is_scalar and np.PyArray_NDIM(n_arr) == 0 if not is_scalar: check_array_constraint(p_arr, 'p', CONS_BOUNDED_0_1_NOTNAN) check_array_constraint(n_arr, 'n', CONS_NON_NEGATIVE) if size is not None: - randoms = np.empty(size, np.int) + randoms = np.empty(size, np.int64) else: it = np.PyArray_MultiIterNew2(p_arr, n_arr) - randoms = np.empty(it.shape, np.int) + randoms = np.empty(it.shape, np.int64) - randoms_data = np.PyArray_DATA(randoms) + randoms_data = np.PyArray_DATA(randoms) cnt = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew3(randoms, p_arr, n_arr) with self.lock, nogil: for i in range(cnt): _dp = (np.PyArray_MultiIter_DATA(it, 1))[0] - _in = (np.PyArray_MultiIter_DATA(it, 2))[0] - (np.PyArray_MultiIter_DATA(it, 0))[0] = random_binomial(self._prng, _dp, _in, self._binomial) + _in = (np.PyArray_MultiIter_DATA(it, 2))[0] + (np.PyArray_MultiIter_DATA(it, 0))[0] = random_binomial(self._prng, _dp, _in, self._binomial) np.PyArray_MultiIter_NEXT(it) @@ -3210,9 +3208,9 @@ cdef class RandomGenerator: with self.lock: return random_binomial(self._prng, _dp, _in, self._binomial) - randoms = np.empty(size, np.int) + randoms = np.empty(size, np.int64) cnt = np.PyArray_SIZE(randoms) - randoms_data = np.PyArray_DATA(randoms) + randoms_data = np.PyArray_DATA(randoms) with self.lock, nogil: for i in range(cnt): @@ -3334,7 +3332,7 @@ cdef class RandomGenerator: :math:`k` events occurring within the observed interval :math:`\\lambda`. - Because the output is limited to the range of the C long type, a + Because the output is limited to the range of the C int64 type, a ValueError is raised when `lam` is within 10 sigma of the maximum representable value. @@ -3589,11 +3587,11 @@ cdef class RandomGenerator: """ cdef bint is_scalar = True cdef np.ndarray ongood, onbad, onsample - cdef long lngood, lnbad, lnsample + cdef int64_t lngood, lnbad, lnsample - ongood = np.PyArray_FROM_OTF(ngood, np.NPY_LONG, np.NPY_ALIGNED) - onbad = np.PyArray_FROM_OTF(nbad, np.NPY_LONG, np.NPY_ALIGNED) - onsample = np.PyArray_FROM_OTF(nsample, np.NPY_LONG, np.NPY_ALIGNED) + ongood = np.PyArray_FROM_OTF(ngood, np.NPY_INT64, np.NPY_ALIGNED) + onbad = np.PyArray_FROM_OTF(nbad, np.NPY_INT64, np.NPY_ALIGNED) + onsample = np.PyArray_FROM_OTF(nsample, np.NPY_INT64, np.NPY_ALIGNED) if np.PyArray_NDIM(ongood) == np.PyArray_NDIM(onbad) == np.PyArray_NDIM(onsample) == 0: @@ -3941,7 +3939,7 @@ cdef class RandomGenerator: cdef np.npy_intp d, i, j, dn, sz cdef np.ndarray parr "arrayObject_parr", mnarr "arrayObject_mnarr" cdef double *pix - cdef long *mnix + cdef int64_t *mnix cdef double Sum d = len(pvals) @@ -3959,9 +3957,9 @@ cdef class RandomGenerator: except: shape = tuple(size) + (d,) - multin = np.zeros(shape, dtype=np.int) + multin = np.zeros(shape, dtype=np.int64) mnarr = multin - mnix = np.PyArray_DATA(mnarr) + mnix = np.PyArray_DATA(mnarr) sz = np.PyArray_SIZE(mnarr) with self.lock, nogil: diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/core_prng/src/distributions/distributions.c index 3dd83e66d38a..daed964ecc09 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/core_prng/src/distributions/distributions.c @@ -3,13 +3,9 @@ #include "ziggurat_constants.h" /* Random generators for external use */ -float random_sample_f(prng_t *prng_state) { - return random_float(prng_state); -} +float random_sample_f(prng_t *prng_state) { return random_float(prng_state); } -double random_sample(prng_t *prng_state) { - return random_double(prng_state); -} +double random_sample(prng_t *prng_state) { return random_double(prng_state); } double random_standard_exponential(prng_t *prng_state) { return -log(1.0 - random_double(prng_state)); @@ -75,8 +71,7 @@ static double standard_exponential_zig_unlikely(prng_t *prng_state, uint8_t idx, double x) { if (idx == 0) { return ziggurat_exp_r - log(random_double(prng_state)); - } else if ((fe_double[idx - 1] - fe_double[idx]) * - random_double(prng_state) + + } else if ((fe_double[idx - 1] - fe_double[idx]) * random_double(prng_state) + fe_double[idx] < exp(-x)) { return x; @@ -158,16 +153,14 @@ double random_gauss_zig(prng_t *prng_state) { return x; // # 99.3% of the time return here if (idx == 0) { for (;;) { - xx = -ziggurat_nor_inv_r * - log(random_double(prng_state)); + xx = -ziggurat_nor_inv_r * log(random_double(prng_state)); yy = -log(random_double(prng_state)); if (yy + yy > xx * xx) return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r + xx) : ziggurat_nor_r + xx; } } else { - if (((fi_double[idx - 1] - fi_double[idx]) * - random_double(prng_state) + + if (((fi_double[idx - 1] - fi_double[idx]) * random_double(prng_state) + fi_double[idx]) < exp(-0.5 * x * x)) return x; } @@ -402,15 +395,15 @@ int32_t random_positive_int32(prng_t *prng_state) { return random_uint32(prng_state) >> 1; } -long random_positive_int(prng_t *prng_state) { +int64_t random_positive_int(prng_t *prng_state) { #if ULONG_MAX <= 0xffffffffUL - return (long)(random_uint32(prng_state) >> 1); + return (int64_t)(random_uint32(prng_state) >> 1); #else - return (long)(random_uint64(prng_state) >> 1); + return (int64_t)(random_uint64(prng_state) >> 1); #endif } -unsigned long random_uint(prng_t *prng_state) { +uint64_t random_uint(prng_t *prng_state) { #if ULONG_MAX <= 0xffffffffUL return random_uint32(prng_state); #else @@ -425,7 +418,7 @@ unsigned long random_uint(prng_t *prng_state) { */ static double loggam(double x) { double x0, x2, xp, gl, gl0; - long k, n; + int64_t k, n; static double a[10] = {8.333333333333333e-02, -2.777777777777778e-03, 7.936507936507937e-04, -5.952380952380952e-04, @@ -437,7 +430,7 @@ static double loggam(double x) { if ((x == 1.0) || (x == 2.0)) { return 0.0; } else if (x <= 7.0) { - n = (long)(7 - x); + n = (int64_t)(7 - x); x0 = x + n; } x2 = 1.0 / (x0 * x0); @@ -584,8 +577,8 @@ double random_standard_t(prng_t *prng_state, double df) { return sqrt(df / 2) * num / sqrt(denom); } -static long random_poisson_mult(prng_t *prng_state, double lam) { - long X; +static int64_t random_poisson_mult(prng_t *prng_state, double lam) { + int64_t X; double prod, U, enlam; enlam = exp(-lam); @@ -609,8 +602,8 @@ static long random_poisson_mult(prng_t *prng_state, double lam) { */ #define LS2PI 0.91893853320467267 #define TWELFTH 0.083333333333333333333333 -static long random_poisson_ptrs(prng_t *prng_state, double lam) { - long k; +static int64_t random_poisson_ptrs(prng_t *prng_state, double lam) { + int64_t k; double U, V, slam, loglam, a, b, invalpha, vr, us; slam = sqrt(lam); @@ -624,7 +617,7 @@ static long random_poisson_ptrs(prng_t *prng_state, double lam) { U = random_sample(prng_state) - 0.5; V = random_sample(prng_state); us = 0.5 - fabs(U); - k = (long)floor((2 * a / us + b) * U + lam + 0.43); + k = (int64_t)floor((2 * a / us + b) * U + lam + 0.43); if ((us >= 0.07) && (V <= vr)) { return k; } @@ -638,7 +631,7 @@ static long random_poisson_ptrs(prng_t *prng_state, double lam) { } } -long random_poisson(prng_t *prng_state, double lam) { +int64_t random_poisson(prng_t *prng_state, double lam) { if (lam >= 10) { return random_poisson_ptrs(prng_state, lam); } else if (lam == 0) { @@ -648,18 +641,18 @@ long random_poisson(prng_t *prng_state, double lam) { } } -long random_negative_binomial(prng_t *prng_state, double n, double p) { +int64_t random_negative_binomial(prng_t *prng_state, double n, double p) { double Y = random_gamma(prng_state, n, (1 - p) / p); return random_poisson(prng_state, Y); } -long random_binomial_btpe(prng_t *prng_state, long n, double p, binomial_t* binomial) { +int64_t random_binomial_btpe(prng_t *prng_state, int64_t n, double p, + binomial_t *binomial) { double r, q, fm, p1, xm, xl, xr, c, laml, lamr, p2, p3, p4; double a, u, v, s, F, rho, t, A, nrq, x1, x2, f1, f2, z, z2, w, w2, x; - long m, y, k, i; + int64_t m, y, k, i; - if (!(binomial->has_binomial) || - (binomial->nsave != n) || + if (!(binomial->has_binomial) || (binomial->nsave != n) || (binomial->psave != p)) { /* initialize */ binomial->nsave = n; @@ -668,9 +661,8 @@ long random_binomial_btpe(prng_t *prng_state, long n, double p, binomial_t* bino binomial->r = r = min(p, 1.0 - p); binomial->q = q = 1.0 - r; binomial->fm = fm = n * r + r; - binomial->m = m = (long)floor(binomial->fm); - binomial->p1 = p1 = - floor(2.195 * sqrt(n * r * q) - 4.6 * q) + 0.5; + binomial->m = m = (int64_t)floor(binomial->fm); + binomial->p1 = p1 = floor(2.195 * sqrt(n * r * q) - 4.6 * q) + 0.5; binomial->xm = xm = m + 0.5; binomial->xl = xl = xm - p1; binomial->xr = xr = xm + p1; @@ -706,7 +698,7 @@ long random_binomial_btpe(prng_t *prng_state, long n, double p, binomial_t* bino v = random_sample(prng_state); if (u > p1) goto Step20; - y = (long)floor(xm - p1 * v + u); + y = (int64_t)floor(xm - p1 * v + u); goto Step60; Step20: @@ -716,26 +708,26 @@ long random_binomial_btpe(prng_t *prng_state, long n, double p, binomial_t* bino v = v * c + 1.0 - fabs(m - x + 0.5) / p1; if (v > 1.0) goto Step10; - y = (long)floor(x); + y = (int64_t)floor(x); goto Step50; Step30: if (u > p3) goto Step40; - y = (long)floor(xl + log(v) / laml); + y = (int64_t)floor(xl + log(v) / laml); if (y < 0) goto Step10; v = v * (u - p2) * laml; goto Step50; Step40: - y = (long)floor(xr - log(v) / lamr); + y = (int64_t)floor(xr - log(v) / lamr); if (y > n) goto Step10; v = v * (u - p3) * lamr; Step50: - k = labs(y - m); + k = llabs(y - m); if ((k > 20) && (k < ((nrq) / 2.0 - 1))) goto Step52; @@ -794,12 +786,12 @@ long random_binomial_btpe(prng_t *prng_state, long n, double p, binomial_t* bino return y; } -long random_binomial_inversion(prng_t *prng_state, long n, double p, binomial_t* binomial) { +int64_t random_binomial_inversion(prng_t *prng_state, int64_t n, double p, + binomial_t *binomial) { double q, qn, np, px, U; - long X, bound; + int64_t X, bound; - if (!(binomial->has_binomial) || - (binomial->nsave != n) || + if (!(binomial->has_binomial) || (binomial->nsave != n) || (binomial->psave != p)) { binomial->nsave = n; binomial->psave = p; @@ -807,8 +799,7 @@ long random_binomial_inversion(prng_t *prng_state, long n, double p, binomial_t* binomial->q = q = 1.0 - p; binomial->r = qn = exp(n * log(q)); binomial->c = np = n * p; - binomial->m = bound = - (long)min(n, np + 10.0 * sqrt(np * q + 1)); + binomial->m = bound = (int64_t)min(n, np + 10.0 * sqrt(np * q + 1)); } else { q = binomial->q; qn = binomial->r; @@ -832,7 +823,8 @@ long random_binomial_inversion(prng_t *prng_state, long n, double p, binomial_t* return X; } -long random_binomial(prng_t *prng_state, double p, long n, binomial_t * binomial) { +int64_t random_binomial(prng_t *prng_state, double p, int64_t n, + binomial_t *binomial) { double q; if (p <= 0.5) { @@ -860,7 +852,7 @@ double random_noncentral_chisquare(prng_t *prng_state, double df, double nonc) { const double n = random_gauss_zig(prng_state) + sqrt(nonc); return Chi2 + n * n; } else { - const long i = random_poisson(prng_state, nonc / 2.0); + const int64_t i = random_poisson(prng_state, nonc / 2.0); return random_chisquare(prng_state, df + 2 * i); } } @@ -938,9 +930,9 @@ double random_vonmises(prng_t *prng_state, double mu, double kappa) { } } -long random_logseries(prng_t *prng_state, double p) { +int64_t random_logseries(prng_t *prng_state, double p) { double q, r, U, V; - long result; + int64_t result; r = log(1.0 - p); @@ -952,7 +944,7 @@ long random_logseries(prng_t *prng_state, double p) { U = random_sample(prng_state); q = 1.0 - exp(r * U); if (V <= q * q) { - result = (long)floor(1 + log(V) / log(q)); + result = (int64_t)floor(1 + log(V) / log(q)); if (result < 1) { continue; } else { @@ -966,9 +958,9 @@ long random_logseries(prng_t *prng_state, double p) { } } -long random_geometric_search(prng_t *prng_state, double p) { +int64_t random_geometric_search(prng_t *prng_state, double p) { double U; - long X; + int64_t X; double sum, prod, q; X = 1; @@ -983,11 +975,11 @@ long random_geometric_search(prng_t *prng_state, double p) { return X; } -long random_geometric_inversion(prng_t *prng_state, double p) { - return (long)ceil(log(1.0 - random_sample(prng_state)) / log(1.0 - p)); +int64_t random_geometric_inversion(prng_t *prng_state, double p) { + return (int64_t)ceil(log(1.0 - random_sample(prng_state)) / log(1.0 - p)); } -long random_geometric(prng_t *prng_state, double p) { +int64_t random_geometric(prng_t *prng_state, double p) { if (p >= 0.333333333333333333333333) { return random_geometric_search(prng_state, p); } else { @@ -995,9 +987,9 @@ long random_geometric(prng_t *prng_state, double p) { } } -long random_zipf(prng_t *prng_state, double a) { +int64_t random_zipf(prng_t *prng_state, double a) { double T, U, V; - long X; + int64_t X; double am1, b; am1 = a - 1.0; @@ -1005,9 +997,9 @@ long random_zipf(prng_t *prng_state, double a) { do { U = 1.0 - random_sample(prng_state); V = random_sample(prng_state); - X = (long)floor(pow(U, -1.0 / am1)); - /* The real result may be above what can be represented in a signed - * long. It will get casted to -sys.maxint-1. Since this is + X = (int64_t)floor(pow(U, -1.0 / am1)); + /* The real result may be above what can be represented in a int64. + * It will get casted to -sys.maxint-1. Since this is * a straightforward rejection algorithm, we can just reject this value * in the rejection condition below. This function then models a Zipf * distribution truncated to sys.maxint. @@ -1036,9 +1028,9 @@ double random_triangular(prng_t *prng_state, double left, double mode, } } -long random_hypergeometric_hyp(prng_t *prng_state, long good, long bad, - long sample) { - long d1, k, z; +int64_t random_hypergeometric_hyp(prng_t *prng_state, int64_t good, int64_t bad, + int64_t sample) { + int64_t d1, k, z; double d2, u, y; d1 = bad + good - sample; @@ -1048,12 +1040,12 @@ long random_hypergeometric_hyp(prng_t *prng_state, long good, long bad, k = sample; while (y > 0.0) { u = random_sample(prng_state); - y -= (long)floor(u + y / (d1 + k)); + y -= (int64_t)floor(u + y / (d1 + k)); k--; if (k == 0) break; } - z = (long)(d2 - y); + z = (int64_t)(d2 - y); if (good > bad) z = sample - z; return z; @@ -1063,11 +1055,11 @@ long random_hypergeometric_hyp(prng_t *prng_state, long good, long bad, /* D2 = 3 - 2*sqrt(3/e) */ #define D1 1.7155277699214135 #define D2 0.8989161620588988 -long random_hypergeometric_hrua(prng_t *prng_state, long good, long bad, - long sample) { - long mingoodbad, maxgoodbad, popsize, m, d9; +int64_t random_hypergeometric_hrua(prng_t *prng_state, int64_t good, + int64_t bad, int64_t sample) { + int64_t mingoodbad, maxgoodbad, popsize, m, d9; double d4, d5, d6, d7, d8, d10, d11; - long Z; + int64_t Z; double T, W, X, Y; mingoodbad = min(good, bad); @@ -1079,7 +1071,7 @@ long random_hypergeometric_hrua(prng_t *prng_state, long good, long bad, d6 = m * d4 + 0.5; d7 = sqrt((double)(popsize - m) * sample * d4 * d5 / (popsize - 1) + 0.5); d8 = D1 * d7 + D2; - d9 = (long)floor((double)(m + 1) * (mingoodbad + 1) / (popsize + 2)); + d9 = (int64_t)floor((double)(m + 1) * (mingoodbad + 1) / (popsize + 2)); d10 = (loggam(d9 + 1) + loggam(mingoodbad - d9 + 1) + loggam(m - d9 + 1) + loggam(maxgoodbad - m + d9 + 1)); d11 = min(min(m, mingoodbad) + 1.0, floor(d6 + 16 * d7)); @@ -1094,7 +1086,7 @@ long random_hypergeometric_hrua(prng_t *prng_state, long good, long bad, if ((W < 0.0) || (W >= d11)) continue; - Z = (long)floor(W); + Z = (int64_t)floor(W); T = d10 - (loggam(Z + 1) + loggam(mingoodbad - Z + 1) + loggam(m - Z + 1) + loggam(maxgoodbad - m + Z + 1)); @@ -1123,8 +1115,8 @@ long random_hypergeometric_hrua(prng_t *prng_state, long good, long bad, #undef D1 #undef D2 -long random_hypergeometric(prng_t *prng_state, long good, long bad, - long sample) { +int64_t random_hypergeometric(prng_t *prng_state, int64_t good, int64_t bad, + int64_t sample) { if (sample > 10) { return random_hypergeometric_hrua(prng_state, good, bad, sample); } else { diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h index 9b1a70e9e1fc..c5050d400ea6 100644 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ b/_randomgen/core_prng/src/distributions/distributions.h @@ -18,6 +18,21 @@ typedef int bool; #include "numpy/npy_common.h" #include +#ifdef _WIN32 +#if _MSC_VER == 1500 + +static NPY_INLINE int64_t llabs(int64_t x) { + int64_t o; + if (x < 0) { + o = -x; + } else { + o = x; + } + return o; +} +#endif +#endif + #ifdef DLL_EXPORT #define DECLDIR __declspec(dllexport) #else @@ -36,11 +51,11 @@ typedef int bool; typedef struct s_binomial_t { int has_binomial; /* !=0: following parameters initialized for binomial */ double psave; - long nsave; + int64_t nsave; double r; double q; double fm; - long m; + int64_t m; double p1; double xm; double xl; @@ -83,8 +98,8 @@ DECLDIR double random_sample(prng_t *prng_state); DECLDIR int64_t random_positive_int64(prng_t *prng_state); DECLDIR int32_t random_positive_int32(prng_t *prng_state); -DECLDIR long random_positive_int(prng_t *prng_state); -DECLDIR unsigned long random_uint(prng_t *prng_state); +DECLDIR int64_t random_positive_int(prng_t *prng_state); +DECLDIR uint64_t random_uint(prng_t *prng_state); DECLDIR double random_standard_exponential(prng_t *prng_state); DECLDIR float random_standard_exponential_f(prng_t *prng_state); @@ -137,16 +152,18 @@ DECLDIR double random_vonmises(prng_t *prng_state, double mu, double kappa); DECLDIR double random_triangular(prng_t *prng_state, double left, double mode, double right); -DECLDIR long random_poisson(prng_t *prng_state, double lam); -DECLDIR long random_negative_binomial(prng_t *prng_state, double n, double p); -DECLDIR long random_binomial(prng_t *prng_state, double p, long n, binomial_t* binomial); -DECLDIR long random_logseries(prng_t *prng_state, double p); -DECLDIR long random_geometric_search(prng_t *prng_state, double p); -DECLDIR long random_geometric_inversion(prng_t *prng_state, double p); -DECLDIR long random_geometric(prng_t *prng_state, double p); -DECLDIR long random_zipf(prng_t *prng_state, double a); -DECLDIR long random_hypergeometric(prng_t *prng_state, long good, long bad, - long sample); +DECLDIR int64_t random_poisson(prng_t *prng_state, double lam); +DECLDIR int64_t random_negative_binomial(prng_t *prng_state, double n, + double p); +DECLDIR int64_t random_binomial(prng_t *prng_state, double p, int64_t n, + binomial_t *binomial); +DECLDIR int64_t random_logseries(prng_t *prng_state, double p); +DECLDIR int64_t random_geometric_search(prng_t *prng_state, double p); +DECLDIR int64_t random_geometric_inversion(prng_t *prng_state, double p); +DECLDIR int64_t random_geometric(prng_t *prng_state, double p); +DECLDIR int64_t random_zipf(prng_t *prng_state, double a); +DECLDIR int64_t random_hypergeometric(prng_t *prng_state, int64_t good, + int64_t bad, int64_t sample); DECLDIR uint64_t random_interval(prng_t *prng_state, uint64_t max); DECLDIR uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, diff --git a/_randomgen/core_prng/tests/test_numpy_mt19937.py b/_randomgen/core_prng/tests/test_numpy_mt19937.py index 9ff45504fdb2..dbe25172843a 100644 --- a/_randomgen/core_prng/tests/test_numpy_mt19937.py +++ b/_randomgen/core_prng/tests/test_numpy_mt19937.py @@ -298,16 +298,14 @@ def test_repeatability(self): res = hashlib.md5(val.view(np.int8)).hexdigest() print(tgt[np.dtype(dt).name] == res) - # TODO - # assert_(tgt[np.dtype(dt).name] == res) + assert_(tgt[np.dtype(dt).name] == res) # bools do not depend on endianess mt19937.seed(1234) val = self.rfunc(0, 2, size=1000, dtype=bool).view(np.int8) res = hashlib.md5(val).hexdigest() print(tgt[np.dtype(bool).name] == res) - # TODO - # assert_(tgt[np.dtype(bool).name] == res) + assert_(tgt[np.dtype(bool).name] == res) def test_repeatability_broadcasting(self): @@ -1082,9 +1080,6 @@ def setup(self): def set_seed(self): random.seed(self.seed) - # TODO: Include test for randint once it can broadcast - # Can steal the test written in PR #6938 - def test_uniform(self): low = [0] high = [1] diff --git a/_randomgen/demo.py b/_randomgen/demo.py deleted file mode 100644 index 30b0984221d2..000000000000 --- a/_randomgen/demo.py +++ /dev/null @@ -1,103 +0,0 @@ -import timeit - -from core_prng import Xoroshiro128, ThreeFry, MT19937, \ - Xorshift1024, PCG64, Philox, DSFMT -from core_prng.generator import RandomGenerator - -print(RandomGenerator().random_integer(32)) -print(RandomGenerator(Xoroshiro128()).random_integer()) -print(RandomGenerator(ThreeFry()).random_integer()) - -print('\n' * 3) -print('Check random_sample') -rg = RandomGenerator() -print(rg.state) -print(rg.random_sample()) -print(rg.state) -print(rg.random_sample()) -print(rg.random_sample((3))) -print(rg.random_sample((3, 1))) -print(rg.state) -import numpy as np - -a = rg.random_sample((1, 1), dtype=np.float32) -print(a) -print(a.dtype) -print(rg.state) - -print('\n' * 3) -print('Check set/get state') -state = rg.state -print(rg.state) -print(rg.random_integer()) -print(rg.state) -rg.state = state -print(rg.random_integer()) - -print(RandomGenerator(Xoroshiro128()).state) -rg = RandomGenerator(ThreeFry()) -print(rg.state) -rg.random_integer() -print(rg.state) -rg = RandomGenerator(MT19937()) -state = rg.state -print(state) -rg.state = state -print(rg.random_integer()) -print(rg.random_integer(32)) -print(rg.random_sample()) - -rg = RandomGenerator(Xorshift1024()) -state = rg.state -print(state) -rg.state = state - -rg = RandomGenerator(PCG64()) -state = rg.state -print(state) -rg.state = state - -rg = RandomGenerator(Philox()) -state = rg.state -print(state) -rg.state = state - -rg = RandomGenerator(DSFMT()) -state = rg.state -print(state) -rg.state = state - - -PRNGS = [MT19937, PCG64, Philox, ThreeFry, Xoroshiro128, Xorshift1024, DSFMT] - -setup = """ -from core_prng import {module} -m = {module}() -m._benchmark(701) -""" -import pandas as pd -res = [] -for p in PRNGS: - module = p.__name__ - print(module) - t = timeit.timeit("m._benchmark(10000000)", setup.format(module=module), - number=10) - res.append(pd.Series({'module': module, 'ms': 1000 * - t / 10, 'rps': int(10000000 / (t/10))})) - #print('{:0.2f} ms'.format()) - # print('{:,} randoms per second'.format())) -res = pd.DataFrame(res) -print(res.set_index('module').sort_values('ms')) - -res = [] -for p in PRNGS: - module = p.__name__ - print(module) - t = timeit.timeit("m._benchmark(10000000, 'double')", setup.format(module=module), - number=10) - res.append(pd.Series({'module': module, 'ms': 1000 * - t / 10, 'rps': int(10000000 / (t/10))})) - #print('{:0.2f} ms'.format()) - # print('{:,} randoms per second'.format())) -res = pd.DataFrame(res) -print(res.set_index('module').sort_values('ms')) From 0c89a4b75c31fc5e9684689f58f44f9b87477a8c Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 00:03:25 +0000 Subject: [PATCH 075/279] DOC: Start documentation Make a start of docs --- _randomgen/core_prng/__init__.py | 11 +- _randomgen/core_prng/common.pxd | 2 +- _randomgen/core_prng/common.pyx | 6 + _randomgen/core_prng/dsfmt.pyx | 276 ++++++++++++++------ _randomgen/core_prng/entropy.pxd | 5 - _randomgen/core_prng/entropy.pyx | 2 +- _randomgen/core_prng/generator.pyx | 254 ++++++++++-------- _randomgen/core_prng/pcg32.pyx | 1 - _randomgen/core_prng/pcg64.pyx | 1 - _randomgen/core_prng/philox.pyx | 5 +- _randomgen/core_prng/threefry.pyx | 5 +- _randomgen/core_prng/threefry32.pyx | 5 +- _randomgen/core_prng/xoroshiro128.pyx | 216 +++++++++++---- _randomgen/core_prng/xorshift1024.pyx | 206 ++++++++++++++- _randomgen/doc/Makefile | 20 ++ _randomgen/doc/make.bat | 36 +++ _randomgen/doc/source/conf.py | 175 +++++++++++++ _randomgen/doc/source/generator.rst | 74 ++++++ _randomgen/doc/source/index.rst | 22 ++ _randomgen/doc/source/prng/dsfmt.rst | 38 +++ _randomgen/doc/source/prng/index.rst | 30 +++ _randomgen/doc/source/prng/xoroshiro128.rst | 38 +++ _randomgen/doc/source/prng/xorshift1024.rst | 38 +++ _randomgen/requirements.txt | 4 + 24 files changed, 1199 insertions(+), 271 deletions(-) delete mode 100644 _randomgen/core_prng/entropy.pxd create mode 100644 _randomgen/doc/Makefile create mode 100644 _randomgen/doc/make.bat create mode 100644 _randomgen/doc/source/conf.py create mode 100644 _randomgen/doc/source/generator.rst create mode 100644 _randomgen/doc/source/index.rst create mode 100644 _randomgen/doc/source/prng/dsfmt.rst create mode 100644 _randomgen/doc/source/prng/index.rst create mode 100644 _randomgen/doc/source/prng/xoroshiro128.rst create mode 100644 _randomgen/doc/source/prng/xorshift1024.rst create mode 100644 _randomgen/requirements.txt diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/core_prng/__init__.py index 9a4b0a1b19a6..6d389ae9604b 100644 --- a/_randomgen/core_prng/__init__.py +++ b/_randomgen/core_prng/__init__.py @@ -1,5 +1,5 @@ from .dsfmt import DSFMT -from .generator import RandomGenerator +from .generator import * from .mt19937 import MT19937 from .pcg32 import PCG32 from .pcg64 import PCG64 @@ -10,7 +10,14 @@ from .xorshift1024 import Xorshift1024 __all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'PCG32', 'Philox', - 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024'] + 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024', + 'beta', 'binomial', 'bytes', 'chisquare', 'choice', 'complex_normal', 'dirichlet', 'exponential', 'f', + 'gamma', 'geometric', 'gumbel', 'hypergeometric', 'laplace', 'logistic', 'lognormal', 'logseries', + 'multinomial', 'multivariate_normal', 'negative_binomial', 'noncentral_chisquare', 'noncentral_f', + 'normal', 'permutation', 'pareto', 'poisson', 'power', 'rand', 'randint', 'randn', + 'random_integers', 'random_raw', 'random_uintegers', 'rayleigh', 'state', 'sample', 'shuffle', + 'standard_cauchy', 'standard_exponential', 'standard_gamma', 'standard_normal', 'standard_t', + 'tomaxint', 'triangular', 'uniform', 'vonmises', 'wald', 'weibull', 'zipf'] from ._version import get_versions diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/core_prng/common.pxd index 66d961edc4ef..fce433449729 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/core_prng/common.pxd @@ -1,7 +1,7 @@ from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t) from libc.math cimport sqrt -from cpython cimport PyInt_AsLong, PyFloat_AsDouble + from distributions cimport prng_t import numpy as np cimport numpy as np diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/core_prng/common.pyx index b25510e1a955..aad1ad6f10b0 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/core_prng/common.pyx @@ -1,6 +1,8 @@ #!python #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True +from collections import namedtuple +from cpython cimport PyInt_AsLong, PyFloat_AsDouble import sys import numpy as np cimport numpy as np @@ -8,6 +10,10 @@ from common cimport * np.import_array() +interface = namedtuple('interface', ['state_address', 'state', 'next_uint64', + 'next_uint32', 'next_double', 'prng']) + + cdef double kahan_sum(double *darr, np.npy_intp n): cdef double c, y, t, sum cdef np.npy_intp i diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/core_prng/dsfmt.pyx index 552941b189d1..d1da29127237 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/core_prng/dsfmt.pyx @@ -5,11 +5,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np +from common import interface from common cimport * from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle -cimport entropy np.import_array() @@ -65,22 +65,83 @@ cdef uint64_t dsfmt_raw(void *st) nogil: return dsfmt_next_raw(st) cdef class DSFMT: - """ - Prototype Core PRNG using dsfmt + u""" + DSFMT(seed=None) + + Container for the SIMD-based Mersenne Twister pseudo RNG. Parameters ---------- - seed : int, array of int - Integer or array of integers between 0 and 2**64 - 1 + seed : {None, int, array_like}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**32-1], array of integers in + [0, 2**32-1] or ``None`` (the default). If `seed` is ``None``, + then ``DSFMT`` will try to read entropy from ``/dev/urandom`` + (or the Windows analog) if available to produce a 64-bit + seed. If unavailable, a 64-bit hash of the time and process + ID is used. Notes ----- - Exposes no user-facing API except `state`. Designed for use in a - `RandomGenerator` object. + ``DSFMT`` directly provides generators for doubles, and unsigned 32 and 64- + bit integers [1]_ . These are not firectly available and must b consumed + via a ``RandomGenerator`` object. + + The Python stdlib module "random" also contains a Mersenne Twister + pseudo-random number generator. + + **Parallel Features** + + ``DSFMT`` can be used in parallel applications by calling the method + ``jump`` which advances the state as-if :math:`2^{128}` random numbers + have been generated [2]_. This allows the original sequence to be split + so that distinct segments can be used in each worker process. All + generators should be initialized with the same seed to ensure that the + segments come from the same sequence. + + >>> from core_prng.entropy import random_entropy + >>> from core_prng import RandomGenerator, DSFMT + >>> seed = random_entropy() + >>> rs = [RandomGenerator(DSFMT(seed)) for _ in range(10)] + # Advance rs[i] by i jumps + >>> for i in range(10): + ... rs[i].jump() + + **State and Seeding** + + The ``DSFMT`` state vector consists of a 384 element array of + 64-bit unsigned integers plus a single integer value between 0 and 382 + indicating the current position within the main array. The implementation + used here augments this with a 384 element array of doubles which are used + to efficiently access the random numbers produced by the dSFMT generator. + + ``DSFMT`` is seeded using either a single 32-bit unsigned integer + or a vector of 32-bit unsigned integers. In either case, the input seed is + used as an input (or inputs) for a hashing function, and the output of the + hashing function is used as the initial state. Using a single 32-bit value + for the seed can only initialize a small range of the possible initial + state values. + + **Compatibility Guarantee** + + ``DSFMT`` does makes a guarantee that a fixed seed and will always + produce the same results. + + References + ---------- + .. [1] Mutsuo Saito and Makoto Matsumoto, "SIMD-oriented Fast Mersenne + Twister: a 128-bit Pseudorandom Number Generator." Monte Carlo + and Quasi-Monte Carlo Methods 2006, Springer, pp. 607 -- 622, 2008. + .. [2] Hiroshi Haramoto, Makoto Matsumoto, and Pierre L\'Ecuyer, "A Fast + Jump Ahead Algorithm for Linear Recurrences in a Polynomial Space", + Sequences and Their Applications - SETA, 290--298, 2008. """ cdef dsfmt_state *rng_state cdef prng_t *_prng cdef public object capsule + cdef public object _cffi + cdef public object _ctypes + cdef public object _generator def __init__(self, seed=None): self.rng_state = malloc(sizeof(dsfmt_state)) @@ -97,6 +158,10 @@ cdef class DSFMT: cdef const char *name = "CorePRNG" self.capsule = PyCapsule_New(self._prng, name, NULL) + self._cffi = None + self._ctypes = None + self._generator = None + # Pickling support: def __getstate__(self): return self.state @@ -115,34 +180,6 @@ cdef class DSFMT: free(self.rng_state) free(self._prng) - cdef _reset_state_variables(self): - pass - - def __random_integer(self, bits=64): - """ - 64-bit Random Integers from the PRNG - - Parameters - ---------- - bits : {32, 64} - Number of random bits to return - - Returns - ------- - rv : int - Next random value - - Notes - ----- - Testing only - """ - if bits == 64: - return dsfmt_next64(self.rng_state) - elif bits == 32: - return dsfmt_next32(self.rng_state) - else: - raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i if method==u'uint64': @@ -156,18 +193,20 @@ cdef class DSFMT: def seed(self, seed=None): """ - seed(seed=None, stream=None) + seed(seed=None) Seed the generator. - This method is called when ``RandomState`` is initialized. It can be - called again to re-seed the generator. For details, see - ``RandomState``. - Parameters ---------- - seed : int, optional - Seed for ``RandomState``. + seed : {None, int, array_like}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**32-1], array of integers in + [0, 2**32-1] or ``None`` (the default). If `seed` is ``None``, + then ``DSFMT`` will try to read entropy from ``/dev/urandom`` + (or the Windows analog) if available to produce a 64-bit + seed. If unavailable, a 64-bit hash of the time and process + ID is used. Raises ------ @@ -197,61 +236,41 @@ cdef class DSFMT: dsfmt_init_by_array(self.rng_state.state, obj.data, np.PyArray_DIM(obj, 0)) - self._reset_state_variables() - def seed(self, seed=None): + def jump(self, np.npy_intp iter): """ - seed(seed=None, stream=None) - - Seed the generator. + jump(iter = 1) - This method is called when ``RandomState`` is initialized. It can be - called again to re-seed the generator. For details, see - ``RandomState``. + Jumps the state of the random number generator as-if 2**128 random numbers + have been generated. Parameters ---------- - seed : int, optional - Seed for ``RandomState``. - - Raises - ------ - ValueError - If seed values are out of range for the PRNG. + iter : integer, positive + Number of times to jump the state of the prng. + Returns + ------- + self : DSFMT + PRNG jumped iter times """ - cdef np.ndarray obj - try: - if seed is None: - try: - seed = random_entropy(1) - except RuntimeError: - seed = random_entropy(1, 'fallback') - dsfmt_init_gen_rand(self.rng_state.state, seed[0]) - else: - if hasattr(seed, 'squeeze'): - seed = seed.squeeze() - idx = operator.index(seed) - if idx > int(2**32 - 1) or idx < 0: - raise ValueError("Seed must be between 0 and 2**32 - 1") - dsfmt_init_gen_rand(self.rng_state.state, seed) - except TypeError: - obj = np.asarray(seed).astype(np.int64, casting='safe').ravel() - if ((obj > int(2**32 - 1)) | (obj < 0)).any(): - raise ValueError("Seed must be between 0 and 2**32 - 1") - obj = obj.astype(np.uint32, casting='unsafe', order='C') - dsfmt_init_by_array(self.rng_state.state, obj.data, - np.PyArray_DIM(obj, 0)) - - self._reset_state_variables() - - def jump(self): - dsfmt_jump(self.rng_state) + cdef np.npy_intp i + for i in range(iter): + dsfmt_jump(self.rng_state) return self @property def state(self): - """Get or set the PRNG state""" + """ + Get or set the PRNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the PRNG + """ + cdef Py_ssize_t i, j, loc = 0 cdef uint64_t[::1] state cdef double[::1] buffered_uniforms @@ -288,4 +307,89 @@ cdef class DSFMT: buffered_uniforms = value['buffered_uniforms'] for i in range(DSFMT_N64): self.rng_state.buffered_uniforms[i] = buffered_uniforms[i] - self.rng_state.buffer_loc = value['buffer_loc'] \ No newline at end of file + self.rng_state.buffer_loc = value['buffer_loc'] + + @property + def ctypes(self): + """ + Cytpes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * prng - pointer to the PRNG struct + """ + + if self._ctypes is not None: + return self._ctypes + + import ctypes + + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&dsfmt_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&dsfmt_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&dsfmt_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p(self._prng)) + return self.ctypes + + @property + def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * prng - pointer to the PRNG struct + """ + if self._cffi is not None: + return self._cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') + + ffi = cffi.FFI() + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._prng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._prng.next_uint32), + ffi.cast('double (*)(void *)',self._prng.next_double), + ffi.cast('void *',self._prng)) + return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : core_prng.generator.RandomGenerator + Random generator used this instance as the core PRNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator \ No newline at end of file diff --git a/_randomgen/core_prng/entropy.pxd b/_randomgen/core_prng/entropy.pxd deleted file mode 100644 index c0a1a0e871f7..000000000000 --- a/_randomgen/core_prng/entropy.pxd +++ /dev/null @@ -1,5 +0,0 @@ - -from libc.stdint cimport uint64_t -cimport numpy as np - -cdef np.ndarray seed_by_array(object seed, Py_ssize_t n) \ No newline at end of file diff --git a/_randomgen/core_prng/entropy.pyx b/_randomgen/core_prng/entropy.pyx index 19dbb0fd20b2..cec1bb9a81b6 100644 --- a/_randomgen/core_prng/entropy.pyx +++ b/_randomgen/core_prng/entropy.pyx @@ -23,7 +23,7 @@ cdef Py_ssize_t compute_numel(size): n = size return n -cdef np.ndarray seed_by_array(object seed, Py_ssize_t n): +def seed_by_array(object seed, Py_ssize_t n): """ Transforms a seed array into an initial state diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/core_prng/generator.pyx index ec52a1839f0b..cb9a001c2669 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/core_prng/generator.pyx @@ -4,7 +4,8 @@ import operator import warnings from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer -from cpython cimport Py_INCREF, PyComplex_RealAsDouble, PyComplex_ImagAsDouble, PyComplex_FromDoubles +from cpython cimport (Py_INCREF, PyComplex_RealAsDouble, PyInt_AsLong, + PyComplex_ImagAsDouble, PyComplex_FromDoubles, PyFloat_AsDouble) from common cimport * from distributions cimport * from bounded_integers cimport * @@ -14,10 +15,6 @@ cimport numpy as np import numpy as np cimport cython -from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer - -from common cimport * - try: from threading import Lock except ImportError: @@ -52,7 +49,7 @@ cdef class RandomGenerator: -------- >>> from core_prng.generator import RandomGenerator >>> rg = RandomGenerator() - >>> rg.random_integer() + >>> rg.standard_normal() """ cdef public object __core_prng cdef prng_t *_prng @@ -226,14 +223,6 @@ cdef class RandomGenerator: randoms_data[i] = self._prng.next_raw(self._prng.state) return randoms - def random_integer(self, bits=64): - if bits == 64: - return self._prng.next_uint64(self._prng.state) - elif bits == 32: - return self._prng.next_uint32(self._prng.state) - else: - raise ValueError('bits must be 32 or 64') - def random_sample(self, size=None, dtype=np.float64, out=None): """ random_sample(size=None, dtype='d', out=None) @@ -269,16 +258,16 @@ cdef class RandomGenerator: Examples -------- - >>> np.random.random_sample() + >>> core_prng.random_sample() 0.47108547995356098 - >>> type(np.random.random_sample()) + >>> type(core_prng.random_sample()) - >>> np.random.random_sample((5,)) + >>> core_prng.random_sample((5,)) array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) Three-by-two array of random numbers from [-5, 0): - >>> 5 * np.random.random_sample((3, 2)) - 5 + >>> 5 * core_prng.random_sample((3, 2)) - 5 array([[-3.99149989, -0.52338984], [-2.99091858, -0.79479508], [-1.23204345, -1.75224494]]) @@ -423,7 +412,7 @@ cdef class RandomGenerator: -------- Output a 3x8000 array: - >>> n = np.random.standard_exponential((3, 8000)) + >>> n = core_prng.standard_exponential((3, 8000)) """ key = np.dtype(dtype).name if key == 'float64': @@ -469,7 +458,7 @@ cdef class RandomGenerator: Examples -------- - >>> RS = np.random.mtrand.RandomState() # need a RandomState object + >>> RS = core_prng.mtrand.RandomState() # need a RandomState object >>> RS.tomaxint((2,2,2)) array([[[1170048599, 1600360186], [ 739731006, 1947757578]], @@ -549,30 +538,30 @@ cdef class RandomGenerator: Examples -------- - >>> np.random.randint(2, size=10) + >>> core_prng.randint(2, size=10) array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) - >>> np.random.randint(1, size=10) + >>> core_prng.randint(1, size=10) array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) Generate a 2 x 4 array of ints between 0 and 4, inclusive: - >>> np.random.randint(5, size=(2, 4)) + >>> core_prng.randint(5, size=(2, 4)) array([[4, 0, 2, 1], [3, 2, 2, 0]]) Generate a 1 x 3 array with 3 different upper bounds - >>> np.random.randint(1, [3, 5, 10]) + >>> core_prng.randint(1, [3, 5, 10]) array([2, 2, 9]) Generate a 1 by 3 array with 3 different lower bounds - >>> np.random.randint([1, 5, 7], 10) + >>> core_prng.randint([1, 5, 7], 10) array([9, 8, 7]) Generate a 2 by 4 array using broadcasting with dtype of uint8 - >>> np.random.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) + >>> core_prng.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) array([[ 8, 6, 9, 7], [ 1, 16, 9, 12]], dtype=uint8) """ @@ -626,7 +615,7 @@ cdef class RandomGenerator: Examples -------- - >>> np.random.bytes(10) + >>> core_prng.bytes(10) ' eh\\x85\\x022SZ\\xbf\\xa4' #random """ @@ -681,33 +670,33 @@ cdef class RandomGenerator: -------- Generate a uniform random sample from np.arange(5) of size 3: - >>> np.random.choice(5, 3) + >>> core_prng.choice(5, 3) array([0, 3, 4]) - >>> #This is equivalent to np.random.randint(0,5,3) + >>> #This is equivalent to core_prng.randint(0,5,3) Generate a non-uniform random sample from np.arange(5) of size 3: - >>> np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) + >>> core_prng.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) array([3, 3, 0]) Generate a uniform random sample from np.arange(5) of size 3 without replacement: - >>> np.random.choice(5, 3, replace=False) + >>> core_prng.choice(5, 3, replace=False) array([3,1,0]) - >>> #This is equivalent to np.random.permutation(np.arange(5))[:3] + >>> #This is equivalent to core_prng.permutation(np.arange(5))[:3] Generate a non-uniform random sample from np.arange(5) of size 3 without replacement: - >>> np.random.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) + >>> core_prng.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) array([2, 3, 0]) Any of the above can be repeated with an arbitrary array-like instead of just integers. For instance: >>> aa_milne_arr = ['pooh', 'rabbit', 'piglet', 'Christopher'] - >>> np.random.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) + >>> core_prng.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) array(['pooh', 'pooh', 'pooh', 'Christopher', 'piglet'], dtype='|S11') @@ -876,7 +865,7 @@ cdef class RandomGenerator: -------- Draw samples from the distribution: - >>> s = np.random.uniform(-1,0,1000) + >>> s = core_prng.uniform(-1,0,1000) All values are within the given interval: @@ -958,13 +947,13 @@ cdef class RandomGenerator: Notes ----- This is a convenience function. If you want an interface that takes - a shape-tuple as the first argument, refer to np.random.random_sample. + a shape-tuple as the first argument, refer to core_prng.random_sample. ``dtype`` can only be changed using a keyword argument. Examples -------- - >>> np.random.rand(3,2) + >>> core_prng.rand(3,2) array([[ 0.14022471, 0.96360618], #random [ 0.37601032, 0.25528411], #random [ 0.49313049, 0.94909878]]) #random @@ -1016,16 +1005,16 @@ cdef class RandomGenerator: ----- For random samples from :math:`N(\\mu, \\sigma^2)`, use: - ``sigma * np.random.randn(...) + mu`` + ``sigma * core_prng.randn(...) + mu`` Examples -------- - >>> np.random.randn() + >>> core_prng.randn() 2.1923875335537315 #random Two-by-four array of samples from N(3, 6.25): - >>> 2.5 * np.random.randn(2, 4) + 3 + >>> 2.5 * core_prng.randn(2, 4) + 3 array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random @@ -1080,15 +1069,15 @@ cdef class RandomGenerator: To sample from N evenly spaced floating-point numbers between a and b, use:: - a + (b - a) * (np.random.random_integers(N) - 1) / (N - 1.) + a + (b - a) * (core_prng.random_integers(N) - 1) / (N - 1.) Examples -------- - >>> np.random.random_integers(5) + >>> core_prng.random_integers(5) 4 - >>> type(np.random.random_integers(5)) + >>> type(core_prng.random_integers(5)) - >>> np.random.random_integers(5, size=(3.,2.)) + >>> core_prng.random_integers(5, size=(3.,2.)) array([[5, 4], [3, 3], [4, 5]]) @@ -1097,13 +1086,13 @@ cdef class RandomGenerator: numbers between 0 and 2.5, inclusive (*i.e.*, from the set :math:`{0, 5/8, 10/8, 15/8, 20/8}`): - >>> 2.5 * (np.random.random_integers(5, size=(5,)) - 1) / 4. + >>> 2.5 * (core_prng.random_integers(5, size=(5,)) - 1) / 4. array([ 0.625, 1.25 , 0.625, 0.625, 2.5 ]) Roll two six sided dice 1000 times and sum the results: - >>> d1 = np.random.random_integers(1, 6, 1000) - >>> d2 = np.random.random_integers(1, 6, 1000) + >>> d1 = core_prng.random_integers(1, 6, 1000) + >>> d2 = core_prng.random_integers(1, 6, 1000) >>> dsums = d1 + d2 Display results as a histogram: @@ -1156,13 +1145,13 @@ cdef class RandomGenerator: Examples -------- - >>> s = np.random.standard_normal(8000) + >>> s = core_prng.standard_normal(8000) >>> s array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random -0.38672696, -0.4685006 ]) #random >>> s.shape (8000,) - >>> s = np.random.standard_normal(size=(3, 4, 2)) + >>> s = core_prng.standard_normal(size=(3, 4, 2)) >>> s.shape (3, 4, 2) @@ -1245,7 +1234,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, sigma = 0, 0.1 # mean and standard deviation - >>> s = np.random.normal(mu, sigma, 1000) + >>> s = core_prng.normal(mu, sigma, 1000) Verify the mean and the variance: @@ -1327,7 +1316,7 @@ cdef class RandomGenerator: -------- Draw samples from the distribution: - >>> s = np.random.complex_normal(size=1000) + >>> s = core_prng.complex_normal(size=1000) """ cdef np.ndarray ogamma, orelation, oloc, randoms, v_real, v_imag, rho cdef double *randoms_data @@ -1496,7 +1485,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> shape, scale = 2., 1. # mean and width - >>> s = np.random.standard_gamma(shape, 1000000) + >>> s = core_prng.standard_gamma(shape, 1000000) Display the histogram of the samples, along with the probability density function: @@ -1583,7 +1572,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> shape, scale = 2., 2. # mean and dispersion - >>> s = np.random.gamma(shape, scale, 1000) + >>> s = core_prng.gamma(shape, scale, 1000) Display the histogram of the samples, along with the probability density function: @@ -1673,7 +1662,7 @@ cdef class RandomGenerator: >>> dfnum = 1. # between group degrees of freedom >>> dfden = 48. # within groups degrees of freedom - >>> s = np.random.f(dfnum, dfden, 1000) + >>> s = core_prng.f(dfnum, dfden, 1000) The lower bound for the top 1% of the samples is : @@ -1748,9 +1737,9 @@ cdef class RandomGenerator: >>> dfnum = 3 # between group deg of freedom >>> dfden = 20 # within groups degrees of freedom >>> nonc = 3.0 - >>> nc_vals = np.random.noncentral_f(dfnum, dfden, nonc, 1000000) + >>> nc_vals = core_prng.noncentral_f(dfnum, dfden, nonc, 1000000) >>> NF = np.histogram(nc_vals, bins=50, normed=True) - >>> c_vals = np.random.f(dfnum, dfden, 1000000) + >>> c_vals = core_prng.f(dfnum, dfden, 1000000) >>> F = np.histogram(c_vals, bins=50, normed=True) >>> plt.plot(F[1][1:], F[0]) >>> plt.plot(NF[1][1:], NF[0]) @@ -1821,7 +1810,7 @@ cdef class RandomGenerator: Examples -------- - >>> np.random.chisquare(2,4) + >>> core_prng.chisquare(2,4) array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) """ @@ -1886,7 +1875,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram >>> import matplotlib.pyplot as plt - >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(core_prng.noncentral_chisquare(3, 20, 100000), ... bins=200, normed=True) >>> plt.show() @@ -1894,9 +1883,9 @@ cdef class RandomGenerator: and compare to a chisquare. >>> plt.figure() - >>> values = plt.hist(np.random.noncentral_chisquare(3, .0000001, 100000), + >>> values = plt.hist(core_prng.noncentral_chisquare(3, .0000001, 100000), ... bins=np.arange(0., 25, .1), normed=True) - >>> values2 = plt.hist(np.random.chisquare(3, 100000), + >>> values2 = plt.hist(core_prng.chisquare(3, 100000), ... bins=np.arange(0., 25, .1), normed=True) >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') >>> plt.show() @@ -1905,7 +1894,7 @@ cdef class RandomGenerator: distribution. >>> plt.figure() - >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(core_prng.noncentral_chisquare(3, 20, 100000), ... bins=200, normed=True) >>> plt.show() @@ -1970,7 +1959,7 @@ cdef class RandomGenerator: -------- Draw samples and plot the distribution: - >>> s = np.random.standard_cauchy(1000000) + >>> s = core_prng.standard_cauchy(1000000) >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well >>> plt.hist(s, bins=100) >>> plt.show() @@ -2043,7 +2032,7 @@ cdef class RandomGenerator: We have 10 degrees of freedom, so is the sample mean within 95% of the recommended value? - >>> s = np.random.standard_t(10, size=100000) + >>> s = core_prng.standard_t(10, size=100000) >>> np.mean(intake) 6753.636363636364 >>> intake.std(ddof=1) @@ -2137,7 +2126,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, kappa = 0.0, 4.0 # mean and dispersion - >>> s = np.random.vonmises(mu, kappa, 1000) + >>> s = core_prng.vonmises(mu, kappa, 1000) Display the histogram of the samples, along with the probability density function: @@ -2237,7 +2226,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a, m = 3., 2. # shape and mode - >>> s = (np.random.pareto(a, 1000) + 1) * m + >>> s = (core_prng.pareto(a, 1000) + 1) * m Display the histogram of the samples, along with the probability density function: @@ -2330,7 +2319,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a = 5. # shape - >>> s = np.random.weibull(a, 1000) + >>> s = core_prng.weibull(a, 1000) Display the histogram of the samples, along with the probability density function: @@ -2340,7 +2329,7 @@ cdef class RandomGenerator: >>> def weib(x,n,a): ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) - >>> count, bins, ignored = plt.hist(np.random.weibull(5.,1000)) + >>> count, bins, ignored = plt.hist(core_prng.weibull(5.,1000)) >>> x = np.arange(1,100.)/50. >>> scale = count.max()/weib(x, 1., 5.).max() >>> plt.plot(x, weib(x, 1., 5.)*scale) @@ -2410,7 +2399,7 @@ cdef class RandomGenerator: >>> a = 5. # shape >>> samples = 1000 - >>> s = np.random.power(a, samples) + >>> s = core_prng.power(a, samples) Display the histogram of the samples, along with the probability density function: @@ -2426,20 +2415,20 @@ cdef class RandomGenerator: Compare the power function distribution to the inverse of the Pareto. >>> from scipy import stats - >>> rvs = np.random.power(5, 1000000) - >>> rvsp = np.random.pareto(5, 1000000) + >>> rvs = core_prng.power(5, 1000000) + >>> rvsp = core_prng.pareto(5, 1000000) >>> xx = np.linspace(0,1,100) >>> powpdf = stats.powerlaw.pdf(xx,5) >>> plt.figure() >>> plt.hist(rvs, bins=50, normed=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('np.random.power(5)') + >>> plt.title('core_prng.power(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('inverse of 1 + np.random.pareto(5)') + >>> plt.title('inverse of 1 + core_prng.pareto(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) @@ -2513,7 +2502,7 @@ cdef class RandomGenerator: Draw samples from the distribution >>> loc, scale = 0., 1. - >>> s = np.random.laplace(loc, scale, 1000) + >>> s = core_prng.laplace(loc, scale, 1000) Display the histogram of the samples, along with the probability density function: @@ -2615,7 +2604,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, beta = 0, 0.1 # location and scale - >>> s = np.random.gumbel(mu, beta, 1000) + >>> s = core_prng.gumbel(mu, beta, 1000) Display the histogram of the samples, along with the probability density function: @@ -2633,7 +2622,7 @@ cdef class RandomGenerator: >>> means = [] >>> maxima = [] >>> for i in range(0,1000) : - ... a = np.random.normal(mu, beta, 1000) + ... a = core_prng.normal(mu, beta, 1000) ... means.append(a.mean()) ... maxima.append(a.max()) >>> count, bins, ignored = plt.hist(maxima, 30, normed=True) @@ -2715,7 +2704,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> loc, scale = 10, 1 - >>> s = np.random.logistic(loc, scale, 10000) + >>> s = core_prng.logistic(loc, scale, 10000) >>> count, bins, ignored = plt.hist(s, bins=50) # plot against distribution @@ -2797,7 +2786,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, sigma = 3., 1. # mean and standard deviation - >>> s = np.random.lognormal(mu, sigma, 1000) + >>> s = core_prng.lognormal(mu, sigma, 1000) Display the histogram of the samples, along with the probability density function: @@ -2821,7 +2810,7 @@ cdef class RandomGenerator: >>> # values, drawn from a normal distribution. >>> b = [] >>> for i in range(1000): - ... a = 10. + np.random.random(100) + ... a = 10. + core_prng.random(100) ... b.append(np.product(a)) >>> b = np.array(b) / np.min(b) # scale values to be positive @@ -2888,7 +2877,7 @@ cdef class RandomGenerator: -------- Draw values from the distribution and plot the histogram - >>> values = hist(np.random.rayleigh(3, 100000), bins=200, normed=True) + >>> values = hist(core_prng.rayleigh(3, 100000), bins=200, normed=True) Wave heights tend to follow a Rayleigh distribution. If the mean wave height is 1 meter, what fraction of waves are likely to be larger than 3 @@ -2896,7 +2885,7 @@ cdef class RandomGenerator: >>> meanvalue = 1 >>> modevalue = np.sqrt(2 / np.pi) * meanvalue - >>> s = np.random.rayleigh(modevalue, 1000000) + >>> s = core_prng.rayleigh(modevalue, 1000000) The percentage of waves larger than 3 meters is: @@ -2968,7 +2957,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(np.random.wald(3, 2, 100000), bins=200, normed=True) + >>> h = plt.hist(core_prng.wald(3, 2, 100000), bins=200, normed=True) >>> plt.show() """ @@ -3035,7 +3024,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(np.random.triangular(-3, 0, 8, 100000), bins=200, + >>> h = plt.hist(core_prng.triangular(-3, 0, 8, 100000), bins=200, ... normed=True) >>> plt.show() @@ -3148,7 +3137,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> n, p = 10, .5 # number of trials, probability of each trial - >>> s = np.random.binomial(n, p, 1000) + >>> s = core_prng.binomial(n, p, 1000) # result of flipping a coin 10 times, tested 1000 times. A real world example. A company drills 9 wild-cat oil exploration @@ -3158,7 +3147,7 @@ cdef class RandomGenerator: Let's do 20,000 trials of the model, and count the number that generate zero positive results. - >>> sum(np.random.binomial(9, 0.1, 20000) == 0)/20000. + >>> sum(core_prng.binomial(9, 0.1, 20000) == 0)/20000. # answer = 0.38885, or 38%. """ @@ -3285,7 +3274,7 @@ cdef class RandomGenerator: for each successive well, that is what is the probability of a single success after drilling 5 wells, after 6 wells, etc.? - >>> s = np.random.negative_binomial(1, 0.1, 100000) + >>> s = core_prng.negative_binomial(1, 0.1, 100000) >>> for i in range(1, 11): ... probability = sum(s>> a = 2. # parameter - >>> s = np.random.zipf(a, 1000) + >>> s = core_prng.zipf(a, 1000) Display the histogram of the samples, along with the probability density function: @@ -3484,7 +3473,7 @@ cdef class RandomGenerator: Draw ten thousand values from the geometric distribution, with the probability of an individual success equal to 0.35: - >>> z = np.random.geometric(p=0.35, size=10000) + >>> z = core_prng.geometric(p=0.35, size=10000) How many trials succeeded after a single run? @@ -3572,7 +3561,7 @@ cdef class RandomGenerator: >>> ngood, nbad, nsamp = 100, 2, 10 # number of good, number of bad, and number of samples - >>> s = np.random.hypergeometric(ngood, nbad, nsamp, 1000) + >>> s = core_prng.hypergeometric(ngood, nbad, nsamp, 1000) >>> hist(s) # note that it is very unlikely to grab both bad items @@ -3580,7 +3569,7 @@ cdef class RandomGenerator: If you pull 15 marbles at random, how likely is it that 12 or more of them are one color? - >>> s = np.random.hypergeometric(15, 15, 15, 100000) + >>> s = core_prng.hypergeometric(15, 15, 15, 100000) >>> sum(s>=12)/100000. + sum(s<=3)/100000. # answer = 0.003 ... pretty unlikely! @@ -3681,7 +3670,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a = .6 - >>> s = np.random.logseries(a, 10000) + >>> s = core_prng.logseries(a, 10000) >>> count, bins, ignored = plt.hist(s) # plot against distribution @@ -3702,8 +3691,7 @@ cdef class RandomGenerator: def multivariate_normal(self, mean, cov, size=None, check_valid='warn', tol=1e-8): """ - multivariate_normal(self, mean, cov, size=None, check_valid='warn', - tol=1e-8) + multivariate_normal(self, mean, cov, size=None, check_valid='warn', tol=1e-8) Draw random samples from a multivariate normal distribution. @@ -3770,7 +3758,7 @@ cdef class RandomGenerator: Diagonal covariance means that points are oriented along x or y-axis: >>> import matplotlib.pyplot as plt - >>> x, y = np.random.multivariate_normal(mean, cov, 5000).T + >>> x, y = core_prng.multivariate_normal(mean, cov, 5000).T >>> plt.plot(x, y, 'x') >>> plt.axis('equal') >>> plt.show() @@ -3790,7 +3778,7 @@ cdef class RandomGenerator: -------- >>> mean = (1, 2) >>> cov = [[1, 0], [0, 1]] - >>> x = np.random.multivariate_normal(mean, cov, (3, 3)) + >>> x = core_prng.multivariate_normal(mean, cov, (3, 3)) >>> x.shape (3, 3, 2) @@ -3902,14 +3890,14 @@ cdef class RandomGenerator: -------- Throw a dice 20 times: - >>> np.random.multinomial(20, [1/6.]*6, size=1) + >>> core_prng.multinomial(20, [1/6.]*6, size=1) array([[4, 1, 7, 5, 2, 1]]) It landed 4 times on 1, once on 2, etc. Now, throw the dice 20 times, and 20 times again: - >>> np.random.multinomial(20, [1/6.]*6, size=2) + >>> core_prng.multinomial(20, [1/6.]*6, size=2) array([[3, 4, 3, 3, 4, 3], [2, 4, 3, 4, 0, 7]]) @@ -3918,7 +3906,7 @@ cdef class RandomGenerator: A loaded die is more likely to land on number 6: - >>> np.random.multinomial(100, [1/7.]*5 + [2/7.]) + >>> core_prng.multinomial(100, [1/7.]*5 + [2/7.]) array([11, 16, 14, 17, 16, 26]) The probability inputs should be normalized. As an implementation @@ -3927,12 +3915,12 @@ cdef class RandomGenerator: A biased coin which has twice as much weight on one side as on the other should be sampled like so: - >>> np.random.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT + >>> core_prng.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT array([38, 62]) not like: - >>> np.random.multinomial(100, [1.0, 2.0]) # WRONG + >>> core_prng.multinomial(100, [1.0, 2.0]) # WRONG array([100, 0]) """ @@ -4033,7 +4021,7 @@ cdef class RandomGenerator: average length, but allowing some variation in the relative sizes of the pieces. - >>> s = np.random.dirichlet((10, 5, 3), 20).transpose() + >>> s = core_prng.dirichlet((10, 5, 3), 20).transpose() >>> plt.barh(range(20), s[0]) >>> plt.barh(range(20), s[1], left=s[0], color='g') @@ -4127,14 +4115,14 @@ cdef class RandomGenerator: Examples -------- >>> arr = np.arange(10) - >>> np.random.shuffle(arr) + >>> core_prng.shuffle(arr) >>> arr [1 7 5 2 9 4 3 6 0 8] Multi-dimensional arrays are only shuffled along the first axis: >>> arr = np.arange(9).reshape((3, 3)) - >>> np.random.shuffle(arr) + >>> core_prng.shuffle(arr) >>> arr array([[3, 4, 5], [6, 7, 8], @@ -4216,14 +4204,14 @@ cdef class RandomGenerator: Examples -------- - >>> np.random.permutation(10) + >>> core_prng.permutation(10) array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) - >>> np.random.permutation([1, 4, 9, 12, 15]) + >>> core_prng.permutation([1, 4, 9, 12, 15]) array([15, 1, 9, 4, 12]) >>> arr = np.arange(9).reshape((3, 3)) - >>> np.random.permutation(arr) + >>> core_prng.permutation(arr) array([[6, 7, 8], [0, 1, 2], [3, 4, 5]]) @@ -4235,3 +4223,55 @@ cdef class RandomGenerator: arr = np.array(x) self.shuffle(arr) return arr + +_random_generator = RandomGenerator() + +beta = _random_generator.beta +binomial = _random_generator.binomial +bytes = _random_generator.bytes +chisquare = _random_generator.chisquare +choice = _random_generator.choice +complex_normal = _random_generator.complex_normal +dirichlet = _random_generator.dirichlet +exponential = _random_generator.exponential +f = _random_generator.f +gamma = _random_generator.gamma +geometric = _random_generator.geometric +gumbel = _random_generator.gumbel +hypergeometric = _random_generator.hypergeometric +laplace = _random_generator.laplace +logistic = _random_generator.logistic +lognormal = _random_generator.lognormal +logseries = _random_generator.logseries +multinomial = _random_generator.multinomial +multivariate_normal = _random_generator.multivariate_normal +negative_binomial = _random_generator.negative_binomial +noncentral_chisquare = _random_generator.noncentral_chisquare +noncentral_f = _random_generator.noncentral_f +normal = _random_generator.normal +pareto = _random_generator.pareto +permutation = _random_generator.permutation +poisson = _random_generator.poisson +power = _random_generator.power +rand = _random_generator.rand +randint = _random_generator.randint +randn = _random_generator.randn +random_integers = _random_generator.random_integers +random_raw = _random_generator.random_raw +sample = _random_generator.random_sample +random_uintegers = _random_generator.random_uintegers +rayleigh = _random_generator.rayleigh +shuffle = _random_generator.shuffle +standard_cauchy = _random_generator.standard_cauchy +standard_exponential = _random_generator.standard_exponential +standard_gamma = _random_generator.standard_gamma +standard_normal = _random_generator.standard_normal +standard_t = _random_generator.standard_t +state = _random_generator.state +tomaxint = _random_generator.tomaxint +triangular = _random_generator.triangular +uniform = _random_generator.uniform +vonmises = _random_generator.vonmises +wald = _random_generator.wald +weibull = _random_generator.weibull +zipf = _random_generator.zipf \ No newline at end of file diff --git a/_randomgen/core_prng/pcg32.pyx b/_randomgen/core_prng/pcg32.pyx index df97e1a815df..104701142e78 100644 --- a/_randomgen/core_prng/pcg32.pyx +++ b/_randomgen/core_prng/pcg32.pyx @@ -8,7 +8,6 @@ from common cimport * from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle -cimport entropy np.import_array() diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/core_prng/pcg64.pyx index 1d6b504f8038..332553c1b119 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/core_prng/pcg64.pyx @@ -8,7 +8,6 @@ from common cimport * from distributions cimport prng_t from core_prng.entropy import random_entropy import core_prng.pickle -cimport entropy np.import_array() diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/core_prng/philox.pyx index 399c95bfad58..e55bd27bd314 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/core_prng/philox.pyx @@ -5,9 +5,8 @@ import numpy as np from common cimport * from distributions cimport prng_t -from core_prng.entropy import random_entropy +from core_prng.entropy import random_entropy, seed_by_array import core_prng.pickle -cimport entropy np.import_array() @@ -190,7 +189,7 @@ cdef class Philox: state = random_entropy(4, 'fallback') state = state.view(np.uint64) else: - state = entropy.seed_by_array(seed, 2) + state = seed_by_array(seed, 2) for i in range(2): self.rng_state.key.v[i] = state[i] else: diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/core_prng/threefry.pyx index 197fe4aaa703..e2b5b3c71082 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/core_prng/threefry.pyx @@ -5,9 +5,8 @@ import numpy as np from common cimport * from distributions cimport prng_t -from core_prng.entropy import random_entropy +from core_prng.entropy import random_entropy, seed_by_array import core_prng.pickle -cimport entropy np.import_array() @@ -183,7 +182,7 @@ cdef class ThreeFry: state = random_entropy(8, 'fallback') state = state.view(np.uint64) else: - state = entropy.seed_by_array(seed, 4) + state = seed_by_array(seed, 4) for i in range(4): self.rng_state.key.v[i] = state[i] else: diff --git a/_randomgen/core_prng/threefry32.pyx b/_randomgen/core_prng/threefry32.pyx index ef31bfb1b328..376a6e4ded00 100644 --- a/_randomgen/core_prng/threefry32.pyx +++ b/_randomgen/core_prng/threefry32.pyx @@ -5,9 +5,8 @@ import numpy as np from common cimport * from distributions cimport prng_t -from core_prng.entropy import random_entropy +from core_prng.entropy import random_entropy, seed_by_array import core_prng.pickle -cimport entropy np.import_array() @@ -183,7 +182,7 @@ cdef class ThreeFry32: except RuntimeError: state = random_entropy(4, 'fallback') else: - state = entropy.seed_by_array(seed, 2) + state = seed_by_array(seed, 2) state = state.view(np.uint32) for i in range(4): self.rng_state.key.v[i] = state[i] diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/core_prng/xoroshiro128.pyx index 0301c0ea20f3..03535333f795 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/core_prng/xoroshiro128.pyx @@ -1,18 +1,14 @@ -from libc.stdint cimport uint32_t, uint64_t from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New -from collections import namedtuple -interface = namedtuple('interface', ['state_address','state','next_uint64','next_uint32','next_double','prng']) - import numpy as np cimport numpy as np +from common import interface from common cimport * from distributions cimport prng_t -from core_prng.entropy import random_entropy +from core_prng.entropy import random_entropy, seed_by_array import core_prng.pickle -cimport entropy np.import_array() @@ -40,23 +36,95 @@ cdef double xoroshiro128_double(void* st) nogil: cdef class Xoroshiro128: """ - Prototype Core PRNG using xoroshiro128 + Xoroshiro128(seed=None) + + Container for the xoroshiro128+ pseudo-random number generator. Parameters ---------- - seed : int, array of int - Integer or array of integers between 0 and 2**64 - 1 + seed : {None, int, array_like}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**64-1], array of integers in + [0, 2**64-1] or ``None`` (the default). If `seed` is ``None``, + then ``xoroshiro128plus.RandomState`` will try to read data from + ``/dev/urandom`` (or the Windows analog) if available. If + unavailable, a 64-bit hash of the time and process ID is used. Notes ----- - Exposes no user-facing API except `get_state` and `set_state`. Designed - for use in a `RandomGenerator` object. + xoroshiro128+ is the successor to xorshift128+ written by David Blackman and + Sebastiano Vigna. It is a 64-bit PRNG that uses a carefully handcrafted + shift/rotate-based linear transformation. This change both improves speed and + statistical quality of the PRNG [1]_. xoroshiro128+ has a period of + :math:`2^{128} - 1` and supports jumping the sequence in increments of + :math:`2^{64}`, which allows multiple non-overlapping sequences to be + generated. + + ``Xoroshiro128`` exposes no user-facing API except ``generator``, + ``state``, ``cffi`` and ``ctypes``. Designed for use in a + ``RandomGenerator`` object. + + **Compatibility Guarantee** + + ``Xoroshiro128`` guarantees that a fixed seed will always produce the + same results. + + See ``Xorshift1024`` for an related PRNG implementation with a larger + period (:math:`2^{1024} - 1`) and jump size (:math:`2^{512} - 1`). + + **Parallel Features** + + ``Xoroshiro128`` can be used in parallel applications by + calling the method ``jump`` which advances the state as-if + :math:`2^{64}` random numbers have been generated. This + allow the original sequence to be split so that distinct segments can be used + in each worker process. All generators should be initialized with the same + seed to ensure that the segments come from the same sequence. + + >>> from core_prng import RandomGenerator, Xoroshiro128 + >>> rg = [RandomGenerator(Xoroshiro128(1234)) for _ in range(10)] + # Advance rs[i] by i jumps + >>> for i in range(10): + ... rg[i].jump(i) + + **State and Seeding** + + The ``Xoroshiro128`` state vector consists of a 2 element array + of 64-bit unsigned integers. + + ``Xoroshiro128`` is seeded using either a single 64-bit unsigned integer + or a vector of 64-bit unsigned integers. In either case, the input seed is + used as an input (or inputs) for another simple random number generator, + Splitmix64, and the output of this PRNG function is used as the initial state. + Using a single 64-bit value for the seed can only initialize a small range of + the possible initial state values. When using an array, the SplitMix64 state + for producing the ith component of the initial state is XORd with the ith + value of the seed array until the seed array is exhausted. When using an array + the initial state for the SplitMix64 state is 0 so that using a single element + array and using the same value as a scalar will produce the same initial state. + + Examples + -------- + >>> from core_prng import RandomGenerator, Xoroshiro128 + >>> rg = RandomGenerator(Xoroshiro128(1234)) + >>> rg.standard_normal() + + Identical method using only Xoroshiro128 + + >>> rg = Xoroshiro128(1234).generator + >>> rg.standard_normal() + + References + ---------- + .. [1] "xoroshiro+ / xorshift* / xorshift+ generators and the PRNG shootout", + http://xorshift.di.unimi.it/ """ cdef xoroshiro128_state *rng_state cdef prng_t *_prng cdef public object capsule cdef object _ctypes cdef object _cffi + cdef object _generator def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoroshiro128_state)) @@ -71,6 +139,7 @@ cdef class Xoroshiro128: self._ctypes = None self._cffi = None + self._generator = None cdef const char *name = "CorePRNG" self.capsule = PyCapsule_New(self._prng, name, NULL) @@ -95,32 +164,8 @@ cdef class Xoroshiro128: self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - def __random_integer(self, bits=64): - """ - 64-bit Random Integers from the PRNG - - Parameters - ---------- - bits : {32, 64} - Number of random bits to return - - Returns - ------- - rv : int - Next random value - - Notes - ----- - Testing only - """ - if bits == 64: - return xoroshiro128_next64(self.rng_state) - elif bits == 32: - return xoroshiro128_next32(self.rng_state) - else: - raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): + """Private benchmark command""" cdef Py_ssize_t i if method==u'uint64': for i in range(cnt): @@ -133,24 +178,23 @@ cdef class Xoroshiro128: def seed(self, seed=None): """ - seed(seed=None, stream=None) + seed(seed=None) Seed the generator. - This method is called when ``RandomState`` is initialized. It can be - called again to re-seed the generator. For details, see - ``RandomState``. + This method is called at initialized. It can be + called again to re-seed the generator. Parameters ---------- - seed : int, optional - Seed for ``RandomState``. + seed : {int, ndarray}, optional + Seed for PRNG. Can be a single 64 biy unsigned integer or an array + of 64 bit unsigned integers. Raises ------ ValueError If seed values are out of range for the PRNG. - """ ub = 2 ** 64 if seed is None: @@ -160,18 +204,50 @@ cdef class Xoroshiro128: state = random_entropy(4, 'fallback') state = state.view(np.uint64) else: - state = entropy.seed_by_array(seed, 2) + state = seed_by_array(seed, 2) self.rng_state.s[0] = int(state[0]) self.rng_state.s[1] = int(state[1]) self._reset_state_variables() - def jump(self): - xoroshiro128_jump(self.rng_state) + def jump(self, np.npy_intp iter=1): + """ + jump(iter = 1) + + Jumps the state of the random number generator as-if 2**64 random numbers + have been generated. + + Parameters + ---------- + iter : integer, positive + Number of times to jump the state of the rng. + + Returns + ------- + self : Xoroshiro128 + PRNG jumped iter times + + Notes + ----- + Jumping the rng state resets any pre-computed random numbers. This is required + to ensure exact reproducibility. + """ + cdef np.npy_intp i + for i in range(iter): + xoroshiro128_jump(self.rng_state) + self._reset_state_variables() return self @property def state(self): - """Get or set the PRNG state""" + """ + Get or set the PRNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the PRNG + """ state = np.empty(2, dtype=np.uint64) state[0] = self.rng_state.s[0] state[1] = self.rng_state.s[1] @@ -195,6 +271,22 @@ cdef class Xoroshiro128: @property def ctypes(self): + """ + Cytpes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * prng - pointer to the PRNG struct + """ + if self._ctypes is not None: return self._ctypes @@ -216,6 +308,21 @@ cdef class Xoroshiro128: @property def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * prng - pointer to the PRNG struct + """ if self._cffi is not None: return self._cffi try: @@ -231,3 +338,18 @@ cdef class Xoroshiro128: ffi.cast('double (*)(void *)',self._prng.next_double), ffi.cast('void *',self._prng)) return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : core_prng.generator.RandomGenerator + Random generator used this instance as the core PRNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator \ No newline at end of file diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/core_prng/xorshift1024.pyx index 73fa052850bb..761f3403976c 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/core_prng/xorshift1024.pyx @@ -4,11 +4,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np +from common import interface from common cimport * from distributions cimport prng_t -from core_prng.entropy import random_entropy +from core_prng.entropy import random_entropy, seed_by_array import core_prng.pickle -cimport entropy np.import_array() @@ -36,19 +36,95 @@ cdef double xorshift1024_double(void* st) nogil: return uint64_to_double(xorshift1024_next64(st)) cdef class Xorshift1024: - """ - Prototype Core PRNG using xorshift1024 + u""" + Xorshift1024(seed=None) + + Container for the xorshift1024*φ pseudo-random number generator. + + xorshift1024*φ is a 64-bit implementation of Saito and Matsumoto's XSadd + generator [1]_ (see also [2]_, [3]_, [4]_). xorshift1024* has a period of + :math:`2^{1024} - 1` and supports jumping the sequence in increments of + :math:`2^{512}`, which allows multiple non-overlapping sequences to be + generated. + + ``Xorshift1024`` exposes no user-facing API except ``generator``, + ``state``, ``cffi`` and ``ctypes``. Designed for use in a + ``RandomGenerator`` object. + + **Compatibility Guarantee** + + ``Xorshift1024`` guarantees that a fixed seed will always produce the + same results. Parameters ---------- - seed : int, array of int - Integer or array of integers between 0 and 2**64 - 1 + seed : {None, int, array_like}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**64-1], array of integers in + [0, 2**64-1] or ``None`` (the default). If `seed` is ``None``, + then ``xorshift1024.RandomState`` will try to read data from + ``/dev/urandom`` (or the Windows analog) if available. If + unavailable, a 64-bit hash of the time and process ID is used. Notes ----- - Exposes no user-facing API except `get_state` and `set_state`. Designed - for use in a `RandomGenerator` object. + See ``Xoroshiro128`` for a faster implementation that has a smaller + period. + + **Parallel Features** + + ``Xorshift1024`` can be used in parallel applications by + calling the method ``jump`` which advances the state as-if + :math:`2^{512}` random numbers have been generated. This + allows the original sequence to be split so that distinct segments can be used + in each worker process. All generators should be initialized with the same + seed to ensure that the segments come from the same sequence. + + >>> from core_prng import RandomGenerator, Xorshift1024 + >>> rg = [RandomGenerator(Xorshift1024(1234)) for _ in range(10)] + # Advance rg[i] by i jumps + >>> for i in range(10): + ... rg[i].jump(i) + + **State and Seeding** + + The ``Xorshift1024`` state vector consists of a 16 element array + of 64-bit unsigned integers. + + ``Xorshift1024`` is seeded using either a single 64-bit unsigned integer + or a vector of 64-bit unsigned integers. In either case, the input seed is + used as an input (or inputs) for another simple random number generator, + Splitmix64, and the output of this PRNG function is used as the initial state. + Using a single 64-bit value for the seed can only initialize a small range of + the possible initial state values. When using an array, the SplitMix64 state + for producing the ith component of the initial state is XORd with the ith + value of the seed array until the seed array is exhausted. When using an array + the initial state for the SplitMix64 state is 0 so that using a single element + array and using the same value as a scalar will produce the same initial state. + + Examples + -------- + >>> from core_prng import RandomGenerator, Xorshift1024 + >>> rg = RandomGenerator(Xorshift1024(1234)) + >>> rg.standard_normal() + + Identical method using only Xoroshiro128 + + >>> rg = Xorshift10241234).generator + >>> rg.standard_normal() + + References + ---------- + .. [1] "xorshift*/xorshift+ generators and the PRNG shootout", + http://xorshift.di.unimi.it/ + .. [2] Marsaglia, George. "Xorshift RNGs." Journal of Statistical Software + [Online], 8.14, pp. 1 - 6, .2003. + .. [3] Sebastiano Vigna. "An experimental exploration of Marsaglia's xorshift + generators, scrambled." CoRR, abs/1402.6246, 2014. + .. [4] Sebastiano Vigna. "Further scramblings of Marsaglia's xorshift + generators." CoRR, abs/1403.0930, 2014. """ + cdef xorshift1024_state *rng_state cdef prng_t *_prng cdef public object capsule @@ -152,14 +228,37 @@ cdef class Xorshift1024: state = random_entropy(4, 'fallback') state = state.view(np.uint64) else: - state = entropy.seed_by_array(seed, 16) + state = seed_by_array(seed, 16) for i in range(16): self.rng_state.s[i] = int(state[i]) self.rng_state.p = 0 self._reset_state_variables() - def jump(self): - xorshift1024_jump(self.rng_state) + def jump(self, np.npy_intp iter): + """ + jump(iter = 1) + + Jumps the state as-if 2**512 random numbers have been generated + + Parameters + ---------- + iter : integer, positive + Number of times to jump the state of the rng. + + Returns + ------- + self : Xorshift1024 + PRNG jumped iter times + + Notes + ----- + Jumping the rng state resets any pre-computed random numbers. This is required + to ensure exact reproducibility. + """ + cdef np.npy_intp i + for i in range(iter): + xorshift1024_jump(self.rng_state) + self._reset_state_variables() return self @property @@ -186,3 +285,88 @@ cdef class Xorshift1024: self.rng_state.p = value['state']['p'] self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] + + @property + def ctypes(self): + """ + Cytpes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * prng - pointer to the PRNG struct + """ + + if self._ctypes is not None: + return self._ctypes + + import ctypes + + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&xorshift1024_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&xorshift1024_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&xorshift1024_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p(self._prng)) + return self.ctypes + + @property + def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * prng - pointer to the PRNG struct + """ + if self._cffi is not None: + return self._cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') + + ffi = cffi.FFI() + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._prng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._prng.next_uint32), + ffi.cast('double (*)(void *)',self._prng.next_double), + ffi.cast('void *',self._prng)) + return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : core_prng.generator.RandomGenerator + Random generator used this instance as the core PRNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator \ No newline at end of file diff --git a/_randomgen/doc/Makefile b/_randomgen/doc/Makefile new file mode 100644 index 000000000000..ab432f78cf0c --- /dev/null +++ b/_randomgen/doc/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = CorePRNG +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/_randomgen/doc/make.bat b/_randomgen/doc/make.bat new file mode 100644 index 000000000000..4bc049d32ac3 --- /dev/null +++ b/_randomgen/doc/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build +set SPHINXPROJ=CorePRNG + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/_randomgen/doc/source/conf.py b/_randomgen/doc/source/conf.py new file mode 100644 index 000000000000..18c357a103b0 --- /dev/null +++ b/_randomgen/doc/source/conf.py @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/stable/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) +from distutils.version import LooseVersion +# import guzzle_sphinx_theme +import sphinx_rtd_theme +import core_prng + +# -- Project information ----------------------------------------------------- + +project = 'Core PRNG' +copyright = '2018, Kevin Sheppard' +author = 'Kevin Sheppard' + +# The short X.Y version. +version = '.'.join(map(str,LooseVersion(core_prng.__version__).version[:2])) +# The full version, including alpha/beta/rc tags. +release = core_prng.__version__ + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.napoleon', + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.autosummary', + 'sphinx.ext.mathjax', + 'sphinx.ext.githubpages', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +# html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' +html_theme_path = ["_themes", ] +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'CorePRNGdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'CorePRNG.tex', 'Core PRNG Documentation', + 'Kevin Sheppard', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'coreprng', 'Core PRNG Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'CorePRNG', 'Core PRNG Documentation', + author, 'CorePRNG', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Extension configuration ------------------------------------------------- + +# -- Options for intersphinx extension --------------------------------------- + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} + +autosummary_generate=True \ No newline at end of file diff --git a/_randomgen/doc/source/generator.rst b/_randomgen/doc/source/generator.rst new file mode 100644 index 000000000000..2b093d9f6569 --- /dev/null +++ b/_randomgen/doc/source/generator.rst @@ -0,0 +1,74 @@ +Random Generator +---------------- + +.. currentmodule:: core_prng.generator + +Random generator +================ +.. autoclass:: + RandomGenerator + +Simple random data +================== +.. autosummary:: + :toctree: generated/ + + ~RandomGenerator.rand + ~RandomGenerator.randn + ~RandomGenerator.randint + ~RandomGenerator.random_integers + ~RandomGenerator.random_sample + ~RandomGenerator.choice + ~RandomGenerator.bytes + ~RandomGenerator.random_uintegers + ~RandomGenerator.random_raw + +Permutations +============ +.. autosummary:: + :toctree: generated/ + + ~RandomGenerator.shuffle + ~RandomGenerator.permutation + +Distributions +============= +.. autosummary:: + :toctree: generated/ + + ~RandomGenerator.beta + ~RandomGenerator.binomial + ~RandomGenerator.chisquare + ~RandomGenerator.complex_normal + ~RandomGenerator.dirichlet + ~RandomGenerator.exponential + ~RandomGenerator.f + ~RandomGenerator.gamma + ~RandomGenerator.geometric + ~RandomGenerator.gumbel + ~RandomGenerator.hypergeometric + ~RandomGenerator.laplace + ~RandomGenerator.logistic + ~RandomGenerator.lognormal + ~RandomGenerator.logseries + ~RandomGenerator.multinomial + ~RandomGenerator.multivariate_normal + ~RandomGenerator.negative_binomial + ~RandomGenerator.noncentral_chisquare + ~RandomGenerator.noncentral_f + ~RandomGenerator.normal + ~RandomGenerator.pareto + ~RandomGenerator.poisson + ~RandomGenerator.power + ~RandomGenerator.rayleigh + ~RandomGenerator.standard_cauchy + ~RandomGenerator.standard_exponential + ~RandomGenerator.standard_gamma + ~RandomGenerator.standard_normal + ~RandomGenerator.standard_t + ~RandomGenerator.triangular + ~RandomGenerator.uniform + ~RandomGenerator.vonmises + ~RandomGenerator.wald + ~RandomGenerator.weibull + ~RandomGenerator.zipf \ No newline at end of file diff --git a/_randomgen/doc/source/index.rst b/_randomgen/doc/source/index.rst new file mode 100644 index 000000000000..fe1d09abd038 --- /dev/null +++ b/_randomgen/doc/source/index.rst @@ -0,0 +1,22 @@ +.. Core PRNG documentation master file, created by + sphinx-quickstart on Tue Mar 13 20:30:45 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Core PRNG +========= + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + Random Generator + Core Pseudo Random Number Generators + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/_randomgen/doc/source/prng/dsfmt.rst b/_randomgen/doc/source/prng/dsfmt.rst new file mode 100644 index 000000000000..5d3d747194d9 --- /dev/null +++ b/_randomgen/doc/source/prng/dsfmt.rst @@ -0,0 +1,38 @@ +Double SIMD Mersenne Twister (dSFMT) +------------------------------------ + +.. currentmodule:: core_prng.dsfmt + +Random generator +================ +.. autoclass:: DSFMT + +.. autosummary:: + :toctree: generated/ + + ~DSFMT.seed + ~DSFMT.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~DSFMT.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~DSFMT.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~DSFMT.cffi + ~DSFMT.ctypes + + diff --git a/_randomgen/doc/source/prng/index.rst b/_randomgen/doc/source/prng/index.rst new file mode 100644 index 000000000000..07c1a0f07dea --- /dev/null +++ b/_randomgen/doc/source/prng/index.rst @@ -0,0 +1,30 @@ +Core Pseudo Random Number Generators (PRNG) +------------------------------------------- + +Stable PRNGs +============ +These PRNGs will be included in future releases. + + +.. toctree:: + :maxdepth: 1 + + DSFMT + PCG64 + Philox + ThreeFry + XoroShiro128+ + Xorshift1024*φ + + +Experimental PRNGs +================== + +These PRNGs are currently included for testing but are may not be +permanent. + +.. toctree:: + :maxdepth: 1 + + ThreeFry32 + PCG32 \ No newline at end of file diff --git a/_randomgen/doc/source/prng/xoroshiro128.rst b/_randomgen/doc/source/prng/xoroshiro128.rst new file mode 100644 index 000000000000..871527a5a58d --- /dev/null +++ b/_randomgen/doc/source/prng/xoroshiro128.rst @@ -0,0 +1,38 @@ +Xoroshiro128+ +------------- + +.. currentmodule:: core_prng.xoroshiro128 + +Random generator +================ +.. autoclass:: Xoroshiro128 + +.. autosummary:: + :toctree: generated/ + + ~Xoroshiro128.seed + ~Xoroshiro128.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~Xoroshiro128.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~Xoroshiro128.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~Xoroshiro128.cffi + ~Xoroshiro128.ctypes + + diff --git a/_randomgen/doc/source/prng/xorshift1024.rst b/_randomgen/doc/source/prng/xorshift1024.rst new file mode 100644 index 000000000000..1e239733f05d --- /dev/null +++ b/_randomgen/doc/source/prng/xorshift1024.rst @@ -0,0 +1,38 @@ +Xorshift1024*φ +-------------- + +.. currentmodule:: core_prng.xorshift1024 + +Random generator +================ +.. autoclass:: Xorshift1024 + +.. autosummary:: + :toctree: generated/ + + ~Xorshift1024.seed + ~Xorshift1024.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~Xorshift1024.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~Xorshift1024.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~Xorshift1024.cffi + ~Xorshift1024.ctypes + + diff --git a/_randomgen/requirements.txt b/_randomgen/requirements.txt new file mode 100644 index 000000000000..a02ebc02a654 --- /dev/null +++ b/_randomgen/requirements.txt @@ -0,0 +1,4 @@ +numpy +cython +cffi +pandas From 9785c12126277351ba4c8431cdf437a7d0a65d12 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 08:52:30 +0000 Subject: [PATCH 076/279] REF: Rename from Core PRNG to RandomGen Switch canonical name to RandomGen Switch use of prng to brng to indicate basic RNG --- _randomgen/.gitattributes | 2 +- _randomgen/.travis.yml | 6 +- _randomgen/MANIFEST.in | 2 +- _randomgen/README.md | 22 +- _randomgen/appveyor.yml | 2 +- _randomgen/benchmark.py | 12 +- _randomgen/core_prng/distributions.pxd | 123 ----- .../src/distributions/distributions.h | 199 -------- _randomgen/doc/Makefile | 2 +- _randomgen/doc/make.bat | 2 +- _randomgen/doc/source/conf.py | 20 +- _randomgen/doc/source/generator.rst | 2 +- _randomgen/doc/source/index.rst | 6 +- _randomgen/doc/source/prng/dsfmt.rst | 2 +- _randomgen/doc/source/prng/index.rst | 16 +- _randomgen/doc/source/prng/xoroshiro128.rst | 2 +- _randomgen/doc/source/prng/xorshift1024.rst | 2 +- _randomgen/examples/cython/extending.pyx | 18 +- .../cython/extending_distributions.pyx | 10 +- _randomgen/examples/cython/setup.py | 2 +- _randomgen/examples/numba/extending.py | 2 +- .../examples/numba/extending_distributions.py | 18 +- .../{core_prng => randomgen}/__init__.py | 0 .../{core_prng => randomgen}/_testing.py | 0 .../{core_prng => randomgen}/_version.py | 4 +- .../bounded_integers.pxd | 20 +- .../bounded_integers.pxd.in | 4 +- .../bounded_integers.pyx | 54 +- .../bounded_integers.pyx.in | 8 +- .../{core_prng => randomgen}/common.pxd | 50 +- .../{core_prng => randomgen}/common.pyx | 32 +- _randomgen/randomgen/distributions.pxd | 123 +++++ _randomgen/{core_prng => randomgen}/dsfmt.pyx | 64 +-- .../{core_prng => randomgen}/entropy.pyx | 0 .../{core_prng => randomgen}/generator.pyx | 372 +++++++------- .../{core_prng => randomgen}/mt19937.pyx | 48 +- _randomgen/{core_prng => randomgen}/pcg32.pyx | 46 +- _randomgen/{core_prng => randomgen}/pcg64.pyx | 46 +- .../{core_prng => randomgen}/philox.pyx | 46 +- _randomgen/{core_prng => randomgen}/pickle.py | 34 +- .../src/aligned_malloc/aligned_malloc.c | 0 .../src/aligned_malloc/aligned_malloc.h | 0 .../src/common/inttypes.h | 0 .../src/common/stdint.h | 0 .../src/distributions/binomial.h | 0 .../src/distributions/distributions.c | 470 +++++++++--------- .../src/distributions/distributions.h | 199 ++++++++ .../src/distributions/ziggurat.h | 0 .../src/distributions/ziggurat_constants.h | 0 .../src/dsfmt/128-bit-jump.poly.txt | 0 .../src/dsfmt/96-bit-jump.poly.txt | 0 .../src/dsfmt/LICENSE.txt | 0 .../src/dsfmt/calc-jump.cpp | 0 .../src/dsfmt/dSFMT-benchmark.c | 0 .../src/dsfmt/dSFMT-calc-jump.hpp | 0 .../src/dsfmt/dSFMT-common.h | 0 .../src/dsfmt/dSFMT-jump.c | 0 .../src/dsfmt/dSFMT-jump.h | 0 .../src/dsfmt/dSFMT-params.h | 0 .../src/dsfmt/dSFMT-params19937.h | 0 .../src/dsfmt/dSFMT-poly.h | 0 .../src/dsfmt/dSFMT-test-gen.c | 0 .../src/dsfmt/dSFMT.c | 0 .../src/dsfmt/dSFMT.h | 0 .../src/entropy/entropy.c | 0 .../src/entropy/entropy.h | 0 .../src/mt19937/mt19937-benchmark.c | 0 .../src/mt19937/mt19937-jump.c | 0 .../src/mt19937/mt19937-jump.h | 0 .../src/mt19937/mt19937-poly.h | 0 .../src/mt19937/mt19937-test-data-gen.c | 0 .../src/mt19937/mt19937.c | 0 .../src/mt19937/mt19937.h | 0 .../src/mt19937/randomkit.c | 0 .../src/mt19937/randomkit.h | 0 .../src/pcg32/pcg-advance-64.c | 0 .../src/pcg32/pcg32-test-data-gen.c | 0 .../src/pcg32/pcg32.c | 0 .../src/pcg32/pcg32.h | 0 .../src/pcg32/pcg_variants.h | 0 .../src/pcg64/pcg64-benchmark.c | 0 .../src/pcg64/pcg64-test-data-gen.c | 0 .../src/pcg64/pcg64.c | 0 .../src/pcg64/pcg64.h | 0 .../src/pcg64/pcg64.orig.c | 0 .../src/pcg64/pcg64.orig.h | 0 .../src/philox/philox-benchmark.c | 0 .../src/philox/philox-test-data-gen.c | 0 .../src/philox/philox.c | 0 .../src/philox/philox.h | 0 .../src/splitmix64/splitmix64.c | 0 .../src/splitmix64/splitmix64.h | 0 .../src/splitmix64/splitmix64.orig.c | 0 .../src/threefry/threefry-benchmark.c | 0 .../src/threefry/threefry-orig.c | 0 .../src/threefry/threefry-test-data-gen.c | 0 .../src/threefry/threefry.c | 0 .../src/threefry/threefry.h | 0 .../src/threefry32/threefry32-test-data-gen.c | 0 .../src/threefry32/threefry32.c | 0 .../src/threefry32/threefry32.h | 0 .../src/xoroshiro128/xoroshiro128-benchmark.c | 0 .../xoroshiro128/xoroshiro128-test-data-gen.c | 0 .../src/xoroshiro128/xoroshiro128.c | 0 .../src/xoroshiro128/xoroshiro128.h | 0 .../src/xoroshiro128/xoroshiro128plus.orig.c | 0 .../src/xoroshiro128/xoroshiro128plus.orig.h | 0 .../src/xorshift1024/xorshift1024-benchmark.c | 0 .../xorshift1024/xorshift1024-test-data-gen.c | 0 .../src/xorshift1024/xorshift1024.c | 0 .../src/xorshift1024/xorshift1024.h | 0 .../src/xorshift1024/xorshift1024.orig.c | 0 .../src/xorshift1024/xorshift1024.orig.h | 0 .../tests/data/dSFMT-testset-1.csv | 0 .../tests/data/dSFMT-testset-2.csv | 0 .../tests/data/mt19937-testset-1.csv | 0 .../tests/data/mt19937-testset-2.csv | 0 .../tests/data/pcg32-testset-1.csv | 0 .../tests/data/pcg32-testset-2.csv | 0 .../tests/data/pcg64-testset-1.csv | 0 .../tests/data/pcg64-testset-2.csv | 0 .../tests/data/philox-testset-1.csv | 0 .../tests/data/philox-testset-2.csv | 0 .../tests/data/threefry-testset-1.csv | 0 .../tests/data/threefry-testset-2.csv | 0 .../tests/data/threefry32-testset-1.csv | 0 .../tests/data/threefry32-testset-2.csv | 0 .../tests/data/xoroshiro128-testset-1.csv | 0 .../tests/data/xoroshiro128-testset-2.csv | 0 .../tests/data/xorshift1024-testset-1.csv | 0 .../tests/data/xorshift1024-testset-2.csv | 0 .../tests/test_against_numpy.py | 17 +- .../tests/test_direct.py | 81 +-- .../tests/test_numpy_mt19937.py | 44 +- .../tests/test_numpy_mt19937_regressions.py | 7 +- .../tests/test_smoke.py | 78 +-- .../{core_prng => randomgen}/threefry.pyx | 46 +- .../{core_prng => randomgen}/threefry32.pyx | 46 +- .../{core_prng => randomgen}/xoroshiro128.pyx | 62 +-- .../{core_prng => randomgen}/xorshift1024.pyx | 64 +-- _randomgen/setup.cfg | 6 +- _randomgen/setup.py | 60 +-- _randomgen/test.py | 14 - 143 files changed, 1305 insertions(+), 1312 deletions(-) delete mode 100644 _randomgen/core_prng/distributions.pxd delete mode 100644 _randomgen/core_prng/src/distributions/distributions.h rename _randomgen/{core_prng => randomgen}/__init__.py (100%) rename _randomgen/{core_prng => randomgen}/_testing.py (100%) rename _randomgen/{core_prng => randomgen}/_version.py (99%) rename _randomgen/{core_prng => randomgen}/bounded_integers.pxd (65%) rename _randomgen/{core_prng => randomgen}/bounded_integers.pxd.in (94%) rename _randomgen/{core_prng => randomgen}/bounded_integers.pyx (97%) rename _randomgen/{core_prng => randomgen}/bounded_integers.pyx.in (98%) rename _randomgen/{core_prng => randomgen}/common.pxd (66%) rename _randomgen/{core_prng => randomgen}/common.pyx (96%) create mode 100644 _randomgen/randomgen/distributions.pxd rename _randomgen/{core_prng => randomgen}/dsfmt.pyx (89%) rename _randomgen/{core_prng => randomgen}/entropy.pyx (100%) rename _randomgen/{core_prng => randomgen}/generator.pyx (93%) rename _randomgen/{core_prng => randomgen}/mt19937.pyx (82%) rename _randomgen/{core_prng => randomgen}/pcg32.pyx (83%) rename _randomgen/{core_prng => randomgen}/pcg64.pyx (87%) rename _randomgen/{core_prng => randomgen}/philox.pyx (87%) rename _randomgen/{core_prng => randomgen}/pickle.py (65%) rename _randomgen/{core_prng => randomgen}/src/aligned_malloc/aligned_malloc.c (100%) rename _randomgen/{core_prng => randomgen}/src/aligned_malloc/aligned_malloc.h (100%) rename _randomgen/{core_prng => randomgen}/src/common/inttypes.h (100%) rename _randomgen/{core_prng => randomgen}/src/common/stdint.h (100%) rename _randomgen/{core_prng => randomgen}/src/distributions/binomial.h (100%) rename _randomgen/{core_prng => randomgen}/src/distributions/distributions.c (65%) create mode 100644 _randomgen/randomgen/src/distributions/distributions.h rename _randomgen/{core_prng => randomgen}/src/distributions/ziggurat.h (100%) rename _randomgen/{core_prng => randomgen}/src/distributions/ziggurat_constants.h (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/128-bit-jump.poly.txt (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/96-bit-jump.poly.txt (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/LICENSE.txt (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/calc-jump.cpp (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT-benchmark.c (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT-calc-jump.hpp (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT-common.h (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT-jump.c (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT-jump.h (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT-params.h (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT-params19937.h (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT-poly.h (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT-test-gen.c (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT.c (100%) rename _randomgen/{core_prng => randomgen}/src/dsfmt/dSFMT.h (100%) rename _randomgen/{core_prng => randomgen}/src/entropy/entropy.c (100%) rename _randomgen/{core_prng => randomgen}/src/entropy/entropy.h (100%) rename _randomgen/{core_prng => randomgen}/src/mt19937/mt19937-benchmark.c (100%) rename _randomgen/{core_prng => randomgen}/src/mt19937/mt19937-jump.c (100%) rename _randomgen/{core_prng => randomgen}/src/mt19937/mt19937-jump.h (100%) rename _randomgen/{core_prng => randomgen}/src/mt19937/mt19937-poly.h (100%) rename _randomgen/{core_prng => randomgen}/src/mt19937/mt19937-test-data-gen.c (100%) rename _randomgen/{core_prng => randomgen}/src/mt19937/mt19937.c (100%) rename _randomgen/{core_prng => randomgen}/src/mt19937/mt19937.h (100%) rename _randomgen/{core_prng => randomgen}/src/mt19937/randomkit.c (100%) rename _randomgen/{core_prng => randomgen}/src/mt19937/randomkit.h (100%) rename _randomgen/{core_prng => randomgen}/src/pcg32/pcg-advance-64.c (100%) rename _randomgen/{core_prng => randomgen}/src/pcg32/pcg32-test-data-gen.c (100%) rename _randomgen/{core_prng => randomgen}/src/pcg32/pcg32.c (100%) rename _randomgen/{core_prng => randomgen}/src/pcg32/pcg32.h (100%) rename _randomgen/{core_prng => randomgen}/src/pcg32/pcg_variants.h (100%) rename _randomgen/{core_prng => randomgen}/src/pcg64/pcg64-benchmark.c (100%) rename _randomgen/{core_prng => randomgen}/src/pcg64/pcg64-test-data-gen.c (100%) rename _randomgen/{core_prng => randomgen}/src/pcg64/pcg64.c (100%) rename _randomgen/{core_prng => randomgen}/src/pcg64/pcg64.h (100%) rename _randomgen/{core_prng => randomgen}/src/pcg64/pcg64.orig.c (100%) rename _randomgen/{core_prng => randomgen}/src/pcg64/pcg64.orig.h (100%) rename _randomgen/{core_prng => randomgen}/src/philox/philox-benchmark.c (100%) rename _randomgen/{core_prng => randomgen}/src/philox/philox-test-data-gen.c (100%) rename _randomgen/{core_prng => randomgen}/src/philox/philox.c (100%) rename _randomgen/{core_prng => randomgen}/src/philox/philox.h (100%) rename _randomgen/{core_prng => randomgen}/src/splitmix64/splitmix64.c (100%) rename _randomgen/{core_prng => randomgen}/src/splitmix64/splitmix64.h (100%) rename _randomgen/{core_prng => randomgen}/src/splitmix64/splitmix64.orig.c (100%) rename _randomgen/{core_prng => randomgen}/src/threefry/threefry-benchmark.c (100%) rename _randomgen/{core_prng => randomgen}/src/threefry/threefry-orig.c (100%) rename _randomgen/{core_prng => randomgen}/src/threefry/threefry-test-data-gen.c (100%) rename _randomgen/{core_prng => randomgen}/src/threefry/threefry.c (100%) rename _randomgen/{core_prng => randomgen}/src/threefry/threefry.h (100%) rename _randomgen/{core_prng => randomgen}/src/threefry32/threefry32-test-data-gen.c (100%) rename _randomgen/{core_prng => randomgen}/src/threefry32/threefry32.c (100%) rename _randomgen/{core_prng => randomgen}/src/threefry32/threefry32.h (100%) rename _randomgen/{core_prng => randomgen}/src/xoroshiro128/xoroshiro128-benchmark.c (100%) rename _randomgen/{core_prng => randomgen}/src/xoroshiro128/xoroshiro128-test-data-gen.c (100%) rename _randomgen/{core_prng => randomgen}/src/xoroshiro128/xoroshiro128.c (100%) rename _randomgen/{core_prng => randomgen}/src/xoroshiro128/xoroshiro128.h (100%) rename _randomgen/{core_prng => randomgen}/src/xoroshiro128/xoroshiro128plus.orig.c (100%) rename _randomgen/{core_prng => randomgen}/src/xoroshiro128/xoroshiro128plus.orig.h (100%) rename _randomgen/{core_prng => randomgen}/src/xorshift1024/xorshift1024-benchmark.c (100%) rename _randomgen/{core_prng => randomgen}/src/xorshift1024/xorshift1024-test-data-gen.c (100%) rename _randomgen/{core_prng => randomgen}/src/xorshift1024/xorshift1024.c (100%) rename _randomgen/{core_prng => randomgen}/src/xorshift1024/xorshift1024.h (100%) rename _randomgen/{core_prng => randomgen}/src/xorshift1024/xorshift1024.orig.c (100%) rename _randomgen/{core_prng => randomgen}/src/xorshift1024/xorshift1024.orig.h (100%) rename _randomgen/{core_prng => randomgen}/tests/data/dSFMT-testset-1.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/dSFMT-testset-2.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/mt19937-testset-1.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/mt19937-testset-2.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/pcg32-testset-1.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/pcg32-testset-2.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/pcg64-testset-1.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/pcg64-testset-2.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/philox-testset-1.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/philox-testset-2.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/threefry-testset-1.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/threefry-testset-2.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/threefry32-testset-1.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/threefry32-testset-2.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/xoroshiro128-testset-1.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/xoroshiro128-testset-2.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/xorshift1024-testset-1.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/data/xorshift1024-testset-2.csv (100%) rename _randomgen/{core_prng => randomgen}/tests/test_against_numpy.py (97%) rename _randomgen/{core_prng => randomgen}/tests/test_direct.py (85%) rename _randomgen/{core_prng => randomgen}/tests/test_numpy_mt19937.py (98%) rename _randomgen/{core_prng => randomgen}/tests/test_numpy_mt19937_regressions.py (97%) rename _randomgen/{core_prng => randomgen}/tests/test_smoke.py (94%) rename _randomgen/{core_prng => randomgen}/threefry.pyx (86%) rename _randomgen/{core_prng => randomgen}/threefry32.pyx (86%) rename _randomgen/{core_prng => randomgen}/xoroshiro128.pyx (88%) rename _randomgen/{core_prng => randomgen}/xorshift1024.pyx (88%) delete mode 100644 _randomgen/test.py diff --git a/_randomgen/.gitattributes b/_randomgen/.gitattributes index c5ff9551eda2..9b447556a4c4 100644 --- a/_randomgen/.gitattributes +++ b/_randomgen/.gitattributes @@ -1 +1 @@ -core_prng/_version.py export-subst +randomgen/_version.py export-subst diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 7da8cb80b1ab..e7304ee57454 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -37,8 +37,8 @@ before_install: - PKGS="${PKGS} numpy"; if [ ${NUMPY} ]; then PKGS="${PKGS}=${NUMPY}"; fi - PKGS="${PKGS} Cython"; if [ ${CYTHON} ]; then PKGS="${PKGS}=${CYTHON}"; fi - PKGS="${PKGS} pandas"; if [ ${PANDAS} ]; then PKGS="${PKGS}=${PANDAS}"; fi - - conda create -n core-prng-test ${PKGS} pytest setuptools nose --quiet - - source activate core-prng-test + - conda create -n randomgen-test ${PKGS} pytest setuptools nose --quiet + - source activate randomgen-test - pip install tempita -q install: @@ -46,7 +46,7 @@ install: script: - set -e - - pytest core_prng + - pytest randomgen - | if [[ -z ${NUMPY} ]]; then python benchmark.py; diff --git a/_randomgen/MANIFEST.in b/_randomgen/MANIFEST.in index 14d24dca926c..929dfdb24725 100644 --- a/_randomgen/MANIFEST.in +++ b/_randomgen/MANIFEST.in @@ -1,2 +1,2 @@ include versioneer.py -include core_prng/_version.py +include randomgen/_version.py diff --git a/_randomgen/README.md b/_randomgen/README.md index 19f216b3eaf4..1fd99e875b45 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -1,9 +1,9 @@ -# Core PRNG +# RandomGen -[![Travis Build Status](https://travis-ci.org/bashtage/ng-numpy-randomstate.svg?branch=master)](https://travis-ci.org/bashtage/core-prng) -[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true)](https://ci.appveyor.com/project/bashtage/core-prng/branch/master) +[![Travis Build Status](https://travis-ci.org/bashtage/ng-numpy-randomstate.svg?branch=master)](https://travis-ci.org/bashtage/randomgen) +[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true)](https://ci.appveyor.com/project/bashtage/randomgen/branch/master) -Experimental Core Pseudo Random Number Generator interface for future +Random Number Generator using settable Basic RNG interface for future NumPy RandomState evolution. This is a library and generic interface for alternative random @@ -11,7 +11,7 @@ generators in Python and NumPy. ### Compatibility Warning -Core PRNG no longer supports Box-Muller normal variates and so it not +RandomGen no longer supports Box-Muller normal variates and so it not 100% compatible with NumPy (or randomstate). Box-Muller normals are slow to generate and all functions which previously relied on Box-Muller normals now use the faster Ziggurat implementation. @@ -22,7 +22,7 @@ normals now use the faster Ziggurat implementation. ```python # import numpy.random as rnd -from core_prng import RandomGenerator, MT19937 +from randomgen import RandomGenerator, MT19937 rnd = RandomGenerator(MT19937()) x = rnd.standard_normal(100) y = rnd.random_sample(100) @@ -36,7 +36,7 @@ z = rnd.randn(10,10) exponential and standard gamma using the Ziggurat method ```python -from core_prng import RandomGenerator +from randomgen import RandomGenerator # Use Xoroshiro128 rnd = RandomGenerator() w = rnd.standard_normal(10000, method='zig') @@ -110,7 +110,7 @@ PRNG implementation. or 64-bit (`[0, 2**64-1]`) * `jump` - Jumps RNGs that support it. `jump` moves the state a great distance. _Only available if supported by the RNG._ -* `advance` - Advanced the core RNG 'as-if' a number of draws were made, +* `advance` - Advanced the RNG 'as-if' a number of draws were made, without actually drawing the numbers. _Only available if supported by the RNG._ @@ -133,7 +133,7 @@ The version matched the latest version of NumPy where ## Documentation An occasionally updated build of the documentation is available on -[my GitHub pages](http://bashtage.github.io/core-prng/). +[my GitHub pages](http://bashtage.github.io/randomgen/). ## Plans This module is essentially complete. There are a few rough edges that @@ -188,10 +188,10 @@ compiler. ## Using -The separate generators are importable from `core_prng` +The separate generators are importable from `randomgen` ```python -from core_prng import RandomGenerator, ThreeFry, PCG64, MT19937 +from randomgen import RandomGenerator, ThreeFry, PCG64, MT19937 rg = RandomGenerator(ThreeFry()) rg.random_sample(100) diff --git a/_randomgen/appveyor.yml b/_randomgen/appveyor.yml index 25b2f0c54337..8280f54b64e7 100644 --- a/_randomgen/appveyor.yml +++ b/_randomgen/appveyor.yml @@ -26,7 +26,7 @@ build_script: - set "GIT_DIR=%cd%" test_script: - - pytest core_prng + - pytest randomgen on_success: - cd %GIT_DIR%\ diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 462f405fe5cc..665f63c26570 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -10,12 +10,12 @@ SETUP = ''' import numpy as np -if '{prng}' == 'numpy': +if '{brng}' == 'numpy': import numpy.random rg = numpy.random.RandomState() else: - from core_prng import RandomGenerator, {prng} - rg = RandomGenerator({prng}()) + from randomgen import RandomGenerator, {brng} + rg = RandomGenerator({brng}()) rg.random_sample() ''' @@ -44,9 +44,9 @@ def run_timer(dist, command, numpy_command=None, setup='', random_type=''): numpy_command = command res = {} - for prng in PRNGS: - cmd = numpy_command if prng == 'numpy' else command - res[prng] = timer(cmd, setup=setup.format(prng=prng)) + for brng in PRNGS: + cmd = numpy_command if brng == 'numpy' else command + res[brng] = timer(cmd, setup=setup.format(brng=brng)) s = pd.Series(res) t = s.apply(lambda x: '{0:0.2f} ms'.format(x)) diff --git a/_randomgen/core_prng/distributions.pxd b/_randomgen/core_prng/distributions.pxd deleted file mode 100644 index 44f3520690ef..000000000000 --- a/_randomgen/core_prng/distributions.pxd +++ /dev/null @@ -1,123 +0,0 @@ -from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, - int8_t, int16_t, int32_t, int64_t, intptr_t) -import numpy as np -cimport numpy as np - -cdef extern from "src/distributions/distributions.h": - - struct s_binomial_t: - int has_binomial - double psave - int64_t nsave - double r - double q - double fm - int64_t m - double p1 - double xm - double xl - double xr - double c - double laml - double lamr - double p2 - double p3 - double p4 - - ctypedef s_binomial_t binomial_t - - struct prng: - void *state - uint64_t (*next_uint64)(void *st) nogil - uint32_t (*next_uint32)(void *st) nogil - double (*next_double)(void *st) nogil - uint64_t (*next_raw)(void *st) nogil - - ctypedef prng prng_t - - double random_sample(prng_t *prng_state) nogil - double random_standard_exponential(prng_t *prng_state) nogil - double random_standard_exponential_zig(prng_t *prng_state) nogil - double random_gauss_zig(prng_t* prng_state) nogil - double random_standard_gamma_zig(prng_t *prng_state, double shape) nogil - - float random_sample_f(prng_t *prng_state) nogil - float random_standard_exponential_f(prng_t *prng_state) nogil - float random_standard_exponential_zig_f(prng_t *prng_state) nogil - float random_gauss_zig_f(prng_t* prng_state) nogil - float random_standard_gamma_f(prng_t *prng_state, float shape) nogil - float random_standard_gamma_zig_f(prng_t *prng_state, float shape) nogil - - int64_t random_positive_int64(prng_t *prng_state) nogil - int32_t random_positive_int32(prng_t *prng_state) nogil - int64_t random_positive_int(prng_t *prng_state) nogil - uint64_t random_uint(prng_t *prng_state) nogil - - double random_normal_zig(prng_t *prng_state, double loc, double scale) nogil - - double random_gamma(prng_t *prng_state, double shape, double scale) nogil - float random_gamma_float(prng_t *prng_state, float shape, float scale) nogil - - double random_exponential(prng_t *prng_state, double scale) nogil - double random_uniform(prng_t *prng_state, double lower, double range) nogil - double random_beta(prng_t *prng_state, double a, double b) nogil - double random_chisquare(prng_t *prng_state, double df) nogil - double random_f(prng_t *prng_state, double dfnum, double dfden) nogil - double random_standard_cauchy(prng_t *prng_state) nogil - double random_pareto(prng_t *prng_state, double a) nogil - double random_weibull(prng_t *prng_state, double a) nogil - double random_power(prng_t *prng_state, double a) nogil - double random_laplace(prng_t *prng_state, double loc, double scale) nogil - double random_gumbel(prng_t *prng_state, double loc, double scale) nogil - double random_logistic(prng_t *prng_state, double loc, double scale) nogil - double random_lognormal(prng_t *prng_state, double mean, double sigma) nogil - double random_rayleigh(prng_t *prng_state, double mode) nogil - double random_standard_t(prng_t *prng_state, double df) nogil - double random_noncentral_chisquare(prng_t *prng_state, double df, - double nonc) nogil - double random_noncentral_f(prng_t *prng_state, double dfnum, - double dfden, double nonc) nogil - double random_wald(prng_t *prng_state, double mean, double scale) nogil - double random_vonmises(prng_t *prng_state, double mu, double kappa) nogil - double random_triangular(prng_t *prng_state, double left, double mode, - double right) nogil - - int64_t random_poisson(prng_t *prng_state, double lam) nogil - int64_t random_negative_binomial(prng_t *prng_state, double n, double p) nogil - int64_t random_binomial(prng_t *prng_state, double p, int64_t n, binomial_t *binomial) nogil - int64_t random_logseries(prng_t *prng_state, double p) nogil - int64_t random_geometric_search(prng_t *prng_state, double p) nogil - int64_t random_geometric_inversion(prng_t *prng_state, double p) nogil - int64_t random_geometric(prng_t *prng_state, double p) nogil - int64_t random_zipf(prng_t *prng_state, double a) nogil - int64_t random_hypergeometric(prng_t *prng_state, int64_t good, int64_t bad, - int64_t sample) nogil - uint64_t random_interval(prng_t *prng_state, uint64_t max) nogil - uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, - uint64_t rng, uint64_t mask) nogil - uint32_t random_buffered_bounded_uint32(prng_t *prng_state, uint32_t off, - uint32_t rng, uint32_t mask, - int *bcnt, uint32_t *buf) nogil - - uint16_t random_buffered_bounded_uint16(prng_t *prng_state, uint16_t off, - uint16_t rng, uint16_t mask, - int *bcnt, uint32_t *buf) nogil - uint8_t random_buffered_bounded_uint8(prng_t *prng_state, uint8_t off, - uint8_t rng, uint8_t mask, - int *bcnt, uint32_t *buf) nogil - np.npy_bool random_buffered_bounded_bool(prng_t *prng_state, np.npy_bool off, - np.npy_bool rng, np.npy_bool mask, - int *bcnt, uint32_t *buf) nogil - void random_bounded_uint64_fill(prng_t *prng_state, uint64_t off, - uint64_t rng, np.npy_intp cnt, - uint64_t *out) nogil - void random_bounded_uint32_fill(prng_t *prng_state, uint32_t off, - uint32_t rng, np.npy_intp cnt, - uint32_t *out) nogil - void random_bounded_uint16_fill(prng_t *prng_state, uint16_t off, - uint16_t rng, np.npy_intp cnt, - uint16_t *out) nogil - void random_bounded_uint8_fill(prng_t *prng_state, uint8_t off, - uint8_t rng, np.npy_intp cnt, uint8_t *out) nogil - void random_bounded_bool_fill(prng_t *prng_state, np.npy_bool off, - np.npy_bool rng, np.npy_intp cnt, np.npy_bool *out) nogil diff --git a/_randomgen/core_prng/src/distributions/distributions.h b/_randomgen/core_prng/src/distributions/distributions.h deleted file mode 100644 index c5050d400ea6..000000000000 --- a/_randomgen/core_prng/src/distributions/distributions.h +++ /dev/null @@ -1,199 +0,0 @@ -#include -#ifdef _WIN32 -#if _MSC_VER == 1500 -#include "../common/stdint.h" -typedef int bool; -#define false 0 -#define true 1 -#else -#include -#include -#endif -#else -#include -#include -#endif - -#include "Python.h" -#include "numpy/npy_common.h" -#include - -#ifdef _WIN32 -#if _MSC_VER == 1500 - -static NPY_INLINE int64_t llabs(int64_t x) { - int64_t o; - if (x < 0) { - o = -x; - } else { - o = x; - } - return o; -} -#endif -#endif - -#ifdef DLL_EXPORT -#define DECLDIR __declspec(dllexport) -#else -#define DECLDIR extern -#endif - -#ifndef min -#define min(x, y) ((x < y) ? x : y) -#define max(x, y) ((x > y) ? x : y) -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846264338328 -#endif - -typedef struct s_binomial_t { - int has_binomial; /* !=0: following parameters initialized for binomial */ - double psave; - int64_t nsave; - double r; - double q; - double fm; - int64_t m; - double p1; - double xm; - double xl; - double xr; - double c; - double laml; - double lamr; - double p2; - double p3; - double p4; -} binomial_t; - -typedef struct prng { - void *state; - uint64_t (*next_uint64)(void *st); - uint32_t (*next_uint32)(void *st); - double (*next_double)(void *st); - uint64_t (*next_raw)(void *st); -} prng_t; - -/* Inline generators for internal use */ -static NPY_INLINE uint32_t random_uint32(prng_t *prng_state) { - return prng_state->next_uint32(prng_state->state); -} - -static NPY_INLINE uint64_t random_uint64(prng_t *prng_state) { - return prng_state->next_uint64(prng_state->state); -} - -static NPY_INLINE float random_float(prng_t *prng_state) { - return (random_uint32(prng_state) >> 9) * (1.0f / 8388608.0f); -} - -static NPY_INLINE double random_double(prng_t *prng_state) { - return prng_state->next_double(prng_state->state); -} - -DECLDIR float random_sample_f(prng_t *prng_state); -DECLDIR double random_sample(prng_t *prng_state); - -DECLDIR int64_t random_positive_int64(prng_t *prng_state); -DECLDIR int32_t random_positive_int32(prng_t *prng_state); -DECLDIR int64_t random_positive_int(prng_t *prng_state); -DECLDIR uint64_t random_uint(prng_t *prng_state); - -DECLDIR double random_standard_exponential(prng_t *prng_state); -DECLDIR float random_standard_exponential_f(prng_t *prng_state); -DECLDIR double random_standard_exponential_zig(prng_t *prng_state); -DECLDIR float random_standard_exponential_zig_f(prng_t *prng_state); - -/* -DECLDIR double random_gauss(prng_t *prng_state); -DECLDIR float random_gauss_f(prng_t *prng_state); -*/ -DECLDIR double random_gauss_zig(prng_t *prng_state); -DECLDIR float random_gauss_zig_f(prng_t *prng_state); - -/* -DECLDIR double random_standard_gamma(prng_t *prng_state, double shape); -DECLDIR float random_standard_gamma_f(prng_t *prng_state, float shape); -*/ -DECLDIR double random_standard_gamma_zig(prng_t *prng_state, double shape); -DECLDIR float random_standard_gamma_zig_f(prng_t *prng_state, float shape); - -/* -DECLDIR double random_normal(prng_t *prng_state, double loc, double scale); -*/ -DECLDIR double random_normal_zig(prng_t *prng_state, double loc, double scale); - -DECLDIR double random_gamma(prng_t *prng_state, double shape, double scale); -DECLDIR float random_gamma_float(prng_t *prng_state, float shape, float scale); - -DECLDIR double random_exponential(prng_t *prng_state, double scale); -DECLDIR double random_uniform(prng_t *prng_state, double lower, double range); -DECLDIR double random_beta(prng_t *prng_state, double a, double b); -DECLDIR double random_chisquare(prng_t *prng_state, double df); -DECLDIR double random_f(prng_t *prng_state, double dfnum, double dfden); -DECLDIR double random_standard_cauchy(prng_t *prng_state); -DECLDIR double random_pareto(prng_t *prng_state, double a); -DECLDIR double random_weibull(prng_t *prng_state, double a); -DECLDIR double random_power(prng_t *prng_state, double a); -DECLDIR double random_laplace(prng_t *prng_state, double loc, double scale); -DECLDIR double random_gumbel(prng_t *prng_state, double loc, double scale); -DECLDIR double random_logistic(prng_t *prng_state, double loc, double scale); -DECLDIR double random_lognormal(prng_t *prng_state, double mean, double sigma); -DECLDIR double random_rayleigh(prng_t *prng_state, double mode); -DECLDIR double random_standard_t(prng_t *prng_state, double df); -DECLDIR double random_noncentral_chisquare(prng_t *prng_state, double df, - double nonc); -DECLDIR double random_noncentral_f(prng_t *prng_state, double dfnum, - double dfden, double nonc); -DECLDIR double random_wald(prng_t *prng_state, double mean, double scale); -DECLDIR double random_vonmises(prng_t *prng_state, double mu, double kappa); -DECLDIR double random_triangular(prng_t *prng_state, double left, double mode, - double right); - -DECLDIR int64_t random_poisson(prng_t *prng_state, double lam); -DECLDIR int64_t random_negative_binomial(prng_t *prng_state, double n, - double p); -DECLDIR int64_t random_binomial(prng_t *prng_state, double p, int64_t n, - binomial_t *binomial); -DECLDIR int64_t random_logseries(prng_t *prng_state, double p); -DECLDIR int64_t random_geometric_search(prng_t *prng_state, double p); -DECLDIR int64_t random_geometric_inversion(prng_t *prng_state, double p); -DECLDIR int64_t random_geometric(prng_t *prng_state, double p); -DECLDIR int64_t random_zipf(prng_t *prng_state, double a); -DECLDIR int64_t random_hypergeometric(prng_t *prng_state, int64_t good, - int64_t bad, int64_t sample); - -DECLDIR uint64_t random_interval(prng_t *prng_state, uint64_t max); -DECLDIR uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, - uint64_t rng, uint64_t mask); -DECLDIR uint32_t random_buffered_bounded_uint32(prng_t *prng_state, - uint32_t off, uint32_t rng, - uint32_t mask, int *bcnt, - uint32_t *buf); - -DECLDIR uint16_t random_buffered_bounded_uint16(prng_t *prng_state, - uint16_t off, uint16_t rng, - uint16_t mask, int *bcnt, - uint32_t *buf); -DECLDIR uint8_t random_buffered_bounded_uint8(prng_t *prng_state, uint8_t off, - uint8_t rng, uint8_t mask, - int *bcnt, uint32_t *buf); -DECLDIR npy_bool random_buffered_bounded_bool(prng_t *prng_state, npy_bool off, - npy_bool rng, npy_bool mask, - int *bcnt, uint32_t *buf); -DECLDIR void random_bounded_uint64_fill(prng_t *prng_state, uint64_t off, - uint64_t rng, npy_intp cnt, - uint64_t *out); -DECLDIR void random_bounded_uint32_fill(prng_t *prng_state, uint32_t off, - uint32_t rng, npy_intp cnt, - uint32_t *out); -DECLDIR void random_bounded_uint16_fill(prng_t *prng_state, uint16_t off, - uint16_t rng, npy_intp cnt, - uint16_t *out); -DECLDIR void random_bounded_uint8_fill(prng_t *prng_state, uint8_t off, - uint8_t rng, npy_intp cnt, uint8_t *out); -DECLDIR void random_bounded_bool_fill(prng_t *prng_state, npy_bool off, - npy_bool rng, npy_intp cnt, - npy_bool *out); diff --git a/_randomgen/doc/Makefile b/_randomgen/doc/Makefile index ab432f78cf0c..1ee9d3660c0d 100644 --- a/_randomgen/doc/Makefile +++ b/_randomgen/doc/Makefile @@ -4,7 +4,7 @@ # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build -SPHINXPROJ = CorePRNG +SPHINXPROJ = RandomGen SOURCEDIR = source BUILDDIR = build diff --git a/_randomgen/doc/make.bat b/_randomgen/doc/make.bat index 4bc049d32ac3..e5a098a3426e 100644 --- a/_randomgen/doc/make.bat +++ b/_randomgen/doc/make.bat @@ -9,7 +9,7 @@ if "%SPHINXBUILD%" == "" ( ) set SOURCEDIR=source set BUILDDIR=build -set SPHINXPROJ=CorePRNG +set SPHINXPROJ=RandomGen if "%1" == "" goto help diff --git a/_randomgen/doc/source/conf.py b/_randomgen/doc/source/conf.py index 18c357a103b0..3ff696214888 100644 --- a/_randomgen/doc/source/conf.py +++ b/_randomgen/doc/source/conf.py @@ -18,18 +18,18 @@ from distutils.version import LooseVersion # import guzzle_sphinx_theme import sphinx_rtd_theme -import core_prng +import randomgen # -- Project information ----------------------------------------------------- -project = 'Core PRNG' +project = 'RandomGen' copyright = '2018, Kevin Sheppard' author = 'Kevin Sheppard' # The short X.Y version. -version = '.'.join(map(str,LooseVersion(core_prng.__version__).version[:2])) +version = '.'.join(map(str, LooseVersion(randomgen.__version__).version[:2])) # The full version, including alpha/beta/rc tags. -release = core_prng.__version__ +release = randomgen.__version__ # -- General configuration --------------------------------------------------- @@ -111,7 +111,7 @@ # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'CorePRNGdoc' +htmlhelp_basename = 'RandomGendoc' # -- Options for LaTeX output ------------------------------------------------ @@ -138,7 +138,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'CorePRNG.tex', 'Core PRNG Documentation', + (master_doc, 'RandomGen.tex', 'RandomGen Documentation', 'Kevin Sheppard', 'manual'), ] @@ -148,7 +148,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'coreprng', 'Core PRNG Documentation', + (master_doc, 'RandomGen', 'RandomGen Documentation', [author], 1) ] @@ -159,8 +159,8 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'CorePRNG', 'Core PRNG Documentation', - author, 'CorePRNG', 'One line description of project.', + (master_doc, 'RandomGen', 'RandomGen Documentation', + author, 'RandomGen', 'One line description of project.', 'Miscellaneous'), ] @@ -172,4 +172,4 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'https://docs.python.org/': None} -autosummary_generate=True \ No newline at end of file +autosummary_generate = True diff --git a/_randomgen/doc/source/generator.rst b/_randomgen/doc/source/generator.rst index 2b093d9f6569..9f2e69a167b0 100644 --- a/_randomgen/doc/source/generator.rst +++ b/_randomgen/doc/source/generator.rst @@ -1,7 +1,7 @@ Random Generator ---------------- -.. currentmodule:: core_prng.generator +.. currentmodule:: randomgen.generator Random generator ================ diff --git a/_randomgen/doc/source/index.rst b/_randomgen/doc/source/index.rst index fe1d09abd038..067416635ab8 100644 --- a/_randomgen/doc/source/index.rst +++ b/_randomgen/doc/source/index.rst @@ -1,9 +1,9 @@ -.. Core PRNG documentation master file, created by +.. RandomGen documentation master file, created by sphinx-quickstart on Tue Mar 13 20:30:45 2018. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Core PRNG +RandomGen ========= .. toctree:: @@ -11,7 +11,7 @@ Core PRNG :caption: Contents: Random Generator - Core Pseudo Random Number Generators + Basic Random Number Generators Indices and tables diff --git a/_randomgen/doc/source/prng/dsfmt.rst b/_randomgen/doc/source/prng/dsfmt.rst index 5d3d747194d9..2f5ed0ba77de 100644 --- a/_randomgen/doc/source/prng/dsfmt.rst +++ b/_randomgen/doc/source/prng/dsfmt.rst @@ -1,7 +1,7 @@ Double SIMD Mersenne Twister (dSFMT) ------------------------------------ -.. currentmodule:: core_prng.dsfmt +.. currentmodule:: randomgen.dsfmt Random generator ================ diff --git a/_randomgen/doc/source/prng/index.rst b/_randomgen/doc/source/prng/index.rst index 07c1a0f07dea..8aebf16813e0 100644 --- a/_randomgen/doc/source/prng/index.rst +++ b/_randomgen/doc/source/prng/index.rst @@ -1,9 +1,9 @@ -Core Pseudo Random Number Generators (PRNG) -------------------------------------------- +Basic Random Number Generators +------------------------------ -Stable PRNGs -============ -These PRNGs will be included in future releases. +Stable RNGs +=========== +These RNGs will be included in future releases. .. toctree:: @@ -17,10 +17,10 @@ These PRNGs will be included in future releases. Xorshift1024*φ -Experimental PRNGs -================== +Experimental RNGs +================= -These PRNGs are currently included for testing but are may not be +These RNGs are currently included for testing but are may not be permanent. .. toctree:: diff --git a/_randomgen/doc/source/prng/xoroshiro128.rst b/_randomgen/doc/source/prng/xoroshiro128.rst index 871527a5a58d..768ace408806 100644 --- a/_randomgen/doc/source/prng/xoroshiro128.rst +++ b/_randomgen/doc/source/prng/xoroshiro128.rst @@ -1,7 +1,7 @@ Xoroshiro128+ ------------- -.. currentmodule:: core_prng.xoroshiro128 +.. currentmodule:: randomgen.xoroshiro128 Random generator ================ diff --git a/_randomgen/doc/source/prng/xorshift1024.rst b/_randomgen/doc/source/prng/xorshift1024.rst index 1e239733f05d..87adc9821446 100644 --- a/_randomgen/doc/source/prng/xorshift1024.rst +++ b/_randomgen/doc/source/prng/xorshift1024.rst @@ -1,7 +1,7 @@ Xorshift1024*φ -------------- -.. currentmodule:: core_prng.xorshift1024 +.. currentmodule:: randomgen.xorshift1024 Random generator ================ diff --git a/_randomgen/examples/cython/extending.pyx b/_randomgen/examples/cython/extending.pyx index f09563aff5ee..420bb17eaa37 100644 --- a/_randomgen/examples/cython/extending.pyx +++ b/_randomgen/examples/cython/extending.pyx @@ -3,15 +3,15 @@ cimport numpy as np cimport cython from libc.stdint cimport uint32_t from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer -from core_prng.common cimport prng_t -from core_prng.xoroshiro128 import Xoroshiro128 +from randomgen.common cimport brng_t +from randomgen.xoroshiro128 import Xoroshiro128 np.import_array() def uniform_mean(Py_ssize_t N): cdef Py_ssize_t i - cdef prng_t *rng - cdef const char *capsule_name = "CorePRNG" + cdef brng_t *rng + cdef const char *capsule_name = "BasicRNG" cdef double[::1] random_values cdef np.ndarray randoms @@ -19,14 +19,14 @@ def uniform_mean(Py_ssize_t N): capsule = x.capsule if not PyCapsule_IsValid(capsule, capsule_name): raise ValueError("Invalid pointer to anon_func_state") - rng = PyCapsule_GetPointer(capsule, capsule_name) + rng = PyCapsule_GetPointer(capsule, capsule_name) random_values = np.empty(N) for i in range(N): random_values[i] = rng.next_double(rng.state) randoms = np.asarray(random_values) return randoms.mean() -cdef uint32_t bounded_uint(uint32_t lb, uint32_t ub, prng_t *rng): +cdef uint32_t bounded_uint(uint32_t lb, uint32_t ub, brng_t *rng): cdef uint32_t mask, delta, val mask = delta = ub - lb mask |= mask >> 1 @@ -45,9 +45,9 @@ cdef uint32_t bounded_uint(uint32_t lb, uint32_t ub, prng_t *rng): @cython.wraparound(False) def bounded_uints(uint32_t lb, uint32_t ub, Py_ssize_t n): cdef Py_ssize_t i - cdef prng_t *rng + cdef brng_t *rng cdef uint32_t[::1] out - cdef const char *capsule_name = "CorePRNG" + cdef const char *capsule_name = "BasicRNG" x = Xoroshiro128() out = np.empty(n, dtype=np.uint32) @@ -55,7 +55,7 @@ def bounded_uints(uint32_t lb, uint32_t ub, Py_ssize_t n): if not PyCapsule_IsValid(capsule, capsule_name): raise ValueError("Invalid pointer to anon_func_state") - rng = PyCapsule_GetPointer(capsule, capsule_name) + rng = PyCapsule_GetPointer(capsule, capsule_name) for i in range(n): out[i] = bounded_uint(lb, ub, rng) diff --git a/_randomgen/examples/cython/extending_distributions.pyx b/_randomgen/examples/cython/extending_distributions.pyx index 65ff44f9320f..a5fea174aa49 100644 --- a/_randomgen/examples/cython/extending_distributions.pyx +++ b/_randomgen/examples/cython/extending_distributions.pyx @@ -2,22 +2,22 @@ import numpy as np cimport numpy as np cimport cython from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer -from core_prng.common cimport * -from core_prng.xoroshiro128 import Xoroshiro128 +from randomgen.common cimport * +from randomgen.xoroshiro128 import Xoroshiro128 @cython.boundscheck(False) @cython.wraparound(False) def normals_zig(Py_ssize_t n): cdef Py_ssize_t i - cdef prng_t *rng - cdef const char *capsule_name = "CorePRNG" + cdef brng_t *rng + cdef const char *capsule_name = "BasicRNG" cdef double[::1] random_values x = Xoroshiro128() capsule = x.capsule if not PyCapsule_IsValid(capsule, capsule_name): raise ValueError("Invalid pointer to anon_func_state") - rng = PyCapsule_GetPointer(capsule, capsule_name) + rng = PyCapsule_GetPointer(capsule, capsule_name) random_values = np.empty(n) for i in range(n): random_values[i] = random_gauss_zig(rng) diff --git a/_randomgen/examples/cython/setup.py b/_randomgen/examples/cython/setup.py index 61bdc5f606f3..480d5f508f8b 100644 --- a/_randomgen/examples/cython/setup.py +++ b/_randomgen/examples/cython/setup.py @@ -10,7 +10,7 @@ include_dirs=[np.get_include()]) distributions = Extension("extending_distributions", sources=['extending_distributions.pyx', - join('..', '..', 'core_prng', 'src', 'distributions', 'distributions.c')], + join('..', '..', 'randomgen', 'src', 'distributions', 'distributions.c')], include_dirs=[np.get_include()]) extensions = [extending, distributions] diff --git a/_randomgen/examples/numba/extending.py b/_randomgen/examples/numba/extending.py index aa7122c9543a..198c39a29297 100644 --- a/_randomgen/examples/numba/extending.py +++ b/_randomgen/examples/numba/extending.py @@ -1,4 +1,4 @@ -from core_prng import Xoroshiro128 +from randomgen import Xoroshiro128 import numpy as np import numba as nb diff --git a/_randomgen/examples/numba/extending_distributions.py b/_randomgen/examples/numba/extending_distributions.py index 230362747882..07cb074a3177 100644 --- a/_randomgen/examples/numba/extending_distributions.py +++ b/_randomgen/examples/numba/extending_distributions.py @@ -1,5 +1,5 @@ r""" -On *nix, execute in core_prng/src/distributions +On *nix, execute in randomgen/src/distributions export PYTHON_INCLUDE=#path to Python's include folder, usually ${PYTHON_HOME}/include/python${PYTHON_VERSION}m export NUMPY_INCLUDE=#path to numpy's include folder, usually ${PYTHON_HOME}/lib/python${PYTHON_VERSION}/site-packages/numpy/core/include @@ -16,7 +16,7 @@ import os import numpy as np from cffi import FFI -from core_prng import Xoroshiro128 +from randomgen import Xoroshiro128 import numba as nb ffi = FFI() @@ -28,19 +28,19 @@ raise RuntimeError('Required DLL/so file was not found.') ffi.cdef(""" -double random_gauss_zig(void *prng_state); +double random_gauss_zig(void *brng_state); """) x = Xoroshiro128() xffi = x.cffi -prng = xffi.prng +brng = xffi.brng random_gauss_zig = lib.random_gauss_zig -def normals(n, prng): +def normals(n, brng): out = np.empty(n) for i in range(n): - out[i] = random_gauss_zig(prng) + out[i] = random_gauss_zig(brng) return out @@ -48,7 +48,7 @@ def normals(n, prng): # Numba requires a memory address for void * -# Can also get address from x.ctypes.prng.value -prng_address = int(ffi.cast('uintptr_t', prng)) +# Can also get address from x.ctypes.brng.value +brng_address = int(ffi.cast('uintptr_t', brng)) -norm = normalsj(1000, prng_address) +norm = normalsj(1000, brng_address) diff --git a/_randomgen/core_prng/__init__.py b/_randomgen/randomgen/__init__.py similarity index 100% rename from _randomgen/core_prng/__init__.py rename to _randomgen/randomgen/__init__.py diff --git a/_randomgen/core_prng/_testing.py b/_randomgen/randomgen/_testing.py similarity index 100% rename from _randomgen/core_prng/_testing.py rename to _randomgen/randomgen/_testing.py diff --git a/_randomgen/core_prng/_version.py b/_randomgen/randomgen/_version.py similarity index 99% rename from _randomgen/core_prng/_version.py rename to _randomgen/randomgen/_version.py index 1041669c74ea..e400e3efb65d 100644 --- a/_randomgen/core_prng/_version.py +++ b/_randomgen/randomgen/_version.py @@ -42,8 +42,8 @@ def get_config(): cfg.VCS = "git" cfg.style = "pep440" cfg.tag_prefix = "" - cfg.parentdir_prefix = "core_prng-" - cfg.versionfile_source = "core_prng/_version.py" + cfg.parentdir_prefix = "randomgen-" + cfg.versionfile_source = "randomgen/_version.py" cfg.verbose = False return cfg diff --git a/_randomgen/core_prng/bounded_integers.pxd b/_randomgen/randomgen/bounded_integers.pxd similarity index 65% rename from _randomgen/core_prng/bounded_integers.pxd rename to _randomgen/randomgen/bounded_integers.pxd index 0da686427dec..f15f0f5d9d1e 100644 --- a/_randomgen/core_prng/bounded_integers.pxd +++ b/_randomgen/randomgen/bounded_integers.pxd @@ -1,6 +1,6 @@ from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t) -from common cimport prng_t +from common cimport brng_t import numpy as np cimport numpy as np ctypedef np.npy_bool bool_t @@ -28,12 +28,12 @@ cdef inline uint64_t _gen_mask(uint64_t max_val) nogil: mask |= mask >> 32 return mask -cdef object _rand_uint64(object low, object high, object size, prng_t *state, object lock) -cdef object _rand_uint32(object low, object high, object size, prng_t *state, object lock) -cdef object _rand_uint16(object low, object high, object size, prng_t *state, object lock) -cdef object _rand_uint8(object low, object high, object size, prng_t *state, object lock) -cdef object _rand_bool(object low, object high, object size, prng_t *state, object lock) -cdef object _rand_int64(object low, object high, object size, prng_t *state, object lock) -cdef object _rand_int32(object low, object high, object size, prng_t *state, object lock) -cdef object _rand_int16(object low, object high, object size, prng_t *state, object lock) -cdef object _rand_int8(object low, object high, object size, prng_t *state, object lock) +cdef object _rand_uint64(object low, object high, object size, brng_t *state, object lock) +cdef object _rand_uint32(object low, object high, object size, brng_t *state, object lock) +cdef object _rand_uint16(object low, object high, object size, brng_t *state, object lock) +cdef object _rand_uint8(object low, object high, object size, brng_t *state, object lock) +cdef object _rand_bool(object low, object high, object size, brng_t *state, object lock) +cdef object _rand_int64(object low, object high, object size, brng_t *state, object lock) +cdef object _rand_int32(object low, object high, object size, brng_t *state, object lock) +cdef object _rand_int16(object low, object high, object size, brng_t *state, object lock) +cdef object _rand_int8(object low, object high, object size, brng_t *state, object lock) diff --git a/_randomgen/core_prng/bounded_integers.pxd.in b/_randomgen/randomgen/bounded_integers.pxd.in similarity index 94% rename from _randomgen/core_prng/bounded_integers.pxd.in rename to _randomgen/randomgen/bounded_integers.pxd.in index 1b87e8d7ed69..4e1a6409146e 100644 --- a/_randomgen/core_prng/bounded_integers.pxd.in +++ b/_randomgen/randomgen/bounded_integers.pxd.in @@ -1,6 +1,6 @@ from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t) -from common cimport prng_t +from common cimport brng_t import numpy as np cimport numpy as np ctypedef np.npy_bool bool_t @@ -32,5 +32,5 @@ py: inttypes = ('uint64','uint32','uint16','uint8','bool','int64','int32','int16','int8') }} {{for inttype in inttypes}} -cdef object _rand_{{inttype}}(object low, object high, object size, prng_t *state, object lock) +cdef object _rand_{{inttype}}(object low, object high, object size, brng_t *state, object lock) {{endfor}} diff --git a/_randomgen/core_prng/bounded_integers.pyx b/_randomgen/randomgen/bounded_integers.pyx similarity index 97% rename from _randomgen/core_prng/bounded_integers.pyx rename to _randomgen/randomgen/bounded_integers.pyx index e8840d341f6c..fe47bcb8a2e9 100644 --- a/_randomgen/core_prng/bounded_integers.pyx +++ b/_randomgen/randomgen/bounded_integers.pyx @@ -9,7 +9,7 @@ np.import_array() -cdef object _rand_uint32_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): +cdef object _rand_uint32_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): """Array path for smaller integer types""" cdef uint32_t rng, last_rng, off, val, mask, out_val cdef uint32_t buf @@ -61,7 +61,7 @@ cdef object _rand_uint32_broadcast(np.ndarray low, np.ndarray high, object size, return out_arr -cdef object _rand_uint16_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): +cdef object _rand_uint16_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): """Array path for smaller integer types""" cdef uint16_t rng, last_rng, off, val, mask, out_val cdef uint32_t buf @@ -113,7 +113,7 @@ cdef object _rand_uint16_broadcast(np.ndarray low, np.ndarray high, object size, return out_arr -cdef object _rand_uint8_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): +cdef object _rand_uint8_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): """Array path for smaller integer types""" cdef uint8_t rng, last_rng, off, val, mask, out_val cdef uint32_t buf @@ -165,7 +165,7 @@ cdef object _rand_uint8_broadcast(np.ndarray low, np.ndarray high, object size, return out_arr -cdef object _rand_bool_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): +cdef object _rand_bool_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): """Array path for smaller integer types""" cdef bool_t rng, last_rng, off, val, mask, out_val cdef uint32_t buf @@ -217,7 +217,7 @@ cdef object _rand_bool_broadcast(np.ndarray low, np.ndarray high, object size, p return out_arr -cdef object _rand_int32_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): +cdef object _rand_int32_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): """Array path for smaller integer types""" cdef uint32_t rng, last_rng, off, val, mask, out_val cdef uint32_t buf @@ -269,7 +269,7 @@ cdef object _rand_int32_broadcast(np.ndarray low, np.ndarray high, object size, return out_arr -cdef object _rand_int16_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): +cdef object _rand_int16_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): """Array path for smaller integer types""" cdef uint16_t rng, last_rng, off, val, mask, out_val cdef uint32_t buf @@ -321,7 +321,7 @@ cdef object _rand_int16_broadcast(np.ndarray low, np.ndarray high, object size, return out_arr -cdef object _rand_int8_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): +cdef object _rand_int8_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): """Array path for smaller integer types""" cdef uint8_t rng, last_rng, off, val, mask, out_val cdef uint32_t buf @@ -374,7 +374,7 @@ cdef object _rand_int8_broadcast(np.ndarray low, np.ndarray high, object size, p -cdef object _rand_uint64_broadcast(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_uint64_broadcast(object low, object high, object size, brng_t *state, object lock): """Array path for 64-bit integer types""" cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr cdef np.npy_intp i, cnt, n @@ -434,7 +434,7 @@ cdef object _rand_uint64_broadcast(object low, object high, object size, prng_t return out_arr -cdef object _rand_int64_broadcast(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_int64_broadcast(object low, object high, object size, brng_t *state, object lock): """Array path for 64-bit integer types""" cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr cdef np.npy_intp i, cnt, n @@ -496,7 +496,7 @@ cdef object _rand_int64_broadcast(object low, object high, object size, prng_t * -cdef object _rand_uint64(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_uint64(object low, object high, object size, brng_t *state, object lock): """ _rand_uint64(low, high, size, *state, lock) @@ -520,7 +520,7 @@ cdef object _rand_uint64(object low, object high, object size, prng_t *state, ob Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - state : augmented random state + state : basic random state State to use in the core random number generators lock : threading.Lock Lock to prevent multiple using a single RandomState simultaneously @@ -572,7 +572,7 @@ cdef object _rand_uint64(object low, object high, object size, prng_t *state, ob return out_arr return _rand_uint64_broadcast(low_arr, high_arr, size, state, lock) -cdef object _rand_uint32(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_uint32(object low, object high, object size, brng_t *state, object lock): """ _rand_uint32(low, high, size, *state, lock) @@ -596,7 +596,7 @@ cdef object _rand_uint32(object low, object high, object size, prng_t *state, ob Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - state : augmented random state + state : basic random state State to use in the core random number generators lock : threading.Lock Lock to prevent multiple using a single RandomState simultaneously @@ -648,7 +648,7 @@ cdef object _rand_uint32(object low, object high, object size, prng_t *state, ob return out_arr return _rand_uint32_broadcast(low_arr, high_arr, size, state, lock) -cdef object _rand_uint16(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_uint16(object low, object high, object size, brng_t *state, object lock): """ _rand_uint16(low, high, size, *state, lock) @@ -672,7 +672,7 @@ cdef object _rand_uint16(object low, object high, object size, prng_t *state, ob Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - state : augmented random state + state : basic random state State to use in the core random number generators lock : threading.Lock Lock to prevent multiple using a single RandomState simultaneously @@ -724,7 +724,7 @@ cdef object _rand_uint16(object low, object high, object size, prng_t *state, ob return out_arr return _rand_uint16_broadcast(low_arr, high_arr, size, state, lock) -cdef object _rand_uint8(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_uint8(object low, object high, object size, brng_t *state, object lock): """ _rand_uint8(low, high, size, *state, lock) @@ -748,7 +748,7 @@ cdef object _rand_uint8(object low, object high, object size, prng_t *state, obj Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - state : augmented random state + state : basic random state State to use in the core random number generators lock : threading.Lock Lock to prevent multiple using a single RandomState simultaneously @@ -800,7 +800,7 @@ cdef object _rand_uint8(object low, object high, object size, prng_t *state, obj return out_arr return _rand_uint8_broadcast(low_arr, high_arr, size, state, lock) -cdef object _rand_bool(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_bool(object low, object high, object size, brng_t *state, object lock): """ _rand_bool(low, high, size, *state, lock) @@ -824,7 +824,7 @@ cdef object _rand_bool(object low, object high, object size, prng_t *state, obje Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - state : augmented random state + state : basic random state State to use in the core random number generators lock : threading.Lock Lock to prevent multiple using a single RandomState simultaneously @@ -876,7 +876,7 @@ cdef object _rand_bool(object low, object high, object size, prng_t *state, obje return out_arr return _rand_bool_broadcast(low_arr, high_arr, size, state, lock) -cdef object _rand_int64(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_int64(object low, object high, object size, brng_t *state, object lock): """ _rand_int64(low, high, size, *state, lock) @@ -900,7 +900,7 @@ cdef object _rand_int64(object low, object high, object size, prng_t *state, obj Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - state : augmented random state + state : basic random state State to use in the core random number generators lock : threading.Lock Lock to prevent multiple using a single RandomState simultaneously @@ -952,7 +952,7 @@ cdef object _rand_int64(object low, object high, object size, prng_t *state, obj return out_arr return _rand_int64_broadcast(low_arr, high_arr, size, state, lock) -cdef object _rand_int32(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_int32(object low, object high, object size, brng_t *state, object lock): """ _rand_int32(low, high, size, *state, lock) @@ -976,7 +976,7 @@ cdef object _rand_int32(object low, object high, object size, prng_t *state, obj Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - state : augmented random state + state : basic random state State to use in the core random number generators lock : threading.Lock Lock to prevent multiple using a single RandomState simultaneously @@ -1028,7 +1028,7 @@ cdef object _rand_int32(object low, object high, object size, prng_t *state, obj return out_arr return _rand_int32_broadcast(low_arr, high_arr, size, state, lock) -cdef object _rand_int16(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_int16(object low, object high, object size, brng_t *state, object lock): """ _rand_int16(low, high, size, *state, lock) @@ -1052,7 +1052,7 @@ cdef object _rand_int16(object low, object high, object size, prng_t *state, obj Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - state : augmented random state + state : basic random state State to use in the core random number generators lock : threading.Lock Lock to prevent multiple using a single RandomState simultaneously @@ -1104,7 +1104,7 @@ cdef object _rand_int16(object low, object high, object size, prng_t *state, obj return out_arr return _rand_int16_broadcast(low_arr, high_arr, size, state, lock) -cdef object _rand_int8(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_int8(object low, object high, object size, brng_t *state, object lock): """ _rand_int8(low, high, size, *state, lock) @@ -1128,7 +1128,7 @@ cdef object _rand_int8(object low, object high, object size, prng_t *state, obje Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - state : augmented random state + state : basic random state State to use in the core random number generators lock : threading.Lock Lock to prevent multiple using a single RandomState simultaneously diff --git a/_randomgen/core_prng/bounded_integers.pyx.in b/_randomgen/randomgen/bounded_integers.pyx.in similarity index 98% rename from _randomgen/core_prng/bounded_integers.pyx.in rename to _randomgen/randomgen/bounded_integers.pyx.in index ea0bba028d0b..d464e9e2c841 100644 --- a/_randomgen/core_prng/bounded_integers.pyx.in +++ b/_randomgen/randomgen/bounded_integers.pyx.in @@ -19,7 +19,7 @@ type_info = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000U {{for nptype, utype, nptype_up, npctype, remaining, bitshift, lb, ub in type_info}} {{ py: otype = nptype + '_' if nptype == 'bool' else nptype }} -cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, prng_t *state, object lock): +cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): """Array path for smaller integer types""" cdef {{utype}}_t rng, last_rng, off, val, mask, out_val cdef uint32_t buf @@ -78,7 +78,7 @@ big_type_info = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFF )}} {{for nptype, utype, npctype, lb, ub in big_type_info}} {{ py: otype = nptype}} -cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, brng_t *state, object lock): """Array path for 64-bit integer types""" cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr cdef np.npy_intp i, cnt, n @@ -153,7 +153,7 @@ type_info = (('uint64', 'uint64', '0x0ULL', '0xFFFFFFFFFFFFFFFFULL'), )}} {{for nptype, utype, lb, ub in type_info}} {{ py: otype = nptype + '_' if nptype == 'bool' else nptype }} -cdef object _rand_{{nptype}}(object low, object high, object size, prng_t *state, object lock): +cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state, object lock): """ _rand_{{nptype}}(low, high, size, *state, lock) @@ -177,7 +177,7 @@ cdef object _rand_{{nptype}}(object low, object high, object size, prng_t *state Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - state : augmented random state + state : basic random state State to use in the core random number generators lock : threading.Lock Lock to prevent multiple using a single RandomState simultaneously diff --git a/_randomgen/core_prng/common.pxd b/_randomgen/randomgen/common.pxd similarity index 66% rename from _randomgen/core_prng/common.pxd rename to _randomgen/randomgen/common.pxd index fce433449729..33a7bef2629a 100644 --- a/_randomgen/core_prng/common.pxd +++ b/_randomgen/randomgen/common.pxd @@ -2,7 +2,7 @@ from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t) from libc.math cimport sqrt -from distributions cimport prng_t +from distributions cimport brng_t import numpy as np cimport numpy as np @@ -30,62 +30,62 @@ cdef extern from "src/aligned_malloc/aligned_malloc.h": cdef void *PyArray_calloc_aligned(size_t n, size_t s); cdef void PyArray_free_aligned(void *p); -ctypedef double (*random_double_0)(prng_t *state) nogil -ctypedef double (*random_double_1)(prng_t *state, double a) nogil -ctypedef double (*random_double_2)(prng_t *state, double a, double b) nogil -ctypedef double (*random_double_3)(prng_t *state, double a, double b, double c) nogil +ctypedef double (*random_double_0)(brng_t *state) nogil +ctypedef double (*random_double_1)(brng_t *state, double a) nogil +ctypedef double (*random_double_2)(brng_t *state, double a, double b) nogil +ctypedef double (*random_double_3)(brng_t *state, double a, double b, double c) nogil -ctypedef float (*random_float_0)(prng_t *state) nogil -ctypedef float (*random_float_1)(prng_t *state, float a) nogil +ctypedef float (*random_float_0)(brng_t *state) nogil +ctypedef float (*random_float_1)(brng_t *state, float a) nogil -ctypedef int64_t (*random_uint_0)(prng_t *state) nogil -ctypedef int64_t (*random_uint_d)(prng_t *state, double a) nogil -ctypedef int64_t (*random_uint_dd)(prng_t *state, double a, double b) nogil -ctypedef int64_t (*random_uint_di)(prng_t *state, double a, uint64_t b) nogil -ctypedef int64_t (*random_uint_i)(prng_t *state, int64_t a) nogil -ctypedef int64_t (*random_uint_iii)(prng_t *state, int64_t a, int64_t b, int64_t c) nogil +ctypedef int64_t (*random_uint_0)(brng_t *state) nogil +ctypedef int64_t (*random_uint_d)(brng_t *state, double a) nogil +ctypedef int64_t (*random_uint_dd)(brng_t *state, double a, double b) nogil +ctypedef int64_t (*random_uint_di)(brng_t *state, double a, uint64_t b) nogil +ctypedef int64_t (*random_uint_i)(brng_t *state, int64_t a) nogil +ctypedef int64_t (*random_uint_iii)(brng_t *state, int64_t a, int64_t b, int64_t c) nogil -ctypedef uint32_t (*random_uint_0_32)(prng_t *state) nogil -ctypedef uint32_t (*random_uint_1_i_32)(prng_t *state, uint32_t a) nogil +ctypedef uint32_t (*random_uint_0_32)(brng_t *state) nogil +ctypedef uint32_t (*random_uint_1_i_32)(brng_t *state, uint32_t a) nogil -ctypedef int32_t (*random_int_2_i_32)(prng_t *state, int32_t a, int32_t b) nogil -ctypedef int64_t (*random_int_2_i)(prng_t *state, int64_t a, int64_t b) nogil +ctypedef int32_t (*random_int_2_i_32)(brng_t *state, int32_t a, int32_t b) nogil +ctypedef int64_t (*random_int_2_i)(brng_t *state, int64_t a, int64_t b) nogil cdef double kahan_sum(double *darr, np.npy_intp n) cdef inline double uint64_to_double(uint64_t rnd) nogil: return (rnd >> 11) * (1.0 / 9007199254740992.0) -cdef object double_fill(void *func, prng_t *state, object size, object lock, object out) +cdef object double_fill(void *func, brng_t *state, object size, object lock, object out) -cdef object float_fill(void *func, prng_t *state, object size, object lock, object out) +cdef object float_fill(void *func, brng_t *state, object size, object lock, object out) -cdef object float_fill_from_double(void *func, prng_t *state, object size, object lock, object out) +cdef object float_fill_from_double(void *func, brng_t *state, object size, object lock, object out) cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size) -cdef object cont(void *func, prng_t *state, object size, object lock, int narg, +cdef object cont(void *func, brng_t *state, object size, object lock, int narg, object a, object a_name, constraint_type a_constraint, object b, object b_name, constraint_type b_constraint, object c, object c_name, constraint_type c_constraint, object out) -cdef object disc(void *func, prng_t *state, object size, object lock, +cdef object disc(void *func, brng_t *state, object size, object lock, int narg_double, int narg_int64, object a, object a_name, constraint_type a_constraint, object b, object b_name, constraint_type b_constraint, object c, object c_name, constraint_type c_constraint) -cdef object cont_f(void *func, prng_t *state, object size, object lock, +cdef object cont_f(void *func, brng_t *state, object size, object lock, object a, object a_name, constraint_type a_constraint, object out) -cdef object cont_broadcast_3(void *func, prng_t *state, object size, object lock, +cdef object cont_broadcast_3(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint, np.ndarray c_arr, object c_name, constraint_type c_constraint) -cdef object discrete_broadcast_iii(void *func, prng_t *state, object size, object lock, +cdef object discrete_broadcast_iii(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint, np.ndarray c_arr, object c_name, constraint_type c_constraint) diff --git a/_randomgen/core_prng/common.pyx b/_randomgen/randomgen/common.pyx similarity index 96% rename from _randomgen/core_prng/common.pyx rename to _randomgen/randomgen/common.pyx index aad1ad6f10b0..101a14270635 100644 --- a/_randomgen/core_prng/common.pyx +++ b/_randomgen/randomgen/common.pyx @@ -11,7 +11,7 @@ from common cimport * np.import_array() interface = namedtuple('interface', ['state_address', 'state', 'next_uint64', - 'next_uint32', 'next_double', 'prng']) + 'next_uint32', 'next_double', 'brng']) cdef double kahan_sum(double *darr, np.npy_intp n): @@ -69,7 +69,7 @@ cdef check_output(object out, object dtype, object size): raise ValueError('size and out cannot be simultaneously used') -cdef object double_fill(void *func, prng_t *state, object size, object lock, object out): +cdef object double_fill(void *func, brng_t *state, object size, object lock, object out): cdef random_double_0 random_func = (func) cdef double *out_array_data cdef np.ndarray out_array @@ -92,7 +92,7 @@ cdef object double_fill(void *func, prng_t *state, object size, object lock, obj out_array_data[i] = random_func(state) return out_array -cdef object float_fill(void *func, prng_t *state, object size, object lock, object out): +cdef object float_fill(void *func, brng_t *state, object size, object lock, object out): cdef random_float_0 random_func = (func) cdef float *out_array_data cdef np.ndarray out_array @@ -115,7 +115,7 @@ cdef object float_fill(void *func, prng_t *state, object size, object lock, obje out_array_data[i] = random_func(state) return out_array -cdef object float_fill_from_double(void *func, prng_t *state, object size, object lock, object out): +cdef object float_fill_from_double(void *func, brng_t *state, object size, object lock, object out): cdef random_double_0 random_func = (func) cdef float *out_array_data cdef np.ndarray out_array @@ -199,7 +199,7 @@ cdef int check_constraint(double val, object name, constraint_type cons) except return 0 -cdef object cont_broadcast_1(void *func, prng_t *state, object size, object lock, +cdef object cont_broadcast_1(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, object out): @@ -233,7 +233,7 @@ cdef object cont_broadcast_1(void *func, prng_t *state, object size, object lock return randoms -cdef object cont_broadcast_2(void *func, prng_t *state, object size, object lock, +cdef object cont_broadcast_2(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint): cdef np.ndarray randoms @@ -271,7 +271,7 @@ cdef object cont_broadcast_2(void *func, prng_t *state, object size, object lock return randoms -cdef object cont_broadcast_3(void *func, prng_t *state, object size, object lock, +cdef object cont_broadcast_3(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint, np.ndarray c_arr, object c_name, constraint_type c_constraint): @@ -313,7 +313,7 @@ cdef object cont_broadcast_3(void *func, prng_t *state, object size, object lock return randoms -cdef object cont(void *func, prng_t *state, object size, object lock, int narg, +cdef object cont(void *func, brng_t *state, object size, object lock, int narg, object a, object a_name, constraint_type a_constraint, object b, object b_name, constraint_type b_constraint, object c, object c_name, constraint_type c_constraint, @@ -409,7 +409,7 @@ cdef object cont(void *func, prng_t *state, object size, object lock, int narg, else: return out -cdef object discrete_broadcast_d(void *func, prng_t *state, object size, object lock, +cdef object discrete_broadcast_d(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint): cdef np.ndarray randoms @@ -440,7 +440,7 @@ cdef object discrete_broadcast_d(void *func, prng_t *state, object size, object return randoms -cdef object discrete_broadcast_dd(void *func, prng_t *state, object size, object lock, +cdef object discrete_broadcast_dd(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint): cdef np.ndarray randoms @@ -475,7 +475,7 @@ cdef object discrete_broadcast_dd(void *func, prng_t *state, object size, object return randoms -cdef object discrete_broadcast_di(void *func, prng_t *state, object size, object lock, +cdef object discrete_broadcast_di(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint): cdef np.ndarray randoms @@ -511,7 +511,7 @@ cdef object discrete_broadcast_di(void *func, prng_t *state, object size, object return randoms -cdef object discrete_broadcast_iii(void *func, prng_t *state, object size, object lock, +cdef object discrete_broadcast_iii(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint, np.ndarray c_arr, object c_name, constraint_type c_constraint): @@ -551,7 +551,7 @@ cdef object discrete_broadcast_iii(void *func, prng_t *state, object size, objec return randoms -cdef object discrete_broadcast_i(void *func, prng_t *state, object size, object lock, +cdef object discrete_broadcast_i(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint): cdef np.ndarray randoms cdef int64_t *randoms_data @@ -581,7 +581,7 @@ cdef object discrete_broadcast_i(void *func, prng_t *state, object size, object return randoms # Needs double , double-double , double-int64_t, int64_t , int64_t-int64_t-int64_t -cdef object disc(void *func, prng_t *state, object size, object lock, +cdef object disc(void *func, brng_t *state, object size, object lock, int narg_double, int narg_int64, object a, object a_name, constraint_type a_constraint, object b, object b_name, constraint_type b_constraint, @@ -719,7 +719,7 @@ cdef object disc(void *func, prng_t *state, object size, object lock, return randoms -cdef object cont_broadcast_1_f(void *func, prng_t *state, object size, object lock, +cdef object cont_broadcast_1_f(void *func, brng_t *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, object out): @@ -755,7 +755,7 @@ cdef object cont_broadcast_1_f(void *func, prng_t *state, object size, object lo return randoms -cdef object cont_f(void *func, prng_t *state, object size, object lock, +cdef object cont_f(void *func, brng_t *state, object size, object lock, object a, object a_name, constraint_type a_constraint, object out): diff --git a/_randomgen/randomgen/distributions.pxd b/_randomgen/randomgen/distributions.pxd new file mode 100644 index 000000000000..3ac32f210108 --- /dev/null +++ b/_randomgen/randomgen/distributions.pxd @@ -0,0 +1,123 @@ +from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, + int8_t, int16_t, int32_t, int64_t, intptr_t) +import numpy as np +cimport numpy as np + +cdef extern from "src/distributions/distributions.h": + + struct s_binomial_t: + int has_binomial + double psave + int64_t nsave + double r + double q + double fm + int64_t m + double p1 + double xm + double xl + double xr + double c + double laml + double lamr + double p2 + double p3 + double p4 + + ctypedef s_binomial_t binomial_t + + struct brng: + void *state + uint64_t (*next_uint64)(void *st) nogil + uint32_t (*next_uint32)(void *st) nogil + double (*next_double)(void *st) nogil + uint64_t (*next_raw)(void *st) nogil + + ctypedef brng brng_t + + double random_sample(brng_t *brng_state) nogil + double random_standard_exponential(brng_t *brng_state) nogil + double random_standard_exponential_zig(brng_t *brng_state) nogil + double random_gauss_zig(brng_t* brng_state) nogil + double random_standard_gamma_zig(brng_t *brng_state, double shape) nogil + + float random_sample_f(brng_t *brng_state) nogil + float random_standard_exponential_f(brng_t *brng_state) nogil + float random_standard_exponential_zig_f(brng_t *brng_state) nogil + float random_gauss_zig_f(brng_t* brng_state) nogil + float random_standard_gamma_f(brng_t *brng_state, float shape) nogil + float random_standard_gamma_zig_f(brng_t *brng_state, float shape) nogil + + int64_t random_positive_int64(brng_t *brng_state) nogil + int32_t random_positive_int32(brng_t *brng_state) nogil + int64_t random_positive_int(brng_t *brng_state) nogil + uint64_t random_uint(brng_t *brng_state) nogil + + double random_normal_zig(brng_t *brng_state, double loc, double scale) nogil + + double random_gamma(brng_t *brng_state, double shape, double scale) nogil + float random_gamma_float(brng_t *brng_state, float shape, float scale) nogil + + double random_exponential(brng_t *brng_state, double scale) nogil + double random_uniform(brng_t *brng_state, double lower, double range) nogil + double random_beta(brng_t *brng_state, double a, double b) nogil + double random_chisquare(brng_t *brng_state, double df) nogil + double random_f(brng_t *brng_state, double dfnum, double dfden) nogil + double random_standard_cauchy(brng_t *brng_state) nogil + double random_pareto(brng_t *brng_state, double a) nogil + double random_weibull(brng_t *brng_state, double a) nogil + double random_power(brng_t *brng_state, double a) nogil + double random_laplace(brng_t *brng_state, double loc, double scale) nogil + double random_gumbel(brng_t *brng_state, double loc, double scale) nogil + double random_logistic(brng_t *brng_state, double loc, double scale) nogil + double random_lognormal(brng_t *brng_state, double mean, double sigma) nogil + double random_rayleigh(brng_t *brng_state, double mode) nogil + double random_standard_t(brng_t *brng_state, double df) nogil + double random_noncentral_chisquare(brng_t *brng_state, double df, + double nonc) nogil + double random_noncentral_f(brng_t *brng_state, double dfnum, + double dfden, double nonc) nogil + double random_wald(brng_t *brng_state, double mean, double scale) nogil + double random_vonmises(brng_t *brng_state, double mu, double kappa) nogil + double random_triangular(brng_t *brng_state, double left, double mode, + double right) nogil + + int64_t random_poisson(brng_t *brng_state, double lam) nogil + int64_t random_negative_binomial(brng_t *brng_state, double n, double p) nogil + int64_t random_binomial(brng_t *brng_state, double p, int64_t n, binomial_t *binomial) nogil + int64_t random_logseries(brng_t *brng_state, double p) nogil + int64_t random_geometric_search(brng_t *brng_state, double p) nogil + int64_t random_geometric_inversion(brng_t *brng_state, double p) nogil + int64_t random_geometric(brng_t *brng_state, double p) nogil + int64_t random_zipf(brng_t *brng_state, double a) nogil + int64_t random_hypergeometric(brng_t *brng_state, int64_t good, int64_t bad, + int64_t sample) nogil + uint64_t random_interval(brng_t *brng_state, uint64_t max) nogil + uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, + uint64_t rng, uint64_t mask) nogil + uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, + uint32_t rng, uint32_t mask, + int *bcnt, uint32_t *buf) nogil + + uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, + uint16_t rng, uint16_t mask, + int *bcnt, uint32_t *buf) nogil + uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, + uint8_t rng, uint8_t mask, + int *bcnt, uint32_t *buf) nogil + np.npy_bool random_buffered_bounded_bool(brng_t *brng_state, np.npy_bool off, + np.npy_bool rng, np.npy_bool mask, + int *bcnt, uint32_t *buf) nogil + void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, + uint64_t rng, np.npy_intp cnt, + uint64_t *out) nogil + void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, + uint32_t rng, np.npy_intp cnt, + uint32_t *out) nogil + void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, + uint16_t rng, np.npy_intp cnt, + uint16_t *out) nogil + void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, + uint8_t rng, np.npy_intp cnt, uint8_t *out) nogil + void random_bounded_bool_fill(brng_t *brng_state, np.npy_bool off, + np.npy_bool rng, np.npy_intp cnt, np.npy_bool *out) nogil diff --git a/_randomgen/core_prng/dsfmt.pyx b/_randomgen/randomgen/dsfmt.pyx similarity index 89% rename from _randomgen/core_prng/dsfmt.pyx rename to _randomgen/randomgen/dsfmt.pyx index d1da29127237..5c979e6e8040 100644 --- a/_randomgen/core_prng/dsfmt.pyx +++ b/_randomgen/randomgen/dsfmt.pyx @@ -7,9 +7,9 @@ cimport numpy as np from common import interface from common cimport * -from distributions cimport prng_t -from core_prng.entropy import random_entropy -import core_prng.pickle +from distributions cimport brng_t +from randomgen.entropy import random_entropy +import randomgen.pickle np.import_array() @@ -99,8 +99,8 @@ cdef class DSFMT: generators should be initialized with the same seed to ensure that the segments come from the same sequence. - >>> from core_prng.entropy import random_entropy - >>> from core_prng import RandomGenerator, DSFMT + >>> from randomgen.entropy import random_entropy + >>> from randomgen import RandomGenerator, DSFMT >>> seed = random_entropy() >>> rs = [RandomGenerator(DSFMT(seed)) for _ in range(10)] # Advance rs[i] by i jumps @@ -137,7 +137,7 @@ cdef class DSFMT: Sequences and Their Applications - SETA, 290--298, 2008. """ cdef dsfmt_state *rng_state - cdef prng_t *_prng + cdef brng_t *_brng cdef public object capsule cdef public object _cffi cdef public object _ctypes @@ -148,15 +148,15 @@ cdef class DSFMT: self.rng_state.state = PyArray_malloc_aligned(sizeof(dsfmt_t)) self.rng_state.buffered_uniforms = PyArray_calloc_aligned(DSFMT_N64, sizeof(double)) self.rng_state.buffer_loc = DSFMT_N64 - self._prng = malloc(sizeof(prng_t)) + self._brng = malloc(sizeof(brng_t)) self.seed(seed) - self._prng.state = self.rng_state - self._prng.next_uint64 = &dsfmt_uint64 - self._prng.next_uint32 = &dsfmt_uint32 - self._prng.next_double = &dsfmt_double - self._prng.next_raw = &dsfmt_raw - cdef const char *name = "CorePRNG" - self.capsule = PyCapsule_New(self._prng, name, NULL) + self._brng.state = self.rng_state + self._brng.next_uint64 = &dsfmt_uint64 + self._brng.next_uint32 = &dsfmt_uint32 + self._brng.next_double = &dsfmt_double + self._brng.next_raw = &dsfmt_raw + cdef const char *name = "BasicRNG" + self.capsule = PyCapsule_New(self._brng, name, NULL) self._cffi = None self._ctypes = None @@ -170,24 +170,24 @@ cdef class DSFMT: self.state = state def __reduce__(self): - return (core_prng.pickle.__prng_ctor, - (self.state['prng'],), + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), self.state) def __dealloc__(self): PyArray_free_aligned(self.rng_state.state) PyArray_free_aligned(self.rng_state.buffered_uniforms) free(self.rng_state) - free(self._prng) + free(self._brng) def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i if method==u'uint64': for i in range(cnt): - self._prng.next_uint64(self._prng.state) + self._brng.next_uint64(self._brng.state) elif method==u'double': for i in range(cnt): - self._prng.next_double(self._prng.state) + self._brng.next_double(self._brng.state) else: raise ValueError('Unknown method') @@ -247,7 +247,7 @@ cdef class DSFMT: Parameters ---------- iter : integer, positive - Number of times to jump the state of the prng. + Number of times to jump the state of the brng. Returns ------- @@ -283,7 +283,7 @@ cdef class DSFMT: buffered_uniforms = np.empty(DSFMT_N64,dtype=np.double) for i in range(DSFMT_N64): buffered_uniforms[i] = self.rng_state.buffered_uniforms[i] - return {'prng': self.__class__.__name__, + return {'brng': self.__class__.__name__, 'state': {'state':np.asarray(state), 'idx':self.rng_state.state.idx}, 'buffer_loc': self.rng_state.buffer_loc, @@ -294,8 +294,8 @@ cdef class DSFMT: cdef Py_ssize_t i, j, loc = 0 if not isinstance(value, dict): raise TypeError('state must be a dict') - prng = value.get('prng', '') - if prng != self.__class__.__name__: + brng = value.get('brng', '') + if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) state = value['state']['state'] @@ -324,7 +324,7 @@ cdef class DSFMT: * next_uint64 - function pointer to produce 64 bit integers * next_uint32 - function pointer to produce 32 bit integers * next_double - function pointer to produce doubles - * prng - pointer to the PRNG struct + * brng - pointer to the Basic RNG struct """ if self._ctypes is not None: @@ -343,7 +343,7 @@ cdef class DSFMT: ctypes.cast(&dsfmt_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._prng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -361,7 +361,7 @@ cdef class DSFMT: * next_uint64 - function pointer to produce 64 bit integers * next_uint32 - function pointer to produce 32 bit integers * next_double - function pointer to produce doubles - * prng - pointer to the PRNG struct + * brng - pointer to the Basic RNG struct """ if self._cffi is not None: return self._cffi @@ -373,10 +373,10 @@ cdef class DSFMT: ffi = cffi.FFI() self._cffi = interface(self.rng_state, ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._prng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._prng.next_uint32), - ffi.cast('double (*)(void *)',self._prng.next_double), - ffi.cast('void *',self._prng)) + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property @@ -386,8 +386,8 @@ cdef class DSFMT: Returns ------- - gen : core_prng.generator.RandomGenerator - Random generator used this instance as the core PRNG + gen : randomgen.generator.RandomGenerator + Random generator used this instance as the basic RNG """ if self._generator is None: from .generator import RandomGenerator diff --git a/_randomgen/core_prng/entropy.pyx b/_randomgen/randomgen/entropy.pyx similarity index 100% rename from _randomgen/core_prng/entropy.pyx rename to _randomgen/randomgen/entropy.pyx diff --git a/_randomgen/core_prng/generator.pyx b/_randomgen/randomgen/generator.pyx similarity index 93% rename from _randomgen/core_prng/generator.pyx rename to _randomgen/randomgen/generator.pyx index cb9a001c2669..0d988f678295 100644 --- a/_randomgen/core_prng/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -20,8 +20,8 @@ try: except ImportError: from dummy_threading import Lock -from core_prng.xoroshiro128 import Xoroshiro128 -import core_prng.pickle +from randomgen.xoroshiro128 import Xoroshiro128 +import randomgen.pickle np.import_array() @@ -38,35 +38,35 @@ _randint_types = {'bool': (0, 2), cdef class RandomGenerator: """ - Prototype Random Generator that consumes randoms from a CorePRNG class + Prototype Random Generator that consumes randoms from a Basic RNG class Parameters ---------- - prng : CorePRNG, optional + brng : BasicRNG, optional Object exposing a PyCapsule containing state and function pointers Examples -------- - >>> from core_prng.generator import RandomGenerator + >>> from randomgen.generator import RandomGenerator >>> rg = RandomGenerator() >>> rg.standard_normal() """ - cdef public object __core_prng - cdef prng_t *_prng + cdef public object _basicrng + cdef brng_t *_brng cdef binomial_t *_binomial cdef object lock poisson_lam_max = POISSON_LAM_MAX - def __init__(self, prng=None): - if prng is None: - prng = Xoroshiro128() - self.__core_prng = prng + def __init__(self, brng=None): + if brng is None: + brng = Xoroshiro128() + self._basicrng = brng - capsule = prng.capsule - cdef const char *anon_name = "CorePRNG" - if not PyCapsule_IsValid(capsule, anon_name): - raise ValueError("Invalid prng. The prng must be instantized.") - self._prng = PyCapsule_GetPointer(capsule, anon_name) + capsule = brng.capsule + cdef const char *name = "BasicRNG" + if not PyCapsule_IsValid(capsule, name): + raise ValueError("Invalid brng. The brng must be instantized.") + self._brng = PyCapsule_GetPointer(capsule, name) self._binomial = malloc(sizeof(binomial_t)) self.lock = Lock() @@ -77,7 +77,7 @@ cdef class RandomGenerator: return self.__str__() + ' at 0x{:X}'.format(id(self)) def __str__(self): - return 'RandomGenerator(' + self.__core_prng.__class__.__name__ + ')' + return 'RandomGenerator(' + self._basicrng.__class__.__name__ + ')' # Pickling support: def __getstate__(self): @@ -87,25 +87,25 @@ cdef class RandomGenerator: self.state = state def __reduce__(self): - return (core_prng.pickle.__generator_ctor, - (self.state['prng'],), + return (randomgen.pickle.__generator_ctor, + (self.state['brng'],), self.state) def seed(self, *args, **kwargs): """ TODO: Should this remain """ - self.__core_prng.seed(*args, **kwargs) + self._basicrng.seed(*args, **kwargs) return self @property def state(self): """Get or set the underlying PRNG's state""" - return self.__core_prng.state + return self._basicrng.state @state.setter def state(self, value): - self.__core_prng.state = value + self._basicrng.state = value def random_uintegers(self, size=None, int bits=64): """ @@ -144,23 +144,23 @@ cdef class RandomGenerator: if bits == 64: if size is None: with self.lock: - return self._prng.next_uint64(self._prng.state) + return self._brng.next_uint64(self._brng.state) array = np.empty(size, np.uint64) n = np.PyArray_SIZE(array) data64 = np.PyArray_DATA(array) with self.lock, nogil: for i in range(n): - data64[i] = self._prng.next_uint64(self._prng.state) + data64[i] = self._brng.next_uint64(self._brng.state) elif bits == 32: if size is None: with self.lock: - return self._prng.next_uint32(self._prng.state) + return self._brng.next_uint32(self._brng.state) array = np.empty(size, np.uint32) n = np.PyArray_SIZE(array) data32 = np.PyArray_DATA(array) with self.lock, nogil: for i in range(n): - data32[i] = self._prng.next_uint32(self._prng.state) + data32[i] = self._brng.next_uint32(self._brng.state) else: raise ValueError('Unknown value of bits. Must be either 32 or 64.') @@ -202,17 +202,17 @@ cdef class RandomGenerator: if not output: if size is None: with self.lock: - self._prng.next_raw(self._prng.state) + self._brng.next_raw(self._brng.state) return None n = np.asarray(size).sum() with self.lock, nogil: for i in range(n): - self._prng.next_raw(self._prng.state) + self._brng.next_raw(self._brng.state) return None if size is None: with self.lock: - return self._prng.next_raw(self._prng.state) + return self._brng.next_raw(self._brng.state) randoms = np.empty(size, np.uint64) randoms_data = np.PyArray_DATA(randoms) @@ -220,7 +220,7 @@ cdef class RandomGenerator: with self.lock, nogil: for i in range(n): - randoms_data[i] = self._prng.next_raw(self._prng.state) + randoms_data[i] = self._brng.next_raw(self._brng.state) return randoms def random_sample(self, size=None, dtype=np.float64, out=None): @@ -258,16 +258,16 @@ cdef class RandomGenerator: Examples -------- - >>> core_prng.random_sample() + >>> randomgen.random_sample() 0.47108547995356098 - >>> type(core_prng.random_sample()) + >>> type(randomgen.random_sample()) - >>> core_prng.random_sample((5,)) + >>> randomgen.random_sample((5,)) array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) Three-by-two array of random numbers from [-5, 0): - >>> 5 * core_prng.random_sample((3, 2)) - 5 + >>> 5 * randomgen.random_sample((3, 2)) - 5 array([[-3.99149989, -0.52338984], [-2.99091858, -0.79479508], [-1.23204345, -1.75224494]]) @@ -275,9 +275,9 @@ cdef class RandomGenerator: cdef double temp key = np.dtype(dtype).name if key == 'float64': - return double_fill(&random_sample, self._prng, size, self.lock, out) + return double_fill(&random_sample, self._brng, size, self.lock, out) elif key == 'float32': - return float_fill(&random_sample_f, self._prng, size, self.lock, out) + return float_fill(&random_sample_f, self._brng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for random_sample' % key) @@ -319,7 +319,7 @@ cdef class RandomGenerator: Drawn samples from the parameterized beta distribution. """ - return cont(&random_beta, self._prng, size, self.lock, 2, + return cont(&random_beta, self._brng, size, self.lock, 2, a, 'a', CONS_POSITIVE, b, 'b', CONS_POSITIVE, 0.0, '', CONS_NONE, None) @@ -370,7 +370,7 @@ cdef class RandomGenerator: http://en.wikipedia.org/wiki/Exponential_distribution """ - return cont(&random_exponential, self._prng, size, self.lock, 1, + return cont(&random_exponential, self._brng, size, self.lock, 1, scale, 'scale', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, @@ -412,19 +412,19 @@ cdef class RandomGenerator: -------- Output a 3x8000 array: - >>> n = core_prng.standard_exponential((3, 8000)) + >>> n = randomgen.standard_exponential((3, 8000)) """ key = np.dtype(dtype).name if key == 'float64': if method == u'zig': - return double_fill(&random_standard_exponential_zig, self._prng, size, self.lock, out) + return double_fill(&random_standard_exponential_zig, self._brng, size, self.lock, out) else: - return double_fill(&random_standard_exponential, self._prng, size, self.lock, out) + return double_fill(&random_standard_exponential, self._brng, size, self.lock, out) elif key == 'float32': if method == u'zig': - return float_fill(&random_standard_exponential_zig_f, self._prng, size, self.lock, out) + return float_fill(&random_standard_exponential_zig_f, self._brng, size, self.lock, out) else: - return float_fill(&random_standard_exponential_f, self._prng, size, self.lock, out) + return float_fill(&random_standard_exponential_f, self._brng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for standard_exponential' % key) @@ -458,7 +458,7 @@ cdef class RandomGenerator: Examples -------- - >>> RS = core_prng.mtrand.RandomState() # need a RandomState object + >>> RS = randomgen.mtrand.RandomState() # need a RandomState object >>> RS.tomaxint((2,2,2)) array([[[1170048599, 1600360186], [ 739731006, 1947757578]], @@ -480,7 +480,7 @@ cdef class RandomGenerator: if size is None: with self.lock: - return random_positive_int(self._prng) + return random_positive_int(self._brng) randoms = np.empty(size, dtype=np.int64) randoms_data = np.PyArray_DATA(randoms) @@ -488,7 +488,7 @@ cdef class RandomGenerator: for i in range(n): with self.lock, nogil: - randoms_data[i] = random_positive_int(self._prng) + randoms_data[i] = random_positive_int(self._brng) return randoms def randint(self, low, high=None, size=None, dtype=int): @@ -538,30 +538,30 @@ cdef class RandomGenerator: Examples -------- - >>> core_prng.randint(2, size=10) + >>> randomgen.randint(2, size=10) array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) - >>> core_prng.randint(1, size=10) + >>> randomgen.randint(1, size=10) array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) Generate a 2 x 4 array of ints between 0 and 4, inclusive: - >>> core_prng.randint(5, size=(2, 4)) + >>> randomgen.randint(5, size=(2, 4)) array([[4, 0, 2, 1], [3, 2, 2, 0]]) Generate a 1 x 3 array with 3 different upper bounds - >>> core_prng.randint(1, [3, 5, 10]) + >>> randomgen.randint(1, [3, 5, 10]) array([2, 2, 9]) Generate a 1 by 3 array with 3 different lower bounds - >>> core_prng.randint([1, 5, 7], 10) + >>> randomgen.randint([1, 5, 7], 10) array([9, 8, 7]) Generate a 2 by 4 array using broadcasting with dtype of uint8 - >>> core_prng.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) + >>> randomgen.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) array([[ 8, 6, 9, 7], [ 1, 16, 9, 12]], dtype=uint8) """ @@ -574,23 +574,23 @@ cdef class RandomGenerator: raise TypeError('Unsupported dtype "%s" for randint' % key) if key == 'int32': - ret = _rand_int32(low, high, size, self._prng, self.lock) + ret = _rand_int32(low, high, size, self._brng, self.lock) elif key == 'int64': - ret = _rand_int64(low, high, size, self._prng, self.lock) + ret = _rand_int64(low, high, size, self._brng, self.lock) elif key == 'int16': - ret = _rand_int16(low, high, size, self._prng, self.lock) + ret = _rand_int16(low, high, size, self._brng, self.lock) elif key == 'int8': - ret = _rand_int8(low, high, size, self._prng, self.lock) + ret = _rand_int8(low, high, size, self._brng, self.lock) elif key == 'uint64': - ret = _rand_uint64(low, high, size, self._prng, self.lock) + ret = _rand_uint64(low, high, size, self._brng, self.lock) elif key == 'uint32': - ret = _rand_uint32(low, high, size, self._prng, self.lock) + ret = _rand_uint32(low, high, size, self._brng, self.lock) elif key == 'uint16': - ret = _rand_uint16(low, high, size, self._prng, self.lock) + ret = _rand_uint16(low, high, size, self._brng, self.lock) elif key == 'uint8': - ret = _rand_uint8(low, high, size, self._prng, self.lock) + ret = _rand_uint8(low, high, size, self._brng, self.lock) elif key == 'bool': - ret = _rand_bool(low, high, size, self._prng, self.lock) + ret = _rand_bool(low, high, size, self._brng, self.lock) if size is None and dtype in (np.bool, np.int, np.long): if np.array(ret).shape == (): @@ -615,7 +615,7 @@ cdef class RandomGenerator: Examples -------- - >>> core_prng.bytes(10) + >>> randomgen.bytes(10) ' eh\\x85\\x022SZ\\xbf\\xa4' #random """ @@ -670,33 +670,33 @@ cdef class RandomGenerator: -------- Generate a uniform random sample from np.arange(5) of size 3: - >>> core_prng.choice(5, 3) + >>> randomgen.choice(5, 3) array([0, 3, 4]) - >>> #This is equivalent to core_prng.randint(0,5,3) + >>> #This is equivalent to randomgen.randint(0,5,3) Generate a non-uniform random sample from np.arange(5) of size 3: - >>> core_prng.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) + >>> randomgen.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) array([3, 3, 0]) Generate a uniform random sample from np.arange(5) of size 3 without replacement: - >>> core_prng.choice(5, 3, replace=False) + >>> randomgen.choice(5, 3, replace=False) array([3,1,0]) - >>> #This is equivalent to core_prng.permutation(np.arange(5))[:3] + >>> #This is equivalent to randomgen.permutation(np.arange(5))[:3] Generate a non-uniform random sample from np.arange(5) of size 3 without replacement: - >>> core_prng.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) + >>> randomgen.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) array([2, 3, 0]) Any of the above can be repeated with an arbitrary array-like instead of just integers. For instance: >>> aa_milne_arr = ['pooh', 'rabbit', 'piglet', 'Christopher'] - >>> core_prng.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) + >>> randomgen.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) array(['pooh', 'pooh', 'pooh', 'Christopher', 'piglet'], dtype='|S11') @@ -865,7 +865,7 @@ cdef class RandomGenerator: -------- Draw samples from the distribution: - >>> s = core_prng.uniform(-1,0,1000) + >>> s = randomgen.uniform(-1,0,1000) All values are within the given interval: @@ -897,7 +897,7 @@ cdef class RandomGenerator: if not np.isfinite(range): raise OverflowError('Range exceeds valid bounds') - return cont(&random_uniform, self._prng, size, self.lock, 2, + return cont(&random_uniform, self._brng, size, self.lock, 2, _low, '', CONS_NONE, range, '', CONS_NONE, 0.0, '', CONS_NONE, @@ -909,7 +909,7 @@ cdef class RandomGenerator: arange = np.PyArray_EnsureArray(temp) if not np.all(np.isfinite(arange)): raise OverflowError('Range exceeds valid bounds') - return cont(&random_uniform, self._prng, size, self.lock, 2, + return cont(&random_uniform, self._brng, size, self.lock, 2, alow, '', CONS_NONE, arange, '', CONS_NONE, 0.0, '', CONS_NONE, @@ -947,13 +947,13 @@ cdef class RandomGenerator: Notes ----- This is a convenience function. If you want an interface that takes - a shape-tuple as the first argument, refer to core_prng.random_sample. + a shape-tuple as the first argument, refer to randomgen.random_sample. ``dtype`` can only be changed using a keyword argument. Examples -------- - >>> core_prng.rand(3,2) + >>> randomgen.rand(3,2) array([[ 0.14022471, 0.96360618], #random [ 0.37601032, 0.25528411], #random [ 0.49313049, 0.94909878]]) #random @@ -1005,16 +1005,16 @@ cdef class RandomGenerator: ----- For random samples from :math:`N(\\mu, \\sigma^2)`, use: - ``sigma * core_prng.randn(...) + mu`` + ``sigma * randomgen.randn(...) + mu`` Examples -------- - >>> core_prng.randn() + >>> randomgen.randn() 2.1923875335537315 #random Two-by-four array of samples from N(3, 6.25): - >>> 2.5 * core_prng.randn(2, 4) + 3 + >>> 2.5 * randomgen.randn(2, 4) + 3 array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random @@ -1069,15 +1069,15 @@ cdef class RandomGenerator: To sample from N evenly spaced floating-point numbers between a and b, use:: - a + (b - a) * (core_prng.random_integers(N) - 1) / (N - 1.) + a + (b - a) * (randomgen.random_integers(N) - 1) / (N - 1.) Examples -------- - >>> core_prng.random_integers(5) + >>> randomgen.random_integers(5) 4 - >>> type(core_prng.random_integers(5)) + >>> type(randomgen.random_integers(5)) - >>> core_prng.random_integers(5, size=(3.,2.)) + >>> randomgen.random_integers(5, size=(3.,2.)) array([[5, 4], [3, 3], [4, 5]]) @@ -1086,13 +1086,13 @@ cdef class RandomGenerator: numbers between 0 and 2.5, inclusive (*i.e.*, from the set :math:`{0, 5/8, 10/8, 15/8, 20/8}`): - >>> 2.5 * (core_prng.random_integers(5, size=(5,)) - 1) / 4. + >>> 2.5 * (randomgen.random_integers(5, size=(5,)) - 1) / 4. array([ 0.625, 1.25 , 0.625, 0.625, 2.5 ]) Roll two six sided dice 1000 times and sum the results: - >>> d1 = core_prng.random_integers(1, 6, 1000) - >>> d2 = core_prng.random_integers(1, 6, 1000) + >>> d1 = randomgen.random_integers(1, 6, 1000) + >>> d2 = randomgen.random_integers(1, 6, 1000) >>> dsums = d1 + d2 Display results as a histogram: @@ -1145,22 +1145,22 @@ cdef class RandomGenerator: Examples -------- - >>> s = core_prng.standard_normal(8000) + >>> s = randomgen.standard_normal(8000) >>> s array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random -0.38672696, -0.4685006 ]) #random >>> s.shape (8000,) - >>> s = core_prng.standard_normal(size=(3, 4, 2)) + >>> s = randomgen.standard_normal(size=(3, 4, 2)) >>> s.shape (3, 4, 2) """ key = np.dtype(dtype).name if key == 'float64': - return double_fill(&random_gauss_zig, self._prng, size, self.lock, out) + return double_fill(&random_gauss_zig, self._brng, size, self.lock, out) elif key == 'float32': - return float_fill(&random_gauss_zig_f, self._prng, size, self.lock, out) + return float_fill(&random_gauss_zig_f, self._brng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for standard_normal' % key) @@ -1234,7 +1234,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, sigma = 0, 0.1 # mean and standard deviation - >>> s = core_prng.normal(mu, sigma, 1000) + >>> s = randomgen.normal(mu, sigma, 1000) Verify the mean and the variance: @@ -1255,7 +1255,7 @@ cdef class RandomGenerator: >>> plt.show() """ - return cont(&random_normal_zig, self._prng, size, self.lock, 2, + return cont(&random_normal_zig, self._brng, size, self.lock, 2, loc, '', CONS_NONE, scale, 'scale', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, @@ -1316,7 +1316,7 @@ cdef class RandomGenerator: -------- Draw samples from the distribution: - >>> s = core_prng.complex_normal(size=1000) + >>> s = randomgen.complex_normal(size=1000) """ cdef np.ndarray ogamma, orelation, oloc, randoms, v_real, v_imag, rho cdef double *randoms_data @@ -1352,8 +1352,8 @@ cdef class RandomGenerator: raise ValueError('Im(relation) ** 2 > Re(gamma ** 2 - relation** 2)') if size is None: - f_real = random_gauss_zig(self._prng) - f_imag = random_gauss_zig(self._prng) + f_real = random_gauss_zig(self._brng) + f_imag = random_gauss_zig(self._brng) compute_complex(&f_real, &f_imag, floc_r, floc_i, fvar_r, fvar_i, f_rho) return PyComplex_FromDoubles(f_real, f_imag) @@ -1368,8 +1368,8 @@ cdef class RandomGenerator: j = 0 with self.lock, nogil: for i in range(n): - f_real = random_gauss_zig(self._prng) - f_imag = random_gauss_zig(self._prng) + f_real = random_gauss_zig(self._brng) + f_imag = random_gauss_zig(self._brng) randoms_data[j+1] = floc_i + i_scale * (f_rho * f_real + i_r_scale * f_imag) randoms_data[j] = floc_r + r_scale * f_real j += 2 @@ -1407,7 +1407,7 @@ cdef class RandomGenerator: with self.lock, nogil: n2 = 2 * n # Avoid compiler noise for cast for i in range(n2): - randoms_data[i] = random_gauss_zig(self._prng) + randoms_data[i] = random_gauss_zig(self._brng) with nogil: j = 0 for i in range(n): @@ -1485,7 +1485,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> shape, scale = 2., 1. # mean and width - >>> s = core_prng.standard_gamma(shape, 1000000) + >>> s = randomgen.standard_gamma(shape, 1000000) Display the histogram of the samples, along with the probability density function: @@ -1501,13 +1501,13 @@ cdef class RandomGenerator: cdef void *func key = np.dtype(dtype).name if key == 'float64': - return cont(&random_standard_gamma_zig, self._prng, size, self.lock, 1, + return cont(&random_standard_gamma_zig, self._brng, size, self.lock, 1, shape, 'shape', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, out) if key == 'float32': - return cont_f(&random_standard_gamma_zig_f, self._prng, size, self.lock, + return cont_f(&random_standard_gamma_zig_f, self._brng, size, self.lock, shape, 'shape', CONS_NON_NEGATIVE, out) else: @@ -1572,7 +1572,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> shape, scale = 2., 2. # mean and dispersion - >>> s = core_prng.gamma(shape, scale, 1000) + >>> s = randomgen.gamma(shape, scale, 1000) Display the histogram of the samples, along with the probability density function: @@ -1586,7 +1586,7 @@ cdef class RandomGenerator: >>> plt.show() """ - return cont(&random_gamma, self._prng, size, self.lock, 2, + return cont(&random_gamma, self._brng, size, self.lock, 2, shape, 'shape', CONS_NON_NEGATIVE, scale, 'scale', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, None) @@ -1662,7 +1662,7 @@ cdef class RandomGenerator: >>> dfnum = 1. # between group degrees of freedom >>> dfden = 48. # within groups degrees of freedom - >>> s = core_prng.f(dfnum, dfden, 1000) + >>> s = randomgen.f(dfnum, dfden, 1000) The lower bound for the top 1% of the samples is : @@ -1674,7 +1674,7 @@ cdef class RandomGenerator: level. """ - return cont(&random_f, self._prng, size, self.lock, 2, + return cont(&random_f, self._brng, size, self.lock, 2, dfnum, 'dfnum', CONS_POSITIVE, dfden, 'dfden', CONS_POSITIVE, 0.0, '', CONS_NONE, None) @@ -1737,16 +1737,16 @@ cdef class RandomGenerator: >>> dfnum = 3 # between group deg of freedom >>> dfden = 20 # within groups degrees of freedom >>> nonc = 3.0 - >>> nc_vals = core_prng.noncentral_f(dfnum, dfden, nonc, 1000000) + >>> nc_vals = randomgen.noncentral_f(dfnum, dfden, nonc, 1000000) >>> NF = np.histogram(nc_vals, bins=50, normed=True) - >>> c_vals = core_prng.f(dfnum, dfden, 1000000) + >>> c_vals = randomgen.f(dfnum, dfden, 1000000) >>> F = np.histogram(c_vals, bins=50, normed=True) >>> plt.plot(F[1][1:], F[0]) >>> plt.plot(NF[1][1:], NF[0]) >>> plt.show() """ - return cont(&random_noncentral_f, self._prng, size, self.lock, 3, + return cont(&random_noncentral_f, self._brng, size, self.lock, 3, dfnum, 'dfnum', CONS_POSITIVE, dfden, 'dfden', CONS_POSITIVE, nonc, 'nonc', CONS_NON_NEGATIVE, None) @@ -1810,11 +1810,11 @@ cdef class RandomGenerator: Examples -------- - >>> core_prng.chisquare(2,4) + >>> randomgen.chisquare(2,4) array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) """ - return cont(&random_chisquare, self._prng, size, self.lock, 1, + return cont(&random_chisquare, self._brng, size, self.lock, 1, df, 'df', CONS_POSITIVE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) @@ -1875,7 +1875,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram >>> import matplotlib.pyplot as plt - >>> values = plt.hist(core_prng.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), ... bins=200, normed=True) >>> plt.show() @@ -1883,9 +1883,9 @@ cdef class RandomGenerator: and compare to a chisquare. >>> plt.figure() - >>> values = plt.hist(core_prng.noncentral_chisquare(3, .0000001, 100000), + >>> values = plt.hist(randomgen.noncentral_chisquare(3, .0000001, 100000), ... bins=np.arange(0., 25, .1), normed=True) - >>> values2 = plt.hist(core_prng.chisquare(3, 100000), + >>> values2 = plt.hist(randomgen.chisquare(3, 100000), ... bins=np.arange(0., 25, .1), normed=True) >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') >>> plt.show() @@ -1894,12 +1894,12 @@ cdef class RandomGenerator: distribution. >>> plt.figure() - >>> values = plt.hist(core_prng.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), ... bins=200, normed=True) >>> plt.show() """ - return cont(&random_noncentral_chisquare, self._prng, size, self.lock, 2, + return cont(&random_noncentral_chisquare, self._brng, size, self.lock, 2, df, 'df', CONS_POSITIVE, nonc, 'nonc', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, None) @@ -1959,13 +1959,13 @@ cdef class RandomGenerator: -------- Draw samples and plot the distribution: - >>> s = core_prng.standard_cauchy(1000000) + >>> s = randomgen.standard_cauchy(1000000) >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well >>> plt.hist(s, bins=100) >>> plt.show() """ - return cont(&random_standard_cauchy, self._prng, size, self.lock, 0, + return cont(&random_standard_cauchy, self._brng, size, self.lock, 0, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) def standard_t(self, df, size=None): @@ -2032,7 +2032,7 @@ cdef class RandomGenerator: We have 10 degrees of freedom, so is the sample mean within 95% of the recommended value? - >>> s = core_prng.standard_t(10, size=100000) + >>> s = randomgen.standard_t(10, size=100000) >>> np.mean(intake) 6753.636363636364 >>> intake.std(ddof=1) @@ -2056,7 +2056,7 @@ cdef class RandomGenerator: probability of about 99% of being true. """ - return cont(&random_standard_t, self._prng, size, self.lock, 1, + return cont(&random_standard_t, self._brng, size, self.lock, 1, df, 'df', CONS_POSITIVE, 0, '', CONS_NONE, 0, '', CONS_NONE, @@ -2126,7 +2126,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, kappa = 0.0, 4.0 # mean and dispersion - >>> s = core_prng.vonmises(mu, kappa, 1000) + >>> s = randomgen.vonmises(mu, kappa, 1000) Display the histogram of the samples, along with the probability density function: @@ -2140,7 +2140,7 @@ cdef class RandomGenerator: >>> plt.show() """ - return cont(&random_vonmises, self._prng, size, self.lock, 2, + return cont(&random_vonmises, self._brng, size, self.lock, 2, mu, 'mu', CONS_NONE, kappa, 'kappa', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, None) @@ -2226,7 +2226,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a, m = 3., 2. # shape and mode - >>> s = (core_prng.pareto(a, 1000) + 1) * m + >>> s = (randomgen.pareto(a, 1000) + 1) * m Display the histogram of the samples, along with the probability density function: @@ -2238,7 +2238,7 @@ cdef class RandomGenerator: >>> plt.show() """ - return cont(&random_pareto, self._prng, size, self.lock, 1, + return cont(&random_pareto, self._brng, size, self.lock, 1, a, 'a', CONS_POSITIVE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) @@ -2319,7 +2319,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a = 5. # shape - >>> s = core_prng.weibull(a, 1000) + >>> s = randomgen.weibull(a, 1000) Display the histogram of the samples, along with the probability density function: @@ -2329,14 +2329,14 @@ cdef class RandomGenerator: >>> def weib(x,n,a): ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) - >>> count, bins, ignored = plt.hist(core_prng.weibull(5.,1000)) + >>> count, bins, ignored = plt.hist(randomgen.weibull(5.,1000)) >>> x = np.arange(1,100.)/50. >>> scale = count.max()/weib(x, 1., 5.).max() >>> plt.plot(x, weib(x, 1., 5.)*scale) >>> plt.show() """ - return cont(&random_weibull, self._prng, size, self.lock, 1, + return cont(&random_weibull, self._brng, size, self.lock, 1, a, 'a', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) @@ -2399,7 +2399,7 @@ cdef class RandomGenerator: >>> a = 5. # shape >>> samples = 1000 - >>> s = core_prng.power(a, samples) + >>> s = randomgen.power(a, samples) Display the histogram of the samples, along with the probability density function: @@ -2415,20 +2415,20 @@ cdef class RandomGenerator: Compare the power function distribution to the inverse of the Pareto. >>> from scipy import stats - >>> rvs = core_prng.power(5, 1000000) - >>> rvsp = core_prng.pareto(5, 1000000) + >>> rvs = randomgen.power(5, 1000000) + >>> rvsp = randomgen.pareto(5, 1000000) >>> xx = np.linspace(0,1,100) >>> powpdf = stats.powerlaw.pdf(xx,5) >>> plt.figure() >>> plt.hist(rvs, bins=50, normed=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('core_prng.power(5)') + >>> plt.title('randomgen.power(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('inverse of 1 + core_prng.pareto(5)') + >>> plt.title('inverse of 1 + randomgen.pareto(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) @@ -2436,7 +2436,7 @@ cdef class RandomGenerator: >>> plt.title('inverse of stats.pareto(5)') """ - return cont(&random_power, self._prng, size, self.lock, 1, + return cont(&random_power, self._brng, size, self.lock, 1, a, 'a', CONS_POSITIVE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) @@ -2502,7 +2502,7 @@ cdef class RandomGenerator: Draw samples from the distribution >>> loc, scale = 0., 1. - >>> s = core_prng.laplace(loc, scale, 1000) + >>> s = randomgen.laplace(loc, scale, 1000) Display the histogram of the samples, along with the probability density function: @@ -2520,7 +2520,7 @@ cdef class RandomGenerator: >>> plt.plot(x,g) """ - return cont(&random_laplace, self._prng, size, self.lock, 2, + return cont(&random_laplace, self._brng, size, self.lock, 2, loc, 'loc', CONS_NONE, scale, 'scale', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, None) @@ -2604,7 +2604,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, beta = 0, 0.1 # location and scale - >>> s = core_prng.gumbel(mu, beta, 1000) + >>> s = randomgen.gumbel(mu, beta, 1000) Display the histogram of the samples, along with the probability density function: @@ -2622,7 +2622,7 @@ cdef class RandomGenerator: >>> means = [] >>> maxima = [] >>> for i in range(0,1000) : - ... a = core_prng.normal(mu, beta, 1000) + ... a = randomgen.normal(mu, beta, 1000) ... means.append(a.mean()) ... maxima.append(a.max()) >>> count, bins, ignored = plt.hist(maxima, 30, normed=True) @@ -2637,7 +2637,7 @@ cdef class RandomGenerator: >>> plt.show() """ - return cont(&random_gumbel, self._prng, size, self.lock, 2, + return cont(&random_gumbel, self._brng, size, self.lock, 2, loc, 'loc', CONS_NONE, scale, 'scale', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, None) @@ -2704,7 +2704,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> loc, scale = 10, 1 - >>> s = core_prng.logistic(loc, scale, 10000) + >>> s = randomgen.logistic(loc, scale, 10000) >>> count, bins, ignored = plt.hist(s, bins=50) # plot against distribution @@ -2716,7 +2716,7 @@ cdef class RandomGenerator: >>> plt.show() """ - return cont(&random_logistic, self._prng, size, self.lock, 2, + return cont(&random_logistic, self._brng, size, self.lock, 2, loc, 'loc', CONS_NONE, scale, 'scale', CONS_POSITIVE, 0.0, '', CONS_NONE, None) @@ -2786,7 +2786,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, sigma = 3., 1. # mean and standard deviation - >>> s = core_prng.lognormal(mu, sigma, 1000) + >>> s = randomgen.lognormal(mu, sigma, 1000) Display the histogram of the samples, along with the probability density function: @@ -2810,7 +2810,7 @@ cdef class RandomGenerator: >>> # values, drawn from a normal distribution. >>> b = [] >>> for i in range(1000): - ... a = 10. + core_prng.random(100) + ... a = 10. + randomgen.random(100) ... b.append(np.product(a)) >>> b = np.array(b) / np.min(b) # scale values to be positive @@ -2826,7 +2826,7 @@ cdef class RandomGenerator: >>> plt.show() """ - return cont(&random_lognormal, self._prng, size, self.lock, 2, + return cont(&random_lognormal, self._brng, size, self.lock, 2, mean, 'mean', CONS_NONE, sigma, 'sigma', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, None) @@ -2877,7 +2877,7 @@ cdef class RandomGenerator: -------- Draw values from the distribution and plot the histogram - >>> values = hist(core_prng.rayleigh(3, 100000), bins=200, normed=True) + >>> values = hist(randomgen.rayleigh(3, 100000), bins=200, normed=True) Wave heights tend to follow a Rayleigh distribution. If the mean wave height is 1 meter, what fraction of waves are likely to be larger than 3 @@ -2885,7 +2885,7 @@ cdef class RandomGenerator: >>> meanvalue = 1 >>> modevalue = np.sqrt(2 / np.pi) * meanvalue - >>> s = core_prng.rayleigh(modevalue, 1000000) + >>> s = randomgen.rayleigh(modevalue, 1000000) The percentage of waves larger than 3 meters is: @@ -2893,7 +2893,7 @@ cdef class RandomGenerator: 0.087300000000000003 """ - return cont(&random_rayleigh, self._prng, size, self.lock, 1, + return cont(&random_rayleigh, self._brng, size, self.lock, 1, scale, 'scale', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) @@ -2957,11 +2957,11 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(core_prng.wald(3, 2, 100000), bins=200, normed=True) + >>> h = plt.hist(randomgen.wald(3, 2, 100000), bins=200, normed=True) >>> plt.show() """ - return cont(&random_wald, self._prng, size, self.lock, 2, + return cont(&random_wald, self._brng, size, self.lock, 2, mean, 'mean', CONS_POSITIVE, scale, 'scale', CONS_POSITIVE, 0.0, '', CONS_NONE, None) @@ -3024,7 +3024,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(core_prng.triangular(-3, 0, 8, 100000), bins=200, + >>> h = plt.hist(randomgen.triangular(-3, 0, 8, 100000), bins=200, ... normed=True) >>> plt.show() @@ -3048,7 +3048,7 @@ cdef class RandomGenerator: raise ValueError("mode > right") if fleft == fright: raise ValueError("left == right") - return cont(&random_triangular, self._prng, size, self.lock, 3, + return cont(&random_triangular, self._brng, size, self.lock, 3, fleft, '', CONS_NONE, fmode, '', CONS_NONE, fright, '', CONS_NONE, None) @@ -3060,7 +3060,7 @@ cdef class RandomGenerator: if np.any(np.equal(oleft, oright)): raise ValueError("left == right") - return cont_broadcast_3(&random_triangular, self._prng, size, self.lock, + return cont_broadcast_3(&random_triangular, self._brng, size, self.lock, oleft, '', CONS_NONE, omode, '', CONS_NONE, oright, '', CONS_NONE) @@ -3137,7 +3137,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> n, p = 10, .5 # number of trials, probability of each trial - >>> s = core_prng.binomial(n, p, 1000) + >>> s = randomgen.binomial(n, p, 1000) # result of flipping a coin 10 times, tested 1000 times. A real world example. A company drills 9 wild-cat oil exploration @@ -3147,7 +3147,7 @@ cdef class RandomGenerator: Let's do 20,000 trials of the model, and count the number that generate zero positive results. - >>> sum(core_prng.binomial(9, 0.1, 20000) == 0)/20000. + >>> sum(randomgen.binomial(9, 0.1, 20000) == 0)/20000. # answer = 0.38885, or 38%. """ @@ -3182,7 +3182,7 @@ cdef class RandomGenerator: for i in range(cnt): _dp = (np.PyArray_MultiIter_DATA(it, 1))[0] _in = (np.PyArray_MultiIter_DATA(it, 2))[0] - (np.PyArray_MultiIter_DATA(it, 0))[0] = random_binomial(self._prng, _dp, _in, self._binomial) + (np.PyArray_MultiIter_DATA(it, 0))[0] = random_binomial(self._brng, _dp, _in, self._binomial) np.PyArray_MultiIter_NEXT(it) @@ -3195,7 +3195,7 @@ cdef class RandomGenerator: if size is None: with self.lock: - return random_binomial(self._prng, _dp, _in, self._binomial) + return random_binomial(self._brng, _dp, _in, self._binomial) randoms = np.empty(size, np.int64) cnt = np.PyArray_SIZE(randoms) @@ -3203,7 +3203,7 @@ cdef class RandomGenerator: with self.lock, nogil: for i in range(cnt): - randoms_data[i] = random_binomial(self._prng, _dp, _in, + randoms_data[i] = random_binomial(self._brng, _dp, _in, self._binomial) return randoms @@ -3274,13 +3274,13 @@ cdef class RandomGenerator: for each successive well, that is what is the probability of a single success after drilling 5 wells, after 6 wells, etc.? - >>> s = core_prng.negative_binomial(1, 0.1, 100000) + >>> s = randomgen.negative_binomial(1, 0.1, 100000) >>> for i in range(1, 11): ... probability = sum(s>> import numpy as np - >>> s = core_prng.poisson(5, 10000) + >>> s = randomgen.poisson(5, 10000) Display histogram of the sample: @@ -3348,10 +3348,10 @@ cdef class RandomGenerator: Draw each 100 values for lambda 100 and 500: - >>> s = core_prng.poisson(lam=(100., 500.), size=(100, 2)) + >>> s = randomgen.poisson(lam=(100., 500.), size=(100, 2)) """ - return disc(&random_poisson, self._prng, size, self.lock, 1, 0, + return disc(&random_poisson, self._brng, size, self.lock, 1, 0, lam, 'lam', CONS_POISSON, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE) @@ -3413,7 +3413,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a = 2. # parameter - >>> s = core_prng.zipf(a, 1000) + >>> s = randomgen.zipf(a, 1000) Display the histogram of the samples, along with the probability density function: @@ -3430,7 +3430,7 @@ cdef class RandomGenerator: >>> plt.show() """ - return disc(&random_zipf, self._prng, size, self.lock, 1, 0, + return disc(&random_zipf, self._brng, size, self.lock, 1, 0, a, 'a', CONS_GT_1, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE) @@ -3473,7 +3473,7 @@ cdef class RandomGenerator: Draw ten thousand values from the geometric distribution, with the probability of an individual success equal to 0.35: - >>> z = core_prng.geometric(p=0.35, size=10000) + >>> z = randomgen.geometric(p=0.35, size=10000) How many trials succeeded after a single run? @@ -3481,7 +3481,7 @@ cdef class RandomGenerator: 0.34889999999999999 #random """ - return disc(&random_geometric, self._prng, size, self.lock, 1, 0, + return disc(&random_geometric, self._brng, size, self.lock, 1, 0, p, 'p', CONS_BOUNDED_0_1, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE) @@ -3561,7 +3561,7 @@ cdef class RandomGenerator: >>> ngood, nbad, nsamp = 100, 2, 10 # number of good, number of bad, and number of samples - >>> s = core_prng.hypergeometric(ngood, nbad, nsamp, 1000) + >>> s = randomgen.hypergeometric(ngood, nbad, nsamp, 1000) >>> hist(s) # note that it is very unlikely to grab both bad items @@ -3569,7 +3569,7 @@ cdef class RandomGenerator: If you pull 15 marbles at random, how likely is it that 12 or more of them are one color? - >>> s = core_prng.hypergeometric(15, 15, 15, 100000) + >>> s = randomgen.hypergeometric(15, 15, 15, 100000) >>> sum(s>=12)/100000. + sum(s<=3)/100000. # answer = 0.003 ... pretty unlikely! @@ -3596,14 +3596,14 @@ cdef class RandomGenerator: raise ValueError("nsample < 1") if lngood + lnbad < lnsample: raise ValueError("ngood + nbad < nsample") - return disc(&random_hypergeometric, self._prng, size, self.lock, 0, 3, + return disc(&random_hypergeometric, self._brng, size, self.lock, 0, 3, lngood, 'ngood', CONS_NON_NEGATIVE, lnbad, 'nbad', CONS_NON_NEGATIVE, lnsample, 'nsample', CONS_GTE_1) if np.any(np.less(np.add(ongood, onbad),onsample)): raise ValueError("ngood + nbad < nsample") - return discrete_broadcast_iii(&random_hypergeometric, self._prng, size, self.lock, + return discrete_broadcast_iii(&random_hypergeometric, self._brng, size, self.lock, ongood, 'ngood', CONS_NON_NEGATIVE, onbad, nbad, CONS_NON_NEGATIVE, onsample, 'nsample', CONS_GTE_1) @@ -3670,7 +3670,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a = .6 - >>> s = core_prng.logseries(a, 10000) + >>> s = randomgen.logseries(a, 10000) >>> count, bins, ignored = plt.hist(s) # plot against distribution @@ -3682,7 +3682,7 @@ cdef class RandomGenerator: >>> plt.show() """ - return disc(&random_logseries, self._prng, size, self.lock, 1, 0, + return disc(&random_logseries, self._brng, size, self.lock, 1, 0, p, 'p', CONS_BOUNDED_0_1, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE) @@ -3758,7 +3758,7 @@ cdef class RandomGenerator: Diagonal covariance means that points are oriented along x or y-axis: >>> import matplotlib.pyplot as plt - >>> x, y = core_prng.multivariate_normal(mean, cov, 5000).T + >>> x, y = randomgen.multivariate_normal(mean, cov, 5000).T >>> plt.plot(x, y, 'x') >>> plt.axis('equal') >>> plt.show() @@ -3778,7 +3778,7 @@ cdef class RandomGenerator: -------- >>> mean = (1, 2) >>> cov = [[1, 0], [0, 1]] - >>> x = core_prng.multivariate_normal(mean, cov, (3, 3)) + >>> x = randomgen.multivariate_normal(mean, cov, (3, 3)) >>> x.shape (3, 3, 2) @@ -3890,14 +3890,14 @@ cdef class RandomGenerator: -------- Throw a dice 20 times: - >>> core_prng.multinomial(20, [1/6.]*6, size=1) + >>> randomgen.multinomial(20, [1/6.]*6, size=1) array([[4, 1, 7, 5, 2, 1]]) It landed 4 times on 1, once on 2, etc. Now, throw the dice 20 times, and 20 times again: - >>> core_prng.multinomial(20, [1/6.]*6, size=2) + >>> randomgen.multinomial(20, [1/6.]*6, size=2) array([[3, 4, 3, 3, 4, 3], [2, 4, 3, 4, 0, 7]]) @@ -3906,7 +3906,7 @@ cdef class RandomGenerator: A loaded die is more likely to land on number 6: - >>> core_prng.multinomial(100, [1/7.]*5 + [2/7.]) + >>> randomgen.multinomial(100, [1/7.]*5 + [2/7.]) array([11, 16, 14, 17, 16, 26]) The probability inputs should be normalized. As an implementation @@ -3915,12 +3915,12 @@ cdef class RandomGenerator: A biased coin which has twice as much weight on one side as on the other should be sampled like so: - >>> core_prng.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT + >>> randomgen.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT array([38, 62]) not like: - >>> core_prng.multinomial(100, [1.0, 2.0]) # WRONG + >>> randomgen.multinomial(100, [1.0, 2.0]) # WRONG array([100, 0]) """ @@ -3956,7 +3956,7 @@ cdef class RandomGenerator: Sum = 1.0 dn = n for j in range(d-1): - mnix[i+j] = random_binomial(self._prng, pix[j]/Sum, dn, + mnix[i+j] = random_binomial(self._brng, pix[j]/Sum, dn, self._binomial) dn = dn - mnix[i+j] if dn <= 0: @@ -4021,7 +4021,7 @@ cdef class RandomGenerator: average length, but allowing some variation in the relative sizes of the pieces. - >>> s = core_prng.dirichlet((10, 5, 3), 20).transpose() + >>> s = randomgen.dirichlet((10, 5, 3), 20).transpose() >>> plt.barh(range(20), s[0]) >>> plt.barh(range(20), s[1], left=s[0], color='g') @@ -4082,7 +4082,7 @@ cdef class RandomGenerator: while i < totsize: acc = 0.0 for j in range(k): - val_data[i+j] = random_standard_gamma_zig(self._prng, + val_data[i+j] = random_standard_gamma_zig(self._brng, alpha_data[j]) acc = acc + val_data[i + j] invacc = 1/acc @@ -4115,14 +4115,14 @@ cdef class RandomGenerator: Examples -------- >>> arr = np.arange(10) - >>> core_prng.shuffle(arr) + >>> randomgen.shuffle(arr) >>> arr [1 7 5 2 9 4 3 6 0 8] Multi-dimensional arrays are only shuffled along the first axis: >>> arr = np.arange(9).reshape((3, 3)) - >>> core_prng.shuffle(arr) + >>> randomgen.shuffle(arr) >>> arr array([[3, 4, 5], [6, 7, 8], @@ -4160,7 +4160,7 @@ cdef class RandomGenerator: buf = np.empty_like(x[0]) with self.lock: for i in reversed(range(1, n)): - j = random_interval(self._prng, i) + j = random_interval(self._brng, i) if i == j : continue # i == j is not needed and memcpy is undefined. buf[...] = x[j] x[j] = x[i] @@ -4169,14 +4169,14 @@ cdef class RandomGenerator: # Untyped path. with self.lock: for i in reversed(range(1, n)): - j = random_interval(self._prng, i) + j = random_interval(self._brng, i) x[i], x[j] = x[j], x[i] cdef inline _shuffle_raw(self, np.npy_intp n, np.npy_intp itemsize, np.npy_intp stride, char* data, char* buf): cdef np.npy_intp i, j for i in reversed(range(1, n)): - j = random_interval(self._prng, i) + j = random_interval(self._brng, i) string.memcpy(buf, data + j * stride, itemsize) string.memcpy(data + j * stride, data + i * stride, itemsize) string.memcpy(data + i * stride, buf, itemsize) @@ -4204,14 +4204,14 @@ cdef class RandomGenerator: Examples -------- - >>> core_prng.permutation(10) + >>> randomgen.permutation(10) array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) - >>> core_prng.permutation([1, 4, 9, 12, 15]) + >>> randomgen.permutation([1, 4, 9, 12, 15]) array([15, 1, 9, 4, 12]) >>> arr = np.arange(9).reshape((3, 3)) - >>> core_prng.permutation(arr) + >>> randomgen.permutation(arr) array([[6, 7, 8], [0, 1, 2], [3, 4, 5]]) diff --git a/_randomgen/core_prng/mt19937.pyx b/_randomgen/randomgen/mt19937.pyx similarity index 82% rename from _randomgen/core_prng/mt19937.pyx rename to _randomgen/randomgen/mt19937.pyx index 9622b725a236..483bd6baa107 100644 --- a/_randomgen/core_prng/mt19937.pyx +++ b/_randomgen/randomgen/mt19937.pyx @@ -7,9 +7,9 @@ import numpy as np cimport numpy as np from common cimport * -from distributions cimport prng_t -import core_prng.pickle -from core_prng.entropy import random_entropy +from distributions cimport brng_t +import randomgen.pickle +from randomgen.entropy import random_entropy np.import_array() @@ -42,7 +42,7 @@ cdef uint64_t mt19937_raw(void *st) nogil: cdef class MT19937: """ - Prototype Core PRNG using MT19937 + Prototype Basic RNG using MT19937 Parameters ---------- @@ -55,26 +55,26 @@ cdef class MT19937: `RandomGenerator` object. """ cdef mt19937_state *rng_state - cdef prng_t *_prng + cdef brng_t *_brng cdef public object capsule def __init__(self, seed=None): self.rng_state = malloc(sizeof(mt19937_state)) - self._prng = malloc(sizeof(prng_t)) + self._brng = malloc(sizeof(brng_t)) self.seed(seed) - self._prng.state = self.rng_state - self._prng.next_uint64 = &mt19937_uint64 - self._prng.next_uint32 = &mt19937_uint32 - self._prng.next_double = &mt19937_double - self._prng.next_raw = &mt19937_raw + self._brng.state = self.rng_state + self._brng.next_uint64 = &mt19937_uint64 + self._brng.next_uint32 = &mt19937_uint32 + self._brng.next_double = &mt19937_double + self._brng.next_raw = &mt19937_raw - cdef const char *name = "CorePRNG" - self.capsule = PyCapsule_New(self._prng, name, NULL) + cdef const char *name = "BasicRNG" + self.capsule = PyCapsule_New(self._brng, name, NULL) def __dealloc__(self): free(self.rng_state) - free(self._prng) + free(self._brng) # Pickling support: def __getstate__(self): @@ -84,8 +84,8 @@ cdef class MT19937: self.state = state def __reduce__(self): - return (core_prng.pickle.__prng_ctor, - (self.state['prng'],), + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), self.state) def __random_integer(self, bits=64): @@ -107,9 +107,9 @@ cdef class MT19937: Testing only """ if bits == 64: - return self._prng.next_uint64(self._prng.state) + return self._brng.next_uint64(self._brng.state) elif bits == 32: - return self._prng.next_uint32(self._prng.state) + return self._brng.next_uint32(self._brng.state) else: raise ValueError('bits must be 32 or 64') @@ -117,10 +117,10 @@ cdef class MT19937: cdef Py_ssize_t i if method==u'uint64': for i in range(cnt): - self._prng.next_uint64(self._prng.state) + self._brng.next_uint64(self._brng.state) elif method==u'double': for i in range(cnt): - self._prng.next_double(self._prng.state) + self._brng.next_double(self._brng.state) else: raise ValueError('Unknown method') @@ -177,7 +177,7 @@ cdef class MT19937: for i in range(624): key[i] = self.rng_state.key[i] - return {'prng': self.__class__.__name__, + return {'brng': self.__class__.__name__, 'state': {'key':key, 'pos': self.rng_state.pos}} @state.setter @@ -185,14 +185,14 @@ cdef class MT19937: if isinstance(value, tuple): if value[0] != 'MT19937' or len(value) not in (3,5): raise ValueError('state is not a legacy MT19937 state') - value ={'prng': 'MT19937', + value ={'brng': 'MT19937', 'state':{'key': value[1], 'pos': value[2]}} if not isinstance(value, dict): raise TypeError('state must be a dict') - prng = value.get('prng', '') - if prng != self.__class__.__name__: + brng = value.get('brng', '') + if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) key = value['state']['key'] diff --git a/_randomgen/core_prng/pcg32.pyx b/_randomgen/randomgen/pcg32.pyx similarity index 83% rename from _randomgen/core_prng/pcg32.pyx rename to _randomgen/randomgen/pcg32.pyx index 104701142e78..d0b57a2b0562 100644 --- a/_randomgen/core_prng/pcg32.pyx +++ b/_randomgen/randomgen/pcg32.pyx @@ -5,9 +5,9 @@ import numpy as np cimport numpy as np from common cimport * -from distributions cimport prng_t -from core_prng.entropy import random_entropy -import core_prng.pickle +from distributions cimport brng_t +from randomgen.entropy import random_entropy +import randomgen.pickle np.import_array() @@ -47,7 +47,7 @@ cdef uint64_t pcg32_raw(void* st) nogil: cdef class PCG32: """ - Prototype Core PRNG using pcg64 + Prototype Basic RNG using pcg64 Parameters ---------- @@ -60,23 +60,23 @@ cdef class PCG32: for use in a `RandomGenerator` object. """ cdef pcg32_state *rng_state - cdef prng_t *_prng + cdef brng_t *_brng cdef public object capsule def __init__(self, seed=None, inc=0): self.rng_state = malloc(sizeof(pcg32_state)) self.rng_state.pcg_state = malloc(sizeof(pcg32_random_t)) - self._prng = malloc(sizeof(prng_t)) + self._brng = malloc(sizeof(brng_t)) self.seed(seed, inc) - self._prng.state = self.rng_state - self._prng.next_uint64 = &pcg32_uint64 - self._prng.next_uint32 = &pcg32_uint32 - self._prng.next_double = &pcg32_double - self._prng.next_raw = &pcg32_raw + self._brng.state = self.rng_state + self._brng.next_uint64 = &pcg32_uint64 + self._brng.next_uint32 = &pcg32_uint32 + self._brng.next_double = &pcg32_double + self._brng.next_raw = &pcg32_raw - cdef const char *name = "CorePRNG" - self.capsule = PyCapsule_New(self._prng, name, NULL) + cdef const char *name = "BasicRNG" + self.capsule = PyCapsule_New(self._brng, name, NULL) # Pickling support: def __getstate__(self): @@ -86,13 +86,13 @@ cdef class PCG32: self.state = state def __reduce__(self): - return (core_prng.pickle.__prng_ctor, - (self.state['prng'],), + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), self.state) def __dealloc__(self): free(self.rng_state) - free(self._prng) + free(self._brng) def __random_integer(self, bits=64): """ @@ -113,9 +113,9 @@ cdef class PCG32: Testing only """ if bits == 64: - return self._prng.next_uint64(self._prng.state) + return self._brng.next_uint64(self._brng.state) elif bits == 32: - return self._prng.next_uint32(self._prng.state) + return self._brng.next_uint32(self._brng.state) else: raise ValueError('bits must be 32 or 64') @@ -123,10 +123,10 @@ cdef class PCG32: cdef Py_ssize_t i if method==u'uint64': for i in range(cnt): - self._prng.next_uint64(self._prng.state) + self._brng.next_uint64(self._brng.state) elif method==u'double': for i in range(cnt): - self._prng.next_double(self._prng.state) + self._brng.next_double(self._brng.state) else: raise ValueError('Unknown method') @@ -183,7 +183,7 @@ cdef class PCG32: @property def state(self): """Get or set the PRNG state""" - return {'prng': self.__class__.__name__, + return {'brng': self.__class__.__name__, 'state': {'state': self.rng_state.pcg_state.state, 'inc':self.rng_state.pcg_state.inc}} @@ -191,8 +191,8 @@ cdef class PCG32: def state(self, value): if not isinstance(value, dict): raise TypeError('state must be a dict') - prng = value.get('prng', '') - if prng != self.__class__.__name__: + brng = value.get('brng', '') + if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) self.rng_state.pcg_state.state = value['state']['state'] diff --git a/_randomgen/core_prng/pcg64.pyx b/_randomgen/randomgen/pcg64.pyx similarity index 87% rename from _randomgen/core_prng/pcg64.pyx rename to _randomgen/randomgen/pcg64.pyx index 332553c1b119..7afe1266d9f5 100644 --- a/_randomgen/core_prng/pcg64.pyx +++ b/_randomgen/randomgen/pcg64.pyx @@ -5,9 +5,9 @@ import numpy as np cimport numpy as np from common cimport * -from distributions cimport prng_t -from core_prng.entropy import random_entropy -import core_prng.pickle +from distributions cimport brng_t +from randomgen.entropy import random_entropy +import randomgen.pickle np.import_array() @@ -62,7 +62,7 @@ cdef double pcg64_double(void* st) nogil: cdef class PCG64: """ - Prototype Core PRNG using pcg64 + Prototype Basic RNG using pcg64 Parameters ---------- @@ -75,23 +75,23 @@ cdef class PCG64: for use in a `RandomGenerator` object. """ cdef pcg64_state *rng_state - cdef prng_t *_prng + cdef brng_t *_brng cdef public object capsule def __init__(self, seed=None, inc=0): self.rng_state = malloc(sizeof(pcg64_state)) self.rng_state.pcg_state = malloc(sizeof(pcg64_random_t)) - self._prng = malloc(sizeof(prng_t)) + self._brng = malloc(sizeof(brng_t)) self.seed(seed, inc) - self._prng.state = self.rng_state - self._prng.next_uint64 = &pcg64_uint64 - self._prng.next_uint32 = &pcg64_uint32 - self._prng.next_double = &pcg64_double - self._prng.next_raw = &pcg64_uint64 + self._brng.state = self.rng_state + self._brng.next_uint64 = &pcg64_uint64 + self._brng.next_uint32 = &pcg64_uint32 + self._brng.next_double = &pcg64_double + self._brng.next_raw = &pcg64_uint64 - cdef const char *name = "CorePRNG" - self.capsule = PyCapsule_New(self._prng, name, NULL) + cdef const char *name = "BasicRNG" + self.capsule = PyCapsule_New(self._brng, name, NULL) # Pickling support: def __getstate__(self): @@ -101,13 +101,13 @@ cdef class PCG64: self.state = state def __reduce__(self): - return (core_prng.pickle.__prng_ctor, - (self.state['prng'],), + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), self.state) def __dealloc__(self): free(self.rng_state) - free(self._prng) + free(self._brng) cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 @@ -132,9 +132,9 @@ cdef class PCG64: Testing only """ if bits == 64: - return self._prng.next_uint64(self._prng.state) + return self._brng.next_uint64(self._brng.state) elif bits == 32: - return self._prng.next_uint32(self._prng.state) + return self._brng.next_uint32(self._brng.state) else: raise ValueError('bits must be 32 or 64') @@ -142,10 +142,10 @@ cdef class PCG64: cdef Py_ssize_t i if method==u'uint64': for i in range(cnt): - self._prng.next_uint64(self._prng.state) + self._brng.next_uint64(self._brng.state) elif method==u'double': for i in range(cnt): - self._prng.next_double(self._prng.state) + self._brng.next_double(self._brng.state) else: raise ValueError('Unknown method') @@ -217,7 +217,7 @@ cdef class PCG64: state = self.rng_state.pcg_state.state inc = self.rng_state.pcg_state.inc - return {'prng': self.__class__.__name__, + return {'brng': self.__class__.__name__, 'state': {'state': state, 'inc':inc}, 'has_uint32': self.rng_state.has_uint32, 'uinteger': self.rng_state.uinteger} @@ -226,8 +226,8 @@ cdef class PCG64: def state(self, value): if not isinstance(value, dict): raise TypeError('state must be a dict') - prng = value.get('prng', '') - if prng != self.__class__.__name__: + brng = value.get('brng', '') + if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) IF PCG_EMULATED_MATH==1: diff --git a/_randomgen/core_prng/philox.pyx b/_randomgen/randomgen/philox.pyx similarity index 87% rename from _randomgen/core_prng/philox.pyx rename to _randomgen/randomgen/philox.pyx index e55bd27bd314..a61f785331b4 100644 --- a/_randomgen/core_prng/philox.pyx +++ b/_randomgen/randomgen/philox.pyx @@ -4,9 +4,9 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np from common cimport * -from distributions cimport prng_t -from core_prng.entropy import random_entropy, seed_by_array -import core_prng.pickle +from distributions cimport brng_t +from randomgen.entropy import random_entropy, seed_by_array +import randomgen.pickle np.import_array() @@ -52,7 +52,7 @@ cdef double philox_double(void*st) nogil: cdef class Philox: """ - Prototype Core PRNG using philox + Prototype Basic RNG using philox Parameters ---------- @@ -65,7 +65,7 @@ cdef class Philox: a `RandomGenerator` object. """ cdef philox_state *rng_state - cdef prng_t *_prng + cdef brng_t *_brng cdef public object capsule def __init__(self, seed=None, counter=None, key=None): @@ -74,17 +74,17 @@ cdef class Philox: sizeof(philox4x64_ctr_t)) self.rng_state.key = malloc( sizeof(philox4x64_key_t)) - self._prng = malloc(sizeof(prng_t)) + self._brng = malloc(sizeof(brng_t)) self.seed(seed, counter, key) - self._prng.state = self.rng_state - self._prng.next_uint64 = &philox_uint64 - self._prng.next_uint32 = &philox_uint32 - self._prng.next_double = &philox_double - self._prng.next_raw = &philox_uint64 + self._brng.state = self.rng_state + self._brng.next_uint64 = &philox_uint64 + self._brng.next_uint32 = &philox_uint32 + self._brng.next_double = &philox_double + self._brng.next_raw = &philox_uint64 - cdef const char *name = 'CorePRNG' - self.capsule = PyCapsule_New( self._prng, name, NULL) + cdef const char *name = 'BasicRNG' + self.capsule = PyCapsule_New( self._brng, name, NULL) # Pickling support: def __getstate__(self): @@ -94,15 +94,15 @@ cdef class Philox: self.state = state def __reduce__(self): - return (core_prng.pickle.__prng_ctor, - (self.state['prng'],), + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), self.state) def __dealloc__(self): free(self.rng_state.ctr) free(self.rng_state.key) free(self.rng_state) - free(self._prng) + free(self._brng) cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 @@ -130,9 +130,9 @@ cdef class Philox: Testing only """ if bits == 64: - return self._prng.next_uint64(self._prng.state) + return self._brng.next_uint64(self._brng.state) elif bits == 32: - return self._prng.next_uint32(self._prng.state) + return self._brng.next_uint32(self._brng.state) else: raise ValueError('bits must be 32 or 64') @@ -140,10 +140,10 @@ cdef class Philox: cdef Py_ssize_t i if method==u'uint64': for i in range(cnt): - self._prng.next_uint64(self._prng.state) + self._brng.next_uint64(self._brng.state) elif method==u'double': for i in range(cnt): - self._prng.next_double(self._prng.state) + self._brng.next_double(self._brng.state) else: raise ValueError('Unknown method') @@ -217,7 +217,7 @@ cdef class Philox: buffer[i] = self.rng_state.buffer[i] state = {'counter': ctr, 'key': key} - return {'prng': self.__class__.__name__, + return {'brng': self.__class__.__name__, 'state': state, 'buffer': buffer, 'buffer_pos': self.rng_state.buffer_pos, @@ -228,8 +228,8 @@ cdef class Philox: def state(self, value): if not isinstance(value, dict): raise TypeError('state must be a dict') - prng = value.get('prng', '') - if prng != self.__class__.__name__: + brng = value.get('brng', '') + if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) for i in range(4): diff --git a/_randomgen/core_prng/pickle.py b/_randomgen/randomgen/pickle.py similarity index 65% rename from _randomgen/core_prng/pickle.py rename to _randomgen/randomgen/pickle.py index 40557d63edbd..4ec96663d4a3 100644 --- a/_randomgen/core_prng/pickle.py +++ b/_randomgen/randomgen/pickle.py @@ -20,13 +20,13 @@ 'Xoroshiro128': Xoroshiro128} -def __generator_ctor(prng_name='mt19937'): +def __generator_ctor(brng_name='mt19937'): """ Pickling helper function that returns a mod_name.RandomState object Parameters ---------- - prng_name: str + brng_name: str String containing the core PRNG Returns @@ -35,38 +35,38 @@ def __generator_ctor(prng_name='mt19937'): RandomGenerator using the named core PRNG """ try: - prng_name = prng_name.decode('ascii') + brng_name = brng_name.decode('ascii') except AttributeError: pass - if prng_name in PRNGS: - prng = PRNGS[prng_name] + if brng_name in PRNGS: + brng = PRNGS[brng_name] else: - raise ValueError(str(prng_name) + ' is not a known PRNG module.') + raise ValueError(str(brng_name) + ' is not a known PRNG module.') - return RandomGenerator(prng()) + return RandomGenerator(brng()) -def __prng_ctor(prng_name='mt19937'): +def __brng_ctor(brng_name='mt19937'): """ Pickling helper function that returns a mod_name.RandomState object Parameters ---------- - prng_name: str - String containing the core PRNG + brng_name: str + String containing the name of the Basic RNG Returns ------- - prng: CorePRNG - Core PRNG instance + brng: BasicRNG + Basic RNG instance """ try: - prng_name = prng_name.decode('ascii') + brng_name = brng_name.decode('ascii') except AttributeError: pass - if prng_name in PRNGS: - prng = PRNGS[prng_name] + if brng_name in PRNGS: + brng = PRNGS[brng_name] else: - raise ValueError(str(prng_name) + ' is not a known PRNG module.') + raise ValueError(str(brng_name) + ' is not a known PRNG module.') - return prng() + return brng() diff --git a/_randomgen/core_prng/src/aligned_malloc/aligned_malloc.c b/_randomgen/randomgen/src/aligned_malloc/aligned_malloc.c similarity index 100% rename from _randomgen/core_prng/src/aligned_malloc/aligned_malloc.c rename to _randomgen/randomgen/src/aligned_malloc/aligned_malloc.c diff --git a/_randomgen/core_prng/src/aligned_malloc/aligned_malloc.h b/_randomgen/randomgen/src/aligned_malloc/aligned_malloc.h similarity index 100% rename from _randomgen/core_prng/src/aligned_malloc/aligned_malloc.h rename to _randomgen/randomgen/src/aligned_malloc/aligned_malloc.h diff --git a/_randomgen/core_prng/src/common/inttypes.h b/_randomgen/randomgen/src/common/inttypes.h similarity index 100% rename from _randomgen/core_prng/src/common/inttypes.h rename to _randomgen/randomgen/src/common/inttypes.h diff --git a/_randomgen/core_prng/src/common/stdint.h b/_randomgen/randomgen/src/common/stdint.h similarity index 100% rename from _randomgen/core_prng/src/common/stdint.h rename to _randomgen/randomgen/src/common/stdint.h diff --git a/_randomgen/core_prng/src/distributions/binomial.h b/_randomgen/randomgen/src/distributions/binomial.h similarity index 100% rename from _randomgen/core_prng/src/distributions/binomial.h rename to _randomgen/randomgen/src/distributions/binomial.h diff --git a/_randomgen/core_prng/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c similarity index 65% rename from _randomgen/core_prng/src/distributions/distributions.c rename to _randomgen/randomgen/src/distributions/distributions.c index daed964ecc09..c08d5be415dc 100644 --- a/_randomgen/core_prng/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -3,88 +3,88 @@ #include "ziggurat_constants.h" /* Random generators for external use */ -float random_sample_f(prng_t *prng_state) { return random_float(prng_state); } +float random_sample_f(brng_t *brng_state) { return random_float(brng_state); } -double random_sample(prng_t *prng_state) { return random_double(prng_state); } +double random_sample(brng_t *brng_state) { return random_double(brng_state); } -double random_standard_exponential(prng_t *prng_state) { - return -log(1.0 - random_double(prng_state)); +double random_standard_exponential(brng_t *brng_state) { + return -log(1.0 - random_double(brng_state)); } -float random_standard_exponential_f(prng_t *prng_state) { - return -logf(1.0f - random_float(prng_state)); +float random_standard_exponential_f(brng_t *brng_state) { + return -logf(1.0f - random_float(brng_state)); } /* -double random_gauss(prng_t *prng_state) { - if (prng_state->has_gauss) { - const double temp = prng_state->gauss; - prng_state->has_gauss = false; - prng_state->gauss = 0.0; +double random_gauss(brng_t *brng_state) { + if (brng_state->has_gauss) { + const double temp = brng_state->gauss; + brng_state->has_gauss = false; + brng_state->gauss = 0.0; return temp; } else { double f, x1, x2, r2; do { - x1 = 2.0 * random_double(prng_state) - 1.0; - x2 = 2.0 * random_double(prng_state) - 1.0; + x1 = 2.0 * random_double(brng_state) - 1.0; + x2 = 2.0 * random_double(brng_state) - 1.0; r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); // Box-Muller transform f = sqrt(-2.0 * log(r2) / r2); // Keep for next call - prng_state->gauss = f * x1; - prng_state->has_gauss = true; + brng_state->gauss = f * x1; + brng_state->has_gauss = true; return f * x2; } } -float random_gauss_f(prng_t *prng_state) { - if (prng_state->has_gauss_f) { - const float temp = prng_state->gauss_f; - prng_state->has_gauss_f = false; - prng_state->gauss_f = 0.0f; +float random_gauss_f(brng_t *brng_state) { + if (brng_state->has_gauss_f) { + const float temp = brng_state->gauss_f; + brng_state->has_gauss_f = false; + brng_state->gauss_f = 0.0f; return temp; } else { float f, x1, x2, r2; do { - x1 = 2.0f * random_float(prng_state) - 1.0f; - x2 = 2.0f * random_float(prng_state) - 1.0f; + x1 = 2.0f * random_float(brng_state) - 1.0f; + x2 = 2.0f * random_float(brng_state) - 1.0f; r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); // Box-Muller transform f = sqrtf(-2.0f * logf(r2) / r2); // Keep for next call - prng_state->gauss_f = f * x1; - prng_state->has_gauss_f = true; + brng_state->gauss_f = f * x1; + brng_state->has_gauss_f = true; return f * x2; } } */ -static NPY_INLINE double standard_exponential_zig(prng_t *prng_state); +static NPY_INLINE double standard_exponential_zig(brng_t *brng_state); -static double standard_exponential_zig_unlikely(prng_t *prng_state, uint8_t idx, +static double standard_exponential_zig_unlikely(brng_t *brng_state, uint8_t idx, double x) { if (idx == 0) { - return ziggurat_exp_r - log(random_double(prng_state)); - } else if ((fe_double[idx - 1] - fe_double[idx]) * random_double(prng_state) + + return ziggurat_exp_r - log(random_double(brng_state)); + } else if ((fe_double[idx - 1] - fe_double[idx]) * random_double(brng_state) + fe_double[idx] < exp(-x)) { return x; } else { - return standard_exponential_zig(prng_state); + return standard_exponential_zig(brng_state); } } -static NPY_INLINE double standard_exponential_zig(prng_t *prng_state) { +static NPY_INLINE double standard_exponential_zig(brng_t *brng_state) { uint64_t ri; uint8_t idx; double x; - ri = random_uint64(prng_state); + ri = random_uint64(brng_state); ri >>= 3; idx = ri & 0xFF; ri >>= 8; @@ -92,33 +92,33 @@ static NPY_INLINE double standard_exponential_zig(prng_t *prng_state) { if (ri < ke_double[idx]) { return x; // 98.9% of the time we return here 1st try } - return standard_exponential_zig_unlikely(prng_state, idx, x); + return standard_exponential_zig_unlikely(brng_state, idx, x); } -double random_standard_exponential_zig(prng_t *prng_state) { - return standard_exponential_zig(prng_state); +double random_standard_exponential_zig(brng_t *brng_state) { + return standard_exponential_zig(brng_state); } -static NPY_INLINE float standard_exponential_zig_f(prng_t *prng_state); +static NPY_INLINE float standard_exponential_zig_f(brng_t *brng_state); -static float standard_exponential_zig_unlikely_f(prng_t *prng_state, +static float standard_exponential_zig_unlikely_f(brng_t *brng_state, uint8_t idx, float x) { if (idx == 0) { - return ziggurat_exp_r_f - logf(random_float(prng_state)); - } else if ((fe_float[idx - 1] - fe_float[idx]) * random_float(prng_state) + + return ziggurat_exp_r_f - logf(random_float(brng_state)); + } else if ((fe_float[idx - 1] - fe_float[idx]) * random_float(brng_state) + fe_float[idx] < expf(-x)) { return x; } else { - return standard_exponential_zig_f(prng_state); + return standard_exponential_zig_f(brng_state); } } -static NPY_INLINE float standard_exponential_zig_f(prng_t *prng_state) { +static NPY_INLINE float standard_exponential_zig_f(brng_t *brng_state) { uint32_t ri; uint8_t idx; float x; - ri = random_uint32(prng_state); + ri = random_uint32(brng_state); ri >>= 1; idx = ri & 0xFF; ri >>= 8; @@ -126,14 +126,14 @@ static NPY_INLINE float standard_exponential_zig_f(prng_t *prng_state) { if (ri < ke_float[idx]) { return x; // 98.9% of the time we return here 1st try } - return standard_exponential_zig_unlikely_f(prng_state, idx, x); + return standard_exponential_zig_unlikely_f(brng_state, idx, x); } -float random_standard_exponential_zig_f(prng_t *prng_state) { - return standard_exponential_zig_f(prng_state); +float random_standard_exponential_zig_f(brng_t *brng_state) { + return standard_exponential_zig_f(brng_state); } -double random_gauss_zig(prng_t *prng_state) { +double random_gauss_zig(brng_t *brng_state) { uint64_t r; int sign; int64_t rabs; @@ -141,7 +141,7 @@ double random_gauss_zig(prng_t *prng_state) { double x, xx, yy; for (;;) { /* r = e3n52sb8 */ - r = random_uint64(prng_state); + r = random_uint64(brng_state); idx = r & 0xff; r >>= 8; sign = r & 0x1; @@ -153,21 +153,21 @@ double random_gauss_zig(prng_t *prng_state) { return x; // # 99.3% of the time return here if (idx == 0) { for (;;) { - xx = -ziggurat_nor_inv_r * log(random_double(prng_state)); - yy = -log(random_double(prng_state)); + xx = -ziggurat_nor_inv_r * log(random_double(brng_state)); + yy = -log(random_double(brng_state)); if (yy + yy > xx * xx) return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r + xx) : ziggurat_nor_r + xx; } } else { - if (((fi_double[idx - 1] - fi_double[idx]) * random_double(prng_state) + + if (((fi_double[idx - 1] - fi_double[idx]) * random_double(brng_state) + fi_double[idx]) < exp(-0.5 * x * x)) return x; } } } -float random_gauss_zig_f(prng_t *prng_state) { +float random_gauss_zig_f(brng_t *brng_state) { uint32_t r; int sign; int32_t rabs; @@ -175,7 +175,7 @@ float random_gauss_zig_f(prng_t *prng_state) { float x, xx, yy; for (;;) { /* r = n23sb8 */ - r = random_uint32(prng_state); + r = random_uint32(brng_state); idx = r & 0xff; sign = (r >> 8) & 0x1; rabs = (int32_t)((r >> 9) & 0x0007fffff); @@ -186,14 +186,14 @@ float random_gauss_zig_f(prng_t *prng_state) { return x; // # 99.3% of the time return here if (idx == 0) { for (;;) { - xx = -ziggurat_nor_inv_r_f * logf(random_float(prng_state)); - yy = -logf(random_float(prng_state)); + xx = -ziggurat_nor_inv_r_f * logf(random_float(brng_state)); + yy = -logf(random_float(brng_state)); if (yy + yy > xx * xx) return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r_f + xx) : ziggurat_nor_r_f + xx; } } else { - if (((fi_float[idx - 1] - fi_float[idx]) * random_float(prng_state) + + if (((fi_float[idx - 1] - fi_float[idx]) * random_float(brng_state) + fi_float[idx]) < exp(-0.5 * x * x)) return x; } @@ -201,16 +201,16 @@ float random_gauss_zig_f(prng_t *prng_state) { } /* -static NPY_INLINE double standard_gamma(prng_t *prng_state, double shape) { +static NPY_INLINE double standard_gamma(brng_t *brng_state, double shape) { double b, c; double U, V, X, Y; if (shape == 1.0) { - return random_standard_exponential(prng_state); + return random_standard_exponential(brng_state); } else if (shape < 1.0) { for (;;) { - U = random_double(prng_state); - V = random_standard_exponential(prng_state); + U = random_double(brng_state); + V = random_standard_exponential(brng_state); if (U <= 1.0 - shape) { X = pow(U, 1. / shape); if (X <= V) { @@ -229,12 +229,12 @@ static NPY_INLINE double standard_gamma(prng_t *prng_state, double shape) { c = 1. / sqrt(9 * b); for (;;) { do { - X = random_gauss(prng_state); + X = random_gauss(brng_state); V = 1.0 + c * X; } while (V <= 0.0); V = V * V * V; - U = random_sample(prng_state); + U = random_sample(brng_state); if (U < 1.0 - 0.0331 * (X * X) * (X * X)) return (b * V); if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) @@ -243,16 +243,16 @@ static NPY_INLINE double standard_gamma(prng_t *prng_state, double shape) { } } -static NPY_INLINE float standard_gamma_float(prng_t *prng_state, float shape) { +static NPY_INLINE float standard_gamma_float(brng_t *brng_state, float shape) { float b, c; float U, V, X, Y; if (shape == 1.0f) { - return random_standard_exponential_f(prng_state); + return random_standard_exponential_f(brng_state); } else if (shape < 1.0f) { for (;;) { - U = random_sample_f(prng_state); - V = random_standard_exponential_f(prng_state); + U = random_sample_f(brng_state); + V = random_standard_exponential_f(brng_state); if (U <= 1.0f - shape) { X = powf(U, 1.0f / shape); if (X <= V) { @@ -271,12 +271,12 @@ static NPY_INLINE float standard_gamma_float(prng_t *prng_state, float shape) { c = 1.0f / sqrtf(9.0f * b); for (;;) { do { - X = random_gauss_f(prng_state); + X = random_gauss_f(brng_state); V = 1.0f + c * X; } while (V <= 0.0f); V = V * V * V; - U = random_sample_f(prng_state); + U = random_sample_f(brng_state); if (U < 1.0f - 0.0331f * (X * X) * (X * X)) return (b * V); if (logf(U) < 0.5f * X * X + b * (1.0f - V + logf(V))) @@ -286,25 +286,25 @@ static NPY_INLINE float standard_gamma_float(prng_t *prng_state, float shape) { } -double random_standard_gamma(prng_t *prng_state, double shape) { - return standard_gamma(prng_state, shape); +double random_standard_gamma(brng_t *brng_state, double shape) { + return standard_gamma(brng_state, shape); } -float random_standard_gamma_f(prng_t *prng_state, float shape) { - return standard_gamma_float(prng_state, shape); +float random_standard_gamma_f(brng_t *brng_state, float shape) { + return standard_gamma_float(brng_state, shape); } */ -static NPY_INLINE double standard_gamma_zig(prng_t *prng_state, double shape) { +static NPY_INLINE double standard_gamma_zig(brng_t *brng_state, double shape) { double b, c; double U, V, X, Y; if (shape == 1.0) { - return random_standard_exponential_zig(prng_state); + return random_standard_exponential_zig(brng_state); } else if (shape < 1.0) { for (;;) { - U = random_sample(prng_state); - V = random_standard_exponential_zig(prng_state); + U = random_sample(brng_state); + V = random_standard_exponential_zig(brng_state); if (U <= 1.0 - shape) { X = pow(U, 1. / shape); if (X <= V) { @@ -323,12 +323,12 @@ static NPY_INLINE double standard_gamma_zig(prng_t *prng_state, double shape) { c = 1. / sqrt(9 * b); for (;;) { do { - X = random_gauss_zig(prng_state); + X = random_gauss_zig(brng_state); V = 1.0 + c * X; } while (V <= 0.0); V = V * V * V; - U = random_sample(prng_state); + U = random_sample(brng_state); if (U < 1.0 - 0.0331 * (X * X) * (X * X)) return (b * V); if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) @@ -337,16 +337,16 @@ static NPY_INLINE double standard_gamma_zig(prng_t *prng_state, double shape) { } } -static NPY_INLINE float standard_gamma_zig_f(prng_t *prng_state, float shape) { +static NPY_INLINE float standard_gamma_zig_f(brng_t *brng_state, float shape) { float b, c; float U, V, X, Y; if (shape == 1.0f) { - return random_standard_exponential_zig_f(prng_state); + return random_standard_exponential_zig_f(brng_state); } else if (shape < 1.0f) { for (;;) { - U = random_sample_f(prng_state); - V = random_standard_exponential_zig_f(prng_state); + U = random_sample_f(brng_state); + V = random_standard_exponential_zig_f(brng_state); if (U <= 1.0f - shape) { X = powf(U, 1.0f / shape); if (X <= V) { @@ -365,12 +365,12 @@ static NPY_INLINE float standard_gamma_zig_f(prng_t *prng_state, float shape) { c = 1.0f / sqrtf(9.0f * b); for (;;) { do { - X = random_gauss_zig_f(prng_state); + X = random_gauss_zig_f(brng_state); V = 1.0f + c * X; } while (V <= 0.0f); V = V * V * V; - U = random_sample_f(prng_state); + U = random_sample_f(brng_state); if (U < 1.0f - 0.0331f * (X * X) * (X * X)) return (b * V); if (logf(U) < 0.5f * X * X + b * (1.0f - V + logf(V))) @@ -379,35 +379,35 @@ static NPY_INLINE float standard_gamma_zig_f(prng_t *prng_state, float shape) { } } -double random_standard_gamma_zig(prng_t *prng_state, double shape) { - return standard_gamma_zig(prng_state, shape); +double random_standard_gamma_zig(brng_t *brng_state, double shape) { + return standard_gamma_zig(brng_state, shape); } -float random_standard_gamma_zig_f(prng_t *prng_state, float shape) { - return standard_gamma_zig_f(prng_state, shape); +float random_standard_gamma_zig_f(brng_t *brng_state, float shape) { + return standard_gamma_zig_f(brng_state, shape); } -int64_t random_positive_int64(prng_t *prng_state) { - return random_uint64(prng_state) >> 1; +int64_t random_positive_int64(brng_t *brng_state) { + return random_uint64(brng_state) >> 1; } -int32_t random_positive_int32(prng_t *prng_state) { - return random_uint32(prng_state) >> 1; +int32_t random_positive_int32(brng_t *brng_state) { + return random_uint32(brng_state) >> 1; } -int64_t random_positive_int(prng_t *prng_state) { +int64_t random_positive_int(brng_t *brng_state) { #if ULONG_MAX <= 0xffffffffUL - return (int64_t)(random_uint32(prng_state) >> 1); + return (int64_t)(random_uint32(brng_state) >> 1); #else - return (int64_t)(random_uint64(prng_state) >> 1); + return (int64_t)(random_uint64(brng_state) >> 1); #endif } -uint64_t random_uint(prng_t *prng_state) { +uint64_t random_uint(brng_t *brng_state) { #if ULONG_MAX <= 0xffffffffUL - return random_uint32(prng_state); + return random_uint32(brng_state); #else - return random_uint64(prng_state); + return random_uint64(brng_state); #endif } @@ -451,32 +451,32 @@ static double loggam(double x) { } /* -double random_normal(prng_t *prng_state, double loc, double scale) { - return loc + scale * random_gauss(prng_state); +double random_normal(brng_t *brng_state, double loc, double scale) { + return loc + scale * random_gauss(brng_state); } */ -double random_normal_zig(prng_t *prng_state, double loc, double scale) { - return loc + scale * random_gauss_zig(prng_state); +double random_normal_zig(brng_t *brng_state, double loc, double scale) { + return loc + scale * random_gauss_zig(brng_state); } -double random_exponential(prng_t *prng_state, double scale) { - return scale * random_standard_exponential(prng_state); +double random_exponential(brng_t *brng_state, double scale) { + return scale * random_standard_exponential(brng_state); } -double random_uniform(prng_t *prng_state, double lower, double range) { - return lower + range * random_sample(prng_state); +double random_uniform(brng_t *brng_state, double lower, double range) { + return lower + range * random_sample(brng_state); } -double random_gamma(prng_t *prng_state, double shape, double scale) { - return scale * random_standard_gamma_zig(prng_state, shape); +double random_gamma(brng_t *brng_state, double shape, double scale) { + return scale * random_standard_gamma_zig(brng_state, shape); } -float random_gamma_float(prng_t *prng_state, float shape, float scale) { - return scale * random_standard_gamma_zig_f(prng_state, shape); +float random_gamma_float(brng_t *brng_state, float shape, float scale) { + return scale * random_standard_gamma_zig_f(brng_state, shape); } -double random_beta(prng_t *prng_state, double a, double b) { +double random_beta(brng_t *brng_state, double a, double b) { double Ga, Gb; if ((a <= 1.0) && (b <= 1.0)) { @@ -484,8 +484,8 @@ double random_beta(prng_t *prng_state, double a, double b) { /* Use Johnk's algorithm */ while (1) { - U = random_sample(prng_state); - V = random_sample(prng_state); + U = random_sample(brng_state); + V = random_sample(brng_state); X = pow(U, 1.0 / a); Y = pow(V, 1.0 / b); @@ -504,41 +504,41 @@ double random_beta(prng_t *prng_state, double a, double b) { } } } else { - Ga = random_standard_gamma_zig(prng_state, a); - Gb = random_standard_gamma_zig(prng_state, b); + Ga = random_standard_gamma_zig(brng_state, a); + Gb = random_standard_gamma_zig(brng_state, b); return Ga / (Ga + Gb); } } -double random_chisquare(prng_t *prng_state, double df) { - return 2.0 * random_standard_gamma_zig(prng_state, df / 2.0); +double random_chisquare(brng_t *brng_state, double df) { + return 2.0 * random_standard_gamma_zig(brng_state, df / 2.0); } -double random_f(prng_t *prng_state, double dfnum, double dfden) { - return ((random_chisquare(prng_state, dfnum) * dfden) / - (random_chisquare(prng_state, dfden) * dfnum)); +double random_f(brng_t *brng_state, double dfnum, double dfden) { + return ((random_chisquare(brng_state, dfnum) * dfden) / + (random_chisquare(brng_state, dfden) * dfnum)); } -double random_standard_cauchy(prng_t *prng_state) { - return random_gauss_zig(prng_state) / random_gauss_zig(prng_state); +double random_standard_cauchy(brng_t *brng_state) { + return random_gauss_zig(brng_state) / random_gauss_zig(brng_state); } -double random_pareto(prng_t *prng_state, double a) { - return exp(random_standard_exponential(prng_state) / a) - 1; +double random_pareto(brng_t *brng_state, double a) { + return exp(random_standard_exponential(brng_state) / a) - 1; } -double random_weibull(prng_t *prng_state, double a) { - return pow(random_standard_exponential(prng_state), 1. / a); +double random_weibull(brng_t *brng_state, double a) { + return pow(random_standard_exponential(brng_state), 1. / a); } -double random_power(prng_t *prng_state, double a) { - return pow(1 - exp(-random_standard_exponential(prng_state)), 1. / a); +double random_power(brng_t *brng_state, double a) { + return pow(1 - exp(-random_standard_exponential(brng_state)), 1. / a); } -double random_laplace(prng_t *prng_state, double loc, double scale) { +double random_laplace(brng_t *brng_state, double loc, double scale) { double U; - U = random_sample(prng_state); + U = random_sample(brng_state); if (U < 0.5) { U = loc + scale * log(U + U); } else { @@ -547,37 +547,37 @@ double random_laplace(prng_t *prng_state, double loc, double scale) { return U; } -double random_gumbel(prng_t *prng_state, double loc, double scale) { +double random_gumbel(brng_t *brng_state, double loc, double scale) { double U; - U = 1.0 - random_sample(prng_state); + U = 1.0 - random_sample(brng_state); return loc - scale * log(-log(U)); } -double random_logistic(prng_t *prng_state, double loc, double scale) { +double random_logistic(brng_t *brng_state, double loc, double scale) { double U; - U = random_sample(prng_state); + U = random_sample(brng_state); return loc + scale * log(U / (1.0 - U)); } -double random_lognormal(prng_t *prng_state, double mean, double sigma) { - return exp(random_normal_zig(prng_state, mean, sigma)); +double random_lognormal(brng_t *brng_state, double mean, double sigma) { + return exp(random_normal_zig(brng_state, mean, sigma)); } -double random_rayleigh(prng_t *prng_state, double mode) { - return mode * sqrt(-2.0 * log(1.0 - random_sample(prng_state))); +double random_rayleigh(brng_t *brng_state, double mode) { + return mode * sqrt(-2.0 * log(1.0 - random_sample(brng_state))); } -double random_standard_t(prng_t *prng_state, double df) { +double random_standard_t(brng_t *brng_state, double df) { double num, denom; - num = random_gauss_zig(prng_state); - denom = random_standard_gamma_zig(prng_state, df / 2); + num = random_gauss_zig(brng_state); + denom = random_standard_gamma_zig(brng_state, df / 2); return sqrt(df / 2) * num / sqrt(denom); } -static int64_t random_poisson_mult(prng_t *prng_state, double lam) { +static int64_t random_poisson_mult(brng_t *brng_state, double lam) { int64_t X; double prod, U, enlam; @@ -585,7 +585,7 @@ static int64_t random_poisson_mult(prng_t *prng_state, double lam) { X = 0; prod = 1.0; while (1) { - U = random_sample(prng_state); + U = random_sample(brng_state); prod *= U; if (prod > enlam) { X += 1; @@ -602,7 +602,7 @@ static int64_t random_poisson_mult(prng_t *prng_state, double lam) { */ #define LS2PI 0.91893853320467267 #define TWELFTH 0.083333333333333333333333 -static int64_t random_poisson_ptrs(prng_t *prng_state, double lam) { +static int64_t random_poisson_ptrs(brng_t *brng_state, double lam) { int64_t k; double U, V, slam, loglam, a, b, invalpha, vr, us; @@ -614,8 +614,8 @@ static int64_t random_poisson_ptrs(prng_t *prng_state, double lam) { vr = 0.9277 - 3.6224 / (b - 2); while (1) { - U = random_sample(prng_state) - 0.5; - V = random_sample(prng_state); + U = random_sample(brng_state) - 0.5; + V = random_sample(brng_state); us = 0.5 - fabs(U); k = (int64_t)floor((2 * a / us + b) * U + lam + 0.43); if ((us >= 0.07) && (V <= vr)) { @@ -631,22 +631,22 @@ static int64_t random_poisson_ptrs(prng_t *prng_state, double lam) { } } -int64_t random_poisson(prng_t *prng_state, double lam) { +int64_t random_poisson(brng_t *brng_state, double lam) { if (lam >= 10) { - return random_poisson_ptrs(prng_state, lam); + return random_poisson_ptrs(brng_state, lam); } else if (lam == 0) { return 0; } else { - return random_poisson_mult(prng_state, lam); + return random_poisson_mult(brng_state, lam); } } -int64_t random_negative_binomial(prng_t *prng_state, double n, double p) { - double Y = random_gamma(prng_state, n, (1 - p) / p); - return random_poisson(prng_state, Y); +int64_t random_negative_binomial(brng_t *brng_state, double n, double p) { + double Y = random_gamma(brng_state, n, (1 - p) / p); + return random_poisson(brng_state, Y); } -int64_t random_binomial_btpe(prng_t *prng_state, int64_t n, double p, +int64_t random_binomial_btpe(brng_t *brng_state, int64_t n, double p, binomial_t *binomial) { double r, q, fm, p1, xm, xl, xr, c, laml, lamr, p2, p3, p4; double a, u, v, s, F, rho, t, A, nrq, x1, x2, f1, f2, z, z2, w, w2, x; @@ -694,8 +694,8 @@ int64_t random_binomial_btpe(prng_t *prng_state, int64_t n, double p, /* sigh ... */ Step10: nrq = n * r * q; - u = random_sample(prng_state) * p4; - v = random_sample(prng_state); + u = random_sample(brng_state) * p4; + v = random_sample(brng_state); if (u > p1) goto Step20; y = (int64_t)floor(xm - p1 * v + u); @@ -786,7 +786,7 @@ int64_t random_binomial_btpe(prng_t *prng_state, int64_t n, double p, return y; } -int64_t random_binomial_inversion(prng_t *prng_state, int64_t n, double p, +int64_t random_binomial_inversion(brng_t *brng_state, int64_t n, double p, binomial_t *binomial) { double q, qn, np, px, U; int64_t X, bound; @@ -808,13 +808,13 @@ int64_t random_binomial_inversion(prng_t *prng_state, int64_t n, double p, } X = 0; px = qn; - U = random_sample(prng_state); + U = random_sample(brng_state); while (U > px) { X++; if (X > bound) { X = 0; px = qn; - U = random_sample(prng_state); + U = random_sample(brng_state); } else { U -= px; px = ((n - X + 1) * p * px) / (X * q); @@ -823,55 +823,55 @@ int64_t random_binomial_inversion(prng_t *prng_state, int64_t n, double p, return X; } -int64_t random_binomial(prng_t *prng_state, double p, int64_t n, +int64_t random_binomial(brng_t *brng_state, double p, int64_t n, binomial_t *binomial) { double q; if (p <= 0.5) { if (p * n <= 30.0) { - return random_binomial_inversion(prng_state, n, p, binomial); + return random_binomial_inversion(brng_state, n, p, binomial); } else { - return random_binomial_btpe(prng_state, n, p, binomial); + return random_binomial_btpe(brng_state, n, p, binomial); } } else { q = 1.0 - p; if (q * n <= 30.0) { - return n - random_binomial_inversion(prng_state, n, q, binomial); + return n - random_binomial_inversion(brng_state, n, q, binomial); } else { - return n - random_binomial_btpe(prng_state, n, q, binomial); + return n - random_binomial_btpe(brng_state, n, q, binomial); } } } -double random_noncentral_chisquare(prng_t *prng_state, double df, double nonc) { +double random_noncentral_chisquare(brng_t *brng_state, double df, double nonc) { if (nonc == 0) { - return random_chisquare(prng_state, df); + return random_chisquare(brng_state, df); } if (1 < df) { - const double Chi2 = random_chisquare(prng_state, df - 1); - const double n = random_gauss_zig(prng_state) + sqrt(nonc); + const double Chi2 = random_chisquare(brng_state, df - 1); + const double n = random_gauss_zig(brng_state) + sqrt(nonc); return Chi2 + n * n; } else { - const int64_t i = random_poisson(prng_state, nonc / 2.0); - return random_chisquare(prng_state, df + 2 * i); + const int64_t i = random_poisson(brng_state, nonc / 2.0); + return random_chisquare(brng_state, df + 2 * i); } } -double random_noncentral_f(prng_t *prng_state, double dfnum, double dfden, +double random_noncentral_f(brng_t *brng_state, double dfnum, double dfden, double nonc) { - double t = random_noncentral_chisquare(prng_state, dfnum, nonc) * dfden; - return t / (random_chisquare(prng_state, dfden) * dfnum); + double t = random_noncentral_chisquare(brng_state, dfnum, nonc) * dfden; + return t / (random_chisquare(brng_state, dfden) * dfnum); } -double random_wald(prng_t *prng_state, double mean, double scale) { +double random_wald(brng_t *brng_state, double mean, double scale) { double U, X, Y; double mu_2l; mu_2l = mean / (2 * scale); - Y = random_gauss_zig(prng_state); + Y = random_gauss_zig(brng_state); Y = mean * Y * Y; X = mean + mu_2l * (Y - sqrt(4 * scale * Y + Y * Y)); - U = random_sample(prng_state); + U = random_sample(brng_state); if (U <= mean / (mean + X)) { return X; } else { @@ -879,14 +879,14 @@ double random_wald(prng_t *prng_state, double mean, double scale) { } } -double random_vonmises(prng_t *prng_state, double mu, double kappa) { +double random_vonmises(brng_t *brng_state, double mu, double kappa) { double s; double U, V, W, Y, Z; double result, mod; int neg; if (kappa < 1e-8) { - return M_PI * (2 * random_sample(prng_state) - 1); + return M_PI * (2 * random_sample(brng_state) - 1); } else { /* with double precision rho is zero until 1.4e-8 */ if (kappa < 1e-5) { @@ -902,17 +902,17 @@ double random_vonmises(prng_t *prng_state, double mu, double kappa) { } while (1) { - U = random_sample(prng_state); + U = random_sample(brng_state); Z = cos(M_PI * U); W = (1 + s * Z) / (s + Z); Y = kappa * (s - W); - V = random_sample(prng_state); + V = random_sample(brng_state); if ((Y * (2 - Y) - V >= 0) || (log(Y / V) + 1 - Y >= 0)) { break; } } - U = random_sample(prng_state); + U = random_sample(brng_state); result = acos(W); if (U < 0.5) { @@ -930,18 +930,18 @@ double random_vonmises(prng_t *prng_state, double mu, double kappa) { } } -int64_t random_logseries(prng_t *prng_state, double p) { +int64_t random_logseries(brng_t *brng_state, double p) { double q, r, U, V; int64_t result; r = log(1.0 - p); while (1) { - V = random_sample(prng_state); + V = random_sample(brng_state); if (V >= p) { return 1; } - U = random_sample(prng_state); + U = random_sample(brng_state); q = 1.0 - exp(r * U); if (V <= q * q) { result = (int64_t)floor(1 + log(V) / log(q)); @@ -958,7 +958,7 @@ int64_t random_logseries(prng_t *prng_state, double p) { } } -int64_t random_geometric_search(prng_t *prng_state, double p) { +int64_t random_geometric_search(brng_t *brng_state, double p) { double U; int64_t X; double sum, prod, q; @@ -966,7 +966,7 @@ int64_t random_geometric_search(prng_t *prng_state, double p) { X = 1; sum = prod = p; q = 1.0 - p; - U = random_sample(prng_state); + U = random_sample(brng_state); while (U > sum) { prod *= q; sum += prod; @@ -975,19 +975,19 @@ int64_t random_geometric_search(prng_t *prng_state, double p) { return X; } -int64_t random_geometric_inversion(prng_t *prng_state, double p) { - return (int64_t)ceil(log(1.0 - random_sample(prng_state)) / log(1.0 - p)); +int64_t random_geometric_inversion(brng_t *brng_state, double p) { + return (int64_t)ceil(log(1.0 - random_sample(brng_state)) / log(1.0 - p)); } -int64_t random_geometric(prng_t *prng_state, double p) { +int64_t random_geometric(brng_t *brng_state, double p) { if (p >= 0.333333333333333333333333) { - return random_geometric_search(prng_state, p); + return random_geometric_search(brng_state, p); } else { - return random_geometric_inversion(prng_state, p); + return random_geometric_inversion(brng_state, p); } } -int64_t random_zipf(prng_t *prng_state, double a) { +int64_t random_zipf(brng_t *brng_state, double a) { double T, U, V; int64_t X; double am1, b; @@ -995,8 +995,8 @@ int64_t random_zipf(prng_t *prng_state, double a) { am1 = a - 1.0; b = pow(2.0, am1); do { - U = 1.0 - random_sample(prng_state); - V = random_sample(prng_state); + U = 1.0 - random_sample(brng_state); + V = random_sample(brng_state); X = (int64_t)floor(pow(U, -1.0 / am1)); /* The real result may be above what can be represented in a int64. * It will get casted to -sys.maxint-1. Since this is @@ -1009,7 +1009,7 @@ int64_t random_zipf(prng_t *prng_state, double a) { return X; } -double random_triangular(prng_t *prng_state, double left, double mode, +double random_triangular(brng_t *brng_state, double left, double mode, double right) { double base, leftbase, ratio, leftprod, rightprod; double U; @@ -1020,7 +1020,7 @@ double random_triangular(prng_t *prng_state, double left, double mode, leftprod = leftbase * base; rightprod = (right - mode) * base; - U = random_sample(prng_state); + U = random_sample(brng_state); if (U <= ratio) { return left + sqrt(U * leftprod); } else { @@ -1028,7 +1028,7 @@ double random_triangular(prng_t *prng_state, double left, double mode, } } -int64_t random_hypergeometric_hyp(prng_t *prng_state, int64_t good, int64_t bad, +int64_t random_hypergeometric_hyp(brng_t *brng_state, int64_t good, int64_t bad, int64_t sample) { int64_t d1, k, z; double d2, u, y; @@ -1039,7 +1039,7 @@ int64_t random_hypergeometric_hyp(prng_t *prng_state, int64_t good, int64_t bad, y = d2; k = sample; while (y > 0.0) { - u = random_sample(prng_state); + u = random_sample(brng_state); y -= (int64_t)floor(u + y / (d1 + k)); k--; if (k == 0) @@ -1055,7 +1055,7 @@ int64_t random_hypergeometric_hyp(prng_t *prng_state, int64_t good, int64_t bad, /* D2 = 3 - 2*sqrt(3/e) */ #define D1 1.7155277699214135 #define D2 0.8989161620588988 -int64_t random_hypergeometric_hrua(prng_t *prng_state, int64_t good, +int64_t random_hypergeometric_hrua(brng_t *brng_state, int64_t good, int64_t bad, int64_t sample) { int64_t mingoodbad, maxgoodbad, popsize, m, d9; double d4, d5, d6, d7, d8, d10, d11; @@ -1078,8 +1078,8 @@ int64_t random_hypergeometric_hrua(prng_t *prng_state, int64_t good, /* 16 for 16-decimal-digit precision in D1 and D2 */ while (1) { - X = random_sample(prng_state); - Y = random_sample(prng_state); + X = random_sample(brng_state); + Y = random_sample(brng_state); W = d6 + d8 * (Y - 0.5) / X; /* fast rejection: */ @@ -1115,16 +1115,16 @@ int64_t random_hypergeometric_hrua(prng_t *prng_state, int64_t good, #undef D1 #undef D2 -int64_t random_hypergeometric(prng_t *prng_state, int64_t good, int64_t bad, +int64_t random_hypergeometric(brng_t *brng_state, int64_t good, int64_t bad, int64_t sample) { if (sample > 10) { - return random_hypergeometric_hrua(prng_state, good, bad, sample); + return random_hypergeometric_hrua(brng_state, good, bad, sample); } else { - return random_hypergeometric_hyp(prng_state, good, bad, sample); + return random_hypergeometric_hyp(brng_state, good, bad, sample); } } -uint64_t random_interval(prng_t *prng_state, uint64_t max) { +uint64_t random_interval(brng_t *brng_state, uint64_t max) { uint64_t mask, value; if (max == 0) { return 0; @@ -1142,10 +1142,10 @@ uint64_t random_interval(prng_t *prng_state, uint64_t max) { /* Search a random value in [0..mask] <= max */ if (max <= 0xffffffffUL) { - while ((value = (random_uint32(prng_state) & mask)) > max) + while ((value = (random_uint32(brng_state) & mask)) > max) ; } else { - while ((value = (random_uint64(prng_state) & mask)) > max) + while ((value = (random_uint64(brng_state) & mask)) > max) ; } return value; @@ -1167,28 +1167,28 @@ static NPY_INLINE uint64_t gen_mask(uint64_t max) { * inclusive. The numbers wrap if rng is sufficiently large. */ -static NPY_INLINE uint64_t bounded_uint64(prng_t *prng_state, uint64_t off, +static NPY_INLINE uint64_t bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, uint64_t mask) { uint64_t val; if (rng == 0) return off; if (rng <= 0xffffffffUL) { - while ((val = (random_uint32(prng_state) & mask)) > rng) + while ((val = (random_uint32(brng_state) & mask)) > rng) ; } else { - while ((val = (random_uint64(prng_state) & mask)) > rng) + while ((val = (random_uint64(brng_state) & mask)) > rng) ; } return off + val; } -uint64_t random_bounded_uint64(prng_t *prng_state, uint64_t off, uint64_t rng, +uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, uint64_t mask) { - return bounded_uint64(prng_state, off, rng, mask); + return bounded_uint64(brng_state, off, rng, mask); } -static NPY_INLINE uint32_t bounded_uint32(prng_t *prng_state, uint32_t off, +static NPY_INLINE uint32_t bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask) { /* * The buffer and buffer count are not used here but are included to allow @@ -1200,22 +1200,22 @@ static NPY_INLINE uint32_t bounded_uint32(prng_t *prng_state, uint32_t off, if (rng == 0) return off; - while ((val = (random_uint32(prng_state) & mask)) > rng) + while ((val = (random_uint32(brng_state) & mask)) > rng) ; return off + val; } -uint32_t random_buffered_bounded_uint32(prng_t *prng_state, uint32_t off, +uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask, int *bcnt, uint32_t *buf) { /* * Unused bcnt and buf are here only to allow templating with other uint * generators */ - return bounded_uint32(prng_state, off, rng, mask); + return bounded_uint32(brng_state, off, rng, mask); } -static NPY_INLINE uint16_t buffered_bounded_uint16(prng_t *prng_state, +static NPY_INLINE uint16_t buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, uint16_t mask, int *bcnt, uint32_t *buf) { @@ -1225,7 +1225,7 @@ static NPY_INLINE uint16_t buffered_bounded_uint16(prng_t *prng_state, do { if (!(bcnt[0])) { - buf[0] = random_uint32(prng_state); + buf[0] = random_uint32(brng_state); bcnt[0] = 1; } else { buf[0] >>= 16; @@ -1236,13 +1236,13 @@ static NPY_INLINE uint16_t buffered_bounded_uint16(prng_t *prng_state, return off + val; } -uint16_t random_buffered_bounded_uint16(prng_t *prng_state, uint16_t off, +uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, uint16_t mask, int *bcnt, uint32_t *buf) { - return buffered_bounded_uint16(prng_state, off, rng, mask, bcnt, buf); + return buffered_bounded_uint16(brng_state, off, rng, mask, bcnt, buf); } -static NPY_INLINE uint8_t buffered_bounded_uint8(prng_t *prng_state, +static NPY_INLINE uint8_t buffered_bounded_uint8(brng_t *brng_state, uint8_t off, uint8_t rng, uint8_t mask, int *bcnt, uint32_t *buf) { @@ -1251,7 +1251,7 @@ static NPY_INLINE uint8_t buffered_bounded_uint8(prng_t *prng_state, return off; do { if (!(bcnt[0])) { - buf[0] = random_uint32(prng_state); + buf[0] = random_uint32(brng_state); bcnt[0] = 3; } else { buf[0] >>= 8; @@ -1262,20 +1262,20 @@ static NPY_INLINE uint8_t buffered_bounded_uint8(prng_t *prng_state, return off + val; } -uint8_t random_buffered_bounded_uint8(prng_t *prng_state, uint8_t off, +uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, uint8_t rng, uint8_t mask, int *bcnt, uint32_t *buf) { - return buffered_bounded_uint8(prng_state, off, rng, mask, bcnt, buf); + return buffered_bounded_uint8(brng_state, off, rng, mask, bcnt, buf); } -static NPY_INLINE npy_bool buffered_bounded_bool(prng_t *prng_state, +static NPY_INLINE npy_bool buffered_bounded_bool(brng_t *brng_state, npy_bool off, npy_bool rng, npy_bool mask, int *bcnt, uint32_t *buf) { if (rng == 0) return off; if (!(bcnt[0])) { - buf[0] = random_uint32(prng_state); + buf[0] = random_uint32(brng_state); bcnt[0] = 31; } else { buf[0] >>= 1; @@ -1284,13 +1284,13 @@ static NPY_INLINE npy_bool buffered_bounded_bool(prng_t *prng_state, return (buf[0] & 0x00000001UL) != 0; } -npy_bool random_buffered_bounded_bool(prng_t *prng_state, npy_bool off, +npy_bool random_buffered_bounded_bool(brng_t *brng_state, npy_bool off, npy_bool rng, npy_bool mask, int *bcnt, uint32_t *buf) { - return buffered_bounded_bool(prng_state, off, rng, mask, bcnt, buf); + return buffered_bounded_bool(brng_state, off, rng, mask, bcnt, buf); } -void random_bounded_uint64_fill(prng_t *prng_state, uint64_t off, uint64_t rng, +void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, npy_intp cnt, uint64_t *out) { uint64_t mask; npy_intp i; @@ -1298,7 +1298,7 @@ void random_bounded_uint64_fill(prng_t *prng_state, uint64_t off, uint64_t rng, /* Smallest bit mask >= max */ mask = gen_mask(rng); for (i = 0; i < cnt; i++) { - out[i] = bounded_uint64(prng_state, off, rng, mask); + out[i] = bounded_uint64(brng_state, off, rng, mask); } } @@ -1306,7 +1306,7 @@ void random_bounded_uint64_fill(prng_t *prng_state, uint64_t off, uint64_t rng, * Fills an array with cnt random npy_uint32 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -void random_bounded_uint32_fill(prng_t *prng_state, uint32_t off, uint32_t rng, +void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, npy_intp cnt, uint32_t *out) { uint32_t mask; npy_intp i; @@ -1314,7 +1314,7 @@ void random_bounded_uint32_fill(prng_t *prng_state, uint32_t off, uint32_t rng, /* Smallest bit mask >= max */ mask = (uint32_t)gen_mask(rng); for (i = 0; i < cnt; i++) { - out[i] = bounded_uint32(prng_state, off, rng, mask); + out[i] = bounded_uint32(brng_state, off, rng, mask); } } @@ -1322,7 +1322,7 @@ void random_bounded_uint32_fill(prng_t *prng_state, uint32_t off, uint32_t rng, * Fills an array with cnt random npy_uint16 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -void random_bounded_uint16_fill(prng_t *prng_state, uint16_t off, uint16_t rng, +void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, npy_intp cnt, uint16_t *out) { uint16_t mask; npy_intp i; @@ -1332,7 +1332,7 @@ void random_bounded_uint16_fill(prng_t *prng_state, uint16_t off, uint16_t rng, /* Smallest bit mask >= max */ mask = (uint16_t)gen_mask(rng); for (i = 0; i < cnt; i++) { - out[i] = buffered_bounded_uint16(prng_state, off, rng, mask, &bcnt, &buf); + out[i] = buffered_bounded_uint16(brng_state, off, rng, mask, &bcnt, &buf); } } @@ -1340,7 +1340,7 @@ void random_bounded_uint16_fill(prng_t *prng_state, uint16_t off, uint16_t rng, * Fills an array with cnt random npy_uint8 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -void random_bounded_uint8_fill(prng_t *prng_state, uint8_t off, uint8_t rng, +void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, uint8_t rng, npy_intp cnt, uint8_t *out) { uint8_t mask; npy_intp i; @@ -1350,7 +1350,7 @@ void random_bounded_uint8_fill(prng_t *prng_state, uint8_t off, uint8_t rng, /* Smallest bit mask >= max */ mask = (uint8_t)gen_mask(rng); for (i = 0; i < cnt; i++) { - out[i] = buffered_bounded_uint8(prng_state, off, rng, mask, &bcnt, &buf); + out[i] = buffered_bounded_uint8(brng_state, off, rng, mask, &bcnt, &buf); } } @@ -1358,7 +1358,7 @@ void random_bounded_uint8_fill(prng_t *prng_state, uint8_t off, uint8_t rng, * Fills an array with cnt random npy_bool between off and off + rng * inclusive. */ -void random_bounded_bool_fill(prng_t *prng_state, npy_bool off, npy_bool rng, +void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, npy_bool rng, npy_intp cnt, npy_bool *out) { npy_bool mask = 0; npy_intp i; @@ -1366,6 +1366,6 @@ void random_bounded_bool_fill(prng_t *prng_state, npy_bool off, npy_bool rng, int bcnt = 0; for (i = 0; i < cnt; i++) { - out[i] = buffered_bounded_bool(prng_state, off, rng, mask, &bcnt, &buf); + out[i] = buffered_bounded_bool(brng_state, off, rng, mask, &bcnt, &buf); } } diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h new file mode 100644 index 000000000000..f3a5448b3479 --- /dev/null +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -0,0 +1,199 @@ +#include +#ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/stdint.h" +typedef int bool; +#define false 0 +#define true 1 +#else +#include +#include +#endif +#else +#include +#include +#endif + +#include "Python.h" +#include "numpy/npy_common.h" +#include + +#ifdef _WIN32 +#if _MSC_VER == 1500 + +static NPY_INLINE int64_t llabs(int64_t x) { + int64_t o; + if (x < 0) { + o = -x; + } else { + o = x; + } + return o; +} +#endif +#endif + +#ifdef DLL_EXPORT +#define DECLDIR __declspec(dllexport) +#else +#define DECLDIR extern +#endif + +#ifndef min +#define min(x, y) ((x < y) ? x : y) +#define max(x, y) ((x > y) ? x : y) +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338328 +#endif + +typedef struct s_binomial_t { + int has_binomial; /* !=0: following parameters initialized for binomial */ + double psave; + int64_t nsave; + double r; + double q; + double fm; + int64_t m; + double p1; + double xm; + double xl; + double xr; + double c; + double laml; + double lamr; + double p2; + double p3; + double p4; +} binomial_t; + +typedef struct brng { + void *state; + uint64_t (*next_uint64)(void *st); + uint32_t (*next_uint32)(void *st); + double (*next_double)(void *st); + uint64_t (*next_raw)(void *st); +} brng_t; + +/* Inline generators for internal use */ +static NPY_INLINE uint32_t random_uint32(brng_t *brng_state) { + return brng_state->next_uint32(brng_state->state); +} + +static NPY_INLINE uint64_t random_uint64(brng_t *brng_state) { + return brng_state->next_uint64(brng_state->state); +} + +static NPY_INLINE float random_float(brng_t *brng_state) { + return (random_uint32(brng_state) >> 9) * (1.0f / 8388608.0f); +} + +static NPY_INLINE double random_double(brng_t *brng_state) { + return brng_state->next_double(brng_state->state); +} + +DECLDIR float random_sample_f(brng_t *brng_state); +DECLDIR double random_sample(brng_t *brng_state); + +DECLDIR int64_t random_positive_int64(brng_t *brng_state); +DECLDIR int32_t random_positive_int32(brng_t *brng_state); +DECLDIR int64_t random_positive_int(brng_t *brng_state); +DECLDIR uint64_t random_uint(brng_t *brng_state); + +DECLDIR double random_standard_exponential(brng_t *brng_state); +DECLDIR float random_standard_exponential_f(brng_t *brng_state); +DECLDIR double random_standard_exponential_zig(brng_t *brng_state); +DECLDIR float random_standard_exponential_zig_f(brng_t *brng_state); + +/* +DECLDIR double random_gauss(brng_t *brng_state); +DECLDIR float random_gauss_f(brng_t *brng_state); +*/ +DECLDIR double random_gauss_zig(brng_t *brng_state); +DECLDIR float random_gauss_zig_f(brng_t *brng_state); + +/* +DECLDIR double random_standard_gamma(brng_t *brng_state, double shape); +DECLDIR float random_standard_gamma_f(brng_t *brng_state, float shape); +*/ +DECLDIR double random_standard_gamma_zig(brng_t *brng_state, double shape); +DECLDIR float random_standard_gamma_zig_f(brng_t *brng_state, float shape); + +/* +DECLDIR double random_normal(brng_t *brng_state, double loc, double scale); +*/ +DECLDIR double random_normal_zig(brng_t *brng_state, double loc, double scale); + +DECLDIR double random_gamma(brng_t *brng_state, double shape, double scale); +DECLDIR float random_gamma_float(brng_t *brng_state, float shape, float scale); + +DECLDIR double random_exponential(brng_t *brng_state, double scale); +DECLDIR double random_uniform(brng_t *brng_state, double lower, double range); +DECLDIR double random_beta(brng_t *brng_state, double a, double b); +DECLDIR double random_chisquare(brng_t *brng_state, double df); +DECLDIR double random_f(brng_t *brng_state, double dfnum, double dfden); +DECLDIR double random_standard_cauchy(brng_t *brng_state); +DECLDIR double random_pareto(brng_t *brng_state, double a); +DECLDIR double random_weibull(brng_t *brng_state, double a); +DECLDIR double random_power(brng_t *brng_state, double a); +DECLDIR double random_laplace(brng_t *brng_state, double loc, double scale); +DECLDIR double random_gumbel(brng_t *brng_state, double loc, double scale); +DECLDIR double random_logistic(brng_t *brng_state, double loc, double scale); +DECLDIR double random_lognormal(brng_t *brng_state, double mean, double sigma); +DECLDIR double random_rayleigh(brng_t *brng_state, double mode); +DECLDIR double random_standard_t(brng_t *brng_state, double df); +DECLDIR double random_noncentral_chisquare(brng_t *brng_state, double df, + double nonc); +DECLDIR double random_noncentral_f(brng_t *brng_state, double dfnum, + double dfden, double nonc); +DECLDIR double random_wald(brng_t *brng_state, double mean, double scale); +DECLDIR double random_vonmises(brng_t *brng_state, double mu, double kappa); +DECLDIR double random_triangular(brng_t *brng_state, double left, double mode, + double right); + +DECLDIR int64_t random_poisson(brng_t *brng_state, double lam); +DECLDIR int64_t random_negative_binomial(brng_t *brng_state, double n, + double p); +DECLDIR int64_t random_binomial(brng_t *brng_state, double p, int64_t n, + binomial_t *binomial); +DECLDIR int64_t random_logseries(brng_t *brng_state, double p); +DECLDIR int64_t random_geometric_search(brng_t *brng_state, double p); +DECLDIR int64_t random_geometric_inversion(brng_t *brng_state, double p); +DECLDIR int64_t random_geometric(brng_t *brng_state, double p); +DECLDIR int64_t random_zipf(brng_t *brng_state, double a); +DECLDIR int64_t random_hypergeometric(brng_t *brng_state, int64_t good, + int64_t bad, int64_t sample); + +DECLDIR uint64_t random_interval(brng_t *brng_state, uint64_t max); +DECLDIR uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, + uint64_t rng, uint64_t mask); +DECLDIR uint32_t random_buffered_bounded_uint32(brng_t *brng_state, + uint32_t off, uint32_t rng, + uint32_t mask, int *bcnt, + uint32_t *buf); + +DECLDIR uint16_t random_buffered_bounded_uint16(brng_t *brng_state, + uint16_t off, uint16_t rng, + uint16_t mask, int *bcnt, + uint32_t *buf); +DECLDIR uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, + uint8_t rng, uint8_t mask, + int *bcnt, uint32_t *buf); +DECLDIR npy_bool random_buffered_bounded_bool(brng_t *brng_state, npy_bool off, + npy_bool rng, npy_bool mask, + int *bcnt, uint32_t *buf); +DECLDIR void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, + uint64_t rng, npy_intp cnt, + uint64_t *out); +DECLDIR void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, + uint32_t rng, npy_intp cnt, + uint32_t *out); +DECLDIR void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, + uint16_t rng, npy_intp cnt, + uint16_t *out); +DECLDIR void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, + uint8_t rng, npy_intp cnt, uint8_t *out); +DECLDIR void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, + npy_bool rng, npy_intp cnt, + npy_bool *out); diff --git a/_randomgen/core_prng/src/distributions/ziggurat.h b/_randomgen/randomgen/src/distributions/ziggurat.h similarity index 100% rename from _randomgen/core_prng/src/distributions/ziggurat.h rename to _randomgen/randomgen/src/distributions/ziggurat.h diff --git a/_randomgen/core_prng/src/distributions/ziggurat_constants.h b/_randomgen/randomgen/src/distributions/ziggurat_constants.h similarity index 100% rename from _randomgen/core_prng/src/distributions/ziggurat_constants.h rename to _randomgen/randomgen/src/distributions/ziggurat_constants.h diff --git a/_randomgen/core_prng/src/dsfmt/128-bit-jump.poly.txt b/_randomgen/randomgen/src/dsfmt/128-bit-jump.poly.txt similarity index 100% rename from _randomgen/core_prng/src/dsfmt/128-bit-jump.poly.txt rename to _randomgen/randomgen/src/dsfmt/128-bit-jump.poly.txt diff --git a/_randomgen/core_prng/src/dsfmt/96-bit-jump.poly.txt b/_randomgen/randomgen/src/dsfmt/96-bit-jump.poly.txt similarity index 100% rename from _randomgen/core_prng/src/dsfmt/96-bit-jump.poly.txt rename to _randomgen/randomgen/src/dsfmt/96-bit-jump.poly.txt diff --git a/_randomgen/core_prng/src/dsfmt/LICENSE.txt b/_randomgen/randomgen/src/dsfmt/LICENSE.txt similarity index 100% rename from _randomgen/core_prng/src/dsfmt/LICENSE.txt rename to _randomgen/randomgen/src/dsfmt/LICENSE.txt diff --git a/_randomgen/core_prng/src/dsfmt/calc-jump.cpp b/_randomgen/randomgen/src/dsfmt/calc-jump.cpp similarity index 100% rename from _randomgen/core_prng/src/dsfmt/calc-jump.cpp rename to _randomgen/randomgen/src/dsfmt/calc-jump.cpp diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-benchmark.c b/_randomgen/randomgen/src/dsfmt/dSFMT-benchmark.c similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT-benchmark.c rename to _randomgen/randomgen/src/dsfmt/dSFMT-benchmark.c diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-calc-jump.hpp b/_randomgen/randomgen/src/dsfmt/dSFMT-calc-jump.hpp similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT-calc-jump.hpp rename to _randomgen/randomgen/src/dsfmt/dSFMT-calc-jump.hpp diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-common.h b/_randomgen/randomgen/src/dsfmt/dSFMT-common.h similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT-common.h rename to _randomgen/randomgen/src/dsfmt/dSFMT-common.h diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-jump.c b/_randomgen/randomgen/src/dsfmt/dSFMT-jump.c similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT-jump.c rename to _randomgen/randomgen/src/dsfmt/dSFMT-jump.c diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-jump.h b/_randomgen/randomgen/src/dsfmt/dSFMT-jump.h similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT-jump.h rename to _randomgen/randomgen/src/dsfmt/dSFMT-jump.h diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-params.h b/_randomgen/randomgen/src/dsfmt/dSFMT-params.h similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT-params.h rename to _randomgen/randomgen/src/dsfmt/dSFMT-params.h diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-params19937.h b/_randomgen/randomgen/src/dsfmt/dSFMT-params19937.h similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT-params19937.h rename to _randomgen/randomgen/src/dsfmt/dSFMT-params19937.h diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-poly.h b/_randomgen/randomgen/src/dsfmt/dSFMT-poly.h similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT-poly.h rename to _randomgen/randomgen/src/dsfmt/dSFMT-poly.h diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c b/_randomgen/randomgen/src/dsfmt/dSFMT-test-gen.c similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT-test-gen.c rename to _randomgen/randomgen/src/dsfmt/dSFMT-test-gen.c diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.c b/_randomgen/randomgen/src/dsfmt/dSFMT.c similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT.c rename to _randomgen/randomgen/src/dsfmt/dSFMT.c diff --git a/_randomgen/core_prng/src/dsfmt/dSFMT.h b/_randomgen/randomgen/src/dsfmt/dSFMT.h similarity index 100% rename from _randomgen/core_prng/src/dsfmt/dSFMT.h rename to _randomgen/randomgen/src/dsfmt/dSFMT.h diff --git a/_randomgen/core_prng/src/entropy/entropy.c b/_randomgen/randomgen/src/entropy/entropy.c similarity index 100% rename from _randomgen/core_prng/src/entropy/entropy.c rename to _randomgen/randomgen/src/entropy/entropy.c diff --git a/_randomgen/core_prng/src/entropy/entropy.h b/_randomgen/randomgen/src/entropy/entropy.h similarity index 100% rename from _randomgen/core_prng/src/entropy/entropy.h rename to _randomgen/randomgen/src/entropy/entropy.h diff --git a/_randomgen/core_prng/src/mt19937/mt19937-benchmark.c b/_randomgen/randomgen/src/mt19937/mt19937-benchmark.c similarity index 100% rename from _randomgen/core_prng/src/mt19937/mt19937-benchmark.c rename to _randomgen/randomgen/src/mt19937/mt19937-benchmark.c diff --git a/_randomgen/core_prng/src/mt19937/mt19937-jump.c b/_randomgen/randomgen/src/mt19937/mt19937-jump.c similarity index 100% rename from _randomgen/core_prng/src/mt19937/mt19937-jump.c rename to _randomgen/randomgen/src/mt19937/mt19937-jump.c diff --git a/_randomgen/core_prng/src/mt19937/mt19937-jump.h b/_randomgen/randomgen/src/mt19937/mt19937-jump.h similarity index 100% rename from _randomgen/core_prng/src/mt19937/mt19937-jump.h rename to _randomgen/randomgen/src/mt19937/mt19937-jump.h diff --git a/_randomgen/core_prng/src/mt19937/mt19937-poly.h b/_randomgen/randomgen/src/mt19937/mt19937-poly.h similarity index 100% rename from _randomgen/core_prng/src/mt19937/mt19937-poly.h rename to _randomgen/randomgen/src/mt19937/mt19937-poly.h diff --git a/_randomgen/core_prng/src/mt19937/mt19937-test-data-gen.c b/_randomgen/randomgen/src/mt19937/mt19937-test-data-gen.c similarity index 100% rename from _randomgen/core_prng/src/mt19937/mt19937-test-data-gen.c rename to _randomgen/randomgen/src/mt19937/mt19937-test-data-gen.c diff --git a/_randomgen/core_prng/src/mt19937/mt19937.c b/_randomgen/randomgen/src/mt19937/mt19937.c similarity index 100% rename from _randomgen/core_prng/src/mt19937/mt19937.c rename to _randomgen/randomgen/src/mt19937/mt19937.c diff --git a/_randomgen/core_prng/src/mt19937/mt19937.h b/_randomgen/randomgen/src/mt19937/mt19937.h similarity index 100% rename from _randomgen/core_prng/src/mt19937/mt19937.h rename to _randomgen/randomgen/src/mt19937/mt19937.h diff --git a/_randomgen/core_prng/src/mt19937/randomkit.c b/_randomgen/randomgen/src/mt19937/randomkit.c similarity index 100% rename from _randomgen/core_prng/src/mt19937/randomkit.c rename to _randomgen/randomgen/src/mt19937/randomkit.c diff --git a/_randomgen/core_prng/src/mt19937/randomkit.h b/_randomgen/randomgen/src/mt19937/randomkit.h similarity index 100% rename from _randomgen/core_prng/src/mt19937/randomkit.h rename to _randomgen/randomgen/src/mt19937/randomkit.h diff --git a/_randomgen/core_prng/src/pcg32/pcg-advance-64.c b/_randomgen/randomgen/src/pcg32/pcg-advance-64.c similarity index 100% rename from _randomgen/core_prng/src/pcg32/pcg-advance-64.c rename to _randomgen/randomgen/src/pcg32/pcg-advance-64.c diff --git a/_randomgen/core_prng/src/pcg32/pcg32-test-data-gen.c b/_randomgen/randomgen/src/pcg32/pcg32-test-data-gen.c similarity index 100% rename from _randomgen/core_prng/src/pcg32/pcg32-test-data-gen.c rename to _randomgen/randomgen/src/pcg32/pcg32-test-data-gen.c diff --git a/_randomgen/core_prng/src/pcg32/pcg32.c b/_randomgen/randomgen/src/pcg32/pcg32.c similarity index 100% rename from _randomgen/core_prng/src/pcg32/pcg32.c rename to _randomgen/randomgen/src/pcg32/pcg32.c diff --git a/_randomgen/core_prng/src/pcg32/pcg32.h b/_randomgen/randomgen/src/pcg32/pcg32.h similarity index 100% rename from _randomgen/core_prng/src/pcg32/pcg32.h rename to _randomgen/randomgen/src/pcg32/pcg32.h diff --git a/_randomgen/core_prng/src/pcg32/pcg_variants.h b/_randomgen/randomgen/src/pcg32/pcg_variants.h similarity index 100% rename from _randomgen/core_prng/src/pcg32/pcg_variants.h rename to _randomgen/randomgen/src/pcg32/pcg_variants.h diff --git a/_randomgen/core_prng/src/pcg64/pcg64-benchmark.c b/_randomgen/randomgen/src/pcg64/pcg64-benchmark.c similarity index 100% rename from _randomgen/core_prng/src/pcg64/pcg64-benchmark.c rename to _randomgen/randomgen/src/pcg64/pcg64-benchmark.c diff --git a/_randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c b/_randomgen/randomgen/src/pcg64/pcg64-test-data-gen.c similarity index 100% rename from _randomgen/core_prng/src/pcg64/pcg64-test-data-gen.c rename to _randomgen/randomgen/src/pcg64/pcg64-test-data-gen.c diff --git a/_randomgen/core_prng/src/pcg64/pcg64.c b/_randomgen/randomgen/src/pcg64/pcg64.c similarity index 100% rename from _randomgen/core_prng/src/pcg64/pcg64.c rename to _randomgen/randomgen/src/pcg64/pcg64.c diff --git a/_randomgen/core_prng/src/pcg64/pcg64.h b/_randomgen/randomgen/src/pcg64/pcg64.h similarity index 100% rename from _randomgen/core_prng/src/pcg64/pcg64.h rename to _randomgen/randomgen/src/pcg64/pcg64.h diff --git a/_randomgen/core_prng/src/pcg64/pcg64.orig.c b/_randomgen/randomgen/src/pcg64/pcg64.orig.c similarity index 100% rename from _randomgen/core_prng/src/pcg64/pcg64.orig.c rename to _randomgen/randomgen/src/pcg64/pcg64.orig.c diff --git a/_randomgen/core_prng/src/pcg64/pcg64.orig.h b/_randomgen/randomgen/src/pcg64/pcg64.orig.h similarity index 100% rename from _randomgen/core_prng/src/pcg64/pcg64.orig.h rename to _randomgen/randomgen/src/pcg64/pcg64.orig.h diff --git a/_randomgen/core_prng/src/philox/philox-benchmark.c b/_randomgen/randomgen/src/philox/philox-benchmark.c similarity index 100% rename from _randomgen/core_prng/src/philox/philox-benchmark.c rename to _randomgen/randomgen/src/philox/philox-benchmark.c diff --git a/_randomgen/core_prng/src/philox/philox-test-data-gen.c b/_randomgen/randomgen/src/philox/philox-test-data-gen.c similarity index 100% rename from _randomgen/core_prng/src/philox/philox-test-data-gen.c rename to _randomgen/randomgen/src/philox/philox-test-data-gen.c diff --git a/_randomgen/core_prng/src/philox/philox.c b/_randomgen/randomgen/src/philox/philox.c similarity index 100% rename from _randomgen/core_prng/src/philox/philox.c rename to _randomgen/randomgen/src/philox/philox.c diff --git a/_randomgen/core_prng/src/philox/philox.h b/_randomgen/randomgen/src/philox/philox.h similarity index 100% rename from _randomgen/core_prng/src/philox/philox.h rename to _randomgen/randomgen/src/philox/philox.h diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.c b/_randomgen/randomgen/src/splitmix64/splitmix64.c similarity index 100% rename from _randomgen/core_prng/src/splitmix64/splitmix64.c rename to _randomgen/randomgen/src/splitmix64/splitmix64.c diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.h b/_randomgen/randomgen/src/splitmix64/splitmix64.h similarity index 100% rename from _randomgen/core_prng/src/splitmix64/splitmix64.h rename to _randomgen/randomgen/src/splitmix64/splitmix64.h diff --git a/_randomgen/core_prng/src/splitmix64/splitmix64.orig.c b/_randomgen/randomgen/src/splitmix64/splitmix64.orig.c similarity index 100% rename from _randomgen/core_prng/src/splitmix64/splitmix64.orig.c rename to _randomgen/randomgen/src/splitmix64/splitmix64.orig.c diff --git a/_randomgen/core_prng/src/threefry/threefry-benchmark.c b/_randomgen/randomgen/src/threefry/threefry-benchmark.c similarity index 100% rename from _randomgen/core_prng/src/threefry/threefry-benchmark.c rename to _randomgen/randomgen/src/threefry/threefry-benchmark.c diff --git a/_randomgen/core_prng/src/threefry/threefry-orig.c b/_randomgen/randomgen/src/threefry/threefry-orig.c similarity index 100% rename from _randomgen/core_prng/src/threefry/threefry-orig.c rename to _randomgen/randomgen/src/threefry/threefry-orig.c diff --git a/_randomgen/core_prng/src/threefry/threefry-test-data-gen.c b/_randomgen/randomgen/src/threefry/threefry-test-data-gen.c similarity index 100% rename from _randomgen/core_prng/src/threefry/threefry-test-data-gen.c rename to _randomgen/randomgen/src/threefry/threefry-test-data-gen.c diff --git a/_randomgen/core_prng/src/threefry/threefry.c b/_randomgen/randomgen/src/threefry/threefry.c similarity index 100% rename from _randomgen/core_prng/src/threefry/threefry.c rename to _randomgen/randomgen/src/threefry/threefry.c diff --git a/_randomgen/core_prng/src/threefry/threefry.h b/_randomgen/randomgen/src/threefry/threefry.h similarity index 100% rename from _randomgen/core_prng/src/threefry/threefry.h rename to _randomgen/randomgen/src/threefry/threefry.h diff --git a/_randomgen/core_prng/src/threefry32/threefry32-test-data-gen.c b/_randomgen/randomgen/src/threefry32/threefry32-test-data-gen.c similarity index 100% rename from _randomgen/core_prng/src/threefry32/threefry32-test-data-gen.c rename to _randomgen/randomgen/src/threefry32/threefry32-test-data-gen.c diff --git a/_randomgen/core_prng/src/threefry32/threefry32.c b/_randomgen/randomgen/src/threefry32/threefry32.c similarity index 100% rename from _randomgen/core_prng/src/threefry32/threefry32.c rename to _randomgen/randomgen/src/threefry32/threefry32.c diff --git a/_randomgen/core_prng/src/threefry32/threefry32.h b/_randomgen/randomgen/src/threefry32/threefry32.h similarity index 100% rename from _randomgen/core_prng/src/threefry32/threefry32.h rename to _randomgen/randomgen/src/threefry32/threefry32.h diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-benchmark.c b/_randomgen/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c similarity index 100% rename from _randomgen/core_prng/src/xoroshiro128/xoroshiro128-benchmark.c rename to _randomgen/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128-test-data-gen.c b/_randomgen/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c similarity index 100% rename from _randomgen/core_prng/src/xoroshiro128/xoroshiro128-test-data-gen.c rename to _randomgen/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.c b/_randomgen/randomgen/src/xoroshiro128/xoroshiro128.c similarity index 100% rename from _randomgen/core_prng/src/xoroshiro128/xoroshiro128.c rename to _randomgen/randomgen/src/xoroshiro128/xoroshiro128.c diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128.h b/_randomgen/randomgen/src/xoroshiro128/xoroshiro128.h similarity index 100% rename from _randomgen/core_prng/src/xoroshiro128/xoroshiro128.h rename to _randomgen/randomgen/src/xoroshiro128/xoroshiro128.h diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.c b/_randomgen/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c similarity index 100% rename from _randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.c rename to _randomgen/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c diff --git a/_randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.h b/_randomgen/randomgen/src/xoroshiro128/xoroshiro128plus.orig.h similarity index 100% rename from _randomgen/core_prng/src/xoroshiro128/xoroshiro128plus.orig.h rename to _randomgen/randomgen/src/xoroshiro128/xoroshiro128plus.orig.h diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c b/_randomgen/randomgen/src/xorshift1024/xorshift1024-benchmark.c similarity index 100% rename from _randomgen/core_prng/src/xorshift1024/xorshift1024-benchmark.c rename to _randomgen/randomgen/src/xorshift1024/xorshift1024-benchmark.c diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024-test-data-gen.c b/_randomgen/randomgen/src/xorshift1024/xorshift1024-test-data-gen.c similarity index 100% rename from _randomgen/core_prng/src/xorshift1024/xorshift1024-test-data-gen.c rename to _randomgen/randomgen/src/xorshift1024/xorshift1024-test-data-gen.c diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.c b/_randomgen/randomgen/src/xorshift1024/xorshift1024.c similarity index 100% rename from _randomgen/core_prng/src/xorshift1024/xorshift1024.c rename to _randomgen/randomgen/src/xorshift1024/xorshift1024.c diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.h b/_randomgen/randomgen/src/xorshift1024/xorshift1024.h similarity index 100% rename from _randomgen/core_prng/src/xorshift1024/xorshift1024.h rename to _randomgen/randomgen/src/xorshift1024/xorshift1024.h diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.orig.c b/_randomgen/randomgen/src/xorshift1024/xorshift1024.orig.c similarity index 100% rename from _randomgen/core_prng/src/xorshift1024/xorshift1024.orig.c rename to _randomgen/randomgen/src/xorshift1024/xorshift1024.orig.c diff --git a/_randomgen/core_prng/src/xorshift1024/xorshift1024.orig.h b/_randomgen/randomgen/src/xorshift1024/xorshift1024.orig.h similarity index 100% rename from _randomgen/core_prng/src/xorshift1024/xorshift1024.orig.h rename to _randomgen/randomgen/src/xorshift1024/xorshift1024.orig.h diff --git a/_randomgen/core_prng/tests/data/dSFMT-testset-1.csv b/_randomgen/randomgen/tests/data/dSFMT-testset-1.csv similarity index 100% rename from _randomgen/core_prng/tests/data/dSFMT-testset-1.csv rename to _randomgen/randomgen/tests/data/dSFMT-testset-1.csv diff --git a/_randomgen/core_prng/tests/data/dSFMT-testset-2.csv b/_randomgen/randomgen/tests/data/dSFMT-testset-2.csv similarity index 100% rename from _randomgen/core_prng/tests/data/dSFMT-testset-2.csv rename to _randomgen/randomgen/tests/data/dSFMT-testset-2.csv diff --git a/_randomgen/core_prng/tests/data/mt19937-testset-1.csv b/_randomgen/randomgen/tests/data/mt19937-testset-1.csv similarity index 100% rename from _randomgen/core_prng/tests/data/mt19937-testset-1.csv rename to _randomgen/randomgen/tests/data/mt19937-testset-1.csv diff --git a/_randomgen/core_prng/tests/data/mt19937-testset-2.csv b/_randomgen/randomgen/tests/data/mt19937-testset-2.csv similarity index 100% rename from _randomgen/core_prng/tests/data/mt19937-testset-2.csv rename to _randomgen/randomgen/tests/data/mt19937-testset-2.csv diff --git a/_randomgen/core_prng/tests/data/pcg32-testset-1.csv b/_randomgen/randomgen/tests/data/pcg32-testset-1.csv similarity index 100% rename from _randomgen/core_prng/tests/data/pcg32-testset-1.csv rename to _randomgen/randomgen/tests/data/pcg32-testset-1.csv diff --git a/_randomgen/core_prng/tests/data/pcg32-testset-2.csv b/_randomgen/randomgen/tests/data/pcg32-testset-2.csv similarity index 100% rename from _randomgen/core_prng/tests/data/pcg32-testset-2.csv rename to _randomgen/randomgen/tests/data/pcg32-testset-2.csv diff --git a/_randomgen/core_prng/tests/data/pcg64-testset-1.csv b/_randomgen/randomgen/tests/data/pcg64-testset-1.csv similarity index 100% rename from _randomgen/core_prng/tests/data/pcg64-testset-1.csv rename to _randomgen/randomgen/tests/data/pcg64-testset-1.csv diff --git a/_randomgen/core_prng/tests/data/pcg64-testset-2.csv b/_randomgen/randomgen/tests/data/pcg64-testset-2.csv similarity index 100% rename from _randomgen/core_prng/tests/data/pcg64-testset-2.csv rename to _randomgen/randomgen/tests/data/pcg64-testset-2.csv diff --git a/_randomgen/core_prng/tests/data/philox-testset-1.csv b/_randomgen/randomgen/tests/data/philox-testset-1.csv similarity index 100% rename from _randomgen/core_prng/tests/data/philox-testset-1.csv rename to _randomgen/randomgen/tests/data/philox-testset-1.csv diff --git a/_randomgen/core_prng/tests/data/philox-testset-2.csv b/_randomgen/randomgen/tests/data/philox-testset-2.csv similarity index 100% rename from _randomgen/core_prng/tests/data/philox-testset-2.csv rename to _randomgen/randomgen/tests/data/philox-testset-2.csv diff --git a/_randomgen/core_prng/tests/data/threefry-testset-1.csv b/_randomgen/randomgen/tests/data/threefry-testset-1.csv similarity index 100% rename from _randomgen/core_prng/tests/data/threefry-testset-1.csv rename to _randomgen/randomgen/tests/data/threefry-testset-1.csv diff --git a/_randomgen/core_prng/tests/data/threefry-testset-2.csv b/_randomgen/randomgen/tests/data/threefry-testset-2.csv similarity index 100% rename from _randomgen/core_prng/tests/data/threefry-testset-2.csv rename to _randomgen/randomgen/tests/data/threefry-testset-2.csv diff --git a/_randomgen/core_prng/tests/data/threefry32-testset-1.csv b/_randomgen/randomgen/tests/data/threefry32-testset-1.csv similarity index 100% rename from _randomgen/core_prng/tests/data/threefry32-testset-1.csv rename to _randomgen/randomgen/tests/data/threefry32-testset-1.csv diff --git a/_randomgen/core_prng/tests/data/threefry32-testset-2.csv b/_randomgen/randomgen/tests/data/threefry32-testset-2.csv similarity index 100% rename from _randomgen/core_prng/tests/data/threefry32-testset-2.csv rename to _randomgen/randomgen/tests/data/threefry32-testset-2.csv diff --git a/_randomgen/core_prng/tests/data/xoroshiro128-testset-1.csv b/_randomgen/randomgen/tests/data/xoroshiro128-testset-1.csv similarity index 100% rename from _randomgen/core_prng/tests/data/xoroshiro128-testset-1.csv rename to _randomgen/randomgen/tests/data/xoroshiro128-testset-1.csv diff --git a/_randomgen/core_prng/tests/data/xoroshiro128-testset-2.csv b/_randomgen/randomgen/tests/data/xoroshiro128-testset-2.csv similarity index 100% rename from _randomgen/core_prng/tests/data/xoroshiro128-testset-2.csv rename to _randomgen/randomgen/tests/data/xoroshiro128-testset-2.csv diff --git a/_randomgen/core_prng/tests/data/xorshift1024-testset-1.csv b/_randomgen/randomgen/tests/data/xorshift1024-testset-1.csv similarity index 100% rename from _randomgen/core_prng/tests/data/xorshift1024-testset-1.csv rename to _randomgen/randomgen/tests/data/xorshift1024-testset-1.csv diff --git a/_randomgen/core_prng/tests/data/xorshift1024-testset-2.csv b/_randomgen/randomgen/tests/data/xorshift1024-testset-2.csv similarity index 100% rename from _randomgen/core_prng/tests/data/xorshift1024-testset-2.csv rename to _randomgen/randomgen/tests/data/xorshift1024-testset-2.csv diff --git a/_randomgen/core_prng/tests/test_against_numpy.py b/_randomgen/randomgen/tests/test_against_numpy.py similarity index 97% rename from _randomgen/core_prng/tests/test_against_numpy.py rename to _randomgen/randomgen/tests/test_against_numpy.py index 61a7a10206df..1bffe3f78fb3 100644 --- a/_randomgen/core_prng/tests/test_against_numpy.py +++ b/_randomgen/randomgen/tests/test_against_numpy.py @@ -3,7 +3,7 @@ from numpy.testing import assert_allclose, assert_array_equal, assert_equal import pytest -from core_prng import RandomGenerator, MT19937 +from randomgen import RandomGenerator, MT19937 def compare_0_input(f1, f2): @@ -38,8 +38,10 @@ def compare_2_input(f1, f2, is_np=False, is_scalar=False): ((np.array([a] * 10), b), {}), ((a, np.array([b] * 10)), {}), ((a, np.array([b] * 10)), {'size': 10}), - ((np.reshape(np.array([[a] * 100]), (100, 1)), np.array([b] * 10)), {'size': (100, 10)}), - ((np.ones((7, 31), dtype=dtype) * a, np.array([b] * 31)), {'size': (7, 31)}), + ((np.reshape(np.array([[a] * 100]), (100, 1)), + np.array([b] * 10)), {'size': (100, 10)}), + ((np.ones((7, 31), dtype=dtype) * a, + np.array([b] * 31)), {'size': (7, 31)}), ((np.ones((7, 31), dtype=dtype) * a, np.array([b] * 31)), {'size': (10, 7, 31)})] if is_scalar: @@ -81,9 +83,9 @@ class TestAgainstNumPy(object): @classmethod def setup_class(cls): cls.np = numpy.random - cls.prng = MT19937 + cls.brng = MT19937 cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] - cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.nprs = cls.np.RandomState(*cls.seed) cls.initial_state = cls.rg.state cls._set_common_state() @@ -430,7 +432,8 @@ def test_multinomial(self): p = [.1, .3, .4, .2] assert_equal(f(100, p), g(100, p)) assert_equal(f(100, np.array(p)), g(100, np.array(p))) - assert_equal(f(100, np.array(p), size=(7, 23)), g(100, np.array(p), size=(7, 23))) + assert_equal(f(100, np.array(p), size=(7, 23)), + g(100, np.array(p), size=(7, 23))) self._is_state_common() def test_choice(self): @@ -525,7 +528,7 @@ def test_array(self): def test_dir(self): nprs_d = set(dir(self.nprs)) rs_d = dir(self.rg) - excluded = {'get_state', 'poisson_lam_max','set_state'} + excluded = {'get_state', 'poisson_lam_max', 'set_state'} nprs_d.difference_update(excluded) assert (len(nprs_d.difference(rs_d)) == 0) diff --git a/_randomgen/core_prng/tests/test_direct.py b/_randomgen/randomgen/tests/test_direct.py similarity index 85% rename from _randomgen/core_prng/tests/test_direct.py rename to _randomgen/randomgen/tests/test_direct.py index 1bd5deafebdc..c6cd00bd56d4 100644 --- a/_randomgen/core_prng/tests/test_direct.py +++ b/_randomgen/randomgen/tests/test_direct.py @@ -7,7 +7,7 @@ assert_raises import pytest -from core_prng import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ +from randomgen import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024 if (sys.version_info > (3, 0)): @@ -25,7 +25,7 @@ def uniform32_from_uint64(x): out = (joined >> np.uint32(9)) * (1.0 / 2 ** 23) return out.astype(np.float32) - + def uniform32_from_uint63(x): x = np.uint64(x) x = np.uint32(x >> np.uint64(32)) @@ -121,7 +121,7 @@ class Base(object): @classmethod def setup_class(cls): - cls.prng = Xoroshiro128 + cls.brng = Xoroshiro128 cls.bits = 64 cls.dtype = np.uint64 cls.seed_error_type = TypeError @@ -138,48 +138,48 @@ def _read_csv(cls, filename): return {'seed': seed, 'data': np.array(data, dtype=cls.dtype)} def test_raw(self): - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) uints = rs.random_raw(1000) assert_equal(uints, self.data1['data']) - rs = RandomGenerator(self.prng(*self.data2['seed'])) + rs = RandomGenerator(self.brng(*self.data2['seed'])) uints = rs.random_raw(1000) assert_equal(uints, self.data2['data']) @pytest.mark.skip(reason='Box-Muller no longer supported') def test_gauss_inv(self): n = 25 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) gauss = rs.standard_normal(n) assert_allclose(gauss, gauss_from_uint(self.data1['data'], n, self.bits)) - rs = RandomGenerator(self.prng(*self.data2['seed'])) + rs = RandomGenerator(self.brng(*self.data2['seed'])) gauss = rs.standard_normal(25) assert_allclose(gauss, gauss_from_uint(self.data2['data'], n, self.bits)) def test_uniform_double(self): - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) vals = uniform_from_uint(self.data1['data'], self.bits) uniforms = rs.random_sample(len(vals)) assert_allclose(uniforms, vals) assert_equal(uniforms.dtype, np.float64) - rs = RandomGenerator(self.prng(*self.data2['seed'])) + rs = RandomGenerator(self.brng(*self.data2['seed'])) vals = uniform_from_uint(self.data2['data'], self.bits) uniforms = rs.random_sample(len(vals)) assert_allclose(uniforms, vals) assert_equal(uniforms.dtype, np.float64) def test_uniform_float(self): - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) vals = uniform32_from_uint(self.data1['data'], self.bits) uniforms = rs.random_sample(len(vals), dtype=np.float32) assert_allclose(uniforms, vals) assert_equal(uniforms.dtype, np.float32) - rs = RandomGenerator(self.prng(*self.data2['seed'])) + rs = RandomGenerator(self.brng(*self.data2['seed'])) vals = uniform32_from_uint(self.data2['data'], self.bits) uniforms = rs.random_sample(len(vals), dtype=np.float32) assert_allclose(uniforms, vals) @@ -187,13 +187,13 @@ def test_uniform_float(self): def test_seed_float(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(self.seed_error_type, rs.seed, np.pi) assert_raises(self.seed_error_type, rs.seed, -np.pi) def test_seed_float_array(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(self.seed_error_type, rs.seed, np.array([np.pi])) assert_raises(self.seed_error_type, rs.seed, np.array([-np.pi])) assert_raises(ValueError, rs.seed, np.array([np.pi, -np.pi])) @@ -203,13 +203,13 @@ def test_seed_float_array(self): def test_seed_out_of_range(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(ValueError, rs.seed, 2 ** (2 * self.bits + 1)) assert_raises(ValueError, rs.seed, -1) def test_seed_out_of_range_array(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(ValueError, rs.seed, [2 ** (2 * self.bits + 1)]) assert_raises(ValueError, rs.seed, [-1]) @@ -217,7 +217,7 @@ def test_seed_out_of_range_array(self): class TestXoroshiro128(Base): @classmethod def setup_class(cls): - cls.prng = Xoroshiro128 + cls.brng = Xoroshiro128 cls.bits = 64 cls.dtype = np.uint64 cls.data1 = cls._read_csv( @@ -230,7 +230,7 @@ def setup_class(cls): class TestXorshift1024(Base): @classmethod def setup_class(cls): - cls.prng = Xorshift1024 + cls.brng = Xorshift1024 cls.bits = 64 cls.dtype = np.uint64 cls.data1 = cls._read_csv( @@ -243,7 +243,7 @@ def setup_class(cls): class TestThreeFry(Base): @classmethod def setup_class(cls): - cls.prng = ThreeFry + cls.brng = ThreeFry cls.bits = 64 cls.dtype = np.uint64 cls.data1 = cls._read_csv( @@ -256,7 +256,7 @@ def setup_class(cls): class TestPCG64(Base): @classmethod def setup_class(cls): - cls.prng = PCG64 + cls.brng = PCG64 cls.bits = 64 cls.dtype = np.uint64 cls.data1 = cls._read_csv(join(pwd, './data/pcg64-testset-1.csv')) @@ -264,7 +264,7 @@ def setup_class(cls): cls.seed_error_type = TypeError def test_seed_float_array(self): - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(self.seed_error_type, rs.seed, np.array([np.pi])) assert_raises(self.seed_error_type, rs.seed, np.array([-np.pi])) assert_raises(self.seed_error_type, rs.seed, np.array([np.pi, -np.pi])) @@ -273,15 +273,16 @@ def test_seed_float_array(self): assert_raises(self.seed_error_type, rs.seed, [0, np.pi]) def test_seed_out_of_range_array(self): - rs = RandomGenerator(self.prng(*self.data1['seed'])) - assert_raises(self.seed_error_type, rs.seed, [2 ** (2 * self.bits + 1)]) + rs = RandomGenerator(self.brng(*self.data1['seed'])) + assert_raises(self.seed_error_type, rs.seed, + [2 ** (2 * self.bits + 1)]) assert_raises(self.seed_error_type, rs.seed, [-1]) class TestPhilox(Base): @classmethod def setup_class(cls): - cls.prng = Philox + cls.brng = Philox cls.bits = 64 cls.dtype = np.uint64 cls.data1 = cls._read_csv( @@ -294,7 +295,7 @@ def setup_class(cls): class TestMT19937(Base): @classmethod def setup_class(cls): - cls.prng = MT19937 + cls.brng = MT19937 cls.bits = 32 cls.dtype = np.uint32 cls.data1 = cls._read_csv(join(pwd, './data/mt19937-testset-1.csv')) @@ -303,27 +304,27 @@ def setup_class(cls): def test_seed_out_of_range(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(ValueError, rs.seed, 2 ** (self.bits + 1)) assert_raises(ValueError, rs.seed, -1) assert_raises(ValueError, rs.seed, 2 ** (2 * self.bits + 1)) def test_seed_out_of_range_array(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(ValueError, rs.seed, [2 ** (self.bits + 1)]) assert_raises(ValueError, rs.seed, [-1]) assert_raises(TypeError, rs.seed, [2 ** (2 * self.bits + 1)]) def test_seed_float(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(TypeError, rs.seed, np.pi) assert_raises(TypeError, rs.seed, -np.pi) def test_seed_float_array(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(TypeError, rs.seed, np.array([np.pi])) assert_raises(TypeError, rs.seed, np.array([-np.pi])) assert_raises(TypeError, rs.seed, np.array([np.pi, -np.pi])) @@ -335,7 +336,7 @@ def test_seed_float_array(self): class TestDSFMT(Base): @classmethod def setup_class(cls): - cls.prng = DSFMT + cls.brng = DSFMT cls.bits = 53 cls.dtype = np.uint64 cls.data1 = cls._read_csv(join(pwd, './data/dSFMT-testset-1.csv')) @@ -343,43 +344,43 @@ def setup_class(cls): cls.seed_error_type = TypeError def test_uniform_double(self): - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_array_equal(uniform_from_dsfmt(self.data1['data']), rs.random_sample(1000)) - rs = RandomGenerator(self.prng(*self.data2['seed'])) + rs = RandomGenerator(self.brng(*self.data2['seed'])) assert_equal(uniform_from_dsfmt(self.data2['data']), rs.random_sample(1000)) @pytest.mark.skip(reason='Box-Muller no longer supported') def test_gauss_inv(self): n = 25 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) gauss = rs.standard_normal(n) assert_allclose(gauss, gauss_from_uint(self.data1['data'], n, 'dsfmt')) - rs = RandomGenerator(self.prng(*self.data2['seed'])) + rs = RandomGenerator(self.brng(*self.data2['seed'])) gauss = rs.standard_normal(25) assert_allclose(gauss, gauss_from_uint(self.data2['data'], n, 'dsfmt')) def test_seed_out_of_range_array(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(ValueError, rs.seed, [2 ** (self.bits + 1)]) assert_raises(ValueError, rs.seed, [-1]) assert_raises(TypeError, rs.seed, [2 ** (2 * self.bits + 1)]) def test_seed_float(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(TypeError, rs.seed, np.pi) assert_raises(TypeError, rs.seed, -np.pi) def test_seed_float_array(self): # GH #82 - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) assert_raises(TypeError, rs.seed, np.array([np.pi])) assert_raises(TypeError, rs.seed, np.array([-np.pi])) assert_raises(TypeError, rs.seed, np.array([np.pi, -np.pi])) @@ -388,13 +389,13 @@ def test_seed_float_array(self): assert_raises(TypeError, rs.seed, [0, np.pi]) def test_uniform_float(self): - rs = RandomGenerator(self.prng(*self.data1['seed'])) + rs = RandomGenerator(self.brng(*self.data1['seed'])) vals = uniform32_from_uint(self.data1['data'], self.bits) uniforms = rs.random_sample(len(vals), dtype=np.float32) assert_allclose(uniforms, vals) assert_equal(uniforms.dtype, np.float32) - rs = RandomGenerator(self.prng(*self.data2['seed'])) + rs = RandomGenerator(self.brng(*self.data2['seed'])) vals = uniform32_from_uint(self.data2['data'], self.bits) uniforms = rs.random_sample(len(vals), dtype=np.float32) assert_allclose(uniforms, vals) @@ -404,7 +405,7 @@ def test_uniform_float(self): class TestThreeFry32(Base): @classmethod def setup_class(cls): - cls.prng = ThreeFry32 + cls.brng = ThreeFry32 cls.bits = 32 cls.dtype = np.uint32 cls.data1 = cls._read_csv(join(pwd, './data/threefry32-testset-1.csv')) @@ -415,7 +416,7 @@ def setup_class(cls): class TestPCG32(TestPCG64): @classmethod def setup_class(cls): - cls.prng = PCG32 + cls.brng = PCG32 cls.bits = 32 cls.dtype = np.uint32 cls.data1 = cls._read_csv(join(pwd, './data/pcg32-testset-1.csv')) diff --git a/_randomgen/core_prng/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py similarity index 98% rename from _randomgen/core_prng/tests/test_numpy_mt19937.py rename to _randomgen/randomgen/tests/test_numpy_mt19937.py index dbe25172843a..85419b2172bf 100644 --- a/_randomgen/core_prng/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -10,8 +10,8 @@ assert_array_almost_equal) import pytest -from core_prng._testing import suppress_warnings -from core_prng import RandomGenerator, MT19937 +from randomgen._testing import suppress_warnings +from randomgen import RandomGenerator, MT19937 random = mt19937 = RandomGenerator(MT19937()) @@ -92,34 +92,34 @@ def test_size(self): class TestSetState(object): def setup(self): self.seed = 1234567890 - self.prng = RandomGenerator(MT19937(self.seed)) - self.state = self.prng.state - self.legacy_state = (self.state['prng'], + self.brng = RandomGenerator(MT19937(self.seed)) + self.state = self.brng.state + self.legacy_state = (self.state['brng'], self.state['state']['key'], self.state['state']['pos']) def test_basic(self): - old = self.prng.tomaxint(16) - self.prng.state = self.state - new = self.prng.tomaxint(16) + old = self.brng.tomaxint(16) + self.brng.state = self.state + new = self.brng.tomaxint(16) assert_(np.all(old == new)) def test_gaussian_reset(self): # Make sure the cached every-other-Gaussian is reset. - old = self.prng.standard_normal(size=3) - self.prng.state = self.state - new = self.prng.standard_normal(size=3) + old = self.brng.standard_normal(size=3) + self.brng.state = self.state + new = self.brng.standard_normal(size=3) assert_(np.all(old == new)) def test_gaussian_reset_in_media_res(self): # When the state is saved with a cached Gaussian, make sure the # cached Gaussian is restored. - self.prng.standard_normal() - state = self.prng.state - old = self.prng.standard_normal(size=3) - self.prng.state = state - new = self.prng.standard_normal(size=3) + self.brng.standard_normal() + state = self.brng.state + old = self.brng.standard_normal(size=3) + self.brng.state = state + new = self.brng.standard_normal(size=3) assert_(np.all(old == new)) @pytest.mark.skip(reason='Box-Muller no longer supported') @@ -127,18 +127,18 @@ def test_backwards_compatibility(self): # Make sure we can accept old state tuples that do not have the # cached Gaussian value. old_state = self.legacy_state[:-2] - x1 = self.prng.standard_normal(size=16) - self.prng.state = old_state - x2 = self.prng.standard_normal(size=16) - self.prng.state = self.state - x3 = self.prng.standard_normal(size=16) + x1 = self.brng.standard_normal(size=16) + self.brng.state = old_state + x2 = self.brng.standard_normal(size=16) + self.brng.state = self.state + x3 = self.brng.standard_normal(size=16) assert_(np.all(x1 == x2)) assert_(np.all(x1 == x3)) def test_negative_binomial(self): # Ensure that the negative binomial results take floating point # arguments without truncation. - self.prng.negative_binomial(0.5, 0.5) + self.brng.negative_binomial(0.5, 0.5) class TestRandint(object): diff --git a/_randomgen/core_prng/tests/test_numpy_mt19937_regressions.py b/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py similarity index 97% rename from _randomgen/core_prng/tests/test_numpy_mt19937_regressions.py rename to _randomgen/randomgen/tests/test_numpy_mt19937_regressions.py index 37ca9aa77f00..4a972462d2a4 100644 --- a/_randomgen/core_prng/tests/test_numpy_mt19937_regressions.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py @@ -6,10 +6,11 @@ from numpy.compat import long import numpy as np import pytest -from core_prng import RandomGenerator, MT19937 +from randomgen import RandomGenerator, MT19937 mt19937 = RandomGenerator(MT19937()) + class TestRegression(object): def test_VonMises_range(self): @@ -30,7 +31,8 @@ def test_hypergeometric_range(self): ] is_64bits = sys.maxsize > 2**32 if is_64bits and sys.platform != 'win32': - args.append((2**40 - 2, 2**40 - 2, 2**40 - 2)) # Check for 64-bit systems + # Check for 64-bit systems + args.append((2**40 - 2, 2**40 - 2, 2**40 - 2)) for arg in args: assert_(mt19937.hypergeometric(*arg) > 0) @@ -136,5 +138,6 @@ def test_shuffle_of_array_of_objects(self): import gc gc.collect() + if __name__ == "__main__": run_module_suite() diff --git a/_randomgen/core_prng/tests/test_smoke.py b/_randomgen/randomgen/tests/test_smoke.py similarity index 94% rename from _randomgen/core_prng/tests/test_smoke.py rename to _randomgen/randomgen/tests/test_smoke.py index a5f35390da45..cc720f1f0d2e 100644 --- a/_randomgen/core_prng/tests/test_smoke.py +++ b/_randomgen/randomgen/tests/test_smoke.py @@ -8,9 +8,9 @@ from numpy.testing import assert_almost_equal, assert_equal, assert_, \ assert_array_equal -from core_prng import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ +from randomgen import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024 -from core_prng import entropy +from randomgen import entropy @pytest.fixture(scope='module', @@ -110,7 +110,7 @@ def _reset_state(self): self.rg.state = self.initial_state def test_init(self): - rg = RandomGenerator(self.prng()) + rg = RandomGenerator(self.brng()) state = rg.state rg.standard_normal(1) rg.standard_normal(1) @@ -208,13 +208,13 @@ def test_reset_state(self): assert_(int_1 == int_2) def test_entropy_init(self): - rg = RandomGenerator(self.prng()) - rg2 = RandomGenerator(self.prng()) + rg = RandomGenerator(self.brng()) + rg2 = RandomGenerator(self.brng()) assert_(not comp_state(rg.state, rg2.state)) def test_seed(self): - rg = RandomGenerator(self.prng(*self.seed)) - rg2 = RandomGenerator(self.prng(*self.seed)) + rg = RandomGenerator(self.brng(*self.seed)) + rg2 = RandomGenerator(self.brng(*self.seed)) rg.random_sample() rg2.random_sample() if not comp_state(rg.state, rg2.state): @@ -225,31 +225,31 @@ def test_seed(self): assert_(comp_state(rg.state, rg2.state)) def test_reset_state_gauss(self): - rg = RandomGenerator(self.prng(*self.seed)) + rg = RandomGenerator(self.brng(*self.seed)) rg.standard_normal() state = rg.state n1 = rg.standard_normal(size=10) - rg2 = RandomGenerator(self.prng()) + rg2 = RandomGenerator(self.brng()) rg2.state = state n2 = rg2.standard_normal(size=10) assert_array_equal(n1, n2) def test_reset_state_uint32(self): - rg = RandomGenerator(self.prng(*self.seed)) + rg = RandomGenerator(self.brng(*self.seed)) rg.randint(0, 2 ** 24, 120, dtype=np.uint32) state = rg.state n1 = rg.randint(0, 2 ** 24, 10, dtype=np.uint32) - rg2 = RandomGenerator(self.prng()) + rg2 = RandomGenerator(self.brng()) rg2.state = state n2 = rg2.randint(0, 2 ** 24, 10, dtype=np.uint32) assert_array_equal(n1, n2) def test_reset_state_uintegers(self): - rg = RandomGenerator(self.prng(*self.seed)) + rg = RandomGenerator(self.brng(*self.seed)) rg.random_uintegers(bits=32) state = rg.state n1 = rg.random_uintegers(bits=32, size=10) - rg2 = RandomGenerator(self.prng()) + rg2 = RandomGenerator(self.brng()) rg2.state = state n2 = rg2.random_uintegers(bits=32, size=10) assert_((n1 == n2).all()) @@ -603,11 +603,11 @@ def test_seed_array_error(self): self.rg.seed(seed) def test_uniform_float(self): - rg = RandomGenerator(self.prng(12345)) + rg = RandomGenerator(self.brng(12345)) warmup(rg) state = rg.state r1 = rg.random_sample(11, dtype=np.float32) - rg2 = RandomGenerator(self.prng()) + rg2 = RandomGenerator(self.brng()) warmup(rg2) rg2.state = state r2 = rg2.random_sample(11, dtype=np.float32) @@ -616,11 +616,11 @@ def test_uniform_float(self): assert_(comp_state(rg.state, rg2.state)) def test_gamma_floats(self): - rg = RandomGenerator(self.prng()) + rg = RandomGenerator(self.brng()) warmup(rg) state = rg.state r1 = rg.standard_gamma(4.0, 11, dtype=np.float32) - rg2 = RandomGenerator(self.prng()) + rg2 = RandomGenerator(self.brng()) warmup(rg2) rg2.state = state r2 = rg2.standard_gamma(4.0, 11, dtype=np.float32) @@ -629,11 +629,11 @@ def test_gamma_floats(self): assert_(comp_state(rg.state, rg2.state)) def test_normal_floats(self): - rg = RandomGenerator(self.prng()) + rg = RandomGenerator(self.brng()) warmup(rg) state = rg.state r1 = rg.standard_normal(11, dtype=np.float32) - rg2 = RandomGenerator(self.prng()) + rg2 = RandomGenerator(self.brng()) warmup(rg2) rg2.state = state r2 = rg2.standard_normal(11, dtype=np.float32) @@ -642,11 +642,11 @@ def test_normal_floats(self): assert_(comp_state(rg.state, rg2.state)) def test_normal_zig_floats(self): - rg = RandomGenerator(self.prng()) + rg = RandomGenerator(self.brng()) warmup(rg) state = rg.state r1 = rg.standard_normal(11, dtype=np.float32) - rg2 = RandomGenerator(self.prng()) + rg2 = RandomGenerator(self.brng()) warmup(rg2) rg2.state = state r2 = rg2.standard_normal(11, dtype=np.float32) @@ -835,10 +835,10 @@ def test_randint_broadcast_errors(self, dtype): class TestMT19937(RNG): @classmethod def setup_class(cls): - cls.prng = MT19937 + cls.brng = MT19937 cls.advance = None cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] - cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state cls.seed_vector_bits = 32 cls._extra_setup() @@ -857,11 +857,11 @@ def test_numpy_state(self): class TestPCG64(RNG): @classmethod def setup_class(cls): - cls.prng = PCG64 + cls.brng = PCG64 cls.advance = 2 ** 96 + 2 ** 48 + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1 cls.seed = [2 ** 96 + 2 ** 48 + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1, 2 ** 21 + 2 ** 16 + 2 ** 5 + 1] - cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state cls.seed_vector_bits = None cls._extra_setup() @@ -894,10 +894,10 @@ def test_seed_array_error(self): class TestPhilox(RNG): @classmethod def setup_class(cls): - cls.prng = Philox + cls.brng = Philox cls.advance = None cls.seed = [12345] - cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -906,10 +906,10 @@ def setup_class(cls): class TestThreeFry(RNG): @classmethod def setup_class(cls): - cls.prng = ThreeFry + cls.brng = ThreeFry cls.advance = None cls.seed = [12345] - cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -918,10 +918,10 @@ def setup_class(cls): class TestXoroshiro128(RNG): @classmethod def setup_class(cls): - cls.prng = Xoroshiro128 + cls.brng = Xoroshiro128 cls.advance = None cls.seed = [12345] - cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -930,10 +930,10 @@ def setup_class(cls): class TestXorshift1024(RNG): @classmethod def setup_class(cls): - cls.prng = Xorshift1024 + cls.brng = Xorshift1024 cls.advance = None cls.seed = [12345] - cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -942,10 +942,10 @@ def setup_class(cls): class TestDSFMT(RNG): @classmethod def setup_class(cls): - cls.prng = DSFMT + cls.brng = DSFMT cls.advance = None cls.seed = [12345] - cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state cls._extra_setup() cls.seed_vector_bits = 32 @@ -954,10 +954,10 @@ def setup_class(cls): class TestThreeFry32(RNG): @classmethod def setup_class(cls): - cls.prng = ThreeFry32 + cls.brng = ThreeFry32 cls.advance = [2 ** 96 + 2 ** 16 + 2 ** 5 + 1] cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] - cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -986,11 +986,11 @@ def test_fallback(self): class TestPCG32(TestPCG64): @classmethod def setup_class(cls): - cls.prng = PCG32 + cls.brng = PCG32 cls.advance = 2 ** 48 + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1 cls.seed = [2 ** 48 + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1, 2 ** 21 + 2 ** 16 + 2 ** 5 + 1] - cls.rg = RandomGenerator(cls.prng(*cls.seed)) + cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state cls.seed_vector_bits = None cls._extra_setup() diff --git a/_randomgen/core_prng/threefry.pyx b/_randomgen/randomgen/threefry.pyx similarity index 86% rename from _randomgen/core_prng/threefry.pyx rename to _randomgen/randomgen/threefry.pyx index e2b5b3c71082..ffcc754171f0 100644 --- a/_randomgen/core_prng/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -4,9 +4,9 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np from common cimport * -from distributions cimport prng_t -from core_prng.entropy import random_entropy, seed_by_array -import core_prng.pickle +from distributions cimport brng_t +from randomgen.entropy import random_entropy, seed_by_array +import randomgen.pickle np.import_array() @@ -48,7 +48,7 @@ cdef double threefry_double(void* st) nogil: cdef class ThreeFry: """ - Prototype Core PRNG using threefry + Prototype Basic RNG using threefry Parameters ---------- @@ -61,24 +61,24 @@ cdef class ThreeFry: a `RandomGenerator` object. """ cdef threefry_state *rng_state - cdef prng_t *_prng + cdef brng_t *_brng cdef public object capsule def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(threefry_state)) self.rng_state.ctr = malloc(sizeof(threefry4x64_ctr_t)) self.rng_state.key = malloc(sizeof(threefry4x64_key_t)) - self._prng = malloc(sizeof(prng_t)) + self._brng = malloc(sizeof(brng_t)) self.seed(seed, counter, key) - self._prng.state = self.rng_state - self._prng.next_uint64 = &threefry_uint64 - self._prng.next_uint32 = &threefry_uint32 - self._prng.next_double = &threefry_double - self._prng.next_raw = &threefry_uint64 + self._brng.state = self.rng_state + self._brng.next_uint64 = &threefry_uint64 + self._brng.next_uint32 = &threefry_uint32 + self._brng.next_double = &threefry_double + self._brng.next_raw = &threefry_uint64 - cdef const char *name = 'CorePRNG' - self.capsule = PyCapsule_New(self._prng, name, NULL) + cdef const char *name = 'BasicRNG' + self.capsule = PyCapsule_New(self._brng, name, NULL) # Pickling support: def __getstate__(self): @@ -88,15 +88,15 @@ cdef class ThreeFry: self.state = state def __reduce__(self): - return (core_prng.pickle.__prng_ctor, - (self.state['prng'],), + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), self.state) def __dealloc__(self): free(self.rng_state.ctr) free(self.rng_state.key) free(self.rng_state) - free(self._prng) + free(self._brng) cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 @@ -124,9 +124,9 @@ cdef class ThreeFry: Testing only """ if bits == 64: - return self._prng.next_uint64(self._prng.state) + return self._brng.next_uint64(self._brng.state) elif bits == 32: - return self._prng.next_uint32(self._prng.state) + return self._brng.next_uint32(self._brng.state) else: raise ValueError('bits must be 32 or 64') @@ -134,10 +134,10 @@ cdef class ThreeFry: cdef Py_ssize_t i if method==u'uint64': for i in range(cnt): - self._prng.next_uint64(self._prng.state) + self._brng.next_uint64(self._brng.state) elif method==u'double': for i in range(cnt): - self._prng.next_double(self._prng.state) + self._brng.next_double(self._brng.state) else: raise ValueError('Unknown method') @@ -209,7 +209,7 @@ cdef class ThreeFry: for i in range(THREEFRY_BUFFER_SIZE): buffer[i] = self.rng_state.buffer[i] state = {'counter':ctr,'key':key} - return {'prng': self.__class__.__name__, + return {'brng': self.__class__.__name__, 'state': state, 'buffer': buffer, 'buffer_pos': self.rng_state.buffer_pos, @@ -220,8 +220,8 @@ cdef class ThreeFry: def state(self, value): if not isinstance(value, dict): raise TypeError('state must be a dict') - prng = value.get('prng', '') - if prng != self.__class__.__name__: + brng = value.get('brng', '') + if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) for i in range(4): diff --git a/_randomgen/core_prng/threefry32.pyx b/_randomgen/randomgen/threefry32.pyx similarity index 86% rename from _randomgen/core_prng/threefry32.pyx rename to _randomgen/randomgen/threefry32.pyx index 376a6e4ded00..86f9c4f656c3 100644 --- a/_randomgen/core_prng/threefry32.pyx +++ b/_randomgen/randomgen/threefry32.pyx @@ -4,9 +4,9 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np from common cimport * -from distributions cimport prng_t -from core_prng.entropy import random_entropy, seed_by_array -import core_prng.pickle +from distributions cimport brng_t +from randomgen.entropy import random_entropy, seed_by_array +import randomgen.pickle np.import_array() @@ -51,7 +51,7 @@ cdef uint64_t threefry32_raw(void *st) nogil: cdef class ThreeFry32: """ - Prototype Core PRNG using threefry + Prototype Basic RNG using threefry Parameters ---------- @@ -64,24 +64,24 @@ cdef class ThreeFry32: a `RandomGenerator` object. """ cdef threefry32_state *rng_state - cdef prng_t *_prng + cdef brng_t *_brng cdef public object capsule def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(threefry32_state)) self.rng_state.ctr = malloc(sizeof(threefry4x32_ctr_t)) self.rng_state.key = malloc(sizeof(threefry4x32_key_t)) - self._prng = malloc(sizeof(prng_t)) + self._brng = malloc(sizeof(brng_t)) self.seed(seed, counter, key) - self._prng.state = self.rng_state - self._prng.next_uint64 = &threefry32_uint64 - self._prng.next_uint32 = &threefry32_uint32 - self._prng.next_double = &threefry32_double - self._prng.next_raw = &threefry32_raw + self._brng.state = self.rng_state + self._brng.next_uint64 = &threefry32_uint64 + self._brng.next_uint32 = &threefry32_uint32 + self._brng.next_double = &threefry32_double + self._brng.next_raw = &threefry32_raw - cdef const char *name = 'CorePRNG' - self.capsule = PyCapsule_New(self._prng, name, NULL) + cdef const char *name = 'BasicRNG' + self.capsule = PyCapsule_New(self._brng, name, NULL) # Pickling support: def __getstate__(self): @@ -91,15 +91,15 @@ cdef class ThreeFry32: self.state = state def __reduce__(self): - return (core_prng.pickle.__prng_ctor, - (self.state['prng'],), + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), self.state) def __dealloc__(self): free(self.rng_state.ctr) free(self.rng_state.key) free(self.rng_state) - free(self._prng) + free(self._brng) cdef _reset_state_variables(self): self.rng_state.buffer_pos = THREEFRY_BUFFER_SIZE @@ -125,9 +125,9 @@ cdef class ThreeFry32: Testing only """ if bits == 64: - return self._prng.next_uint64(self._prng.state) + return self._brng.next_uint64(self._brng.state) elif bits == 32: - return self._prng.next_uint32(self._prng.state) + return self._brng.next_uint32(self._brng.state) else: raise ValueError('bits must be 32 or 64') @@ -135,10 +135,10 @@ cdef class ThreeFry32: cdef Py_ssize_t i if method==u'uint64': for i in range(cnt): - self._prng.next_uint64(self._prng.state) + self._brng.next_uint64(self._brng.state) elif method==u'double': for i in range(cnt): - self._prng.next_double(self._prng.state) + self._brng.next_double(self._brng.state) else: raise ValueError('Unknown method') @@ -210,7 +210,7 @@ cdef class ThreeFry32: for i in range(THREEFRY_BUFFER_SIZE): buffer[i] = self.rng_state.buffer[i] state = {'counter':ctr,'key':key} - return {'prng': self.__class__.__name__, + return {'brng': self.__class__.__name__, 'state': state, 'buffer': buffer, 'buffer_pos': self.rng_state.buffer_pos} @@ -219,8 +219,8 @@ cdef class ThreeFry32: def state(self, value): if not isinstance(value, dict): raise TypeError('state must be a dict') - prng = value.get('prng', '') - if prng != self.__class__.__name__: + brng = value.get('brng', '') + if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) for i in range(4): diff --git a/_randomgen/core_prng/xoroshiro128.pyx b/_randomgen/randomgen/xoroshiro128.pyx similarity index 88% rename from _randomgen/core_prng/xoroshiro128.pyx rename to _randomgen/randomgen/xoroshiro128.pyx index 03535333f795..46058e9ca13b 100644 --- a/_randomgen/core_prng/xoroshiro128.pyx +++ b/_randomgen/randomgen/xoroshiro128.pyx @@ -6,9 +6,9 @@ cimport numpy as np from common import interface from common cimport * -from distributions cimport prng_t -from core_prng.entropy import random_entropy, seed_by_array -import core_prng.pickle +from distributions cimport brng_t +from randomgen.entropy import random_entropy, seed_by_array +import randomgen.pickle np.import_array() @@ -81,7 +81,7 @@ cdef class Xoroshiro128: in each worker process. All generators should be initialized with the same seed to ensure that the segments come from the same sequence. - >>> from core_prng import RandomGenerator, Xoroshiro128 + >>> from randomgen import RandomGenerator, Xoroshiro128 >>> rg = [RandomGenerator(Xoroshiro128(1234)) for _ in range(10)] # Advance rs[i] by i jumps >>> for i in range(10): @@ -105,7 +105,7 @@ cdef class Xoroshiro128: Examples -------- - >>> from core_prng import RandomGenerator, Xoroshiro128 + >>> from randomgen import RandomGenerator, Xoroshiro128 >>> rg = RandomGenerator(Xoroshiro128(1234)) >>> rg.standard_normal() @@ -120,7 +120,7 @@ cdef class Xoroshiro128: http://xorshift.di.unimi.it/ """ cdef xoroshiro128_state *rng_state - cdef prng_t *_prng + cdef brng_t *_brng cdef public object capsule cdef object _ctypes cdef object _cffi @@ -128,21 +128,21 @@ cdef class Xoroshiro128: def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoroshiro128_state)) - self._prng = malloc(sizeof(prng_t)) + self._brng = malloc(sizeof(brng_t)) self.seed(seed) - self._prng.state = self.rng_state - self._prng.next_uint64 = &xoroshiro128_uint64 - self._prng.next_uint32 = &xoroshiro128_uint32 - self._prng.next_double = &xoroshiro128_double - self._prng.next_raw = &xoroshiro128_uint64 + self._brng.state = self.rng_state + self._brng.next_uint64 = &xoroshiro128_uint64 + self._brng.next_uint32 = &xoroshiro128_uint32 + self._brng.next_double = &xoroshiro128_double + self._brng.next_raw = &xoroshiro128_uint64 self._ctypes = None self._cffi = None self._generator = None - cdef const char *name = "CorePRNG" - self.capsule = PyCapsule_New(self._prng, name, NULL) + cdef const char *name = "BasicRNG" + self.capsule = PyCapsule_New(self._brng, name, NULL) # Pickling support: def __getstate__(self): @@ -152,13 +152,13 @@ cdef class Xoroshiro128: self.state = state def __reduce__(self): - return (core_prng.pickle.__prng_ctor, - (self.state['prng'],), + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), self.state) def __dealloc__(self): free(self.rng_state) - free(self._prng) + free(self._brng) cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 @@ -169,10 +169,10 @@ cdef class Xoroshiro128: cdef Py_ssize_t i if method==u'uint64': for i in range(cnt): - self._prng.next_uint64(self._prng.state) + self._brng.next_uint64(self._brng.state) elif method==u'double': for i in range(cnt): - self._prng.next_double(self._prng.state) + self._brng.next_double(self._brng.state) else: raise ValueError('Unknown method') @@ -251,7 +251,7 @@ cdef class Xoroshiro128: state = np.empty(2, dtype=np.uint64) state[0] = self.rng_state.s[0] state[1] = self.rng_state.s[1] - return {'prng': self.__class__.__name__, + return {'brng': self.__class__.__name__, 's': state, 'has_uint32': self.rng_state.has_uint32, 'uinteger': self.rng_state.uinteger} @@ -260,8 +260,8 @@ cdef class Xoroshiro128: def state(self, value): if not isinstance(value, dict): raise TypeError('state must be a dict') - prng = value.get('prng', '') - if prng != self.__class__.__name__: + brng = value.get('brng', '') + if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) self.rng_state.s[0] = value['s'][0] @@ -284,7 +284,7 @@ cdef class Xoroshiro128: * next_uint64 - function pointer to produce 64 bit integers * next_uint32 - function pointer to produce 32 bit integers * next_double - function pointer to produce doubles - * prng - pointer to the PRNG struct + * brng - pointer to the Basic RNG struct """ if self._ctypes is not None: @@ -303,7 +303,7 @@ cdef class Xoroshiro128: ctypes.cast(&xoroshiro128_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._prng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -321,7 +321,7 @@ cdef class Xoroshiro128: * next_uint64 - function pointer to produce 64 bit integers * next_uint32 - function pointer to produce 32 bit integers * next_double - function pointer to produce doubles - * prng - pointer to the PRNG struct + * brng - pointer to the Basic RNG struct """ if self._cffi is not None: return self._cffi @@ -333,10 +333,10 @@ cdef class Xoroshiro128: ffi = cffi.FFI() self._cffi = interface(self.rng_state, ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._prng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._prng.next_uint32), - ffi.cast('double (*)(void *)',self._prng.next_double), - ffi.cast('void *',self._prng)) + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property @@ -346,8 +346,8 @@ cdef class Xoroshiro128: Returns ------- - gen : core_prng.generator.RandomGenerator - Random generator used this instance as the core PRNG + gen : randomgen.generator.RandomGenerator + Random generator used this instance as the basic RNG """ if self._generator is None: from .generator import RandomGenerator diff --git a/_randomgen/core_prng/xorshift1024.pyx b/_randomgen/randomgen/xorshift1024.pyx similarity index 88% rename from _randomgen/core_prng/xorshift1024.pyx rename to _randomgen/randomgen/xorshift1024.pyx index 761f3403976c..210702358fd8 100644 --- a/_randomgen/core_prng/xorshift1024.pyx +++ b/_randomgen/randomgen/xorshift1024.pyx @@ -6,9 +6,9 @@ cimport numpy as np from common import interface from common cimport * -from distributions cimport prng_t -from core_prng.entropy import random_entropy, seed_by_array -import core_prng.pickle +from distributions cimport brng_t +from randomgen.entropy import random_entropy, seed_by_array +import randomgen.pickle np.import_array() @@ -80,7 +80,7 @@ cdef class Xorshift1024: in each worker process. All generators should be initialized with the same seed to ensure that the segments come from the same sequence. - >>> from core_prng import RandomGenerator, Xorshift1024 + >>> from randomgen import RandomGenerator, Xorshift1024 >>> rg = [RandomGenerator(Xorshift1024(1234)) for _ in range(10)] # Advance rg[i] by i jumps >>> for i in range(10): @@ -104,7 +104,7 @@ cdef class Xorshift1024: Examples -------- - >>> from core_prng import RandomGenerator, Xorshift1024 + >>> from randomgen import RandomGenerator, Xorshift1024 >>> rg = RandomGenerator(Xorshift1024(1234)) >>> rg.standard_normal() @@ -126,22 +126,22 @@ cdef class Xorshift1024: """ cdef xorshift1024_state *rng_state - cdef prng_t *_prng + cdef brng_t *_brng cdef public object capsule def __init__(self, seed=None): self.rng_state = malloc(sizeof(xorshift1024_state)) - self._prng = malloc(sizeof(prng_t)) + self._brng = malloc(sizeof(brng_t)) self.seed(seed) - self._prng.state = self.rng_state - self._prng.next_uint64 = &xorshift1024_uint64 - self._prng.next_uint32 = &xorshift1024_uint32 - self._prng.next_double = &xorshift1024_double - self._prng.next_raw = &xorshift1024_uint64 + self._brng.state = self.rng_state + self._brng.next_uint64 = &xorshift1024_uint64 + self._brng.next_uint32 = &xorshift1024_uint32 + self._brng.next_double = &xorshift1024_double + self._brng.next_raw = &xorshift1024_uint64 - cdef const char *name = "CorePRNG" - self.capsule = PyCapsule_New(self._prng, name, NULL) + cdef const char *name = "BasicRNG" + self.capsule = PyCapsule_New(self._brng, name, NULL) # Pickling support: def __getstate__(self): @@ -151,13 +151,13 @@ cdef class Xorshift1024: self.state = state def __reduce__(self): - return (core_prng.pickle.__prng_ctor, - (self.state['prng'],), + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), self.state) def __dealloc__(self): free(self.rng_state) - free(self._prng) + free(self._brng) cdef _reset_state_variables(self): self.rng_state.has_uint32 = 0 @@ -182,9 +182,9 @@ cdef class Xorshift1024: Testing only """ if bits == 64: - return self._prng.next_uint64(self._prng.state) + return self._brng.next_uint64(self._brng.state) elif bits == 32: - return self._prng.next_uint32(self._prng.state) + return self._brng.next_uint32(self._brng.state) else: raise ValueError('bits must be 32 or 64') @@ -192,10 +192,10 @@ cdef class Xorshift1024: cdef Py_ssize_t i if method==u'uint64': for i in range(cnt): - self._prng.next_uint64(self._prng.state) + self._brng.next_uint64(self._brng.state) elif method==u'double': for i in range(cnt): - self._prng.next_double(self._prng.state) + self._brng.next_double(self._brng.state) else: raise ValueError('Unknown method') @@ -267,7 +267,7 @@ cdef class Xorshift1024: s = np.empty(16, dtype=np.uint64) for i in range(16): s[i] = self.rng_state.s[i] - return {'prng': self.__class__.__name__, + return {'brng': self.__class__.__name__, 'state': {'s':s,'p':self.rng_state.p}, 'has_uint32': self.rng_state.has_uint32, 'uinteger': self.rng_state.uinteger} @@ -276,8 +276,8 @@ cdef class Xorshift1024: def state(self, value): if not isinstance(value, dict): raise TypeError('state must be a dict') - prng = value.get('prng', '') - if prng != self.__class__.__name__: + brng = value.get('brng', '') + if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) for i in range(16): @@ -301,7 +301,7 @@ cdef class Xorshift1024: * next_uint64 - function pointer to produce 64 bit integers * next_uint32 - function pointer to produce 32 bit integers * next_double - function pointer to produce doubles - * prng - pointer to the PRNG struct + * brng - pointer to the Basic RNG struct """ if self._ctypes is not None: @@ -320,7 +320,7 @@ cdef class Xorshift1024: ctypes.cast(&xorshift1024_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._prng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -338,7 +338,7 @@ cdef class Xorshift1024: * next_uint64 - function pointer to produce 64 bit integers * next_uint32 - function pointer to produce 32 bit integers * next_double - function pointer to produce doubles - * prng - pointer to the PRNG struct + * brng - pointer to the Basic RNG struct """ if self._cffi is not None: return self._cffi @@ -350,10 +350,10 @@ cdef class Xorshift1024: ffi = cffi.FFI() self._cffi = interface(self.rng_state, ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._prng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._prng.next_uint32), - ffi.cast('double (*)(void *)',self._prng.next_double), - ffi.cast('void *',self._prng)) + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property @@ -363,7 +363,7 @@ cdef class Xorshift1024: Returns ------- - gen : core_prng.generator.RandomGenerator + gen : randomgen.generator.RandomGenerator Random generator used this instance as the core PRNG """ if self._generator is None: diff --git a/_randomgen/setup.cfg b/_randomgen/setup.cfg index d622db893c08..d6b61d347b3d 100644 --- a/_randomgen/setup.cfg +++ b/_randomgen/setup.cfg @@ -1,7 +1,7 @@ [versioneer] VCS = git style = pep440 -versionfile_source = core_prng/_version.py -versionfile_build = core_prng/_version.py +versionfile_source = randomgen/_version.py +versionfile_build = randomgen/_version.py tag_prefix = -parentdir_prefix = core_prng- +parentdir_prefix = randomgen- diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 6508bde6473c..9c73c3d70e05 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -24,7 +24,7 @@ Cython.Compiler.Options.annotate = True USE_SSE2 = True if not '--no-sse2' in sys.argv else False -MOD_DIR = './core_prng' +MOD_DIR = './randomgen' DEBUG = False PCG_EMULATED_MATH = False @@ -53,7 +53,7 @@ if struct.calcsize('P') < 8: PCG_EMULATED_MATH = True -files = glob.glob('./core_prng/*.in') +files = glob.glob('./randomgen/*.in') for templated_file in files: output_file_name = os.path.splitext(templated_file)[0] if (os.path.exists(output_file_name) and @@ -65,7 +65,7 @@ output_file.write(template.substitute()) -extensions = [Extension('core_prng.entropy', +extensions = [Extension('randomgen.entropy', sources=[join(MOD_DIR, 'entropy.pyx'), join(MOD_DIR, 'src', 'entropy', 'entropy.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), @@ -74,8 +74,8 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.dsfmt", - ["core_prng/dsfmt.pyx", + Extension("randomgen.dsfmt", + ["randomgen/dsfmt.pyx", join(MOD_DIR, 'src', 'dsfmt', 'dSFMT.c'), join(MOD_DIR, 'src', 'dsfmt', 'dSFMT-jump.c'), join(MOD_DIR, 'src', 'aligned_malloc', 'aligned_malloc.c')], @@ -86,8 +86,8 @@ extra_link_args=EXTRA_LINK_ARGS, define_macros=DSFMT_DEFS, ), - Extension("core_prng.mt19937", - ["core_prng/mt19937.pyx", + Extension("randomgen.mt19937", + ["randomgen/mt19937.pyx", join(MOD_DIR, 'src', 'mt19937', 'mt19937.c'), join(MOD_DIR, 'src', 'mt19937', 'mt19937-jump.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), @@ -96,8 +96,8 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.philox", - ["core_prng/philox.pyx", + Extension("randomgen.philox", + ["randomgen/philox.pyx", join(MOD_DIR, 'src', 'philox', 'philox.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', @@ -105,8 +105,8 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.pcg64", - ["core_prng/pcg64.pyx", + Extension("randomgen.pcg64", + ["randomgen/pcg64.pyx", join(MOD_DIR, 'src', 'pcg64', 'pcg64.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', @@ -114,8 +114,8 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.pcg32", - ["core_prng/pcg32.pyx", + Extension("randomgen.pcg32", + ["randomgen/pcg32.pyx", join(MOD_DIR, 'src', 'pcg32', 'pcg32.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', @@ -123,8 +123,8 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.threefry", - ["core_prng/threefry.pyx", + Extension("randomgen.threefry", + ["randomgen/threefry.pyx", join(MOD_DIR, 'src', 'threefry', 'threefry.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', @@ -132,8 +132,8 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.threefry32", - ["core_prng/threefry32.pyx", + Extension("randomgen.threefry32", + ["randomgen/threefry32.pyx", join(MOD_DIR, 'src', 'threefry32', 'threefry32.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', @@ -141,8 +141,8 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.xoroshiro128", - ["core_prng/xoroshiro128.pyx", + Extension("randomgen.xoroshiro128", + ["randomgen/xoroshiro128.pyx", join(MOD_DIR, 'src', 'xoroshiro128', 'xoroshiro128.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), @@ -152,8 +152,8 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.xorshift1024", - ["core_prng/xorshift1024.pyx", + Extension("randomgen.xorshift1024", + ["randomgen/xorshift1024.pyx", join(MOD_DIR, 'src', 'xorshift1024', 'xorshift1024.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), @@ -162,22 +162,22 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.generator", - ["core_prng/generator.pyx", + Extension("randomgen.generator", + ["randomgen/generator.pyx", join(MOD_DIR, 'src', 'distributions', 'distributions.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.common", - ["core_prng/common.pyx"], + Extension("randomgen.common", + ["randomgen/common.pyx"], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("core_prng.bounded_integers", - ["core_prng/bounded_integers.pyx", + Extension("randomgen.bounded_integers", + ["randomgen/bounded_integers.pyx", join(MOD_DIR, 'src', 'distributions', 'distributions.c')], include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], @@ -197,9 +197,9 @@ def is_pure(self): cmdclass=versioneer.get_cmdclass(), ext_modules=cythonize(extensions, compile_time_env={ "PCG_EMULATED_MATH": PCG_EMULATED_MATH}), - name='core_prng', + name='randomgen', packages=find_packages(), - package_dir={'core_prng': './core_prng'}, + package_dir={'randomgen': './randomgen'}, package_data={'': ['*.c', '*.h', '*.pxi', '*.pyx', '*.pxd']}, include_package_data=True, license='NSCA', @@ -207,7 +207,7 @@ def is_pure(self): author_email='kevin.k.sheppard@gmail.com', distclass=BinaryDistribution, description='Next-gen RandomState supporting multiple PRNGs', - url='https://github.com/bashtage/core-prng', + url='https://github.com/bashtage/randomgen', keywords=['pseudo random numbers', 'PRNG', 'Python'], zip_safe=False ) diff --git a/_randomgen/test.py b/_randomgen/test.py deleted file mode 100644 index 38ffa02b05c4..000000000000 --- a/_randomgen/test.py +++ /dev/null @@ -1,14 +0,0 @@ -import core_prng as c -rg = c.RandomGenerator() -print(rg.state) -rg.random_integer(32) -print(rg.state) -rg.random_integer(32) -print(rg.state) - -rg.random_integer(64) -print(rg.state) -rg.random_integer(32) -print(rg.state) -rg.random_integer(64) -print(rg.state) From b859848aa9ab239e5956d5c504f400720d519c8f Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 12:40:45 +0000 Subject: [PATCH 077/279] DOC: Update docs Major doc upgrade --- .../doc/source/{prng => brng}/dsfmt.rst | 2 + .../doc/source/{prng => brng}/index.rst | 3 +- _randomgen/doc/source/brng/mt19937.rst | 40 +++ _randomgen/doc/source/brng/pcg32.rst | 41 +++ _randomgen/doc/source/brng/pcg64.rst | 41 +++ .../source/{prng => brng}/xoroshiro128.rst | 2 + .../source/{prng => brng}/xorshift1024.rst | 2 + _randomgen/doc/source/change-log.rst | 4 + _randomgen/doc/source/conf.py | 13 +- _randomgen/doc/source/entropy.rst | 6 + _randomgen/doc/source/extending.rst | 16 ++ _randomgen/doc/source/index.rst | 164 +++++++++++- _randomgen/doc/source/multithreading.rst | 130 +++++++++ _randomgen/doc/source/new-or-different.rst | 95 +++++++ _randomgen/doc/source/parallel.rst | 141 ++++++++++ _randomgen/doc/source/performance.py | 73 +++++ _randomgen/doc/source/performance.rst | 73 +++++ _randomgen/randomgen/dsfmt.pyx | 4 +- _randomgen/randomgen/generator.pyx | 60 ++++- _randomgen/randomgen/mt19937.pyx | 93 +++++++ _randomgen/randomgen/pcg32.pyx | 228 +++++++++++++++- _randomgen/randomgen/pcg64.pyx | 250 ++++++++++++++++-- _randomgen/randomgen/philox.pyx | 92 +++++++ _randomgen/randomgen/threefry.pyx | 93 +++++++ _randomgen/randomgen/xoroshiro128.pyx | 2 +- _randomgen/randomgen/xorshift1024.pyx | 21 +- 26 files changed, 1637 insertions(+), 52 deletions(-) rename _randomgen/doc/source/{prng => brng}/dsfmt.rst (94%) rename _randomgen/doc/source/{prng => brng}/index.rst (92%) create mode 100644 _randomgen/doc/source/brng/mt19937.rst create mode 100644 _randomgen/doc/source/brng/pcg32.rst create mode 100644 _randomgen/doc/source/brng/pcg64.rst rename _randomgen/doc/source/{prng => brng}/xoroshiro128.rst (93%) rename _randomgen/doc/source/{prng => brng}/xorshift1024.rst (93%) create mode 100644 _randomgen/doc/source/change-log.rst create mode 100644 _randomgen/doc/source/entropy.rst create mode 100644 _randomgen/doc/source/extending.rst create mode 100644 _randomgen/doc/source/multithreading.rst create mode 100644 _randomgen/doc/source/new-or-different.rst create mode 100644 _randomgen/doc/source/parallel.rst create mode 100644 _randomgen/doc/source/performance.py create mode 100644 _randomgen/doc/source/performance.rst diff --git a/_randomgen/doc/source/prng/dsfmt.rst b/_randomgen/doc/source/brng/dsfmt.rst similarity index 94% rename from _randomgen/doc/source/prng/dsfmt.rst rename to _randomgen/doc/source/brng/dsfmt.rst index 2f5ed0ba77de..3432d4d043ce 100644 --- a/_randomgen/doc/source/prng/dsfmt.rst +++ b/_randomgen/doc/source/brng/dsfmt.rst @@ -1,6 +1,8 @@ Double SIMD Mersenne Twister (dSFMT) ------------------------------------ +.. module:: randomgen.dsfmt + .. currentmodule:: randomgen.dsfmt Random generator diff --git a/_randomgen/doc/source/prng/index.rst b/_randomgen/doc/source/brng/index.rst similarity index 92% rename from _randomgen/doc/source/prng/index.rst rename to _randomgen/doc/source/brng/index.rst index 8aebf16813e0..8bd29c1ca622 100644 --- a/_randomgen/doc/source/prng/index.rst +++ b/_randomgen/doc/source/brng/index.rst @@ -10,6 +10,7 @@ These RNGs will be included in future releases. :maxdepth: 1 DSFMT + MT19937 PCG64 Philox ThreeFry @@ -26,5 +27,5 @@ permanent. .. toctree:: :maxdepth: 1 + PCG32 ThreeFry32 - PCG32 \ No newline at end of file diff --git a/_randomgen/doc/source/brng/mt19937.rst b/_randomgen/doc/source/brng/mt19937.rst new file mode 100644 index 000000000000..3fbc8f0994c4 --- /dev/null +++ b/_randomgen/doc/source/brng/mt19937.rst @@ -0,0 +1,40 @@ +Mersenne Twister (MT19937) +-------------------------- + +.. module:: randomgen.mt19937 + +.. currentmodule:: randomgen.mt19937 + +Random generator +================ +.. autoclass:: MT19937 + +.. autosummary:: + :toctree: generated/ + + ~MT19937.seed + ~MT19937.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~MT19937.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~MT19937.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~MT19937.cffi + ~MT19937.ctypes + + diff --git a/_randomgen/doc/source/brng/pcg32.rst b/_randomgen/doc/source/brng/pcg32.rst new file mode 100644 index 000000000000..97bb341ad45b --- /dev/null +++ b/_randomgen/doc/source/brng/pcg32.rst @@ -0,0 +1,41 @@ +Parallel Congruent Generator (32-bit, PCG32) +-------------------------------------------- + +.. module:: randomgen.pcg32 + +.. currentmodule:: randomgen.pcg32 + +Random generator +================ +.. autoclass:: PCG32 + +.. autosummary:: + :toctree: generated/ + + ~PCG32.seed + ~PCG32.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~PCG32.advance + ~PCG32.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~PCG32.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~PCG32.cffi + ~PCG32.ctypes + + diff --git a/_randomgen/doc/source/brng/pcg64.rst b/_randomgen/doc/source/brng/pcg64.rst new file mode 100644 index 000000000000..2ef19abb2123 --- /dev/null +++ b/_randomgen/doc/source/brng/pcg64.rst @@ -0,0 +1,41 @@ +Parallel Congruent Generator (64-bit, PCG64) +-------------------------------------------- + +.. module:: randomgen.pcg64 + +.. currentmodule:: randomgen.pcg64 + +Random generator +================ +.. autoclass:: PCG64 + +.. autosummary:: + :toctree: generated/ + + ~PCG64.seed + ~PCG64.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~PCG64.advance + ~PCG64.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~PCG64.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~PCG64.cffi + ~PCG64.ctypes + + diff --git a/_randomgen/doc/source/prng/xoroshiro128.rst b/_randomgen/doc/source/brng/xoroshiro128.rst similarity index 93% rename from _randomgen/doc/source/prng/xoroshiro128.rst rename to _randomgen/doc/source/brng/xoroshiro128.rst index 768ace408806..9f8b2dfadc65 100644 --- a/_randomgen/doc/source/prng/xoroshiro128.rst +++ b/_randomgen/doc/source/brng/xoroshiro128.rst @@ -1,6 +1,8 @@ Xoroshiro128+ ------------- +.. module:: randomgen.xoroshiro128 + .. currentmodule:: randomgen.xoroshiro128 Random generator diff --git a/_randomgen/doc/source/prng/xorshift1024.rst b/_randomgen/doc/source/brng/xorshift1024.rst similarity index 93% rename from _randomgen/doc/source/prng/xorshift1024.rst rename to _randomgen/doc/source/brng/xorshift1024.rst index 87adc9821446..5340579c0f8a 100644 --- a/_randomgen/doc/source/prng/xorshift1024.rst +++ b/_randomgen/doc/source/brng/xorshift1024.rst @@ -1,6 +1,8 @@ Xorshift1024*φ -------------- +.. module:: randomgen.xorshift1024 + .. currentmodule:: randomgen.xorshift1024 Random generator diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst new file mode 100644 index 000000000000..36c46223ad4c --- /dev/null +++ b/_randomgen/doc/source/change-log.rst @@ -0,0 +1,4 @@ +Change Log +---------- + +The project is too new for a change log. \ No newline at end of file diff --git a/_randomgen/doc/source/conf.py b/_randomgen/doc/source/conf.py index 3ff696214888..b832553cb218 100644 --- a/_randomgen/doc/source/conf.py +++ b/_randomgen/doc/source/conf.py @@ -48,6 +48,8 @@ 'sphinx.ext.autosummary', 'sphinx.ext.mathjax', 'sphinx.ext.githubpages', + 'IPython.sphinxext.ipython_console_highlighting', + 'IPython.sphinxext.ipython_directive' ] # Add any paths that contain templates here, relative to this directory. @@ -170,6 +172,15 @@ # -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = { + 'statsmodels': ('http://www.statsmodels.org/dev/', None), + 'matplotlib': ('https://matplotlib.org', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None), + 'python': ('https://docs.python.org/3', None), + 'numpy': ('https://docs.scipy.org/doc/numpy', None), + 'np': ('https://docs.scipy.org/doc/numpy', None), + 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), + 'pd': ('https://pandas.pydata.org/pandas-docs/stable/', None), +} autosummary_generate = True diff --git a/_randomgen/doc/source/entropy.rst b/_randomgen/doc/source/entropy.rst new file mode 100644 index 000000000000..3e50c892fc1d --- /dev/null +++ b/_randomgen/doc/source/entropy.rst @@ -0,0 +1,6 @@ +System Entropy +============== + +.. module:: randomgen.entropy + +.. autofunction:: random_entropy diff --git a/_randomgen/doc/source/extending.rst b/_randomgen/doc/source/extending.rst new file mode 100644 index 000000000000..0f4592bca1af --- /dev/null +++ b/_randomgen/doc/source/extending.rst @@ -0,0 +1,16 @@ +Extending +--------- + +.. TODO: Complete + +Using a Basic RNG in numba +========================== + +Accessing a distribution in numba +================================= + +Using with Cython +================= + +Adding a New Basic RNG +====================== diff --git a/_randomgen/doc/source/index.rst b/_randomgen/doc/source/index.rst index 067416635ab8..55e0b206dd31 100644 --- a/_randomgen/doc/source/index.rst +++ b/_randomgen/doc/source/index.rst @@ -1,21 +1,171 @@ -.. RandomGen documentation master file, created by - sphinx-quickstart on Tue Mar 13 20:30:45 2018. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - RandomGen ========= +This package contains replacements for the NumPy +:class:`~numpy.random.RandomState` object that allows the core random number +generator be be changed. + +Introduction +------------ +RandomGen takes a different approach to producing random numbers from the +:class:`~numpy.random.RandomState` object used in NumPy. Random number +generation is separated into two components, a basic RNG and a random +generator. + +The basic RNG has a limited set of responsibilities -- it manages the +underlying RNG state and provides functions to produce random doubles and +random unsigned 32- and 64-bit values. The basic random generator also handles +all seeding since this varies when using alternative basic RNGs. + +The random generator (:class:`~randomgen.generator.RandomGenerator`) takes the +basic RNG-provided functions and transforms them into more useful +distributions, e.g., simulated normal random values. This structure allows +alternative basic RNGs to be used without code duplication. + +The :class:`~randomgen.generator.RandomGenerator` is the user-facing object +that is nearly identical to :class:`~numpy.random.RandomState`. The canonical +method to initialize a generator passes a basic RNG -- +:class:`~randomgen.mt19937.MT19937`, the underlying RNG in NumPy -- as the +sole argument. Note that the basic RNG must be instantized. + +.. ipython:: python + + from randomgen import RandomGenerator, MT19937 + rg = RandomGenerator(MT19937()) + rg.random_sample() + +Seed information is directly passed to the basic RNG. + +.. ipython:: python + + rg = RandomGenerator(MT19937(12345)) + rg.random_sample() + +A shorthand method is also available which uses the +:meth:`~randomgen.mt19937.MT19937.generator` property from a basic RNG to +access an embedded random generator. + +.. ipython:: python + + rg = MT19937(12345).generator + rg.random_sample() + +What's New or Different +~~~~~~~~~~~~~~~~~~~~~~~ +.. warning:: + + The Box-Muller method used to produce NumPy's normals is no longer available. + It is not possible to exactly reproduce the random values produced from NumPy + for the normal distribution or any other distribution that relies on the + normal such as the gamma or student's t. + +* The normal, exponential and gamma generators use 256-step Ziggurat + methods which are 2-10 times faster than NumPy's Box-Muller or inverse CDF + implementations. +* Optional ``dtype`` argument that accepts ``np.float32`` or ``np.float64`` + to produce either single or double prevision uniform random variables for + select distributions +* Optional ``out`` argument that allows existing arrays to be filled for + select distributions +* Simulate from the complex normal distribution + (:meth:`~randomgen.generator.RandomGenerator.complex_normal`) +* :func:`randomgen.entropy.random_entropy` provides access to the system + source of randomness that is used in cryptographic applications (e.g., + ``/dev/urandom`` on Unix). +* All basic random generators functions to produce doubles, uint64s and + uint32s via CTypes (:meth:`~randomgen.xoroshiro128.Xoroshiro128.ctypes`) + and CFFI (:meth:`~randomgen.xoroshiro128.Xoroshiro128.cffi`). This allows + these basic RNGs to be used in numba. +* The basic random number generators can be used in downstream projects via + Cython. + +See :ref:`new-or-different` for a complete list of improvements and +differences. +Parallel Generation +~~~~~~~~~~~~~~~~~~~ + +The included generators can be used in parallel, distributed applications in +one of two ways: + +* :ref:`independent-streams` +* :ref:`jump-and-advance` + +Supported Generators +-------------------- +The main innovation is the inclusion of a number of alternative pseudo-random number +generators, 'in addition' to the standard PRNG in NumPy. The included PRNGs are: + +* MT19937 - The standard NumPy generator. Produces identical results to NumPy + using the same seed/state. Adds a jump function that advances the generator + as-if 2**128 draws have been made (:meth:`randomstate.prng.mt19937.jump`). + See `NumPy's documentation`_. +* dSFMT - SSE2 enabled versions of the MT19937 generator. Theoretically + the same, but with a different state and so it is not possible to produce a + sequence identical to MT19937. Supports ``jump`` and so can + be used in parallel applications. See the `dSFMT authors' page`_. +* XoroShiro128+ - Improved version of XorShift128+ with better performance + and statistical quality. Like the XorShift generators, it can be jumped + to produce multiple streams in parallel applications. See + :meth:`randomgen.xoroshiro128.Xoroshiro128.jump` for details. + More information about this PRNG is available at the + `xorshift and xoroshiro authors' page`_. +* XorShift1024*φ - Vast fast generator based on the XSadd + generator. Supports ``jump`` and so can be used in + parallel applications. See the documentation for + :meth:`randomgen.xorshift1024.Xorshift1024.jump` for details. More information + about these PRNGs is available at the + `xorshift and xoroshiro authors' page`_. +* PCG-64 - Fast generator that support many parallel streams and + can be advanced by an arbitrary amount. See the documentation for + :meth:`randomgen.pcg64.PCG64.advance`. PCG-64 has a period of + :math:`2^{128}`. See the `PCG author's page`_ for more details about + this class of PRNG. +* ThreeFry and Philox - counter-based generators capable of being advanced an + arbitrary number of steps or generating independent streams. See the + `Random123`_ page for more details about this class of PRNG. + +.. _`NumPy's documentation`: https://docs.scipy.org/doc/numpy/reference/routines.random.html +.. _`dSFMT authors' page`: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/ +.. _`xorshift and xoroshiro authors' page`: http://xoroshiro.di.unimi.it/ +.. _`PCG author's page`: http://www.pcg-random.org/ +.. _`Random123`: https://www.deshawresearch.com/resources_random123.html + +New Features +------------ .. toctree:: :maxdepth: 2 - :caption: Contents: + + Parallel Applications + Multithreaded Generation + new-or-different + Reading System Entropy + Comparing Performance + extending + +Random Generator +---------------- +.. toctree:: + :maxdepth: 1 Random Generator + +Basic Random Number Generators +------------------------------ + +.. toctree:: + :maxdepth: 3 + Basic Random Number Generators +Changes +~~~~~~~ +.. toctree:: + :maxdepth: 2 + + Change Log Indices and tables -================== +~~~~~~~~~~~~~~~~~~ * :ref:`genindex` * :ref:`modindex` diff --git a/_randomgen/doc/source/multithreading.rst b/_randomgen/doc/source/multithreading.rst new file mode 100644 index 000000000000..ef8d710dff26 --- /dev/null +++ b/_randomgen/doc/source/multithreading.rst @@ -0,0 +1,130 @@ +Multithreaded Generation +======================== + +The four core distributions all allow existing arrays to be filled using the +``out`` keyword argument. Existing arrays need to be contiguous and +well-behaved (writable and aligned). Under normal circumstances, arrays +created using the common constructors such as :meth:`numpy.empty` will satisfy +these requirements. + +This example makes use of Python 3 :mod:`concurrent.futures` to fill an array +using multiple threads. Threads are long-lived so that repeated calls do not +require any additional overheads from thread creation. The underlying PRNG is +xorshift2014 which is fast, has a long period and supports using ``jump`` to +advance the state. The random numbers generated are reproducible in the sense +that the same seed will produce the same outputs. + +.. code-block:: python + + from randomgen import Xorshift1024 + import multiprocessing + import concurrent.futures + import numpy as np + + class MultithreadedRNG(object): + def __init__(self, n, seed=None, threads=None): + rg = Xorshift1024(seed) + if threads is None: + threads = multiprocessing.cpu_count() + self.threads = threads + + self._random_generators = [] + for _ in range(0, threads-1): + _rg = Xorshift1024() + _rg.state = rg.state + self._random_generators.append(_rg.generator) + rg.jump() + self._random_generators.append(rg.generator) + + self.n = n + self.executor = concurrent.futures.ThreadPoolExecutor(threads) + self.values = np.empty(n) + self.step = np.ceil(n / threads).astype(np.int) + + def fill(self): + def _fill(random_state, out, first, last): + random_state.standard_normal(out=out[first:last]) + + futures = {} + for i in range(self.threads): + args = (_fill, self._random_generators[i], self.values, i * self.step, (i + 1) * self.step) + futures[self.executor.submit(*args)] = i + concurrent.futures.wait(futures) + + def __del__(self): + self.executor.shutdown(False) + + +.. ipython:: python + :suppress: + + + In [1]: from randomgen import Xorshift1024 + ....: import multiprocessing + ....: import concurrent.futures + ....: import numpy as np + ....: class MultithreadedRNG(object): + ....: def __init__(self, n, seed=None, threads=None): + ....: rg = Xorshift1024(seed) + ....: if threads is None: + ....: threads = multiprocessing.cpu_count() + ....: self.threads = threads + ....: self._random_generators = [] + ....: for _ in range(0, threads-1): + ....: _rg = Xorshift1024() + ....: _rg.state = rg.state + ....: self._random_generators.append(_rg.generator) + ....: rg.jump() + ....: self._random_generators.append(rg.generator) + ....: self.n = n + ....: self.executor = concurrent.futures.ThreadPoolExecutor(threads) + ....: self.values = np.empty(n) + ....: self.step = np.ceil(n / threads).astype(np.int) + ....: def fill(self): + ....: def _fill(random_state, out, first, last): + ....: random_state.standard_normal(out=out[first:last]) + ....: futures = {} + ....: for i in range(self.threads): + ....: args = (_fill, self._random_generators[i], self.values, i * self.step, (i + 1) * self.step) + ....: futures[self.executor.submit(*args)] = i + ....: concurrent.futures.wait(futures) + ....: def __del__(self): + ....: self.executor.shutdown(False) + ....: + +The multithreaded random number generator can be used to fill an array. +The ``values`` attributes shows the zero-value before the fill and the +random value after. + +.. ipython:: python + + mrng = MultithreadedRNG(10000000, seed=0) + print(mrng.values[-1]) + mrng.fill() + print(mrng.values[-1]) + +The time required to produce using multiple threads can be compared to +the time required to generate using a single thread. + +.. ipython:: python + + print(mrng.threads) + %timeit mrng.fill() + + +The single threaded call directly uses the PRNG. + +.. ipython:: python + + values = np.empty(10000000) + rg = Xorshift1024().generator + %timeit rg.standard_normal(out=values) + +The gains are substantial and the scaling is reasonable even for large that +are only moderately large. The gains are even larger when compared to a call +that does not use an existing array due to array creation overhead. + +.. ipython:: python + + rg = Xorshift1024().generator + %timeit rg.standard_normal(10000000) diff --git a/_randomgen/doc/source/new-or-different.rst b/_randomgen/doc/source/new-or-different.rst new file mode 100644 index 000000000000..d65463065673 --- /dev/null +++ b/_randomgen/doc/source/new-or-different.rst @@ -0,0 +1,95 @@ +.. _new-or-different: + +What's New or Different +----------------------- + +.. warning:: + + The Box-Muller method used to produce NumPy's normals is no longer available. + It is not possible to exactly reproduce the random values produced from NumPy + for the normal distribution or any other distribution that relies on the + normal such as the gamma or student's t. + + +* :func:`randomgen.entropy.random_entropy` provides access to the system + source of randomness that is used in cryptographic applications (e.g., + ``/dev/urandom`` on Unix). +* Simulate from the complex normal distribution + (:meth:`~randomgen.generator.RandomGenerator.complex_normal`) +* The normal, exponential and gamma generators use 256-step Ziggurat + methods which are 2-10 times faster than NumPy's default implementation in + :meth:`~randomgen.generator.RandomGenerator.standard_normal`, + :meth:`~randomgen.generator.RandomGenerator.standard_exponential` or + :meth:`~randomgen.generator.RandomGenerator.standard_gamma`. +* The Box-Muller used to produce NumPy's normals is no longer available. +* All basic random generators functions to produce doubles, uint64s and + uint32s via CTypes (:meth:`~randomgen.xoroshiro128.Xoroshiro128.ctypes`) + and CFFI (:meth:`~randomgen.xoroshiro128.Xoroshiro128.cffi`). This allows + these basic RNGs to be used in numba. +* The basic random number generators can be used in downstream projects via + Cython. + +.. ipython:: python + + from randomgen import Xoroshiro128 + rg = Xoroshiro128().generator + %timeit rg.standard_normal(1000000) + from numpy.random import standard_normal + %timeit standard_normal(1000000) + +.. ipython:: python + + from randomgen import Xoroshiro128 + rg = Xoroshiro128().generator + %timeit rg.standard_exponential(1000000) + from numpy.random import standard_exponential + %timeit standard_exponential(1000000) + +.. ipython:: python + + from randomgen import Xoroshiro128 + rg = Xoroshiro128().generator + %timeit rg.standard_gamma(3.0, 1000000) + from numpy.random import standard_gamma + %timeit standard_gamma(3.0, 1000000) + +* Optional ``dtype`` argument that accepts ``np.float32`` or ``np.float64`` + to produce either single or double prevision uniform random variables for + select distributions + + * Uniforms (:meth:`~randomgen.generator.RandomGenerator.random_sample` and + :meth:`~randomgen.generator.RandomGenerator.rand`) + * Normals (:meth:`~randomgen.generator.RandomGenerator.standard_normal` and + :meth:`~randomgen.generator.RandomGenerator.randn`) + * Standard Gammas (:meth:`~randomgen.generator.RandomGenerator.standard_gamma`) + * Standard Exponentials (:meth:`~randomgen.generator.RandomGenerator.standard_exponential`) + +.. ipython:: python + + from randomgen import Xoroshiro128 + rg = Xoroshiro128().generator + rg.seed(0) + rg.random_sample(3, dtype='d') + rg.seed(0) + rg.random_sample(3, dtype='f') + +* Optional ``out`` argument that allows existing arrays to be filled for + select distributions + + * Uniforms (:meth:`~randomgen.generator.RandomGenerator.random_sample`) + * Normals (:meth:`~randomgen.generator.RandomGenerator.standard_normal`) + * Standard Gammas (:meth:`~randomgen.generator.RandomGenerator.standard_gamma`) + * Standard Exponentials (:meth:`~randomgen.generator.RandomGenerator.standard_exponential`) + + This allows multithreading to fill large arrays in chunks using suitable + PRNGs in parallel. + +.. ipython:: python + + from randomgen import Xoroshiro128 + rg = Xoroshiro128(0).generator + existing = np.zeros(4) + rg.random_sample(out=existing[:2]) + print(existing) + +.. * For changes since the previous release, see the :ref:`change-log` diff --git a/_randomgen/doc/source/parallel.rst b/_randomgen/doc/source/parallel.rst new file mode 100644 index 000000000000..ee6990f8bd85 --- /dev/null +++ b/_randomgen/doc/source/parallel.rst @@ -0,0 +1,141 @@ +Parallel Random Number Generation +================================= + +There are three strategies implemented that can be used to produce +repeatable pseudo-random numbers across multiple processes (local +or distributed). + +.. _independent-streams: + +Independent Streams +------------------- + +:class:`~randomgen.pcg64.PCG64`, :class:`~randomgen.threefry.ThreeFry` +and :class:`~randomgen.philox.Philox` support independent streams. This +example shows how many streams can be created by passing in different index +values in the second input while using the same seed in the first. + +.. code-block:: python + + from randomgen.entropy import random_entropy + from randomgen import PCG64 + + entropy = random_entropy(4) + # 128-bit number as a seed + seed = sum([int(entropy[i]) * 2 ** (32 * i) for i in range(4)]) + streams = [PCG64(seed, stream) for stream in range(10)] + + +:class:`~randomgen.philox.Philox` and :class:`~randomgen.threefry.ThreeFry` are +counter-based RNGs which use a counter and key. Different keys can be used +to produce independent streams. + +.. code-block:: python + + import numpy as np + from randomgen import ThreeFry + + key = random_entropy(8) + key = key.view(np.uint64) + key[0] = 0 + step = np.zeros(4, dtype=np.uint64) + step[0] = 1 + streams = [ThreeFry(key=key + stream * step) for stream in range(10)] + +.. _jump-and-advance: + +Jump/Advance the PRNG state +--------------------------- + +Jump +**** + +``jump`` advances the state of the PRNG *as-if* a large number of random +numbers have been drawn. The specific number of draws varies by PRNG, and +ranges from :math:`2^{64}` to :math:`2^{512}`. Additionally, the *as-if* +draws also depend on the size of the default random number produced by the +specific PRNG. The PRNGs that support ``jump``, along with the period of +the PRNG, the size of the jump and the bits in the default unsigned random +are listed below. + ++-----------------+-------------------------+-------------------------+-------------------------+ +| PRNG | Period | Jump Size | Bits | ++=================+=========================+=========================+=========================+ +| DSFMT | :math:`2^{19937}` | :math:`2^{128}` | 53 | ++-----------------+-------------------------+-------------------------+-------------------------+ +| MT19937 | :math:`2^{19937}` | :math:`2^{128}` | 32 | ++-----------------+-------------------------+-------------------------+-------------------------+ +| PCG64 | :math:`2^{128}` | :math:`2^{64}` | 64 | ++-----------------+-------------------------+-------------------------+-------------------------+ +| Philox | :math:`2^{256}` | :math:`2^{128}` | 64 | ++-----------------+----------------- --------+-------------------------+-------------------------+ +| ThreeFry | :math:`2^{256}` | :math:`2^{128}` | 64 | ++-----------------+-------------------------+-------------------------+-------------------------+ +| Xoroshiro128 | :math:`2^{128}` | :math:`2^{64}` | 64 | ++-----------------+-------------------------+-------------------------+-------------------------+ +| Xorshift1024 | :math:`2^{1024}` | :math:`2^{512}` | 64 | ++-----------------+-------------------------+-------------------------+-------------------------+ + +``jump`` can be used to produce long blocks which should be long enough to not +overlap. + +.. code-block:: python + + from randomgen.entropy import random_entropy + from randomgen import Xorshift1024 + + entropy = random_entropy(2).astype(np.uint64) + # 64-bit number as a seed + seed = entropy[0] * 2**32 + entropy[1] + blocked_rng = [] + for i in range(10): + rng = Xorshift1024(seed) + rng.jump(i) + blocked_rng.append(rng) + + +Advance +******* +``advance`` can be used to jump the state an arbitrary number of steps, and so +is a more general approach than ``jump``. :class:`~randomgen.pcg64.PCG64`, +:class:`~randomgen.threefry.ThreeFry` and :class:`~randomgen.philox.Philox` +support ``advance``, and since these also support independent +streams, it is not usually necessary to use ``advance``. + +Advancing a PRNG updates the underlying PRNG state as-if a given number of +calls to the underlying PRNG have been made. In general there is not a +one-to-one relationship between the number output random values from a +particular distribution and the number of draws from the core PRNG. +This occurs for two reasons: + +* The random values are simulated using a rejection-based method + and so, on average, more than one value from the underlying + PRNG is required to generate an single draw. +* The number of bits required to generate a simulated value + differs from the number of bits generated by the underlying + PRNG. For example, two 16-bit integer values can be simulated + from a single draw of a 32-bit PRNG. + +Advancing the PRNG state resets any pre-computed random numbers. This is +required to ensure exact reproducibility. + +This example uses ``advance`` to advance a :class:`~randomgen.pcg64.PCG64` +generator 2 ** 127 steps to set a sequence of random number generators. + +.. code-block:: python + + from randomgen import PCG64 + brng = PCG64() + brng_copy = PCG64() + brng_copy.state = brng.state + + advance = 2**127 + brngs = [brng] + for _ in range(9): + brng_copy.advance(advance) + brng = PCG64() + brng.state = brng_copy.state + brngs.append(brng) + +.. end block + diff --git a/_randomgen/doc/source/performance.py b/_randomgen/doc/source/performance.py new file mode 100644 index 000000000000..d84c3147e398 --- /dev/null +++ b/_randomgen/doc/source/performance.py @@ -0,0 +1,73 @@ +import numpy as np +from timeit import timeit, repeat +import pandas as pd + +from randomgen import MT19937, DSFMT, ThreeFry, PCG64, Xoroshiro128, \ + Xorshift1024, Philox + +PRNGS = [DSFMT, MT19937, Philox, PCG64, ThreeFry, Xoroshiro128, Xorshift1024] + +funcs = {'32-bit Unsigned Ints': 'random_uintegers(size=1000000,bits=32)', + '64-bit Unsigned Ints': 'random_uintegers(size=1000000,bits=32)', + 'Uniforms': 'random_sample(size=1000000)', + 'Complex Normals': 'complex_normal(size=1000000)', + 'Normals': 'standard_normal(size=1000000)', + 'Exponentials': 'standard_exponential(size=1000000)', + 'Gammas': 'standard_gamma(3.0,size=1000000)', + 'Binomials': 'binomial(9, .1, size=1000000)', + 'Laplaces': 'laplace(size=1000000)', + 'Poissons': 'poisson(3.0, size=1000000)', } + +setup = """ +from randomgen import {prng} +rg = {prng}().generator +""" + +test = "rg.{func}" +table = {} +for prng in PRNGS: + print(prng) + col = {} + for key in funcs: + t = repeat(test.format(func=funcs[key]), + setup.format(prng=prng().__class__.__name__), + number=1, repeat=3) + col[key]= 1000 * min(t) + col = pd.Series(col) + table[prng().__class__.__name__] = col + + +npfuncs = {} +npfuncs.update(funcs) +npfuncs['32-bit Unsigned Ints'] = 'randint(2**32,dtype="uint32",size=1000000)' +npfuncs['64-bit Unsigned Ints'] = 'tomaxint(size=1000000)' +del npfuncs['Complex Normals'] +setup = """ +from numpy.random import RandomState +rg = RandomState() +""" +col = {} +for key in npfuncs: + t = repeat(test.format(func=npfuncs[key]), + setup.format(prng=prng().__class__.__name__), + number=1, repeat=3) + col[key] = 1000 * min(t) +table['NumPy'] = pd.Series(col) + + +table = pd.DataFrame(table) +table = table.reindex(table.mean(1).sort_values().index) +order = np.log(table).mean().sort_values().index +table = table.T +table = table.reindex(order) +table = table.T +print(table.to_csv(float_format='%0.1f')) + +rel = table / (table.iloc[:,[0]].values @ np.ones((1,8))) +rel.pop(rel.columns[0]) +rel = rel.T +rel['Overall'] = np.exp(np.log(rel).mean(1)) +rel *= 100 +rel = np.round(rel) +rel = rel.T +print(rel.to_csv(float_format='%0d')) \ No newline at end of file diff --git a/_randomgen/doc/source/performance.rst b/_randomgen/doc/source/performance.rst new file mode 100644 index 000000000000..263da09dd9ab --- /dev/null +++ b/_randomgen/doc/source/performance.rst @@ -0,0 +1,73 @@ +Performance +----------- + +.. py:module:: randomstate + +Recommendation +************** +The recommended generator for single use is +:class:`~randomgen.xoroshiro128.Xoroshiro128`. The recommended generator +for use in large-scale parallel applications is +:class:`~randomgen.xorshift1024.Xorshift1024` +where the `jump` method is used to advance the state. For very large scale +applications -- requiring 1,000+ independent streams, +:class:`~randomgen.pcg64.PCG64` or :class:`~randomgen.threefry.ThreeFry` are +the best choices. + +Timings +******* + +The timings below are ns/random value. The fastest generator is the +raw generator (`random_raw`) which does not make any transformation +to the underlying random value. `xoroshiro128+` is the fastest, followed by +`xorshift1024*` and the two SIMD aware MT generators. The original MT19937 +generator is much slower since it requires 2 32-bit values to equal the output +of the faster generators. + +Integer performance has a similar ordering although `dSFMT` is slower since +it generates 53-bit floating point values rather than integer values. On the +other hand, it is very fast for uniforms, although slower than `xoroshiro128+`. + +The patterm is similar for other, more complex generators. The normal +performance of NumPy's MT19937 is much lower than the other since it +uses the Box-Muller transformation rather than the Ziggurat generator. + +.. csv-table:: + :header: ,Xoroshiro128,Xorshift1024,PCG64,DSFMT,MT19937,Philox,ThreeFry,NumPy + :widths: 14,14,14,14,14,14,14,14,14 + + 32-bit Unsigned Ints,3.0,3.0,3.0,3.5,3.7,6.8,6.6,3.3 + 64-bit Unsigned Ints,2.6,3.0,3.1,3.4,3.8,6.9,6.6,8.8 + Uniforms,3.2,3.8,4.4,5.0,7.4,8.9,9.9,8.8 + Normals,11.0,13.9,13.7,15.8,16.9,17.8,18.8,63.0 + Exponentials,7.0,8.4,9.0,11.2,12.5,14.1,15.0,102.2 + Binomials,20.9,22.6,22.0,21.2,26.7,27.7,29.2,26.5 + Complex Normals,23.2,28.7,29.1,33.2,35.4,37.6,38.6, + Gammas,35.3,38.6,39.2,41.3,46.7,49.4,51.2,98.8 + Laplaces,97.8,99.9,99.8,96.2,104.1,104.6,104.8,104.1 + Poissons,104.8,113.2,113.3,107.6,129.7,135.6,138.1,131.9 + + +The next table presents the performance relative to `xoroshiro128+` in +percentage. The overall performance was computed using a geometric mean. + +.. csv-table:: + :header: ,Xorshift1024,PCG64,DSFMT,MT19937,Philox,ThreeFry,NumPy + :widths: 14,14,14,14,14,14,14,14 + + 32-bit Unsigned Ints,102,99,118,125,229,221,111 + 64-bit Unsigned Ints,114,116,129,143,262,248,331 + Uniforms,116,137,156,231,275,306,274 + Normals,126,124,143,153,161,170,572 + Exponentials,121,130,161,179,203,215,1467 + Binomials,108,105,101,128,133,140,127 + Complex Normals,124,125,143,153,162,166, + Gammas,109,111,117,132,140,145,280 + Laplaces,102,102,98,106,107,107,106 + Poissons,108,108,103,124,129,132,126 + Overall,113,115,125,144,172,177,251 + + +.. note:: + + All timings were taken using Linux on a i5-3570 processor. diff --git a/_randomgen/randomgen/dsfmt.pyx b/_randomgen/randomgen/dsfmt.pyx index 5c979e6e8040..778fd34f7074 100644 --- a/_randomgen/randomgen/dsfmt.pyx +++ b/_randomgen/randomgen/dsfmt.pyx @@ -237,9 +237,9 @@ cdef class DSFMT: obj.data, np.PyArray_DIM(obj, 0)) - def jump(self, np.npy_intp iter): + def jump(self, np.npy_intp iter=1): """ - jump(iter = 1) + jump(iter=1) Jumps the state of the random number generator as-if 2**128 random numbers have been generated. diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 0d988f678295..3c5006b6d8a8 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -38,18 +38,55 @@ _randint_types = {'bool': (0, 2), cdef class RandomGenerator: """ - Prototype Random Generator that consumes randoms from a Basic RNG class + RandomGenerator(brng=None) + + Container for the Basic Random Number Generators. + + ``RandomGenerator`` exposes a number of methods for generating random + numbers drawn from a variety of probability distributions. In addition to the + distribution-specific arguments, each method takes a keyword argument + `size` that defaults to ``None``. If `size` is ``None``, then a single + value is generated and returned. If `size` is an integer, then a 1-D + array filled with generated values is returned. If `size` is a tuple, + then an array with that shape is filled and returned. + + **No Compatibility Guarantee** + + ``RandomGenerator`` is evolving and so it isn't possible to provide a + compatibility guarantee like NumPy does. In particular, better algorithms + have already been added. This will change once ``RandomGenerator`` + stabilizes. Parameters ---------- - brng : BasicRNG, optional - Object exposing a PyCapsule containing state and function pointers + brng : Basic RNG, optional + Basic RNG to use as the core generator. If none is provided, uses + Xoroshiro128. + + Notes + ----- + The Python stdlib module "random" contains pseudo-random number generator + with a number of methods that are similar to the ones available in + ``RandomGenerator``. It uses Mersenne Twister, and this basic RNG can be + accessed using ``MT19937``. ``RandomGenerator``, besides being + NumPy-aware, has the advantage that it provides a much larger number + of probability distributions to choose from. Examples -------- - >>> from randomgen.generator import RandomGenerator + >>> from randomgen import RandomGenerator >>> rg = RandomGenerator() >>> rg.standard_normal() + + Using a specific generator + + >>> from randomgen import MT19937 + >>> rg = RandomGenerator(MT19937()) + + The generator is also directly avialable from basic RNGs + + >>> rg = MT19937().generator + >>> rg.standard_normal() """ cdef public object _basicrng cdef brng_t *_brng @@ -93,14 +130,25 @@ cdef class RandomGenerator: def seed(self, *args, **kwargs): """ - TODO: Should this remain + Reseed the basic RNG. + + Parameters depend on the basic RNG used. """ + # TODO: Should this remain self._basicrng.seed(*args, **kwargs) return self @property def state(self): - """Get or set the underlying PRNG's state""" + """ + Get or set the Basic RNG's state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the Basic RNG + """ return self._basicrng.state @state.setter diff --git a/_randomgen/randomgen/mt19937.pyx b/_randomgen/randomgen/mt19937.pyx index 483bd6baa107..c66f89a03e95 100644 --- a/_randomgen/randomgen/mt19937.pyx +++ b/_randomgen/randomgen/mt19937.pyx @@ -6,6 +6,7 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np +from common import interface from common cimport * from distributions cimport brng_t import randomgen.pickle @@ -57,6 +58,9 @@ cdef class MT19937: cdef mt19937_state *rng_state cdef brng_t *_brng cdef public object capsule + cdef object _ctypes + cdef object _cffi + cdef object _generator def __init__(self, seed=None): self.rng_state = malloc(sizeof(mt19937_state)) @@ -69,6 +73,10 @@ cdef class MT19937: self._brng.next_double = &mt19937_double self._brng.next_raw = &mt19937_raw + self._ctypes = None + self._cffi = None + self._generator = None + cdef const char *name = "BasicRNG" self.capsule = PyCapsule_New(self._brng, name, NULL) @@ -199,3 +207,88 @@ cdef class MT19937: for i in range(624): self.rng_state.key[i] = key[i] self.rng_state.pos = value['state']['pos'] + + @property + def ctypes(self): + """ + Cytpes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + + if self._ctypes is not None: + return self._ctypes + + import ctypes + + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&mt19937_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&mt19937_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&mt19937_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p(self._brng)) + return self.ctypes + + @property + def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + if self._cffi is not None: + return self._cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') + + ffi = cffi.FFI() + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) + return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : randomgen.generator.RandomGenerator + Random generator used this instance as the core PRNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator \ No newline at end of file diff --git a/_randomgen/randomgen/pcg32.pyx b/_randomgen/randomgen/pcg32.pyx index d0b57a2b0562..a2cb4c71ec23 100644 --- a/_randomgen/randomgen/pcg32.pyx +++ b/_randomgen/randomgen/pcg32.pyx @@ -4,6 +4,7 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np +from common import interface from common cimport * from distributions cimport brng_t from randomgen.entropy import random_entropy @@ -46,22 +47,80 @@ cdef uint64_t pcg32_raw(void* st) nogil: cdef class PCG32: - """ - Prototype Basic RNG using pcg64 + u""" + PCG32(seed=None, inc=0) + + Container for the PCG-32 pseudo-random number generator. + + PCG-32 is a 64-bit implementation of O'Neill's permutation congruential + generator ([1]_, [2]_). PCG-32 has a period of :math:`2^{64}` and supports + advancing an arbitrary number of steps as well as :math:`2^{63}` streams. + + ``PCG32`` exposes no user-facing API except ``generator``,``state``, + ``cffi`` and ``ctypes``. Designed for use in a ``RandomGenerator`` object. + + **Compatibility Guarantee** + + ``PCG32`` makes a guarantee that a fixed seed will always produce the same + results. Parameters ---------- - seed : int, array of int - Integer or array of integers between 0 and 2**64 - 1 + seed : {None, long}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**64] or ``None`` (the default). + If `seed` is ``None``, then ``PCG32`` will try to read data + from ``/dev/urandom`` (or the Windows analog) if available. If + unavailable, a 64-bit hash of the time and process ID is used. + inc : {None, int}, optional + Stream to return. + Can be an integer in [0, 2**64] or ``None`` (the default). If `inc` is + ``None``, then 0 is used. Can be used with the same seed to + produce multiple streams using other values of inc. Notes ----- - Exposes no user-facing API except `get_state` and `set_state`. Designed - for use in a `RandomGenerator` object. + Supports the method advance to advance the PRNG an arbitrary number of + steps. The state of the PCG-32 PRNG is represented by 2 128-bit unsigned + integers. + + See ``PCG32`` for a similar implementation with a smaller period. + + **Parallel Features** + + ``PCG32`` can be used in parallel applications in one of two ways. + The preferable method is to use sub-streams, which are generated by using the + same value of ``seed`` and incrementing the second value, ``inc``. + + >>> from randomgen import RandomGenerator, PCG32 + >>> rg = [RandomGenerator(PCG32(1234, i + 1)) for i in range(10)] + + The alternative method is to call ``advance`` on a single RandomState to + produce non-overlapping sequences. + + >>> rg = [RandomGenerator(PCG32(1234, i + 1)) for i in range(10)] + >>> for i in range(10): + ... rg[i].advance(i * 2**32) + + **State and Seeding** + + The ``PCG32`` state vector consists of 2 unsigned 64-bit values/ + ``PCG32`` is seeded using a single 64-bit unsigned integer. In addition, + a second 64-bit unsigned integer is used to set the stream. + + References + ---------- + .. [1] "PCG, A Family of Better Random Number Generators", + http://www.pcg-random.org/ + .. [2] O'Neill, Melissa E. "PCG: A Family of Simple Fast Space-Efficient + Statistically Good Algorithms for Random Number Generation" """ cdef pcg32_state *rng_state cdef brng_t *_brng cdef public object capsule + cdef object _ctypes + cdef object _cffi + cdef object _generator def __init__(self, seed=None, inc=0): self.rng_state = malloc(sizeof(pcg32_state)) @@ -75,6 +134,10 @@ cdef class PCG32: self._brng.next_double = &pcg32_double self._brng.next_raw = &pcg32_raw + self._ctypes = None + self._cffi = None + self._generator = None + cdef const char *name = "BasicRNG" self.capsule = PyCapsule_New(self._brng, name, NULL) @@ -133,7 +196,7 @@ cdef class PCG32: def seed(self, seed=None, inc=0): """ - seed(seed=None, stream=None) + seed(seed=None, inc=0) Seed the generator. @@ -152,7 +215,6 @@ cdef class PCG32: ------ ValueError If seed values are out of range for the PRNG. - """ ub = 2 ** 64 if seed is None: @@ -182,7 +244,15 @@ cdef class PCG32: @property def state(self): - """Get or set the PRNG state""" + """ + Get or set the PRNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the PRNG + """ return {'brng': self.__class__.__name__, 'state': {'state': self.rng_state.pcg_state.state, 'inc':self.rng_state.pcg_state.inc}} @@ -198,9 +268,141 @@ cdef class PCG32: self.rng_state.pcg_state.state = value['state']['state'] self.rng_state.pcg_state.inc = value['state']['inc'] - def advance(self, step): - pcg32_advance_state(self.rng_state, step) + def advance(self, delta): + """ + advance(delta) + + Advance the underlying RNG as-if delta draws have occurred. + + Parameters + ---------- + delta : integer, positive + Number of draws to advance the RNG. Must be less than the + size state variable in the underlying RNG. + + Returns + ------- + self : PCG32 + RNG advanced delta steps + + Notes + ----- + Advancing a RNG updates the underlying RNG state as-if a given + number of calls to the underlying RNG have been made. In general + there is not a one-to-one relationship between the number output + random values from a particular distribution and the number of + draws from the core RNG. This occurs for two reasons: + + * The random values are simulated using a rejection-based method + and so, on average, more than one value from the underlying + RNG is required to generate an single draw. + * The number of bits required to generate a simulated value + differs from the number of bits generated by the underlying + RNG. For example, two 16-bit integer values can be simulated + from a single draw of a 32-bit RNG. + """ + pcg32_advance_state(self.rng_state, delta) return self - def jump(self): - return self.advance(2**32) + def jump(self, np.npy_intp iter=1): + """ + jump(iter=1) + + Jumps the state as-if 2**32 random numbers have been generated + + Parameters + ---------- + iter : integer, positive + Number of times to jump the state of the rng. + + Returns + ------- + self : PCG32 + RNG jumped iter times + """ + return self.advance(iter * 2**32) + + @property + def ctypes(self): + """ + Cytpes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + + if self._ctypes is not None: + return self._ctypes + + import ctypes + + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&pcg32_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&pcg32_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&pcg32_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p(self._brng)) + return self.ctypes + + @property + def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + if self._cffi is not None: + return self._cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') + + ffi = cffi.FFI() + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) + return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : randomgen.generator.RandomGenerator + Random generator used this instance as the core PRNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator \ No newline at end of file diff --git a/_randomgen/randomgen/pcg64.pyx b/_randomgen/randomgen/pcg64.pyx index 7afe1266d9f5..bd3a24440c44 100644 --- a/_randomgen/randomgen/pcg64.pyx +++ b/_randomgen/randomgen/pcg64.pyx @@ -4,6 +4,7 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np +from common import interface from common cimport * from distributions cimport brng_t from randomgen.entropy import random_entropy @@ -61,22 +62,82 @@ cdef double pcg64_double(void* st) nogil: return uint64_to_double(pcg64_next64(st)) cdef class PCG64: - """ - Prototype Basic RNG using pcg64 + u""" + PCG64(seed=None, inc=0) + + Container for the PCG-64 pseudo-random number generator. + + PCG-64 is a 128-bit implementation of O'Neill's permutation congruential + generator ([1]_, [2]_). PCG-64 has a period of :math:`2^{128}` and supports + advancing an arbitrary number of steps as well as :math:`2^{127}` streams. + + ``PCG64`` exposes no user-facing API except ``generator``,``state``, + ``cffi`` and ``ctypes``. Designed for use in a ``RandomGenerator`` object. + + **Compatibility Guarantee** + + ``PCG64`` makes a guarantee that a fixed seed will always produce the same + results. Parameters ---------- - seed : int, array of int - Integer or array of integers between 0 and 2**64 - 1 + seed : {None, long}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**128] or ``None`` (the default). + If `seed` is ``None``, then ``PCG64`` will try to read data + from ``/dev/urandom`` (or the Windows analog) if available. If + unavailable, a 64-bit hash of the time and process ID is used. + inc : {None, int}, optional + Stream to return. + Can be an integer in [0, 2**128] or ``None`` (the default). If `inc` is + ``None``, then 0 is used. Can be used with the same seed to + produce multiple streams using other values of inc. Notes ----- - Exposes no user-facing API except `get_state` and `set_state`. Designed - for use in a `RandomGenerator` object. + Supports the method advance to advance the RNG an arbitrary number of + steps. The state of the PCG-64 RNG is represented by 2 128-bit unsigned + integers. + + See ``PCG32`` for a similar implementation with a smaller period. + + **Parallel Features** + + ``PCG64`` can be used in parallel applications in one of two ways. + The preferable method is to use sub-streams, which are generated by using the + same value of ``seed`` and incrementing the second value, ``inc``. + + >>> from randomgen import RandomGenerator, PCG64 + >>> rg = [RandomGenerator(PCG64(1234, i + 1)) for i in range(10)] + + The alternative method is to call ``advance`` on a single RandomState to + produce non-overlapping sequences. + + >>> rg = [RandomGenerator(PCG64(1234, i + 1)) for i in range(10)] + >>> for i in range(10): + ... rg[i].advance(i * 2**64) + + **State and Seeding** + + The ``PCG64`` state vector consists of 2 unsigned 128-bit values, + which are represented externally as python longs (2.x) or ints (Python 3+). + ``PCG64`` is seeded using a single 128-bit unsigned integer + (Python long/int). In addition, a second 128-bit unsigned integer is used + to set the stream. + + References + ---------- + .. [1] "PCG, A Family of Better Random Number Generators", + http://www.pcg-random.org/ + .. [2] O'Neill, Melissa E. "PCG: A Family of Simple Fast Space-Efficient + Statistically Good Algorithms for Random Number Generation" """ cdef pcg64_state *rng_state cdef brng_t *_brng cdef public object capsule + cdef object _ctypes + cdef object _cffi + cdef object _generator def __init__(self, seed=None, inc=0): self.rng_state = malloc(sizeof(pcg64_state)) @@ -90,6 +151,10 @@ cdef class PCG64: self._brng.next_double = &pcg64_double self._brng.next_raw = &pcg64_uint64 + self._ctypes = None + self._cffi = None + self._generator = None + cdef const char *name = "BasicRNG" self.capsule = PyCapsule_New(self._brng, name, NULL) @@ -115,7 +180,7 @@ cdef class PCG64: def __random_integer(self, bits=64): """ - 64-bit Random Integers from the PRNG + 64-bit Random Integers from the RNG Parameters ---------- @@ -152,7 +217,7 @@ cdef class PCG64: def seed(self, seed=None, inc=0): """ - seed(seed=None, stream=None) + seed(seed=None, inc=0) Seed the generator. @@ -170,7 +235,7 @@ cdef class PCG64: Raises ------ ValueError - If seed values are out of range for the PRNG. + If seed values are out of range for the RNG. """ cdef np.ndarray _seed, _inc @@ -207,7 +272,15 @@ cdef class PCG64: @property def state(self): - """Get or set the PRNG state""" + """ + Get or set the RNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the RNG + """ IF PCG_EMULATED_MATH==1: state = 2 **64 * self.rng_state.pcg_state.state.high state += self.rng_state.pcg_state.state.low @@ -229,7 +302,7 @@ cdef class PCG64: brng = value.get('brng', '') if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' - 'PRNG'.format(self.__class__.__name__)) + 'RNG'.format(self.__class__.__name__)) IF PCG_EMULATED_MATH==1: self.rng_state.pcg_state.state.high = value['state']['state'] // 2 ** 64 self.rng_state.pcg_state.state.low = value['state']['state'] % 2 ** 64 @@ -242,12 +315,153 @@ cdef class PCG64: self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] - def advance(self, step): - cdef np.ndarray delta = np.empty(2,dtype=np.uint64) - delta[0] = step // 2**64 - delta[1] = step % 2**64 - pcg64_advance(self.rng_state, delta.data) + def advance(self, delta): + """ + advance(delta) + + Advance the underlying RNG as-if delta draws have occurred. + + Parameters + ---------- + delta : integer, positive + Number of draws to advance the RNG. Must be less than the + size state variable in the underlying RNG. + + Returns + ------- + self : PCG64 + RNG advanced delta steps + + Notes + ----- + Advancing a RNG updates the underlying RNG state as-if a given + number of calls to the underlying RNG have been made. In general + there is not a one-to-one relationship between the number output + random values from a particular distribution and the number of + draws from the core RNG. This occurs for two reasons: + + * The random values are simulated using a rejection-based method + and so, on average, more than one value from the underlying + RNG is required to generate an single draw. + * The number of bits required to generate a simulated value + differs from the number of bits generated by the underlying + RNG. For example, two 16-bit integer values can be simulated + from a single draw of a 32-bit RNG. + + Advancing the RNG state resets any pre-computed random numbers. + This is required to ensure exact reproducibility. + """ + cdef np.ndarray d = np.empty(2, dtype=np.uint64) + d[0] = delta // 2**64 + d[1] = delta % 2**64 + pcg64_advance(self.rng_state, d.data) + self._reset_state_variables() return self - def jump(self): - return self.advance(2**64) + def jump(self, np.npy_intp iter=1): + """ + jump(iter=1) + + Jumps the state as-if 2**64 random numbers have been generated + + Parameters + ---------- + iter : integer, positive + Number of times to jump the state of the rng. + + Returns + ------- + self : PCG64 + RNG jumped iter times + + Notes + ----- + Jumping the rng state resets any pre-computed random numbers. This is required + to ensure exact reproducibility. + """ + return self.advance(iter * 2**64) + + @property + def ctypes(self): + """ + Cytpes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + + if self._ctypes is not None: + return self._ctypes + + import ctypes + + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&pcg64_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&pcg64_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&pcg64_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p(self._brng)) + return self.ctypes + + @property + def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + if self._cffi is not None: + return self._cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') + + ffi = cffi.FFI() + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) + return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : randomgen.generator.RandomGenerator + Random generator using this instance as the core RNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator \ No newline at end of file diff --git a/_randomgen/randomgen/philox.pyx b/_randomgen/randomgen/philox.pyx index a61f785331b4..397dcb45f864 100644 --- a/_randomgen/randomgen/philox.pyx +++ b/_randomgen/randomgen/philox.pyx @@ -3,6 +3,7 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np +from common import interface from common cimport * from distributions cimport brng_t from randomgen.entropy import random_entropy, seed_by_array @@ -67,6 +68,9 @@ cdef class Philox: cdef philox_state *rng_state cdef brng_t *_brng cdef public object capsule + cdef object _ctypes + cdef object _cffi + cdef object _generator def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(philox_state)) @@ -83,6 +87,10 @@ cdef class Philox: self._brng.next_double = &philox_double self._brng.next_raw = &philox_uint64 + self._ctypes = None + self._cffi = None + self._generator = None + cdef const char *name = 'BasicRNG' self.capsule = PyCapsule_New( self._brng, name, NULL) @@ -254,3 +262,87 @@ cdef class Philox: loc = 0 philox_advance( step_a.data, self.rng_state) return self + + def ctypes(self): + """ + Cytpes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + + if self._ctypes is not None: + return self._ctypes + + import ctypes + + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&philox_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&philox_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&philox_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p(self._brng)) + return self.ctypes + + @property + def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + if self._cffi is not None: + return self._cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') + + ffi = cffi.FFI() + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) + return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : randomgen.generator.RandomGenerator + Random generator used this instance as the core PRNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator \ No newline at end of file diff --git a/_randomgen/randomgen/threefry.pyx b/_randomgen/randomgen/threefry.pyx index ffcc754171f0..70874d94532d 100644 --- a/_randomgen/randomgen/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -3,6 +3,7 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np +from common import interface from common cimport * from distributions cimport brng_t from randomgen.entropy import random_entropy, seed_by_array @@ -63,6 +64,10 @@ cdef class ThreeFry: cdef threefry_state *rng_state cdef brng_t *_brng cdef public object capsule + cdef object _ctypes + cdef object _cffi + cdef object _generator + def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(threefry_state)) @@ -77,6 +82,10 @@ cdef class ThreeFry: self._brng.next_double = &threefry_double self._brng.next_raw = &threefry_uint64 + self._ctypes = None + self._cffi = None + self._generator = None + cdef const char *name = 'BasicRNG' self.capsule = PyCapsule_New(self._brng, name, NULL) @@ -244,3 +253,87 @@ cdef class ThreeFry: loc = 0 threefry_advance(step_a.data, self.rng_state) return self + + def ctypes(self): + """ + Cytpes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + + if self._ctypes is not None: + return self._ctypes + + import ctypes + + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&threefry_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&threefry_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&threefry_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p(self._brng)) + return self.ctypes + + @property + def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + if self._cffi is not None: + return self._cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') + + ffi = cffi.FFI() + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) + return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : randomgen.generator.RandomGenerator + Random generator used this instance as the core PRNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator \ No newline at end of file diff --git a/_randomgen/randomgen/xoroshiro128.pyx b/_randomgen/randomgen/xoroshiro128.pyx index 46058e9ca13b..ae02372898df 100644 --- a/_randomgen/randomgen/xoroshiro128.pyx +++ b/_randomgen/randomgen/xoroshiro128.pyx @@ -211,7 +211,7 @@ cdef class Xoroshiro128: def jump(self, np.npy_intp iter=1): """ - jump(iter = 1) + jump(iter=1) Jumps the state of the random number generator as-if 2**64 random numbers have been generated. diff --git a/_randomgen/randomgen/xorshift1024.pyx b/_randomgen/randomgen/xorshift1024.pyx index 210702358fd8..86fd5d5f1346 100644 --- a/_randomgen/randomgen/xorshift1024.pyx +++ b/_randomgen/randomgen/xorshift1024.pyx @@ -128,6 +128,9 @@ cdef class Xorshift1024: cdef xorshift1024_state *rng_state cdef brng_t *_brng cdef public object capsule + cdef object _ctypes + cdef object _cffi + cdef object _generator def __init__(self, seed=None): self.rng_state = malloc(sizeof(xorshift1024_state)) @@ -140,6 +143,10 @@ cdef class Xorshift1024: self._brng.next_double = &xorshift1024_double self._brng.next_raw = &xorshift1024_uint64 + self._ctypes = None + self._cffi = None + self._generator = None + cdef const char *name = "BasicRNG" self.capsule = PyCapsule_New(self._brng, name, NULL) @@ -234,9 +241,9 @@ cdef class Xorshift1024: self.rng_state.p = 0 self._reset_state_variables() - def jump(self, np.npy_intp iter): + def jump(self, np.npy_intp iter=1): """ - jump(iter = 1) + jump(iter=1) Jumps the state as-if 2**512 random numbers have been generated @@ -263,7 +270,15 @@ cdef class Xorshift1024: @property def state(self): - """Get or set the PRNG state""" + """ + Get or set the PRNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the PRNG + """ s = np.empty(16, dtype=np.uint64) for i in range(16): s[i] = self.rng_state.s[i] From ae2174922c353204698f6b315b919f7f73737b82 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 17:33:59 +0000 Subject: [PATCH 078/279] DOC: Add more docs Documentation is virtually complete --- _randomgen/MANIFEST.in | 4 + _randomgen/README.md | 4 +- _randomgen/doc/source/brng/philox.rst | 41 +++ _randomgen/doc/source/brng/threefry.rst | 41 +++ _randomgen/doc/source/brng/threefry32.rst | 41 +++ _randomgen/doc/source/extending.rst | 165 ++++++++- _randomgen/doc/source/index.rst | 12 +- _randomgen/doc/source/new-or-different.rst | 2 +- _randomgen/doc/source/parallel.rst | 2 +- _randomgen/doc/source/performance.rst | 16 +- _randomgen/randomgen/dsfmt.pyx | 2 +- .../examples/cython/extending.pyx | 0 .../cython/extending_distributions.pyx | 23 ++ .../{ => randomgen}/examples/cython/setup.py | 0 .../examples/numba/extending.py | 54 +-- .../examples/numba/extending_distributions.py | 9 +- _randomgen/randomgen/philox.pyx | 208 ++++++++--- .../randomgen/tests/test_against_numpy.py | 18 +- _randomgen/randomgen/threefry.pyx | 214 ++++++++--- _randomgen/randomgen/threefry32.pyx | 336 +++++++++++++++--- _randomgen/setup.py | 6 +- 21 files changed, 991 insertions(+), 207 deletions(-) create mode 100644 _randomgen/doc/source/brng/philox.rst create mode 100644 _randomgen/doc/source/brng/threefry.rst create mode 100644 _randomgen/doc/source/brng/threefry32.rst rename _randomgen/{ => randomgen}/examples/cython/extending.pyx (100%) rename _randomgen/{ => randomgen}/examples/cython/extending_distributions.pyx (51%) rename _randomgen/{ => randomgen}/examples/cython/setup.py (100%) rename _randomgen/{ => randomgen}/examples/numba/extending.py (52%) rename _randomgen/{ => randomgen}/examples/numba/extending_distributions.py (94%) diff --git a/_randomgen/MANIFEST.in b/_randomgen/MANIFEST.in index 929dfdb24725..c961f9101cd4 100644 --- a/_randomgen/MANIFEST.in +++ b/_randomgen/MANIFEST.in @@ -1,2 +1,6 @@ include versioneer.py include randomgen/_version.py +recursive-include randomgen *.py *.pyx *.px[di] *.h *.in +recursive-include randomgen/src *.c + + diff --git a/_randomgen/README.md b/_randomgen/README.md index 1fd99e875b45..93b0e461b0be 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -1,7 +1,7 @@ # RandomGen -[![Travis Build Status](https://travis-ci.org/bashtage/ng-numpy-randomstate.svg?branch=master)](https://travis-ci.org/bashtage/randomgen) -[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true)](https://ci.appveyor.com/project/bashtage/randomgen/branch/master) +[![Travis Build Status](https://travis-ci.org/bashtage/core-prng.svg?branch=master)](https://travis-ci.org/bashtage/core-prng) +[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true)](https://ci.appveyor.com/project/bashtage/core-prng/branch/master) Random Number Generator using settable Basic RNG interface for future NumPy RandomState evolution. diff --git a/_randomgen/doc/source/brng/philox.rst b/_randomgen/doc/source/brng/philox.rst new file mode 100644 index 000000000000..e12de40531a9 --- /dev/null +++ b/_randomgen/doc/source/brng/philox.rst @@ -0,0 +1,41 @@ +Philox Counter-based RNG +------------------------ + +.. module:: randomgen.philox + +.. currentmodule:: randomgen.philox + +Random generator +================ +.. autoclass:: Philox + +.. autosummary:: + :toctree: generated/ + + ~Philox.seed + ~Philox.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~Philox.advance + ~Philox.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~Philox.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~Philox.cffi + ~Philox.ctypes + + diff --git a/_randomgen/doc/source/brng/threefry.rst b/_randomgen/doc/source/brng/threefry.rst new file mode 100644 index 000000000000..6c1ff5387a5a --- /dev/null +++ b/_randomgen/doc/source/brng/threefry.rst @@ -0,0 +1,41 @@ +ThreeFry Counter-based RNG +-------------------------- + +.. module:: randomgen.threefry + +.. currentmodule:: randomgen.threefry + +Random generator +================ +.. autoclass:: ThreeFry + +.. autosummary:: + :toctree: generated/ + + ~ThreeFry.seed + ~ThreeFry.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~ThreeFry.advance + ~ThreeFry.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~ThreeFry.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~ThreeFry.cffi + ~ThreeFry.ctypes + + diff --git a/_randomgen/doc/source/brng/threefry32.rst b/_randomgen/doc/source/brng/threefry32.rst new file mode 100644 index 000000000000..96576413c535 --- /dev/null +++ b/_randomgen/doc/source/brng/threefry32.rst @@ -0,0 +1,41 @@ +ThreeFry32 Counter-based RNG +---------------------------- + +.. module:: randomgen.threefry32 + +.. currentmodule:: randomgen.threefry32 + +Random generator +================ +.. autoclass:: ThreeFry32 + +.. autosummary:: + :toctree: generated/ + + ~ThreeFry32.seed + ~ThreeFry32.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~ThreeFry32.advance + ~ThreeFry32.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~ThreeFry32.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~ThreeFry32.cffi + ~ThreeFry32.ctypes + + diff --git a/_randomgen/doc/source/extending.rst b/_randomgen/doc/source/extending.rst index 0f4592bca1af..aacfab393289 100644 --- a/_randomgen/doc/source/extending.rst +++ b/_randomgen/doc/source/extending.rst @@ -1,16 +1,163 @@ Extending --------- +The basic RNGs have been designed to be extendable using standard tools for +high-performance Python -- numba and Cython. +The :class:`randomgen.generator.RandomGenerator` object can also be used with +user-provided basic RNGs as long as these export a small set of required +functions. -.. TODO: Complete +Numba +===== +Numba can be used with either CTypes or CFFI. The current iteration of the +basic RNGs all export a small set of functions through both interfaces. -Using a Basic RNG in numba -========================== +This example shows how numba can be used to produce Box-Muller normals using +a pure Python implementation which is then compiled. The random numbers are +provided by ``ctypes.next_double``. -Accessing a distribution in numba -================================= +.. ipython:: python -Using with Cython -================= + from randomgen import Xoroshiro128 + import numpy as np + import numba as nb -Adding a New Basic RNG -====================== + x = Xoroshiro128() + f = x.ctypes.next_double + s = x.ctypes.state + state_addr = x.ctypes.state_address + + def normals(n, state): + out = np.empty(n) + for i in range((n+1)//2): + x1 = 2.0*f(state) - 1.0 + x2 = 2.0*f(state) - 1.0 + r2 = x1*x1 + x2*x2 + while r2 >= 1.0 or r2 == 0.0: + x1 = 2.0*f(state) - 1.0 + x2 = 2.0*f(state) - 1.0 + r2 = x1*x1 + x2*x2 + g = np.sqrt(-2.0*np.log(r2)/r2) + out[2*i] = g*x1 + if 2*i+1 < n: + out[2*i+1] = g*x2 + return out + + # Compile using Numba + print(normals(10, s).var()) + # Warm up + normalsj = nb.jit(normals, nopython=True) + # Must use state address not state with numba + normalsj(1, state_addr) + %timeit normalsj(1000000, state_addr) + print('1,000,000 Box-Muller (numba/Xoroshiro128) randoms') + %timeit np.random.standard_normal(1000000) + print('1,000,000 Box-Muller (NumPy) randoms') + + +Both CTypes and CFFI allow the more complicated distributions to be used +directly in Numba after compiling the file distributions.c into a DLL or so. +An example showing the use of a more complicated distribution is in the +examples folder. + +Cython +====== + +Cython can be used to unpack the ``PyCapsule`` provided by a basic RNG. +This example uses :class:`~randomgen.xoroshiro128.Xoroshiro128` and +``random_gauss_zig``, the Ziggurat-based generator for normals, to fill an +array. The usual caveats for writing high-performance code using Cython -- +removing bounds checks and wrap around, providing array alignment information +-- still apply. + +.. code-block:: cython + + import numpy as np + cimport numpy as np + cimport cython + from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer + from randomgen.common cimport * + from randomgen.distributions import random_gauss_zig + from randomgen.xoroshiro128 import Xoroshiro128 + + + @cython.boundscheck(False) + @cython.wraparound(False) + def normals_zig(Py_ssize_t n): + cdef Py_ssize_t i + cdef brng_t *rng + cdef const char *capsule_name = "BasicRNG" + cdef double[::1] random_values + + x = Xoroshiro128() + capsule = x.capsule + # Optional check that the capsule if from a Basic RNG + if not PyCapsule_IsValid(capsule, capsule_name): + raise ValueError("Invalid pointer to anon_func_state") + # Cast the pointer + rng = PyCapsule_GetPointer(capsule, capsule_name) + random_values = np.empty(n) + for i in range(n): + # Call the function + random_values[i] = random_gauss_zig(rng) + randoms = np.asarray(random_values) + return randoms + + +The basic RNG can also be directly accessed using the members of the basic +RNG structure. + +.. code-block:: cython + + @cython.boundscheck(False) + @cython.wraparound(False) + def uniforms(Py_ssize_t n): + cdef Py_ssize_t i + cdef brng_t *rng + cdef const char *capsule_name = "BasicRNG" + cdef double[::1] random_values + + x = Xoroshiro128() + capsule = x.capsule + # Optional check that the capsule if from a Basic RNG + if not PyCapsule_IsValid(capsule, capsule_name): + raise ValueError("Invalid pointer to anon_func_state") + # Cast the pointer + rng = PyCapsule_GetPointer(capsule, capsule_name) + random_values = np.empty(n) + for i in range(n): + # Call the function + random_values[i] = rng.next_double(rng.state) + randoms = np.asarray(random_values) + return randoms + +These functions along with a minimal setup file are included in the +examples folder. + +New Basic RNGs +============== +:class:`~randomgen.generator.RandomGenerator` can be used with other +user-provided basic RNGs. The simplest way to write a new basic RNG is to +examine the pyx file of one of the existing basic RNGs. The key structure +that must be provided is the ``capsule`` which contains a ``PyCapsule`` to a +struct pointer of type ``brng_t``, + +.. code-block:: c + + typedef struct brng { + void *state; + uint64_t (*next_uint64)(void *st); + uint32_t (*next_uint32)(void *st); + double (*next_double)(void *st); + uint64_t (*next_raw)(void *st); + } brng_t; + +which provides 5 pointers. The first is an opaque pointer to the data structure +used by the basic RNG. The next three are function pointers which return the +next 64- and 32-bit unsigned integers, the next random double and the next +raw value. This final function is used for testing and so can be set to +the next 64-bit unsigned integer function if not needed. Functions inside +:class:`~randomgen.generator.RandomGenerator` use this structure as in + +.. code-block:: c + + brng_state->next_uint64(brng_state->state) diff --git a/_randomgen/doc/source/index.rst b/_randomgen/doc/source/index.rst index 55e0b206dd31..b89679a29e62 100644 --- a/_randomgen/doc/source/index.rst +++ b/_randomgen/doc/source/index.rst @@ -7,7 +7,7 @@ generator be be changed. Introduction ------------ RandomGen takes a different approach to producing random numbers from the -:class:`~numpy.random.RandomState` object used in NumPy. Random number +:class:`numpy.random.RandomState` object used in NumPy. Random number generation is separated into two components, a basic RNG and a random generator. @@ -68,7 +68,7 @@ What's New or Different select distributions * Simulate from the complex normal distribution (:meth:`~randomgen.generator.RandomGenerator.complex_normal`) -* :func:`randomgen.entropy.random_entropy` provides access to the system +* :func:`~randomgen.entropy.random_entropy` provides access to the system source of randomness that is used in cryptographic applications (e.g., ``/dev/urandom`` on Unix). * All basic random generators functions to produce doubles, uint64s and @@ -97,7 +97,7 @@ generators, 'in addition' to the standard PRNG in NumPy. The included PRNGs are * MT19937 - The standard NumPy generator. Produces identical results to NumPy using the same seed/state. Adds a jump function that advances the generator - as-if 2**128 draws have been made (:meth:`randomstate.prng.mt19937.jump`). + as-if 2**128 draws have been made (:meth:`~randomgen.mt19937.MT19937.jump`). See `NumPy's documentation`_. * dSFMT - SSE2 enabled versions of the MT19937 generator. Theoretically the same, but with a different state and so it is not possible to produce a @@ -106,18 +106,18 @@ generators, 'in addition' to the standard PRNG in NumPy. The included PRNGs are * XoroShiro128+ - Improved version of XorShift128+ with better performance and statistical quality. Like the XorShift generators, it can be jumped to produce multiple streams in parallel applications. See - :meth:`randomgen.xoroshiro128.Xoroshiro128.jump` for details. + :meth:`~randomgen.xoroshiro128.Xoroshiro128.jump` for details. More information about this PRNG is available at the `xorshift and xoroshiro authors' page`_. * XorShift1024*φ - Vast fast generator based on the XSadd generator. Supports ``jump`` and so can be used in parallel applications. See the documentation for - :meth:`randomgen.xorshift1024.Xorshift1024.jump` for details. More information + :meth:`~randomgen.xorshift1024.Xorshift1024.jump` for details. More information about these PRNGs is available at the `xorshift and xoroshiro authors' page`_. * PCG-64 - Fast generator that support many parallel streams and can be advanced by an arbitrary amount. See the documentation for - :meth:`randomgen.pcg64.PCG64.advance`. PCG-64 has a period of + :meth:`~randomgen.pcg64.PCG64.advance`. PCG-64 has a period of :math:`2^{128}`. See the `PCG author's page`_ for more details about this class of PRNG. * ThreeFry and Philox - counter-based generators capable of being advanced an diff --git a/_randomgen/doc/source/new-or-different.rst b/_randomgen/doc/source/new-or-different.rst index d65463065673..7fb70ed1ab66 100644 --- a/_randomgen/doc/source/new-or-different.rst +++ b/_randomgen/doc/source/new-or-different.rst @@ -11,7 +11,7 @@ What's New or Different normal such as the gamma or student's t. -* :func:`randomgen.entropy.random_entropy` provides access to the system +* :func:`~randomgen.entropy.random_entropy` provides access to the system source of randomness that is used in cryptographic applications (e.g., ``/dev/urandom`` on Unix). * Simulate from the complex normal distribution diff --git a/_randomgen/doc/source/parallel.rst b/_randomgen/doc/source/parallel.rst index ee6990f8bd85..df6f58d75a9b 100644 --- a/_randomgen/doc/source/parallel.rst +++ b/_randomgen/doc/source/parallel.rst @@ -68,7 +68,7 @@ are listed below. | PCG64 | :math:`2^{128}` | :math:`2^{64}` | 64 | +-----------------+-------------------------+-------------------------+-------------------------+ | Philox | :math:`2^{256}` | :math:`2^{128}` | 64 | -+-----------------+----------------- --------+-------------------------+-------------------------+ ++-----------------+-------------------------+-------------------------+-------------------------+ | ThreeFry | :math:`2^{256}` | :math:`2^{128}` | 64 | +-----------------+-------------------------+-------------------------+-------------------------+ | Xoroshiro128 | :math:`2^{128}` | :math:`2^{64}` | 64 | diff --git a/_randomgen/doc/source/performance.rst b/_randomgen/doc/source/performance.rst index 263da09dd9ab..2dfb32101c5e 100644 --- a/_randomgen/doc/source/performance.rst +++ b/_randomgen/doc/source/performance.rst @@ -1,7 +1,7 @@ Performance ----------- -.. py:module:: randomstate +.. py:module:: randomgen Recommendation ************** @@ -17,10 +17,10 @@ the best choices. Timings ******* -The timings below are ns/random value. The fastest generator is the -raw generator (`random_raw`) which does not make any transformation -to the underlying random value. `xoroshiro128+` is the fastest, followed by -`xorshift1024*` and the two SIMD aware MT generators. The original MT19937 +The timings below are the time in ms to produce 1,000,000 random values from a +specific distribution. :class:`~randomgen.xoroshiro128.Xoroshiro128` is the +fastest, followed by :class:`~randomgen.xorshift1024.Xorshift1024` and +:class:`~randomgen.pcg64.PCG64`. The original :class:`~randomgen.mt19937.MT19937` generator is much slower since it requires 2 32-bit values to equal the output of the faster generators. @@ -28,9 +28,11 @@ Integer performance has a similar ordering although `dSFMT` is slower since it generates 53-bit floating point values rather than integer values. On the other hand, it is very fast for uniforms, although slower than `xoroshiro128+`. -The patterm is similar for other, more complex generators. The normal +The pattern is similar for other, more complex generators. The normal performance of NumPy's MT19937 is much lower than the other since it -uses the Box-Muller transformation rather than the Ziggurat generator. +uses the Box-Muller transformation rather than the Ziggurat generator. The +performance gap for Exponentials is also large due to the cost of computing +the log function to invert the CDF. .. csv-table:: :header: ,Xoroshiro128,Xorshift1024,PCG64,DSFMT,MT19937,Philox,ThreeFry,NumPy diff --git a/_randomgen/randomgen/dsfmt.pyx b/_randomgen/randomgen/dsfmt.pyx index 778fd34f7074..cec90994346c 100644 --- a/_randomgen/randomgen/dsfmt.pyx +++ b/_randomgen/randomgen/dsfmt.pyx @@ -131,7 +131,7 @@ cdef class DSFMT: ---------- .. [1] Mutsuo Saito and Makoto Matsumoto, "SIMD-oriented Fast Mersenne Twister: a 128-bit Pseudorandom Number Generator." Monte Carlo - and Quasi-Monte Carlo Methods 2006, Springer, pp. 607 -- 622, 2008. + and Quasi-Monte Carlo Methods 2006, Springer, pp. 607--622, 2008. .. [2] Hiroshi Haramoto, Makoto Matsumoto, and Pierre L\'Ecuyer, "A Fast Jump Ahead Algorithm for Linear Recurrences in a Polynomial Space", Sequences and Their Applications - SETA, 290--298, 2008. diff --git a/_randomgen/examples/cython/extending.pyx b/_randomgen/randomgen/examples/cython/extending.pyx similarity index 100% rename from _randomgen/examples/cython/extending.pyx rename to _randomgen/randomgen/examples/cython/extending.pyx diff --git a/_randomgen/examples/cython/extending_distributions.pyx b/_randomgen/randomgen/examples/cython/extending_distributions.pyx similarity index 51% rename from _randomgen/examples/cython/extending_distributions.pyx rename to _randomgen/randomgen/examples/cython/extending_distributions.pyx index a5fea174aa49..630d952bf75e 100644 --- a/_randomgen/examples/cython/extending_distributions.pyx +++ b/_randomgen/randomgen/examples/cython/extending_distributions.pyx @@ -3,6 +3,7 @@ cimport numpy as np cimport cython from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from randomgen.common cimport * +from randomgen.distributions cimport random_gauss_zig from randomgen.xoroshiro128 import Xoroshiro128 @cython.boundscheck(False) @@ -23,3 +24,25 @@ def normals_zig(Py_ssize_t n): random_values[i] = random_gauss_zig(rng) randoms = np.asarray(random_values) return randoms + +@cython.boundscheck(False) +@cython.wraparound(False) +def uniforms(Py_ssize_t n): + cdef Py_ssize_t i + cdef brng_t *rng + cdef const char *capsule_name = "BasicRNG" + cdef double[::1] random_values + + x = Xoroshiro128() + capsule = x.capsule + # Optional check that the capsule if from a Basic RNG + if not PyCapsule_IsValid(capsule, capsule_name): + raise ValueError("Invalid pointer to anon_func_state") + # Cast the pointer + rng = PyCapsule_GetPointer(capsule, capsule_name) + random_values = np.empty(n) + for i in range(n): + # Call the function + random_values[i] = rng.next_double(rng.state) + randoms = np.asarray(random_values) + return randoms \ No newline at end of file diff --git a/_randomgen/examples/cython/setup.py b/_randomgen/randomgen/examples/cython/setup.py similarity index 100% rename from _randomgen/examples/cython/setup.py rename to _randomgen/randomgen/examples/cython/setup.py diff --git a/_randomgen/examples/numba/extending.py b/_randomgen/randomgen/examples/numba/extending.py similarity index 52% rename from _randomgen/examples/numba/extending.py rename to _randomgen/randomgen/examples/numba/extending.py index 198c39a29297..09e07a437674 100644 --- a/_randomgen/examples/numba/extending.py +++ b/_randomgen/randomgen/examples/numba/extending.py @@ -1,7 +1,8 @@ -from randomgen import Xoroshiro128 import numpy as np import numba as nb +from randomgen import Xoroshiro128 + x = Xoroshiro128() f = x.ctypes.next_uint32 s = x.ctypes.state @@ -35,7 +36,6 @@ def bounded_uints(lb, ub, n, state): bounded_uints(323, 2394691, 10000000, s.value) - g = x.cffi.next_double cffi_state = x.cffi.state state_addr = x.cffi.state_address @@ -43,33 +43,35 @@ def bounded_uints(lb, ub, n, state): def normals(n, state): out = np.empty(n) - for i in range(n//2): - x1 = 2.0*g(state) - 1.0 - x2 = 2.0*g(state) - 1.0 - r2 = x1*x1 + x2*x2 - while r2 >= 1.0 or r2 == 0.0: - x1 = 2.0*g(state) - 1.0 - x2 = 2.0*g(state) - 1.0 - r2 = x1*x1 + x2*x2 - f = np.sqrt(-2.0*np.log(r2)/r2) - out[2*i] = f*x1 - out[2*i+1] = f*x2 - - if n % 2 == 1: - x1 = 2.0*g(state) - 1.0 - x2 = 2.0*g(state) - 1.0 - r2 = x1*x1 + x2*x2 + for i in range((n + 1) // 2): + x1 = 2.0 * g(state) - 1.0 + x2 = 2.0 * g(state) - 1.0 + r2 = x1 * x1 + x2 * x2 while r2 >= 1.0 or r2 == 0.0: - x1 = 2.0*g(state) - 1.0 - x2 = 2.0*g(state) - 1.0 - r2 = x1*x1 + x2*x2 - f = np.sqrt(-2.0*np.log(r2)/r2) - out[n] = f*x1 + x1 = 2.0 * g(state) - 1.0 + x2 = 2.0 * g(state) - 1.0 + r2 = x1 * x1 + x2 * x2 + f = np.sqrt(-2.0 * np.log(r2) / r2) + out[2 * i] = f * x1 + if 2 * i + 1 < n: + out[2 * i + 1] = f * x2 return out - print(normals(10, cffi_state).var()) - +# Warm up normalsj = nb.jit(normals, nopython=True) +normalsj(1, state_addr) +import datetime as dt + +start = dt.datetime.now() +normalsj(1000000, state_addr) +ms = 1000 * (dt.datetime.now() - start).total_seconds() +print('1,000,000 Box-Muller (numba/Xoroshiro128) randoms in ' + '{ms:0.1f}ms'.format(ms=ms)) + +import numpy as np -print(normalsj(10000000, state_addr).var()) +start = dt.datetime.now() +np.random.standard_normal(1000000) +ms = 1000 * (dt.datetime.now() - start).total_seconds() +print('1,000,000 Box-Muller (NumPy) randoms in {ms:0.1f}ms'.format(ms=ms)) diff --git a/_randomgen/examples/numba/extending_distributions.py b/_randomgen/randomgen/examples/numba/extending_distributions.py similarity index 94% rename from _randomgen/examples/numba/extending_distributions.py rename to _randomgen/randomgen/examples/numba/extending_distributions.py index 07cb074a3177..47f811c06d54 100644 --- a/_randomgen/examples/numba/extending_distributions.py +++ b/_randomgen/randomgen/examples/numba/extending_distributions.py @@ -4,20 +4,22 @@ export PYTHON_INCLUDE=#path to Python's include folder, usually ${PYTHON_HOME}/include/python${PYTHON_VERSION}m export NUMPY_INCLUDE=#path to numpy's include folder, usually ${PYTHON_HOME}/lib/python${PYTHON_VERSION}/site-packages/numpy/core/include gcc -shared -o libdistributions.so -fPIC distributions.c -I${NUMPY_INCLUDE} -I${PYTHON_INCLUDE} -mv libdistributions.so ../../../examples/numba/ +mv libdistributions.so ../../examples/numba/ On Windows rem PYTHON_HOME is setup dependent, this is an example set PYTHON_HOME=c:\Anaconda cl.exe /LD .\distributions.c -DDLL_EXPORT -I%PYTHON_HOME%\lib\site-packages\numpy\core\include -I%PYTHON_HOME%\include %PYTHON_HOME%\libs\python36.lib -move distributions.dll ../../../examples/numba/ +move distributions.dll ../../examples/numba/ """ import os + +import numba as nb import numpy as np from cffi import FFI + from randomgen import Xoroshiro128 -import numba as nb ffi = FFI() if os.path.exists('./distributions.dll'): @@ -46,7 +48,6 @@ def normals(n, brng): normalsj = nb.jit(normals, nopython=True) - # Numba requires a memory address for void * # Can also get address from x.ctypes.brng.value brng_address = int(ffi.cast('uintptr_t', brng)) diff --git a/_randomgen/randomgen/philox.pyx b/_randomgen/randomgen/philox.pyx index 397dcb45f864..75213ef5aa58 100644 --- a/_randomgen/randomgen/philox.pyx +++ b/_randomgen/randomgen/philox.pyx @@ -53,17 +53,108 @@ cdef double philox_double(void*st) nogil: cdef class Philox: """ - Prototype Basic RNG using philox + Philox(seed=None, counter=None, key=None) + + Container for the Philox (4x64) pseudo-random number generator. Parameters ---------- - seed : int, array of int - Integer or array of integers between 0 and 2**64 - 1 + seed : {None, int, array_like}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**64-1], array of integers in + [0, 2**64-1] or ``None`` (the default). If `seed` is ``None``, + data will be read from ``/dev/urandom`` (or the Windows analog) + if available. If unavailable, a hash of the time and process ID is + used. + counter : {None, int, array_like}, optional + Counter to use in the Philox state. Can be either + a Python int (long in 2.x) in [0, 2**256) or a 4-element uint64 array. + If not provided, the RNG is initialized at 0. + key : {None, int, array_like}, optional + Key to use in the Philox state. Unlike seed, which is run through + another RNG before use, the value in key is directly set. Can be either + a Python int (long in 2.x) in [0, 2**128) or a 2-element uint64 array. + key and seed cannot both be used. Notes ----- - Exposes no user-facing API except `state`. Designed for use in - a `RandomGenerator` object. + Philox is a 64-bit PRNG that uses a counter-based design based on weaker + (and faster) versions of cryptographic functions [1]_. Instances using + different values of the key produce independent sequences. Philox has a + period of :math:`2^{256} - 1` and supports arbitrary advancing and jumping + the sequence in increments of :math:`2^{128}`. These features allow + multiple non-overlapping sequences to be generated. + + ``Philox`` exposes no user-facing API except ``generator``, + ``state``, ``cffi`` and ``ctypes``. Designed for use in a + ``RandomGenerator`` object. + + **Compatibility Guarantee** + + ``Philox`` guarantees that a fixed seed will always produce the + same results. + + See ``Philox`` for a closely related PRNG implementation. + + **Parallel Features** + + ``Philox`` can be used in parallel applications by + calling the method ``jump`` which advances the state as-if + :math:`2^{128}` random numbers have been generated. Alternatively, + ``advance`` can be used to advance the counter for an abritrary number of + positive steps in [0, 2**256). When using ``jump``, all generators should + be initialized with the same seed to ensure that the segments come from + the same sequence. Alternatively, ``Philox`` can be used + in parallel applications by using a sequence of distinct keys where each + instance uses different key. + + >>> from randomgen import RandomGenerator, Philox + >>> rg = [RandomGenerator(Philox(1234)) for _ in range(10)] + # Advance rs[i] by i jumps + >>> for i in range(10): + ... rg[i].jump(i) + + Using distinct keys produces independent streams + + >>> key = 2**196 + 2**132 + 2**65 + 2**33 + 2**17 + 2**9 + >>> rg = [RandomGenerator(Philox(key=key+i)) for i in range(10)] + + **State and Seeding** + + The ``Philox`` state vector consists of a 256-bit counter encoded as a + 4-element uint64 array and a 128-bit key encoded as a 2-element uint64 + array. The counter is incremented by 1 for every 4 64-bit randoms + produced. The key determines the sequence produced. Using different + keys produces independent sequences. + + ``Philox`` is seeded using either a single 64-bit unsigned integer + or a vector of 64-bit unsigned integers. In either case, the input seed is + used as an input (or inputs) for another simple random number generator, + Splitmix64, and the output of this PRNG function is used as the initial state. + Using a single 64-bit value for the seed can only initialize a small range of + the possible initial state values. When using an array, the SplitMix64 state + for producing the ith component of the initial state is XORd with the ith + value of the seed array until the seed array is exhausted. When using an array + the initial state for the SplitMix64 state is 0 so that using a single element + array and using the same value as a scalar will produce the same initial state. + + Examples + -------- + >>> from randomgen import RandomGenerator, Philox + >>> rg = RandomGenerator(Philox(1234)) + >>> rg.standard_normal() + + Identical method using only Philox + + >>> rg = Philox(1234).generator + >>> rg.standard_normal() + + References + ---------- + .. [1] John K. Salmon, Mark A. Moraes, Ron O. Dror, and David E. Shaw, + "Parallel Random Numbers: As Easy as 1, 2, 3," Proceedings of + the International Conference for High Performance Computing, + Networking, Storage and Analysis (SC11), New York, NY: ACM, 2011. """ cdef philox_state *rng_state cdef brng_t *_brng @@ -119,31 +210,6 @@ cdef class Philox: for i in range(PHILOX_BUFFER_SIZE): self.rng_state.buffer[i] = 0 - def __random_integer(self, bits=64): - """ - 64-bit Random Integers from the PRNG - - Parameters - ---------- - bits : {32, 64} - Number of random bits to return - - Returns - ------- - rv : int - Next random value - - Notes - ----- - Testing only - """ - if bits == 64: - return self._brng.next_uint64(self._brng.state) - elif bits == 32: - return self._brng.next_uint32(self._brng.state) - else: - raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i if method==u'uint64': @@ -213,7 +279,15 @@ cdef class Philox: @property def state(self): - """Get or set the PRNG state""" + """ + Get or set the PRNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the PRNG + """ ctr = np.empty(4, dtype=np.uint64) key = np.empty(2, dtype=np.uint64) buffer = np.empty(PHILOX_BUFFER_SIZE, dtype=np.uint64) @@ -251,16 +325,70 @@ cdef class Philox: self.rng_state.uinteger = value['uinteger'] self.rng_state.buffer_pos = value['buffer_pos'] - def jump(self): - """Jump the state as-if 2**128 draws have been made""" - return self.advance(2**128) + def jump(self, np.npy_intp iter): + """ + jump(iter=1) - def advance(self, step): - """Advance the state as-if a specific number of draws have been made""" - cdef np.ndarray step_a - step_a = int_to_array(step, 'step', 256, 64) - loc = 0 - philox_advance( step_a.data, self.rng_state) + Jumps the state of the random number generator as-if 2**128 random + numbers have been generated. + + Parameters + ---------- + iter : integer, positive + Number of times to jump the state of the rng. + + Returns + ------- + self : Philox + PRNG jumped iter times + + Notes + ----- + Jumping the rng state resets any pre-computed random numbers. This is + required to ensure exact reproducibility. + """ + return self.advance(iter * 2 ** 128) + + def advance(self, delta): + """ + advance(delta) + + Advance the underlying RNG as-if delta draws have occurred. + + Parameters + ---------- + delta : integer, positive + Number of draws to advance the RNG. Must be less than the + size state variable in the underlying RNG. + + Returns + ------- + self : Philox + RNG advanced delta steps + + Notes + ----- + Advancing a RNG updates the underlying RNG state as-if a given + number of calls to the underlying RNG have been made. In general + there is not a one-to-one relationship between the number output + random values from a particular distribution and the number of + draws from the core RNG. This occurs for two reasons: + + * The random values are simulated using a rejection-based method + and so, on average, more than one value from the underlying + RNG is required to generate an single draw. + * The number of bits required to generate a simulated value + differs from the number of bits generated by the underlying + RNG. For example, two 16-bit integer values can be simulated + from a single draw of a 32-bit RNG. + + Advancing the RNG state resets any pre-computed random numbers. + This is required to ensure exact reproducibility. + """ + cdef np.ndarray delta_a + delta_a = int_to_array(delta, 'step', 256, 64) + philox_advance( delta_a.data, self.rng_state) + self._reset_state_variables() return self def ctypes(self): diff --git a/_randomgen/randomgen/tests/test_against_numpy.py b/_randomgen/randomgen/tests/test_against_numpy.py index 1bffe3f78fb3..c4673c2d2306 100644 --- a/_randomgen/randomgen/tests/test_against_numpy.py +++ b/_randomgen/randomgen/tests/test_against_numpy.py @@ -4,7 +4,7 @@ import pytest from randomgen import RandomGenerator, MT19937 - +import randomgen def compare_0_input(f1, f2): inputs = [(tuple([]), {}), (tuple([]), {'size': 10}), @@ -532,11 +532,11 @@ def test_dir(self): nprs_d.difference_update(excluded) assert (len(nprs_d.difference(rs_d)) == 0) - # npmod = dir(numpy.random) - # mod = dir(randomstate) - # known_exlcuded = ['__all__', 'Tester', 'info', 'bench', - # '__RandomState_ctor', 'mtrand', 'test', - # '__warningregistry__', '_numpy_tester'] - # mod += known_exlcuded - # diff = set(npmod).difference(mod) - # assert_equal(len(diff), 0) + npmod = dir(numpy.random) + mod = dir(randomgen) + known_exlcuded = ['__all__', 'Tester', 'info', 'bench', + '__RandomState_ctor', 'mtrand', 'test', + '__warningregistry__', '_numpy_tester'] + mod += known_exlcuded + diff = set(npmod).difference(mod) + assert_equal(len(diff), 0) diff --git a/_randomgen/randomgen/threefry.pyx b/_randomgen/randomgen/threefry.pyx index 70874d94532d..47dde07e0bd2 100644 --- a/_randomgen/randomgen/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -49,17 +49,108 @@ cdef double threefry_double(void* st) nogil: cdef class ThreeFry: """ - Prototype Basic RNG using threefry + ThreeFry(seed=None, counter=None, key=None) + + Container for the ThreeFry (4x64) pseudo-random number generator. Parameters ---------- - seed : int, array of int - Integer or array of integers between 0 and 2**64 - 1 + seed : {None, int, array_like}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**64-1], array of integers in + [0, 2**64-1] or ``None`` (the default). If `seed` is ``None``, + data will be read from ``/dev/urandom`` (or the Windows analog) + if available. If unavailable, a hash of the time and process ID is + used. + counter : {None, int, array_like}, optional + Counter to use in the ThreeFry state. Can be either + a Python int (long in 2.x) in [0, 2**256) or a 4-element uint64 array. + If not provided, the RNG is initialized at 0. + key : {None, int, array_like}, optional + Key to use in the ThreeFry state. Unlike seed, which is run through + another RNG before use, the value in key is directly set. Can be either + a Python int (long in 2.x) in [0, 2**256) or a 4-element uint64 array. + key and seed cannot both be used. Notes ----- - Exposes no user-facing API except `state`. Designed for use in - a `RandomGenerator` object. + ThreeFry is a 64-bit PRNG that uses a counter-based design based on weaker + (and faster) versions of cryptographic functions [1]_. Instances using + different values of the key produce independent sequences. ThreeFry has a + period of :math:`2^{256} - 1` and supports arbitrary advancing and jumping + the sequence in increments of :math:`2^{128}`. These features allow + multiple non-overlapping sequences to be generated. + + ``ThreeFry`` exposes no user-facing API except ``generator``, + ``state``, ``cffi`` and ``ctypes``. Designed for use in a + ``RandomGenerator`` object. + + **Compatibility Guarantee** + + ``ThreeFry`` guarantees that a fixed seed will always produce the + same results. + + See ``Philox`` for a closely related PRNG implementation. + + **Parallel Features** + + ``ThreeFry`` can be used in parallel applications by + calling the method ``jump`` which advances the state as-if + :math:`2^{128}` random numbers have been generated. Alternatively, + ``advance`` can be used to advance the counter for an abritrary number of + positive steps in [0, 2**256). When using ``jump``, all generators should + be initialized with the same seed to ensure that the segments come from + the same sequence. Alternatively, ``ThreeFry`` can be used + in parallel applications by using a sequence of distinct keys where each + instance uses different key. + + >>> from randomgen import RandomGenerator, ThreeFry + >>> rg = [RandomGenerator(ThreeFry(1234)) for _ in range(10)] + # Advance rs[i] by i jumps + >>> for i in range(10): + ... rg[i].jump(i) + + Using distinct keys produces independent streams + + >>> key = 2**196 + 2**132 + 2**65 + 2**33 + 2**17 + 2**9 + >>> rg = [RandomGenerator(ThreeFry(key=key+i)) for i in range(10)] + + **State and Seeding** + + The ``ThreeFry`` state vector consists of a 2 256-bit values encoded as + 4-element uint64 arrays. One is a counter which is incremented by 1 for + every 4 64-bit randoms produced. The second is a key which determined + the sequence produced. Using different keys produces independent + sequences. + + ``ThreeFry`` is seeded using either a single 64-bit unsigned integer + or a vector of 64-bit unsigned integers. In either case, the input seed is + used as an input (or inputs) for another simple random number generator, + Splitmix64, and the output of this PRNG function is used as the initial state. + Using a single 64-bit value for the seed can only initialize a small range of + the possible initial state values. When using an array, the SplitMix64 state + for producing the ith component of the initial state is XORd with the ith + value of the seed array until the seed array is exhausted. When using an array + the initial state for the SplitMix64 state is 0 so that using a single element + array and using the same value as a scalar will produce the same initial state. + + Examples + -------- + >>> from randomgen import RandomGenerator, ThreeFry + >>> rg = RandomGenerator(ThreeFry(1234)) + >>> rg.standard_normal() + + Identical method using only ThreeFry + + >>> rg = ThreeFry(1234).generator + >>> rg.standard_normal() + + References + ---------- + .. [1] John K. Salmon, Mark A. Moraes, Ron O. Dror, and David E. Shaw, + "Parallel Random Numbers: As Easy as 1, 2, 3," Proceedings of + the International Conference for High Performance Computing, + Networking, Storage and Analysis (SC11), New York, NY: ACM, 2011. """ cdef threefry_state *rng_state cdef brng_t *_brng @@ -114,31 +205,6 @@ cdef class ThreeFry: for i in range(THREEFRY_BUFFER_SIZE): self.rng_state.buffer[i] = 0 - def __random_integer(self, bits=64): - """ - 64-bit Random Integers from the PRNG - - Parameters - ---------- - bits : {32, 64} - Number of random bits to return - - Returns - ------- - rv : int - Next random value - - Notes - ----- - Testing only - """ - if bits == 64: - return self._brng.next_uint64(self._brng.state) - elif bits == 32: - return self._brng.next_uint32(self._brng.state) - else: - raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i if method==u'uint64': @@ -164,12 +230,13 @@ cdef class ThreeFry: ---------- seed : int, optional Seed for ``RandomState``. - counter : {int array}, optional + counter : {None, int array}, optional Positive integer less than 2**256 containing the counter position or a 4 element array of uint64 containing the counter - key : {int, array}, options + key : {None, int, array}, optional Positive integer less than 2**256 containing the key - or a 4 element array of uint64 containing the key + or a 4 element array of uint64 containing the key. key and + seed cannot be simultaneously used. Raises ------ @@ -208,7 +275,15 @@ cdef class ThreeFry: @property def state(self): - """Get or set the PRNG state""" + """ + Get or set the PRNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the PRNG + """ ctr = np.empty(4, dtype=np.uint64) key = np.empty(4, dtype=np.uint64) buffer = np.empty(THREEFRY_BUFFER_SIZE, dtype=np.uint64) @@ -242,16 +317,71 @@ cdef class ThreeFry: self.rng_state.uinteger = value['uinteger'] self.rng_state.buffer_pos = value['buffer_pos'] - def jump(self): - """Jump the state as-if 2**128 draws have been made""" - return self.advance(2**128) + def jump(self, np.npy_intp iter): + """ + jump(iter=1) - def advance(self, step): - """Advance the state as-if a specific number of draws have been made""" - cdef np.ndarray step_a - step_a = int_to_array(step, 'step', 256, 64) + Jumps the state of the random number generator as-if 2**128 random + numbers have been generated. + + Parameters + ---------- + iter : integer, positive + Number of times to jump the state of the rng. + + Returns + ------- + self : ThreeFry + PRNG jumped iter times + + Notes + ----- + Jumping the rng state resets any pre-computed random numbers. This is + required to ensure exact reproducibility. + """ + return self.advance(iter * 2**128) + + def advance(self, delta): + """ + advance(delta) + + Advance the underlying RNG as-if delta draws have occurred. + + Parameters + ---------- + delta : integer, positive + Number of draws to advance the RNG. Must be less than the + size state variable in the underlying RNG. + + Returns + ------- + self : ThreeFry + RNG advanced delta steps + + Notes + ----- + Advancing a RNG updates the underlying RNG state as-if a given + number of calls to the underlying RNG have been made. In general + there is not a one-to-one relationship between the number output + random values from a particular distribution and the number of + draws from the core RNG. This occurs for two reasons: + + * The random values are simulated using a rejection-based method + and so, on average, more than one value from the underlying + RNG is required to generate an single draw. + * The number of bits required to generate a simulated value + differs from the number of bits generated by the underlying + RNG. For example, two 16-bit integer values can be simulated + from a single draw of a 32-bit RNG. + + Advancing the RNG state resets any pre-computed random numbers. + This is required to ensure exact reproducibility. + """ + cdef np.ndarray delta_a + delta_a = int_to_array(delta, 'step', 256, 64) loc = 0 - threefry_advance(step_a.data, self.rng_state) + threefry_advance(delta_a.data, self.rng_state) + self._reset_state_variables() return self def ctypes(self): diff --git a/_randomgen/randomgen/threefry32.pyx b/_randomgen/randomgen/threefry32.pyx index 86f9c4f656c3..70210910c6d0 100644 --- a/_randomgen/randomgen/threefry32.pyx +++ b/_randomgen/randomgen/threefry32.pyx @@ -1,12 +1,12 @@ -from libc.stdlib cimport malloc, free -from cpython.pycapsule cimport PyCapsule_New - import numpy as np +from cpython.pycapsule cimport PyCapsule_New +from distributions cimport brng_t +from libc.stdlib cimport malloc, free +import randomgen.pickle from common cimport * -from distributions cimport brng_t +from common import interface from randomgen.entropy import random_entropy, seed_by_array -import randomgen.pickle np.import_array() @@ -51,37 +51,136 @@ cdef uint64_t threefry32_raw(void *st) nogil: cdef class ThreeFry32: """ - Prototype Basic RNG using threefry + ThreeFry32(seed=None, counter=None, key=None) + + Container for the ThreeFry (4x32) pseudo-random number generator. Parameters ---------- - seed : int, array of int - Integer or array of integers between 0 and 2**64 - 1 + seed : {None, int, array_like}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**64-1], array of integers in + [0, 2**64-1] or ``None`` (the default). If `seed` is ``None``, + data will be read from ``/dev/urandom`` (or the Windows analog) + if available. If unavailable, a hash of the time and process ID is + used. + counter : {None, int, array_like}, optional + Counter to use in the ThreeFry32 state. Can be either + a Python int (long in 2.x) in [0, 2**128) or a 4-element uint32 array. + If not provided, the RNG is initialized at 0. + key : {None, int, array_like}, optional + Key to use in the ThreeFry32 state. Unlike seed, which is run through + another RNG before use, the value in key is directly set. Can be either + a Python int (long in 2.x) in [0, 2**128) or a 4-element uint32 array. + key and seed cannot both be used. Notes ----- - Exposes no user-facing API except `state`. Designed for use in - a `RandomGenerator` object. + ThreeFry32 is a 32-bit PRNG that uses a counter-based design based on + weaker (and faster) versions of cryptographic functions [1]_. Instances + using different values of the key produce independent sequences. ThreeFry32 + has a period of :math:`2^{128} - 1` and supports arbitrary advancing and + jumping the sequence in increments of :math:`2^{64}`. These features allow + multiple non-overlapping sequences to be generated. + + ``ThreeFry32`` exposes no user-facing API except ``generator``, + ``state``, ``cffi`` and ``ctypes``. Designed for use in a + ``RandomGenerator`` object. + + **Compatibility Guarantee** + + ``ThreeFry32`` guarantees that a fixed seed will always produce the + same results. + + See ``TheeFry`` and ``Philox`` closely related PRNG implementations. + + **Parallel Features** + + ``ThreeFry32`` can be used in parallel applications by + calling the method ``jump`` which advances the state as-if + :math:`2^{64}` random numbers have been generated. Alternatively, + ``advance`` can be used to advance the counter for an arbitrary number of + positive steps in [0, 2**128). When using ``jump``, all generators should + be initialized with the same seed to ensure that the segments come from + the same sequence. Alternatively, ``ThreeFry32`` can be used + in parallel applications by using a sequence of distinct keys where each + instance uses different key. + + >>> from randomgen import RandomGenerator, ThreeFry32 + >>> rg = [RandomGenerator(ThreeFry32(1234)) for _ in range(10)] + # Advance rs[i] by i jumps + >>> for i in range(10): + ... rg[i].jump(i) + + Using distinct keys produces independent streams + + >>> key = 2**65 + 2**33 + 2**17 + 2**9 + >>> rg = [RandomGenerator(ThreeFry32(key=key+i)) for i in range(10)] + + **State and Seeding** + + The ``ThreeFry32`` state vector consists of a 2 128-bit values encoded as + 4-element uint32 arrays. One is a counter which is incremented by 1 for + every 4 32-bit randoms produced. The second is a key which determined + the sequence produced. Using different keys produces independent + sequences. + + ``ThreeFry32`` is seeded using either a single 64-bit unsigned integer + or a vector of 64-bit unsigned integers. In either case, the input seed is + used as an input (or inputs) for another simple random number generator, + Splitmix64, and the output of this PRNG function is used as the initial + state. Using a single 64-bit value for the seed can only initialize a small + range of the possible initial state values. When using an array, the + SplitMix64 state for producing the ith component of the initial state is + XORd with the ith value of the seed array until the seed array is + exhausted. When using an array the initial state for the SplitMix64 state + is 0 so that using a single element array and using the same value as a + scalar will produce the same initial state. + + Examples + -------- + >>> from randomgen import RandomGenerator, ThreeFry32 + >>> rg = RandomGenerator(ThreeFry32(1234)) + >>> rg.standard_normal() + + Identical method using only ThreeFry32 + + >>> rg = ThreeFry32(1234).generator + >>> rg.standard_normal() + + References + ---------- + .. [1] John K. Salmon, Mark A. Moraes, Ron O. Dror, and David E. Shaw, + "Parallel Random Numbers: As Easy as 1, 2, 3," Proceedings of + the International Conference for High Performance Computing, + Networking, Storage and Analysis (SC11), New York, NY: ACM, 2011. """ cdef threefry32_state *rng_state cdef brng_t *_brng cdef public object capsule + cdef object _ctypes + cdef object _cffi + cdef object _generator def __init__(self, seed=None, counter=None, key=None): - self.rng_state = malloc(sizeof(threefry32_state)) - self.rng_state.ctr = malloc(sizeof(threefry4x32_ctr_t)) - self.rng_state.key = malloc(sizeof(threefry4x32_key_t)) - self._brng = malloc(sizeof(brng_t)) + self.rng_state = malloc(sizeof(threefry32_state)) + self.rng_state.ctr = malloc(sizeof(threefry4x32_ctr_t)) + self.rng_state.key = malloc(sizeof(threefry4x32_key_t)) + self._brng = malloc(sizeof(brng_t)) self.seed(seed, counter, key) - self._brng.state = self.rng_state + self._brng.state = self.rng_state self._brng.next_uint64 = &threefry32_uint64 self._brng.next_uint32 = &threefry32_uint32 self._brng.next_double = &threefry32_double self._brng.next_raw = &threefry32_raw + self._ctypes = None + self._cffi = None + self._generator = None + cdef const char *name = 'BasicRNG' - self.capsule = PyCapsule_New(self._brng, name, NULL) + self.capsule = PyCapsule_New( self._brng, name, NULL) # Pickling support: def __getstate__(self): @@ -106,37 +205,12 @@ cdef class ThreeFry32: for i in range(THREEFRY_BUFFER_SIZE): self.rng_state.buffer[i] = 0 - def __random_integer(self, bits=64): - """ - 64-bit Random Integers from the PRNG - - Parameters - ---------- - bits : {32, 64} - Number of random bits to return - - Returns - ------- - rv : int - Next random value - - Notes - ----- - Testing only - """ - if bits == 64: - return self._brng.next_uint64(self._brng.state) - elif bits == 32: - return self._brng.next_uint32(self._brng.state) - else: - raise ValueError('bits must be 32 or 64') - def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i - if method==u'uint64': + if method == u'uint64': for i in range(cnt): self._brng.next_uint64(self._brng.state) - elif method==u'double': + elif method == u'double': for i in range(cnt): self._brng.next_double(self._brng.state) else: @@ -200,7 +274,15 @@ cdef class ThreeFry32: @property def state(self): - """Get or set the PRNG state""" + """ + Get or set the PRNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the PRNG + """ ctr = np.empty(4, dtype=np.uint32) key = np.empty(4, dtype=np.uint32) buffer = np.empty(THREEFRY_BUFFER_SIZE, dtype=np.uint32) @@ -209,7 +291,7 @@ cdef class ThreeFry32: key[i] = self.rng_state.key.v[i] for i in range(THREEFRY_BUFFER_SIZE): buffer[i] = self.rng_state.buffer[i] - state = {'counter':ctr,'key':key} + state = {'counter': ctr, 'key': key} return {'brng': self.__class__.__name__, 'state': state, 'buffer': buffer, @@ -224,20 +306,162 @@ cdef class ThreeFry32: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) for i in range(4): - self.rng_state.ctr.v[i] = value['state']['counter'][i] - self.rng_state.key.v[i] = value['state']['key'][i] + self.rng_state.ctr.v[i] = value['state']['counter'][i] + self.rng_state.key.v[i] = value['state']['key'][i] for i in range(THREEFRY_BUFFER_SIZE): - self.rng_state.buffer[i] = value['buffer'][i] + self.rng_state.buffer[i] = value['buffer'][i] self.rng_state.buffer_pos = value['buffer_pos'] - def jump(self): - """Jump the state as-if 2**64draws have been made""" - return self.advance(2**64) + def jump(self, np.npy_intp iter): + """ + jump(iter=1) + + Jumps the state of the random number generator as-if 2**64 random + numbers have been generated. + + Parameters + ---------- + iter : integer, positive + Number of times to jump the state of the rng. + + Returns + ------- + self : ThreeFry32 + PRNG jumped iter times + + Notes + ----- + Jumping the rng state resets any pre-computed random numbers. This is + required to ensure exact reproducibility. + """ + return self.advance(iter * 2 ** 64) + + def advance(self, delta): + """ + advance(delta) + + Advance the underlying RNG as-if delta draws have occurred. + + Parameters + ---------- + delta : integer, positive + Number of draws to advance the RNG. Must be less than the + size state variable in the underlying RNG. - def advance(self, step): - """Advance the state as-if a specific number of draws have been made""" - cdef np.ndarray step_a - step_a = int_to_array(step, 'step', 128, 32) + Returns + ------- + self : ThreeFry32 + RNG advanced delta steps + + Notes + ----- + Advancing a RNG updates the underlying RNG state as-if a given + number of calls to the underlying RNG have been made. In general + there is not a one-to-one relationship between the number output + random values from a particular distribution and the number of + draws from the core RNG. This occurs for two reasons: + + * The random values are simulated using a rejection-based method + and so, on average, more than one value from the underlying + RNG is required to generate an single draw. + * The number of bits required to generate a simulated value + differs from the number of bits generated by the underlying + RNG. For example, two 16-bit integer values can be simulated + from a single draw of a 32-bit RNG. + + Advancing the RNG state resets any pre-computed random numbers. + This is required to ensure exact reproducibility. + """ + cdef np.ndarray delta_a + delta_a = int_to_array(delta, 'step', 128, 32) loc = 0 - threefry32_advance(step_a.data, self.rng_state) + threefry32_advance( delta_a.data, self.rng_state) + self._reset_state_variables() return self + + def ctypes(self): + """ + Cytpes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + + if self._ctypes is not None: + return self._ctypes + + import ctypes + + self._ctypes = interface( self.rng_state, + ctypes.c_void_p( self.rng_state), + ctypes.cast( &threefry32_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast( &threefry32_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast( &threefry32_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p( self._brng)) + return self.ctypes + + @property + def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + if self._cffi is not None: + return self._cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') + + ffi = cffi.FFI() + self._cffi = interface( self.rng_state, + ffi.cast('void *', self.rng_state), + ffi.cast('uint64_t (*)(void *)', + self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)', + self._brng.next_uint32), + ffi.cast('double (*)(void *)', + self._brng.next_double), + ffi.cast('void *', self._brng)) + return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : randomgen.generator.RandomGenerator + Random generator used this instance as the core PRNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 9c73c3d70e05..11704f3516cc 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -200,14 +200,14 @@ def is_pure(self): name='randomgen', packages=find_packages(), package_dir={'randomgen': './randomgen'}, - package_data={'': ['*.c', '*.h', '*.pxi', '*.pyx', '*.pxd']}, + package_data={'': ['*.h', '*.pxi', '*.pyx', '*.pxd', '*.in']}, include_package_data=True, license='NSCA', author='Kevin Sheppard', author_email='kevin.k.sheppard@gmail.com', distclass=BinaryDistribution, - description='Next-gen RandomState supporting multiple PRNGs', - url='https://github.com/bashtage/randomgen', + description='Random generator supporting multiple PRNGs', + url='https://github.com/bashtage/core-prng', keywords=['pseudo random numbers', 'PRNG', 'Python'], zip_safe=False ) From 882dbeeac159f4d31cdccd45cd9afe77dda0308e Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 17:39:01 +0000 Subject: [PATCH 079/279] TST: IMprove travis --- _randomgen/.travis.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index e7304ee57454..43e0bf570e54 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -39,7 +39,7 @@ before_install: - PKGS="${PKGS} pandas"; if [ ${PANDAS} ]; then PKGS="${PKGS}=${PANDAS}"; fi - conda create -n randomgen-test ${PKGS} pytest setuptools nose --quiet - source activate randomgen-test - - pip install tempita -q + - pip install tempita sphinx guzzle_sphinx_theme ipython pandas doctr coverage coveralls pytest-cov codecov -q install: - python setup.py develop @@ -51,3 +51,14 @@ script: if [[ -z ${NUMPY} ]]; then python benchmark.py; fi + - | + if [ ${PYTHON} = 3.5 ]; then + cd ${BUILD_DIR}/doc + make html + make html + cd ${BUILD_DIR} + doctr deploy doc + if [[ ${TRAVIS_TAG}} ]]; then + doctr deploy doc --no-require-master + fi; + fi; From 9303f62e85f5274f40c2258c5ad6016856869d7f Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 17:44:10 +0000 Subject: [PATCH 080/279] DOC: Add autodoc building to travis Enable autodoc building --- _randomgen/.travis.yml | 23 ++++++++++++------- .../github_deploy_key_bashtage_core_prng.enc | 1 + 2 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 _randomgen/github_deploy_key_bashtage_core_prng.enc diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 43e0bf570e54..bda3bb228036 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -7,6 +7,11 @@ dist: trusty sudo: required language: python +env: + global: + # Doctr deploy key for bashtage/core-prng + - secure: "urckknKH5lkUNjXuVCQGVEZYQfSQrAAvdp8sWAKlYJwJLT8iB439KrCUQu8InzcZAA9chPp3syCoT4E0NGkCVPhtJSs/7+LhG+aY/iU6Jp7bwpn5QHCNHQ5jwdc8A0ryqEoQhTiDauRtdzLWPtG5iliz+hr5SOB22w563Le3cx9w0vw9Jy36q+DHe91KEKeF4l464MHhx8aNTmSTBfxPUYyaPHn7/0Wi227PChKMbqnbtoNRcnRwNPjXbRIEs5w2VKtj9m+pvb+DGVjNeSrRBP7aaPgYY+WH+eBOsXrZNuYwF3LEcKx8edVGcEYf2CUKf1VWC2uug/BStY2PU2ZUu/ij3qh+tk2GKhFCc61OPiq7rpeG8Alp5b7IWyFzEjV8IahpdOwa81uGv8B52KD3REOJf8N28s1/WzPlOqRm/9ne+txUZHFk7abE69JK2cBjWGrhBLPxXZSumzhkrpZDyzNb0qZYQSAuAuxUdWhI1gdUJXhmlf4UUqM9vTp7129SbO4wrUK3TIZDIt+7tUuLJYfIm6pOdJBNfrTk4mtvwLh/hsNezd/Vv1BOqrvZ6ZGPMM9eDBh+tMvAfVBe6T6rDoSLUQzYf3GEfp/yJP+QrH9AD46s/DRNL/rAiyOW4oDhMiS+S5EVb/CEu4Ud82HyIZNFAi42gx0jJNkaK2gN8hE=" + matrix: fast_finish: true include: @@ -52,13 +57,15 @@ script: python benchmark.py; fi - | - if [ ${PYTHON} = 3.5 ]; then - cd ${BUILD_DIR}/doc - make html - make html - cd ${BUILD_DIR} - doctr deploy doc - if [[ ${TRAVIS_TAG}} ]]; then - doctr deploy doc --no-require-master + if [[ -z ${NUMPY} ]]; then + if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then + cd ${BUILD_DIR}/doc + make html + make html + cd ${BUILD_DIR} + doctr deploy --built-docs doc --no-require-master + if [[ ${TRAVIS_TAG}} ]]; then + doctr deploy --built-docs doc --no-require-master + fi; fi; fi; diff --git a/_randomgen/github_deploy_key_bashtage_core_prng.enc b/_randomgen/github_deploy_key_bashtage_core_prng.enc new file mode 100644 index 000000000000..9487482f0020 --- /dev/null +++ b/_randomgen/github_deploy_key_bashtage_core_prng.enc @@ -0,0 +1 @@ +gAAAAABaqV7yewp22viHuCymP0zVSCFUAlMJZNQH8yFM6OA7KVDd3CIx2b0SLNfMMq6--IyeHF7Gi5wg7UtT6dRo60F7h5-PrZx8iJjA9hqR0ovbZMPaXOQuLlnWYdw9oIBO976w93pDojwv_3QxUsDgRgmUOG7mERkitM8ihvDN17YbAZ_yyh5aX7NTbRr6DoaeL6UQkqfkaZpoflTRRRVIiJoI3aDi8jEDwhEhS_KeDP1fOnJEaJH7nR-zvRveAgbotla4XlW8IUiUP6hiOyGbk3mXZd9J0W6CPAoKbe2CV_6J4rkKd0IteJN2jsYIeNlvBf2BJ5kaIIXte6afejhyrSYcCzEgun5EuiDkqan4f0qgQSN7jjNX9vHNZ0aHNJ8HfvNFTN4fGF2xL3bPAJtGXaqIHEMF5USTRnNN5p0gKxCI5eeD73V-lpE4_LKV5OiWxC4zVFIL6BAEIdF5-cZ9Ikzqtklia17yZna3Rfbhc-0R8YYlpXWyT04c1FIIbHqNk6wsGYNyINTPTloJ6WWjwVD3oTmvFIJOBtR8Rfyk6GYM1PU2ybdbdUJc0iUXv2aL535IpnrK5Fnw4Q-lWSvI6VowJ5aY8GrnQJSyui8kA8BCkE1oblWtR6vmSwFZPjzvkZG2jUwnnaOluCjIzAm70llCO4_4b9IQkdsnNuBlVj1EYDYZQTMe4QJnBoCvB9joFp5dYauoODPcmjrXBCb8Eglg8PAAvVfLeldX2MkFGrv80pxIcN0xsI5qZmmJQOCidHEFSRLCq5Txu7OBOPCtbefs_C4mJdf7iF-F8F0DEOfr5g9CnmbIFzLomsYTzW_M4rqpkF8fxxgd5JwqRsSS36Pm6U8fb8ufpY_e4kUOd3F4qjhFK7PmPYLFdoTAaJobcgMHYNW4Y0KNTKuJM0tf51ysH4Br0EoR3CnzbBcKsgkb74OWzdgbwCdV5zvJl_b36tdd-CRZwA5A85yacuZzrVDJVYrPGwG_7Hsl7WXw-O4sVBaG_yumS1U2nC8y-gTomkvLOHq-fs27mSzcPRApC8d9C2KU9lmvgQPd7OtkPRPeypRPzU5A5UJ_EJVyG4ETUiw-bBLn_viz2HIKEg9wz0i16RSWZkpXHMzMzui2B14vp-RSjSXxK-Ou8dkTDbmw68yIzs4nHUoFA8ZN1CxUzQ2DpUzN9AcLy7q3KGh-XEIBYofsFkPbWYw-KdJi3mOYijShG-4hLGq7YI1r6VGj5Pc9Arh5zdZ_yx8PTz-g6e2-N0dvFfmNmX-bPAsIA5F8UwUVBKFP50vuJ19s8eqsnkrgTSbbF6BTOAifugLODKMeI5UANi-hCUhX3CXRIaOSzg54Ym6e-0suEQ1QygdRsVR4RU1mDf8Za6ZVEYbhuXRVwNnuSzljBjm-ejVAEcgMiTR-lzmu3kcFH_ciHLkO2kJRvv7JkFuDzux1IHM5gcBVYujIMuSFrnAUnuL2vgMfEr2DscSFmezEJz_V1R9NuY3y7hIDitQEAeXUJyUTFwDrFufGqF3IaS2nc6J-aAKVzyGm7JInrpNPH5yyMzEhVLk2V-H-kHSkCZAe240nQ2C0-eKtNCblbOVbfSCkFk2iohUkWK4A8sXSvcDELjCKzkctIANtusdFFEBEu0RswoBouQOICoP7d8ySyGs3XMDDBU_WL_TQk2TAXkVvMEvLLfDxj80JTtqyylD0XDblww6wgVt23KQpvCEpYQB_Ho0NIfkT3qgoDvUuMlz6k8L48AN58mUkqv1a6mhvc86KXsLcYYvwKO33-ErSd6FJKrEKPWr51v6RWpoO5J3ubqSxG_zekchPQ7EnJpHomTlCFK9u-_v4Tr_lTLtDW3vFIfWOyA4LvSVGp05x_HO4MBxL_XNwNzqG8tNJ5fDkOtLxCKWhoHpeA-_zIEFlfGPsfY2j8P-FAR6VyFTecTIFGJGb6ygZL-dGwJeH-FXjdRPMlD_dHxEqxx-JGHlTM297w7yTue80FosiiCkmwJ6BNQJCf-0gom2_ahJgNY_wj0psjLEkIK3pAijICcbZHBYYLyvVDn7llaUc4ziWt-TBego-Nd-5LMl9St0AdBLbGQ0AQqvm5F6MUxnp-KiDNcW0imWXePbqo7Eb4_3SE7mkeHIQY3Tssm_G7sAd6O6Q-V68tfWP8fHWOilaDeIJlahDpUbN3ygLMZwAjaDA0O6g6rSbYGSJtNIBh1VdDGBDOG9pyaRsLIMlxgtjQ7lQPQ44JQzwSa-93tpJQbA2-S_f4SaXt15HVbfr5YeJKcgHJQZfV_Ibi9cWFRp-v12wbPXJ2CkBZXUfzRiW0yR1tlsIxJUreL6SuMvnGulCsw5pbPXvyGOBPhQmKi_JCsanm1_OqQV_5-3p3g2MriHai48kbueoAwV06H9hXFtgZmDcnu8h_99Ld6vpI346xoDo4ShvJC9fU8sGf07zf9zKfpHUberx0mOU4hpyfx4xpAtPJS2ZKni2x2HJuVJkeyPWDIT2kNOOW5G04AnXhrve9CGXDRNIsjeV_q96i1hEaelLGdGkylkHQCJesJDXGN2Kc5QtYaEwRYV7MOdPiaLbPhXwrh2O25UyE-Zjc0UtV-uTCVlQon1nJWk-qyHllDZYxt1AUcwF8EXlG9G1nO7zHFnm68SmC7-Rv6z374YEio3q6PmJzAISd9I4JCPWxrnEPdUtUo8xChttRHys2AzNLRt_WbEtewf5jUeLCtmaRdLbgG-LxBa8IXRLTaQuEw1MH5nsewdoylt-0besWoyhKDtT7oQit7b3gHnCEP3BNSlqmQHodIw0KCC4YH4g4MOVB3YjvBO7lYVCNVyKFQvk2mwo0mKa_H9laljd95pikVuUphoTcbA_fneij-yaUFDu0lVFtio5Tjp7ek2ASxjzuaOgFcdY8LZmCkCx8D0ss8TOsph1JfkIA_rkkOElDc6EROJ-5eTBhQQekcIURltgRjKdrql0T8pD3FPC2Qsv6VMHyFMEpIW7qykJLwoxoendlc7bLNM7DSoIBeqOzY1vRQK1Z1fLFZVwxmtM8P6Up-Lf0aHMpe1jMkKASmj6Xtt-6jiFwS5gTSD_1tiALLgD75HZM88Hrk8zYzfr9MDTEMOiPHIjYfubsO4sve8BD12kh3CyQV26S8573TdaNRlLmTRt4YBi49--xlSrNBP6sqqoN6ZT_S0uA1JAgMHmf4Jr7DRxTfp_qpbjXvCtq7HWowhAsw4oQuF8VSx-PZZM_uzEwjHaR6TpHR3_OkjlbRBL8xR84qCgNjhFze_NxAqIbSuMoRt-n3Dv18Z7bjfokJfPTXS6FA618fZNnryIAyTZsmxjFvywwRRpiFNg6PgXB2LKHGOxpxP8nenfBJAWXD9NodI_sTS7QyaEqUp4lGEcADgLYNNDe77HyhZV1tirHesUE9CwbX-X3Nx_KQ6MhSzIZQn6AiAar5JzenyJV2kRX7Pg_tXYLQLaahnobpCBXpHuDe2_p933SdMU5xsNXQEE4ldJ_R9wfEqlgur5JCiXagLRxjzdrQIBMDXA2pfxu75ow0x7k3-Q9NrNKQQnt7R8HKItSg3m8k0XKSzJ4qgkHeRDdyzlZdA70qcCin4SiF1dYQPRinUjhEiiYdAuxOqOSNJeynwhw3-1NgitiPg03ORP0HAwlUF_SilOjhhCvTG6qQwBLjCIXjsGRNi8HDloIr2JD0gO-pfOsi89QzEm4LkdnQISmVOUFSHQsO4vGtQsnysHpccpNbo63PIEAIX9N9Cnwpi_3ZXcppUfT5FD3s_0R20sqCchys680bRVJivQh3eE79ROHKest_Uxusp14efvKocldd5B8pT9UPh5Y3ZSB2pnFBESYX0Zae3quRF6atlqbtfocixF78a4Rb1H1ZU9opJUbE5YKyQkmWtbbtDsV0OueN2ckC2gyeHtmaJmgne7oxm6JP1f1C68_-YBOGEHaG2MLW1ZS5a5F-3IGLwl6DboRRcV44Q7H5GKr-WuhjTnAlKPB-4ZfxpxCkFd9NKF3LFkrozvsJsKUqC0MdTw0oDNkO3wIxnhmJkAxJbHK0H-XQ7hDRNf_1ajj71kgP3Iv36qQdLqTvH1EBj1Buqe6T5tfKs-ijAmP8Z0ycJ45RMeAf-PEd67NKqdQHSwbhjw0FsP1LTaBQ5TUDjmITPp_nkpmhjRx70o4mm11D_05YwS3qf7-Avf2emZUGY8Ql7lSqFqblWG4DX1pqD15k4f0Vl38M6BysRu-nd7PqERV-KkvRo-LhhTbR313AtptTurr9BXnB4UN_7s86S22m8RAwMDAXURYVv-Dvy6KuITJTd8AP46Z9f0veQUpidA7wGlApOliDZezM_2qskKnF0lmp3ujuO2H2yPGIj7en0s3VwqXTC4fE8dggF6q2mgfBcrBCSd1Mf9lEs= \ No newline at end of file From 0c4b3ac0bb1e519c4d73469a907a94a0658d43c3 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 18:02:42 +0000 Subject: [PATCH 081/279] BUG: Fix failing test Correct list of expected methods Rename random_sample to random_double to allow random_sample to be used by Python --- _randomgen/.gitignore | 13 ++ _randomgen/.travis.yml | 26 ++-- _randomgen/randomgen/__init__.py | 2 +- _randomgen/randomgen/distributions.pxd | 4 +- _randomgen/randomgen/generator.pyx | 6 +- .../src/distributions/distributions.c | 146 +++++++++--------- .../src/distributions/distributions.h | 14 +- .../randomgen/tests/test_against_numpy.py | 17 +- 8 files changed, 125 insertions(+), 103 deletions(-) diff --git a/_randomgen/.gitignore b/_randomgen/.gitignore index 613fc1bf498c..df53d2597f1b 100644 --- a/_randomgen/.gitignore +++ b/_randomgen/.gitignore @@ -9,3 +9,16 @@ build/ **/Random123 settings.json *.so +randomgen/bounded_integers.c +randomgen/common.c +randomgen/dsfmt.c +randomgen/entropy.c +randomgen/generator.c +randomgen/mt19937.c +randomgen/pcg32.c +randomgen/pcg64.c +randomgen/philox.c +randomgen/threefry.c +randomgen/threefry32.c +randomgen/xoroshiro128.c +randomgen/xorshift1024.c diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index bda3bb228036..0f2da0e20c1d 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -44,7 +44,11 @@ before_install: - PKGS="${PKGS} pandas"; if [ ${PANDAS} ]; then PKGS="${PKGS}=${PANDAS}"; fi - conda create -n randomgen-test ${PKGS} pytest setuptools nose --quiet - source activate randomgen-test - - pip install tempita sphinx guzzle_sphinx_theme ipython pandas doctr coverage coveralls pytest-cov codecov -q + - pip install tempita coverage coveralls pytest-cov codecov -q + # Docbuild + - if [[ -z ${NUMPY} && ${TRAVIS_OS_NAME} == "linux" ]]; then pip install sphinx sphinx_rtd_theme guzzle_sphinx_theme ipython doctr -q; fi + - if [[ -z ${NUMPY} && ${TRAVIS_OS_NAME} == "linux" ]]; then conda install numba pandas matplotlib --quiet; fi + - export BUILD_DIR=${PWD} install: - python setup.py develop @@ -57,15 +61,15 @@ script: python benchmark.py; fi - | - if [[ -z ${NUMPY} ]]; then - if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then - cd ${BUILD_DIR}/doc - make html - make html - cd ${BUILD_DIR} - doctr deploy --built-docs doc --no-require-master - if [[ ${TRAVIS_TAG}} ]]; then - doctr deploy --built-docs doc --no-require-master - fi; + if [[ -z ${NUMPY} && ${TRAVIS_OS_NAME} == "linux" ]]; then + ls + echo $PWD + cd ${BUILD_DIR}/doc + make html + make html + cd ${BUILD_DIR} + doctr deploy doc + if [[ ${TRAVIS_TAG}} ]]; then + doctr deploy doc --no-require-master fi; fi; diff --git a/_randomgen/randomgen/__init__.py b/_randomgen/randomgen/__init__.py index 6d389ae9604b..fdddc4ab40d8 100644 --- a/_randomgen/randomgen/__init__.py +++ b/_randomgen/randomgen/__init__.py @@ -15,7 +15,7 @@ 'gamma', 'geometric', 'gumbel', 'hypergeometric', 'laplace', 'logistic', 'lognormal', 'logseries', 'multinomial', 'multivariate_normal', 'negative_binomial', 'noncentral_chisquare', 'noncentral_f', 'normal', 'permutation', 'pareto', 'poisson', 'power', 'rand', 'randint', 'randn', - 'random_integers', 'random_raw', 'random_uintegers', 'rayleigh', 'state', 'sample', 'shuffle', + 'random_integers', 'random_raw', 'random_sample', 'random_uintegers', 'rayleigh', 'state', 'shuffle', 'standard_cauchy', 'standard_exponential', 'standard_gamma', 'standard_normal', 'standard_t', 'tomaxint', 'triangular', 'uniform', 'vonmises', 'wald', 'weibull', 'zipf'] diff --git a/_randomgen/randomgen/distributions.pxd b/_randomgen/randomgen/distributions.pxd index 3ac32f210108..29ee591e3a4d 100644 --- a/_randomgen/randomgen/distributions.pxd +++ b/_randomgen/randomgen/distributions.pxd @@ -35,13 +35,13 @@ cdef extern from "src/distributions/distributions.h": ctypedef brng brng_t - double random_sample(brng_t *brng_state) nogil + double random_double(brng_t *brng_state) nogil double random_standard_exponential(brng_t *brng_state) nogil double random_standard_exponential_zig(brng_t *brng_state) nogil double random_gauss_zig(brng_t* brng_state) nogil double random_standard_gamma_zig(brng_t *brng_state, double shape) nogil - float random_sample_f(brng_t *brng_state) nogil + float random_float(brng_t *brng_state) nogil float random_standard_exponential_f(brng_t *brng_state) nogil float random_standard_exponential_zig_f(brng_t *brng_state) nogil float random_gauss_zig_f(brng_t* brng_state) nogil diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 3c5006b6d8a8..5ae857e9c425 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -323,9 +323,9 @@ cdef class RandomGenerator: cdef double temp key = np.dtype(dtype).name if key == 'float64': - return double_fill(&random_sample, self._brng, size, self.lock, out) + return double_fill(&random_double, self._brng, size, self.lock, out) elif key == 'float32': - return float_fill(&random_sample_f, self._brng, size, self.lock, out) + return float_fill(&random_float, self._brng, size, self.lock, out) else: raise TypeError('Unsupported dtype "%s" for random_sample' % key) @@ -4306,7 +4306,7 @@ randint = _random_generator.randint randn = _random_generator.randn random_integers = _random_generator.random_integers random_raw = _random_generator.random_raw -sample = _random_generator.random_sample +random_sample = _random_generator.random_sample random_uintegers = _random_generator.random_uintegers rayleigh = _random_generator.rayleigh shuffle = _random_generator.shuffle diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index c08d5be415dc..2ed6d26c3dfe 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -3,16 +3,16 @@ #include "ziggurat_constants.h" /* Random generators for external use */ -float random_sample_f(brng_t *brng_state) { return random_float(brng_state); } +float random_float(brng_t *brng_state) { return next_float(brng_state); } -double random_sample(brng_t *brng_state) { return random_double(brng_state); } +double random_double(brng_t *brng_state) { return next_double(brng_state); } double random_standard_exponential(brng_t *brng_state) { - return -log(1.0 - random_double(brng_state)); + return -log(1.0 - next_double(brng_state)); } float random_standard_exponential_f(brng_t *brng_state) { - return -logf(1.0f - random_float(brng_state)); + return -logf(1.0f - next_float(brng_state)); } /* @@ -26,8 +26,8 @@ double random_gauss(brng_t *brng_state) { double f, x1, x2, r2; do { - x1 = 2.0 * random_double(brng_state) - 1.0; - x2 = 2.0 * random_double(brng_state) - 1.0; + x1 = 2.0 * next_double(brng_state) - 1.0; + x2 = 2.0 * next_double(brng_state) - 1.0; r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); @@ -50,8 +50,8 @@ float random_gauss_f(brng_t *brng_state) { float f, x1, x2, r2; do { - x1 = 2.0f * random_float(brng_state) - 1.0f; - x2 = 2.0f * random_float(brng_state) - 1.0f; + x1 = 2.0f * next_float(brng_state) - 1.0f; + x2 = 2.0f * next_float(brng_state) - 1.0f; r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); @@ -70,8 +70,8 @@ static NPY_INLINE double standard_exponential_zig(brng_t *brng_state); static double standard_exponential_zig_unlikely(brng_t *brng_state, uint8_t idx, double x) { if (idx == 0) { - return ziggurat_exp_r - log(random_double(brng_state)); - } else if ((fe_double[idx - 1] - fe_double[idx]) * random_double(brng_state) + + return ziggurat_exp_r - log(next_double(brng_state)); + } else if ((fe_double[idx - 1] - fe_double[idx]) * next_double(brng_state) + fe_double[idx] < exp(-x)) { return x; @@ -84,7 +84,7 @@ static NPY_INLINE double standard_exponential_zig(brng_t *brng_state) { uint64_t ri; uint8_t idx; double x; - ri = random_uint64(brng_state); + ri = next_uint64(brng_state); ri >>= 3; idx = ri & 0xFF; ri >>= 8; @@ -104,8 +104,8 @@ static NPY_INLINE float standard_exponential_zig_f(brng_t *brng_state); static float standard_exponential_zig_unlikely_f(brng_t *brng_state, uint8_t idx, float x) { if (idx == 0) { - return ziggurat_exp_r_f - logf(random_float(brng_state)); - } else if ((fe_float[idx - 1] - fe_float[idx]) * random_float(brng_state) + + return ziggurat_exp_r_f - logf(next_float(brng_state)); + } else if ((fe_float[idx - 1] - fe_float[idx]) * next_float(brng_state) + fe_float[idx] < expf(-x)) { return x; @@ -118,7 +118,7 @@ static NPY_INLINE float standard_exponential_zig_f(brng_t *brng_state) { uint32_t ri; uint8_t idx; float x; - ri = random_uint32(brng_state); + ri = next_uint32(brng_state); ri >>= 1; idx = ri & 0xFF; ri >>= 8; @@ -141,7 +141,7 @@ double random_gauss_zig(brng_t *brng_state) { double x, xx, yy; for (;;) { /* r = e3n52sb8 */ - r = random_uint64(brng_state); + r = next_uint64(brng_state); idx = r & 0xff; r >>= 8; sign = r & 0x1; @@ -153,14 +153,14 @@ double random_gauss_zig(brng_t *brng_state) { return x; // # 99.3% of the time return here if (idx == 0) { for (;;) { - xx = -ziggurat_nor_inv_r * log(random_double(brng_state)); - yy = -log(random_double(brng_state)); + xx = -ziggurat_nor_inv_r * log(next_double(brng_state)); + yy = -log(next_double(brng_state)); if (yy + yy > xx * xx) return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r + xx) : ziggurat_nor_r + xx; } } else { - if (((fi_double[idx - 1] - fi_double[idx]) * random_double(brng_state) + + if (((fi_double[idx - 1] - fi_double[idx]) * next_double(brng_state) + fi_double[idx]) < exp(-0.5 * x * x)) return x; } @@ -175,7 +175,7 @@ float random_gauss_zig_f(brng_t *brng_state) { float x, xx, yy; for (;;) { /* r = n23sb8 */ - r = random_uint32(brng_state); + r = next_uint32(brng_state); idx = r & 0xff; sign = (r >> 8) & 0x1; rabs = (int32_t)((r >> 9) & 0x0007fffff); @@ -186,14 +186,14 @@ float random_gauss_zig_f(brng_t *brng_state) { return x; // # 99.3% of the time return here if (idx == 0) { for (;;) { - xx = -ziggurat_nor_inv_r_f * logf(random_float(brng_state)); - yy = -logf(random_float(brng_state)); + xx = -ziggurat_nor_inv_r_f * logf(next_float(brng_state)); + yy = -logf(next_float(brng_state)); if (yy + yy > xx * xx) return ((rabs >> 8) & 0x1) ? -(ziggurat_nor_r_f + xx) : ziggurat_nor_r_f + xx; } } else { - if (((fi_float[idx - 1] - fi_float[idx]) * random_float(brng_state) + + if (((fi_float[idx - 1] - fi_float[idx]) * next_float(brng_state) + fi_float[idx]) < exp(-0.5 * x * x)) return x; } @@ -209,7 +209,7 @@ static NPY_INLINE double standard_gamma(brng_t *brng_state, double shape) { return random_standard_exponential(brng_state); } else if (shape < 1.0) { for (;;) { - U = random_double(brng_state); + U = next_double(brng_state); V = random_standard_exponential(brng_state); if (U <= 1.0 - shape) { X = pow(U, 1. / shape); @@ -234,7 +234,7 @@ static NPY_INLINE double standard_gamma(brng_t *brng_state, double shape) { } while (V <= 0.0); V = V * V * V; - U = random_sample(brng_state); + U = next_double(brng_state); if (U < 1.0 - 0.0331 * (X * X) * (X * X)) return (b * V); if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) @@ -251,7 +251,7 @@ static NPY_INLINE float standard_gamma_float(brng_t *brng_state, float shape) { return random_standard_exponential_f(brng_state); } else if (shape < 1.0f) { for (;;) { - U = random_sample_f(brng_state); + U = next_float(brng_state); V = random_standard_exponential_f(brng_state); if (U <= 1.0f - shape) { X = powf(U, 1.0f / shape); @@ -276,7 +276,7 @@ static NPY_INLINE float standard_gamma_float(brng_t *brng_state, float shape) { } while (V <= 0.0f); V = V * V * V; - U = random_sample_f(brng_state); + U = next_float(brng_state); if (U < 1.0f - 0.0331f * (X * X) * (X * X)) return (b * V); if (logf(U) < 0.5f * X * X + b * (1.0f - V + logf(V))) @@ -303,7 +303,7 @@ static NPY_INLINE double standard_gamma_zig(brng_t *brng_state, double shape) { return random_standard_exponential_zig(brng_state); } else if (shape < 1.0) { for (;;) { - U = random_sample(brng_state); + U = next_double(brng_state); V = random_standard_exponential_zig(brng_state); if (U <= 1.0 - shape) { X = pow(U, 1. / shape); @@ -328,7 +328,7 @@ static NPY_INLINE double standard_gamma_zig(brng_t *brng_state, double shape) { } while (V <= 0.0); V = V * V * V; - U = random_sample(brng_state); + U = next_double(brng_state); if (U < 1.0 - 0.0331 * (X * X) * (X * X)) return (b * V); if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) @@ -345,7 +345,7 @@ static NPY_INLINE float standard_gamma_zig_f(brng_t *brng_state, float shape) { return random_standard_exponential_zig_f(brng_state); } else if (shape < 1.0f) { for (;;) { - U = random_sample_f(brng_state); + U = next_float(brng_state); V = random_standard_exponential_zig_f(brng_state); if (U <= 1.0f - shape) { X = powf(U, 1.0f / shape); @@ -370,7 +370,7 @@ static NPY_INLINE float standard_gamma_zig_f(brng_t *brng_state, float shape) { } while (V <= 0.0f); V = V * V * V; - U = random_sample_f(brng_state); + U = next_float(brng_state); if (U < 1.0f - 0.0331f * (X * X) * (X * X)) return (b * V); if (logf(U) < 0.5f * X * X + b * (1.0f - V + logf(V))) @@ -388,26 +388,26 @@ float random_standard_gamma_zig_f(brng_t *brng_state, float shape) { } int64_t random_positive_int64(brng_t *brng_state) { - return random_uint64(brng_state) >> 1; + return next_uint64(brng_state) >> 1; } int32_t random_positive_int32(brng_t *brng_state) { - return random_uint32(brng_state) >> 1; + return next_uint32(brng_state) >> 1; } int64_t random_positive_int(brng_t *brng_state) { #if ULONG_MAX <= 0xffffffffUL - return (int64_t)(random_uint32(brng_state) >> 1); + return (int64_t)(next_uint32(brng_state) >> 1); #else - return (int64_t)(random_uint64(brng_state) >> 1); + return (int64_t)(next_uint64(brng_state) >> 1); #endif } uint64_t random_uint(brng_t *brng_state) { #if ULONG_MAX <= 0xffffffffUL - return random_uint32(brng_state); + return next_uint32(brng_state); #else - return random_uint64(brng_state); + return next_uint64(brng_state); #endif } @@ -465,7 +465,7 @@ double random_exponential(brng_t *brng_state, double scale) { } double random_uniform(brng_t *brng_state, double lower, double range) { - return lower + range * random_sample(brng_state); + return lower + range * next_double(brng_state); } double random_gamma(brng_t *brng_state, double shape, double scale) { @@ -484,8 +484,8 @@ double random_beta(brng_t *brng_state, double a, double b) { /* Use Johnk's algorithm */ while (1) { - U = random_sample(brng_state); - V = random_sample(brng_state); + U = next_double(brng_state); + V = next_double(brng_state); X = pow(U, 1.0 / a); Y = pow(V, 1.0 / b); @@ -538,7 +538,7 @@ double random_power(brng_t *brng_state, double a) { double random_laplace(brng_t *brng_state, double loc, double scale) { double U; - U = random_sample(brng_state); + U = next_double(brng_state); if (U < 0.5) { U = loc + scale * log(U + U); } else { @@ -550,14 +550,14 @@ double random_laplace(brng_t *brng_state, double loc, double scale) { double random_gumbel(brng_t *brng_state, double loc, double scale) { double U; - U = 1.0 - random_sample(brng_state); + U = 1.0 - next_double(brng_state); return loc - scale * log(-log(U)); } double random_logistic(brng_t *brng_state, double loc, double scale) { double U; - U = random_sample(brng_state); + U = next_double(brng_state); return loc + scale * log(U / (1.0 - U)); } @@ -566,7 +566,7 @@ double random_lognormal(brng_t *brng_state, double mean, double sigma) { } double random_rayleigh(brng_t *brng_state, double mode) { - return mode * sqrt(-2.0 * log(1.0 - random_sample(brng_state))); + return mode * sqrt(-2.0 * log(1.0 - next_double(brng_state))); } double random_standard_t(brng_t *brng_state, double df) { @@ -585,7 +585,7 @@ static int64_t random_poisson_mult(brng_t *brng_state, double lam) { X = 0; prod = 1.0; while (1) { - U = random_sample(brng_state); + U = next_double(brng_state); prod *= U; if (prod > enlam) { X += 1; @@ -614,8 +614,8 @@ static int64_t random_poisson_ptrs(brng_t *brng_state, double lam) { vr = 0.9277 - 3.6224 / (b - 2); while (1) { - U = random_sample(brng_state) - 0.5; - V = random_sample(brng_state); + U = next_double(brng_state) - 0.5; + V = next_double(brng_state); us = 0.5 - fabs(U); k = (int64_t)floor((2 * a / us + b) * U + lam + 0.43); if ((us >= 0.07) && (V <= vr)) { @@ -694,8 +694,8 @@ int64_t random_binomial_btpe(brng_t *brng_state, int64_t n, double p, /* sigh ... */ Step10: nrq = n * r * q; - u = random_sample(brng_state) * p4; - v = random_sample(brng_state); + u = next_double(brng_state) * p4; + v = next_double(brng_state); if (u > p1) goto Step20; y = (int64_t)floor(xm - p1 * v + u); @@ -808,13 +808,13 @@ int64_t random_binomial_inversion(brng_t *brng_state, int64_t n, double p, } X = 0; px = qn; - U = random_sample(brng_state); + U = next_double(brng_state); while (U > px) { X++; if (X > bound) { X = 0; px = qn; - U = random_sample(brng_state); + U = next_double(brng_state); } else { U -= px; px = ((n - X + 1) * p * px) / (X * q); @@ -871,7 +871,7 @@ double random_wald(brng_t *brng_state, double mean, double scale) { Y = random_gauss_zig(brng_state); Y = mean * Y * Y; X = mean + mu_2l * (Y - sqrt(4 * scale * Y + Y * Y)); - U = random_sample(brng_state); + U = next_double(brng_state); if (U <= mean / (mean + X)) { return X; } else { @@ -886,7 +886,7 @@ double random_vonmises(brng_t *brng_state, double mu, double kappa) { int neg; if (kappa < 1e-8) { - return M_PI * (2 * random_sample(brng_state) - 1); + return M_PI * (2 * next_double(brng_state) - 1); } else { /* with double precision rho is zero until 1.4e-8 */ if (kappa < 1e-5) { @@ -902,17 +902,17 @@ double random_vonmises(brng_t *brng_state, double mu, double kappa) { } while (1) { - U = random_sample(brng_state); + U = next_double(brng_state); Z = cos(M_PI * U); W = (1 + s * Z) / (s + Z); Y = kappa * (s - W); - V = random_sample(brng_state); + V = next_double(brng_state); if ((Y * (2 - Y) - V >= 0) || (log(Y / V) + 1 - Y >= 0)) { break; } } - U = random_sample(brng_state); + U = next_double(brng_state); result = acos(W); if (U < 0.5) { @@ -937,11 +937,11 @@ int64_t random_logseries(brng_t *brng_state, double p) { r = log(1.0 - p); while (1) { - V = random_sample(brng_state); + V = next_double(brng_state); if (V >= p) { return 1; } - U = random_sample(brng_state); + U = next_double(brng_state); q = 1.0 - exp(r * U); if (V <= q * q) { result = (int64_t)floor(1 + log(V) / log(q)); @@ -966,7 +966,7 @@ int64_t random_geometric_search(brng_t *brng_state, double p) { X = 1; sum = prod = p; q = 1.0 - p; - U = random_sample(brng_state); + U = next_double(brng_state); while (U > sum) { prod *= q; sum += prod; @@ -976,7 +976,7 @@ int64_t random_geometric_search(brng_t *brng_state, double p) { } int64_t random_geometric_inversion(brng_t *brng_state, double p) { - return (int64_t)ceil(log(1.0 - random_sample(brng_state)) / log(1.0 - p)); + return (int64_t)ceil(log(1.0 - next_double(brng_state)) / log(1.0 - p)); } int64_t random_geometric(brng_t *brng_state, double p) { @@ -995,8 +995,8 @@ int64_t random_zipf(brng_t *brng_state, double a) { am1 = a - 1.0; b = pow(2.0, am1); do { - U = 1.0 - random_sample(brng_state); - V = random_sample(brng_state); + U = 1.0 - next_double(brng_state); + V = next_double(brng_state); X = (int64_t)floor(pow(U, -1.0 / am1)); /* The real result may be above what can be represented in a int64. * It will get casted to -sys.maxint-1. Since this is @@ -1020,7 +1020,7 @@ double random_triangular(brng_t *brng_state, double left, double mode, leftprod = leftbase * base; rightprod = (right - mode) * base; - U = random_sample(brng_state); + U = next_double(brng_state); if (U <= ratio) { return left + sqrt(U * leftprod); } else { @@ -1039,7 +1039,7 @@ int64_t random_hypergeometric_hyp(brng_t *brng_state, int64_t good, int64_t bad, y = d2; k = sample; while (y > 0.0) { - u = random_sample(brng_state); + u = next_double(brng_state); y -= (int64_t)floor(u + y / (d1 + k)); k--; if (k == 0) @@ -1078,8 +1078,8 @@ int64_t random_hypergeometric_hrua(brng_t *brng_state, int64_t good, /* 16 for 16-decimal-digit precision in D1 and D2 */ while (1) { - X = random_sample(brng_state); - Y = random_sample(brng_state); + X = next_double(brng_state); + Y = next_double(brng_state); W = d6 + d8 * (Y - 0.5) / X; /* fast rejection: */ @@ -1142,10 +1142,10 @@ uint64_t random_interval(brng_t *brng_state, uint64_t max) { /* Search a random value in [0..mask] <= max */ if (max <= 0xffffffffUL) { - while ((value = (random_uint32(brng_state) & mask)) > max) + while ((value = (next_uint32(brng_state) & mask)) > max) ; } else { - while ((value = (random_uint64(brng_state) & mask)) > max) + while ((value = (next_uint64(brng_state) & mask)) > max) ; } return value; @@ -1174,10 +1174,10 @@ static NPY_INLINE uint64_t bounded_uint64(brng_t *brng_state, uint64_t off, return off; if (rng <= 0xffffffffUL) { - while ((val = (random_uint32(brng_state) & mask)) > rng) + while ((val = (next_uint32(brng_state) & mask)) > rng) ; } else { - while ((val = (random_uint64(brng_state) & mask)) > rng) + while ((val = (next_uint64(brng_state) & mask)) > rng) ; } return off + val; @@ -1200,7 +1200,7 @@ static NPY_INLINE uint32_t bounded_uint32(brng_t *brng_state, uint32_t off, if (rng == 0) return off; - while ((val = (random_uint32(brng_state) & mask)) > rng) + while ((val = (next_uint32(brng_state) & mask)) > rng) ; return off + val; } @@ -1225,7 +1225,7 @@ static NPY_INLINE uint16_t buffered_bounded_uint16(brng_t *brng_state, do { if (!(bcnt[0])) { - buf[0] = random_uint32(brng_state); + buf[0] = next_uint32(brng_state); bcnt[0] = 1; } else { buf[0] >>= 16; @@ -1251,7 +1251,7 @@ static NPY_INLINE uint8_t buffered_bounded_uint8(brng_t *brng_state, return off; do { if (!(bcnt[0])) { - buf[0] = random_uint32(brng_state); + buf[0] = next_uint32(brng_state); bcnt[0] = 3; } else { buf[0] >>= 8; @@ -1275,7 +1275,7 @@ static NPY_INLINE npy_bool buffered_bounded_bool(brng_t *brng_state, if (rng == 0) return off; if (!(bcnt[0])) { - buf[0] = random_uint32(brng_state); + buf[0] = next_uint32(brng_state); bcnt[0] = 31; } else { buf[0] >>= 1; diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index f3a5448b3479..6bbbcd8f0f05 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -77,24 +77,24 @@ typedef struct brng { } brng_t; /* Inline generators for internal use */ -static NPY_INLINE uint32_t random_uint32(brng_t *brng_state) { +static NPY_INLINE uint32_t next_uint32(brng_t *brng_state) { return brng_state->next_uint32(brng_state->state); } -static NPY_INLINE uint64_t random_uint64(brng_t *brng_state) { +static NPY_INLINE uint64_t next_uint64(brng_t *brng_state) { return brng_state->next_uint64(brng_state->state); } -static NPY_INLINE float random_float(brng_t *brng_state) { - return (random_uint32(brng_state) >> 9) * (1.0f / 8388608.0f); +static NPY_INLINE float next_float(brng_t *brng_state) { + return (next_uint32(brng_state) >> 9) * (1.0f / 8388608.0f); } -static NPY_INLINE double random_double(brng_t *brng_state) { +static NPY_INLINE double next_double(brng_t *brng_state) { return brng_state->next_double(brng_state->state); } -DECLDIR float random_sample_f(brng_t *brng_state); -DECLDIR double random_sample(brng_t *brng_state); +DECLDIR float random_float(brng_t *brng_state); +DECLDIR double random_double(brng_t *brng_state); DECLDIR int64_t random_positive_int64(brng_t *brng_state); DECLDIR int32_t random_positive_int32(brng_t *brng_state); diff --git a/_randomgen/randomgen/tests/test_against_numpy.py b/_randomgen/randomgen/tests/test_against_numpy.py index c4673c2d2306..dd187f25d8db 100644 --- a/_randomgen/randomgen/tests/test_against_numpy.py +++ b/_randomgen/randomgen/tests/test_against_numpy.py @@ -1,10 +1,11 @@ import numpy as np import numpy.random -from numpy.testing import assert_allclose, assert_array_equal, assert_equal import pytest +from numpy.testing import assert_allclose, assert_array_equal, assert_equal -from randomgen import RandomGenerator, MT19937 import randomgen +from randomgen import RandomGenerator, MT19937 + def compare_0_input(f1, f2): inputs = [(tuple([]), {}), (tuple([]), {'size': 10}), @@ -42,7 +43,8 @@ def compare_2_input(f1, f2, is_np=False, is_scalar=False): np.array([b] * 10)), {'size': (100, 10)}), ((np.ones((7, 31), dtype=dtype) * a, np.array([b] * 31)), {'size': (7, 31)}), - ((np.ones((7, 31), dtype=dtype) * a, np.array([b] * 31)), {'size': (10, 7, 31)})] + ((np.ones((7, 31), dtype=dtype) * a, np.array([b] * 31)), + {'size': (10, 7, 31)})] if is_scalar: inputs = inputs[:3] @@ -528,15 +530,18 @@ def test_array(self): def test_dir(self): nprs_d = set(dir(self.nprs)) rs_d = dir(self.rg) - excluded = {'get_state', 'poisson_lam_max', 'set_state'} + excluded = {'get_state', 'set_state'} nprs_d.difference_update(excluded) assert (len(nprs_d.difference(rs_d)) == 0) npmod = dir(numpy.random) mod = dir(randomgen) known_exlcuded = ['__all__', 'Tester', 'info', 'bench', - '__RandomState_ctor', 'mtrand', 'test', - '__warningregistry__', '_numpy_tester'] + '__RandomState_ctor', 'mtrand', 'test', + '__warningregistry__', '_numpy_tester', 'division', + 'get_state', 'set_state', 'seed', 'ranf', 'random', + 'sample', 'absolute_import', 'print_function', + 'RandomState'] mod += known_exlcuded diff = set(npmod).difference(mod) assert_equal(len(diff), 0) From 664e47d4de5e073138cb40640ac526300c2346c6 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 19:43:07 +0000 Subject: [PATCH 082/279] DOC: Fix location of tagged docs Fix location of tagged docs --- _randomgen/.travis.yml | 3 ++- _randomgen/setup.cfg | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 0f2da0e20c1d..47a37867ca3d 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -31,6 +31,7 @@ matrix: before_install: + - git fetch --tags - if [[ ${TRAVIS_OS_NAME} == "osx" ]]; then wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda3.sh; fi - if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh; fi - chmod +x miniconda3.sh @@ -70,6 +71,6 @@ script: cd ${BUILD_DIR} doctr deploy doc if [[ ${TRAVIS_TAG}} ]]; then - doctr deploy doc --no-require-master + doctr deploy . --build-tags fi; fi; diff --git a/_randomgen/setup.cfg b/_randomgen/setup.cfg index d6b61d347b3d..7e46c5c532af 100644 --- a/_randomgen/setup.cfg +++ b/_randomgen/setup.cfg @@ -3,5 +3,5 @@ VCS = git style = pep440 versionfile_source = randomgen/_version.py versionfile_build = randomgen/_version.py -tag_prefix = +tag_prefix = v parentdir_prefix = randomgen- From 736284f4d7d15d382e25d04f3c6aeea0c95792a1 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 20:34:50 +0000 Subject: [PATCH 083/279] DOC: Fix doctr after change of name Fix doctr to use randomgen --- _randomgen/.travis.yml | 6 +++--- _randomgen/github_deploy_key_bashtage_randomgen.enc | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 _randomgen/github_deploy_key_bashtage_randomgen.enc diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 47a37867ca3d..94c17b200c19 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -9,8 +9,8 @@ language: python env: global: - # Doctr deploy key for bashtage/core-prng - - secure: "urckknKH5lkUNjXuVCQGVEZYQfSQrAAvdp8sWAKlYJwJLT8iB439KrCUQu8InzcZAA9chPp3syCoT4E0NGkCVPhtJSs/7+LhG+aY/iU6Jp7bwpn5QHCNHQ5jwdc8A0ryqEoQhTiDauRtdzLWPtG5iliz+hr5SOB22w563Le3cx9w0vw9Jy36q+DHe91KEKeF4l464MHhx8aNTmSTBfxPUYyaPHn7/0Wi227PChKMbqnbtoNRcnRwNPjXbRIEs5w2VKtj9m+pvb+DGVjNeSrRBP7aaPgYY+WH+eBOsXrZNuYwF3LEcKx8edVGcEYf2CUKf1VWC2uug/BStY2PU2ZUu/ij3qh+tk2GKhFCc61OPiq7rpeG8Alp5b7IWyFzEjV8IahpdOwa81uGv8B52KD3REOJf8N28s1/WzPlOqRm/9ne+txUZHFk7abE69JK2cBjWGrhBLPxXZSumzhkrpZDyzNb0qZYQSAuAuxUdWhI1gdUJXhmlf4UUqM9vTp7129SbO4wrUK3TIZDIt+7tUuLJYfIm6pOdJBNfrTk4mtvwLh/hsNezd/Vv1BOqrvZ6ZGPMM9eDBh+tMvAfVBe6T6rDoSLUQzYf3GEfp/yJP+QrH9AD46s/DRNL/rAiyOW4oDhMiS+S5EVb/CEu4Ud82HyIZNFAi42gx0jJNkaK2gN8hE=" + # Doctr deploy key for bashtage/randomgen + - secure: "czwFlflS1lcfbSQ9ktv+pLAPV9/6+wmwiMTyIYyv5xgQVWRL5NRebWH+ZhQ6s2T5x17wFMtlafcAvkdV0CHQZLru34V2UNldCapuEtQ8b32EDHBXHKbs45b7SSkLx4TFXdjiJurleY4ZIKle0gX6BW21zYBwaHJqbN6I8nRv9Rp47XEU1UV1Mdf/PhfTnxY31rFrPYL77xeWJzoFfT8zao39V4gQds+1Ag7FjdNVdSDVKwDduF4kS7tIbKqb4M+jsbc3PIKyP9nyQpEQF5ebJuG7mqXJhVJGEL83rBx8MLFPA/1X3cUzKacgKyp2+Wmlt0EVhwCa1aRf9cSK6I7TbMC7/eGtDnC2ToiRlFJurVRblaEmhzVQS1yQ4Dkooqsj9hNVl6nhu7JfR52GLogns33Ec/yYuRcWcULKSlR5Cerfef/5YijBEhlr9X76SJiOpjvS4lwWFYX+h8xzuVhRLGwIVB9oQNllxYItzcDSGmRx+EOMXWASHmoUDnBOZg4GMVukqOcF5l0ynoepiA1YHLdZlMy6SB3P7BZKF/aNCOn9nXw+N9X4U/yUpkM3Pb7HoGdNrC8RO4SwrNjGrarkdEB6e1lBReK/dqcylaF/mpK9VLpfQszDI8xnR4VCmlEM+le0xOsyHfeGciabdI4KH0i0SfYl4ls5XrN+CaqFWdo=" matrix: fast_finish: true @@ -70,7 +70,7 @@ script: make html cd ${BUILD_DIR} doctr deploy doc - if [[ ${TRAVIS_TAG}} ]]; then + if [[ -n ${TRAVIS_TAG}} ]]; then doctr deploy . --build-tags fi; fi; diff --git a/_randomgen/github_deploy_key_bashtage_randomgen.enc b/_randomgen/github_deploy_key_bashtage_randomgen.enc new file mode 100644 index 000000000000..ec025c4808eb --- /dev/null +++ b/_randomgen/github_deploy_key_bashtage_randomgen.enc @@ -0,0 +1 @@ +gAAAAABaqYcL3y2gmKPwdhTQvWbDmqvTV9VyGXrEJI0HFVB3ZcmhgwRY_2L9_k7wALgsaQ9-FOqKreKMagBvAiS8IYhW4dUhJ1_6MO0bb8l_fdvkiKY7NH4DXKpO6sGmOg5YPfx44agTLtnI9yuZHo_LgYTkXFS2MQISZJvpmmtgC7fv_ydaRDG3v9c4a4zi7futr6zk0jAlxw29gjyFaReWJQgH6hJTVUVvOq30RJwjpa87jf45mVTsyPdVfHRqn6rcwvGsRKCW6hFnPRsJEP6-ivdjMFbzK6uK1TrswAJ2ZZIGcH84Kaph8kQayMZRL5FUoWsonkGK_SHwiPjmmHRXVMYxSJqNAtjxDgcznzmuazUOwdWCUIkxe0FtJieW5rLwTjT2u1cgcCQ2MKkBiCjO4tORCT0JGCyhOZdsJx6_5i2s1OKaCEb6Uur07itpI2IAEreA38u7CiU150Q7D8zinpPLWuXIrsk9nKfr1YjwXBSVtOBUOuh4Sy9MjcpQuavwJPYVSpNi6_BeIclxP45wjFF5Ai2P8IgaHxSFlMJNfze9H1U-2eTyQaykuZ2WrZBPoGYFRaQExU6jnXOdPMC5FqaO5DV5tvN56fLx9UFXaCqf_UknJRvYnLi94H__nZJWhN6XfCeNaUuPZuuiOFXekK-LC5VFAWXTN84pOesek0-zESKDffFozITTjA-4cvzppUnsSZNm5cXBUdr3wszkNlrQqDVZhP_HU2B8QSilBnnfVEsbKr_-SVQ0s3ipFohPS_GTFKtn8467vvIRgCkks8J1ba5xHb6QMlt2Y2L7yunLh0vmKwqZTVtU-4L4Xm2kKvgHi1kxAaApQiEX2bM-xX7TGNnzRFLKAxpHX4EvO72K2CcQXKu0XkRNc-_c-XcxsWZ7XtvyTCBXNnPtvj26B-FW8XyJH_u0HblrB-AKRgmpRuAhDNh1l_OAcOFHpUrH5t64t6lwOYCR3lXUJJytW-UEz-Nx9j32VX4Ep1IsGjkNuM3FtW4E-iVoGPwYwT3jsGo5rsO6MzrzoEKJbFdgQHnqe3NaxpF6rEVweQTNN2E1LFFuYHnRgo2LuMdK7IDXJ66MCxqEBRMH6Gcne-b5RHEpWoCQAvgyKwU5MclS4M3zLhGnXbtO-q4OL3JV1a-wx9e4vHZJrAolMjvw7a8l5vCDj-FqT5nJIVpG5eKwB_JL24O5d4xUSbgqBm6i1h51L---brkWg9i9YXsjZj5Inf2ZuU3hasZPyXFbTZbpBXN7BMalszLadCOWWsnDJMvl-UJeX2aDDATy5M_4-9Yjt70G1ZJNxZ8K2F6UdXwVifGJGa7jHU9nteCWZVfUdkiexqkLqKebZAlPBpzisrEQw6PmokKP2UO27NBFYTlfYL1NiCahXkOUMPiTKhjQ0_JSqdlUl2igNlNUFSip-63Rk4WtgodQo9iI4icfV5TFkR0h-LPD1m9lIamruWvAQWLU-_daZcN8rdqCWsysuo1ryp80UHHvyTiwloCa2f0ZKr78RIaD_QCkHmevywprNNuMd0ErbAOD7v3dUKjnlvpf8gLpUnu4ZfR1u86OPqsyt2b5tmwB6TWdpaCBNRAjlbFOU8aHDpPDVCAKf1AcEZ1B6p36YgNf5yxmKwc1QEmzXPr1KnSWJRps_QRBX-hEuBu8Q_BUQCjlInJVLcpSgt2lTuJPwwQzdxm5CeU1xdpeWCztSxfghmfE7mzhYizIYa1WaYs32xfZQglEG_O8oXCaU524vyh6cBnIytY3cF1FlwfbKQvbKyKkq8p5YSWe8HX8XRJGVe1bBNM2RYZO5BfLLl5cENIUSbb-REs6j8E61HGgJ9cLBG4-l2QbivSEhKsa4fI0JNVGEL_kwaEOVNHa85y_4oFAQuC4eYOMdgrwGfcD-J-XkE_J6khiLCOaZRcFhFNUfTjghPYzO37D24cAQ9fGnFFehQU-08Ie8SMV2O3fmUV2RbX_h6FXYKZ5Ptp3l2wP5wcuwhPFxPPJ279pswQw9NlHBF3gdtu3_cisqwNfc_HZQ6GXYzbcE7nwTGOY03LN3RjghJgkkeaNs6e0iIxfTJjIqG6-ZWNRNOJKdotjMLVqlhfk0KNZjO5rKEfDfYW_Lbiylgu7I7O-wy-Xn60OTu7na0ObYl-Y9tXkRTZPMNasjDWpfTXKZRp8EX45W-35VKmb0ERj0ee9uXgZxiPGLd3OP8cxIiXqZdZYKwJnD09zZuXwaTa2AAp2WmLYLiF-pDIISNxVF7mCxU9G0AWl0Ml1d5pS5zadM1OYB5yfjx09hlVasaiPaGqIptNtdz8tDQ1ngH-QBPV8wNvSxHwdU4w96pJIY9jG5Z3k-PVO26NNKjZ_KMZhO-3TgQXMJI0GHSyfYFHEMGJuUbeS4ThGyAt2Z6pVKTu7WFjgceseLMmwevJQeyScvtD22t8bpSuqfgxrAGSP5O2-e1UEl_12umZZG3sSd8jc_WNBgX7nSa6LeGAmlY0z_h9SblVl63r2qZi7-Ur0Y7O4JH4rHMDkf07tMU-foCiDDppvZkPRuvPlYgzLmnyOXePN0_1aiou9qbMWmzyJwhrqnt5uZXVHpRwCKKdXRBAcBebuKU-LKqMhWWowf1OUm240628OmQL2oTOaVWBlS3x1XKHMv18_ucbgWB4KaQdidSKMwIXE_LRfhr17g-h2CTQFsfImGKU36ECJHk35K9qr3aZI5X2MLUsOJjdbQiVJsLpdCDbr_HfPDNnux0QiVRZhslKnqOlcv8_6MeKtcqcxDJTi1v1430tpiZj-A2dp3F9YXi_PvCcKD4GheUwN8TUJgEZF3m9Vc80pAWWFDN7Obof_0zCcv7HrXgXCVJHnFzJn0J4AqW6db-DvYAzdejDnLTsTZK9ctJmWxHAWWXYi35aAjj6nalFk97T7EvOr2zS6f_xSUyPeNPs2fIP1lY3togmjPRvwbIN-ZxqLzkfjmxARrLJpqAxK_AvOz2vNlEosQd3zJxk7hEQWRfkTmakvDPgkd5fNsfIGfAt8B_PWnmz41DWKeOlsSQguPAqCE40NSszmyjSBhde8uHN8tGwdQpdcjPt01kgmrdD2GHfLs8zeyNWRzE3qmLT46S1dq1kfQX2j20LXDck9Ox0nFDUXYwaz6pVDPymhPqzh4EHtg0QKePJ5qpY2RDTW3S8UK3YkE3pa_C_-BPcNLVGr_k7WaMWGx0JJ72W2MqcoXgq3bZq_CZeseeKm3rH3YiaibidLk4WqMblcWUurHW09vFCNSOyQ28jkBeMSgadJ2zEbK9M1QmsDxxSCzWtIn_y7nDLCGh0NzD2alVp4QfxwjF5ZEYSXZOYXdhRBkd3pRX9perJT_zlQf7Ag2otXUZE-J6TkDAAwhWxxUFQ0iUIKNKtO-ocM8YevCyl0EK06AzX6jmShrE5eZpej7o7DA2dCoLYksacloBbonqDjkpXR1uZcGJSnhZm29UeSSGQN7cqgR5DDCHkthvOn8gZxS8vr1fQiswazUaMCClHUD_O88IlLXnqXj4n-84TMT9iBGN3iaab4P-fb2t1Azcd8uSGl3CwNEouEekdvVWHSp3bhMkwpPuvakJheLOGfX7npwWo5iIEvdA0VhesiEV8ZVJYCt3zmOwQtI-Sk5uAVAWAieB6-up9KWtwoF89C64CLp99srzLkaPddQJKtTruYQER5l3hL1LBe5g8XPEBNMrFjp2xIN8mNYpZRt41nFxsHoA9xnsv4NXWbwqnkyImP0Wm9HmclvwTOZ9xdT5Ryj8u97XSOz4y8T5Ql5UPwRBujiBI91GQnEKz3FPmUzS70Bbrg3XIirpbPqcRp_VnnxXT8AX0zGZiuWvx94NFa5h4a11vYpeLnKzQ2RyTHB96CSpxxdXHAHfMvc9ib3XzlKRUUfDX0x0tDBj3BkV5UMgLtn2RRCgT1PydLn13wYbeNwfb5GlGutiqQY_QTuUOqSII-2vyNzA5FUPpzofXGYwAz52pGwpZ7w0s4fBpXocxWt0gGW5wxDzTEX3UdkbRsN1GXs5tYkdbcCW_jPrVcq7pUGgOyGXMEYnZUA1ack2h6nSwlxbx_Aka_VyxZCJFYJW9S165lIhm7KkDCfRpQdoA4Fx27aAXwWL70ipNCyNHFOERXD5SoVMJDcz3-cXkttEddXooygKoXojR4epBuxhSkUNxgnd70faZaIC8_L5_ZlZIBn-lH3jLT5Yuzt8-weKpAyczteZ8eLB0YlnYlqhIVFYy4QBR8iejRZBXABKiuIWz_Xf4qu6UGwHTQ-1BBfl9mr0RxULn7NGtfbQ72Xwad-HlT1MnEd_6o95MkFvHbdINlpkaeVwiAgUSFbITPh7x8JaQKlAzjROJQdhGvT4j42woumzQtuqr9UnDWtf8aECkrJP_-AEy1BLbXmUo= \ No newline at end of file From c6ac950c109db79df1f68581368505c7847f1f78 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 22:28:18 +0000 Subject: [PATCH 084/279] DOC: Fix version display Ensure meaningful version is displayed --- _randomgen/doc/source/conf.py | 7 +++++-- _randomgen/github_deploy_key_bashtage_core_prng.enc | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 _randomgen/github_deploy_key_bashtage_core_prng.enc diff --git a/_randomgen/doc/source/conf.py b/_randomgen/doc/source/conf.py index b832553cb218..619272db3c6a 100644 --- a/_randomgen/doc/source/conf.py +++ b/_randomgen/doc/source/conf.py @@ -27,11 +27,14 @@ author = 'Kevin Sheppard' # The short X.Y version. -version = '.'.join(map(str, LooseVersion(randomgen.__version__).version[:2])) + +version = randomgen.__version__ +if '+' in version: + version = version.split('+') + version = ''.join((version[0], ' (+', version[1].split('.')[0], ')')) # The full version, including alpha/beta/rc tags. release = randomgen.__version__ - # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. diff --git a/_randomgen/github_deploy_key_bashtage_core_prng.enc b/_randomgen/github_deploy_key_bashtage_core_prng.enc deleted file mode 100644 index 9487482f0020..000000000000 --- a/_randomgen/github_deploy_key_bashtage_core_prng.enc +++ /dev/null @@ -1 +0,0 @@ -gAAAAABaqV7yewp22viHuCymP0zVSCFUAlMJZNQH8yFM6OA7KVDd3CIx2b0SLNfMMq6--IyeHF7Gi5wg7UtT6dRo60F7h5-PrZx8iJjA9hqR0ovbZMPaXOQuLlnWYdw9oIBO976w93pDojwv_3QxUsDgRgmUOG7mERkitM8ihvDN17YbAZ_yyh5aX7NTbRr6DoaeL6UQkqfkaZpoflTRRRVIiJoI3aDi8jEDwhEhS_KeDP1fOnJEaJH7nR-zvRveAgbotla4XlW8IUiUP6hiOyGbk3mXZd9J0W6CPAoKbe2CV_6J4rkKd0IteJN2jsYIeNlvBf2BJ5kaIIXte6afejhyrSYcCzEgun5EuiDkqan4f0qgQSN7jjNX9vHNZ0aHNJ8HfvNFTN4fGF2xL3bPAJtGXaqIHEMF5USTRnNN5p0gKxCI5eeD73V-lpE4_LKV5OiWxC4zVFIL6BAEIdF5-cZ9Ikzqtklia17yZna3Rfbhc-0R8YYlpXWyT04c1FIIbHqNk6wsGYNyINTPTloJ6WWjwVD3oTmvFIJOBtR8Rfyk6GYM1PU2ybdbdUJc0iUXv2aL535IpnrK5Fnw4Q-lWSvI6VowJ5aY8GrnQJSyui8kA8BCkE1oblWtR6vmSwFZPjzvkZG2jUwnnaOluCjIzAm70llCO4_4b9IQkdsnNuBlVj1EYDYZQTMe4QJnBoCvB9joFp5dYauoODPcmjrXBCb8Eglg8PAAvVfLeldX2MkFGrv80pxIcN0xsI5qZmmJQOCidHEFSRLCq5Txu7OBOPCtbefs_C4mJdf7iF-F8F0DEOfr5g9CnmbIFzLomsYTzW_M4rqpkF8fxxgd5JwqRsSS36Pm6U8fb8ufpY_e4kUOd3F4qjhFK7PmPYLFdoTAaJobcgMHYNW4Y0KNTKuJM0tf51ysH4Br0EoR3CnzbBcKsgkb74OWzdgbwCdV5zvJl_b36tdd-CRZwA5A85yacuZzrVDJVYrPGwG_7Hsl7WXw-O4sVBaG_yumS1U2nC8y-gTomkvLOHq-fs27mSzcPRApC8d9C2KU9lmvgQPd7OtkPRPeypRPzU5A5UJ_EJVyG4ETUiw-bBLn_viz2HIKEg9wz0i16RSWZkpXHMzMzui2B14vp-RSjSXxK-Ou8dkTDbmw68yIzs4nHUoFA8ZN1CxUzQ2DpUzN9AcLy7q3KGh-XEIBYofsFkPbWYw-KdJi3mOYijShG-4hLGq7YI1r6VGj5Pc9Arh5zdZ_yx8PTz-g6e2-N0dvFfmNmX-bPAsIA5F8UwUVBKFP50vuJ19s8eqsnkrgTSbbF6BTOAifugLODKMeI5UANi-hCUhX3CXRIaOSzg54Ym6e-0suEQ1QygdRsVR4RU1mDf8Za6ZVEYbhuXRVwNnuSzljBjm-ejVAEcgMiTR-lzmu3kcFH_ciHLkO2kJRvv7JkFuDzux1IHM5gcBVYujIMuSFrnAUnuL2vgMfEr2DscSFmezEJz_V1R9NuY3y7hIDitQEAeXUJyUTFwDrFufGqF3IaS2nc6J-aAKVzyGm7JInrpNPH5yyMzEhVLk2V-H-kHSkCZAe240nQ2C0-eKtNCblbOVbfSCkFk2iohUkWK4A8sXSvcDELjCKzkctIANtusdFFEBEu0RswoBouQOICoP7d8ySyGs3XMDDBU_WL_TQk2TAXkVvMEvLLfDxj80JTtqyylD0XDblww6wgVt23KQpvCEpYQB_Ho0NIfkT3qgoDvUuMlz6k8L48AN58mUkqv1a6mhvc86KXsLcYYvwKO33-ErSd6FJKrEKPWr51v6RWpoO5J3ubqSxG_zekchPQ7EnJpHomTlCFK9u-_v4Tr_lTLtDW3vFIfWOyA4LvSVGp05x_HO4MBxL_XNwNzqG8tNJ5fDkOtLxCKWhoHpeA-_zIEFlfGPsfY2j8P-FAR6VyFTecTIFGJGb6ygZL-dGwJeH-FXjdRPMlD_dHxEqxx-JGHlTM297w7yTue80FosiiCkmwJ6BNQJCf-0gom2_ahJgNY_wj0psjLEkIK3pAijICcbZHBYYLyvVDn7llaUc4ziWt-TBego-Nd-5LMl9St0AdBLbGQ0AQqvm5F6MUxnp-KiDNcW0imWXePbqo7Eb4_3SE7mkeHIQY3Tssm_G7sAd6O6Q-V68tfWP8fHWOilaDeIJlahDpUbN3ygLMZwAjaDA0O6g6rSbYGSJtNIBh1VdDGBDOG9pyaRsLIMlxgtjQ7lQPQ44JQzwSa-93tpJQbA2-S_f4SaXt15HVbfr5YeJKcgHJQZfV_Ibi9cWFRp-v12wbPXJ2CkBZXUfzRiW0yR1tlsIxJUreL6SuMvnGulCsw5pbPXvyGOBPhQmKi_JCsanm1_OqQV_5-3p3g2MriHai48kbueoAwV06H9hXFtgZmDcnu8h_99Ld6vpI346xoDo4ShvJC9fU8sGf07zf9zKfpHUberx0mOU4hpyfx4xpAtPJS2ZKni2x2HJuVJkeyPWDIT2kNOOW5G04AnXhrve9CGXDRNIsjeV_q96i1hEaelLGdGkylkHQCJesJDXGN2Kc5QtYaEwRYV7MOdPiaLbPhXwrh2O25UyE-Zjc0UtV-uTCVlQon1nJWk-qyHllDZYxt1AUcwF8EXlG9G1nO7zHFnm68SmC7-Rv6z374YEio3q6PmJzAISd9I4JCPWxrnEPdUtUo8xChttRHys2AzNLRt_WbEtewf5jUeLCtmaRdLbgG-LxBa8IXRLTaQuEw1MH5nsewdoylt-0besWoyhKDtT7oQit7b3gHnCEP3BNSlqmQHodIw0KCC4YH4g4MOVB3YjvBO7lYVCNVyKFQvk2mwo0mKa_H9laljd95pikVuUphoTcbA_fneij-yaUFDu0lVFtio5Tjp7ek2ASxjzuaOgFcdY8LZmCkCx8D0ss8TOsph1JfkIA_rkkOElDc6EROJ-5eTBhQQekcIURltgRjKdrql0T8pD3FPC2Qsv6VMHyFMEpIW7qykJLwoxoendlc7bLNM7DSoIBeqOzY1vRQK1Z1fLFZVwxmtM8P6Up-Lf0aHMpe1jMkKASmj6Xtt-6jiFwS5gTSD_1tiALLgD75HZM88Hrk8zYzfr9MDTEMOiPHIjYfubsO4sve8BD12kh3CyQV26S8573TdaNRlLmTRt4YBi49--xlSrNBP6sqqoN6ZT_S0uA1JAgMHmf4Jr7DRxTfp_qpbjXvCtq7HWowhAsw4oQuF8VSx-PZZM_uzEwjHaR6TpHR3_OkjlbRBL8xR84qCgNjhFze_NxAqIbSuMoRt-n3Dv18Z7bjfokJfPTXS6FA618fZNnryIAyTZsmxjFvywwRRpiFNg6PgXB2LKHGOxpxP8nenfBJAWXD9NodI_sTS7QyaEqUp4lGEcADgLYNNDe77HyhZV1tirHesUE9CwbX-X3Nx_KQ6MhSzIZQn6AiAar5JzenyJV2kRX7Pg_tXYLQLaahnobpCBXpHuDe2_p933SdMU5xsNXQEE4ldJ_R9wfEqlgur5JCiXagLRxjzdrQIBMDXA2pfxu75ow0x7k3-Q9NrNKQQnt7R8HKItSg3m8k0XKSzJ4qgkHeRDdyzlZdA70qcCin4SiF1dYQPRinUjhEiiYdAuxOqOSNJeynwhw3-1NgitiPg03ORP0HAwlUF_SilOjhhCvTG6qQwBLjCIXjsGRNi8HDloIr2JD0gO-pfOsi89QzEm4LkdnQISmVOUFSHQsO4vGtQsnysHpccpNbo63PIEAIX9N9Cnwpi_3ZXcppUfT5FD3s_0R20sqCchys680bRVJivQh3eE79ROHKest_Uxusp14efvKocldd5B8pT9UPh5Y3ZSB2pnFBESYX0Zae3quRF6atlqbtfocixF78a4Rb1H1ZU9opJUbE5YKyQkmWtbbtDsV0OueN2ckC2gyeHtmaJmgne7oxm6JP1f1C68_-YBOGEHaG2MLW1ZS5a5F-3IGLwl6DboRRcV44Q7H5GKr-WuhjTnAlKPB-4ZfxpxCkFd9NKF3LFkrozvsJsKUqC0MdTw0oDNkO3wIxnhmJkAxJbHK0H-XQ7hDRNf_1ajj71kgP3Iv36qQdLqTvH1EBj1Buqe6T5tfKs-ijAmP8Z0ycJ45RMeAf-PEd67NKqdQHSwbhjw0FsP1LTaBQ5TUDjmITPp_nkpmhjRx70o4mm11D_05YwS3qf7-Avf2emZUGY8Ql7lSqFqblWG4DX1pqD15k4f0Vl38M6BysRu-nd7PqERV-KkvRo-LhhTbR313AtptTurr9BXnB4UN_7s86S22m8RAwMDAXURYVv-Dvy6KuITJTd8AP46Z9f0veQUpidA7wGlApOliDZezM_2qskKnF0lmp3ujuO2H2yPGIj7en0s3VwqXTC4fE8dggF6q2mgfBcrBCSd1Mf9lEs= \ No newline at end of file From c8454c9ebe1298ba98b577257d21abf39b3e8ea6 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Mar 2018 23:26:00 +0000 Subject: [PATCH 085/279] DOC: Change theme Change to guzzle --- _randomgen/.gitignore | 2 ++ _randomgen/README.md | 4 ++-- _randomgen/doc/source/conf.py | 23 +++++++++++++++++++---- _randomgen/randomgen/__init__.py | 20 ++++++++++---------- _randomgen/setup.py | 2 +- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/_randomgen/.gitignore b/_randomgen/.gitignore index df53d2597f1b..381421b399e9 100644 --- a/_randomgen/.gitignore +++ b/_randomgen/.gitignore @@ -9,6 +9,8 @@ build/ **/Random123 settings.json *.so +randomgen/bounded_integers.pyx +randomgen/bounded_integers.pxd randomgen/bounded_integers.c randomgen/common.c randomgen/dsfmt.c diff --git a/_randomgen/README.md b/_randomgen/README.md index 93b0e461b0be..11939e30008f 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -1,7 +1,7 @@ # RandomGen -[![Travis Build Status](https://travis-ci.org/bashtage/core-prng.svg?branch=master)](https://travis-ci.org/bashtage/core-prng) -[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true)](https://ci.appveyor.com/project/bashtage/core-prng/branch/master) +[![Travis Build Status](https://travis-ci.org/bashtage/randomgen.svg?branch=master)](https://travis-ci.org/bashtage/randomgen) +[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true)](https://ci.appveyor.com/project/bashtage/randomgen/branch/master) Random Number Generator using settable Basic RNG interface for future NumPy RandomState evolution. diff --git a/_randomgen/doc/source/conf.py b/_randomgen/doc/source/conf.py index 619272db3c6a..fd9adb227164 100644 --- a/_randomgen/doc/source/conf.py +++ b/_randomgen/doc/source/conf.py @@ -16,8 +16,8 @@ # import sys # sys.path.insert(0, os.path.abspath('.')) from distutils.version import LooseVersion -# import guzzle_sphinx_theme -import sphinx_rtd_theme +import guzzle_sphinx_theme +# import sphinx_rtd_theme import randomgen # -- Project information ----------------------------------------------------- @@ -89,14 +89,26 @@ # a list of builtin themes. # # html_theme = 'alabaster' -html_theme = 'sphinx_rtd_theme' -html_theme_path = ["_themes", ] +# html_theme = 'sphinx_rtd_theme' +# html_theme_path = ["_themes", ] # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} +html_theme_path = guzzle_sphinx_theme.html_theme_path() +html_theme = 'guzzle_sphinx_theme' + +# Register the theme as an extension to generate a sitemap.xml +extensions.append("guzzle_sphinx_theme") + +# Guzzle theme options (see theme.conf for more information) +html_theme_options = { + # Set the name of the project to appear in the sidebar + "project_nav_name": project + u" " + version, +} + # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". @@ -111,6 +123,9 @@ # 'searchbox.html']``. # # html_sidebars = {} +html_sidebars = { + '**': ['logo-text.html', 'globaltoc.html', 'searchbox.html'] +} # -- Options for HTMLHelp output --------------------------------------------- diff --git a/_randomgen/randomgen/__init__.py b/_randomgen/randomgen/__init__.py index fdddc4ab40d8..43ee16e90904 100644 --- a/_randomgen/randomgen/__init__.py +++ b/_randomgen/randomgen/__init__.py @@ -1,13 +1,13 @@ -from .dsfmt import DSFMT -from .generator import * -from .mt19937 import MT19937 -from .pcg32 import PCG32 -from .pcg64 import PCG64 -from .philox import Philox -from .threefry import ThreeFry -from .threefry32 import ThreeFry32 -from .xoroshiro128 import Xoroshiro128 -from .xorshift1024 import Xorshift1024 +from randomgen.dsfmt import DSFMT +from randomgen.generator import * +from randomgen.mt19937 import MT19937 +from randomgen.pcg32 import PCG32 +from randomgen.pcg64 import PCG64 +from randomgen.philox import Philox +from randomgen.threefry import ThreeFry +from randomgen.threefry32 import ThreeFry32 +from randomgen.xoroshiro128 import Xoroshiro128 +from randomgen.xorshift1024 import Xorshift1024 __all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'PCG32', 'Philox', 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024', diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 11704f3516cc..a80d51a83387 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -207,7 +207,7 @@ def is_pure(self): author_email='kevin.k.sheppard@gmail.com', distclass=BinaryDistribution, description='Random generator supporting multiple PRNGs', - url='https://github.com/bashtage/core-prng', + url='https://github.com/bashtage/randomgen', keywords=['pseudo random numbers', 'PRNG', 'Python'], zip_safe=False ) From 4127240993d0c8fb2f1685892e826e26fa9318c1 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Mar 2018 08:14:54 +0000 Subject: [PATCH 086/279] DOC: Add docstring for MT19937 Add docstring for MT19937 Remove references to randomstate Fix ccp errors --- _randomgen/README.md | 7 +- _randomgen/randomgen/bounded_integers.pyx | 18 +-- _randomgen/randomgen/bounded_integers.pyx.in | 2 +- _randomgen/randomgen/dsfmt.pyx | 2 +- _randomgen/randomgen/entropy.pyx | 2 +- _randomgen/randomgen/generator.pyx | 6 +- _randomgen/randomgen/mt19937.pyx | 117 ++++++++++++++++--- _randomgen/randomgen/pcg32.pyx | 8 +- _randomgen/randomgen/pcg64.pyx | 8 +- _randomgen/randomgen/philox.pyx | 6 +- _randomgen/randomgen/pickle.py | 4 +- _randomgen/randomgen/threefry.pyx | 6 +- _randomgen/randomgen/threefry32.pyx | 6 +- _randomgen/randomgen/xoroshiro128.pyx | 4 +- _randomgen/randomgen/xorshift1024.pyx | 8 +- 15 files changed, 144 insertions(+), 60 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index 11939e30008f..c4bf69f45711 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -116,13 +116,10 @@ the RNG._ ## Status -* Replacement for `numpy.random.RandomState`. The - `MT19937` generator is identical to `numpy.random.RandomState`, and - will produce an identical sequence of random numbers for a given seed. * Builds and passes all tests on: * Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 (probably works on 2.6 and 3.3) * PC-BSD (FreeBSD) 64-bit, Python 2.7 - * OSX 64-bit, Python 2.7 + * OSX 64-bit, Python 3.6 * Windows 32/64 bit (only tested on Python 2.7, 3.5 and 3.6, but should work on 3.3/3.4) @@ -139,7 +136,7 @@ An occasionally updated build of the documentation is available on This module is essentially complete. There are a few rough edges that need to be smoothed. -* Creation of additional streams from a RandomState where supported +* Creation of additional streams from where supported (i.e. a `next_stream()` method) ## Requirements diff --git a/_randomgen/randomgen/bounded_integers.pyx b/_randomgen/randomgen/bounded_integers.pyx index fe47bcb8a2e9..c9fb310c64ff 100644 --- a/_randomgen/randomgen/bounded_integers.pyx +++ b/_randomgen/randomgen/bounded_integers.pyx @@ -523,7 +523,7 @@ cdef object _rand_uint64(object low, object high, object size, brng_t *state, ob state : basic random state State to use in the core random number generators lock : threading.Lock - Lock to prevent multiple using a single RandomState simultaneously + Lock to prevent multiple using a single generator simultaneously Returns ------- @@ -599,7 +599,7 @@ cdef object _rand_uint32(object low, object high, object size, brng_t *state, ob state : basic random state State to use in the core random number generators lock : threading.Lock - Lock to prevent multiple using a single RandomState simultaneously + Lock to prevent multiple using a single generator simultaneously Returns ------- @@ -675,7 +675,7 @@ cdef object _rand_uint16(object low, object high, object size, brng_t *state, ob state : basic random state State to use in the core random number generators lock : threading.Lock - Lock to prevent multiple using a single RandomState simultaneously + Lock to prevent multiple using a single generator simultaneously Returns ------- @@ -751,7 +751,7 @@ cdef object _rand_uint8(object low, object high, object size, brng_t *state, obj state : basic random state State to use in the core random number generators lock : threading.Lock - Lock to prevent multiple using a single RandomState simultaneously + Lock to prevent multiple using a single generator simultaneously Returns ------- @@ -827,7 +827,7 @@ cdef object _rand_bool(object low, object high, object size, brng_t *state, obje state : basic random state State to use in the core random number generators lock : threading.Lock - Lock to prevent multiple using a single RandomState simultaneously + Lock to prevent multiple using a single generator simultaneously Returns ------- @@ -903,7 +903,7 @@ cdef object _rand_int64(object low, object high, object size, brng_t *state, obj state : basic random state State to use in the core random number generators lock : threading.Lock - Lock to prevent multiple using a single RandomState simultaneously + Lock to prevent multiple using a single generator simultaneously Returns ------- @@ -979,7 +979,7 @@ cdef object _rand_int32(object low, object high, object size, brng_t *state, obj state : basic random state State to use in the core random number generators lock : threading.Lock - Lock to prevent multiple using a single RandomState simultaneously + Lock to prevent multiple using a single generator simultaneously Returns ------- @@ -1055,7 +1055,7 @@ cdef object _rand_int16(object low, object high, object size, brng_t *state, obj state : basic random state State to use in the core random number generators lock : threading.Lock - Lock to prevent multiple using a single RandomState simultaneously + Lock to prevent multiple using a single generator simultaneously Returns ------- @@ -1131,7 +1131,7 @@ cdef object _rand_int8(object low, object high, object size, brng_t *state, obje state : basic random state State to use in the core random number generators lock : threading.Lock - Lock to prevent multiple using a single RandomState simultaneously + Lock to prevent multiple using a single generator simultaneously Returns ------- diff --git a/_randomgen/randomgen/bounded_integers.pyx.in b/_randomgen/randomgen/bounded_integers.pyx.in index d464e9e2c841..ff4885130cf8 100644 --- a/_randomgen/randomgen/bounded_integers.pyx.in +++ b/_randomgen/randomgen/bounded_integers.pyx.in @@ -180,7 +180,7 @@ cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state state : basic random state State to use in the core random number generators lock : threading.Lock - Lock to prevent multiple using a single RandomState simultaneously + Lock to prevent multiple using a single generator simultaneously Returns ------- diff --git a/_randomgen/randomgen/dsfmt.pyx b/_randomgen/randomgen/dsfmt.pyx index cec90994346c..040d5a719c5a 100644 --- a/_randomgen/randomgen/dsfmt.pyx +++ b/_randomgen/randomgen/dsfmt.pyx @@ -84,7 +84,7 @@ cdef class DSFMT: Notes ----- ``DSFMT`` directly provides generators for doubles, and unsigned 32 and 64- - bit integers [1]_ . These are not firectly available and must b consumed + bit integers [1]_ . These are not firectly available and must be consumed via a ``RandomGenerator`` object. The Python stdlib module "random" also contains a Mersenne Twister diff --git a/_randomgen/randomgen/entropy.pyx b/_randomgen/randomgen/entropy.pyx index cec1bb9a81b6..bb1c14b4b32d 100644 --- a/_randomgen/randomgen/entropy.pyx +++ b/_randomgen/randomgen/entropy.pyx @@ -118,7 +118,7 @@ def random_entropy(size=None, source='system'): This function reads from the system entropy pool and so samples are not reproducible. In particular, it does *NOT* make use of a - RandomState, and so ``seed``, ``get_state`` and ``set_state`` have no + basic RNG, and so ``seed`` and setting ``state`` have no effect. Raises RuntimeError if the command fails. diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 5ae857e9c425..d878d502f0f6 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -506,8 +506,8 @@ cdef class RandomGenerator: Examples -------- - >>> RS = randomgen.mtrand.RandomState() # need a RandomState object - >>> RS.tomaxint((2,2,2)) + >>> rg = randomgen.RandomGenerator() # need a RandomGenerator object + >>> rg.tomaxint((2,2,2)) array([[[1170048599, 1600360186], [ 739731006, 1947757578]], [[1871712945, 752307660], @@ -515,7 +515,7 @@ cdef class RandomGenerator: >>> import sys >>> sys.maxint 2147483647 - >>> RS.tomaxint((2,2,2)) < sys.maxint + >>> rg.tomaxint((2,2,2)) < sys.maxint array([[[ True, True], [ True, True]], [[ True, True], diff --git a/_randomgen/randomgen/mt19937.pyx b/_randomgen/randomgen/mt19937.pyx index c66f89a03e95..dfcf24fd2357 100644 --- a/_randomgen/randomgen/mt19937.pyx +++ b/_randomgen/randomgen/mt19937.pyx @@ -43,17 +43,76 @@ cdef uint64_t mt19937_raw(void *st) nogil: cdef class MT19937: """ - Prototype Basic RNG using MT19937 + MT19937(seed=None) + + Container for the Mersenne Twister pseudo-random number generator. Parameters ---------- - seed : int, array of int - Integer or array of integers between 0 and 2**64 - 1 + seed : {None, int, array_like}, optional + Random seed used to initialize the pseudo-random number generator. Can + be any integer between 0 and 2**32 - 1 inclusive, an array (or other + sequence) of such integers, or ``None`` (the default). If `seed` is + ``None``, then will attempt to read data from ``/dev/urandom`` + (or the Windows analog) if available or seed from the clock otherwise. Notes ----- - Exposes no user-facing API except `state`. Designed for use in a - `RandomGenerator` object. + ``MT19937`` directly provides generators for doubles, and unsigned 32 and 64- + bit integers [1]_ . These are not firectly available and must be consumed + via a ``RandomGenerator`` object. + + The Python stdlib module "random" also contains a Mersenne Twister + pseudo-random number generator. + + **State and Seeding** + + The ``MT19937`` state vector consists of a 768 element array of + 32-bit unsigned integers plus a single integer value between 0 and 768 + indicating the current position within the main array. + + ``MT19937`` is seeded using either a single 32-bit unsigned integer + or a vector of 32-bit unsigned integers. In either case, the input seed is + used as an input (or inputs) for a hashing function, and the output of the + hashing function is used as the initial state. Using a single 32-bit value + for the seed can only initialize a small range of the possible initial + state values. + + **Compatibility Guarantee** + + ``MT19937`` make a compatibility guarantee. A fixed seed and a fixed + series of calls to ``MT19937`` methods will always produce the same + results up to roundoff error except when the values were incorrect. + Incorrect values will be fixed and the version in which the fix was + made will be noted in the relevant docstring. + + **Parallel Features** + + ``MT19937`` can be used in parallel applications by + calling the method ``jump`` which advances the state as-if :math:`2^{128}` + random numbers have been generated ([1]_, [2]_). This allows the original sequence to + be split so that distinct segments can be used in each worker process. All + generators should be initialized with the same seed to ensure that the + segments come from the same sequence. + + >>> from randomgen.entropy import random_entropy + >>> from randomgen import RandomGenerator, MT19937 + >>> seed = random_entropy() + >>> rs = [RandomGenerator(MT19937(seed) for _ in range(10)] + # Advance rs[i] by i jumps + >>> for i in range(10): + rs[i].jump(i) + + References + ---------- + .. [1] Hiroshi Haramoto, Makoto Matsumoto, and Pierre L\'Ecuyer, "A Fast + Jump Ahead Algorithm for Linear Recurrences in a Polynomial Space", + Sequences and Their Applications - SETA, 290--298, 2008. + .. [2] Hiroshi Haramoto, Makoto Matsumoto, Takuji Nishimura, François + Panneton, Pierre L\'Ecuyer, "Efficient Jump Ahead for F2-Linear + Random Number Generators", INFORMS JOURNAL ON COMPUTING, Vol. 20, + No. 3, Summer 2008, pp. 385-390. + """ cdef mt19937_state *rng_state cdef brng_t *_brng @@ -134,18 +193,20 @@ cdef class MT19937: def seed(self, seed=None): """ - seed(seed=None, stream=None) + seed(seed=None) Seed the generator. - This method is called when ``RandomState`` is initialized. It can be - called again to re-seed the generator. For details, see - ``RandomState``. - Parameters ---------- - seed : int, optional - Seed for ``RandomState``. + seed : {None, int, array_like}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**32-1], array of integers in + [0, 2**32-1] or ``None`` (the default). If `seed` is ``None``, + then ``MT19937`` will try to read entropy from ``/dev/urandom`` + (or the Windows analog) if available to produce a 64-bit + seed. If unavailable, a 64-bit hash of the time and process + ID is used. Raises ------ @@ -174,13 +235,39 @@ cdef class MT19937: obj = obj.astype(np.uint32, casting='unsafe', order='C') mt19937_init_by_array(self.rng_state, obj.data, np.PyArray_DIM(obj, 0)) - def jump(self): - mt19937_jump(self.rng_state) + def jump(self, np.npy_intp iter=1): + """ + jump(iter=1) + + Jumps the state of the random number generator as-if 2**128 random numbers + have been generated. + + Parameters + ---------- + iter : integer, positive + Number of times to jump the state of the brng. + + Returns + ------- + self : DSFMT + PRNG jumped iter times + """ + cdef np.npy_intp i + for i in range(iter): + mt19937_jump(self.rng_state) return self @property def state(self): - """Get or set the PRNG state""" + """ + Get or set the PRNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the PRNG + """ key = np.zeros(624, dtype=np.uint32) for i in range(624): key[i] = self.rng_state.key[i] diff --git a/_randomgen/randomgen/pcg32.pyx b/_randomgen/randomgen/pcg32.pyx index a2cb4c71ec23..b739a12b5d7f 100644 --- a/_randomgen/randomgen/pcg32.pyx +++ b/_randomgen/randomgen/pcg32.pyx @@ -95,7 +95,7 @@ cdef class PCG32: >>> from randomgen import RandomGenerator, PCG32 >>> rg = [RandomGenerator(PCG32(1234, i + 1)) for i in range(10)] - The alternative method is to call ``advance`` on a single RandomState to + The alternative method is to call ``advance`` on a instance to produce non-overlapping sequences. >>> rg = [RandomGenerator(PCG32(1234, i + 1)) for i in range(10)] @@ -200,14 +200,14 @@ cdef class PCG32: Seed the generator. - This method is called when ``RandomState`` is initialized. It can be + This method is called when ``PCG32`` is initialized. It can be called again to re-seed the generator. For details, see - ``RandomState``. + ``PCG32``. Parameters ---------- seed : int, optional - Seed for ``RandomState``. + Seed for ``PCG32``. inc : int, optional Increment to use for PCG stream diff --git a/_randomgen/randomgen/pcg64.pyx b/_randomgen/randomgen/pcg64.pyx index bd3a24440c44..249587a49e5d 100644 --- a/_randomgen/randomgen/pcg64.pyx +++ b/_randomgen/randomgen/pcg64.pyx @@ -110,7 +110,7 @@ cdef class PCG64: >>> from randomgen import RandomGenerator, PCG64 >>> rg = [RandomGenerator(PCG64(1234, i + 1)) for i in range(10)] - The alternative method is to call ``advance`` on a single RandomState to + The alternative method is to call ``advance`` on a single instance to produce non-overlapping sequences. >>> rg = [RandomGenerator(PCG64(1234, i + 1)) for i in range(10)] @@ -221,14 +221,14 @@ cdef class PCG64: Seed the generator. - This method is called when ``RandomState`` is initialized. It can be + This method is called when ``PCG64`` is initialized. It can be called again to re-seed the generator. For details, see - ``RandomState``. + ``PCG64``. Parameters ---------- seed : int, optional - Seed for ``RandomState``. + Seed for ``PCG64``. inc : int, optional Increment to use for PCG stream diff --git a/_randomgen/randomgen/philox.pyx b/_randomgen/randomgen/philox.pyx index 75213ef5aa58..34bcefc61b49 100644 --- a/_randomgen/randomgen/philox.pyx +++ b/_randomgen/randomgen/philox.pyx @@ -227,14 +227,14 @@ cdef class Philox: Seed the generator. - This method is called when ``RandomState`` is initialized. It can be + This method is called when ``Philox`` is initialized. It can be called again to re-seed the generator. For details, see - ``RandomState``. + ``Philox``. Parameters ---------- seed : int, optional - Seed for ``RandomState``. + Seed for ``Philox``. counter : {int array}, optional Positive integer less than 2**256 containing the counter position or a 4 element array of uint64 containing the counter diff --git a/_randomgen/randomgen/pickle.py b/_randomgen/randomgen/pickle.py index 4ec96663d4a3..dbb5324e40dc 100644 --- a/_randomgen/randomgen/pickle.py +++ b/_randomgen/randomgen/pickle.py @@ -22,7 +22,7 @@ def __generator_ctor(brng_name='mt19937'): """ - Pickling helper function that returns a mod_name.RandomState object + Pickling helper function that returns a RandomGenerator object Parameters ---------- @@ -48,7 +48,7 @@ def __generator_ctor(brng_name='mt19937'): def __brng_ctor(brng_name='mt19937'): """ - Pickling helper function that returns a mod_name.RandomState object + Pickling helper function that returns a basic RNG object Parameters ---------- diff --git a/_randomgen/randomgen/threefry.pyx b/_randomgen/randomgen/threefry.pyx index 47dde07e0bd2..36dd12de840d 100644 --- a/_randomgen/randomgen/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -222,14 +222,14 @@ cdef class ThreeFry: Seed the generator. - This method is called when ``RandomState`` is initialized. It can be + This method is called when ``ThreeFry`` is initialized. It can be called again to re-seed the generator. For details, see - ``RandomState``. + ``ThreeFry``. Parameters ---------- seed : int, optional - Seed for ``RandomState``. + Seed for ``ThreeFry``. counter : {None, int array}, optional Positive integer less than 2**256 containing the counter position or a 4 element array of uint64 containing the counter diff --git a/_randomgen/randomgen/threefry32.pyx b/_randomgen/randomgen/threefry32.pyx index 70210910c6d0..e03f2416a682 100644 --- a/_randomgen/randomgen/threefry32.pyx +++ b/_randomgen/randomgen/threefry32.pyx @@ -222,14 +222,14 @@ cdef class ThreeFry32: Seed the generator. - This method is called when ``RandomState`` is initialized. It can be + This method is called when ``ThreeFry32`` is initialized. It can be called again to re-seed the generator. For details, see - ``RandomState``. + ``ThreeFry32``. Parameters ---------- seed : int, optional - Seed for ``RandomState``. + Seed for ``ThreeFry32``. counter : {int array}, optional Positive integer less than 2**128 containing the counter position or a 4 element array of uint32 containing the counter diff --git a/_randomgen/randomgen/xoroshiro128.pyx b/_randomgen/randomgen/xoroshiro128.pyx index ae02372898df..e7ffeb0e20e0 100644 --- a/_randomgen/randomgen/xoroshiro128.pyx +++ b/_randomgen/randomgen/xoroshiro128.pyx @@ -46,13 +46,13 @@ cdef class Xoroshiro128: Random seed initializing the pseudo-random number generator. Can be an integer in [0, 2**64-1], array of integers in [0, 2**64-1] or ``None`` (the default). If `seed` is ``None``, - then ``xoroshiro128plus.RandomState`` will try to read data from + then ``Xoroshiro128`` will try to read data from ``/dev/urandom`` (or the Windows analog) if available. If unavailable, a 64-bit hash of the time and process ID is used. Notes ----- - xoroshiro128+ is the successor to xorshift128+ written by David Blackman and + xoroshiro128+ is the successor to xorshift128+ written by David Blackman and Sebastiano Vigna. It is a 64-bit PRNG that uses a carefully handcrafted shift/rotate-based linear transformation. This change both improves speed and statistical quality of the PRNG [1]_. xoroshiro128+ has a period of diff --git a/_randomgen/randomgen/xorshift1024.pyx b/_randomgen/randomgen/xorshift1024.pyx index 86fd5d5f1346..140923e7fc96 100644 --- a/_randomgen/randomgen/xorshift1024.pyx +++ b/_randomgen/randomgen/xorshift1024.pyx @@ -62,7 +62,7 @@ cdef class Xorshift1024: Random seed initializing the pseudo-random number generator. Can be an integer in [0, 2**64-1], array of integers in [0, 2**64-1] or ``None`` (the default). If `seed` is ``None``, - then ``xorshift1024.RandomState`` will try to read data from + then ``Xorshift1024`` will try to read data from ``/dev/urandom`` (or the Windows analog) if available. If unavailable, a 64-bit hash of the time and process ID is used. @@ -212,14 +212,14 @@ cdef class Xorshift1024: Seed the generator. - This method is called when ``RandomState`` is initialized. It can be + This method is called when ``Xorshift1024`` is initialized. It can be called again to re-seed the generator. For details, see - ``RandomState``. + ``Xorshift1024``. Parameters ---------- seed : int, optional - Seed for ``RandomState``. + Seed for ``Xorshift1024``. Raises ------ From 7dd6b6db62eb6550f9a4bafc0c1b47baa99d177e Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Mar 2018 10:18:30 +0000 Subject: [PATCH 087/279] DOC: Update conf Update sphinx conf --- _randomgen/.travis.yml | 2 -- _randomgen/doc/source/conf.py | 8 +++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 94c17b200c19..a42786d0e0e5 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -63,8 +63,6 @@ script: fi - | if [[ -z ${NUMPY} && ${TRAVIS_OS_NAME} == "linux" ]]; then - ls - echo $PWD cd ${BUILD_DIR}/doc make html make html diff --git a/_randomgen/doc/source/conf.py b/_randomgen/doc/source/conf.py index fd9adb227164..c89900b5579f 100644 --- a/_randomgen/doc/source/conf.py +++ b/_randomgen/doc/source/conf.py @@ -47,6 +47,9 @@ extensions = [ 'sphinx.ext.napoleon', 'sphinx.ext.autodoc', + 'sphinx.ext.extlinks', + 'sphinx.ext.todo', + 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.autosummary', 'sphinx.ext.mathjax', @@ -97,6 +100,7 @@ # # html_theme_options = {} +html_translator_class = 'guzzle_sphinx_theme.HTMLTranslator' html_theme_path = guzzle_sphinx_theme.html_theme_path() html_theme = 'guzzle_sphinx_theme' @@ -127,6 +131,8 @@ '**': ['logo-text.html', 'globaltoc.html', 'searchbox.html'] } +# If false, no module index is generated. +html_domain_indices = True # -- Options for HTMLHelp output --------------------------------------------- @@ -180,7 +186,7 @@ # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'RandomGen', 'RandomGen Documentation', - author, 'RandomGen', 'One line description of project.', + author, 'RandomGen', 'Alternative random number generators for Python.', 'Miscellaneous'), ] From 64a44a6ea58388b0d274be4dbf25147e9c8d69c1 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Mar 2018 10:37:39 +0000 Subject: [PATCH 088/279] DOC: Improve doc build Ensure only tagged builds are pushed to root --- _randomgen/.travis.yml | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index a42786d0e0e5..81702275578f 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -24,7 +24,7 @@ matrix: - os: linux env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.26] - os: linux - env: [PYTHON=3.6] + env: [PYTHON=3.6, DOCBUILD=true] - os: osx language: generic env: [PYTHON=3.6] @@ -46,10 +46,9 @@ before_install: - conda create -n randomgen-test ${PKGS} pytest setuptools nose --quiet - source activate randomgen-test - pip install tempita coverage coveralls pytest-cov codecov -q - # Docbuild - - if [[ -z ${NUMPY} && ${TRAVIS_OS_NAME} == "linux" ]]; then pip install sphinx sphinx_rtd_theme guzzle_sphinx_theme ipython doctr -q; fi - - if [[ -z ${NUMPY} && ${TRAVIS_OS_NAME} == "linux" ]]; then conda install numba pandas matplotlib --quiet; fi - export BUILD_DIR=${PWD} + - if [[ ${DOCBUILD} == true ]]; then pip install sphinx sphinx_rtd_theme guzzle_sphinx_theme ipython doctr -q; fi + - if [[ ${DOCBUILD} == true ]]; then conda install numba pandas matplotlib --quiet; fi install: - python setup.py develop @@ -58,17 +57,23 @@ script: - set -e - pytest randomgen - | - if [[ -z ${NUMPY} ]]; then - python benchmark.py; - fi - - | - if [[ -z ${NUMPY} && ${TRAVIS_OS_NAME} == "linux" ]]; then + if [[ ${DOCBUILD} == true ]]; then cd ${BUILD_DIR}/doc make html make html cd ${BUILD_DIR} - doctr deploy doc - if [[ -n ${TRAVIS_TAG}} ]]; then + doctr deploy doc --build-tags + if [[ -z ${TRAVIS_TAG} ]]; then + echo "Not a tagged build." + else doctr deploy . --build-tags - fi; - fi; + fi + fi + +after_success: + - | + if [[ ${DOCBUILD} == true ]]; then + cd ${BUILD_DIR} + python benchmark.py; + fi + \ No newline at end of file From 3f89a8cdd7c0472e6511db3e905f6abfd20d4983 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Mar 2018 12:31:32 +0000 Subject: [PATCH 089/279] BLD: Improve setup Improve setup to include a long description --- _randomgen/MANIFEST.in | 8 +- _randomgen/README.rst | 279 +++++++++++++++++++++++++++++++++++++++++ _randomgen/setup.py | 44 ++++++- 3 files changed, 325 insertions(+), 6 deletions(-) create mode 100644 _randomgen/README.rst diff --git a/_randomgen/MANIFEST.in b/_randomgen/MANIFEST.in index c961f9101cd4..ffc3d5bee5d8 100644 --- a/_randomgen/MANIFEST.in +++ b/_randomgen/MANIFEST.in @@ -1,6 +1,6 @@ +exclude randomgen/entropy.c +recursive-exclude randomgen *.c include versioneer.py include randomgen/_version.py -recursive-include randomgen *.py *.pyx *.px[di] *.h *.in -recursive-include randomgen/src *.c - - +recursive-include randomgen *.py *.pyx *.px[di] *.h *.in *.csv +graft randomgen/src diff --git a/_randomgen/README.rst b/_randomgen/README.rst new file mode 100644 index 000000000000..16957a167310 --- /dev/null +++ b/_randomgen/README.rst @@ -0,0 +1,279 @@ +RandomGen +========= + +|Travis Build Status| |Appveyor Build Status| + +Random Number Generator using settable Basic RNG interface for future +NumPy RandomState evolution. + +This is a library and generic interface for alternative random +generators in Python and NumPy. + +Compatibility Warning +~~~~~~~~~~~~~~~~~~~~~ + +RandomGen no longer supports Box-Muller normal variates and so it not +100% compatible with NumPy (or randomstate). Box-Muller normals are slow +to generate and all functions which previously relied on Box-Muller +normals now use the faster Ziggurat implementation. + +Features +-------- + +- Replacement for NumPy's RandomState + +.. code:: python + + # import numpy.random as rnd + from randomgen import RandomGenerator, MT19937 + rnd = RandomGenerator(MT19937()) + x = rnd.standard_normal(100) + y = rnd.random_sample(100) + z = rnd.randn(10,10) + +- Default random generator is a fast generator called Xoroshiro128plus +- Support for random number generators that support independent streams + and jumping ahead so that sub-streams can be generated +- Faster random number generation, especially for normal, standard + exponential and standard gamma using the Ziggurat method + +.. code:: python + + from randomgen import RandomGenerator + # Use Xoroshiro128 + rnd = RandomGenerator() + w = rnd.standard_normal(10000, method='zig') + x = rnd.standard_exponential(10000, method='zig') + y = rnd.standard_gamma(5.5, 10000, method='zig') + +- Support for 32-bit floating randoms for core generators. Currently + supported: + + - Uniforms (``random_sample``) + - Exponentials (``standard_exponential``, both Inverse CDF and + Ziggurat) + - Normals (``standard_normal``) + - Standard Gammas (via ``standard_gamma``) + +**WARNING**: The 32-bit generators are **experimental** and subject to +change. + +**Note**: There are *no* plans to extend the alternative precision +generation to all distributions. + +- Support for filling existing arrays using ``out`` keyword argument. + Currently supported in (both 32- and 64-bit outputs) + + - Uniforms (``random_sample``) + - Exponentials (``standard_exponential``) + - Normals (``standard_normal``) + - Standard Gammas (via ``standard_gamma``) + +Included Pseudo Random Number Generators +---------------------------------------- + +This module includes a number of alternative random number generators in +addition to the MT19937 that is included in NumPy. The RNGs include: + +- `MT19937 `__, + the NumPy rng +- `dSFMT `__ a + SSE2-aware version of the MT19937 generator that is especially fast + at generating doubles +- `xoroshiro128+ `__ and + `xorshift1024\*φ `__ +- `PCG64 `__ +- ThreeFry and Philox from + `Random123 `__ + ## Differences from ``numpy.random.RandomState`` + +New Features +~~~~~~~~~~~~ + +- ``standard_normal``, ``normal``, ``randn`` and + ``multivariate_normal`` all use the much faster (100%+) Ziggurat + method. +- ``standard_gamma`` and ``gamma`` both use the much faster Ziggurat + method. +- ``standard_exponential`` ``exponential`` both support an additional + ``method`` keyword argument which can be ``inv`` or ``zig`` where + ``inv`` corresponds to the current method using the inverse CDF and + ``zig`` uses the much faster (100%+) Ziggurat method. +- Core random number generators can produce either single precision + (``np.float32``) or double precision (``np.float64``, the default) + using the optional keyword argument ``dtype`` +- Core random number generators can fill existing arrays using the + ``out`` keyword argument +- Standardizes integer-values random values as int64 for all platforms. + +New Functions +~~~~~~~~~~~~~ + +- ``random_entropy`` - Read from the system entropy provider, which is + commonly used in cryptographic applications +- ``random_raw`` - Direct access to the values produced by the + underlying PRNG. The range of the values returned depends on the + specifics of the PRNG implementation. +- ``random_uintegers`` - unsigned integers, either 32- + (``[0, 2**32-1]``) or 64-bit (``[0, 2**64-1]``) +- ``jump`` - Jumps RNGs that support it. ``jump`` moves the state a + great distance. *Only available if supported by the RNG.* +- ``advance`` - Advanced the RNG 'as-if' a number of draws were made, + without actually drawing the numbers. *Only available if supported by + the RNG.* + +Status +------ + +- Builds and passes all tests on: +- Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 (probably works on 2.6 and + 3.3) +- PC-BSD (FreeBSD) 64-bit, Python 2.7 +- OSX 64-bit, Python 3.6 +- Windows 32/64 bit (only tested on Python 2.7, 3.5 and 3.6, but should + work on 3.3/3.4) + +Version +------- + +The version matched the latest version of NumPy where +``RandoMGenerator(MT19937())`` passes all NumPy test. + +Documentation +------------- + +An occasionally updated build of the documentation is available on `my +GitHub pages `__. + +Plans +----- + +This module is essentially complete. There are a few rough edges that +need to be smoothed. + +- Creation of additional streams from where supported (i.e. a + ``next_stream()`` method) + +Requirements +------------ + +Building requires: + +- Python (2.7, 3.4, 3.5, 3.6) +- NumPy (1.10, 1.11, 1.12, 1.13, 1.14) +- Cython (0.25+) +- tempita (0.5+), if not provided by Cython + +Testing requires pytest (3.0+). + +**Note:** it might work with other versions but only tested with these +versions. + +Development and Testing +----------------------- + +All development has been on 64-bit Linux, and it is regularly tested on +Travis-CI (Linux/OSX) and Appveyor (Windows). The library is +occasionally tested on Linux 32-bit and Free BSD 11.1. + +Basic tests are in place for all RNGs. The MT19937 is tested against +NumPy's implementation for identical results. It also passes NumPy's +test suite where still relevant. + +Installing +---------- + +.. code:: bash + + python setup.py install + +SSE2 +~~~~ + +``dSFTM`` makes use of SSE2 by default. If you have a very old computer +or are building on non-x86, you can install using: + +.. code:: bash + + python setup.py install --no-sse2 + +Windows +~~~~~~~ + +Either use a binary installer, or if building from scratch, use Python +3.6 with Visual Studio 2015 Community Edition. It can also be build +using Microsoft Visual C++ Compiler for Python 2.7 and Python 2.7, +although some modifications may be needed to ``distutils`` to find the +compiler. + +Using +----- + +The separate generators are importable from ``randomgen`` + +.. code:: python + + from randomgen import RandomGenerator, ThreeFry, PCG64, MT19937 + rg = RandomGenerator(ThreeFry()) + rg.random_sample(100) + + rg = RandomGenerator(PCG64()) + rg.random_sample(100) + + # Identical to NumPy + rg = RandomGenerator(MT19937()) + rg.random_sample(100) + +License +------- + +Standard NCSA, plus sub licenses for components. + +Performance +----------- + +Performance is promising, and even the mt19937 seems to be faster than +NumPy's mt19937. + +:: + + Speed-up relative to NumPy (Uniform Doubles) + ************************************************************ + DSFMT 137.1% + MT19937 21.0% + PCG32 101.2% + PCG64 110.7% + Philox -2.7% + ThreeFry -11.4% + ThreeFry32 -62.3% + Xoroshiro128 181.4% + Xorshift1024 141.8% + + Speed-up relative to NumPy (64-bit unsigned integers) + ************************************************************ + DSFMT 24.8% + MT19937 15.0% + PCG32 92.6% + PCG64 99.0% + Philox -20.4% + ThreeFry -21.7% + ThreeFry32 -64.4% + Xoroshiro128 164.2% + Xorshift1024 120.8% + + Speed-up relative to NumPy (Standard normals) + ************************************************************ + DSFMT 299.4% + MT19937 271.2% + PCG32 364.5% + PCG64 364.2% + Philox 256.9% + ThreeFry 236.0% + ThreeFry32 97.0% + Xoroshiro128 477.4% + Xorshift1024 360.7% + +.. |Travis Build Status| image:: https://travis-ci.org/bashtage/randomgen.svg?branch=master + :target: https://travis-ci.org/bashtage/randomgen +.. |Appveyor Build Status| image:: https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true + :target: https://ci.appveyor.com/project/bashtage/randomgen/branch/master diff --git a/_randomgen/setup.py b/_randomgen/setup.py index a80d51a83387..9efac5d46b25 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -19,6 +19,16 @@ raise ImportError('tempita required to install, ' 'use pip install tempita') +try: + import pypandoc + # With an input file: it will infer the input format from the filename + with open('README.rst', 'w') as readme: + readme.write(pypandoc.convert_file('README.md', 'rst')) +except ImportError: + import warnings + warnings.warn( + 'Unable to import pypandoc. Do not use this as a release build!') + import versioneer Cython.Compiler.Options.annotate = True @@ -187,17 +197,43 @@ ] +classifiers = ['Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Intended Audience :: End Users/Desktop', + 'Intended Audience :: Financial and Insurance Industry', + 'Intended Audience :: Information Technology', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved', + 'Operating System :: MacOS :: MacOS X', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX :: Linux', + 'Operating System :: Unix', + 'Programming Language :: C', + 'Programming Language :: Cython', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Topic :: Adaptive Technologies', + 'Topic :: Artistic Software', + 'Topic :: Office/Business :: Financial', + 'Topic :: Scientific/Engineering', + 'Topic :: Security :: Cryptography'] + + class BinaryDistribution(Distribution): def is_pure(self): return False setup( + name='randomgen', version=versioneer.get_version(), + classifiers=classifiers, cmdclass=versioneer.get_cmdclass(), ext_modules=cythonize(extensions, compile_time_env={ "PCG_EMULATED_MATH": PCG_EMULATED_MATH}), - name='randomgen', packages=find_packages(), package_dir={'randomgen': './randomgen'}, package_data={'': ['*.h', '*.pxi', '*.pyx', '*.pxd', '*.in']}, @@ -206,8 +242,12 @@ def is_pure(self): author='Kevin Sheppard', author_email='kevin.k.sheppard@gmail.com', distclass=BinaryDistribution, + long_description=open('README.rst').read(), description='Random generator supporting multiple PRNGs', url='https://github.com/bashtage/randomgen', - keywords=['pseudo random numbers', 'PRNG', 'Python'], + keywords=['pseudo random numbers', 'PRNG', 'RNG', 'RandomState', 'random', + 'random numbers', 'parallel random numbers', 'PCG', + 'XorShift', 'dSFMT', 'MT19937', 'Random123', 'ThreeFry', + 'Philox'], zip_safe=False ) From 4036a5193e3ea40c7bad981b700ac57f91cf0233 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Mar 2018 13:14:34 +0000 Subject: [PATCH 090/279] DOC: Improve documentation Reorder docs Provide extra information about RandomGenerator Explain basic RNGs --- _randomgen/doc/source/brng/dsfmt.rst | 6 +- _randomgen/doc/source/brng/index.rst | 7 ++ _randomgen/doc/source/brng/mt19937.rst | 5 +- _randomgen/doc/source/brng/pcg32.rst | 5 +- _randomgen/doc/source/brng/pcg64.rst | 5 +- _randomgen/doc/source/brng/philox.rst | 5 +- _randomgen/doc/source/brng/threefry.rst | 5 +- _randomgen/doc/source/brng/threefry32.rst | 5 +- _randomgen/doc/source/brng/xoroshiro128.rst | 5 +- _randomgen/doc/source/brng/xorshift1024.rst | 5 +- _randomgen/doc/source/generator.rst | 13 +++- _randomgen/doc/source/index.rst | 69 +++++++++++++++---- _randomgen/randomgen/__init__.py | 11 +-- _randomgen/randomgen/dsfmt.pyx | 3 +- _randomgen/randomgen/mt19937.pyx | 3 +- _randomgen/randomgen/philox.pyx | 3 +- .../randomgen/tests/test_against_numpy.py | 15 ++-- _randomgen/randomgen/threefry.pyx | 3 +- _randomgen/randomgen/threefry32.pyx | 3 +- _randomgen/randomgen/xoroshiro128.pyx | 3 +- _randomgen/randomgen/xorshift1024.pyx | 2 +- 21 files changed, 117 insertions(+), 64 deletions(-) diff --git a/_randomgen/doc/source/brng/dsfmt.rst b/_randomgen/doc/source/brng/dsfmt.rst index 3432d4d043ce..bd660c938d54 100644 --- a/_randomgen/doc/source/brng/dsfmt.rst +++ b/_randomgen/doc/source/brng/dsfmt.rst @@ -5,10 +5,12 @@ Double SIMD Mersenne Twister (dSFMT) .. currentmodule:: randomgen.dsfmt -Random generator -================ + .. autoclass:: DSFMT +Seeding and State +================= + .. autosummary:: :toctree: generated/ diff --git a/_randomgen/doc/source/brng/index.rst b/_randomgen/doc/source/brng/index.rst index 8bd29c1ca622..709151696272 100644 --- a/_randomgen/doc/source/brng/index.rst +++ b/_randomgen/doc/source/brng/index.rst @@ -1,6 +1,13 @@ Basic Random Number Generators ------------------------------ +The random values produced by :class:`~randomgen.generator.RandomGenerator` +are produced by a basic RNG. These basic RNGs do not directly provide +random numbers and only contains methods used for seeding, getting or +setting the state, jumping or advancing the state, and for accessing +low-level wrappers for consumption by code that can efficiently +access the functions provided, e.g., `numba `_. + Stable RNGs =========== These RNGs will be included in future releases. diff --git a/_randomgen/doc/source/brng/mt19937.rst b/_randomgen/doc/source/brng/mt19937.rst index 3fbc8f0994c4..23f8e45940a0 100644 --- a/_randomgen/doc/source/brng/mt19937.rst +++ b/_randomgen/doc/source/brng/mt19937.rst @@ -5,10 +5,11 @@ Mersenne Twister (MT19937) .. currentmodule:: randomgen.mt19937 -Random generator -================ .. autoclass:: MT19937 +Seeding and State +================= + .. autosummary:: :toctree: generated/ diff --git a/_randomgen/doc/source/brng/pcg32.rst b/_randomgen/doc/source/brng/pcg32.rst index 97bb341ad45b..1854b4c68dd9 100644 --- a/_randomgen/doc/source/brng/pcg32.rst +++ b/_randomgen/doc/source/brng/pcg32.rst @@ -5,10 +5,11 @@ Parallel Congruent Generator (32-bit, PCG32) .. currentmodule:: randomgen.pcg32 -Random generator -================ .. autoclass:: PCG32 +Seeding and State +================= + .. autosummary:: :toctree: generated/ diff --git a/_randomgen/doc/source/brng/pcg64.rst b/_randomgen/doc/source/brng/pcg64.rst index 2ef19abb2123..496825dc456a 100644 --- a/_randomgen/doc/source/brng/pcg64.rst +++ b/_randomgen/doc/source/brng/pcg64.rst @@ -5,10 +5,11 @@ Parallel Congruent Generator (64-bit, PCG64) .. currentmodule:: randomgen.pcg64 -Random generator -================ .. autoclass:: PCG64 +Seeding and State +================= + .. autosummary:: :toctree: generated/ diff --git a/_randomgen/doc/source/brng/philox.rst b/_randomgen/doc/source/brng/philox.rst index e12de40531a9..c2ffc44eb1fa 100644 --- a/_randomgen/doc/source/brng/philox.rst +++ b/_randomgen/doc/source/brng/philox.rst @@ -5,10 +5,11 @@ Philox Counter-based RNG .. currentmodule:: randomgen.philox -Random generator -================ .. autoclass:: Philox +Seeding and State +================= + .. autosummary:: :toctree: generated/ diff --git a/_randomgen/doc/source/brng/threefry.rst b/_randomgen/doc/source/brng/threefry.rst index 6c1ff5387a5a..98141d6486c5 100644 --- a/_randomgen/doc/source/brng/threefry.rst +++ b/_randomgen/doc/source/brng/threefry.rst @@ -5,10 +5,11 @@ ThreeFry Counter-based RNG .. currentmodule:: randomgen.threefry -Random generator -================ .. autoclass:: ThreeFry +Seeding and State +================= + .. autosummary:: :toctree: generated/ diff --git a/_randomgen/doc/source/brng/threefry32.rst b/_randomgen/doc/source/brng/threefry32.rst index 96576413c535..2869cbac887c 100644 --- a/_randomgen/doc/source/brng/threefry32.rst +++ b/_randomgen/doc/source/brng/threefry32.rst @@ -5,10 +5,11 @@ ThreeFry32 Counter-based RNG .. currentmodule:: randomgen.threefry32 -Random generator -================ .. autoclass:: ThreeFry32 +Seeding and State +================= + .. autosummary:: :toctree: generated/ diff --git a/_randomgen/doc/source/brng/xoroshiro128.rst b/_randomgen/doc/source/brng/xoroshiro128.rst index 9f8b2dfadc65..3d6735c621d2 100644 --- a/_randomgen/doc/source/brng/xoroshiro128.rst +++ b/_randomgen/doc/source/brng/xoroshiro128.rst @@ -5,10 +5,11 @@ Xoroshiro128+ .. currentmodule:: randomgen.xoroshiro128 -Random generator -================ .. autoclass:: Xoroshiro128 +Seeding and State +================= + .. autosummary:: :toctree: generated/ diff --git a/_randomgen/doc/source/brng/xorshift1024.rst b/_randomgen/doc/source/brng/xorshift1024.rst index 5340579c0f8a..38b293dcd6f8 100644 --- a/_randomgen/doc/source/brng/xorshift1024.rst +++ b/_randomgen/doc/source/brng/xorshift1024.rst @@ -5,10 +5,11 @@ Xorshift1024*φ .. currentmodule:: randomgen.xorshift1024 -Random generator -================ .. autoclass:: Xorshift1024 +Seeding and State +================= + .. autosummary:: :toctree: generated/ diff --git a/_randomgen/doc/source/generator.rst b/_randomgen/doc/source/generator.rst index 9f2e69a167b0..2fedc8f58b72 100644 --- a/_randomgen/doc/source/generator.rst +++ b/_randomgen/doc/source/generator.rst @@ -1,10 +1,19 @@ Random Generator ---------------- +The :class:`~randomgen.generator.RandomGenerator` provides access to +a wide range of distributions, and served as a replacement for +:class:`~numpy.random.RandomState`. The main difference between +the two is that :class:`~randomgen.generator.RandomGenerator` relies +on an additional basic RNG to manage state and generate the random +bits which are then transformed into random values from useful +distributions. The default basic RNG used by +:class:`~randomgen.generator.RandomGenerator` is +:class:`~randomgen.xoroshiro128.Xoroshiro128`. The basic RNG can be +changed by passing an instantized basic RNG to +:class:`~randomgen.generator.RandomGenerator`. .. currentmodule:: randomgen.generator -Random generator -================ .. autoclass:: RandomGenerator diff --git a/_randomgen/doc/source/index.rst b/_randomgen/doc/source/index.rst index b89679a29e62..2e9ce44d94e8 100644 --- a/_randomgen/doc/source/index.rst +++ b/_randomgen/doc/source/index.rst @@ -4,6 +4,45 @@ This package contains replacements for the NumPy :class:`~numpy.random.RandomState` object that allows the core random number generator be be changed. +Quick Start +----------- + +Like :mod:`numpy.random`, RandomGen can be used at the module level. +This uses the default :class:`~randomgen.generator.RandomGenerator` which +uses normals provided by :class:`~randomgen.xoroshiro128.Xoroshiro128`. + +.. code-block:: python + + # As replacement for numpy.random + import randomgen.generator as random + random.standard_normal() + +:class:`~randomgen.generator.RandomGenerator` can also be used as a +replacement for :class:`~numpy.random.RandomState`, although the random +values are generated by :class:`~randomgen.xoroshiro128.Xoroshiro128`. It +also isn't possible to directly seed a +:class:`~randomgen.generator.RandomGenerator`. + + +.. code-block:: python + + # As replacement for RandomState() + from randomgen import RandomGenerator + rg = RandomGenerator() + rg.standard_normal() + + +Seeds can be passed to any of the basic RNGs. Here :class:`~randomgen.mt19937.MT19937` +is used and the :class:`~randomgen.generator.RandomGenerator` is accessed via +the property :attr:`~randomgen.mt19937.MT19937.generator`. + +.. code-block:: python + + from randomgen import MT19937 + rg = MT19937(12345).generator + rg.standard_normal() + + Introduction ------------ RandomGen takes a different approach to producing random numbers from the @@ -27,7 +66,7 @@ method to initialize a generator passes a basic RNG -- :class:`~randomgen.mt19937.MT19937`, the underlying RNG in NumPy -- as the sole argument. Note that the basic RNG must be instantized. -.. ipython:: python +.. code-block:: python from randomgen import RandomGenerator, MT19937 rg = RandomGenerator(MT19937()) @@ -35,7 +74,7 @@ sole argument. Note that the basic RNG must be instantized. Seed information is directly passed to the basic RNG. -.. ipython:: python +.. code-block:: python rg = RandomGenerator(MT19937(12345)) rg.random_sample() @@ -44,7 +83,7 @@ A shorthand method is also available which uses the :meth:`~randomgen.mt19937.MT19937.generator` property from a basic RNG to access an embedded random generator. -.. ipython:: python +.. code-block:: python rg = MT19937(12345).generator rg.random_sample() @@ -130,18 +169,6 @@ generators, 'in addition' to the standard PRNG in NumPy. The included PRNGs are .. _`PCG author's page`: http://www.pcg-random.org/ .. _`Random123`: https://www.deshawresearch.com/resources_random123.html -New Features ------------- -.. toctree:: - :maxdepth: 2 - - Parallel Applications - Multithreaded Generation - new-or-different - Reading System Entropy - Comparing Performance - extending - Random Generator ---------------- .. toctree:: @@ -157,6 +184,18 @@ Basic Random Number Generators Basic Random Number Generators +New Features +------------ +.. toctree:: + :maxdepth: 2 + + Parallel Applications + Multithreaded Generation + new-or-different + Comparing Performance + extending + Reading System Entropy + Changes ~~~~~~~ .. toctree:: diff --git a/_randomgen/randomgen/__init__.py b/_randomgen/randomgen/__init__.py index 43ee16e90904..49094dffcd16 100644 --- a/_randomgen/randomgen/__init__.py +++ b/_randomgen/randomgen/__init__.py @@ -1,5 +1,5 @@ from randomgen.dsfmt import DSFMT -from randomgen.generator import * +from randomgen.generator import RandomGenerator from randomgen.mt19937 import MT19937 from randomgen.pcg32 import PCG32 from randomgen.pcg64 import PCG64 @@ -10,14 +10,7 @@ from randomgen.xorshift1024 import Xorshift1024 __all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'PCG32', 'Philox', - 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024', - 'beta', 'binomial', 'bytes', 'chisquare', 'choice', 'complex_normal', 'dirichlet', 'exponential', 'f', - 'gamma', 'geometric', 'gumbel', 'hypergeometric', 'laplace', 'logistic', 'lognormal', 'logseries', - 'multinomial', 'multivariate_normal', 'negative_binomial', 'noncentral_chisquare', 'noncentral_f', - 'normal', 'permutation', 'pareto', 'poisson', 'power', 'rand', 'randint', 'randn', - 'random_integers', 'random_raw', 'random_sample', 'random_uintegers', 'rayleigh', 'state', 'shuffle', - 'standard_cauchy', 'standard_exponential', 'standard_gamma', 'standard_normal', 'standard_t', - 'tomaxint', 'triangular', 'uniform', 'vonmises', 'wald', 'weibull', 'zipf'] + 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024'] from ._version import get_versions diff --git a/_randomgen/randomgen/dsfmt.pyx b/_randomgen/randomgen/dsfmt.pyx index 040d5a719c5a..13ab087668d4 100644 --- a/_randomgen/randomgen/dsfmt.pyx +++ b/_randomgen/randomgen/dsfmt.pyx @@ -241,8 +241,7 @@ cdef class DSFMT: """ jump(iter=1) - Jumps the state of the random number generator as-if 2**128 random numbers - have been generated. + Jumps the state as-if 2**128 random numbers have been generated. Parameters ---------- diff --git a/_randomgen/randomgen/mt19937.pyx b/_randomgen/randomgen/mt19937.pyx index dfcf24fd2357..ca52b119c4ce 100644 --- a/_randomgen/randomgen/mt19937.pyx +++ b/_randomgen/randomgen/mt19937.pyx @@ -239,8 +239,7 @@ cdef class MT19937: """ jump(iter=1) - Jumps the state of the random number generator as-if 2**128 random numbers - have been generated. + Jumps the state as-if 2**128 random numbers have been generated. Parameters ---------- diff --git a/_randomgen/randomgen/philox.pyx b/_randomgen/randomgen/philox.pyx index 34bcefc61b49..f79bb4ca3d93 100644 --- a/_randomgen/randomgen/philox.pyx +++ b/_randomgen/randomgen/philox.pyx @@ -329,8 +329,7 @@ cdef class Philox: """ jump(iter=1) - Jumps the state of the random number generator as-if 2**128 random - numbers have been generated. + Jumps the state as-if 2**128 random numbers have been generated. Parameters ---------- diff --git a/_randomgen/randomgen/tests/test_against_numpy.py b/_randomgen/randomgen/tests/test_against_numpy.py index dd187f25d8db..2e49c1f18ff6 100644 --- a/_randomgen/randomgen/tests/test_against_numpy.py +++ b/_randomgen/randomgen/tests/test_against_numpy.py @@ -535,13 +535,14 @@ def test_dir(self): assert (len(nprs_d.difference(rs_d)) == 0) npmod = dir(numpy.random) - mod = dir(randomgen) - known_exlcuded = ['__all__', 'Tester', 'info', 'bench', - '__RandomState_ctor', 'mtrand', 'test', - '__warningregistry__', '_numpy_tester', 'division', - 'get_state', 'set_state', 'seed', 'ranf', 'random', - 'sample', 'absolute_import', 'print_function', - 'RandomState'] + mod = dir(randomgen.generator) + known_exlcuded = ['__all__', '__cached__', '__path__', 'Tester', + 'info', 'bench', '__RandomState_ctor', 'mtrand', + 'test', '__warningregistry__', '_numpy_tester', + 'division', 'get_state', 'set_state', 'seed', + 'ranf', 'random', 'sample', 'absolute_import', + 'print_function', 'RandomState'] mod += known_exlcuded diff = set(npmod).difference(mod) + print(diff) assert_equal(len(diff), 0) diff --git a/_randomgen/randomgen/threefry.pyx b/_randomgen/randomgen/threefry.pyx index 36dd12de840d..50e6b9ecd5ee 100644 --- a/_randomgen/randomgen/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -321,8 +321,7 @@ cdef class ThreeFry: """ jump(iter=1) - Jumps the state of the random number generator as-if 2**128 random - numbers have been generated. + Jumps the state as-if 2**128 random numbers have been generated. Parameters ---------- diff --git a/_randomgen/randomgen/threefry32.pyx b/_randomgen/randomgen/threefry32.pyx index e03f2416a682..41de1688860f 100644 --- a/_randomgen/randomgen/threefry32.pyx +++ b/_randomgen/randomgen/threefry32.pyx @@ -316,8 +316,7 @@ cdef class ThreeFry32: """ jump(iter=1) - Jumps the state of the random number generator as-if 2**64 random - numbers have been generated. + Jumps the state as-if 2**64 random numbers have been generated. Parameters ---------- diff --git a/_randomgen/randomgen/xoroshiro128.pyx b/_randomgen/randomgen/xoroshiro128.pyx index e7ffeb0e20e0..edddf4232b56 100644 --- a/_randomgen/randomgen/xoroshiro128.pyx +++ b/_randomgen/randomgen/xoroshiro128.pyx @@ -213,8 +213,7 @@ cdef class Xoroshiro128: """ jump(iter=1) - Jumps the state of the random number generator as-if 2**64 random numbers - have been generated. + Jumps the state as-if 2**64 random numbers have been generated. Parameters ---------- diff --git a/_randomgen/randomgen/xorshift1024.pyx b/_randomgen/randomgen/xorshift1024.pyx index 140923e7fc96..b9149f277736 100644 --- a/_randomgen/randomgen/xorshift1024.pyx +++ b/_randomgen/randomgen/xorshift1024.pyx @@ -42,7 +42,7 @@ cdef class Xorshift1024: Container for the xorshift1024*φ pseudo-random number generator. xorshift1024*φ is a 64-bit implementation of Saito and Matsumoto's XSadd - generator [1]_ (see also [2]_, [3]_, [4]_). xorshift1024* has a period of + generator [1]_ (see also [2]_, [3]_, [4]_). xorshift1024*φ has a period of :math:`2^{1024} - 1` and supports jumping the sequence in increments of :math:`2^{512}`, which allows multiple non-overlapping sequences to be generated. From eae5daea44b63ec70b73b1ebea41c7eadaf871a8 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Mar 2018 13:45:01 +0000 Subject: [PATCH 091/279] BLD: Improve setup Add requirements to setup --- _randomgen/MANIFEST.in | 3 +++ _randomgen/randomgen/generator.pyx | 4 +++- _randomgen/requirements.txt | 8 ++++---- _randomgen/setup.py | 6 +++++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/_randomgen/MANIFEST.in b/_randomgen/MANIFEST.in index ffc3d5bee5d8..b6a20a4feaa1 100644 --- a/_randomgen/MANIFEST.in +++ b/_randomgen/MANIFEST.in @@ -2,5 +2,8 @@ exclude randomgen/entropy.c recursive-exclude randomgen *.c include versioneer.py include randomgen/_version.py +include requirements.txt +include README.md +include README.rst recursive-include randomgen *.py *.pyx *.px[di] *.h *.in *.csv graft randomgen/src diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index d878d502f0f6..488f8152b198 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -4315,7 +4315,9 @@ standard_exponential = _random_generator.standard_exponential standard_gamma = _random_generator.standard_gamma standard_normal = _random_generator.standard_normal standard_t = _random_generator.standard_t -state = _random_generator.state +get_state = lambda: _random_generator.state +def set_state(state): + _random_generator.state = state tomaxint = _random_generator.tomaxint triangular = _random_generator.triangular uniform = _random_generator.uniform diff --git a/_randomgen/requirements.txt b/_randomgen/requirements.txt index a02ebc02a654..f2f2e06ad0aa 100644 --- a/_randomgen/requirements.txt +++ b/_randomgen/requirements.txt @@ -1,4 +1,4 @@ -numpy -cython -cffi -pandas +numpy>=1.10 +cython>=0.24 +setuptools +wheel \ No newline at end of file diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 9efac5d46b25..2fc6f49b519e 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -31,6 +31,9 @@ import versioneer +with open('requirements.txt') as f: + required = f.read().splitlines() + Cython.Compiler.Options.annotate = True USE_SSE2 = True if not '--no-sse2' in sys.argv else False @@ -249,5 +252,6 @@ def is_pure(self): 'random numbers', 'parallel random numbers', 'PCG', 'XorShift', 'dSFMT', 'MT19937', 'Random123', 'ThreeFry', 'Philox'], - zip_safe=False + zip_safe=False, + install_requires=required ) From 3f55c29c34f16d9d04732aea5dd463b6496d1b36 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Mar 2018 14:05:45 +0000 Subject: [PATCH 092/279] DOC: Change location of documentation Change location of documentation --- _randomgen/.travis.yml | 2 +- _randomgen/README.md | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 81702275578f..1c950fdab6b9 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -62,7 +62,7 @@ script: make html make html cd ${BUILD_DIR} - doctr deploy doc --build-tags + doctr deploy devel --build-tags if [[ -z ${TRAVIS_TAG} ]]; then echo "Not a tagged build." else diff --git a/_randomgen/README.md b/_randomgen/README.md index c4bf69f45711..036af1b619b1 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -129,8 +129,10 @@ The version matched the latest version of NumPy where ## Documentation -An occasionally updated build of the documentation is available on -[my GitHub pages](http://bashtage.github.io/randomgen/). +Documentation for the latest release is available on +[my GitHub pages](http://bashtage.github.io/randomgen/). Documentation for +the latest commit (unreleased) is available under +[devel](http://bashtage.github.io/randomgen/devel/). ## Plans This module is essentially complete. There are a few rough edges that From 047465655016d28ec61c21302a6f74af000dec9f Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Mar 2018 14:16:18 +0000 Subject: [PATCH 093/279] DOC: Update README.rst Update README.rst --- _randomgen/README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/_randomgen/README.rst b/_randomgen/README.rst index 16957a167310..b9a0ad5f5053 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -142,8 +142,10 @@ The version matched the latest version of NumPy where Documentation ------------- -An occasionally updated build of the documentation is available on `my -GitHub pages `__. +| Documentation for the latest release is available on `my GitHub + pages `__. Documentation for the + latest commit (unreleased) is available under +| `devel `__. Plans ----- From 6a108f2e263f14d7190dddc18ead7bb58608466a Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Mar 2018 16:20:46 +0000 Subject: [PATCH 094/279] ENH: Restore filler Swap double filler for old version Restore fillers to distributions --- _randomgen/randomgen/common.pxd | 1 + _randomgen/randomgen/common.pyx | 9 ++-- _randomgen/randomgen/distributions.pxd | 4 ++ _randomgen/randomgen/generator.pyx | 8 ++-- .../src/distributions/distributions.c | 45 ++++++++++++++++++- .../src/distributions/distributions.h | 4 ++ 6 files changed, 61 insertions(+), 10 deletions(-) diff --git a/_randomgen/randomgen/common.pxd b/_randomgen/randomgen/common.pxd index 33a7bef2629a..baad9835a82f 100644 --- a/_randomgen/randomgen/common.pxd +++ b/_randomgen/randomgen/common.pxd @@ -30,6 +30,7 @@ cdef extern from "src/aligned_malloc/aligned_malloc.h": cdef void *PyArray_calloc_aligned(size_t n, size_t s); cdef void PyArray_free_aligned(void *p); +ctypedef double (*random_double_fill)(brng_t *state, np.npy_intp count, double* out) nogil ctypedef double (*random_double_0)(brng_t *state) nogil ctypedef double (*random_double_1)(brng_t *state, double a) nogil ctypedef double (*random_double_2)(brng_t *state, double a, double b) nogil diff --git a/_randomgen/randomgen/common.pyx b/_randomgen/randomgen/common.pyx index 101a14270635..e28342e68442 100644 --- a/_randomgen/randomgen/common.pyx +++ b/_randomgen/randomgen/common.pyx @@ -70,14 +70,16 @@ cdef check_output(object out, object dtype, object size): cdef object double_fill(void *func, brng_t *state, object size, object lock, object out): - cdef random_double_0 random_func = (func) + cdef random_double_fill random_func = (func) + cdef double out_val cdef double *out_array_data cdef np.ndarray out_array cdef np.npy_intp i, n if size is None and out is None: with lock: - return random_func(state) + random_func(state, 1, &out_val) + return out_val if out is not None: check_output(out, np.float64, size) @@ -88,8 +90,7 @@ cdef object double_fill(void *func, brng_t *state, object size, object lock, obj n = np.PyArray_SIZE(out_array) out_array_data = np.PyArray_DATA(out_array) with lock, nogil: - for i in range(n): - out_array_data[i] = random_func(state) + random_func(state, n, out_array_data) return out_array cdef object float_fill(void *func, brng_t *state, object size, object lock, object out): diff --git a/_randomgen/randomgen/distributions.pxd b/_randomgen/randomgen/distributions.pxd index 29ee591e3a4d..202c7439de0a 100644 --- a/_randomgen/randomgen/distributions.pxd +++ b/_randomgen/randomgen/distributions.pxd @@ -36,9 +36,13 @@ cdef extern from "src/distributions/distributions.h": ctypedef brng brng_t double random_double(brng_t *brng_state) nogil + void random_double_fill(brng_t* brng_state, np.npy_intp cnt, double *out) double random_standard_exponential(brng_t *brng_state) nogil + void random_standard_exponential_fill(brng_t *brng_state, np.npy_intp cnt, double *out) double random_standard_exponential_zig(brng_t *brng_state) nogil + void random_standard_exponential_zig_fill(brng_t *brng_state, np.npy_intp cnt, double *out) double random_gauss_zig(brng_t* brng_state) nogil + void random_gauss_zig_fill(brng_t *brng_state, np.npy_intp count, double *out) nogil double random_standard_gamma_zig(brng_t *brng_state, double shape) nogil float random_float(brng_t *brng_state) nogil diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 488f8152b198..1aa630dfdaa6 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -323,7 +323,7 @@ cdef class RandomGenerator: cdef double temp key = np.dtype(dtype).name if key == 'float64': - return double_fill(&random_double, self._brng, size, self.lock, out) + return double_fill(&random_double_fill, self._brng, size, self.lock, out) elif key == 'float32': return float_fill(&random_float, self._brng, size, self.lock, out) else: @@ -465,9 +465,9 @@ cdef class RandomGenerator: key = np.dtype(dtype).name if key == 'float64': if method == u'zig': - return double_fill(&random_standard_exponential_zig, self._brng, size, self.lock, out) + return double_fill(&random_standard_exponential_zig_fill, self._brng, size, self.lock, out) else: - return double_fill(&random_standard_exponential, self._brng, size, self.lock, out) + return double_fill(&random_standard_exponential_fill, self._brng, size, self.lock, out) elif key == 'float32': if method == u'zig': return float_fill(&random_standard_exponential_zig_f, self._brng, size, self.lock, out) @@ -1206,7 +1206,7 @@ cdef class RandomGenerator: """ key = np.dtype(dtype).name if key == 'float64': - return double_fill(&random_gauss_zig, self._brng, size, self.lock, out) + return double_fill(&random_gauss_zig_fill, self._brng, size, self.lock, out) elif key == 'float32': return float_fill(&random_gauss_zig_f, self._brng, size, self.lock, out) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 2ed6d26c3dfe..246cddb444e8 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -7,14 +7,34 @@ float random_float(brng_t *brng_state) { return next_float(brng_state); } double random_double(brng_t *brng_state) { return next_double(brng_state); } +static NPY_INLINE double next_standard_exponential(brng_t *brng_state) +{ + return -log(1.0 - next_double(brng_state)); +} + double random_standard_exponential(brng_t *brng_state) { - return -log(1.0 - next_double(brng_state)); + return next_standard_exponential(brng_state); +} + +void random_standard_exponential_fill(brng_t *brng_state, npy_intp cnt, double *out) +{ + npy_intp i; + for (i = 0; i < cnt; i++) { + out[i] = next_standard_exponential(brng_state); + } } float random_standard_exponential_f(brng_t *brng_state) { return -logf(1.0f - next_float(brng_state)); } +void random_double_fill(brng_t* brng_state, npy_intp cnt, double *out) +{ + npy_intp i; + for (i = 0; i < cnt; i++) { + out[i] = next_double(brng_state); + } +} /* double random_gauss(brng_t *brng_state) { if (brng_state->has_gauss) { @@ -99,6 +119,16 @@ double random_standard_exponential_zig(brng_t *brng_state) { return standard_exponential_zig(brng_state); } + +void random_standard_exponential_zig_fill(brng_t *brng_state, npy_intp cnt, double *out) +{ + npy_intp i; + for (i = 0; i < cnt; i++) { + out[i] = standard_exponential_zig(brng_state); + } +} + + static NPY_INLINE float standard_exponential_zig_f(brng_t *brng_state); static float standard_exponential_zig_unlikely_f(brng_t *brng_state, @@ -133,7 +163,7 @@ float random_standard_exponential_zig_f(brng_t *brng_state) { return standard_exponential_zig_f(brng_state); } -double random_gauss_zig(brng_t *brng_state) { +static NPY_INLINE double next_gauss_zig(brng_t *brng_state) { uint64_t r; int sign; int64_t rabs; @@ -167,6 +197,17 @@ double random_gauss_zig(brng_t *brng_state) { } } +double random_gauss_zig(brng_t *brng_state) { + return next_gauss_zig(brng_state); +} + +void random_gauss_zig_fill(brng_t *brng_state, npy_intp cnt, double *out) { + npy_intp i; + for (i = 0; i < cnt; i++) { + out[i] = next_gauss_zig(brng_state); + } +} + float random_gauss_zig_f(brng_t *brng_state) { uint32_t r; int sign; diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index 6bbbcd8f0f05..6785405c7aa0 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -95,6 +95,7 @@ static NPY_INLINE double next_double(brng_t *brng_state) { DECLDIR float random_float(brng_t *brng_state); DECLDIR double random_double(brng_t *brng_state); +DECLDIR void random_double_fill(brng_t* brng_state, npy_intp cnt, double *out); DECLDIR int64_t random_positive_int64(brng_t *brng_state); DECLDIR int32_t random_positive_int32(brng_t *brng_state); @@ -102,8 +103,10 @@ DECLDIR int64_t random_positive_int(brng_t *brng_state); DECLDIR uint64_t random_uint(brng_t *brng_state); DECLDIR double random_standard_exponential(brng_t *brng_state); +DECLDIR void random_standard_exponential_fill(brng_t *brng_state, npy_intp cnt, double *out); DECLDIR float random_standard_exponential_f(brng_t *brng_state); DECLDIR double random_standard_exponential_zig(brng_t *brng_state); +DECLDIR void random_standard_exponential_zig_fill(brng_t *brng_state, npy_intp cnt, double *out); DECLDIR float random_standard_exponential_zig_f(brng_t *brng_state); /* @@ -112,6 +115,7 @@ DECLDIR float random_gauss_f(brng_t *brng_state); */ DECLDIR double random_gauss_zig(brng_t *brng_state); DECLDIR float random_gauss_zig_f(brng_t *brng_state); +DECLDIR void random_gauss_zig_fill(brng_t *brng_state, npy_intp cnt, double *out); /* DECLDIR double random_standard_gamma(brng_t *brng_state, double shape); From 9d5adfd59d50c15086b8c28d9c50c8c60e03005c Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 16 Mar 2018 23:17:49 +0000 Subject: [PATCH 095/279] Replace pointer size Switch to uintptr_t for 32 bit platforms --- _randomgen/randomgen/common.pxd | 3 ++- _randomgen/randomgen/dsfmt.pyx | 24 ++++++++++++------------ _randomgen/randomgen/mt19937.pyx | 24 ++++++++++++------------ _randomgen/randomgen/pcg32.pyx | 24 ++++++++++++------------ _randomgen/randomgen/pcg64.pyx | 24 ++++++++++++------------ _randomgen/randomgen/philox.pyx | 24 ++++++++++++------------ _randomgen/randomgen/threefry.pyx | 24 ++++++++++++------------ _randomgen/randomgen/xoroshiro128.pyx | 24 ++++++++++++------------ _randomgen/randomgen/xorshift1024.pyx | 24 ++++++++++++------------ 9 files changed, 98 insertions(+), 97 deletions(-) diff --git a/_randomgen/randomgen/common.pxd b/_randomgen/randomgen/common.pxd index baad9835a82f..e4ce62818370 100644 --- a/_randomgen/randomgen/common.pxd +++ b/_randomgen/randomgen/common.pxd @@ -1,5 +1,6 @@ from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, - int8_t, int16_t, int32_t, int64_t, intptr_t) + int8_t, int16_t, int32_t, int64_t, intptr_t, + uintptr_t) from libc.math cimport sqrt from distributions cimport brng_t diff --git a/_randomgen/randomgen/dsfmt.pyx b/_randomgen/randomgen/dsfmt.pyx index 13ab087668d4..fa70b4ef52b4 100644 --- a/_randomgen/randomgen/dsfmt.pyx +++ b/_randomgen/randomgen/dsfmt.pyx @@ -331,18 +331,18 @@ cdef class DSFMT: import ctypes - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&dsfmt_uint64, + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&dsfmt_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&dsfmt_uint32, + ctypes.cast(&dsfmt_uint32, ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&dsfmt_double, + ctypes.cast(&dsfmt_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -370,12 +370,12 @@ cdef class DSFMT: raise ImportError('cffi is cannot be imported.') ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property diff --git a/_randomgen/randomgen/mt19937.pyx b/_randomgen/randomgen/mt19937.pyx index ca52b119c4ce..e05a78e481ff 100644 --- a/_randomgen/randomgen/mt19937.pyx +++ b/_randomgen/randomgen/mt19937.pyx @@ -317,18 +317,18 @@ cdef class MT19937: import ctypes - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&mt19937_uint64, + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&mt19937_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&mt19937_uint32, + ctypes.cast(&mt19937_uint32, ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&mt19937_double, + ctypes.cast(&mt19937_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -356,12 +356,12 @@ cdef class MT19937: raise ImportError('cffi is cannot be imported.') ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property diff --git a/_randomgen/randomgen/pcg32.pyx b/_randomgen/randomgen/pcg32.pyx index b739a12b5d7f..5043db8c66a4 100644 --- a/_randomgen/randomgen/pcg32.pyx +++ b/_randomgen/randomgen/pcg32.pyx @@ -345,18 +345,18 @@ cdef class PCG32: import ctypes - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&pcg32_uint64, + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&pcg32_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&pcg32_uint32, + ctypes.cast(&pcg32_uint32, ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&pcg32_double, + ctypes.cast(&pcg32_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -384,12 +384,12 @@ cdef class PCG32: raise ImportError('cffi is cannot be imported.') ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property diff --git a/_randomgen/randomgen/pcg64.pyx b/_randomgen/randomgen/pcg64.pyx index 249587a49e5d..c00d91966864 100644 --- a/_randomgen/randomgen/pcg64.pyx +++ b/_randomgen/randomgen/pcg64.pyx @@ -404,18 +404,18 @@ cdef class PCG64: import ctypes - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&pcg64_uint64, + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&pcg64_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&pcg64_uint32, + ctypes.cast(&pcg64_uint32, ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&pcg64_double, + ctypes.cast(&pcg64_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -443,12 +443,12 @@ cdef class PCG64: raise ImportError('cffi is cannot be imported.') ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property diff --git a/_randomgen/randomgen/philox.pyx b/_randomgen/randomgen/philox.pyx index f79bb4ca3d93..7c27467e9bd3 100644 --- a/_randomgen/randomgen/philox.pyx +++ b/_randomgen/randomgen/philox.pyx @@ -412,18 +412,18 @@ cdef class Philox: import ctypes - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&philox_uint64, + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&philox_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&philox_uint32, + ctypes.cast(&philox_uint32, ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&philox_double, + ctypes.cast(&philox_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -451,12 +451,12 @@ cdef class Philox: raise ImportError('cffi is cannot be imported.') ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property diff --git a/_randomgen/randomgen/threefry.pyx b/_randomgen/randomgen/threefry.pyx index 50e6b9ecd5ee..e347959c3aad 100644 --- a/_randomgen/randomgen/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -405,18 +405,18 @@ cdef class ThreeFry: import ctypes - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&threefry_uint64, + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&threefry_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&threefry_uint32, + ctypes.cast(&threefry_uint32, ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&threefry_double, + ctypes.cast(&threefry_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -444,12 +444,12 @@ cdef class ThreeFry: raise ImportError('cffi is cannot be imported.') ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property diff --git a/_randomgen/randomgen/xoroshiro128.pyx b/_randomgen/randomgen/xoroshiro128.pyx index edddf4232b56..01b51376a38b 100644 --- a/_randomgen/randomgen/xoroshiro128.pyx +++ b/_randomgen/randomgen/xoroshiro128.pyx @@ -291,18 +291,18 @@ cdef class Xoroshiro128: import ctypes - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&xoroshiro128_uint64, + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&xoroshiro128_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&xoroshiro128_uint32, + ctypes.cast(&xoroshiro128_uint32, ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&xoroshiro128_double, + ctypes.cast(&xoroshiro128_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -330,12 +330,12 @@ cdef class Xoroshiro128: raise ImportError('cffi is cannot be imported.') ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property diff --git a/_randomgen/randomgen/xorshift1024.pyx b/_randomgen/randomgen/xorshift1024.pyx index b9149f277736..aef61e9abed7 100644 --- a/_randomgen/randomgen/xorshift1024.pyx +++ b/_randomgen/randomgen/xorshift1024.pyx @@ -324,18 +324,18 @@ cdef class Xorshift1024: import ctypes - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&xorshift1024_uint64, + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&xorshift1024_uint64, ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&xorshift1024_uint32, + ctypes.cast(&xorshift1024_uint32, ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&xorshift1024_double, + ctypes.cast(&xorshift1024_double, ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) + ctypes.c_void_p(self._brng)) return self.ctypes @property @@ -363,12 +363,12 @@ cdef class Xorshift1024: raise ImportError('cffi is cannot be imported.') ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) return self.cffi @property From a9e869c4a92f6ab96a273d4f11b10e8d846bcb1d Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 16 Mar 2018 23:32:17 +0000 Subject: [PATCH 096/279] BLD: Ensure emulated math is used in 32 bit platforms Ensure 32 bit platforms emulate Fix missing static in pcg --- _randomgen/randomgen/src/pcg32/pcg32.h | 21 +++++++------- _randomgen/randomgen/src/pcg64/pcg64.h | 38 ++++++++++++++------------ _randomgen/setup.py | 10 +++++-- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/_randomgen/randomgen/src/pcg32/pcg32.h b/_randomgen/randomgen/src/pcg32/pcg32.h index 5ab59cc85105..15410bd821c7 100644 --- a/_randomgen/randomgen/src/pcg32/pcg32.h +++ b/_randomgen/randomgen/src/pcg32/pcg32.h @@ -15,7 +15,7 @@ struct pcg_state_setseq_64 { uint64_t inc; }; -inline uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) { +static inline uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) { #if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) asm("rorl %%cl, %0" : "=r"(value) : "0"(value), "c"(rot)); return value; @@ -24,15 +24,15 @@ inline uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) { #endif } -inline void pcg_setseq_64_step_r(struct pcg_state_setseq_64 *rng) { +static inline void pcg_setseq_64_step_r(struct pcg_state_setseq_64 *rng) { rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64 + rng->inc; } -inline uint32_t pcg_output_xsh_rr_64_32(uint64_t state) { +static inline uint32_t pcg_output_xsh_rr_64_32(uint64_t state) { return pcg_rotr_32(((state >> 18u) ^ state) >> 27u, state >> 59u); } -inline uint32_t +static inline uint32_t pcg_setseq_64_xsh_rr_32_random_r(struct pcg_state_setseq_64 *rng) { uint64_t oldstate; oldstate = rng->state; @@ -40,8 +40,9 @@ pcg_setseq_64_xsh_rr_32_random_r(struct pcg_state_setseq_64 *rng) { return pcg_output_xsh_rr_64_32(oldstate); } -inline void pcg_setseq_64_srandom_r(struct pcg_state_setseq_64 *rng, - uint64_t initstate, uint64_t initseq) { +static inline void pcg_setseq_64_srandom_r(struct pcg_state_setseq_64 *rng, + uint64_t initstate, + uint64_t initseq) { rng->state = 0U; rng->inc = (initseq << 1u) | 1u; pcg_setseq_64_step_r(rng); @@ -52,8 +53,8 @@ inline void pcg_setseq_64_srandom_r(struct pcg_state_setseq_64 *rng, extern uint64_t pcg_advance_lcg_64(uint64_t state, uint64_t delta, uint64_t cur_mult, uint64_t cur_plus); -inline void pcg_setseq_64_advance_r(struct pcg_state_setseq_64 *rng, - uint64_t delta) { +static inline void pcg_setseq_64_advance_r(struct pcg_state_setseq_64 *rng, + uint64_t delta) { rng->state = pcg_advance_lcg_64(rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, rng->inc); } @@ -63,9 +64,7 @@ typedef struct pcg_state_setseq_64 pcg32_random_t; #define pcg32_srandom_r pcg_setseq_64_srandom_r #define pcg32_advance_r pcg_setseq_64_advance_r -typedef struct s_pcg32_state { - pcg32_random_t *pcg_state; -} pcg32_state; +typedef struct s_pcg32_state { pcg32_random_t *pcg_state; } pcg32_state; static inline uint64_t pcg32_next64(pcg32_state *state) { return (uint64_t)(pcg32_random_r(state->pcg_state)) << 32 | diff --git a/_randomgen/randomgen/src/pcg64/pcg64.h b/_randomgen/randomgen/src/pcg64/pcg64.h index df265cb1a3a4..f3611ce08d2f 100644 --- a/_randomgen/randomgen/src/pcg64/pcg64.h +++ b/_randomgen/randomgen/src/pcg64/pcg64.h @@ -51,7 +51,7 @@ typedef struct { uint64_t low; } pcg128_t; -inline pcg128_t PCG_128BIT_CONSTANT(uint64_t high, uint64_t low) { +static inline pcg128_t PCG_128BIT_CONSTANT(uint64_t high, uint64_t low) { pcg128_t result; result.high = high; result.low = low; @@ -78,13 +78,13 @@ typedef struct { , PCG_128BIT_CONSTANT(0x0000000000000001ULL, 0xda3e39cb94b95bdbULL) \ } -inline uint64_t pcg_rotr_64(uint64_t value, unsigned int rot) { +static inline uint64_t pcg_rotr_64(uint64_t value, unsigned int rot) { return (value >> rot) | (value << ((-rot) & 63)); } #ifdef PCG_EMULATED_128BIT_MATH -inline pcg128_t _pcg128_add(pcg128_t a, pcg128_t b) { +static inline pcg128_t _pcg128_add(pcg128_t a, pcg128_t b) { pcg128_t result; result.low = a.low + b.low; @@ -92,7 +92,8 @@ inline pcg128_t _pcg128_add(pcg128_t a, pcg128_t b) { return result; } -inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t *z1, uint64_t *z0) { +static inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t *z1, + uint64_t *z0) { uint64_t x0, x1, y0, y1; uint64_t w0, w1, w2, t; /* Lower 64 bits are straightforward clock-arithmetic. */ @@ -110,7 +111,7 @@ inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t *z1, uint64_t *z0) { *z1 = x1 * y1 + w2 + (w1 >> 32); } -inline pcg128_t _pcg128_mult(pcg128_t a, pcg128_t b) { +static inline pcg128_t _pcg128_mult(pcg128_t a, pcg128_t b) { uint64_t h1; pcg128_t result; @@ -120,17 +121,18 @@ inline pcg128_t _pcg128_mult(pcg128_t a, pcg128_t b) { return result; } -inline void pcg_setseq_128_step_r(pcg_state_setseq_128 *rng) { +static inline void pcg_setseq_128_step_r(pcg_state_setseq_128 *rng) { rng->state = _pcg128_add(_pcg128_mult(rng->state, PCG_DEFAULT_MULTIPLIER_128), rng->inc); } -inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) { +static inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) { return pcg_rotr_64(state.high ^ state.low, state.high >> 58u); } -inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng, - pcg128_t initstate, pcg128_t initseq) { +static inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng, + pcg128_t initstate, + pcg128_t initseq) { rng->state = PCG_128BIT_CONSTANT(0ULL, 0ULL); rng->inc.high = initseq.high << 1u; rng->inc.high |= initseq.low & 0x800000000000ULL; @@ -142,17 +144,18 @@ inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng, #else /* PCG_EMULATED_128BIT_MATH */ -inline void pcg_setseq_128_step_r(pcg_state_setseq_128 *rng) { +static inline void pcg_setseq_128_step_r(pcg_state_setseq_128 *rng) { rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + rng->inc; } -inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) { +static inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) { return pcg_rotr_64(((uint64_t)(state >> 64u)) ^ (uint64_t)state, state >> 122u); } -inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng, - pcg128_t initstate, pcg128_t initseq) { +static inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng, + pcg128_t initstate, + pcg128_t initseq) { rng->state = 0U; rng->inc = (initseq << 1u) | 1u; pcg_setseq_128_step_r(rng); @@ -162,12 +165,13 @@ inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng, #endif /* PCG_EMULATED_128BIT_MATH */ -inline uint64_t pcg_setseq_128_xsl_rr_64_random_r(pcg_state_setseq_128 *rng) { +static inline uint64_t +pcg_setseq_128_xsl_rr_64_random_r(pcg_state_setseq_128 *rng) { pcg_setseq_128_step_r(rng); return pcg_output_xsl_rr_128_64(rng->state); } -inline uint64_t +static inline uint64_t pcg_setseq_128_xsl_rr_64_boundedrand_r(pcg_state_setseq_128 *rng, uint64_t bound) { uint64_t threshold = -bound % bound; @@ -181,8 +185,8 @@ pcg_setseq_128_xsl_rr_64_boundedrand_r(pcg_state_setseq_128 *rng, extern pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult, pcg128_t cur_plus); -inline void pcg_setseq_128_advance_r(pcg_state_setseq_128 *rng, - pcg128_t delta) { +static inline void pcg_setseq_128_advance_r(pcg_state_setseq_128 *rng, + pcg128_t delta) { rng->state = pcg_advance_lcg_128(rng->state, delta, PCG_DEFAULT_MULTIPLIER_128, rng->inc); } diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 2fc6f49b519e..2bd987367eba 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -44,15 +44,20 @@ EXTRA_INCLUDE_DIRS = [] EXTRA_LINK_ARGS = [] -EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else ['-std=c99'] +# Undef for manylinux +EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else ['-std=c99', '-U__GNUC_GNU_INLINE__'] if os.name == 'nt': EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] - PCG_EMULATED_MATH = True if DEBUG: EXTRA_LINK_ARGS += ['-debug'] EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] if sys.version_info < (3, 0): EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] +PCG64_DEFS = [] +if sys.maxsize < 2 ** 32 or os.name == 'nt': + # Force emulated mode here + PCG_EMULATED_MATH = True + PCG64_DEFS += [('PCG_FORCE_EMULATED_128BIT_MATH', '1')] DSFMT_DEFS = [('DSFMT_MEXP', '19937')] if USE_SSE2: @@ -125,6 +130,7 @@ join(MOD_DIR, 'src', 'pcg64')], extra_compile_args=EXTRA_COMPILE_ARGS, + define_macros=PCG64_DEFS, extra_link_args=EXTRA_LINK_ARGS ), Extension("randomgen.pcg32", From 016e18203d14fd1254455c00f05fa4d5280d0b0f Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 17 Mar 2018 00:03:51 +0000 Subject: [PATCH 097/279] TST: Add init to test directory Add init to test directory to see if manylinux will pick up --- _randomgen/randomgen/tests/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 _randomgen/randomgen/tests/__init__.py diff --git a/_randomgen/randomgen/tests/__init__.py b/_randomgen/randomgen/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 From ec4094736db9ac613dcc4b6d8626d84dd6612d03 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 17 Mar 2018 07:08:37 +0000 Subject: [PATCH 098/279] BLD: Add csv to package data Add to package data to include in bdist wheel --- _randomgen/randomgen/bounded_integers.pxd | 39 - _randomgen/randomgen/bounded_integers.pyx | 1181 ------------------- _randomgen/randomgen/tests/data/__init__.py | 0 _randomgen/setup.py | 3 +- 4 files changed, 2 insertions(+), 1221 deletions(-) delete mode 100644 _randomgen/randomgen/bounded_integers.pxd delete mode 100644 _randomgen/randomgen/bounded_integers.pyx create mode 100644 _randomgen/randomgen/tests/data/__init__.py diff --git a/_randomgen/randomgen/bounded_integers.pxd b/_randomgen/randomgen/bounded_integers.pxd deleted file mode 100644 index f15f0f5d9d1e..000000000000 --- a/_randomgen/randomgen/bounded_integers.pxd +++ /dev/null @@ -1,39 +0,0 @@ -from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, - int8_t, int16_t, int32_t, int64_t, intptr_t) -from common cimport brng_t -import numpy as np -cimport numpy as np -ctypedef np.npy_bool bool_t - -_randint_types = {'bool': (0, 2), - 'int8': (-2**7, 2**7), - 'int16': (-2**15, 2**15), - 'int32': (-2**31, 2**31), - 'int64': (-2**63, 2**63), - 'uint8': (0, 2**8), - 'uint16': (0, 2**16), - 'uint32': (0, 2**32), - 'uint64': (0, 2**64) - } - -cdef inline uint64_t _gen_mask(uint64_t max_val) nogil: - """Mask generator for use in bounded random numbers""" - # Smallest bit mask >= max - cdef uint64_t mask = max_val - mask |= mask >> 1 - mask |= mask >> 2 - mask |= mask >> 4 - mask |= mask >> 8 - mask |= mask >> 16 - mask |= mask >> 32 - return mask - -cdef object _rand_uint64(object low, object high, object size, brng_t *state, object lock) -cdef object _rand_uint32(object low, object high, object size, brng_t *state, object lock) -cdef object _rand_uint16(object low, object high, object size, brng_t *state, object lock) -cdef object _rand_uint8(object low, object high, object size, brng_t *state, object lock) -cdef object _rand_bool(object low, object high, object size, brng_t *state, object lock) -cdef object _rand_int64(object low, object high, object size, brng_t *state, object lock) -cdef object _rand_int32(object low, object high, object size, brng_t *state, object lock) -cdef object _rand_int16(object low, object high, object size, brng_t *state, object lock) -cdef object _rand_int8(object low, object high, object size, brng_t *state, object lock) diff --git a/_randomgen/randomgen/bounded_integers.pyx b/_randomgen/randomgen/bounded_integers.pyx deleted file mode 100644 index c9fb310c64ff..000000000000 --- a/_randomgen/randomgen/bounded_integers.pyx +++ /dev/null @@ -1,1181 +0,0 @@ -#!python -#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True - -import numpy as np -cimport numpy as np -from distributions cimport * -np.import_array() - - - - -cdef object _rand_uint32_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): - """Array path for smaller integer types""" - cdef uint32_t rng, last_rng, off, val, mask, out_val - cdef uint32_t buf - cdef uint32_t *out_data - cdef uint64_t low_v, high_v - cdef np.ndarray low_arr, high_arr, out_arr - cdef np.npy_intp i, cnt - cdef np.broadcast it - cdef int buf_rem = 0 - - - # Array path - low_arr = low - high_arr = high - if np.any(np.less(low_arr, 0)): - raise ValueError('low is out of bounds for uint32') - if np.any(np.greater(high_arr, 0X100000000ULL)): - raise ValueError('high is out of bounds for uint32') - if np.any(np.greater_equal(low_arr, high_arr)): - raise ValueError('low >= high') - - low_arr = np.PyArray_FROM_OTF(low, np.NPY_UINT64, np.NPY_ALIGNED | np.NPY_FORCECAST) - high_arr = np.PyArray_FROM_OTF(high, np.NPY_UINT64, np.NPY_ALIGNED | np.NPY_FORCECAST) - - if size is not None: - out_arr = np.empty(size, np.uint32) - else: - it = np.PyArray_MultiIterNew2(low_arr, high_arr) - out_arr = np.empty(it.shape, np.uint32) - - it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) - out_data = np.PyArray_DATA(out_arr) - cnt = np.PyArray_SIZE(out_arr) - mask = last_rng = 0 - with lock, nogil: - for i in range(cnt): - low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] - high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] - rng = ((high_v - 1) - low_v) - off = (low_v) - - if rng != last_rng: - # Smallest bit mask >= max - mask = _gen_mask(rng) - - out_data[i] = random_buffered_bounded_uint32(state, off, rng, mask, &buf_rem, &buf) - - np.PyArray_MultiIter_NEXT(it) - return out_arr - - -cdef object _rand_uint16_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): - """Array path for smaller integer types""" - cdef uint16_t rng, last_rng, off, val, mask, out_val - cdef uint32_t buf - cdef uint16_t *out_data - cdef uint32_t low_v, high_v - cdef np.ndarray low_arr, high_arr, out_arr - cdef np.npy_intp i, cnt - cdef np.broadcast it - cdef int buf_rem = 0 - - - # Array path - low_arr = low - high_arr = high - if np.any(np.less(low_arr, 0)): - raise ValueError('low is out of bounds for uint16') - if np.any(np.greater(high_arr, 0X10000UL)): - raise ValueError('high is out of bounds for uint16') - if np.any(np.greater_equal(low_arr, high_arr)): - raise ValueError('low >= high') - - low_arr = np.PyArray_FROM_OTF(low, np.NPY_UINT32, np.NPY_ALIGNED | np.NPY_FORCECAST) - high_arr = np.PyArray_FROM_OTF(high, np.NPY_UINT32, np.NPY_ALIGNED | np.NPY_FORCECAST) - - if size is not None: - out_arr = np.empty(size, np.uint16) - else: - it = np.PyArray_MultiIterNew2(low_arr, high_arr) - out_arr = np.empty(it.shape, np.uint16) - - it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) - out_data = np.PyArray_DATA(out_arr) - cnt = np.PyArray_SIZE(out_arr) - mask = last_rng = 0 - with lock, nogil: - for i in range(cnt): - low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] - high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] - rng = ((high_v - 1) - low_v) - off = (low_v) - - if rng != last_rng: - # Smallest bit mask >= max - mask = _gen_mask(rng) - - out_data[i] = random_buffered_bounded_uint16(state, off, rng, mask, &buf_rem, &buf) - - np.PyArray_MultiIter_NEXT(it) - return out_arr - - -cdef object _rand_uint8_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): - """Array path for smaller integer types""" - cdef uint8_t rng, last_rng, off, val, mask, out_val - cdef uint32_t buf - cdef uint8_t *out_data - cdef uint16_t low_v, high_v - cdef np.ndarray low_arr, high_arr, out_arr - cdef np.npy_intp i, cnt - cdef np.broadcast it - cdef int buf_rem = 0 - - - # Array path - low_arr = low - high_arr = high - if np.any(np.less(low_arr, 0)): - raise ValueError('low is out of bounds for uint8') - if np.any(np.greater(high_arr, 0X100UL)): - raise ValueError('high is out of bounds for uint8') - if np.any(np.greater_equal(low_arr, high_arr)): - raise ValueError('low >= high') - - low_arr = np.PyArray_FROM_OTF(low, np.NPY_UINT16, np.NPY_ALIGNED | np.NPY_FORCECAST) - high_arr = np.PyArray_FROM_OTF(high, np.NPY_UINT16, np.NPY_ALIGNED | np.NPY_FORCECAST) - - if size is not None: - out_arr = np.empty(size, np.uint8) - else: - it = np.PyArray_MultiIterNew2(low_arr, high_arr) - out_arr = np.empty(it.shape, np.uint8) - - it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) - out_data = np.PyArray_DATA(out_arr) - cnt = np.PyArray_SIZE(out_arr) - mask = last_rng = 0 - with lock, nogil: - for i in range(cnt): - low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] - high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] - rng = ((high_v - 1) - low_v) - off = (low_v) - - if rng != last_rng: - # Smallest bit mask >= max - mask = _gen_mask(rng) - - out_data[i] = random_buffered_bounded_uint8(state, off, rng, mask, &buf_rem, &buf) - - np.PyArray_MultiIter_NEXT(it) - return out_arr - - -cdef object _rand_bool_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): - """Array path for smaller integer types""" - cdef bool_t rng, last_rng, off, val, mask, out_val - cdef uint32_t buf - cdef bool_t *out_data - cdef uint8_t low_v, high_v - cdef np.ndarray low_arr, high_arr, out_arr - cdef np.npy_intp i, cnt - cdef np.broadcast it - cdef int buf_rem = 0 - - - # Array path - low_arr = low - high_arr = high - if np.any(np.less(low_arr, 0)): - raise ValueError('low is out of bounds for bool') - if np.any(np.greater(high_arr, 0x2UL)): - raise ValueError('high is out of bounds for bool') - if np.any(np.greater_equal(low_arr, high_arr)): - raise ValueError('low >= high') - - low_arr = np.PyArray_FROM_OTF(low, np.NPY_UINT8, np.NPY_ALIGNED | np.NPY_FORCECAST) - high_arr = np.PyArray_FROM_OTF(high, np.NPY_UINT8, np.NPY_ALIGNED | np.NPY_FORCECAST) - - if size is not None: - out_arr = np.empty(size, np.bool_) - else: - it = np.PyArray_MultiIterNew2(low_arr, high_arr) - out_arr = np.empty(it.shape, np.bool_) - - it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) - out_data = np.PyArray_DATA(out_arr) - cnt = np.PyArray_SIZE(out_arr) - mask = last_rng = 0 - with lock, nogil: - for i in range(cnt): - low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] - high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] - rng = ((high_v - 1) - low_v) - off = (low_v) - - if rng != last_rng: - # Smallest bit mask >= max - mask = _gen_mask(rng) - - out_data[i] = random_buffered_bounded_bool(state, off, rng, mask, &buf_rem, &buf) - - np.PyArray_MultiIter_NEXT(it) - return out_arr - - -cdef object _rand_int32_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): - """Array path for smaller integer types""" - cdef uint32_t rng, last_rng, off, val, mask, out_val - cdef uint32_t buf - cdef uint32_t *out_data - cdef uint64_t low_v, high_v - cdef np.ndarray low_arr, high_arr, out_arr - cdef np.npy_intp i, cnt - cdef np.broadcast it - cdef int buf_rem = 0 - - - # Array path - low_arr = low - high_arr = high - if np.any(np.less(low_arr, -0x80000000LL)): - raise ValueError('low is out of bounds for int32') - if np.any(np.greater(high_arr, 0x80000000LL)): - raise ValueError('high is out of bounds for int32') - if np.any(np.greater_equal(low_arr, high_arr)): - raise ValueError('low >= high') - - low_arr = np.PyArray_FROM_OTF(low, np.NPY_INT64, np.NPY_ALIGNED | np.NPY_FORCECAST) - high_arr = np.PyArray_FROM_OTF(high, np.NPY_INT64, np.NPY_ALIGNED | np.NPY_FORCECAST) - - if size is not None: - out_arr = np.empty(size, np.int32) - else: - it = np.PyArray_MultiIterNew2(low_arr, high_arr) - out_arr = np.empty(it.shape, np.int32) - - it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) - out_data = np.PyArray_DATA(out_arr) - cnt = np.PyArray_SIZE(out_arr) - mask = last_rng = 0 - with lock, nogil: - for i in range(cnt): - low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] - high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] - rng = ((high_v - 1) - low_v) - off = (low_v) - - if rng != last_rng: - # Smallest bit mask >= max - mask = _gen_mask(rng) - - out_data[i] = random_buffered_bounded_uint32(state, off, rng, mask, &buf_rem, &buf) - - np.PyArray_MultiIter_NEXT(it) - return out_arr - - -cdef object _rand_int16_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): - """Array path for smaller integer types""" - cdef uint16_t rng, last_rng, off, val, mask, out_val - cdef uint32_t buf - cdef uint16_t *out_data - cdef uint32_t low_v, high_v - cdef np.ndarray low_arr, high_arr, out_arr - cdef np.npy_intp i, cnt - cdef np.broadcast it - cdef int buf_rem = 0 - - - # Array path - low_arr = low - high_arr = high - if np.any(np.less(low_arr, -0x8000LL)): - raise ValueError('low is out of bounds for int16') - if np.any(np.greater(high_arr, 0x8000LL)): - raise ValueError('high is out of bounds for int16') - if np.any(np.greater_equal(low_arr, high_arr)): - raise ValueError('low >= high') - - low_arr = np.PyArray_FROM_OTF(low, np.NPY_INT32, np.NPY_ALIGNED | np.NPY_FORCECAST) - high_arr = np.PyArray_FROM_OTF(high, np.NPY_INT32, np.NPY_ALIGNED | np.NPY_FORCECAST) - - if size is not None: - out_arr = np.empty(size, np.int16) - else: - it = np.PyArray_MultiIterNew2(low_arr, high_arr) - out_arr = np.empty(it.shape, np.int16) - - it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) - out_data = np.PyArray_DATA(out_arr) - cnt = np.PyArray_SIZE(out_arr) - mask = last_rng = 0 - with lock, nogil: - for i in range(cnt): - low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] - high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] - rng = ((high_v - 1) - low_v) - off = (low_v) - - if rng != last_rng: - # Smallest bit mask >= max - mask = _gen_mask(rng) - - out_data[i] = random_buffered_bounded_uint16(state, off, rng, mask, &buf_rem, &buf) - - np.PyArray_MultiIter_NEXT(it) - return out_arr - - -cdef object _rand_int8_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): - """Array path for smaller integer types""" - cdef uint8_t rng, last_rng, off, val, mask, out_val - cdef uint32_t buf - cdef uint8_t *out_data - cdef uint16_t low_v, high_v - cdef np.ndarray low_arr, high_arr, out_arr - cdef np.npy_intp i, cnt - cdef np.broadcast it - cdef int buf_rem = 0 - - - # Array path - low_arr = low - high_arr = high - if np.any(np.less(low_arr, -0x80LL)): - raise ValueError('low is out of bounds for int8') - if np.any(np.greater(high_arr, 0x80LL)): - raise ValueError('high is out of bounds for int8') - if np.any(np.greater_equal(low_arr, high_arr)): - raise ValueError('low >= high') - - low_arr = np.PyArray_FROM_OTF(low, np.NPY_INT16, np.NPY_ALIGNED | np.NPY_FORCECAST) - high_arr = np.PyArray_FROM_OTF(high, np.NPY_INT16, np.NPY_ALIGNED | np.NPY_FORCECAST) - - if size is not None: - out_arr = np.empty(size, np.int8) - else: - it = np.PyArray_MultiIterNew2(low_arr, high_arr) - out_arr = np.empty(it.shape, np.int8) - - it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) - out_data = np.PyArray_DATA(out_arr) - cnt = np.PyArray_SIZE(out_arr) - mask = last_rng = 0 - with lock, nogil: - for i in range(cnt): - low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] - high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] - rng = ((high_v - 1) - low_v) - off = (low_v) - - if rng != last_rng: - # Smallest bit mask >= max - mask = _gen_mask(rng) - - out_data[i] = random_buffered_bounded_uint8(state, off, rng, mask, &buf_rem, &buf) - - np.PyArray_MultiIter_NEXT(it) - return out_arr - - - -cdef object _rand_uint64_broadcast(object low, object high, object size, brng_t *state, object lock): - """Array path for 64-bit integer types""" - cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr - cdef np.npy_intp i, cnt, n - cdef np.broadcast it - cdef object closed_upper - cdef uint64_t *out_data - cdef uint64_t *highm1_data - cdef uint64_t low_v, high_v - cdef uint64_t rng, last_rng, val, mask, off, out_val - - low_arr = low - high_arr = high - - if np.any(np.less(low_arr, 0x0ULL)): - raise ValueError('low is out of bounds for uint64') - - highm1_arr = np.empty_like(high_arr, dtype=np.uint64) - highm1_data = np.PyArray_DATA(highm1_arr) - cnt = np.PyArray_SIZE(high_arr) - flat = high_arr.flat - for i in range(cnt): - closed_upper = int(flat[i]) - 1 - if closed_upper > 0xFFFFFFFFFFFFFFFFULL: - raise ValueError('high is out of bounds for uint64') - if closed_upper < 0x0ULL: - raise ValueError('low >= high') - highm1_data[i] = closed_upper - - if np.any(np.greater(low_arr, highm1_arr)): - raise ValueError('low >= high') - - high_arr = highm1_arr - low_arr = np.PyArray_FROM_OTF(low, np.NPY_UINT64, np.NPY_ALIGNED | np.NPY_FORCECAST) - - if size is not None: - out_arr = np.empty(size, np.uint64) - else: - it = np.PyArray_MultiIterNew2(low_arr, high_arr) - out_arr = np.empty(it.shape, np.uint64) - - it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) - out_data = np.PyArray_DATA(out_arr) - n = np.PyArray_SIZE(out_arr) - mask = last_rng = 0 - with lock, nogil: - for i in range(n): - low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] - high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] - rng = (high_v - low_v) # No -1 here since implemented above - off = (low_v) - - if rng != last_rng: - mask = _gen_mask(rng) - out_data[i] = random_bounded_uint64(state, off, rng, mask) - - np.PyArray_MultiIter_NEXT(it) - - return out_arr - -cdef object _rand_int64_broadcast(object low, object high, object size, brng_t *state, object lock): - """Array path for 64-bit integer types""" - cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr - cdef np.npy_intp i, cnt, n - cdef np.broadcast it - cdef object closed_upper - cdef uint64_t *out_data - cdef int64_t *highm1_data - cdef int64_t low_v, high_v - cdef uint64_t rng, last_rng, val, mask, off, out_val - - low_arr = low - high_arr = high - - if np.any(np.less(low_arr, -0x8000000000000000LL)): - raise ValueError('low is out of bounds for int64') - - highm1_arr = np.empty_like(high_arr, dtype=np.int64) - highm1_data = np.PyArray_DATA(highm1_arr) - cnt = np.PyArray_SIZE(high_arr) - flat = high_arr.flat - for i in range(cnt): - closed_upper = int(flat[i]) - 1 - if closed_upper > 0x7FFFFFFFFFFFFFFFLL: - raise ValueError('high is out of bounds for int64') - if closed_upper < -0x8000000000000000LL: - raise ValueError('low >= high') - highm1_data[i] = closed_upper - - if np.any(np.greater(low_arr, highm1_arr)): - raise ValueError('low >= high') - - high_arr = highm1_arr - low_arr = np.PyArray_FROM_OTF(low, np.NPY_INT64, np.NPY_ALIGNED | np.NPY_FORCECAST) - - if size is not None: - out_arr = np.empty(size, np.int64) - else: - it = np.PyArray_MultiIterNew2(low_arr, high_arr) - out_arr = np.empty(it.shape, np.int64) - - it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr) - out_data = np.PyArray_DATA(out_arr) - n = np.PyArray_SIZE(out_arr) - mask = last_rng = 0 - with lock, nogil: - for i in range(n): - low_v = (np.PyArray_MultiIter_DATA(it, 0))[0] - high_v = (np.PyArray_MultiIter_DATA(it, 1))[0] - rng = (high_v - low_v) # No -1 here since implemented above - off = (low_v) - - if rng != last_rng: - mask = _gen_mask(rng) - out_data[i] = random_bounded_uint64(state, off, rng, mask) - - np.PyArray_MultiIter_NEXT(it) - - return out_arr - - - -cdef object _rand_uint64(object low, object high, object size, brng_t *state, object lock): - """ - _rand_uint64(low, high, size, *state, lock) - - Return random np.uint64 integers between `low` and `high`, inclusive. - - Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), - then results are from [0, `low`). On entry the arguments are presumed - to have been validated for size and order for the np.uint64 type. - - Parameters - ---------- - low : int or array-like - Lowest (signed) integer to be drawn from the distribution (unless - ``high=None``, in which case this parameter is the *highest* such - integer). - high : int or array-like - If provided, the largest (signed) integer to be drawn from the - distribution (see above for behavior if ``high=None``). - size : int or tuple of ints - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - state : basic random state - State to use in the core random number generators - lock : threading.Lock - Lock to prevent multiple using a single generator simultaneously - - Returns - ------- - out : python scalar or ndarray of np.uint64 - `size`-shaped array of random integers from the appropriate - distribution, or a single such random int if `size` not provided. - """ - cdef np.ndarray out_arr, low_arr, high_arr - cdef uint64_t rng, off, out_val - cdef uint64_t *out_data - cdef np.npy_intp i, n, cnt - - if size is not None: - if (np.prod(size) == 0): - return np.empty(size, dtype=np.uint64) - - low_arr = np.array(low, copy=False) - high_arr = np.array(high, copy=False) - low_ndim = np.PyArray_NDIM(low_arr) - high_ndim = np.PyArray_NDIM(high_arr) - if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and - (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): - low = int(low_arr) - high = int(high_arr) - high -= 1 - - if low < 0x0ULL: - raise ValueError("low is out of bounds for uint64") - if high > 0xFFFFFFFFFFFFFFFFULL: - raise ValueError("high is out of bounds for uint64") - if low > high: # -1 already subtracted, closed interval - raise ValueError("low >= high") - - rng = (high - low) - off = (low) - if size is None: - with lock: - random_bounded_uint64_fill(state, off, rng, 1, &out_val) - return np.uint64(out_val) - else: - out_arr = np.empty(size, np.uint64) - cnt = np.PyArray_SIZE(out_arr) - out_data = np.PyArray_DATA(out_arr) - with lock, nogil: - random_bounded_uint64_fill(state, off, rng, cnt, out_data) - return out_arr - return _rand_uint64_broadcast(low_arr, high_arr, size, state, lock) - -cdef object _rand_uint32(object low, object high, object size, brng_t *state, object lock): - """ - _rand_uint32(low, high, size, *state, lock) - - Return random np.uint32 integers between `low` and `high`, inclusive. - - Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), - then results are from [0, `low`). On entry the arguments are presumed - to have been validated for size and order for the np.uint32 type. - - Parameters - ---------- - low : int or array-like - Lowest (signed) integer to be drawn from the distribution (unless - ``high=None``, in which case this parameter is the *highest* such - integer). - high : int or array-like - If provided, the largest (signed) integer to be drawn from the - distribution (see above for behavior if ``high=None``). - size : int or tuple of ints - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - state : basic random state - State to use in the core random number generators - lock : threading.Lock - Lock to prevent multiple using a single generator simultaneously - - Returns - ------- - out : python scalar or ndarray of np.uint32 - `size`-shaped array of random integers from the appropriate - distribution, or a single such random int if `size` not provided. - """ - cdef np.ndarray out_arr, low_arr, high_arr - cdef uint32_t rng, off, out_val - cdef uint32_t *out_data - cdef np.npy_intp i, n, cnt - - if size is not None: - if (np.prod(size) == 0): - return np.empty(size, dtype=np.uint32) - - low_arr = np.array(low, copy=False) - high_arr = np.array(high, copy=False) - low_ndim = np.PyArray_NDIM(low_arr) - high_ndim = np.PyArray_NDIM(high_arr) - if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and - (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): - low = int(low_arr) - high = int(high_arr) - high -= 1 - - if low < 0x0UL: - raise ValueError("low is out of bounds for uint32") - if high > 0XFFFFFFFFUL: - raise ValueError("high is out of bounds for uint32") - if low > high: # -1 already subtracted, closed interval - raise ValueError("low >= high") - - rng = (high - low) - off = (low) - if size is None: - with lock: - random_bounded_uint32_fill(state, off, rng, 1, &out_val) - return np.uint32(out_val) - else: - out_arr = np.empty(size, np.uint32) - cnt = np.PyArray_SIZE(out_arr) - out_data = np.PyArray_DATA(out_arr) - with lock, nogil: - random_bounded_uint32_fill(state, off, rng, cnt, out_data) - return out_arr - return _rand_uint32_broadcast(low_arr, high_arr, size, state, lock) - -cdef object _rand_uint16(object low, object high, object size, brng_t *state, object lock): - """ - _rand_uint16(low, high, size, *state, lock) - - Return random np.uint16 integers between `low` and `high`, inclusive. - - Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), - then results are from [0, `low`). On entry the arguments are presumed - to have been validated for size and order for the np.uint16 type. - - Parameters - ---------- - low : int or array-like - Lowest (signed) integer to be drawn from the distribution (unless - ``high=None``, in which case this parameter is the *highest* such - integer). - high : int or array-like - If provided, the largest (signed) integer to be drawn from the - distribution (see above for behavior if ``high=None``). - size : int or tuple of ints - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - state : basic random state - State to use in the core random number generators - lock : threading.Lock - Lock to prevent multiple using a single generator simultaneously - - Returns - ------- - out : python scalar or ndarray of np.uint16 - `size`-shaped array of random integers from the appropriate - distribution, or a single such random int if `size` not provided. - """ - cdef np.ndarray out_arr, low_arr, high_arr - cdef uint16_t rng, off, out_val - cdef uint16_t *out_data - cdef np.npy_intp i, n, cnt - - if size is not None: - if (np.prod(size) == 0): - return np.empty(size, dtype=np.uint16) - - low_arr = np.array(low, copy=False) - high_arr = np.array(high, copy=False) - low_ndim = np.PyArray_NDIM(low_arr) - high_ndim = np.PyArray_NDIM(high_arr) - if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and - (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): - low = int(low_arr) - high = int(high_arr) - high -= 1 - - if low < 0x0UL: - raise ValueError("low is out of bounds for uint16") - if high > 0XFFFFUL: - raise ValueError("high is out of bounds for uint16") - if low > high: # -1 already subtracted, closed interval - raise ValueError("low >= high") - - rng = (high - low) - off = (low) - if size is None: - with lock: - random_bounded_uint16_fill(state, off, rng, 1, &out_val) - return np.uint16(out_val) - else: - out_arr = np.empty(size, np.uint16) - cnt = np.PyArray_SIZE(out_arr) - out_data = np.PyArray_DATA(out_arr) - with lock, nogil: - random_bounded_uint16_fill(state, off, rng, cnt, out_data) - return out_arr - return _rand_uint16_broadcast(low_arr, high_arr, size, state, lock) - -cdef object _rand_uint8(object low, object high, object size, brng_t *state, object lock): - """ - _rand_uint8(low, high, size, *state, lock) - - Return random np.uint8 integers between `low` and `high`, inclusive. - - Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), - then results are from [0, `low`). On entry the arguments are presumed - to have been validated for size and order for the np.uint8 type. - - Parameters - ---------- - low : int or array-like - Lowest (signed) integer to be drawn from the distribution (unless - ``high=None``, in which case this parameter is the *highest* such - integer). - high : int or array-like - If provided, the largest (signed) integer to be drawn from the - distribution (see above for behavior if ``high=None``). - size : int or tuple of ints - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - state : basic random state - State to use in the core random number generators - lock : threading.Lock - Lock to prevent multiple using a single generator simultaneously - - Returns - ------- - out : python scalar or ndarray of np.uint8 - `size`-shaped array of random integers from the appropriate - distribution, or a single such random int if `size` not provided. - """ - cdef np.ndarray out_arr, low_arr, high_arr - cdef uint8_t rng, off, out_val - cdef uint8_t *out_data - cdef np.npy_intp i, n, cnt - - if size is not None: - if (np.prod(size) == 0): - return np.empty(size, dtype=np.uint8) - - low_arr = np.array(low, copy=False) - high_arr = np.array(high, copy=False) - low_ndim = np.PyArray_NDIM(low_arr) - high_ndim = np.PyArray_NDIM(high_arr) - if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and - (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): - low = int(low_arr) - high = int(high_arr) - high -= 1 - - if low < 0x0UL: - raise ValueError("low is out of bounds for uint8") - if high > 0XFFUL: - raise ValueError("high is out of bounds for uint8") - if low > high: # -1 already subtracted, closed interval - raise ValueError("low >= high") - - rng = (high - low) - off = (low) - if size is None: - with lock: - random_bounded_uint8_fill(state, off, rng, 1, &out_val) - return np.uint8(out_val) - else: - out_arr = np.empty(size, np.uint8) - cnt = np.PyArray_SIZE(out_arr) - out_data = np.PyArray_DATA(out_arr) - with lock, nogil: - random_bounded_uint8_fill(state, off, rng, cnt, out_data) - return out_arr - return _rand_uint8_broadcast(low_arr, high_arr, size, state, lock) - -cdef object _rand_bool(object low, object high, object size, brng_t *state, object lock): - """ - _rand_bool(low, high, size, *state, lock) - - Return random np.bool integers between `low` and `high`, inclusive. - - Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), - then results are from [0, `low`). On entry the arguments are presumed - to have been validated for size and order for the np.bool type. - - Parameters - ---------- - low : int or array-like - Lowest (signed) integer to be drawn from the distribution (unless - ``high=None``, in which case this parameter is the *highest* such - integer). - high : int or array-like - If provided, the largest (signed) integer to be drawn from the - distribution (see above for behavior if ``high=None``). - size : int or tuple of ints - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - state : basic random state - State to use in the core random number generators - lock : threading.Lock - Lock to prevent multiple using a single generator simultaneously - - Returns - ------- - out : python scalar or ndarray of np.bool - `size`-shaped array of random integers from the appropriate - distribution, or a single such random int if `size` not provided. - """ - cdef np.ndarray out_arr, low_arr, high_arr - cdef bool_t rng, off, out_val - cdef bool_t *out_data - cdef np.npy_intp i, n, cnt - - if size is not None: - if (np.prod(size) == 0): - return np.empty(size, dtype=np.bool) - - low_arr = np.array(low, copy=False) - high_arr = np.array(high, copy=False) - low_ndim = np.PyArray_NDIM(low_arr) - high_ndim = np.PyArray_NDIM(high_arr) - if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and - (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): - low = int(low_arr) - high = int(high_arr) - high -= 1 - - if low < 0x0UL: - raise ValueError("low is out of bounds for bool") - if high > 0x1UL: - raise ValueError("high is out of bounds for bool") - if low > high: # -1 already subtracted, closed interval - raise ValueError("low >= high") - - rng = (high - low) - off = (low) - if size is None: - with lock: - random_bounded_bool_fill(state, off, rng, 1, &out_val) - return np.bool_(out_val) - else: - out_arr = np.empty(size, np.bool) - cnt = np.PyArray_SIZE(out_arr) - out_data = np.PyArray_DATA(out_arr) - with lock, nogil: - random_bounded_bool_fill(state, off, rng, cnt, out_data) - return out_arr - return _rand_bool_broadcast(low_arr, high_arr, size, state, lock) - -cdef object _rand_int64(object low, object high, object size, brng_t *state, object lock): - """ - _rand_int64(low, high, size, *state, lock) - - Return random np.int64 integers between `low` and `high`, inclusive. - - Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), - then results are from [0, `low`). On entry the arguments are presumed - to have been validated for size and order for the np.int64 type. - - Parameters - ---------- - low : int or array-like - Lowest (signed) integer to be drawn from the distribution (unless - ``high=None``, in which case this parameter is the *highest* such - integer). - high : int or array-like - If provided, the largest (signed) integer to be drawn from the - distribution (see above for behavior if ``high=None``). - size : int or tuple of ints - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - state : basic random state - State to use in the core random number generators - lock : threading.Lock - Lock to prevent multiple using a single generator simultaneously - - Returns - ------- - out : python scalar or ndarray of np.int64 - `size`-shaped array of random integers from the appropriate - distribution, or a single such random int if `size` not provided. - """ - cdef np.ndarray out_arr, low_arr, high_arr - cdef uint64_t rng, off, out_val - cdef uint64_t *out_data - cdef np.npy_intp i, n, cnt - - if size is not None: - if (np.prod(size) == 0): - return np.empty(size, dtype=np.int64) - - low_arr = np.array(low, copy=False) - high_arr = np.array(high, copy=False) - low_ndim = np.PyArray_NDIM(low_arr) - high_ndim = np.PyArray_NDIM(high_arr) - if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and - (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): - low = int(low_arr) - high = int(high_arr) - high -= 1 - - if low < -0x8000000000000000LL: - raise ValueError("low is out of bounds for int64") - if high > 0x7FFFFFFFFFFFFFFFL: - raise ValueError("high is out of bounds for int64") - if low > high: # -1 already subtracted, closed interval - raise ValueError("low >= high") - - rng = (high - low) - off = (low) - if size is None: - with lock: - random_bounded_uint64_fill(state, off, rng, 1, &out_val) - return np.int64(out_val) - else: - out_arr = np.empty(size, np.int64) - cnt = np.PyArray_SIZE(out_arr) - out_data = np.PyArray_DATA(out_arr) - with lock, nogil: - random_bounded_uint64_fill(state, off, rng, cnt, out_data) - return out_arr - return _rand_int64_broadcast(low_arr, high_arr, size, state, lock) - -cdef object _rand_int32(object low, object high, object size, brng_t *state, object lock): - """ - _rand_int32(low, high, size, *state, lock) - - Return random np.int32 integers between `low` and `high`, inclusive. - - Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), - then results are from [0, `low`). On entry the arguments are presumed - to have been validated for size and order for the np.int32 type. - - Parameters - ---------- - low : int or array-like - Lowest (signed) integer to be drawn from the distribution (unless - ``high=None``, in which case this parameter is the *highest* such - integer). - high : int or array-like - If provided, the largest (signed) integer to be drawn from the - distribution (see above for behavior if ``high=None``). - size : int or tuple of ints - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - state : basic random state - State to use in the core random number generators - lock : threading.Lock - Lock to prevent multiple using a single generator simultaneously - - Returns - ------- - out : python scalar or ndarray of np.int32 - `size`-shaped array of random integers from the appropriate - distribution, or a single such random int if `size` not provided. - """ - cdef np.ndarray out_arr, low_arr, high_arr - cdef uint32_t rng, off, out_val - cdef uint32_t *out_data - cdef np.npy_intp i, n, cnt - - if size is not None: - if (np.prod(size) == 0): - return np.empty(size, dtype=np.int32) - - low_arr = np.array(low, copy=False) - high_arr = np.array(high, copy=False) - low_ndim = np.PyArray_NDIM(low_arr) - high_ndim = np.PyArray_NDIM(high_arr) - if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and - (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): - low = int(low_arr) - high = int(high_arr) - high -= 1 - - if low < -0x80000000L: - raise ValueError("low is out of bounds for int32") - if high > 0x7FFFFFFFL: - raise ValueError("high is out of bounds for int32") - if low > high: # -1 already subtracted, closed interval - raise ValueError("low >= high") - - rng = (high - low) - off = (low) - if size is None: - with lock: - random_bounded_uint32_fill(state, off, rng, 1, &out_val) - return np.int32(out_val) - else: - out_arr = np.empty(size, np.int32) - cnt = np.PyArray_SIZE(out_arr) - out_data = np.PyArray_DATA(out_arr) - with lock, nogil: - random_bounded_uint32_fill(state, off, rng, cnt, out_data) - return out_arr - return _rand_int32_broadcast(low_arr, high_arr, size, state, lock) - -cdef object _rand_int16(object low, object high, object size, brng_t *state, object lock): - """ - _rand_int16(low, high, size, *state, lock) - - Return random np.int16 integers between `low` and `high`, inclusive. - - Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), - then results are from [0, `low`). On entry the arguments are presumed - to have been validated for size and order for the np.int16 type. - - Parameters - ---------- - low : int or array-like - Lowest (signed) integer to be drawn from the distribution (unless - ``high=None``, in which case this parameter is the *highest* such - integer). - high : int or array-like - If provided, the largest (signed) integer to be drawn from the - distribution (see above for behavior if ``high=None``). - size : int or tuple of ints - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - state : basic random state - State to use in the core random number generators - lock : threading.Lock - Lock to prevent multiple using a single generator simultaneously - - Returns - ------- - out : python scalar or ndarray of np.int16 - `size`-shaped array of random integers from the appropriate - distribution, or a single such random int if `size` not provided. - """ - cdef np.ndarray out_arr, low_arr, high_arr - cdef uint16_t rng, off, out_val - cdef uint16_t *out_data - cdef np.npy_intp i, n, cnt - - if size is not None: - if (np.prod(size) == 0): - return np.empty(size, dtype=np.int16) - - low_arr = np.array(low, copy=False) - high_arr = np.array(high, copy=False) - low_ndim = np.PyArray_NDIM(low_arr) - high_ndim = np.PyArray_NDIM(high_arr) - if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and - (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): - low = int(low_arr) - high = int(high_arr) - high -= 1 - - if low < -0x8000L: - raise ValueError("low is out of bounds for int16") - if high > 0x7FFFL: - raise ValueError("high is out of bounds for int16") - if low > high: # -1 already subtracted, closed interval - raise ValueError("low >= high") - - rng = (high - low) - off = (low) - if size is None: - with lock: - random_bounded_uint16_fill(state, off, rng, 1, &out_val) - return np.int16(out_val) - else: - out_arr = np.empty(size, np.int16) - cnt = np.PyArray_SIZE(out_arr) - out_data = np.PyArray_DATA(out_arr) - with lock, nogil: - random_bounded_uint16_fill(state, off, rng, cnt, out_data) - return out_arr - return _rand_int16_broadcast(low_arr, high_arr, size, state, lock) - -cdef object _rand_int8(object low, object high, object size, brng_t *state, object lock): - """ - _rand_int8(low, high, size, *state, lock) - - Return random np.int8 integers between `low` and `high`, inclusive. - - Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), - then results are from [0, `low`). On entry the arguments are presumed - to have been validated for size and order for the np.int8 type. - - Parameters - ---------- - low : int or array-like - Lowest (signed) integer to be drawn from the distribution (unless - ``high=None``, in which case this parameter is the *highest* such - integer). - high : int or array-like - If provided, the largest (signed) integer to be drawn from the - distribution (see above for behavior if ``high=None``). - size : int or tuple of ints - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - state : basic random state - State to use in the core random number generators - lock : threading.Lock - Lock to prevent multiple using a single generator simultaneously - - Returns - ------- - out : python scalar or ndarray of np.int8 - `size`-shaped array of random integers from the appropriate - distribution, or a single such random int if `size` not provided. - """ - cdef np.ndarray out_arr, low_arr, high_arr - cdef uint8_t rng, off, out_val - cdef uint8_t *out_data - cdef np.npy_intp i, n, cnt - - if size is not None: - if (np.prod(size) == 0): - return np.empty(size, dtype=np.int8) - - low_arr = np.array(low, copy=False) - high_arr = np.array(high, copy=False) - low_ndim = np.PyArray_NDIM(low_arr) - high_ndim = np.PyArray_NDIM(high_arr) - if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and - (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): - low = int(low_arr) - high = int(high_arr) - high -= 1 - - if low < -0x80L: - raise ValueError("low is out of bounds for int8") - if high > 0x7FL: - raise ValueError("high is out of bounds for int8") - if low > high: # -1 already subtracted, closed interval - raise ValueError("low >= high") - - rng = (high - low) - off = (low) - if size is None: - with lock: - random_bounded_uint8_fill(state, off, rng, 1, &out_val) - return np.int8(out_val) - else: - out_arr = np.empty(size, np.int8) - cnt = np.PyArray_SIZE(out_arr) - out_data = np.PyArray_DATA(out_arr) - with lock, nogil: - random_bounded_uint8_fill(state, off, rng, cnt, out_data) - return out_arr - return _rand_int8_broadcast(low_arr, high_arr, size, state, lock) diff --git a/_randomgen/randomgen/tests/data/__init__.py b/_randomgen/randomgen/tests/data/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 2bd987367eba..f4a0902c1472 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -245,7 +245,8 @@ def is_pure(self): "PCG_EMULATED_MATH": PCG_EMULATED_MATH}), packages=find_packages(), package_dir={'randomgen': './randomgen'}, - package_data={'': ['*.h', '*.pxi', '*.pyx', '*.pxd', '*.in']}, + package_data={'': ['*.h', '*.pxi', '*.pyx', '*.pxd', '*.in'], + 'randomgen.tests.data': ['*.csv']}, include_package_data=True, license='NSCA', author='Kevin Sheppard', From 0223c483ce5d977b349b7aee000fbf6dcb5e3324 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 17 Mar 2018 07:21:50 +0000 Subject: [PATCH 099/279] BLD: Cache pip Add cache for pip --- _randomgen/.travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 1c950fdab6b9..5fb593cff07c 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -12,6 +12,10 @@ env: # Doctr deploy key for bashtage/randomgen - secure: "czwFlflS1lcfbSQ9ktv+pLAPV9/6+wmwiMTyIYyv5xgQVWRL5NRebWH+ZhQ6s2T5x17wFMtlafcAvkdV0CHQZLru34V2UNldCapuEtQ8b32EDHBXHKbs45b7SSkLx4TFXdjiJurleY4ZIKle0gX6BW21zYBwaHJqbN6I8nRv9Rp47XEU1UV1Mdf/PhfTnxY31rFrPYL77xeWJzoFfT8zao39V4gQds+1Ag7FjdNVdSDVKwDduF4kS7tIbKqb4M+jsbc3PIKyP9nyQpEQF5ebJuG7mqXJhVJGEL83rBx8MLFPA/1X3cUzKacgKyp2+Wmlt0EVhwCa1aRf9cSK6I7TbMC7/eGtDnC2ToiRlFJurVRblaEmhzVQS1yQ4Dkooqsj9hNVl6nhu7JfR52GLogns33Ec/yYuRcWcULKSlR5Cerfef/5YijBEhlr9X76SJiOpjvS4lwWFYX+h8xzuVhRLGwIVB9oQNllxYItzcDSGmRx+EOMXWASHmoUDnBOZg4GMVukqOcF5l0ynoepiA1YHLdZlMy6SB3P7BZKF/aNCOn9nXw+N9X4U/yUpkM3Pb7HoGdNrC8RO4SwrNjGrarkdEB6e1lBReK/dqcylaF/mpK9VLpfQszDI8xnR4VCmlEM+le0xOsyHfeGciabdI4KH0i0SfYl4ls5XrN+CaqFWdo=" +cache: + directories: + - $HOME/.cache/pip + matrix: fast_finish: true include: From 43c8746c034d1078ef0c8f96b407c3ca1c43b089 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 17 Mar 2018 07:50:13 +0000 Subject: [PATCH 100/279] BLD: Show gcc version Show gcc and cland version --- _randomgen/.travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 5fb593cff07c..b11f5b73055a 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -53,6 +53,8 @@ before_install: - export BUILD_DIR=${PWD} - if [[ ${DOCBUILD} == true ]]; then pip install sphinx sphinx_rtd_theme guzzle_sphinx_theme ipython doctr -q; fi - if [[ ${DOCBUILD} == true ]]; then conda install numba pandas matplotlib --quiet; fi + - gcc --version || true + - clang --version || true install: - python setup.py develop From 292e08f3f3dff4eb6e05b3636e2872b2c1c57106 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 17 Mar 2018 10:49:58 +0000 Subject: [PATCH 101/279] DOC: Update change-log Update change log for release --- _randomgen/doc/source/change-log.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst index 36c46223ad4c..c59718b9c7f5 100644 --- a/_randomgen/doc/source/change-log.rst +++ b/_randomgen/doc/source/change-log.rst @@ -1,4 +1,11 @@ Change Log ---------- -The project is too new for a change log. \ No newline at end of file +Changes since v1.14 +=================== + +- Switch to array-fillers for 0 parameter distribution to improve performance +- Small changes to build on manylinux +- Build wheels using multibuild + + From 921c9fe1419969aad0ae7fdccdada0c5aa447fd2 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 21 Mar 2018 10:14:18 +0000 Subject: [PATCH 102/279] DOC: Add PyPi badge Add badge Improve pypandoc conversion --- _randomgen/README.md | 2 +- _randomgen/README.rst | 4 +++- _randomgen/setup.py | 7 ++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index 036af1b619b1..836ef131539d 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -2,6 +2,7 @@ [![Travis Build Status](https://travis-ci.org/bashtage/randomgen.svg?branch=master)](https://travis-ci.org/bashtage/randomgen) [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true)](https://ci.appveyor.com/project/bashtage/randomgen/branch/master) +[![PyPI version](https://badge.fury.io/py/randomgen.svg)](https://pypi.org/project/randomgen/) Random Number Generator using settable Basic RNG interface for future NumPy RandomState evolution. @@ -9,7 +10,6 @@ NumPy RandomState evolution. This is a library and generic interface for alternative random generators in Python and NumPy. - ### Compatibility Warning RandomGen no longer supports Box-Muller normal variates and so it not 100% compatible with NumPy (or randomstate). Box-Muller normals are slow diff --git a/_randomgen/README.rst b/_randomgen/README.rst index b9a0ad5f5053..7448523d8838 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -1,7 +1,7 @@ RandomGen ========= -|Travis Build Status| |Appveyor Build Status| +|Travis Build Status| |Appveyor Build Status| |PyPI version| Random Number Generator using settable Basic RNG interface for future NumPy RandomState evolution. @@ -279,3 +279,5 @@ NumPy's mt19937. :target: https://travis-ci.org/bashtage/randomgen .. |Appveyor Build Status| image:: https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true :target: https://ci.appveyor.com/project/bashtage/randomgen/branch/master +.. |PyPI version| image:: https://badge.fury.io/py/randomgen.svg + :target: https://pypi.org/project/randomgen/ diff --git a/_randomgen/setup.py b/_randomgen/setup.py index f4a0902c1472..c010cfc9bff5 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -22,8 +22,8 @@ try: import pypandoc # With an input file: it will infer the input format from the filename - with open('README.rst', 'w') as readme: - readme.write(pypandoc.convert_file('README.md', 'rst')) + with open('README.rst', 'wb') as readme: + readme.write(pypandoc.convert_file('README.md', 'rst').encode('utf8')) except ImportError: import warnings warnings.warn( @@ -45,7 +45,8 @@ EXTRA_INCLUDE_DIRS = [] EXTRA_LINK_ARGS = [] # Undef for manylinux -EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else ['-std=c99', '-U__GNUC_GNU_INLINE__'] +EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else [ + '-std=c99', '-U__GNUC_GNU_INLINE__'] if os.name == 'nt': EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] if DEBUG: From 3d0ad7eb3bb9eb27d6b9d3f03b2f2843d754df09 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 21 Mar 2018 21:08:07 +0000 Subject: [PATCH 103/279] BUG: Restore nogil for fillers Use nogil for fillers --- _randomgen/randomgen/distributions.pxd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_randomgen/randomgen/distributions.pxd b/_randomgen/randomgen/distributions.pxd index 202c7439de0a..6b13733d3e25 100644 --- a/_randomgen/randomgen/distributions.pxd +++ b/_randomgen/randomgen/distributions.pxd @@ -36,11 +36,11 @@ cdef extern from "src/distributions/distributions.h": ctypedef brng brng_t double random_double(brng_t *brng_state) nogil - void random_double_fill(brng_t* brng_state, np.npy_intp cnt, double *out) + void random_double_fill(brng_t* brng_state, np.npy_intp cnt, double *out) nogil double random_standard_exponential(brng_t *brng_state) nogil - void random_standard_exponential_fill(brng_t *brng_state, np.npy_intp cnt, double *out) + void random_standard_exponential_fill(brng_t *brng_state, np.npy_intp cnt, double *out) nogil double random_standard_exponential_zig(brng_t *brng_state) nogil - void random_standard_exponential_zig_fill(brng_t *brng_state, np.npy_intp cnt, double *out) + void random_standard_exponential_zig_fill(brng_t *brng_state, np.npy_intp cnt, double *out) nogil double random_gauss_zig(brng_t* brng_state) nogil void random_gauss_zig_fill(brng_t *brng_state, np.npy_intp count, double *out) nogil double random_standard_gamma_zig(brng_t *brng_state, double shape) nogil From dae0ee8db968692837e4814d5cb0f8539675faad Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 22 Mar 2018 10:56:46 +0000 Subject: [PATCH 104/279] CLN: Remove references to long Replace conversion to long with int64 --- _randomgen/randomgen/common.pyx | 10 +++++----- _randomgen/randomgen/generator.pyx | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/_randomgen/randomgen/common.pyx b/_randomgen/randomgen/common.pyx index e28342e68442..8e2f69c5d8a8 100644 --- a/_randomgen/randomgen/common.pyx +++ b/_randomgen/randomgen/common.pyx @@ -2,7 +2,7 @@ #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True from collections import namedtuple -from cpython cimport PyInt_AsLong, PyFloat_AsDouble +from cpython cimport PyFloat_AsDouble import sys import numpy as np cimport numpy as np @@ -642,20 +642,20 @@ cdef object disc(void *func, brng_t *state, object size, object lock, if b_constraint != CONS_NONE and is_scalar: check_constraint(_db, b_name, b_constraint) elif narg_int64 == 1: - _ib = PyInt_AsLong(b) + _ib = b if b_constraint != CONS_NONE and is_scalar: check_constraint(_ib, b_name, b_constraint) else: if narg_int64 > 0: - _ia = PyInt_AsLong(a) + _ia = a if a_constraint != CONS_NONE and is_scalar: check_constraint(_ia, a_name, a_constraint) if narg_int64 > 1: - _ib = PyInt_AsLong(b) + _ib = b if b_constraint != CONS_NONE and is_scalar: check_constraint(_ib, b_name, b_constraint) if narg_int64 > 2 : - _ic = PyInt_AsLong(c) + _ic = c if c_constraint != CONS_NONE and is_scalar: check_constraint(_ic, c_name, c_constraint) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 1aa630dfdaa6..c9d7659945a6 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -4,7 +4,7 @@ import operator import warnings from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer -from cpython cimport (Py_INCREF, PyComplex_RealAsDouble, PyInt_AsLong, +from cpython cimport (Py_INCREF, PyComplex_RealAsDouble, PyComplex_ImagAsDouble, PyComplex_FromDoubles, PyFloat_AsDouble) from common cimport * from distributions cimport * @@ -3237,7 +3237,7 @@ cdef class RandomGenerator: return randoms _dp = PyFloat_AsDouble(p) - _in = PyInt_AsLong(n) + _in = n check_constraint(_dp, 'p', CONS_BOUNDED_0_1_NOTNAN) check_constraint(_in, 'n', CONS_NON_NEGATIVE) @@ -3632,9 +3632,9 @@ cdef class RandomGenerator: if np.PyArray_NDIM(ongood) == np.PyArray_NDIM(onbad) == np.PyArray_NDIM(onsample) == 0: - lngood = PyInt_AsLong(ngood) - lnbad = PyInt_AsLong(nbad) - lnsample = PyInt_AsLong(nsample) + lngood = ngood + lnbad = nbad + lnsample = nsample if lngood < 0: raise ValueError("ngood < 0") From 61656c462638605694a20144fded06fcd6d6a894 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 21 Mar 2018 20:59:59 +0000 Subject: [PATCH 105/279] ENH: Add Box-Muller gauss Add legacy distributions through new generator --- _randomgen/.travis.yml | 4 +- _randomgen/README.md | 2 +- _randomgen/README.rst | 2 +- _randomgen/doc/source/change-log.rst | 2 + _randomgen/doc/source/extending.rst | 2 +- _randomgen/doc/source/index.rst | 3 +- _randomgen/doc/source/legacy.rst | 95 + _randomgen/doc/source/multithreading.rst | 96 +- _randomgen/doc/source/new-or-different.rst | 25 +- _randomgen/randomgen/common.pxd | 28 +- _randomgen/randomgen/common.pyx | 20 +- _randomgen/randomgen/legacy/__init__.py | 3 + _randomgen/randomgen/legacy/legacy.pyx | 1953 +++++++++++++++++ .../randomgen/legacy/legacy_distributions.pxd | 40 + .../src/distributions/distributions.c | 26 +- .../src/distributions/distributions.h | 12 +- .../src/legacy/distributions-boxmuller.c | 201 ++ .../src/legacy/distributions-boxmuller.h | 34 + .../randomgen/tests/test_against_numpy.py | 327 +-- .../randomgen/tests/test_numpy_mt19937.py | 223 +- _randomgen/requirements.txt | 2 +- _randomgen/setup.py | 10 + 22 files changed, 2710 insertions(+), 400 deletions(-) create mode 100644 _randomgen/doc/source/legacy.rst create mode 100644 _randomgen/randomgen/legacy/__init__.py create mode 100644 _randomgen/randomgen/legacy/legacy.pyx create mode 100644 _randomgen/randomgen/legacy/legacy_distributions.pxd create mode 100644 _randomgen/randomgen/src/legacy/distributions-boxmuller.c create mode 100644 _randomgen/randomgen/src/legacy/distributions-boxmuller.h diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index b11f5b73055a..052681727ab9 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -20,11 +20,11 @@ matrix: fast_finish: true include: - os: linux - env: [PYTHON=2.7, NUMPY=1.10, CYTHON=0.24] + env: [PYTHON=2.7, NUMPY=1.10, CYTHON=0.26] - os: linux env: [PYTHON=3.5, NUMPY=1.11] - os: linux - env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.25] + env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.27] - os: linux env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.26] - os: linux diff --git a/_randomgen/README.md b/_randomgen/README.md index 836ef131539d..e1fe7cbd4df0 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -146,7 +146,7 @@ Building requires: * Python (2.7, 3.4, 3.5, 3.6) * NumPy (1.10, 1.11, 1.12, 1.13, 1.14) - * Cython (0.25+) + * Cython (0.26+) * tempita (0.5+), if not provided by Cython Testing requires pytest (3.0+). diff --git a/_randomgen/README.rst b/_randomgen/README.rst index 7448523d8838..e37a7193cf64 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -163,7 +163,7 @@ Building requires: - Python (2.7, 3.4, 3.5, 3.6) - NumPy (1.10, 1.11, 1.12, 1.13, 1.14) -- Cython (0.25+) +- Cython (0.26+) - tempita (0.5+), if not provided by Cython Testing requires pytest (3.0+). diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst index c59718b9c7f5..9029981e3ed5 100644 --- a/_randomgen/doc/source/change-log.rst +++ b/_randomgen/doc/source/change-log.rst @@ -4,6 +4,8 @@ Change Log Changes since v1.14 =================== +- Add legacy generator which allows NumPy replication +- Improve type handling of integers - Switch to array-fillers for 0 parameter distribution to improve performance - Small changes to build on manylinux - Build wheels using multibuild diff --git a/_randomgen/doc/source/extending.rst b/_randomgen/doc/source/extending.rst index aacfab393289..764e3428b066 100644 --- a/_randomgen/doc/source/extending.rst +++ b/_randomgen/doc/source/extending.rst @@ -15,7 +15,7 @@ This example shows how numba can be used to produce Box-Muller normals using a pure Python implementation which is then compiled. The random numbers are provided by ``ctypes.next_double``. -.. ipython:: python +.. code-block:: python from randomgen import Xoroshiro128 import numpy as np diff --git a/_randomgen/doc/source/index.rst b/_randomgen/doc/source/index.rst index 2e9ce44d94e8..c0b55f5cb215 100644 --- a/_randomgen/doc/source/index.rst +++ b/_randomgen/doc/source/index.rst @@ -174,7 +174,8 @@ Random Generator .. toctree:: :maxdepth: 1 - Random Generator + Random Generation + legacy Basic Random Number Generators ------------------------------ diff --git a/_randomgen/doc/source/legacy.rst b/_randomgen/doc/source/legacy.rst new file mode 100644 index 000000000000..8a73f9029c92 --- /dev/null +++ b/_randomgen/doc/source/legacy.rst @@ -0,0 +1,95 @@ +Legacy Random Generation +------------------------ +The :class:`~randomgen.legacy.LegacyGenerator` provides access to +some legacy generators. These all depend on Box-Muller normals or +inverse CDF exponentials or gammas. This class should only be used +if it is essential to have randoms that are identical to what +would have been produced by NumPy. + +:class:`~randomgen.legacy.LegacyGenerator` add additional information +to the state which is required when using Box-Muller normals since these +are produced in pairs. It is important to use +:attr:`~randomgen.legacy.LegacyGenerator.state` +when accessing the state so that these extra values are saved. + +.. warning:: + + :class:`~randomgen.legacy.LegacyGenerator` only contains functions + that have changed. Since it does not contain other functions, it + is not direclty possible to replace :class:`~numpy.random.RandomState`. + In order to full replace :class:`~numpy.random.RandomState`, it is + necessary to use both :class:`~randomgen.legacy.LegacyGenerator` + and :class:`~randomgen.generator.RandomGenerator` both driven + by the same basic RNG. Methods present in :class:`~randomgen.legacy.LegacyGenerator` + must be called from :class:`~randomgen.legacy.LegacyGenerator`. Other Methods + should be called from :class:`~randomgen.generator.RandomGenerator`. + + +.. code-block:: python + + from randomgen import RandomGenerator, MT19937 + from randomgen.legacy import LegacyGenerator + from numpy.random import RandomState + # Use same seed + rs = RandomState(12345) + mt19937 = MT19937(12345) + rg = RandomGenerator(mt19937) + lg = LegacyGenerator(mt19937) + + # Identical output + rs.standard_normal() + lg.standard_normal() + + rs.random_sample() + rg.random_sample() + + rs.standard_exponential() + lg.standard_exponential() + + +.. currentmodule:: randomgen.legacy + +.. autoclass:: + LegacyGenerator + +Seeding and State +================= + +.. autosummary:: + :toctree: generated/ + + ~LegacyGenerator.state + +Simple random data +================== +.. autosummary:: + :toctree: generated/ + + ~LegacyGenerator.randn + +Distributions +============= +.. autosummary:: + :toctree: generated/ + + ~LegacyGenerator.beta + ~LegacyGenerator.chisquare + ~LegacyGenerator.dirichlet + ~LegacyGenerator.exponential + ~LegacyGenerator.f + ~LegacyGenerator.gamma + ~LegacyGenerator.lognormal + ~LegacyGenerator.multivariate_normal + ~LegacyGenerator.negative_binomial + ~LegacyGenerator.noncentral_chisquare + ~LegacyGenerator.noncentral_f + ~LegacyGenerator.normal + ~LegacyGenerator.pareto + ~LegacyGenerator.power + ~LegacyGenerator.standard_cauchy + ~LegacyGenerator.standard_exponential + ~LegacyGenerator.standard_gamma + ~LegacyGenerator.standard_normal + ~LegacyGenerator.standard_t + ~LegacyGenerator.wald + ~LegacyGenerator.weibull diff --git a/_randomgen/doc/source/multithreading.rst b/_randomgen/doc/source/multithreading.rst index ef8d710dff26..253764632c77 100644 --- a/_randomgen/doc/source/multithreading.rst +++ b/_randomgen/doc/source/multithreading.rst @@ -14,20 +14,20 @@ xorshift2014 which is fast, has a long period and supports using ``jump`` to advance the state. The random numbers generated are reproducible in the sense that the same seed will produce the same outputs. -.. code-block:: python +.. code-block:: ipython from randomgen import Xorshift1024 import multiprocessing import concurrent.futures import numpy as np - + class MultithreadedRNG(object): def __init__(self, n, seed=None, threads=None): rg = Xorshift1024(seed) if threads is None: threads = multiprocessing.cpu_count() self.threads = threads - + self._random_generators = [] for _ in range(0, threads-1): _rg = Xorshift1024() @@ -35,96 +35,70 @@ that the same seed will produce the same outputs. self._random_generators.append(_rg.generator) rg.jump() self._random_generators.append(rg.generator) - + self.n = n self.executor = concurrent.futures.ThreadPoolExecutor(threads) self.values = np.empty(n) self.step = np.ceil(n / threads).astype(np.int) - + def fill(self): def _fill(random_state, out, first, last): random_state.standard_normal(out=out[first:last]) - + futures = {} for i in range(self.threads): - args = (_fill, self._random_generators[i], self.values, i * self.step, (i + 1) * self.step) + args = (_fill, + self._random_generators[i], + self.values, + i * self.step, + (i + 1) * self.step) futures[self.executor.submit(*args)] = i concurrent.futures.wait(futures) - + def __del__(self): self.executor.shutdown(False) -.. ipython:: python - :suppress: - - - In [1]: from randomgen import Xorshift1024 - ....: import multiprocessing - ....: import concurrent.futures - ....: import numpy as np - ....: class MultithreadedRNG(object): - ....: def __init__(self, n, seed=None, threads=None): - ....: rg = Xorshift1024(seed) - ....: if threads is None: - ....: threads = multiprocessing.cpu_count() - ....: self.threads = threads - ....: self._random_generators = [] - ....: for _ in range(0, threads-1): - ....: _rg = Xorshift1024() - ....: _rg.state = rg.state - ....: self._random_generators.append(_rg.generator) - ....: rg.jump() - ....: self._random_generators.append(rg.generator) - ....: self.n = n - ....: self.executor = concurrent.futures.ThreadPoolExecutor(threads) - ....: self.values = np.empty(n) - ....: self.step = np.ceil(n / threads).astype(np.int) - ....: def fill(self): - ....: def _fill(random_state, out, first, last): - ....: random_state.standard_normal(out=out[first:last]) - ....: futures = {} - ....: for i in range(self.threads): - ....: args = (_fill, self._random_generators[i], self.values, i * self.step, (i + 1) * self.step) - ....: futures[self.executor.submit(*args)] = i - ....: concurrent.futures.wait(futures) - ....: def __del__(self): - ....: self.executor.shutdown(False) - ....: - The multithreaded random number generator can be used to fill an array. The ``values`` attributes shows the zero-value before the fill and the random value after. -.. ipython:: python +.. code-block:: ipython - mrng = MultithreadedRNG(10000000, seed=0) - print(mrng.values[-1]) - mrng.fill() - print(mrng.values[-1]) + In [2]: mrng = MultithreadedRNG(10000000, seed=0) + ...: print(mrng.values[-1]) + 0.0 + + In [3]: mrng.fill() + ...: print(mrng.values[-1]) + 3.296046120254392 The time required to produce using multiple threads can be compared to the time required to generate using a single thread. -.. ipython:: python - - print(mrng.threads) - %timeit mrng.fill() +.. code-block:: ipython + In [4]: print(mrng.threads) + ...: %timeit mrng.fill() + 4 + 42.9 ms ± 2.55 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) The single threaded call directly uses the PRNG. -.. ipython:: python +.. code-block:: ipython - values = np.empty(10000000) - rg = Xorshift1024().generator - %timeit rg.standard_normal(out=values) + In [5]: values = np.empty(10000000) + ...: rg = Xorshift1024().generator + ...: %timeit rg.standard_normal(out=values) + 220 ms ± 27.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) The gains are substantial and the scaling is reasonable even for large that are only moderately large. The gains are even larger when compared to a call that does not use an existing array due to array creation overhead. -.. ipython:: python +.. code-block:: ipython - rg = Xorshift1024().generator - %timeit rg.standard_normal(10000000) + In [6]: rg = Xorshift1024().generator + ...: %timeit rg.standard_normal(10000000) + ...: + 256 ms ± 41.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) diff --git a/_randomgen/doc/source/new-or-different.rst b/_randomgen/doc/source/new-or-different.rst index 7fb70ed1ab66..fdff589461e5 100644 --- a/_randomgen/doc/source/new-or-different.rst +++ b/_randomgen/doc/source/new-or-different.rst @@ -29,29 +29,24 @@ What's New or Different * The basic random number generators can be used in downstream projects via Cython. + .. ipython:: python from randomgen import Xoroshiro128 + import numpy.random rg = Xoroshiro128().generator - %timeit rg.standard_normal(1000000) - from numpy.random import standard_normal - %timeit standard_normal(1000000) + %timeit rg.standard_normal(100000) + %timeit numpy.random.standard_normal(100000) .. ipython:: python - from randomgen import Xoroshiro128 - rg = Xoroshiro128().generator - %timeit rg.standard_exponential(1000000) - from numpy.random import standard_exponential - %timeit standard_exponential(1000000) + %timeit rg.standard_exponential(100000) + %timeit numpy.random.standard_exponential(100000) .. ipython:: python - from randomgen import Xoroshiro128 - rg = Xoroshiro128().generator - %timeit rg.standard_gamma(3.0, 1000000) - from numpy.random import standard_gamma - %timeit standard_gamma(3.0, 1000000) + %timeit rg.standard_gamma(3.0, 100000) + %timeit numpy.random.standard_gamma(3.0, 100000) * Optional ``dtype`` argument that accepts ``np.float32`` or ``np.float64`` to produce either single or double prevision uniform random variables for @@ -66,8 +61,6 @@ What's New or Different .. ipython:: python - from randomgen import Xoroshiro128 - rg = Xoroshiro128().generator rg.seed(0) rg.random_sample(3, dtype='d') rg.seed(0) @@ -86,8 +79,6 @@ What's New or Different .. ipython:: python - from randomgen import Xoroshiro128 - rg = Xoroshiro128(0).generator existing = np.zeros(4) rg.random_sample(out=existing[:2]) print(existing) diff --git a/_randomgen/randomgen/common.pxd b/_randomgen/randomgen/common.pxd index e4ce62818370..5a661dfb3db1 100644 --- a/_randomgen/randomgen/common.pxd +++ b/_randomgen/randomgen/common.pxd @@ -32,20 +32,20 @@ cdef extern from "src/aligned_malloc/aligned_malloc.h": cdef void PyArray_free_aligned(void *p); ctypedef double (*random_double_fill)(brng_t *state, np.npy_intp count, double* out) nogil -ctypedef double (*random_double_0)(brng_t *state) nogil -ctypedef double (*random_double_1)(brng_t *state, double a) nogil -ctypedef double (*random_double_2)(brng_t *state, double a, double b) nogil -ctypedef double (*random_double_3)(brng_t *state, double a, double b, double c) nogil +ctypedef double (*random_double_0)(void *state) nogil +ctypedef double (*random_double_1)(void *state, double a) nogil +ctypedef double (*random_double_2)(void *state, double a, double b) nogil +ctypedef double (*random_double_3)(void *state, double a, double b, double c) nogil ctypedef float (*random_float_0)(brng_t *state) nogil ctypedef float (*random_float_1)(brng_t *state, float a) nogil -ctypedef int64_t (*random_uint_0)(brng_t *state) nogil -ctypedef int64_t (*random_uint_d)(brng_t *state, double a) nogil -ctypedef int64_t (*random_uint_dd)(brng_t *state, double a, double b) nogil -ctypedef int64_t (*random_uint_di)(brng_t *state, double a, uint64_t b) nogil -ctypedef int64_t (*random_uint_i)(brng_t *state, int64_t a) nogil -ctypedef int64_t (*random_uint_iii)(brng_t *state, int64_t a, int64_t b, int64_t c) nogil +ctypedef int64_t (*random_uint_0)(void *state) nogil +ctypedef int64_t (*random_uint_d)(void *state, double a) nogil +ctypedef int64_t (*random_uint_dd)(void *state, double a, double b) nogil +ctypedef int64_t (*random_uint_di)(void *state, double a, uint64_t b) nogil +ctypedef int64_t (*random_uint_i)(void *state, int64_t a) nogil +ctypedef int64_t (*random_uint_iii)(void *state, int64_t a, int64_t b, int64_t c) nogil ctypedef uint32_t (*random_uint_0_32)(brng_t *state) nogil ctypedef uint32_t (*random_uint_1_i_32)(brng_t *state, uint32_t a) nogil @@ -66,13 +66,13 @@ cdef object float_fill_from_double(void *func, brng_t *state, object size, objec cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size) -cdef object cont(void *func, brng_t *state, object size, object lock, int narg, +cdef object cont(void *func, void *state, object size, object lock, int narg, object a, object a_name, constraint_type a_constraint, object b, object b_name, constraint_type b_constraint, object c, object c_name, constraint_type c_constraint, object out) -cdef object disc(void *func, brng_t *state, object size, object lock, +cdef object disc(void *func, void *state, object size, object lock, int narg_double, int narg_int64, object a, object a_name, constraint_type a_constraint, object b, object b_name, constraint_type b_constraint, @@ -82,12 +82,12 @@ cdef object cont_f(void *func, brng_t *state, object size, object lock, object a, object a_name, constraint_type a_constraint, object out) -cdef object cont_broadcast_3(void *func, brng_t *state, object size, object lock, +cdef object cont_broadcast_3(void *func, void *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint, np.ndarray c_arr, object c_name, constraint_type c_constraint) -cdef object discrete_broadcast_iii(void *func, brng_t *state, object size, object lock, +cdef object discrete_broadcast_iii(void *func, void *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint, np.ndarray c_arr, object c_name, constraint_type c_constraint) diff --git a/_randomgen/randomgen/common.pyx b/_randomgen/randomgen/common.pyx index e28342e68442..3f2ba352a9ee 100644 --- a/_randomgen/randomgen/common.pyx +++ b/_randomgen/randomgen/common.pyx @@ -200,7 +200,7 @@ cdef int check_constraint(double val, object name, constraint_type cons) except return 0 -cdef object cont_broadcast_1(void *func, brng_t *state, object size, object lock, +cdef object cont_broadcast_1(void *func, void *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, object out): @@ -234,7 +234,7 @@ cdef object cont_broadcast_1(void *func, brng_t *state, object size, object lock return randoms -cdef object cont_broadcast_2(void *func, brng_t *state, object size, object lock, +cdef object cont_broadcast_2(void *func, void *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint): cdef np.ndarray randoms @@ -272,7 +272,7 @@ cdef object cont_broadcast_2(void *func, brng_t *state, object size, object lock return randoms -cdef object cont_broadcast_3(void *func, brng_t *state, object size, object lock, +cdef object cont_broadcast_3(void *func, void *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint, np.ndarray c_arr, object c_name, constraint_type c_constraint): @@ -314,7 +314,7 @@ cdef object cont_broadcast_3(void *func, brng_t *state, object size, object lock return randoms -cdef object cont(void *func, brng_t *state, object size, object lock, int narg, +cdef object cont(void *func, void *state, object size, object lock, int narg, object a, object a_name, constraint_type a_constraint, object b, object b_name, constraint_type b_constraint, object c, object c_name, constraint_type c_constraint, @@ -410,7 +410,7 @@ cdef object cont(void *func, brng_t *state, object size, object lock, int narg, else: return out -cdef object discrete_broadcast_d(void *func, brng_t *state, object size, object lock, +cdef object discrete_broadcast_d(void *func, void *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint): cdef np.ndarray randoms @@ -441,7 +441,7 @@ cdef object discrete_broadcast_d(void *func, brng_t *state, object size, object return randoms -cdef object discrete_broadcast_dd(void *func, brng_t *state, object size, object lock, +cdef object discrete_broadcast_dd(void *func, void *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint): cdef np.ndarray randoms @@ -476,7 +476,7 @@ cdef object discrete_broadcast_dd(void *func, brng_t *state, object size, object return randoms -cdef object discrete_broadcast_di(void *func, brng_t *state, object size, object lock, +cdef object discrete_broadcast_di(void *func, void *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint): cdef np.ndarray randoms @@ -512,7 +512,7 @@ cdef object discrete_broadcast_di(void *func, brng_t *state, object size, object return randoms -cdef object discrete_broadcast_iii(void *func, brng_t *state, object size, object lock, +cdef object discrete_broadcast_iii(void *func, void *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint, np.ndarray c_arr, object c_name, constraint_type c_constraint): @@ -552,7 +552,7 @@ cdef object discrete_broadcast_iii(void *func, brng_t *state, object size, objec return randoms -cdef object discrete_broadcast_i(void *func, brng_t *state, object size, object lock, +cdef object discrete_broadcast_i(void *func, void *state, object size, object lock, np.ndarray a_arr, object a_name, constraint_type a_constraint): cdef np.ndarray randoms cdef int64_t *randoms_data @@ -582,7 +582,7 @@ cdef object discrete_broadcast_i(void *func, brng_t *state, object size, object return randoms # Needs double , double-double , double-int64_t, int64_t , int64_t-int64_t-int64_t -cdef object disc(void *func, brng_t *state, object size, object lock, +cdef object disc(void *func, void *state, object size, object lock, int narg_double, int narg_int64, object a, object a_name, constraint_type a_constraint, object b, object b_name, constraint_type b_constraint, diff --git a/_randomgen/randomgen/legacy/__init__.py b/_randomgen/randomgen/legacy/__init__.py new file mode 100644 index 000000000000..b59b221b49bc --- /dev/null +++ b/_randomgen/randomgen/legacy/__init__.py @@ -0,0 +1,3 @@ +from randomgen.legacy.legacy import LegacyGenerator + +__all__ = ['LegacyGenerator'] diff --git a/_randomgen/randomgen/legacy/legacy.pyx b/_randomgen/randomgen/legacy/legacy.pyx new file mode 100644 index 000000000000..0a5a67bcf867 --- /dev/null +++ b/_randomgen/randomgen/legacy/legacy.pyx @@ -0,0 +1,1953 @@ +#!python +#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True +import warnings +import operator + +from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer +from libc.stdlib cimport malloc, free +cimport numpy as np +import numpy as np +cimport cython + +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock + +from randomgen.common cimport cont, disc, CONS_NONE, CONS_POSITIVE, CONS_NON_NEGATIVE, CONS_BOUNDED_0_1 +from randomgen.distributions cimport brng_t +from randomgen.legacy.legacy_distributions cimport * +from randomgen.xoroshiro128 import Xoroshiro128 +import randomgen.pickle + +np.import_array() + +cdef class LegacyGenerator: + """ + LegacyGenerator(brng=None) + + Container providing legacy generators. + + ``LegacyGenerator`` exposes a number of methods for generating random + numbers for a set of distributions where the method used to produce random + samples has changed. Three core generators have changed: normals, exponentials + and gammas. These have been replaced by fster Ziggurat-based methds in + ``RadnomGenerator``. ``LegacyGenerator`` retains the slower methods + to produce samples from these distributions as well as from distributions + that depend on these such as the Chi-square, power or Weibull. + + **No Compatibility Guarantee** + + ``LegacyGenerator`` is evolving and so it isn't possible to provide a + compatibility guarantee like NumPy does. In particular, better algorithms + have already been added. This will change once ``RandomGenerator`` + stabilizes. + + Parameters + ---------- + brng : Basic RNG, optional + Basic RNG to use as the core generator. If none is provided, uses + Xoroshiro128. + + + Examples + -------- + Exactly reproducing a NumPy stream requires both a ``RandomGenerator`` + and a ``LegacyGenerator``. These must share a common ``MT19937`` basic + RNG. Functions that are available in LegacyGenerator must be called + from ``LegacyGenerator``, and other functions must be called from + ``RandomGenerator``. + + >>> from randomgen import RandomGenerator, MT19937 + >>> from randomgen.legacy import LegacyGenerator + >>> mt = MT19937(12345) + >>> lg = LegacyGenerator(mt) + >>> rg = RandomGenerator(mt) + >>> x = lg.standard_normal(10) + >>> rg.shuffle(x) + >>> x[0] + 0.09290787674371767 + >>> lg.standard_exponential() + 1.6465621229906502 + + The equivalent commands from NumPy produce identical output. + + >>> from numpy.random import RandomState + >>> rs = RandomState(12345) + >>> x = rs.standard_normal(10) + >>> rs.shuffle(x) + >>> x[0] + 0.09290787674371767 + >>> rs.standard_exponential() + 1.6465621229906502 + """ + cdef public object _basicrng + cdef brng_t *_brng + cdef aug_brng_t *_aug_state + cdef object lock + + def __init__(self, brng=None): + if brng is None: + brng = Xoroshiro128() + self._basicrng = brng + + capsule = brng.capsule + cdef const char *name = "BasicRNG" + if not PyCapsule_IsValid(capsule, name): + raise ValueError("Invalid brng. The brng must be instantized.") + self._brng = PyCapsule_GetPointer(capsule, name) + self._aug_state = malloc(sizeof(aug_brng_t)) + self._aug_state.basicrng = self._brng + self._reset_gauss() + self.lock = Lock() + + def __dealloc__(self): + free(self._aug_state) + + def __repr__(self): + return self.__str__() + ' at 0x{:X}'.format(id(self)) + + def __str__(self): + return 'RandomGenerator(' + self._basicrng.__class__.__name__ + ')' + + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (randomgen.pickle.__generator_ctor, + (self.state['brng'],), + self.state) + + cdef _reset_gauss(self): + self._aug_state.has_gauss = 0 + self._aug_state.gauss = 0.0 + + def seed(self, *args, **kwargs): + """ + Reseed the basic RNG. + + Parameters depend on the basic RNG used. + """ + # TODO: Should this remain + self._basicrng.seed(*args, **kwargs) + self._reset_gauss() + return self + + @property + def state(self): + """ + Get or set the augmented state + + Returns the basic RNGs state as well as two values added to track + normal generation using the Box-Muller method. + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the Basic RNG with two additional fields, gauss and + has_gauss, required to store generated Box-Muller normals. + """ + st = self._basicrng.state + st['has_gauss'] = self._aug_state.has_gauss + st['gauss'] = self._aug_state.gauss + return st + + @state.setter + def state(self, value): + if isinstance(value, tuple): + if value[0] != 'MT19937': + raise ValueError('tuple only supported for MT19937') + st = {'brng': value[0], + 'state': {'key': value[1], 'pos': value[2]}} + if len(value) > 3: + st['has_gauss'] = value[3] + st['gauss'] = value[4] + value = st + + self._aug_state.gauss = value.get('gauss', 0.0) + self._aug_state.has_gauss = value.get('has_gauss', 0) + self._basicrng.state = value + + # Complicated, continuous distributions: + def standard_normal(self, size=None): + """ + standard_normal(size=None) + + Draw samples from a standard Normal distribution (mean=0, stdev=1). + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : float or ndarray + Drawn samples. + + Examples + -------- + >>> s = randomgen.standard_normal(8000) + >>> s + array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random + -0.38672696, -0.4685006 ]) #random + >>> s.shape + (8000,) + >>> s = randomgen.standard_normal(size=(3, 4, 2)) + >>> s.shape + (3, 4, 2) + + """ + return cont(&legacy_gauss, self._aug_state, size, self.lock, 0, + None, None, CONS_NONE, + None, None, CONS_NONE, + None, None, CONS_NONE, + None) + + def standard_t(self, df, size=None): + """ + standard_t(df, size=None) + + Draw samples from a standard Student's t distribution with `df` degrees + of freedom. + + A special case of the hyperbolic distribution. As `df` gets + large, the result resembles that of the standard normal + distribution (`standard_normal`). + + Parameters + ---------- + df : int or array_like of ints + Degrees of freedom, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` is a scalar. Otherwise, + ``np.array(df).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized standard Student's t distribution. + + Notes + ----- + The probability density function for the t distribution is + + .. math:: P(x, df) = \\frac{\\Gamma(\\frac{df+1}{2})}{\\sqrt{\\pi df} + \\Gamma(\\frac{df}{2})}\\Bigl( 1+\\frac{x^2}{df} \\Bigr)^{-(df+1)/2} + + The t test is based on an assumption that the data come from a + Normal distribution. The t test provides a way to test whether + the sample mean (that is the mean calculated from the data) is + a good estimate of the true mean. + + The derivation of the t-distribution was first published in + 1908 by William Gosset while working for the Guinness Brewery + in Dublin. Due to proprietary issues, he had to publish under + a pseudonym, and so he used the name Student. + + References + ---------- + .. [1] Dalgaard, Peter, "Introductory Statistics With R", + Springer, 2002. + .. [2] Wikipedia, "Student's t-distribution" + http://en.wikipedia.org/wiki/Student's_t-distribution + + Examples + -------- + From Dalgaard page 83 [1]_, suppose the daily energy intake for 11 + women in Kj is: + + >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\ + ... 7515, 8230, 8770]) + + Does their energy intake deviate systematically from the recommended + value of 7725 kJ? + + We have 10 degrees of freedom, so is the sample mean within 95% of the + recommended value? + + >>> s = randomgen.standard_t(10, size=100000) + >>> np.mean(intake) + 6753.636363636364 + >>> intake.std(ddof=1) + 1142.1232221373727 + + Calculate the t statistic, setting the ddof parameter to the unbiased + value so the divisor in the standard deviation will be degrees of + freedom, N-1. + + >>> t = (np.mean(intake)-7725)/(intake.std(ddof=1)/np.sqrt(len(intake))) + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(s, bins=100, normed=True) + + For a one-sided t-test, how far out in the distribution does the t + statistic appear? + + >>> np.sum(s>> mu, sigma = 3., 1. # mean and standard deviation + >>> s = randomgen.lognormal(mu, sigma, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 100, normed=True, align='mid') + + >>> x = np.linspace(min(bins), max(bins), 10000) + >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) + ... / (x * sigma * np.sqrt(2 * np.pi))) + + >>> plt.plot(x, pdf, linewidth=2, color='r') + >>> plt.axis('tight') + >>> plt.show() + + Demonstrate that taking the products of random samples from a uniform + distribution can be fit well by a log-normal probability density + function. + + >>> # Generate a thousand samples: each is the product of 100 random + >>> # values, drawn from a normal distribution. + >>> b = [] + >>> for i in range(1000): + ... a = 10. + randomgen.random(100) + ... b.append(np.product(a)) + + >>> b = np.array(b) / np.min(b) # scale values to be positive + >>> count, bins, ignored = plt.hist(b, 100, normed=True, align='mid') + >>> sigma = np.std(np.log(b)) + >>> mu = np.mean(np.log(b)) + + >>> x = np.linspace(min(bins), max(bins), 10000) + >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) + ... / (x * sigma * np.sqrt(2 * np.pi))) + + >>> plt.plot(x, pdf, color='r', linewidth=2) + >>> plt.show() + + """ + return cont(&legacy_lognormal, self._aug_state, size, self.lock, 2, + mean, 'mean', CONS_NONE, + sigma, 'sigma', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def wald(self, mean, scale, size=None): + """ + wald(mean, scale, size=None) + + Draw samples from a Wald, or inverse Gaussian, distribution. + + As the scale approaches infinity, the distribution becomes more like a + Gaussian. Some references claim that the Wald is an inverse Gaussian + with mean equal to 1, but this is by no means universal. + + The inverse Gaussian distribution was first studied in relationship to + Brownian motion. In 1956 M.C.K. Tweedie used the name inverse Gaussian + because there is an inverse relationship between the time to cover a + unit distance and distance covered in unit time. + + Parameters + ---------- + mean : float or array_like of floats + Distribution mean, should be > 0. + scale : float or array_like of floats + Scale parameter, should be >= 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mean`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(mean, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Wald distribution. + + Notes + ----- + The probability density function for the Wald distribution is + + .. math:: P(x;mean,scale) = \\sqrt{\\frac{scale}{2\\pi x^3}}e^ + \\frac{-scale(x-mean)^2}{2\\cdotp mean^2x} + + As noted above the inverse Gaussian distribution first arise + from attempts to model Brownian motion. It is also a + competitor to the Weibull for use in reliability modeling and + modeling stock returns and interest rate processes. + + References + ---------- + .. [1] Brighton Webs Ltd., Wald Distribution, + http://www.brighton-webs.co.uk/distributions/wald.asp + .. [2] Chhikara, Raj S., and Folks, J. Leroy, "The Inverse Gaussian + Distribution: Theory : Methodology, and Applications", CRC Press, + 1988. + .. [3] Wikipedia, "Wald distribution" + http://en.wikipedia.org/wiki/Wald_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram: + + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(randomgen.wald(3, 2, 100000), bins=200, normed=True) + >>> plt.show() + + """ + return cont(&legacy_wald, self._aug_state, size, self.lock, 2, + mean, 'mean', CONS_POSITIVE, + scale, 'scale', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + def pareto(self, a, size=None): + """ + pareto(a, size=None) + + Draw samples from a Pareto II or Lomax distribution with + specified shape. + + The Lomax or Pareto II distribution is a shifted Pareto + distribution. The classical Pareto distribution can be + obtained from the Lomax distribution by adding 1 and + multiplying by the scale parameter ``m`` (see Notes). The + smallest value of the Lomax distribution is zero while for the + classical Pareto distribution it is ``mu``, where the standard + Pareto distribution has location ``mu = 1``. Lomax can also + be considered as a simplified version of the Generalized + Pareto distribution (available in SciPy), with the scale set + to one and the location set to zero. + + The Pareto distribution must be greater than zero, and is + unbounded above. It is also known as the "80-20 rule". In + this distribution, 80 percent of the weights are in the lowest + 20 percent of the range, while the other 20 percent fill the + remaining 80 percent of the range. + + Parameters + ---------- + a : float or array_like of floats + Shape of the distribution. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Pareto distribution. + + See Also + -------- + scipy.stats.lomax : probability density function, distribution or + cumulative density function, etc. + scipy.stats.genpareto : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Pareto distribution is + + .. math:: p(x) = \\frac{am^a}{x^{a+1}} + + where :math:`a` is the shape and :math:`m` the scale. + + The Pareto distribution, named after the Italian economist + Vilfredo Pareto, is a power law probability distribution + useful in many real world problems. Outside the field of + economics it is generally referred to as the Bradford + distribution. Pareto developed the distribution to describe + the distribution of wealth in an economy. It has also found + use in insurance, web page access statistics, oil field sizes, + and many other problems, including the download frequency for + projects in Sourceforge [1]_. It is one of the so-called + "fat-tailed" distributions. + + + References + ---------- + .. [1] Francis Hunt and Paul Johnson, On the Pareto Distribution of + Sourceforge projects. + .. [2] Pareto, V. (1896). Course of Political Economy. Lausanne. + .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme + Values, Birkhauser Verlag, Basel, pp 23-30. + .. [4] Wikipedia, "Pareto distribution", + http://en.wikipedia.org/wiki/Pareto_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a, m = 3., 2. # shape and mode + >>> s = (randomgen.pareto(a, 1000) + 1) * m + + Display the histogram of the samples, along with the probability + density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, _ = plt.hist(s, 100, normed=True) + >>> fit = a*m**a / bins**(a+1) + >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r') + >>> plt.show() + + """ + return cont(&legacy_pareto, self._aug_state, size, self.lock, 1, + a, 'a', CONS_POSITIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def weibull(self, a, size=None): + """ + weibull(a, size=None) + + Draw samples from a Weibull distribution. + + Draw samples from a 1-parameter Weibull distribution with the given + shape parameter `a`. + + .. math:: X = (-ln(U))^{1/a} + + Here, U is drawn from the uniform distribution over (0,1]. + + The more common 2-parameter Weibull, including a scale parameter + :math:`\\lambda` is just :math:`X = \\lambda(-ln(U))^{1/a}`. + + Parameters + ---------- + a : float or array_like of floats + Shape of the distribution. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Weibull distribution. + + See Also + -------- + scipy.stats.weibull_max + scipy.stats.weibull_min + scipy.stats.genextreme + gumbel + + Notes + ----- + The Weibull (or Type III asymptotic extreme value distribution + for smallest values, SEV Type III, or Rosin-Rammler + distribution) is one of a class of Generalized Extreme Value + (GEV) distributions used in modeling extreme value problems. + This class includes the Gumbel and Frechet distributions. + + The probability density for the Weibull distribution is + + .. math:: p(x) = \\frac{a} + {\\lambda}(\\frac{x}{\\lambda})^{a-1}e^{-(x/\\lambda)^a}, + + where :math:`a` is the shape and :math:`\\lambda` the scale. + + The function has its peak (the mode) at + :math:`\\lambda(\\frac{a-1}{a})^{1/a}`. + + When ``a = 1``, the Weibull distribution reduces to the exponential + distribution. + + References + ---------- + .. [1] Waloddi Weibull, Royal Technical University, Stockholm, + 1939 "A Statistical Theory Of The Strength Of Materials", + Ingeniorsvetenskapsakademiens Handlingar Nr 151, 1939, + Generalstabens Litografiska Anstalts Forlag, Stockholm. + .. [2] Waloddi Weibull, "A Statistical Distribution Function of + Wide Applicability", Journal Of Applied Mechanics ASME Paper + 1951. + .. [3] Wikipedia, "Weibull distribution", + http://en.wikipedia.org/wiki/Weibull_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a = 5. # shape + >>> s = randomgen.weibull(a, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> x = np.arange(1,100.)/50. + >>> def weib(x,n,a): + ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) + + >>> count, bins, ignored = plt.hist(randomgen.weibull(5.,1000)) + >>> x = np.arange(1,100.)/50. + >>> scale = count.max()/weib(x, 1., 5.).max() + >>> plt.plot(x, weib(x, 1., 5.)*scale) + >>> plt.show() + + """ + return cont(&legacy_weibull, self._aug_state, size, self.lock, 1, + a, 'a', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def noncentral_f(self, dfnum, dfden, nonc, size=None): + """ + noncentral_f(dfnum, dfden, nonc, size=None) + + Draw samples from the noncentral F distribution. + + Samples are drawn from an F distribution with specified parameters, + `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of + freedom in denominator), where both parameters > 1. + `nonc` is the non-centrality parameter. + + Parameters + ---------- + dfnum : int or array_like of ints + Parameter, should be > 1. + dfden : int or array_like of ints + Parameter, should be > 1. + nonc : float or array_like of floats + Parameter, should be >= 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``dfnum``, ``dfden``, and ``nonc`` + are all scalars. Otherwise, ``np.broadcast(dfnum, dfden, nonc).size`` + samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized noncentral Fisher distribution. + + Notes + ----- + When calculating the power of an experiment (power = probability of + rejecting the null hypothesis when a specific alternative is true) the + non-central F statistic becomes important. When the null hypothesis is + true, the F statistic follows a central F distribution. When the null + hypothesis is not true, then it follows a non-central F statistic. + + References + ---------- + .. [1] Weisstein, Eric W. "Noncentral F-Distribution." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/NoncentralF-Distribution.html + .. [2] Wikipedia, "Noncentral F-distribution", + http://en.wikipedia.org/wiki/Noncentral_F-distribution + + Examples + -------- + In a study, testing for a specific alternative to the null hypothesis + requires use of the Noncentral F distribution. We need to calculate the + area in the tail of the distribution that exceeds the value of the F + distribution for the null hypothesis. We'll plot the two probability + distributions for comparison. + + >>> dfnum = 3 # between group deg of freedom + >>> dfden = 20 # within groups degrees of freedom + >>> nonc = 3.0 + >>> nc_vals = randomgen.noncentral_f(dfnum, dfden, nonc, 1000000) + >>> NF = np.histogram(nc_vals, bins=50, normed=True) + >>> c_vals = randomgen.f(dfnum, dfden, 1000000) + >>> F = np.histogram(c_vals, bins=50, normed=True) + >>> plt.plot(F[1][1:], F[0]) + >>> plt.plot(NF[1][1:], NF[0]) + >>> plt.show() + + """ + return cont(&legacy_noncentral_f, self._aug_state, size, self.lock, 3, + dfnum, 'dfnum', CONS_POSITIVE, + dfden, 'dfden', CONS_POSITIVE, + nonc, 'nonc', CONS_NON_NEGATIVE, None) + + def chisquare(self, df, size=None): + """ + chisquare(df, size=None) + + Draw samples from a chi-square distribution. + + When `df` independent random variables, each with standard normal + distributions (mean 0, variance 1), are squared and summed, the + resulting distribution is chi-square (see Notes). This distribution + is often used in hypothesis testing. + + Parameters + ---------- + df : int or array_like of ints + Number of degrees of freedom. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` is a scalar. Otherwise, + ``np.array(df).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized chi-square distribution. + + Raises + ------ + ValueError + When `df` <= 0 or when an inappropriate `size` (e.g. ``size=-1``) + is given. + + Notes + ----- + The variable obtained by summing the squares of `df` independent, + standard normally distributed random variables: + + .. math:: Q = \\sum_{i=0}^{\\mathtt{df}} X^2_i + + is chi-square distributed, denoted + + .. math:: Q \\sim \\chi^2_k. + + The probability density function of the chi-squared distribution is + + .. math:: p(x) = \\frac{(1/2)^{k/2}}{\\Gamma(k/2)} + x^{k/2 - 1} e^{-x/2}, + + where :math:`\\Gamma` is the gamma function, + + .. math:: \\Gamma(x) = \\int_0^{-\\infty} t^{x - 1} e^{-t} dt. + + References + ---------- + .. [1] NIST "Engineering Statistics Handbook" + http://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm + + Examples + -------- + >>> randomgen.chisquare(2,4) + array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) + + """ + return cont(&legacy_chisquare, self._aug_state, size, self.lock, 1, + df, 'df', CONS_POSITIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def noncentral_chisquare(self, df, nonc, size=None): + """ + noncentral_chisquare(df, nonc, size=None) + + Draw samples from a noncentral chi-square distribution. + + The noncentral :math:`\\chi^2` distribution is a generalisation of + the :math:`\\chi^2` distribution. + + Parameters + ---------- + df : int or array_like of ints + Degrees of freedom, should be > 0 as of NumPy 1.10.0, + should be > 1 for earlier versions. + nonc : float or array_like of floats + Non-centrality, should be non-negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` and ``nonc`` are both scalars. + Otherwise, ``np.broadcast(df, nonc).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized noncentral chi-square distribution. + + Notes + ----- + The probability density function for the noncentral Chi-square + distribution is + + .. math:: P(x;df,nonc) = \\sum^{\\infty}_{i=0} + \\frac{e^{-nonc/2}(nonc/2)^{i}}{i!} + \\P_{Y_{df+2i}}(x), + + where :math:`Y_{q}` is the Chi-square with q degrees of freedom. + + In Delhi (2007), it is noted that the noncentral chi-square is + useful in bombing and coverage problems, the probability of + killing the point target given by the noncentral chi-squared + distribution. + + References + ---------- + .. [1] Delhi, M.S. Holla, "On a noncentral chi-square distribution in + the analysis of weapon systems effectiveness", Metrika, + Volume 15, Number 1 / December, 1970. + .. [2] Wikipedia, "Noncentral chi-square distribution" + http://en.wikipedia.org/wiki/Noncentral_chi-square_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram + + >>> import matplotlib.pyplot as plt + >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), + ... bins=200, normed=True) + >>> plt.show() + + Draw values from a noncentral chisquare with very small noncentrality, + and compare to a chisquare. + + >>> plt.figure() + >>> values = plt.hist(randomgen.noncentral_chisquare(3, .0000001, 100000), + ... bins=np.arange(0., 25, .1), normed=True) + >>> values2 = plt.hist(randomgen.chisquare(3, 100000), + ... bins=np.arange(0., 25, .1), normed=True) + >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') + >>> plt.show() + + Demonstrate how large values of non-centrality lead to a more symmetric + distribution. + + >>> plt.figure() + >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), + ... bins=200, normed=True) + >>> plt.show() + + """ + return cont(&legacy_noncentral_chisquare, self._aug_state, size, self.lock, 2, + df, 'df', CONS_POSITIVE, + nonc, 'nonc', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def standard_cauchy(self, size=None): + """ + standard_cauchy(size=None) + + Draw samples from a standard Cauchy distribution with mode = 0. + + Also known as the Lorentz distribution. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + samples : ndarray or scalar + The drawn samples. + + Notes + ----- + The probability density function for the full Cauchy distribution is + + .. math:: P(x; x_0, \\gamma) = \\frac{1}{\\pi \\gamma \\bigl[ 1+ + (\\frac{x-x_0}{\\gamma})^2 \\bigr] } + + and the Standard Cauchy distribution just sets :math:`x_0=0` and + :math:`\\gamma=1` + + The Cauchy distribution arises in the solution to the driven harmonic + oscillator problem, and also describes spectral line broadening. It + also describes the distribution of values at which a line tilted at + a random angle will cut the x axis. + + When studying hypothesis tests that assume normality, seeing how the + tests perform on data from a Cauchy distribution is a good indicator of + their sensitivity to a heavy-tailed distribution, since the Cauchy looks + very much like a Gaussian distribution, but with heavier tails. + + References + ---------- + .. [1] NIST/SEMATECH e-Handbook of Statistical Methods, "Cauchy + Distribution", + http://www.itl.nist.gov/div898/handbook/eda/section3/eda3663.htm + .. [2] Weisstein, Eric W. "Cauchy Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/CauchyDistribution.html + .. [3] Wikipedia, "Cauchy distribution" + http://en.wikipedia.org/wiki/Cauchy_distribution + + Examples + -------- + Draw samples and plot the distribution: + + >>> s = randomgen.standard_cauchy(1000000) + >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well + >>> plt.hist(s, bins=100) + >>> plt.show() + + """ + return cont(&legacy_standard_cauchy, self._aug_state, size, self.lock, 0, + 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) + + + def standard_gamma(self, shape, size=None): + """ + standard_gamma(shape, size=None) + + Draw samples from a standard Gamma distribution. + + Samples are drawn from a Gamma distribution with specified parameters, + shape (sometimes designated "k") and scale=1. + + Parameters + ---------- + shape : float or array_like of floats + Parameter, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``shape`` is a scalar. Otherwise, + ``np.array(shape).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized standard gamma distribution. + + See Also + -------- + scipy.stats.gamma : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gamma distribution is + + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. + + References + ---------- + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + http://en.wikipedia.org/wiki/Gamma_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> shape, scale = 2., 1. # mean and width + >>> s = randomgen.standard_gamma(shape, 1000000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ + ... (sps.gamma(shape) * scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') + >>> plt.show() + """ + return cont(&legacy_standard_gamma, self._aug_state, size, self.lock, 1, + shape, 'shape', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) + + def gamma(self, shape, scale=1.0, size=None): + """ + gamma(shape, scale=1.0, size=None) + + Draw samples from a Gamma distribution. + + Samples are drawn from a Gamma distribution with specified parameters, + `shape` (sometimes designated "k") and `scale` (sometimes designated + "theta"), where both parameters are > 0. + + Parameters + ---------- + shape : float or array_like of floats + The shape of the gamma distribution. Should be greater than zero. + scale : float or array_like of floats, optional + The scale of the gamma distribution. Should be greater than zero. + Default is equal to 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``shape`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(shape, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized gamma distribution. + + See Also + -------- + scipy.stats.gamma : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gamma distribution is + + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. + + References + ---------- + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + http://en.wikipedia.org/wiki/Gamma_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> shape, scale = 2., 2. # mean and dispersion + >>> s = randomgen.gamma(shape, scale, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> y = bins**(shape-1)*(np.exp(-bins/scale) / + ... (sps.gamma(shape)*scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') + >>> plt.show() + + """ + return cont(&legacy_gamma, self._aug_state, size, self.lock, 2, + shape, 'shape', CONS_NON_NEGATIVE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def beta(self, a, b, size=None): + """ + beta(a, b, size=None) + + Draw samples from a Beta distribution. + + The Beta distribution is a special case of the Dirichlet distribution, + and is related to the Gamma distribution. It has the probability + distribution function + + .. math:: f(x; a,b) = \\frac{1}{B(\\alpha, \\beta)} x^{\\alpha - 1} + (1 - x)^{\\beta - 1}, + + where the normalisation, B, is the beta function, + + .. math:: B(\\alpha, \\beta) = \\int_0^1 t^{\\alpha - 1} + (1 - t)^{\\beta - 1} dt. + + It is often seen in Bayesian inference and order statistics. + + Parameters + ---------- + a : float or array_like of floats + Alpha, non-negative. + b : float or array_like of floats + Beta, non-negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` and ``b`` are both scalars. + Otherwise, ``np.broadcast(a, b).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized beta distribution. + + """ + return cont(&legacy_beta, self._aug_state, size, self.lock, 2, + a, 'a', CONS_POSITIVE, + b, 'b', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + def f(self, dfnum, dfden, size=None): + """ + f(dfnum, dfden, size=None) + + Draw samples from an F distribution. + + Samples are drawn from an F distribution with specified parameters, + `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of + freedom in denominator), where both parameters should be greater than + zero. + + The random variate of the F distribution (also known as the + Fisher distribution) is a continuous probability distribution + that arises in ANOVA tests, and is the ratio of two chi-square + variates. + + Parameters + ---------- + dfnum : int or array_like of ints + Degrees of freedom in numerator. Should be greater than zero. + dfden : int or array_like of ints + Degrees of freedom in denominator. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``dfnum`` and ``dfden`` are both scalars. + Otherwise, ``np.broadcast(dfnum, dfden).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Fisher distribution. + + See Also + -------- + scipy.stats.f : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The F statistic is used to compare in-group variances to between-group + variances. Calculating the distribution depends on the sampling, and + so it is a function of the respective degrees of freedom in the + problem. The variable `dfnum` is the number of samples minus one, the + between-groups degrees of freedom, while `dfden` is the within-groups + degrees of freedom, the sum of the number of samples in each group + minus the number of groups. + + References + ---------- + .. [1] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, + Fifth Edition, 2002. + .. [2] Wikipedia, "F-distribution", + http://en.wikipedia.org/wiki/F-distribution + + Examples + -------- + An example from Glantz[1], pp 47-40: + + Two groups, children of diabetics (25 people) and children from people + without diabetes (25 controls). Fasting blood glucose was measured, + case group had a mean value of 86.1, controls had a mean value of + 82.2. Standard deviations were 2.09 and 2.49 respectively. Are these + data consistent with the null hypothesis that the parents diabetic + status does not affect their children's blood glucose levels? + Calculating the F statistic from the data gives a value of 36.01. + + Draw samples from the distribution: + + >>> dfnum = 1. # between group degrees of freedom + >>> dfden = 48. # within groups degrees of freedom + >>> s = randomgen.f(dfnum, dfden, 1000) + + The lower bound for the top 1% of the samples is : + + >>> sort(s)[-10] + 7.61988120985 + + So there is about a 1% chance that the F statistic will exceed 7.62, + the measured value is 36, so the null hypothesis is rejected at the 1% + level. + + """ + return cont(&legacy_f, self._aug_state, size, self.lock, 2, + dfnum, 'dfnum', CONS_POSITIVE, + dfden, 'dfden', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + + def normal(self, loc=0.0, scale=1.0, size=None): + """ + normal(loc=0.0, scale=1.0, size=None) + + Draw random samples from a normal (Gaussian) distribution. + + The probability density function of the normal distribution, first + derived by De Moivre and 200 years later by both Gauss and Laplace + independently [2]_, is often called the bell curve because of + its characteristic shape (see the example below). + + The normal distributions occurs often in nature. For example, it + describes the commonly occurring distribution of samples influenced + by a large number of tiny, random disturbances, each with its own + unique distribution [2]_. + + Parameters + ---------- + loc : float or array_like of floats + Mean ("centre") of the distribution. + scale : float or array_like of floats + Standard deviation (spread or "width") of the distribution. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized normal distribution. + + See Also + -------- + scipy.stats.norm : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gaussian distribution is + + .. math:: p(x) = \\frac{1}{\\sqrt{ 2 \\pi \\sigma^2 }} + e^{ - \\frac{ (x - \\mu)^2 } {2 \\sigma^2} }, + + where :math:`\\mu` is the mean and :math:`\\sigma` the standard + deviation. The square of the standard deviation, :math:`\\sigma^2`, + is called the variance. + + The function has its peak at the mean, and its "spread" increases with + the standard deviation (the function reaches 0.607 times its maximum at + :math:`x + \\sigma` and :math:`x - \\sigma` [2]_). This implies that + `numpy.random.normal` is more likely to return samples lying close to + the mean, rather than those far away. + + References + ---------- + .. [1] Wikipedia, "Normal distribution", + http://en.wikipedia.org/wiki/Normal_distribution + .. [2] P. R. Peebles Jr., "Central Limit Theorem" in "Probability, + Random Variables and Random Signal Principles", 4th ed., 2001, + pp. 51, 51, 125. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, sigma = 0, 0.1 # mean and standard deviation + >>> s = randomgen.normal(mu, sigma, 1000) + + Verify the mean and the variance: + + >>> abs(mu - np.mean(s)) < 0.01 + True + + >>> abs(sigma - np.std(s, ddof=1)) < 0.01 + True + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * + ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ), + ... linewidth=2, color='r') + >>> plt.show() + + """ + return cont(&legacy_normal, self._aug_state, size, self.lock, 2, + loc, '', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + None) + + def randn(self, *args): + """ + randn(d0, d1, ..., dn) + + Return a sample (or samples) from the "standard normal" distribution. + + If positive, int_like or int-convertible arguments are provided, + `randn` generates an array of shape ``(d0, d1, ..., dn)``, filled + with random floats sampled from a univariate "normal" (Gaussian) + distribution of mean 0 and variance 1 (if any of the :math:`d_i` are + floats, they are first converted to integers by truncation). A single + float randomly sampled from the distribution is returned if no + argument is provided. + + This is a convenience function. If you want an interface that takes a + tuple as the first argument, use `numpy.random.standard_normal` instead. + + Parameters + ---------- + d0, d1, ..., dn : int, optional + The dimensions of the returned array, should be all positive. + If no argument is given a single Python float is returned. + + Returns + ------- + Z : ndarray or float + A ``(d0, d1, ..., dn)``-shaped array of floating-point samples from + the standard normal distribution, or a single such float if + no parameters were supplied. + + See Also + -------- + random.standard_normal : Similar, but takes a tuple as its argument. + + Notes + ----- + For random samples from :math:`N(\\mu, \\sigma^2)`, use: + + ``sigma * randomgen.randn(...) + mu`` + + Examples + -------- + >>> randomgen.randn() + 2.1923875335537315 #random + + Two-by-four array of samples from N(3, 6.25): + + >>> 2.5 * randomgen.randn(2, 4) + 3 + array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random + [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random + + """ + if len(args) == 0: + return self.standard_normal() + else: + return self.standard_normal(size=args) + + def negative_binomial(self, n, p, size=None): + """ + negative_binomial(n, p, size=None) + + Draw samples from a negative binomial distribution. + + Samples are drawn from a negative binomial distribution with specified + parameters, `n` trials and `p` probability of success where `n` is an + integer > 0 and `p` is in the interval [0, 1]. + + Parameters + ---------- + n : int or array_like of ints + Parameter of the distribution, > 0. Floats are also accepted, + but they will be truncated to integers. + p : float or array_like of floats + Parameter of the distribution, >= 0 and <=1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``n`` and ``p`` are both scalars. + Otherwise, ``np.broadcast(n, p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized negative binomial distribution, + where each sample is equal to N, the number of trials it took to + achieve n - 1 successes, N - (n - 1) failures, and a success on the, + (N + n)th trial. + + Notes + ----- + The probability density for the negative binomial distribution is + + .. math:: P(N;n,p) = \\binom{N+n-1}{n-1}p^{n}(1-p)^{N}, + + where :math:`n-1` is the number of successes, :math:`p` is the + probability of success, and :math:`N+n-1` is the number of trials. + The negative binomial distribution gives the probability of n-1 + successes and N failures in N+n-1 trials, and success on the (N+n)th + trial. + + If one throws a die repeatedly until the third time a "1" appears, + then the probability distribution of the number of non-"1"s that + appear before the third "1" is a negative binomial distribution. + + References + ---------- + .. [1] Weisstein, Eric W. "Negative Binomial Distribution." From + MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/NegativeBinomialDistribution.html + .. [2] Wikipedia, "Negative binomial distribution", + http://en.wikipedia.org/wiki/Negative_binomial_distribution + + Examples + -------- + Draw samples from the distribution: + + A real world example. A company drills wild-cat oil + exploration wells, each with an estimated probability of + success of 0.1. What is the probability of having one success + for each successive well, that is what is the probability of a + single success after drilling 5 wells, after 6 wells, etc.? + + >>> s = randomgen.negative_binomial(1, 0.1, 100000) + >>> for i in range(1, 11): + ... probability = sum(s>> s = randomgen.dirichlet((10, 5, 3), 20).transpose() + + >>> plt.barh(range(20), s[0]) + >>> plt.barh(range(20), s[1], left=s[0], color='g') + >>> plt.barh(range(20), s[2], left=s[0]+s[1], color='r') + >>> plt.title("Lengths of Strings") + + """ + + #================= + # Pure python algo + #================= + #alpha = N.atleast_1d(alpha) + #k = alpha.size + + #if n == 1: + # val = N.zeros(k) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val) + #else: + # val = N.zeros((k, n)) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val, axis = 0) + # val = val.T + + #return val + + cdef np.npy_intp k + cdef np.npy_intp totsize + cdef np.ndarray alpha_arr, val_arr + cdef double *alpha_data + cdef double *val_data + cdef np.npy_intp i, j + cdef double acc, invacc + + k = len(alpha) + alpha_arr = np.PyArray_FROM_OTF(alpha, np.NPY_DOUBLE, np.NPY_ALIGNED) + if np.any(np.less_equal(alpha_arr, 0)): + raise ValueError('alpha <= 0') + alpha_data = np.PyArray_DATA(alpha_arr) + + if size is None: + shape = (k,) + else: + try: + shape = (operator.index(size), k) + except: + shape = tuple(size) + (k,) + + diric = np.zeros(shape, np.float64) + val_arr = diric + val_data= np.PyArray_DATA(val_arr) + + i = 0 + totsize = np.PyArray_SIZE(val_arr) + with self.lock, nogil: + while i < totsize: + acc = 0.0 + for j in range(k): + val_data[i+j] = legacy_standard_gamma(self._aug_state, + alpha_data[j]) + acc = acc + val_data[i + j] + invacc = 1/acc + for j in range(k): + val_data[i + j] = val_data[i + j] * invacc + i = i + k + + return diric + + + def multivariate_normal(self, mean, cov, size=None, check_valid='warn', + tol=1e-8): + """ + multivariate_normal(self, mean, cov, size=None, check_valid='warn', tol=1e-8) + + Draw random samples from a multivariate normal distribution. + + The multivariate normal, multinormal or Gaussian distribution is a + generalization of the one-dimensional normal distribution to higher + dimensions. Such a distribution is specified by its mean and + covariance matrix. These parameters are analogous to the mean + (average or "center") and variance (standard deviation, or "width," + squared) of the one-dimensional normal distribution. + + Parameters + ---------- + mean : 1-D array_like, of length N + Mean of the N-dimensional distribution. + cov : 2-D array_like, of shape (N, N) + Covariance matrix of the distribution. It must be symmetric and + positive-semidefinite for proper sampling. + size : int or tuple of ints, optional + Given a shape of, for example, ``(m,n,k)``, ``m*n*k`` samples are + generated, and packed in an `m`-by-`n`-by-`k` arrangement. Because + each sample is `N`-dimensional, the output shape is ``(m,n,k,N)``. + If no shape is specified, a single (`N`-D) sample is returned. + check_valid : { 'warn', 'raise', 'ignore' }, optional + Behavior when the covariance matrix is not positive semidefinite. + tol : float, optional + Tolerance when checking the singular values in covariance matrix. + + Returns + ------- + out : ndarray + The drawn samples, of shape *size*, if that was provided. If not, + the shape is ``(N,)``. + + In other words, each entry ``out[i,j,...,:]`` is an N-dimensional + value drawn from the distribution. + + Notes + ----- + The mean is a coordinate in N-dimensional space, which represents the + location where samples are most likely to be generated. This is + analogous to the peak of the bell curve for the one-dimensional or + univariate normal distribution. + + Covariance indicates the level to which two variables vary together. + From the multivariate normal distribution, we draw N-dimensional + samples, :math:`X = [x_1, x_2, ... x_N]`. The covariance matrix + element :math:`C_{ij}` is the covariance of :math:`x_i` and :math:`x_j`. + The element :math:`C_{ii}` is the variance of :math:`x_i` (i.e. its + "spread"). + + Instead of specifying the full covariance matrix, popular + approximations include: + + - Spherical covariance (`cov` is a multiple of the identity matrix) + - Diagonal covariance (`cov` has non-negative elements, and only on + the diagonal) + + This geometrical property can be seen in two dimensions by plotting + generated data-points: + + >>> mean = [0, 0] + >>> cov = [[1, 0], [0, 100]] # diagonal covariance + + Diagonal covariance means that points are oriented along x or y-axis: + + >>> import matplotlib.pyplot as plt + >>> x, y = randomgen.multivariate_normal(mean, cov, 5000).T + >>> plt.plot(x, y, 'x') + >>> plt.axis('equal') + >>> plt.show() + + Note that the covariance matrix must be positive semidefinite (a.k.a. + nonnegative-definite). Otherwise, the behavior of this method is + undefined and backwards compatibility is not guaranteed. + + References + ---------- + .. [1] Papoulis, A., "Probability, Random Variables, and Stochastic + Processes," 3rd ed., New York: McGraw-Hill, 1991. + .. [2] Duda, R. O., Hart, P. E., and Stork, D. G., "Pattern + Classification," 2nd ed., New York: Wiley, 2001. + + Examples + -------- + >>> mean = (1, 2) + >>> cov = [[1, 0], [0, 1]] + >>> x = randomgen.multivariate_normal(mean, cov, (3, 3)) + >>> x.shape + (3, 3, 2) + + The following is probably true, given that 0.6 is roughly twice the + standard deviation: + + >>> list((x[0,0,:] - mean) < 0.6) + [True, True] + + """ + from numpy.dual import svd + + # Check preconditions on arguments + mean = np.array(mean) + cov = np.array(cov) + if size is None: + shape = [] + elif isinstance(size, (int, long, np.integer)): + shape = [size] + else: + shape = size + + if len(mean.shape) != 1: + raise ValueError("mean must be 1 dimensional") + if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + raise ValueError("cov must be 2 dimensional and square") + if mean.shape[0] != cov.shape[0]: + raise ValueError("mean and cov must have same length") + + # Compute shape of output and create a matrix of independent + # standard normally distributed random numbers. The matrix has rows + # with the same length as mean and as many rows are necessary to + # form a matrix of shape final_shape. + final_shape = list(shape[:]) + final_shape.append(mean.shape[0]) + x = self.standard_normal(final_shape).reshape(-1, mean.shape[0]) + + # Transform matrix of standard normals into matrix where each row + # contains multivariate normals with the desired covariance. + # Compute A such that dot(transpose(A),A) == cov. + # Then the matrix products of the rows of x and A has the desired + # covariance. Note that sqrt(s)*v where (u,s,v) is the singular value + # decomposition of cov is such an A. + # + # Also check that cov is positive-semidefinite. If so, the u.T and v + # matrices should be equal up to roundoff error if cov is + # symmetrical and the singular value of the corresponding row is + # not zero. We continue to use the SVD rather than Cholesky in + # order to preserve current outputs. Note that symmetry has not + # been checked. + + (u, s, v) = svd(cov) + + if check_valid != 'ignore': + if check_valid != 'warn' and check_valid != 'raise': + raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") + + psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) + if not psd: + if check_valid == 'warn': + warnings.warn("covariance is not positive-semidefinite.", + RuntimeWarning) + else: + raise ValueError("covariance is not positive-semidefinite.") + + x = np.dot(x, np.sqrt(s)[:, None] * v) + x += mean + x.shape = tuple(final_shape) + return x + + + def standard_exponential(self, size=None): + """ + standard_exponential(size=None) + + Draw samples from the standard exponential distribution. + + `standard_exponential` is identical to the exponential distribution + with a scale parameter of 1. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : float or ndarray + Drawn samples. + + Examples + -------- + Output a 3x8000 array: + + >>> n = randomgen.standard_exponential((3, 8000)) + """ + return cont(&legacy_standard_exponential, self._aug_state, size, self.lock, 0, + None, None, CONS_NONE, + None, None, CONS_NONE, + None, None, CONS_NONE, + None) + + def exponential(self, scale=1.0, size=None): + """ + exponential(scale=1.0, size=None) + + Draw samples from an exponential distribution. + + Its probability density function is + + .. math:: f(x; \\frac{1}{\\beta}) = \\frac{1}{\\beta} \\exp(-\\frac{x}{\\beta}), + + for ``x > 0`` and 0 elsewhere. :math:`\\beta` is the scale parameter, + which is the inverse of the rate parameter :math:`\\lambda = 1/\\beta`. + The rate parameter is an alternative, widely used parameterization + of the exponential distribution [3]_. + + The exponential distribution is a continuous analogue of the + geometric distribution. It describes many common situations, such as + the size of raindrops measured over many rainstorms [1]_, or the time + between page requests to Wikipedia [2]_. + + Parameters + ---------- + scale : float or array_like of floats + The scale parameter, :math:`\\beta = 1/\\lambda`. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``scale`` is a scalar. Otherwise, + ``np.array(scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized exponential distribution. + + References + ---------- + .. [1] Peyton Z. Peebles Jr., "Probability, Random Variables and + Random Signal Principles", 4th ed, 2001, p. 57. + .. [2] Wikipedia, "Poisson process", + http://en.wikipedia.org/wiki/Poisson_process + .. [3] Wikipedia, "Exponential distribution", + http://en.wikipedia.org/wiki/Exponential_distribution + + """ + return cont(&legacy_exponential, self._aug_state, size, self.lock, 1, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) + + def power(self, a, size=None): + """ + power(a, size=None) + + Draws samples in [0, 1] from a power distribution with positive + exponent a - 1. + + Also known as the power function distribution. + + Parameters + ---------- + a : float or array_like of floats + Parameter of the distribution. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized power distribution. + + Raises + ------ + ValueError + If a < 1. + + Notes + ----- + The probability density function is + + .. math:: P(x; a) = ax^{a-1}, 0 \\le x \\le 1, a>0. + + The power function distribution is just the inverse of the Pareto + distribution. It may also be seen as a special case of the Beta + distribution. + + It is used, for example, in modeling the over-reporting of insurance + claims. + + References + ---------- + .. [1] Christian Kleiber, Samuel Kotz, "Statistical size distributions + in economics and actuarial sciences", Wiley, 2003. + .. [2] Heckert, N. A. and Filliben, James J. "NIST Handbook 148: + Dataplot Reference Manual, Volume 2: Let Subcommands and Library + Functions", National Institute of Standards and Technology + Handbook Series, June 2003. + http://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf + + Examples + -------- + Draw samples from the distribution: + + >>> a = 5. # shape + >>> samples = 1000 + >>> s = randomgen.power(a, samples) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, bins=30) + >>> x = np.linspace(0, 1, 100) + >>> y = a*x**(a-1.) + >>> normed_y = samples*np.diff(bins)[0]*y + >>> plt.plot(x, normed_y) + >>> plt.show() + + Compare the power function distribution to the inverse of the Pareto. + + >>> from scipy import stats + >>> rvs = randomgen.power(5, 1000000) + >>> rvsp = randomgen.pareto(5, 1000000) + >>> xx = np.linspace(0,1,100) + >>> powpdf = stats.powerlaw.pdf(xx,5) + + >>> plt.figure() + >>> plt.hist(rvs, bins=50, normed=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('randomgen.power(5)') + + >>> plt.figure() + >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('inverse of 1 + randomgen.pareto(5)') + + >>> plt.figure() + >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('inverse of stats.pareto(5)') + + """ + return cont(&legacy_power, self._aug_state, size, self.lock, 1, + a, 'a', CONS_POSITIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) diff --git a/_randomgen/randomgen/legacy/legacy_distributions.pxd b/_randomgen/randomgen/legacy/legacy_distributions.pxd new file mode 100644 index 000000000000..d22d6a73aacf --- /dev/null +++ b/_randomgen/randomgen/legacy/legacy_distributions.pxd @@ -0,0 +1,40 @@ +from libc.stdint cimport uint64_t + +import numpy as np +cimport numpy as np + +from randomgen.distributions cimport brng_t + +cdef extern from "../src/legacy/distributions-boxmuller.h": + + struct aug_brng: + brng_t *basicrng + int has_gauss + double gauss + + ctypedef aug_brng aug_brng_t + + double legacy_gauss(aug_brng_t *aug_state) nogil + double legacy_pareto(aug_brng_t *aug_state, double a) nogil + double legacy_weibull(aug_brng_t *aug_state, double a) nogil + double legacy_standard_gamma(aug_brng_t *aug_state, double shape) nogil + double legacy_normal(aug_brng_t *aug_state, double loc, double scale) nogil + double legacy_standard_t(aug_brng_t *aug_state, double df) nogil + + double legacy_standard_exponential(aug_brng_t *aug_state) nogil + double legacy_power(aug_brng_t *aug_state, double a) nogil + double legacy_gamma(aug_brng_t *aug_state, double shape, double scale) nogil + double legacy_power(aug_brng_t *aug_state, double a) nogil + double legacy_chisquare(aug_brng_t *aug_state, double df) nogil + double legacy_noncentral_chisquare(aug_brng_t *aug_state, double df, + double nonc) nogil + double legacy_noncentral_f(aug_brng_t *aug_state, double dfnum, double dfden, + double nonc) nogil + double legacy_wald(aug_brng_t *aug_state, double mean, double scale) nogil + double legacy_lognormal(aug_brng_t *aug_state, double mean, double sigma) nogil + uint64_t legacy_negative_binomial(aug_brng_t *aug_state, double n, double p) nogil + double legacy_standard_cauchy(aug_brng_t *state) nogil + double legacy_beta(aug_brng_t *aug_state, double a, double b) nogil + double legacy_f(aug_brng_t *aug_state, double dfnum, double dfden) nogil + double legacy_exponential(aug_brng_t *aug_state, double scale) nogil + double legacy_power(aug_brng_t *state, double a) nogil diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 246cddb444e8..0e6e9cd578f5 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -7,17 +7,16 @@ float random_float(brng_t *brng_state) { return next_float(brng_state); } double random_double(brng_t *brng_state) { return next_double(brng_state); } -static NPY_INLINE double next_standard_exponential(brng_t *brng_state) -{ - return -log(1.0 - next_double(brng_state)); +static NPY_INLINE double next_standard_exponential(brng_t *brng_state) { + return -log(1.0 - next_double(brng_state)); } double random_standard_exponential(brng_t *brng_state) { return next_standard_exponential(brng_state); } -void random_standard_exponential_fill(brng_t *brng_state, npy_intp cnt, double *out) -{ +void random_standard_exponential_fill(brng_t *brng_state, npy_intp cnt, + double *out) { npy_intp i; for (i = 0; i < cnt; i++) { out[i] = next_standard_exponential(brng_state); @@ -28,8 +27,7 @@ float random_standard_exponential_f(brng_t *brng_state) { return -logf(1.0f - next_float(brng_state)); } -void random_double_fill(brng_t* brng_state, npy_intp cnt, double *out) -{ +void random_double_fill(brng_t *brng_state, npy_intp cnt, double *out) { npy_intp i; for (i = 0; i < cnt; i++) { out[i] = next_double(brng_state); @@ -119,16 +117,14 @@ double random_standard_exponential_zig(brng_t *brng_state) { return standard_exponential_zig(brng_state); } - -void random_standard_exponential_zig_fill(brng_t *brng_state, npy_intp cnt, double *out) -{ +void random_standard_exponential_zig_fill(brng_t *brng_state, npy_intp cnt, + double *out) { npy_intp i; for (i = 0; i < cnt; i++) { out[i] = standard_exponential_zig(brng_state); } } - static NPY_INLINE float standard_exponential_zig_f(brng_t *brng_state); static float standard_exponential_zig_unlikely_f(brng_t *brng_state, @@ -502,7 +498,7 @@ double random_normal_zig(brng_t *brng_state, double loc, double scale) { } double random_exponential(brng_t *brng_state, double scale) { - return scale * random_standard_exponential(brng_state); + return scale * standard_exponential_zig(brng_state); } double random_uniform(brng_t *brng_state, double lower, double range) { @@ -565,15 +561,15 @@ double random_standard_cauchy(brng_t *brng_state) { } double random_pareto(brng_t *brng_state, double a) { - return exp(random_standard_exponential(brng_state) / a) - 1; + return exp(standard_exponential_zig(brng_state) / a) - 1; } double random_weibull(brng_t *brng_state, double a) { - return pow(random_standard_exponential(brng_state), 1. / a); + return pow(standard_exponential_zig(brng_state), 1. / a); } double random_power(brng_t *brng_state, double a) { - return pow(1 - exp(-random_standard_exponential(brng_state)), 1. / a); + return pow(1 - exp(-standard_exponential_zig(brng_state)), 1. / a); } double random_laplace(brng_t *brng_state, double loc, double scale) { diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index 6785405c7aa0..2dd453d3a734 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -1,3 +1,4 @@ +#pragma once #include #ifdef _WIN32 #if _MSC_VER == 1500 @@ -95,7 +96,7 @@ static NPY_INLINE double next_double(brng_t *brng_state) { DECLDIR float random_float(brng_t *brng_state); DECLDIR double random_double(brng_t *brng_state); -DECLDIR void random_double_fill(brng_t* brng_state, npy_intp cnt, double *out); +DECLDIR void random_double_fill(brng_t *brng_state, npy_intp cnt, double *out); DECLDIR int64_t random_positive_int64(brng_t *brng_state); DECLDIR int32_t random_positive_int32(brng_t *brng_state); @@ -103,10 +104,12 @@ DECLDIR int64_t random_positive_int(brng_t *brng_state); DECLDIR uint64_t random_uint(brng_t *brng_state); DECLDIR double random_standard_exponential(brng_t *brng_state); -DECLDIR void random_standard_exponential_fill(brng_t *brng_state, npy_intp cnt, double *out); +DECLDIR void random_standard_exponential_fill(brng_t *brng_state, npy_intp cnt, + double *out); DECLDIR float random_standard_exponential_f(brng_t *brng_state); DECLDIR double random_standard_exponential_zig(brng_t *brng_state); -DECLDIR void random_standard_exponential_zig_fill(brng_t *brng_state, npy_intp cnt, double *out); +DECLDIR void random_standard_exponential_zig_fill(brng_t *brng_state, + npy_intp cnt, double *out); DECLDIR float random_standard_exponential_zig_f(brng_t *brng_state); /* @@ -115,7 +118,8 @@ DECLDIR float random_gauss_f(brng_t *brng_state); */ DECLDIR double random_gauss_zig(brng_t *brng_state); DECLDIR float random_gauss_zig_f(brng_t *brng_state); -DECLDIR void random_gauss_zig_fill(brng_t *brng_state, npy_intp cnt, double *out); +DECLDIR void random_gauss_zig_fill(brng_t *brng_state, npy_intp cnt, + double *out); /* DECLDIR double random_standard_gamma(brng_t *brng_state, double shape); diff --git a/_randomgen/randomgen/src/legacy/distributions-boxmuller.c b/_randomgen/randomgen/src/legacy/distributions-boxmuller.c new file mode 100644 index 000000000000..8d3d94095cc8 --- /dev/null +++ b/_randomgen/randomgen/src/legacy/distributions-boxmuller.c @@ -0,0 +1,201 @@ +#include "distributions-boxmuller.h" + +static NPY_INLINE double legacy_double(aug_brng_t *aug_state) { + return aug_state->basicrng->next_double(aug_state->basicrng->state); +} + +double legacy_gauss(aug_brng_t *aug_state) { + if (aug_state->has_gauss) { + const double temp = aug_state->gauss; + aug_state->has_gauss = false; + aug_state->gauss = 0.0; + return temp; + } else { + double f, x1, x2, r2; + + do { + x1 = 2.0 * legacy_double(aug_state) - 1.0; + x2 = 2.0 * legacy_double(aug_state) - 1.0; + r2 = x1 * x1 + x2 * x2; + } while (r2 >= 1.0 || r2 == 0.0); + + /* Box-Muller transform */ + f = sqrt(-2.0 * log(r2) / r2); + /* Keep for next call */ + aug_state->gauss = f * x1; + aug_state->has_gauss = true; + return f * x2; + } +} + +double legacy_standard_exponential(aug_brng_t *aug_state) { + /* We use -log(1-U) since U is [0, 1) */ + return -log(1.0 - legacy_double(aug_state)); +} + +double legacy_standard_gamma(aug_brng_t *aug_state, double shape) { + double b, c; + double U, V, X, Y; + + if (shape == 1.0) { + return legacy_standard_exponential(aug_state); + } else if (shape < 1.0) { + for (;;) { + U = legacy_double(aug_state); + V = legacy_standard_exponential(aug_state); + if (U <= 1.0 - shape) { + X = pow(U, 1. / shape); + if (X <= V) { + return X; + } + } else { + Y = -log((1 - U) / shape); + X = pow(1.0 - shape + shape * Y, 1. / shape); + if (X <= (V + Y)) { + return X; + } + } + } + } else { + b = shape - 1. / 3.; + c = 1. / sqrt(9 * b); + for (;;) { + do { + X = legacy_gauss(aug_state); + V = 1.0 + c * X; + } while (V <= 0.0); + + V = V * V * V; + U = legacy_double(aug_state); + if (U < 1.0 - 0.0331 * (X * X) * (X * X)) + return (b * V); + if (log(U) < 0.5 * X * X + b * (1. - V + log(V))) + return (b * V); + } + } +} + +double legacy_gamma(aug_brng_t *aug_state, double shape, double scale) { + return scale * legacy_standard_gamma(aug_state, shape); +} + +double legacy_pareto(aug_brng_t *aug_state, double a) { + return exp(legacy_standard_exponential(aug_state) / a) - 1; +} + +double legacy_weibull(aug_brng_t *aug_state, double a) { + return pow(legacy_standard_exponential(aug_state), 1. / a); +} + +double legacy_power(aug_brng_t *aug_state, double a) { + return pow(1 - exp(-legacy_standard_exponential(aug_state)), 1. / a); +} + +double legacy_chisquare(aug_brng_t *aug_state, double df) { + return 2.0 * legacy_standard_gamma(aug_state, df / 2.0); +} + +double legacy_noncentral_chisquare(aug_brng_t *aug_state, double df, + double nonc) { + if (nonc == 0) { + return legacy_chisquare(aug_state, df); + } + if (1 < df) { + const double Chi2 = legacy_chisquare(aug_state, df - 1); + const double n = legacy_gauss(aug_state) + sqrt(nonc); + return Chi2 + n * n; + } else { + const long i = random_poisson(aug_state->basicrng, nonc / 2.0); + return legacy_chisquare(aug_state, df + 2 * i); + } +} + +double legacy_noncentral_f(aug_brng_t *aug_state, double dfnum, double dfden, + double nonc) { + double t = legacy_noncentral_chisquare(aug_state, dfnum, nonc) * dfden; + return t / (legacy_chisquare(aug_state, dfden) * dfnum); +} + +double legacy_wald(aug_brng_t *aug_state, double mean, double scale) { + double U, X, Y; + double mu_2l; + + mu_2l = mean / (2 * scale); + Y = legacy_gauss(aug_state); + Y = mean * Y * Y; + X = mean + mu_2l * (Y - sqrt(4 * scale * Y + Y * Y)); + U = legacy_double(aug_state); + if (U <= mean / (mean + X)) { + return X; + } else { + return mean * mean / X; + } +} + +double legacy_normal(aug_brng_t *aug_state, double loc, double scale) { + return loc + scale * legacy_gauss(aug_state); +} + +double legacy_lognormal(aug_brng_t *aug_state, double mean, double sigma) { + return exp(legacy_normal(aug_state, mean, sigma)); +} + +double legacy_standard_t(aug_brng_t *aug_state, double df) { + double num, denom; + + num = legacy_gauss(aug_state); + denom = legacy_standard_gamma(aug_state, df / 2); + return sqrt(df / 2) * num / sqrt(denom); +} + +int64_t legacy_negative_binomial(aug_brng_t *aug_state, double n, double p) { + double Y = legacy_gamma(aug_state, n, (1 - p) / p); + return random_poisson(aug_state->basicrng, Y); +} + +double legacy_standard_cauchy(aug_brng_t *aug_state) { + return legacy_gauss(aug_state) / legacy_gauss(aug_state); +} + +double legacy_beta(aug_brng_t *aug_state, double a, double b) { + double Ga, Gb; + + if ((a <= 1.0) && (b <= 1.0)) { + double U, V, X, Y; + /* Use Johnk's algorithm */ + + while (1) { + U = legacy_double(aug_state); + V = legacy_double(aug_state); + X = pow(U, 1.0 / a); + Y = pow(V, 1.0 / b); + + if ((X + Y) <= 1.0) { + if (X + Y > 0) { + return X / (X + Y); + } else { + double logX = log(U) / a; + double logY = log(V) / b; + double logM = logX > logY ? logX : logY; + logX -= logM; + logY -= logM; + + return exp(logX - log(exp(logX) + exp(logY))); + } + } + } + } else { + Ga = legacy_standard_gamma(aug_state, a); + Gb = legacy_standard_gamma(aug_state, b); + return Ga / (Ga + Gb); + } +} + +double legacy_f(aug_brng_t *aug_state, double dfnum, double dfden) { + return ((legacy_chisquare(aug_state, dfnum) * dfden) / + (legacy_chisquare(aug_state, dfden) * dfnum)); +} + +double legacy_exponential(aug_brng_t *aug_state, double scale) { + return scale * legacy_standard_exponential(aug_state); +} diff --git a/_randomgen/randomgen/src/legacy/distributions-boxmuller.h b/_randomgen/randomgen/src/legacy/distributions-boxmuller.h new file mode 100644 index 000000000000..2c0615bdb868 --- /dev/null +++ b/_randomgen/randomgen/src/legacy/distributions-boxmuller.h @@ -0,0 +1,34 @@ +#include "../distributions/distributions.h" + +typedef struct aug_brng { + brng_t *basicrng; + int has_gauss; + double gauss; +} aug_brng_t; + +extern double legacy_gauss(aug_brng_t *aug_state); +extern double legacy_standard_exponential(aug_brng_t *aug_state); +extern double legacy_pareto(aug_brng_t *aug_state, double a); +extern double legacy_weibull(aug_brng_t *aug_state, double a); +extern double legacy_power(aug_brng_t *aug_state, double a); +extern double legacy_gamma(aug_brng_t *aug_state, double shape, double scale); +extern double legacy_pareto(aug_brng_t *aug_state, double a); +extern double legacy_weibull(aug_brng_t *aug_state, double a); +extern double legacy_chisquare(aug_brng_t *aug_state, double df); +extern double legacy_noncentral_chisquare(aug_brng_t *aug_state, double df, + double nonc); + +extern double legacy_noncentral_f(aug_brng_t *aug_state, double dfnum, + double dfden, double nonc); +extern double legacy_wald(aug_brng_t *aug_state, double mean, double scale); +extern double legacy_lognormal(aug_brng_t *aug_state, double mean, + double sigma); +extern double legacy_standard_t(aug_brng_t *aug_state, double df); +extern int64_t legacy_negative_binomial(aug_brng_t *aug_state, double n, + double p); +extern double legacy_standard_cauchy(aug_brng_t *state); +extern double legacy_beta(aug_brng_t *aug_state, double a, double b); +extern double legacy_f(aug_brng_t *aug_state, double dfnum, double dfden); +extern double legacy_normal(aug_brng_t *aug_state, double loc, double scale); +extern double legacy_standard_gamma(aug_brng_t *aug_state, double shape); +extern double legacy_exponential(aug_brng_t *aug_state, double scale); diff --git a/_randomgen/randomgen/tests/test_against_numpy.py b/_randomgen/randomgen/tests/test_against_numpy.py index 2e49c1f18ff6..a7da65d5997b 100644 --- a/_randomgen/randomgen/tests/test_against_numpy.py +++ b/_randomgen/randomgen/tests/test_against_numpy.py @@ -5,6 +5,7 @@ import randomgen from randomgen import RandomGenerator, MT19937 +from randomgen.legacy import LegacyGenerator def compare_0_input(f1, f2): @@ -88,6 +89,7 @@ def setup_class(cls): cls.brng = MT19937 cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] cls.rg = RandomGenerator(cls.brng(*cls.seed)) + cls.lg = LegacyGenerator(cls.brng(*cls.seed)) cls.nprs = cls.np.RandomState(*cls.seed) cls.initial_state = cls.rg.state cls._set_common_state() @@ -103,12 +105,31 @@ def _set_common_state(cls): st[4] = 0.0 cls.nprs.set_state(st) + @classmethod + def _set_common_state_legacy(cls): + state = cls.lg.state + st = [[]] * 5 + st[0] = 'MT19937' + st[1] = state['state']['key'] + st[2] = state['state']['pos'] + st[3] = state['has_gauss'] + st[4] = state['gauss'] + cls.nprs.set_state(st) + def _is_state_common(self): state = self.nprs.get_state() state2 = self.rg.state assert (state[1] == state2['state']['key']).all() assert (state[2] == state2['state']['pos']) + def _is_state_common_legacy(self): + state = self.nprs.get_state() + state2 = self.lg.state + assert (state[1] == state2['state']['key']).all() + assert (state[2] == state2['state']['pos']) + assert (state[3] == state2['has_gauss']) + assert (state[4] == state2['gauss']) + def test_common_seed(self): self.rg.seed(1234) self.nprs.seed(1234) @@ -162,37 +183,6 @@ def test_tomaxint(self): self.rg.tomaxint) self._is_state_common() - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_chisquare(self): - self._set_common_state() - self._is_state_common() - compare_1_input(self.nprs.chisquare, - self.rg.chisquare) - self._is_state_common() - - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_standard_gamma(self): - self._set_common_state() - self._is_state_common() - compare_1_input(self.nprs.standard_gamma, - self.rg.standard_gamma) - self._is_state_common() - - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_standard_t(self): - self._set_common_state() - self._is_state_common() - compare_1_input(self.nprs.standard_t, - self.rg.standard_t) - self._is_state_common() - - def test_pareto(self): - self._set_common_state() - self._is_state_common() - compare_1_input(self.nprs.pareto, - self.rg.pareto) - self._is_state_common() - def test_poisson(self): self._set_common_state() self._is_state_common() @@ -200,13 +190,6 @@ def test_poisson(self): self.rg.poisson) self._is_state_common() - def test_power(self): - self._set_common_state() - self._is_state_common() - compare_1_input(self.nprs.power, - self.rg.power) - self._is_state_common() - def test_rayleigh(self): self._set_common_state() self._is_state_common() @@ -214,13 +197,6 @@ def test_rayleigh(self): self.rg.rayleigh) self._is_state_common() - def test_weibull(self): - self._set_common_state() - self._is_state_common() - compare_1_input(self.nprs.weibull, - self.rg.weibull) - self._is_state_common() - def test_zipf(self): self._set_common_state() self._is_state_common() @@ -244,37 +220,6 @@ def test_geometric(self): is_small=True) self._is_state_common() - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_beta(self): - self._set_common_state() - self._is_state_common() - compare_2_input(self.nprs.beta, - self.rg.beta) - self._is_state_common() - - def test_exponential(self): - self._set_common_state() - self._is_state_common() - compare_1_input(self.nprs.exponential, - self.rg.exponential) - self._is_state_common() - - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_f(self): - self._set_common_state() - self._is_state_common() - compare_2_input(self.nprs.f, - self.rg.f) - self._is_state_common() - - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_gamma(self): - self._set_common_state() - self._is_state_common() - compare_2_input(self.nprs.gamma, - self.rg.gamma) - self._is_state_common() - def test_logistic(self): self._set_common_state() self._is_state_common() @@ -296,30 +241,6 @@ def test_laplace(self): self.rg.laplace) self._is_state_common() - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_lognormal(self): - self._set_common_state() - self._is_state_common() - compare_2_input(self.nprs.lognormal, - self.rg.lognormal) - self._is_state_common() - - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_noncentral_chisquare(self): - self._set_common_state() - self._is_state_common() - compare_2_input(self.nprs.noncentral_chisquare, - self.rg.noncentral_chisquare) - self._is_state_common() - - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_normal(self): - self._set_common_state() - self._is_state_common() - compare_2_input(self.nprs.normal, - self.rg.normal) - self._is_state_common() - def test_uniform(self): self._set_common_state() self._is_state_common() @@ -334,14 +255,6 @@ def test_vonmises(self): self.rg.vonmises) self._is_state_common() - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_wald(self): - self._set_common_state() - self._is_state_common() - compare_2_input(self.nprs.wald, - self.rg.wald) - self._is_state_common() - def test_random_integers(self): self._set_common_state() self._is_state_common() @@ -358,22 +271,6 @@ def test_binomial(self): is_np=True) self._is_state_common() - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_negative_binomial(self): - self._set_common_state() - self._is_state_common() - compare_2_input(self.nprs.negative_binomial, - self.rg.negative_binomial, - is_np=True) - self._is_state_common() - - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_randn(self): - f = self.rg.randn - g = self.nprs.randn - assert_allclose(f(10), g(10)) - assert_allclose(f(3, 4, 5), g(3, 4, 5)) - def test_rand(self): self._set_common_state() self._is_state_common() @@ -385,23 +282,6 @@ def test_rand(self): def test_poisson_lam_max(self): assert_allclose(self.rg.poisson_lam_max, self.nprs.poisson_lam_max) - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_dirichlet(self): - f = self.rg.dirichlet - g = self.nprs.dirichlet - a = [3, 4, 5, 6, 7, 10] - assert_allclose(f(a), g(a)) - assert_allclose(f(np.array(a), 10), g(np.array(a), 10)) - assert_allclose(f(np.array(a), (3, 37)), g(np.array(a), (3, 37))) - - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_noncentral_f(self): - self._set_common_state() - self._is_state_common() - compare_3_input(self.nprs.noncentral_f, - self.rg.noncentral_f) - self._is_state_common() - def test_triangular(self): self._set_common_state() self._is_state_common() @@ -473,22 +353,6 @@ def test_shuffle(self): assert_equal(fa, ga) self._is_state_common() - @pytest.mark.skip(reason='Box-Muller no longer supported') - def test_multivariate_normal(self): - self._set_common_state() - self._is_state_common() - mu = [1, 2, 3] - cov = [[1, .2, .3], [.2, 4, 1], [.3, 1, 10]] - f = self.rg.multivariate_normal - g = self.nprs.multivariate_normal - assert_allclose(f(mu, cov), g(mu, cov)) - assert_allclose(f(np.array(mu), cov), g(np.array(mu), cov)) - assert_allclose(f(np.array(mu), np.array(cov)), - g(np.array(mu), np.array(cov))) - assert_allclose(f(np.array(mu), np.array(cov), size=(7, 31)), - g(np.array(mu), np.array(cov), size=(7, 31))) - self._is_state_common() - def test_randint(self): self._set_common_state() self._is_state_common() @@ -546,3 +410,152 @@ def test_dir(self): diff = set(npmod).difference(mod) print(diff) assert_equal(len(diff), 0) + + # Tests using legacy generator + def test_chisquare(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_1_input(self.nprs.chisquare, + self.lg.chisquare) + self._is_state_common_legacy() + + def test_standard_gamma(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_1_input(self.nprs.standard_gamma, + self.lg.standard_gamma) + self._is_state_common_legacy() + + def test_standard_t(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_1_input(self.nprs.standard_t, + self.lg.standard_t) + self._is_state_common_legacy() + + def test_pareto(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_1_input(self.nprs.pareto, + self.lg.pareto) + self._is_state_common_legacy() + + def test_power(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_1_input(self.nprs.power, + self.lg.power) + self._is_state_common_legacy() + + def test_weibull(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_1_input(self.nprs.weibull, + self.lg.weibull) + self._is_state_common_legacy() + + def test_beta(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_2_input(self.nprs.beta, + self.lg.beta) + self._is_state_common_legacy() + + def test_exponential(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_1_input(self.nprs.exponential, + self.lg.exponential) + self._is_state_common_legacy() + + def test_f(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_2_input(self.nprs.f, + self.lg.f) + self._is_state_common_legacy() + + def test_gamma(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_2_input(self.nprs.gamma, + self.lg.gamma) + self._is_state_common_legacy() + + def test_lognormal(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_2_input(self.nprs.lognormal, + self.lg.lognormal) + self._is_state_common_legacy() + + def test_noncentral_chisquare(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_2_input(self.nprs.noncentral_chisquare, + self.lg.noncentral_chisquare) + self._is_state_common_legacy() + + def test_normal(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_2_input(self.nprs.normal, + self.lg.normal) + self._is_state_common_legacy() + + def test_wald(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_2_input(self.nprs.wald, + self.lg.wald) + self._is_state_common_legacy() + + def test_negative_binomial(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_2_input(self.nprs.negative_binomial, + self.lg.negative_binomial, + is_np=True) + self._is_state_common_legacy() + + def test_randn(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + f = self.lg.randn + g = self.nprs.randn + assert_allclose(f(10), g(10)) + assert_allclose(f(3, 4, 5), g(3, 4, 5)) + self._is_state_common_legacy() + + def test_dirichlet(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + f = self.lg.dirichlet + g = self.nprs.dirichlet + a = [3, 4, 5, 6, 7, 10] + assert_allclose(f(a), g(a)) + assert_allclose(f(np.array(a), 10), g(np.array(a), 10)) + assert_allclose(f(np.array(a), (3, 37)), g(np.array(a), (3, 37))) + self._is_state_common_legacy() + + def test_noncentral_f(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + compare_3_input(self.nprs.noncentral_f, + self.lg.noncentral_f) + self._is_state_common_legacy() + + def test_multivariate_normal(self): + self._set_common_state_legacy() + self._is_state_common_legacy() + mu = [1, 2, 3] + cov = [[1, .2, .3], [.2, 4, 1], [.3, 1, 10]] + f = self.lg.multivariate_normal + g = self.nprs.multivariate_normal + assert_allclose(f(mu, cov), g(mu, cov)) + assert_allclose(f(np.array(mu), cov), g(np.array(mu), cov)) + assert_allclose(f(np.array(mu), np.array(cov)), + g(np.array(mu), np.array(cov))) + assert_allclose(f(np.array(mu), np.array(cov), size=(7, 31)), + g(np.array(mu), np.array(cov), size=(7, 31))) + self._is_state_common_legacy() diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 85419b2172bf..c22aa35808f7 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -12,8 +12,11 @@ from randomgen._testing import suppress_warnings from randomgen import RandomGenerator, MT19937 +from randomgen.legacy import LegacyGenerator random = mt19937 = RandomGenerator(MT19937()) +legacy = LegacyGenerator(MT19937()) + class TestSeed(object): def test_scalar(self): @@ -122,16 +125,16 @@ def test_gaussian_reset_in_media_res(self): new = self.brng.standard_normal(size=3) assert_(np.all(old == new)) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_backwards_compatibility(self): # Make sure we can accept old state tuples that do not have the # cached Gaussian value. - old_state = self.legacy_state[:-2] - x1 = self.brng.standard_normal(size=16) - self.brng.state = old_state - x2 = self.brng.standard_normal(size=16) - self.brng.state = self.state - x3 = self.brng.standard_normal(size=16) + old_state = self.legacy_state + legacy.state = old_state + x1 = legacy.standard_normal(size=16) + legacy.state = old_state + x2 = legacy.standard_normal(size=16) + legacy.state = old_state + (0, 0.0) + x3 = legacy.standard_normal(size=16) assert_(np.all(x1 == x2)) assert_(np.all(x1 == x3)) @@ -169,8 +172,10 @@ def test_bounds_checking_array(self): for dt in self.itype: lbnd = 0 if dt is bool else np.iinfo(dt).min ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 - assert_raises(ValueError, self.rfunc, [lbnd - 1] * 2, [ubnd] * 2, dtype=dt) - assert_raises(ValueError, self.rfunc, [lbnd] * 2, [ubnd + 1] * 2, dtype=dt) + assert_raises(ValueError, self.rfunc, [ + lbnd - 1] * 2, [ubnd] * 2, dtype=dt) + assert_raises(ValueError, self.rfunc, [ + lbnd] * 2, [ubnd + 1] * 2, dtype=dt) assert_raises(ValueError, self.rfunc, ubnd, [lbnd] * 2, dtype=dt) assert_raises(ValueError, self.rfunc, [1] * 2, 0, dtype=dt) @@ -189,7 +194,8 @@ def test_rng_zero_and_extremes(self): tgt = (lbnd + ubnd) // 2 assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt) - assert_equal(self.rfunc([tgt], [tgt + 1], size=1000, dtype=dt), tgt) + assert_equal(self.rfunc([tgt], [tgt + 1], + size=1000, dtype=dt), tgt) def test_rng_zero_and_extremes_array(self): size = 1000 @@ -198,19 +204,28 @@ def test_rng_zero_and_extremes_array(self): ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 tgt = ubnd - 1 - assert_equal(self.rfunc([tgt], [tgt + 1], size=size, dtype=dt), tgt) - assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, dtype=dt), tgt) - assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, size=size, dtype=dt), tgt) + assert_equal(self.rfunc([tgt], [tgt + 1], + size=size, dtype=dt), tgt) + assert_equal(self.rfunc( + [tgt] * size, [tgt + 1] * size, dtype=dt), tgt) + assert_equal(self.rfunc( + [tgt] * size, [tgt + 1] * size, size=size, dtype=dt), tgt) tgt = lbnd - assert_equal(self.rfunc([tgt], [tgt + 1], size=size, dtype=dt), tgt) - assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, dtype=dt), tgt) - assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, size=size, dtype=dt), tgt) + assert_equal(self.rfunc([tgt], [tgt + 1], + size=size, dtype=dt), tgt) + assert_equal(self.rfunc( + [tgt] * size, [tgt + 1] * size, dtype=dt), tgt) + assert_equal(self.rfunc( + [tgt] * size, [tgt + 1] * size, size=size, dtype=dt), tgt) tgt = (lbnd + ubnd) // 2 - assert_equal(self.rfunc([tgt], [tgt + 1], size=size, dtype=dt), tgt) - assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, dtype=dt), tgt) - assert_equal(self.rfunc([tgt] * size, [tgt + 1] * size, size=size, dtype=dt), tgt) + assert_equal(self.rfunc([tgt], [tgt + 1], + size=size, dtype=dt), tgt) + assert_equal(self.rfunc( + [tgt] * size, [tgt + 1] * size, dtype=dt), tgt) + assert_equal(self.rfunc( + [tgt] * size, [tgt + 1] * size, size=size, dtype=dt), tgt) def test_full_range(self): # Test for ticket #1690 @@ -268,7 +283,8 @@ def test_scalar_array_equiv(self): scalar_array = self.rfunc([lbnd], [ubnd], size=size, dtype=dt) mt19937.seed(1234) - array = self.rfunc([lbnd] * size, [ubnd] * size, size=size, dtype=dt) + array = self.rfunc([lbnd] * size, [ubnd] * + size, size=size, dtype=dt) assert_array_equal(scalar, scalar_array) assert_array_equal(scalar, array) @@ -297,21 +313,20 @@ def test_repeatability(self): val = self.rfunc(0, 6, size=1000, dtype=dt).byteswap() res = hashlib.md5(val.view(np.int8)).hexdigest() - print(tgt[np.dtype(dt).name] == res) assert_(tgt[np.dtype(dt).name] == res) # bools do not depend on endianess mt19937.seed(1234) val = self.rfunc(0, 2, size=1000, dtype=bool).view(np.int8) res = hashlib.md5(val).hexdigest() - print(tgt[np.dtype(bool).name] == res) assert_(tgt[np.dtype(bool).name] == res) def test_repeatability_broadcasting(self): for dt in self.itype: lbnd = 0 if dt in (np.bool, bool, np.bool_) else np.iinfo(dt).min - ubnd = 2 if dt in (np.bool, bool, np.bool_) else np.iinfo(dt).max + 1 + ubnd = 2 if dt in ( + np.bool, bool, np.bool_) else np.iinfo(dt).max + 1 # view as little endian for hash mt19937.seed(1234) @@ -405,10 +420,9 @@ def test_rand(self): [0.4575674820298663, 0.7781880808593471]]) assert_array_almost_equal(actual, desired, decimal=15) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_randn(self): - mt19937.seed(self.seed) - actual = mt19937.randn(3, 2) + legacy.seed(self.seed) + actual = legacy.randn(3, 2) desired = np.array([[1.34016345771863121, 1.73759122771936081], [1.498988344300628, -0.2286433324536169], [2.031033998682787, 2.17032494605655257]]) @@ -612,20 +626,18 @@ def test_binomial(self): [46, 45]]) assert_array_equal(actual, desired) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_chisquare(self): - mt19937.seed(self.seed) - actual = mt19937.chisquare(50, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.chisquare(50, size=(3, 2)) desired = np.array([[63.87858175501090585, 68.68407748911370447], [65.77116116901505904, 47.09686762438974483], [72.3828403199695174, 74.18408615260374006]]) assert_array_almost_equal(actual, desired, decimal=13) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_dirichlet(self): - mt19937.seed(self.seed) + legacy.seed(self.seed) alpha = np.array([51.72840233779265162, 39.74494232180943953]) - actual = mt19937.dirichlet(alpha, size=(3, 2)) + actual = legacy.dirichlet(alpha, size=(3, 2)) desired = np.array([[[0.54539444573611562, 0.45460555426388438], [0.62345816822039413, 0.37654183177960598]], [[0.55206000085785778, 0.44793999914214233], @@ -654,8 +666,8 @@ def test_dirichlet_bad_alpha(self): assert_raises(ValueError, mt19937.dirichlet, alpha) def test_exponential(self): - mt19937.seed(self.seed) - actual = mt19937.exponential(1.1234, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.exponential(1.1234, size=(3, 2)) desired = np.array([[1.08342649775011624, 1.00607889924557314], [2.46628830085216721, 2.49668106809923884], [0.68717433461363442, 1.69175666993575979]]) @@ -665,19 +677,17 @@ def test_exponential_0(self): assert_equal(mt19937.exponential(scale=0), 0) assert_raises(ValueError, mt19937.exponential, scale=-0.) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_f(self): - mt19937.seed(self.seed) - actual = mt19937.f(12, 77, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.f(12, 77, size=(3, 2)) desired = np.array([[1.21975394418575878, 1.75135759791559775], [1.44803115017146489, 1.22108959480396262], [1.02176975757740629, 1.34431827623300415]]) assert_array_almost_equal(actual, desired, decimal=15) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_gamma(self): - mt19937.seed(self.seed) - actual = mt19937.gamma(5, 3, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.gamma(5, 3, size=(3, 2)) desired = np.array([[24.60509188649287182, 28.54993563207210627], [26.13476110204064184, 12.56988482927716078], [31.71863275789960568, 33.30143302795922011]]) @@ -753,10 +763,9 @@ def test_logistic(self): [-0.21682183359214885, 2.63373365386060332]]) assert_array_almost_equal(actual, desired, decimal=15) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_lognormal(self): - mt19937.seed(self.seed) - actual = mt19937.lognormal(mean=.123456789, sigma=2.0, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.lognormal(mean=.123456789, sigma=2.0, size=(3, 2)) desired = np.array([[16.50698631688883822, 36.54846706092654784], [22.67886599981281748, 0.71617561058995771], [65.72798501792723869, 86.84341601437161273]]) @@ -785,13 +794,12 @@ def test_multinomial(self): [4, 3, 4, 2, 3, 4]]]) assert_array_equal(actual, desired) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_multivariate_normal(self): - mt19937.seed(self.seed) + legacy.seed(self.seed) mean = (.123456789, 10) cov = [[1, 0], [0, 1]] size = (3, 2) - actual = mt19937.multivariate_normal(mean, cov, size) + actual = legacy.multivariate_normal(mean, cov, size) desired = np.array([[[1.463620246718631, 11.73759122771936], [1.622445133300628, 9.771356667546383]], [[2.154490787682787, 12.170324946056553], @@ -802,7 +810,7 @@ def test_multivariate_normal(self): assert_array_almost_equal(actual, desired, decimal=15) # Check for default size, was raising deprecation warning - actual = mt19937.multivariate_normal(mean, cov) + actual = legacy.multivariate_normal(mean, cov) desired = np.array([0.895289569463708, 9.17180864067987]) assert_array_almost_equal(actual, desired, decimal=15) @@ -820,51 +828,47 @@ def test_multivariate_normal(self): assert_raises(ValueError, mt19937.multivariate_normal, mean, cov, check_valid='raise') - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_negative_binomial(self): - mt19937.seed(self.seed) - actual = mt19937.negative_binomial(n=100, p=.12345, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.negative_binomial(n=100, p=.12345, size=(3, 2)) desired = np.array([[848, 841], [892, 611], [779, 647]]) assert_array_equal(actual, desired) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_noncentral_chisquare(self): - mt19937.seed(self.seed) - actual = mt19937.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) desired = np.array([[23.91905354498517511, 13.35324692733826346], [31.22452661329736401, 16.60047399466177254], [5.03461598262724586, 17.94973089023519464]]) assert_array_almost_equal(actual, desired, decimal=14) - actual = mt19937.noncentral_chisquare(df=.5, nonc=.2, size=(3, 2)) + actual = legacy.noncentral_chisquare(df=.5, nonc=.2, size=(3, 2)) desired = np.array([[1.47145377828516666, 0.15052899268012659], [0.00943803056963588, 1.02647251615666169], [0.332334982684171, 0.15451287602753125]]) assert_array_almost_equal(actual, desired, decimal=14) - mt19937.seed(self.seed) - actual = mt19937.noncentral_chisquare(df=5, nonc=0, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.noncentral_chisquare(df=5, nonc=0, size=(3, 2)) desired = np.array([[9.597154162763948, 11.725484450296079], [10.413711048138335, 3.694475922923986], [13.484222138963087, 14.377255424602957]]) assert_array_almost_equal(actual, desired, decimal=14) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_noncentral_f(self): - mt19937.seed(self.seed) - actual = mt19937.noncentral_f(dfnum=5, dfden=2, nonc=1, - size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.noncentral_f(dfnum=5, dfden=2, nonc=1, + size=(3, 2)) desired = np.array([[1.40598099674926669, 0.34207973179285761], [3.57715069265772545, 7.92632662577829805], [0.43741599463544162, 1.1774208752428319]]) assert_array_almost_equal(actual, desired, decimal=14) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_normal(self): - mt19937.seed(self.seed) - actual = mt19937.normal(loc=.123456789, scale=2.0, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.normal(loc=.123456789, scale=2.0, size=(3, 2)) desired = np.array([[2.80378370443726244, 3.59863924443872163], [3.121433477601256, -0.33382987590723379], [4.18552478636557357, 4.46410668111310471]]) @@ -875,8 +879,8 @@ def test_normal_0(self): assert_raises(ValueError, mt19937.normal, scale=-0.) def test_pareto(self): - mt19937.seed(self.seed) - actual = mt19937.pareto(a=.123456789, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.pareto(a=.123456789, size=(3, 2)) desired = np.array( [[2.46852460439034849e+03, 1.41286880810518346e+03], [5.28287797029485181e+07, 6.57720981047328785e+07], @@ -906,8 +910,8 @@ def test_poisson_exceptions(self): assert_raises(ValueError, mt19937.poisson, [lambig] * 10) def test_power(self): - mt19937.seed(self.seed) - actual = mt19937.power(a=.123456789, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.power(a=.123456789, size=(3, 2)) desired = np.array([[0.02048932883240791, 0.01424192241128213], [0.38446073748535298, 0.39499689943484395], [0.00177699707563439, 0.13115505880863756]]) @@ -925,10 +929,9 @@ def test_rayleigh_0(self): assert_equal(mt19937.rayleigh(scale=0), 0) assert_raises(ValueError, mt19937.rayleigh, scale=-0.) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_cauchy(self): - mt19937.seed(self.seed) - actual = mt19937.standard_cauchy(size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.standard_cauchy(size=(3, 2)) desired = np.array([[0.77127660196445336, -6.55601161955910605], [0.93582023391158309, -2.07479293013759447], [-4.74601644297011926, 0.18338989290760804]]) @@ -942,10 +945,9 @@ def test_standard_exponential(self): [0.6116915921431676, 1.50592546727413201]]) assert_array_almost_equal(actual, desired, decimal=15) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_gamma(self): - mt19937.seed(self.seed) - actual = mt19937.standard_gamma(shape=3, size=(3, 2), method='inv') + legacy.seed(self.seed) + actual = legacy.standard_gamma(shape=3, size=(3, 2)) desired = np.array([[5.50841531318455058, 6.62953470301903103], [5.93988484943779227, 2.31044849402133989], [7.54838614231317084, 8.012756093271868]]) @@ -955,19 +957,17 @@ def test_standard_gamma_0(self): assert_equal(mt19937.standard_gamma(shape=0), 0) assert_raises(ValueError, mt19937.standard_gamma, shape=-0.) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_normal(self): - mt19937.seed(self.seed) - actual = mt19937.standard_normal(size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.standard_normal(size=(3, 2)) desired = np.array([[1.34016345771863121, 1.73759122771936081], [1.498988344300628, -0.2286433324536169], [2.031033998682787, 2.17032494605655257]]) assert_array_almost_equal(actual, desired, decimal=15) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_t(self): - mt19937.seed(self.seed) - actual = mt19937.standard_t(df=10, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.standard_t(df=10, size=(3, 2)) desired = np.array([[0.97140611862659965, -0.08830486548450577], [1.36311143689505321, -0.55317463909867071], [-0.18473749069684214, 0.61181537341755321]]) @@ -1018,7 +1018,8 @@ def __float__(self): raise TypeError throwing_float = np.array(1.0).view(ThrowingFloat) - assert_raises(TypeError, mt19937.uniform, throwing_float, throwing_float) + assert_raises(TypeError, mt19937.uniform, + throwing_float, throwing_float) class ThrowingInteger(np.ndarray): def __int__(self): @@ -1041,18 +1042,17 @@ def test_vonmises_small(self): r = mt19937.vonmises(mu=0., kappa=1.1e-8, size=10 ** 6) assert_(np.isfinite(r).all()) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_wald(self): - mt19937.seed(self.seed) - actual = mt19937.wald(mean=1.23, scale=1.54, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.wald(mean=1.23, scale=1.54, size=(3, 2)) desired = np.array([[3.82935265715889983, 5.13125249184285526], [0.35045403618358717, 1.50832396872003538], [0.24124319895843183, 0.22031101461955038]]) assert_array_almost_equal(actual, desired, decimal=14) def test_weibull(self): - mt19937.seed(self.seed) - actual = mt19937.weibull(a=1.23, size=(3, 2)) + legacy.seed(self.seed) + actual = legacy.weibull(a=1.23, size=(3, 2)) desired = np.array([[0.97097342648766727, 0.91422896443565516], [1.89517770034962929, 1.91414357960479564], [0.67057783752390987, 1.39494046635066793]]) @@ -1079,6 +1079,7 @@ def setup(self): def set_seed(self): random.seed(self.seed) + legacy.seed(self.seed) def test_uniform(self): low = [0] @@ -1096,12 +1097,11 @@ def test_uniform(self): actual = uniform(low, high * 3) assert_array_almost_equal(actual, desired, decimal=14) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_normal(self): loc = [0] scale = [1] bad_scale = [-1] - normal = random.normal + normal = legacy.normal desired = np.array([2.2129019979039612, 2.1283977976520019, 1.8417114045748335]) @@ -1116,13 +1116,12 @@ def test_normal(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc, bad_scale * 3) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_beta(self): a = [1] b = [2] bad_a = [-1] bad_b = [-2] - beta = random.beta + beta = legacy.beta desired = np.array([0.19843558305989056, 0.075230336409423643, 0.24976865978980844]) @@ -1142,7 +1141,7 @@ def test_beta(self): def test_exponential(self): scale = [1] bad_scale = [-1] - exponential = random.exponential + exponential = legacy.exponential desired = np.array([0.76106853658845242, 0.76386282278691653, 0.71243813125891797]) @@ -1152,27 +1151,25 @@ def test_exponential(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, exponential, bad_scale * 3) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_gamma(self): shape = [1] bad_shape = [-1] - std_gamma = random.standard_gamma + std_gamma = legacy.standard_gamma desired = np.array([0.76106853658845242, 0.76386282278691653, 0.71243813125891797]) self.set_seed() - actual = std_gamma(shape * 3, method='inv') + actual = std_gamma(shape * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, std_gamma, bad_shape * 3) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_gamma(self): shape = [1] scale = [2] bad_shape = [-1] bad_scale = [-2] - gamma = random.gamma + gamma = legacy.gamma desired = np.array([1.5221370731769048, 1.5277256455738331, 1.4248762625178359]) @@ -1189,13 +1186,12 @@ def test_gamma(self): assert_raises(ValueError, gamma, bad_shape, scale * 3) assert_raises(ValueError, gamma, shape, bad_scale * 3) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_f(self): dfnum = [1] dfden = [2] bad_dfnum = [-1] bad_dfden = [-2] - f = random.f + f = legacy.f desired = np.array([0.80038951638264799, 0.86768719635363512, 2.7251095168386801]) @@ -1212,7 +1208,6 @@ def test_f(self): assert_raises(ValueError, f, bad_dfnum, dfden * 3) assert_raises(ValueError, f, dfnum, bad_dfden * 3) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_noncentral_f(self): dfnum = [2] dfden = [3] @@ -1220,7 +1215,7 @@ def test_noncentral_f(self): bad_dfnum = [0] bad_dfden = [-1] bad_nonc = [-2] - nonc_f = random.noncentral_f + nonc_f = legacy.noncentral_f desired = np.array([9.1393943263705211, 13.025456344595602, 8.8018098359100545]) @@ -1259,13 +1254,12 @@ def test_chisquare(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, chisquare, bad_df * 3) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_noncentral_chisquare(self): df = [1] nonc = [2] bad_df = [-1] bad_nonc = [-2] - nonc_chi = random.noncentral_chisquare + nonc_chi = legacy.noncentral_chisquare desired = np.array([9.0015599467913763, 4.5804135049718742, 6.0872302432834564]) @@ -1282,11 +1276,10 @@ def test_noncentral_chisquare(self): assert_raises(ValueError, nonc_chi, bad_df, nonc * 3) assert_raises(ValueError, nonc_chi, df, bad_nonc * 3) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_standard_t(self): df = [1] bad_df = [-1] - t = random.standard_t + t = legacy.standard_t desired = np.array([3.0702872575217643, 5.8560725167361607, 1.0274791436474273]) @@ -1318,7 +1311,7 @@ def test_vonmises(self): def test_pareto(self): a = [1] bad_a = [-1] - pareto = random.pareto + pareto = legacy.pareto desired = np.array([1.1405622680198362, 1.1465519762044529, 1.0389564467453547]) @@ -1331,7 +1324,7 @@ def test_pareto(self): def test_weibull(self): a = [1] bad_a = [-1] - weibull = random.weibull + weibull = legacy.weibull desired = np.array([0.76106853658845242, 0.76386282278691653, 0.71243813125891797]) @@ -1344,7 +1337,7 @@ def test_weibull(self): def test_power(self): a = [1] bad_a = [-1] - power = random.power + power = legacy.power desired = np.array([0.53283302478975902, 0.53413660089041659, 0.50955303552646702]) @@ -1411,12 +1404,11 @@ def test_logistic(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, logistic, loc, bad_scale * 3) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_lognormal(self): mean = [0] sigma = [1] bad_sigma = [-1] - lognormal = random.lognormal + lognormal = legacy.lognormal desired = np.array([9.1422086044848427, 8.4013952870126261, 6.3073234116578671]) @@ -1444,13 +1436,12 @@ def test_rayleigh(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, rayleigh, bad_scale * 3) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_wald(self): mean = [0.5] scale = [1] bad_mean = [0] bad_scale = [-2] - wald = random.wald + wald = legacy.wald desired = np.array([0.11873681120271318, 0.12450084820795027, 0.9096122728408238]) @@ -1484,21 +1475,24 @@ def test_triangular(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, triangular, bad_left_one * 3, mode, right) assert_raises(ValueError, triangular, left * 3, bad_mode_one, right) - assert_raises(ValueError, triangular, bad_left_two * 3, bad_mode_two, right) + assert_raises(ValueError, triangular, + bad_left_two * 3, bad_mode_two, right) self.set_seed() actual = triangular(left, mode * 3, right) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, triangular, bad_left_one, mode * 3, right) assert_raises(ValueError, triangular, left, bad_mode_one * 3, right) - assert_raises(ValueError, triangular, bad_left_two, bad_mode_two * 3, right) + assert_raises(ValueError, triangular, bad_left_two, + bad_mode_two * 3, right) self.set_seed() actual = triangular(left, mode, right * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, triangular, bad_left_one, mode, right * 3) assert_raises(ValueError, triangular, left, bad_mode_one, right * 3) - assert_raises(ValueError, triangular, bad_left_two, bad_mode_two, right * 3) + assert_raises(ValueError, triangular, bad_left_two, + bad_mode_two, right * 3) def test_binomial(self): n = [1] @@ -1523,14 +1517,13 @@ def test_binomial(self): assert_raises(ValueError, binom, n, bad_p_one * 3) assert_raises(ValueError, binom, n, bad_p_two * 3) - @pytest.mark.skip(reason='Box-Muller no longer supported') def test_negative_binomial(self): n = [1] p = [0.5] bad_n = [-1] bad_p_one = [-1] bad_p_two = [1.5] - neg_binom = random.negative_binomial + neg_binom = legacy.negative_binomial desired = np.array([1, 0, 1]) self.set_seed() diff --git a/_randomgen/requirements.txt b/_randomgen/requirements.txt index f2f2e06ad0aa..6c3af8ca3a6b 100644 --- a/_randomgen/requirements.txt +++ b/_randomgen/requirements.txt @@ -1,4 +1,4 @@ numpy>=1.10 -cython>=0.24 +cython>=0.26 setuptools wheel \ No newline at end of file diff --git a/_randomgen/setup.py b/_randomgen/setup.py index c010cfc9bff5..219db375e159 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -204,6 +204,16 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), + Extension("randomgen.legacy.legacy", + ["randomgen/legacy/legacy.pyx", + join(MOD_DIR, 'src', 'legacy', + 'distributions-boxmuller.c'), + join(MOD_DIR, 'src', 'distributions', 'distributions.c')], + include_dirs=EXTRA_INCLUDE_DIRS + + [np.get_include()] + [join(MOD_DIR, 'legacy')], + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), ] From 8667564d19df0dbeaf4e4a907e92441ef628684b Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 27 Mar 2018 10:43:21 +0100 Subject: [PATCH 106/279] DOC: Update multithreading doc Update performance comp --- _randomgen/doc/source/multithreading.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/_randomgen/doc/source/multithreading.rst b/_randomgen/doc/source/multithreading.rst index 253764632c77..6efbcdbe76e3 100644 --- a/_randomgen/doc/source/multithreading.rst +++ b/_randomgen/doc/source/multithreading.rst @@ -80,8 +80,9 @@ the time required to generate using a single thread. In [4]: print(mrng.threads) ...: %timeit mrng.fill() + 4 - 42.9 ms ± 2.55 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) + 32.8 ms ± 2.71 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) The single threaded call directly uses the PRNG. @@ -90,7 +91,8 @@ The single threaded call directly uses the PRNG. In [5]: values = np.empty(10000000) ...: rg = Xorshift1024().generator ...: %timeit rg.standard_normal(out=values) - 220 ms ± 27.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) + + 99.6 ms ± 222 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) The gains are substantial and the scaling is reasonable even for large that are only moderately large. The gains are even larger when compared to a call @@ -100,5 +102,5 @@ that does not use an existing array due to array creation overhead. In [6]: rg = Xorshift1024().generator ...: %timeit rg.standard_normal(10000000) - ...: - 256 ms ± 41.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) + + 125 ms ± 309 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) From 788bec33106e7b19ae738014f3e1f80896ff916e Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 27 Mar 2018 10:55:40 +0100 Subject: [PATCH 107/279] CLN: Remove set/get state for system generator Remove ability to set or get the state of the default generator --- _randomgen/randomgen/generator.pyx | 3 --- 1 file changed, 3 deletions(-) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index c9d7659945a6..7c9e1699484f 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -4315,9 +4315,6 @@ standard_exponential = _random_generator.standard_exponential standard_gamma = _random_generator.standard_gamma standard_normal = _random_generator.standard_normal standard_t = _random_generator.standard_t -get_state = lambda: _random_generator.state -def set_state(state): - _random_generator.state = state tomaxint = _random_generator.tomaxint triangular = _random_generator.triangular uniform = _random_generator.uniform From 31a8ead7efc0f9765dd5e6996b1ec9226ad2c95c Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 27 Mar 2018 11:28:34 +0100 Subject: [PATCH 108/279] TST: Fix tailing test on 32bit platofrms Relax check for 32 bit platforms --- _randomgen/randomgen/tests/test_against_numpy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_randomgen/randomgen/tests/test_against_numpy.py b/_randomgen/randomgen/tests/test_against_numpy.py index a7da65d5997b..480e1a2d110c 100644 --- a/_randomgen/randomgen/tests/test_against_numpy.py +++ b/_randomgen/randomgen/tests/test_against_numpy.py @@ -128,7 +128,7 @@ def _is_state_common_legacy(self): assert (state[1] == state2['state']['key']).all() assert (state[2] == state2['state']['pos']) assert (state[3] == state2['has_gauss']) - assert (state[4] == state2['gauss']) + assert_allclose(state[4], state2['gauss'], atol=1e-10) def test_common_seed(self): self.rg.seed(1234) From 3d5f1f304be26a5ac24f4ee629700b53588ba29e Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 27 Mar 2018 16:47:19 +0100 Subject: [PATCH 109/279] BLD: Add conda recipe Add recipe for conda building --- _randomgen/building/randomgen/bld.bat | 2 ++ _randomgen/building/randomgen/build.sh | 4 ++++ _randomgen/building/randomgen/meta.yaml | 24 ++++++++++++++++++++++ _randomgen/building/randomgen/run_test.bat | 2 ++ _randomgen/building/randomgen/run_test.sh | 4 ++++ 5 files changed, 36 insertions(+) create mode 100644 _randomgen/building/randomgen/bld.bat create mode 100644 _randomgen/building/randomgen/build.sh create mode 100644 _randomgen/building/randomgen/meta.yaml create mode 100644 _randomgen/building/randomgen/run_test.bat create mode 100644 _randomgen/building/randomgen/run_test.sh diff --git a/_randomgen/building/randomgen/bld.bat b/_randomgen/building/randomgen/bld.bat new file mode 100644 index 000000000000..b9cd616ce4d9 --- /dev/null +++ b/_randomgen/building/randomgen/bld.bat @@ -0,0 +1,2 @@ +"%PYTHON%" setup.py install --single-version-externally-managed --record=record.txt +if errorlevel 1 exit 1 diff --git a/_randomgen/building/randomgen/build.sh b/_randomgen/building/randomgen/build.sh new file mode 100644 index 000000000000..d36c699059cf --- /dev/null +++ b/_randomgen/building/randomgen/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# Python command to install the script. +$PYTHON setup.py install --single-version-externally-managed --record=record.txt \ No newline at end of file diff --git a/_randomgen/building/randomgen/meta.yaml b/_randomgen/building/randomgen/meta.yaml new file mode 100644 index 000000000000..a6300278b84a --- /dev/null +++ b/_randomgen/building/randomgen/meta.yaml @@ -0,0 +1,24 @@ +package: + name: randomgen + version: v1.14.2 +source: + version: v1.14.2 + git_url: 'https://github.com/bashtage/randomgen.git' +build: + number: 0 +requirements: + build: + - python + - setuptools + - cython + - 'numpy x.x' + run: + - python + - 'numpy x.x' +test: + requires: + - pytest + - nose +about: + home: 'https://github.com/bashtage/randomgen' + license: NSCA diff --git a/_randomgen/building/randomgen/run_test.bat b/_randomgen/building/randomgen/run_test.bat new file mode 100644 index 000000000000..09a6f600c729 --- /dev/null +++ b/_randomgen/building/randomgen/run_test.bat @@ -0,0 +1,2 @@ +set NUMBER_OF_PROCESSORS=1 +pytest -v --pyargs randomgen diff --git a/_randomgen/building/randomgen/run_test.sh b/_randomgen/building/randomgen/run_test.sh new file mode 100644 index 000000000000..ad59a2bff8e6 --- /dev/null +++ b/_randomgen/building/randomgen/run_test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +export QT_QPA_PLATFORM=offscreen +pytest -v --pyargs randomgen From 27a27ca054d38d14ee3053ffd6c9b9bd8627c2a5 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 27 Mar 2018 21:59:08 +0100 Subject: [PATCH 110/279] ENH: Add integrated legacy generator Use composition to produce a single class legacy generator --- _randomgen/doc/source/legacy.rst | 51 ++++++--- .../legacy/{legacy.pyx => _legacy.pyx} | 24 ++-- _randomgen/randomgen/legacy/legacy.py | 84 ++++++++++++++ _randomgen/randomgen/pickle.py | 103 +++++++++++++----- _randomgen/setup.py | 4 +- 5 files changed, 210 insertions(+), 56 deletions(-) rename _randomgen/randomgen/legacy/{legacy.pyx => _legacy.pyx} (99%) create mode 100644 _randomgen/randomgen/legacy/legacy.py diff --git a/_randomgen/doc/source/legacy.rst b/_randomgen/doc/source/legacy.rst index 8a73f9029c92..780611b849fc 100644 --- a/_randomgen/doc/source/legacy.rst +++ b/_randomgen/doc/source/legacy.rst @@ -1,7 +1,7 @@ Legacy Random Generation ------------------------ The :class:`~randomgen.legacy.LegacyGenerator` provides access to -some legacy generators. These all depend on Box-Muller normals or +legacy generators. These all depend on Box-Muller normals or inverse CDF exponentials or gammas. This class should only be used if it is essential to have randoms that are identical to what would have been produced by NumPy. @@ -12,28 +12,14 @@ are produced in pairs. It is important to use :attr:`~randomgen.legacy.LegacyGenerator.state` when accessing the state so that these extra values are saved. -.. warning:: - - :class:`~randomgen.legacy.LegacyGenerator` only contains functions - that have changed. Since it does not contain other functions, it - is not direclty possible to replace :class:`~numpy.random.RandomState`. - In order to full replace :class:`~numpy.random.RandomState`, it is - necessary to use both :class:`~randomgen.legacy.LegacyGenerator` - and :class:`~randomgen.generator.RandomGenerator` both driven - by the same basic RNG. Methods present in :class:`~randomgen.legacy.LegacyGenerator` - must be called from :class:`~randomgen.legacy.LegacyGenerator`. Other Methods - should be called from :class:`~randomgen.generator.RandomGenerator`. - - .. code-block:: python - from randomgen import RandomGenerator, MT19937 + from randomgen import MT19937 from randomgen.legacy import LegacyGenerator from numpy.random import RandomState # Use same seed rs = RandomState(12345) mt19937 = MT19937(12345) - rg = RandomGenerator(mt19937) lg = LegacyGenerator(mt19937) # Identical output @@ -41,7 +27,7 @@ when accessing the state so that these extra values are saved. lg.standard_normal() rs.random_sample() - rg.random_sample() + lg.random_sample() rs.standard_exponential() lg.standard_exponential() @@ -65,7 +51,23 @@ Simple random data .. autosummary:: :toctree: generated/ + ~LegacyGenerator.rand ~LegacyGenerator.randn + ~LegacyGenerator.randint + ~LegacyGenerator.random_integers + ~LegacyGenerator.random_sample + ~LegacyGenerator.choice + ~LegacyGenerator.bytes + ~LegacyGenerator.random_uintegers + ~LegacyGenerator.random_raw + +Permutations +============ +.. autosummary:: + :toctree: generated/ + + ~LegacyGenerator.shuffle + ~LegacyGenerator.permutation Distributions ============= @@ -73,23 +75,38 @@ Distributions :toctree: generated/ ~LegacyGenerator.beta + ~LegacyGenerator.binomial ~LegacyGenerator.chisquare + ~LegacyGenerator.complex_normal ~LegacyGenerator.dirichlet ~LegacyGenerator.exponential ~LegacyGenerator.f ~LegacyGenerator.gamma + ~LegacyGenerator.geometric + ~LegacyGenerator.gumbel + ~LegacyGenerator.hypergeometric + ~LegacyGenerator.laplace + ~LegacyGenerator.logistic ~LegacyGenerator.lognormal + ~LegacyGenerator.logseries + ~LegacyGenerator.multinomial ~LegacyGenerator.multivariate_normal ~LegacyGenerator.negative_binomial ~LegacyGenerator.noncentral_chisquare ~LegacyGenerator.noncentral_f ~LegacyGenerator.normal ~LegacyGenerator.pareto + ~LegacyGenerator.poisson ~LegacyGenerator.power + ~LegacyGenerator.rayleigh ~LegacyGenerator.standard_cauchy ~LegacyGenerator.standard_exponential ~LegacyGenerator.standard_gamma ~LegacyGenerator.standard_normal ~LegacyGenerator.standard_t + ~LegacyGenerator.triangular + ~LegacyGenerator.uniform + ~LegacyGenerator.vonmises ~LegacyGenerator.wald ~LegacyGenerator.weibull + ~LegacyGenerator.zipf \ No newline at end of file diff --git a/_randomgen/randomgen/legacy/legacy.pyx b/_randomgen/randomgen/legacy/_legacy.pyx similarity index 99% rename from _randomgen/randomgen/legacy/legacy.pyx rename to _randomgen/randomgen/legacy/_legacy.pyx index 0a5a67bcf867..11e9cb50cdf4 100644 --- a/_randomgen/randomgen/legacy/legacy.pyx +++ b/_randomgen/randomgen/legacy/_legacy.pyx @@ -22,23 +22,23 @@ import randomgen.pickle np.import_array() -cdef class LegacyGenerator: +cdef class _LegacyGenerator: """ - LegacyGenerator(brng=None) + _LegacyGenerator(brng=None) Container providing legacy generators. - ``LegacyGenerator`` exposes a number of methods for generating random + ``_LegacyGenerator`` exposes a number of methods for generating random numbers for a set of distributions where the method used to produce random - samples has changed. Three core generators have changed: normals, exponentials - and gammas. These have been replaced by fster Ziggurat-based methds in - ``RadnomGenerator``. ``LegacyGenerator`` retains the slower methods + samples has changed. Three core generators have changed: normal, exponential + and gamma. These have been replaced by faster Ziggurat-based methods in + ``RadnomGenerator``. ``_LegacyGenerator`` retains the slower methods to produce samples from these distributions as well as from distributions that depend on these such as the Chi-square, power or Weibull. **No Compatibility Guarantee** - ``LegacyGenerator`` is evolving and so it isn't possible to provide a + ``_LegacyGenerator`` is evolving and so it isn't possible to provide a compatibility guarantee like NumPy does. In particular, better algorithms have already been added. This will change once ``RandomGenerator`` stabilizes. @@ -53,15 +53,15 @@ cdef class LegacyGenerator: Examples -------- Exactly reproducing a NumPy stream requires both a ``RandomGenerator`` - and a ``LegacyGenerator``. These must share a common ``MT19937`` basic + and a ``_LegacyGenerator``. These must share a common ``MT19937`` basic RNG. Functions that are available in LegacyGenerator must be called - from ``LegacyGenerator``, and other functions must be called from + from ``_LegacyGenerator``, and other functions must be called from ``RandomGenerator``. >>> from randomgen import RandomGenerator, MT19937 - >>> from randomgen.legacy import LegacyGenerator + >>> from randomgen.legacy._legacy import _LegacyGenerator >>> mt = MT19937(12345) - >>> lg = LegacyGenerator(mt) + >>> lg = _LegacyGenerator(mt) >>> rg = RandomGenerator(mt) >>> x = lg.standard_normal(10) >>> rg.shuffle(x) @@ -118,7 +118,7 @@ cdef class LegacyGenerator: self.state = state def __reduce__(self): - return (randomgen.pickle.__generator_ctor, + return (randomgen.pickle.__legacy_ctor, (self.state['brng'],), self.state) diff --git a/_randomgen/randomgen/legacy/legacy.py b/_randomgen/randomgen/legacy/legacy.py new file mode 100644 index 000000000000..2b036528d59d --- /dev/null +++ b/_randomgen/randomgen/legacy/legacy.py @@ -0,0 +1,84 @@ +from randomgen.generator import RandomGenerator +from randomgen.mt19937 import MT19937 +from randomgen.legacy._legacy import _LegacyGenerator +import randomgen.pickle + + +class LegacyGenerator(RandomGenerator): + """ + LegacyGenerator(brng=None) + + Container providing legacy generators. + + ``LegacyGenerator`` exposes a number of methods for generating random + numbers for a set of distributions where the method used to produce random + samples has changed. Three core generators have changed: normal, exponential + and gamma. These have been replaced by faster Ziggurat-based methods in + ``RadnomGenerator``. ``LegacyGenerator`` retains the slower methods + to produce samples from these distributions as well as from distributions + that depend on these such as the Chi-square, power or Weibull. + + **No Compatibility Guarantee** + + ``LegacyGenerator`` is evolving and so it isn't possible to provide a + compatibility guarantee like NumPy does. In particular, better algorithms + have already been added. This will change once ``RandomGenerator`` + stabilizes. + + Parameters + ---------- + brng : Basic RNG, optional + Basic RNG to use as the core generator. If none is provided, uses + MT19937. + + + Examples + -------- + Exactly reproducing a NumPy stream requires using ``MT19937`` as + the Basic RNG. + + >>> from randomgen import MT19937 + >>> lg = LegacyGenerator(MT19937(12345)) + >>> x = lg.standard_normal(10) + >>> lg.shuffle(x) + >>> x[0] + 0.09290787674371767 + >>> lg.standard_exponential() + 1.6465621229906502 + + The equivalent commands from NumPy produce identical output. + + >>> from numpy.random import RandomState + >>> rs = RandomState(12345) + >>> x = rs.standard_normal(10) + >>> rs.shuffle(x) + >>> x[0] + 0.09290787674371767 + >>> rs.standard_exponential() + 1.6465621229906502 + """ + _LEGACY_ATTRIBUTES = tuple(a for a in dir( + _LegacyGenerator) if not a.startswith('_')) + + def __init__(self, brng=None): + if brng is None: + brng = MT19937() + super(LegacyGenerator, self).__init__(brng) + self.__legacy = _LegacyGenerator(brng) + + def __getattribute__(self, name): + if name in LegacyGenerator._LEGACY_ATTRIBUTES: + return self.__legacy.__getattribute__(name) + return object.__getattribute__(self, name) + + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (randomgen.pickle._experiment_ctor, + (self.state['brng'],), + self.state) diff --git a/_randomgen/randomgen/pickle.py b/_randomgen/randomgen/pickle.py index dbb5324e40dc..ca6f9cd4c83d 100644 --- a/_randomgen/randomgen/pickle.py +++ b/_randomgen/randomgen/pickle.py @@ -1,23 +1,24 @@ from .generator import RandomGenerator from .dsfmt import DSFMT from .mt19937 import MT19937 -from .pcg32 import PCG32 -from .pcg64 import PCG64 -from .philox import Philox -from .threefry import ThreeFry -from .threefry32 import ThreeFry32 -from .xoroshiro128 import Xoroshiro128 -from .xorshift1024 import Xorshift1024 - -PRNGS = {'MT19937': MT19937, - 'DSFMT': DSFMT, - 'PCG32': PCG32, - 'PCG64': PCG64, - 'Philox': Philox, - 'ThreeFry': ThreeFry, - 'ThreeFry32': ThreeFry32, - 'Xorshift1024': Xorshift1024, - 'Xoroshiro128': Xoroshiro128} +from randomgen.pcg32 import PCG32 +from randomgen.pcg64 import PCG64 +from randomgen.philox import Philox +from randomgen.threefry import ThreeFry +from randomgen.threefry32 import ThreeFry32 +from randomgen.xoroshiro128 import Xoroshiro128 +from randomgen.xorshift1024 import Xorshift1024 +from randomgen.legacy import LegacyGenerator + +BasicRNGS = {'MT19937': MT19937, + 'DSFMT': DSFMT, + 'PCG32': PCG32, + 'PCG64': PCG64, + 'Philox': Philox, + 'ThreeFry': ThreeFry, + 'ThreeFry32': ThreeFry32, + 'Xorshift1024': Xorshift1024, + 'Xoroshiro128': Xoroshiro128} def __generator_ctor(brng_name='mt19937'): @@ -27,21 +28,21 @@ def __generator_ctor(brng_name='mt19937'): Parameters ---------- brng_name: str - String containing the core PRNG + String containing the core BasicRNG Returns ------- rg: RandomGenerator - RandomGenerator using the named core PRNG + RandomGenerator using the named core BasicRNG """ try: brng_name = brng_name.decode('ascii') except AttributeError: pass - if brng_name in PRNGS: - brng = PRNGS[brng_name] + if brng_name in BasicRNGS: + brng = BasicRNGS[brng_name] else: - raise ValueError(str(brng_name) + ' is not a known PRNG module.') + raise ValueError(str(brng_name) + ' is not a known BasicRNG module.') return RandomGenerator(brng()) @@ -64,9 +65,61 @@ def __brng_ctor(brng_name='mt19937'): brng_name = brng_name.decode('ascii') except AttributeError: pass - if brng_name in PRNGS: - brng = PRNGS[brng_name] + if brng_name in BasicRNGS: + brng = BasicRNGS[brng_name] else: - raise ValueError(str(brng_name) + ' is not a known PRNG module.') + raise ValueError(str(brng_name) + ' is not a known BasicRNG module.') return brng() + + +def __legacy_ctor(brng_name='mt19937'): + """ + Pickling helper function that returns a LegacyGenerator object + + Parameters + ---------- + brng_name: str + String containing the core BasicRNG + + Returns + ------- + lg: LegacyGenerator + LegacyGenerator using the named core BasicRNG + """ + try: + brng_name = brng_name.decode('ascii') + except AttributeError: + pass + if brng_name in BasicRNGS: + brng = BasicRNGS[brng_name] + else: + raise ValueError(str(brng_name) + ' is not a known BasicRNG module.') + + return LegacyGenerator(brng()) + + +def _experiment_ctor(brng_name='mt19937'): + """ + Pickling helper function that returns a LegacyGenerator object + + Parameters + ---------- + brng_name: str + String containing the name of the Basic RNG + + Returns + ------- + brng: BasicRNG + Basic RNG instance + """ + try: + brng_name = brng_name.decode('ascii') + except AttributeError: + pass + if brng_name in BasicRNGS: + brng = BasicRNGS[brng_name] + else: + raise ValueError(str(brng_name) + ' is not a known BasicRNG module.') + + return LegacyGenerator(brng()) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 219db375e159..c7f193d19734 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -204,8 +204,8 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), - Extension("randomgen.legacy.legacy", - ["randomgen/legacy/legacy.pyx", + Extension("randomgen.legacy._legacy", + ["randomgen/legacy/_legacy.pyx", join(MOD_DIR, 'src', 'legacy', 'distributions-boxmuller.c'), join(MOD_DIR, 'src', 'distributions', 'distributions.c')], From f452fbe45781bf46b2cead36aac1561a2f1ff981 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 28 Mar 2018 12:47:53 +0100 Subject: [PATCH 111/279] CLN: Remove conda recipe Move conda recipr to randomgen-wheels --- _randomgen/building/randomgen/bld.bat | 2 -- _randomgen/building/randomgen/build.sh | 4 ---- _randomgen/building/randomgen/meta.yaml | 24 ---------------------- _randomgen/building/randomgen/run_test.bat | 2 -- _randomgen/building/randomgen/run_test.sh | 4 ---- 5 files changed, 36 deletions(-) delete mode 100644 _randomgen/building/randomgen/bld.bat delete mode 100644 _randomgen/building/randomgen/build.sh delete mode 100644 _randomgen/building/randomgen/meta.yaml delete mode 100644 _randomgen/building/randomgen/run_test.bat delete mode 100644 _randomgen/building/randomgen/run_test.sh diff --git a/_randomgen/building/randomgen/bld.bat b/_randomgen/building/randomgen/bld.bat deleted file mode 100644 index b9cd616ce4d9..000000000000 --- a/_randomgen/building/randomgen/bld.bat +++ /dev/null @@ -1,2 +0,0 @@ -"%PYTHON%" setup.py install --single-version-externally-managed --record=record.txt -if errorlevel 1 exit 1 diff --git a/_randomgen/building/randomgen/build.sh b/_randomgen/building/randomgen/build.sh deleted file mode 100644 index d36c699059cf..000000000000 --- a/_randomgen/building/randomgen/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -# Python command to install the script. -$PYTHON setup.py install --single-version-externally-managed --record=record.txt \ No newline at end of file diff --git a/_randomgen/building/randomgen/meta.yaml b/_randomgen/building/randomgen/meta.yaml deleted file mode 100644 index a6300278b84a..000000000000 --- a/_randomgen/building/randomgen/meta.yaml +++ /dev/null @@ -1,24 +0,0 @@ -package: - name: randomgen - version: v1.14.2 -source: - version: v1.14.2 - git_url: 'https://github.com/bashtage/randomgen.git' -build: - number: 0 -requirements: - build: - - python - - setuptools - - cython - - 'numpy x.x' - run: - - python - - 'numpy x.x' -test: - requires: - - pytest - - nose -about: - home: 'https://github.com/bashtage/randomgen' - license: NSCA diff --git a/_randomgen/building/randomgen/run_test.bat b/_randomgen/building/randomgen/run_test.bat deleted file mode 100644 index 09a6f600c729..000000000000 --- a/_randomgen/building/randomgen/run_test.bat +++ /dev/null @@ -1,2 +0,0 @@ -set NUMBER_OF_PROCESSORS=1 -pytest -v --pyargs randomgen diff --git a/_randomgen/building/randomgen/run_test.sh b/_randomgen/building/randomgen/run_test.sh deleted file mode 100644 index ad59a2bff8e6..000000000000 --- a/_randomgen/building/randomgen/run_test.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -export QT_QPA_PLATFORM=offscreen -pytest -v --pyargs randomgen From c4ab63eb963241ff3c47d4b2e85e3f1b1c7709ce Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 28 Mar 2018 13:01:00 +0100 Subject: [PATCH 112/279] CLN: Fix str for RandomGenerator Update __str__ to use class name to solve oop naming issue in LegacyGen --- _randomgen/randomgen/generator.pyx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 7c9e1699484f..724ebdcdb33f 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -114,7 +114,9 @@ cdef class RandomGenerator: return self.__str__() + ' at 0x{:X}'.format(id(self)) def __str__(self): - return 'RandomGenerator(' + self._basicrng.__class__.__name__ + ')' + _str = self.__class__.__name__ + _str += '(' + self._basicrng.__class__.__name__ + ')' + return _str # Pickling support: def __getstate__(self): From 3fd4b600d56c99f96ad36794bc4e72ee477a274b Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 28 Mar 2018 21:19:59 +0100 Subject: [PATCH 113/279] DOC: Update legacy docs Update documentation about legacy generation --- _randomgen/README.md | 9 ++++--- _randomgen/README.rst | 15 ++++++----- _randomgen/doc/source/generator.rst | 8 ++++++ _randomgen/doc/source/index.rst | 11 +++++--- _randomgen/doc/source/legacy.rst | 2 +- _randomgen/doc/source/new-or-different.rst | 9 ++++--- _randomgen/randomgen/generator.pyx | 29 ++++++++++++++++++++++ 7 files changed, 66 insertions(+), 17 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index e1fe7cbd4df0..fbcc1f6d25bc 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -10,11 +10,14 @@ NumPy RandomState evolution. This is a library and generic interface for alternative random generators in Python and NumPy. -### Compatibility Warning -RandomGen no longer supports Box-Muller normal variates and so it not +## Compatibility Warning + +`RandomGenerator` does notsupports Box-Muller normal variates and so it not 100% compatible with NumPy (or randomstate). Box-Muller normals are slow to generate and all functions which previously relied on Box-Muller -normals now use the faster Ziggurat implementation. +normals now use the faster Ziggurat implementation. If you require backward +compatibility, a legacy generator, ``LegacyGenerator``, has been created +which can fully reproduce the sequence produced by NumPy. ## Features diff --git a/_randomgen/README.rst b/_randomgen/README.rst index e37a7193cf64..587d73f82231 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -10,12 +10,15 @@ This is a library and generic interface for alternative random generators in Python and NumPy. Compatibility Warning -~~~~~~~~~~~~~~~~~~~~~ - -RandomGen no longer supports Box-Muller normal variates and so it not -100% compatible with NumPy (or randomstate). Box-Muller normals are slow -to generate and all functions which previously relied on Box-Muller -normals now use the faster Ziggurat implementation. +--------------------- + +``RandomGenerator`` does notsupports Box-Muller normal variates and so +it not 100% compatible with NumPy (or randomstate). Box-Muller normals +are slow to generate and all functions which previously relied on +Box-Muller normals now use the faster Ziggurat implementation. If you +require backward compatibility, a legacy generator, ``LegacyGenerator``, +has been created which can fully reproduce the sequence produced by +NumPy. Features -------- diff --git a/_randomgen/doc/source/generator.rst b/_randomgen/doc/source/generator.rst index 2fedc8f58b72..4e8e46718d7c 100644 --- a/_randomgen/doc/source/generator.rst +++ b/_randomgen/doc/source/generator.rst @@ -17,6 +17,14 @@ changed by passing an instantized basic RNG to .. autoclass:: RandomGenerator +Seed and State Manipulation +================== +.. autosummary:: + :toctree: generated/ + + ~RandomGenerator.seed + ~RandomGenerator.state + Simple random data ================== .. autosummary:: diff --git a/_randomgen/doc/source/index.rst b/_randomgen/doc/source/index.rst index c0b55f5cb215..0885666c8826 100644 --- a/_randomgen/doc/source/index.rst +++ b/_randomgen/doc/source/index.rst @@ -92,11 +92,14 @@ What's New or Different ~~~~~~~~~~~~~~~~~~~~~~~ .. warning:: - The Box-Muller method used to produce NumPy's normals is no longer available. - It is not possible to exactly reproduce the random values produced from NumPy + The Box-Muller method used to produce NumPy's normals is no longer available + in :class:`~randomgen.generator.RandomGenerator`. It is not possible to + reproduce the random values using :class:`~randomgen.generator.RandomGenerator` for the normal distribution or any other distribution that relies on the - normal such as the gamma or student's t. - + normal such as the gamma or student's t. If you require backward compatibility, a + legacy generator, :class:`~randomgen.legacy.LegacyGenerator`, has been created + which can fully reproduce the sequence produced by NumPy. + * The normal, exponential and gamma generators use 256-step Ziggurat methods which are 2-10 times faster than NumPy's Box-Muller or inverse CDF implementations. diff --git a/_randomgen/doc/source/legacy.rst b/_randomgen/doc/source/legacy.rst index 780611b849fc..a0ee90d4f2b5 100644 --- a/_randomgen/doc/source/legacy.rst +++ b/_randomgen/doc/source/legacy.rst @@ -33,7 +33,7 @@ when accessing the state so that these extra values are saved. lg.standard_exponential() -.. currentmodule:: randomgen.legacy +.. currentmodule:: randomgen.legacy.legacy .. autoclass:: LegacyGenerator diff --git a/_randomgen/doc/source/new-or-different.rst b/_randomgen/doc/source/new-or-different.rst index fdff589461e5..c94d95c7c094 100644 --- a/_randomgen/doc/source/new-or-different.rst +++ b/_randomgen/doc/source/new-or-different.rst @@ -5,10 +5,13 @@ What's New or Different .. warning:: - The Box-Muller method used to produce NumPy's normals is no longer available. - It is not possible to exactly reproduce the random values produced from NumPy + The Box-Muller method used to produce NumPy's normals is no longer available + in :class:`~randomgen.generator.RandomGenerator`. It is not possible to + reproduce the random values using :class:`~randomgen.generator.RandomGenerator` for the normal distribution or any other distribution that relies on the - normal such as the gamma or student's t. + normal such as the gamma or student's t. If you require backward compatibility, a + legacy generator, :class:`~randomgen.legacy.LegacyGenerator`, has been created + which can fully reproduce the sequence produced by NumPy. * :func:`~randomgen.entropy.random_entropy` provides access to the system diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 724ebdcdb33f..773f34d61bfc 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -135,6 +135,30 @@ cdef class RandomGenerator: Reseed the basic RNG. Parameters depend on the basic RNG used. + + Notes + ----- + Arguments are directly passed to the basic RNG. This is a convenience + function. + + The best method to access seed is to directly use a basic RNG instance. + This example demonstrates this best practice. + + >>> from randomgen import RandomGenerator, PCG64 + >>> brng = PCG64(1234567891011) + >>> rg = brng.generator + >>> brng.seed(1110987654321) + + The method used to create the generator is not important. + + >>> brng = PCG64(1234567891011) + >>> rg = RandomGenerator(brng) + >>> brng.seed(1110987654321) + + These best practice examples are equivalent to + + >>> rg = RandomGenerator(PCG64(1234567891011)) + >>> rg.seed(1110987654321) """ # TODO: Should this remain self._basicrng.seed(*args, **kwargs) @@ -150,6 +174,11 @@ cdef class RandomGenerator: state : dict Dictionary containing the information required to describe the state of the Basic RNG + + Notes + ----- + This is a trivial pass-through function. RandomGenerator does not + directly contain or manipulate the basic RNG's state. """ return self._basicrng.state From dcdf421ffdf7e4a34da08fcac7b7a3d14e1707a6 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 28 Mar 2018 22:54:18 +0100 Subject: [PATCH 114/279] BUG: Fix pickle for LegacyGenerator Ensure LG pickles correctly --- _randomgen/doc/source/generator.rst | 2 +- _randomgen/randomgen/legacy/_legacy.pyx | 29 ++++++++++++++- _randomgen/randomgen/legacy/legacy.py | 37 +++++++++++++++++-- .../randomgen/tests/test_against_numpy.py | 1 - _randomgen/randomgen/tests/test_legacy.py | 12 ++++++ 5 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 _randomgen/randomgen/tests/test_legacy.py diff --git a/_randomgen/doc/source/generator.rst b/_randomgen/doc/source/generator.rst index 4e8e46718d7c..dba51eb6d00f 100644 --- a/_randomgen/doc/source/generator.rst +++ b/_randomgen/doc/source/generator.rst @@ -18,7 +18,7 @@ changed by passing an instantized basic RNG to RandomGenerator Seed and State Manipulation -================== +=========================== .. autosummary:: :toctree: generated/ diff --git a/_randomgen/randomgen/legacy/_legacy.pyx b/_randomgen/randomgen/legacy/_legacy.pyx index 11e9cb50cdf4..aa59d3c8e785 100644 --- a/_randomgen/randomgen/legacy/_legacy.pyx +++ b/_randomgen/randomgen/legacy/_legacy.pyx @@ -108,7 +108,7 @@ cdef class _LegacyGenerator: return self.__str__() + ' at 0x{:X}'.format(id(self)) def __str__(self): - return 'RandomGenerator(' + self._basicrng.__class__.__name__ + ')' + return self.__class__.__name__ + '(' + self._basicrng.__class__.__name__ + ')' # Pickling support: def __getstate__(self): @@ -131,7 +131,33 @@ cdef class _LegacyGenerator: Reseed the basic RNG. Parameters depend on the basic RNG used. + + Notes + ----- + Arguments are directly passed to the basic RNG. This is a convenience + function. + + The best method to access seed is to directly use a basic RNG instance. + This example demonstrates this best practice. + + >>> from randomgen import MT19937 + >>> from randomgen.legacy import LegacyGenerator + >>> brng = MT19937(123456789) + >>> lg = brng.generator + >>> brng.seed(987654321) + + The method used to create the generator is not important. + + >>> brng = MT19937(123456789) + >>> lg = LegacyGenerator(brng) + >>> brng.seed(987654321) + + These best practice examples are equivalent to + + >>> lg = LegacyGenerator(MT19937(123456789)) + >>> lg.seed(987654321) """ + # TODO: Should this remain self._basicrng.seed(*args, **kwargs) self._reset_gauss() @@ -168,7 +194,6 @@ cdef class _LegacyGenerator: st['has_gauss'] = value[3] st['gauss'] = value[4] value = st - self._aug_state.gauss = value.get('gauss', 0.0) self._aug_state.has_gauss = value.get('has_gauss', 0) self._basicrng.state = value diff --git a/_randomgen/randomgen/legacy/legacy.py b/_randomgen/randomgen/legacy/legacy.py index 2b036528d59d..e1b04b12bee7 100644 --- a/_randomgen/randomgen/legacy/legacy.py +++ b/_randomgen/randomgen/legacy/legacy.py @@ -4,7 +4,38 @@ import randomgen.pickle -class LegacyGenerator(RandomGenerator): +_LEGACY_ATTRIBUTES = tuple(a for a in dir( + _LegacyGenerator) if not a.startswith('_')) + +_LEGACY_ATTRIBUTES += ('__getstate__', '__setstate__', '__reduce__') + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + + # From six, https://raw.githubusercontent.com/benjaminp/six + class metaclass(type): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +class LegacyGeneratorType(type): + def __getattribute__(self, name): + if name in _LEGACY_ATTRIBUTES: + return object.__getattribute__(_LegacyGenerator, name) + return object.__getattribute__(RandomGenerator, name) + + +class LegacyGenerator(with_metaclass(LegacyGeneratorType, RandomGenerator)): """ LegacyGenerator(brng=None) @@ -57,8 +88,6 @@ class LegacyGenerator(RandomGenerator): >>> rs.standard_exponential() 1.6465621229906502 """ - _LEGACY_ATTRIBUTES = tuple(a for a in dir( - _LegacyGenerator) if not a.startswith('_')) def __init__(self, brng=None): if brng is None: @@ -67,7 +96,7 @@ def __init__(self, brng=None): self.__legacy = _LegacyGenerator(brng) def __getattribute__(self, name): - if name in LegacyGenerator._LEGACY_ATTRIBUTES: + if name in _LEGACY_ATTRIBUTES: return self.__legacy.__getattribute__(name) return object.__getattribute__(self, name) diff --git a/_randomgen/randomgen/tests/test_against_numpy.py b/_randomgen/randomgen/tests/test_against_numpy.py index 480e1a2d110c..cce6228a33d7 100644 --- a/_randomgen/randomgen/tests/test_against_numpy.py +++ b/_randomgen/randomgen/tests/test_against_numpy.py @@ -408,7 +408,6 @@ def test_dir(self): 'print_function', 'RandomState'] mod += known_exlcuded diff = set(npmod).difference(mod) - print(diff) assert_equal(len(diff), 0) # Tests using legacy generator diff --git a/_randomgen/randomgen/tests/test_legacy.py b/_randomgen/randomgen/tests/test_legacy.py new file mode 100644 index 000000000000..e45ba3619796 --- /dev/null +++ b/_randomgen/randomgen/tests/test_legacy.py @@ -0,0 +1,12 @@ +import pickle + +from randomgen.legacy import LegacyGenerator + + +def test_pickle(): + lg = LegacyGenerator() + lg.random_sample(100) + lg.standard_normal() + lg2 = pickle.loads(pickle.dumps(lg)) + assert lg.standard_normal() == lg2.standard_normal() + assert lg.random_sample() == lg2.random_sample() From 91a6bbcb696018324f30770affa5e8ab216c4447 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 28 Mar 2018 23:52:41 +0100 Subject: [PATCH 115/279] TST: Make test more verbose Test occasionally fails on Windows --- _randomgen/randomgen/tests/test_numpy_mt19937.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index c22aa35808f7..468a6232e290 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -56,7 +56,8 @@ def test_n_zero(self): # This test addresses issue #3480. zeros = np.zeros(2, dtype='int') for p in [0, .5, 1]: - assert_(random.binomial(0, p) == 0) + val = random.binomial(0, p) + assert val == 0 assert_array_equal(random.binomial(zeros, p), zeros) def test_p_is_nan(self): From b62875afc9ee8ba3784e101223599ad53d493e52 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 2 Apr 2018 00:06:12 +0100 Subject: [PATCH 116/279] CLN: Add absolute_import to avoid noise Add absolute_import to avoid noise when importing --- _randomgen/randomgen/bounded_integers.pyx.in | 1 + _randomgen/randomgen/common.pyx | 1 + _randomgen/randomgen/dsfmt.pyx | 2 ++ _randomgen/randomgen/entropy.pyx | 2 ++ _randomgen/randomgen/generator.pyx | 2 ++ _randomgen/randomgen/legacy/_legacy.pyx | 2 ++ _randomgen/randomgen/mt19937.pyx | 2 ++ _randomgen/randomgen/pcg32.pyx | 2 ++ _randomgen/randomgen/pcg64.pyx | 2 ++ _randomgen/randomgen/philox.pyx | 2 ++ _randomgen/randomgen/threefry.pyx | 2 ++ _randomgen/randomgen/threefry32.pyx | 2 ++ _randomgen/randomgen/xoroshiro128.pyx | 2 ++ _randomgen/randomgen/xorshift1024.pyx | 2 ++ 14 files changed, 26 insertions(+) diff --git a/_randomgen/randomgen/bounded_integers.pyx.in b/_randomgen/randomgen/bounded_integers.pyx.in index ff4885130cf8..adeaa70059aa 100644 --- a/_randomgen/randomgen/bounded_integers.pyx.in +++ b/_randomgen/randomgen/bounded_integers.pyx.in @@ -1,5 +1,6 @@ #!python #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True +from __future__ import absolute_import import numpy as np cimport numpy as np diff --git a/_randomgen/randomgen/common.pyx b/_randomgen/randomgen/common.pyx index 6189ba19920b..e627d798363b 100644 --- a/_randomgen/randomgen/common.pyx +++ b/_randomgen/randomgen/common.pyx @@ -1,5 +1,6 @@ #!python #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True +from __future__ import absolute_import from collections import namedtuple from cpython cimport PyFloat_AsDouble diff --git a/_randomgen/randomgen/dsfmt.pyx b/_randomgen/randomgen/dsfmt.pyx index fa70b4ef52b4..5fcd3fccd043 100644 --- a/_randomgen/randomgen/dsfmt.pyx +++ b/_randomgen/randomgen/dsfmt.pyx @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import operator from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New diff --git a/_randomgen/randomgen/entropy.pyx b/_randomgen/randomgen/entropy.pyx index bb1c14b4b32d..2c85066c1d9d 100644 --- a/_randomgen/randomgen/entropy.pyx +++ b/_randomgen/randomgen/entropy.pyx @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import operator cimport numpy as np diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 773f34d61bfc..abc352eced05 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -1,5 +1,7 @@ #!python #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True +from __future__ import absolute_import + import operator import warnings diff --git a/_randomgen/randomgen/legacy/_legacy.pyx b/_randomgen/randomgen/legacy/_legacy.pyx index aa59d3c8e785..af1a6b417d68 100644 --- a/_randomgen/randomgen/legacy/_legacy.pyx +++ b/_randomgen/randomgen/legacy/_legacy.pyx @@ -1,5 +1,7 @@ #!python #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True +from __future__ import absolute_import + import warnings import operator diff --git a/_randomgen/randomgen/mt19937.pyx b/_randomgen/randomgen/mt19937.pyx index e05a78e481ff..18caeb9ac4fd 100644 --- a/_randomgen/randomgen/mt19937.pyx +++ b/_randomgen/randomgen/mt19937.pyx @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import operator from libc.stdlib cimport malloc, free diff --git a/_randomgen/randomgen/pcg32.pyx b/_randomgen/randomgen/pcg32.pyx index 5043db8c66a4..2479cd66eb22 100644 --- a/_randomgen/randomgen/pcg32.pyx +++ b/_randomgen/randomgen/pcg32.pyx @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New diff --git a/_randomgen/randomgen/pcg64.pyx b/_randomgen/randomgen/pcg64.pyx index c00d91966864..3bf2a1051476 100644 --- a/_randomgen/randomgen/pcg64.pyx +++ b/_randomgen/randomgen/pcg64.pyx @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New diff --git a/_randomgen/randomgen/philox.pyx b/_randomgen/randomgen/philox.pyx index 7c27467e9bd3..70a1b9677690 100644 --- a/_randomgen/randomgen/philox.pyx +++ b/_randomgen/randomgen/philox.pyx @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New diff --git a/_randomgen/randomgen/threefry.pyx b/_randomgen/randomgen/threefry.pyx index e347959c3aad..84cf7d9a69d3 100644 --- a/_randomgen/randomgen/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New diff --git a/_randomgen/randomgen/threefry32.pyx b/_randomgen/randomgen/threefry32.pyx index 41de1688860f..a308417828df 100644 --- a/_randomgen/randomgen/threefry32.pyx +++ b/_randomgen/randomgen/threefry32.pyx @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import numpy as np from cpython.pycapsule cimport PyCapsule_New from distributions cimport brng_t diff --git a/_randomgen/randomgen/xoroshiro128.pyx b/_randomgen/randomgen/xoroshiro128.pyx index 01b51376a38b..4a5d98fe9deb 100644 --- a/_randomgen/randomgen/xoroshiro128.pyx +++ b/_randomgen/randomgen/xoroshiro128.pyx @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New diff --git a/_randomgen/randomgen/xorshift1024.pyx b/_randomgen/randomgen/xorshift1024.pyx index aef61e9abed7..b254351cc5d5 100644 --- a/_randomgen/randomgen/xorshift1024.pyx +++ b/_randomgen/randomgen/xorshift1024.pyx @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New From a4a416546206bf9ffabfe5a624e0669a6e5438db Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 2 Apr 2018 09:31:35 +0100 Subject: [PATCH 117/279] BUG: Fix absolute_import Use full import paths to resolve absolute_import bug --- _randomgen/randomgen/bounded_integers.pxd.in | 5 ++++- _randomgen/randomgen/bounded_integers.pyx.in | 4 +++- _randomgen/randomgen/common.pxd | 4 +++- _randomgen/randomgen/common.pyx | 3 ++- _randomgen/randomgen/dsfmt.pyx | 6 +++--- _randomgen/randomgen/generator.pyx | 6 +++--- _randomgen/randomgen/mt19937.pyx | 8 ++++---- _randomgen/randomgen/pcg32.pyx | 6 +++--- _randomgen/randomgen/pcg64.pyx | 6 +++--- _randomgen/randomgen/philox.pyx | 6 +++--- _randomgen/randomgen/threefry.pyx | 6 +++--- _randomgen/randomgen/threefry32.pyx | 8 ++++---- _randomgen/randomgen/xoroshiro128.pyx | 6 +++--- _randomgen/randomgen/xorshift1024.pyx | 6 +++--- 14 files changed, 44 insertions(+), 36 deletions(-) diff --git a/_randomgen/randomgen/bounded_integers.pxd.in b/_randomgen/randomgen/bounded_integers.pxd.in index 4e1a6409146e..69d2fc0e7242 100644 --- a/_randomgen/randomgen/bounded_integers.pxd.in +++ b/_randomgen/randomgen/bounded_integers.pxd.in @@ -1,10 +1,13 @@ +from __future__ import absolute_import + from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t) -from common cimport brng_t import numpy as np cimport numpy as np ctypedef np.npy_bool bool_t +from randomgen.common cimport brng_t + _randint_types = {'bool': (0, 2), 'int8': (-2**7, 2**7), 'int16': (-2**15, 2**15), diff --git a/_randomgen/randomgen/bounded_integers.pyx.in b/_randomgen/randomgen/bounded_integers.pyx.in index adeaa70059aa..bdd31a84410c 100644 --- a/_randomgen/randomgen/bounded_integers.pyx.in +++ b/_randomgen/randomgen/bounded_integers.pyx.in @@ -4,7 +4,9 @@ from __future__ import absolute_import import numpy as np cimport numpy as np -from distributions cimport * + +from randomgen.distributions cimport * + np.import_array() {{ diff --git a/_randomgen/randomgen/common.pxd b/_randomgen/randomgen/common.pxd index 5a661dfb3db1..f6017c0d7504 100644 --- a/_randomgen/randomgen/common.pxd +++ b/_randomgen/randomgen/common.pxd @@ -1,9 +1,11 @@ +from __future__ import absolute_import + from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t, uintptr_t) from libc.math cimport sqrt -from distributions cimport brng_t +from randomgen.distributions cimport brng_t import numpy as np cimport numpy as np diff --git a/_randomgen/randomgen/common.pyx b/_randomgen/randomgen/common.pyx index e627d798363b..73638aaa32bb 100644 --- a/_randomgen/randomgen/common.pyx +++ b/_randomgen/randomgen/common.pyx @@ -7,7 +7,8 @@ from cpython cimport PyFloat_AsDouble import sys import numpy as np cimport numpy as np -from common cimport * + +from randomgen.common cimport * np.import_array() diff --git a/_randomgen/randomgen/dsfmt.pyx b/_randomgen/randomgen/dsfmt.pyx index 5fcd3fccd043..ef813f10ff7e 100644 --- a/_randomgen/randomgen/dsfmt.pyx +++ b/_randomgen/randomgen/dsfmt.pyx @@ -7,9 +7,9 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from common import interface -from common cimport * -from distributions cimport brng_t +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t from randomgen.entropy import random_entropy import randomgen.pickle diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index abc352eced05..4abe1e54d12e 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -8,9 +8,6 @@ import warnings from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from cpython cimport (Py_INCREF, PyComplex_RealAsDouble, PyComplex_ImagAsDouble, PyComplex_FromDoubles, PyFloat_AsDouble) -from common cimport * -from distributions cimport * -from bounded_integers cimport * from libc cimport string from libc.stdlib cimport malloc, free cimport numpy as np @@ -22,6 +19,9 @@ try: except ImportError: from dummy_threading import Lock +from randomgen.bounded_integers cimport * +from randomgen.common cimport * +from randomgen.distributions cimport * from randomgen.xoroshiro128 import Xoroshiro128 import randomgen.pickle diff --git a/_randomgen/randomgen/mt19937.pyx b/_randomgen/randomgen/mt19937.pyx index 18caeb9ac4fd..df3d03b0bc71 100644 --- a/_randomgen/randomgen/mt19937.pyx +++ b/_randomgen/randomgen/mt19937.pyx @@ -8,11 +8,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from common import interface -from common cimport * -from distributions cimport brng_t -import randomgen.pickle +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t from randomgen.entropy import random_entropy +import randomgen.pickle np.import_array() diff --git a/_randomgen/randomgen/pcg32.pyx b/_randomgen/randomgen/pcg32.pyx index 2479cd66eb22..0148c4ec18f9 100644 --- a/_randomgen/randomgen/pcg32.pyx +++ b/_randomgen/randomgen/pcg32.pyx @@ -6,9 +6,9 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from common import interface -from common cimport * -from distributions cimport brng_t +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t from randomgen.entropy import random_entropy import randomgen.pickle diff --git a/_randomgen/randomgen/pcg64.pyx b/_randomgen/randomgen/pcg64.pyx index 3bf2a1051476..226c47a272a0 100644 --- a/_randomgen/randomgen/pcg64.pyx +++ b/_randomgen/randomgen/pcg64.pyx @@ -6,9 +6,9 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from common import interface -from common cimport * -from distributions cimport brng_t +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t from randomgen.entropy import random_entropy import randomgen.pickle diff --git a/_randomgen/randomgen/philox.pyx b/_randomgen/randomgen/philox.pyx index 70a1b9677690..610f3d055586 100644 --- a/_randomgen/randomgen/philox.pyx +++ b/_randomgen/randomgen/philox.pyx @@ -5,9 +5,9 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np -from common import interface -from common cimport * -from distributions cimport brng_t +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t from randomgen.entropy import random_entropy, seed_by_array import randomgen.pickle diff --git a/_randomgen/randomgen/threefry.pyx b/_randomgen/randomgen/threefry.pyx index 84cf7d9a69d3..789c50c44146 100644 --- a/_randomgen/randomgen/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -5,9 +5,9 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np -from common import interface -from common cimport * -from distributions cimport brng_t +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t from randomgen.entropy import random_entropy, seed_by_array import randomgen.pickle diff --git a/_randomgen/randomgen/threefry32.pyx b/_randomgen/randomgen/threefry32.pyx index a308417828df..4a11ce693653 100644 --- a/_randomgen/randomgen/threefry32.pyx +++ b/_randomgen/randomgen/threefry32.pyx @@ -2,13 +2,13 @@ from __future__ import absolute_import import numpy as np from cpython.pycapsule cimport PyCapsule_New -from distributions cimport brng_t from libc.stdlib cimport malloc, free -import randomgen.pickle -from common cimport * -from common import interface +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t from randomgen.entropy import random_entropy, seed_by_array +import randomgen.pickle np.import_array() diff --git a/_randomgen/randomgen/xoroshiro128.pyx b/_randomgen/randomgen/xoroshiro128.pyx index 4a5d98fe9deb..061e03f5ff00 100644 --- a/_randomgen/randomgen/xoroshiro128.pyx +++ b/_randomgen/randomgen/xoroshiro128.pyx @@ -6,9 +6,9 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from common import interface -from common cimport * -from distributions cimport brng_t +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t from randomgen.entropy import random_entropy, seed_by_array import randomgen.pickle diff --git a/_randomgen/randomgen/xorshift1024.pyx b/_randomgen/randomgen/xorshift1024.pyx index b254351cc5d5..98065d447a90 100644 --- a/_randomgen/randomgen/xorshift1024.pyx +++ b/_randomgen/randomgen/xorshift1024.pyx @@ -6,9 +6,9 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from common import interface -from common cimport * -from distributions cimport brng_t +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t from randomgen.entropy import random_entropy, seed_by_array import randomgen.pickle From 2330bad8b7e89220d2e37fdb26e862cbd3a91bb9 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 2 Apr 2018 10:20:06 +0100 Subject: [PATCH 118/279] DOC: Spelling changes Fix multiple spelling errors --- _randomgen/README.md | 4 ++-- _randomgen/README.rst | 4 ++-- _randomgen/doc/source/change-log.rst | 1 + _randomgen/randomgen/dsfmt.pyx | 4 ++-- _randomgen/randomgen/generator.pyx | 4 ++-- _randomgen/randomgen/legacy/_legacy.pyx | 2 +- _randomgen/randomgen/mt19937.pyx | 4 ++-- _randomgen/randomgen/pcg32.pyx | 2 +- _randomgen/randomgen/pcg64.pyx | 2 +- _randomgen/randomgen/philox.pyx | 2 +- _randomgen/randomgen/threefry.pyx | 6 +++--- _randomgen/randomgen/threefry32.pyx | 2 +- _randomgen/randomgen/xoroshiro128.pyx | 2 +- _randomgen/randomgen/xorshift1024.pyx | 2 +- 14 files changed, 21 insertions(+), 20 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index fbcc1f6d25bc..c90d9e2256ce 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -12,7 +12,7 @@ generators in Python and NumPy. ## Compatibility Warning -`RandomGenerator` does notsupports Box-Muller normal variates and so it not +`RandomGenerator` does not support Box-Muller normal variates and so it not 100% compatible with NumPy (or randomstate). Box-Muller normals are slow to generate and all functions which previously relied on Box-Muller normals now use the faster Ziggurat implementation. If you require backward @@ -128,7 +128,7 @@ the RNG._ ## Version The version matched the latest version of NumPy where -`RandoMGenerator(MT19937())` passes all NumPy test. +`RandomGenerator(MT19937())` passes all NumPy test. ## Documentation diff --git a/_randomgen/README.rst b/_randomgen/README.rst index 587d73f82231..79252abc4347 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -12,7 +12,7 @@ generators in Python and NumPy. Compatibility Warning --------------------- -``RandomGenerator`` does notsupports Box-Muller normal variates and so +``RandomGenerator`` does not support Box-Muller normal variates and so it not 100% compatible with NumPy (or randomstate). Box-Muller normals are slow to generate and all functions which previously relied on Box-Muller normals now use the faster Ziggurat implementation. If you @@ -140,7 +140,7 @@ Version ------- The version matched the latest version of NumPy where -``RandoMGenerator(MT19937())`` passes all NumPy test. +``RandomGenerator(MT19937())`` passes all NumPy test. Documentation ------------- diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst index 9029981e3ed5..271ee5647e13 100644 --- a/_randomgen/doc/source/change-log.rst +++ b/_randomgen/doc/source/change-log.rst @@ -4,6 +4,7 @@ Change Log Changes since v1.14 =================== +- Added absolute_import to avoid import noise on Python 2.7 - Add legacy generator which allows NumPy replication - Improve type handling of integers - Switch to array-fillers for 0 parameter distribution to improve performance diff --git a/_randomgen/randomgen/dsfmt.pyx b/_randomgen/randomgen/dsfmt.pyx index ef813f10ff7e..c83ade5cdf2f 100644 --- a/_randomgen/randomgen/dsfmt.pyx +++ b/_randomgen/randomgen/dsfmt.pyx @@ -86,7 +86,7 @@ cdef class DSFMT: Notes ----- ``DSFMT`` directly provides generators for doubles, and unsigned 32 and 64- - bit integers [1]_ . These are not firectly available and must be consumed + bit integers [1]_ . These are not directly available and must be consumed via a ``RandomGenerator`` object. The Python stdlib module "random" also contains a Mersenne Twister @@ -313,7 +313,7 @@ cdef class DSFMT: @property def ctypes(self): """ - Cytpes interface + Ctypes interface Returns ------- diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 4abe1e54d12e..c996f905de4a 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -85,7 +85,7 @@ cdef class RandomGenerator: >>> from randomgen import MT19937 >>> rg = RandomGenerator(MT19937()) - The generator is also directly avialable from basic RNGs + The generator is also directly available from basic RNGs >>> rg = MT19937().generator >>> rg.standard_normal() @@ -375,7 +375,7 @@ cdef class RandomGenerator: .. math:: f(x; a,b) = \\frac{1}{B(\\alpha, \\beta)} x^{\\alpha - 1} (1 - x)^{\\beta - 1}, - where the normalisation, B, is the beta function, + where the normalization, B, is the beta function, .. math:: B(\\alpha, \\beta) = \\int_0^1 t^{\\alpha - 1} (1 - t)^{\\beta - 1} dt. diff --git a/_randomgen/randomgen/legacy/_legacy.pyx b/_randomgen/randomgen/legacy/_legacy.pyx index af1a6b417d68..5a6dc5542828 100644 --- a/_randomgen/randomgen/legacy/_legacy.pyx +++ b/_randomgen/randomgen/legacy/_legacy.pyx @@ -34,7 +34,7 @@ cdef class _LegacyGenerator: numbers for a set of distributions where the method used to produce random samples has changed. Three core generators have changed: normal, exponential and gamma. These have been replaced by faster Ziggurat-based methods in - ``RadnomGenerator``. ``_LegacyGenerator`` retains the slower methods + ``RandomGenerator``. ``_LegacyGenerator`` retains the slower methods to produce samples from these distributions as well as from distributions that depend on these such as the Chi-square, power or Weibull. diff --git a/_randomgen/randomgen/mt19937.pyx b/_randomgen/randomgen/mt19937.pyx index df3d03b0bc71..14ab24f39878 100644 --- a/_randomgen/randomgen/mt19937.pyx +++ b/_randomgen/randomgen/mt19937.pyx @@ -61,7 +61,7 @@ cdef class MT19937: Notes ----- ``MT19937`` directly provides generators for doubles, and unsigned 32 and 64- - bit integers [1]_ . These are not firectly available and must be consumed + bit integers [1]_ . These are not directly available and must be consumed via a ``RandomGenerator`` object. The Python stdlib module "random" also contains a Mersenne Twister @@ -299,7 +299,7 @@ cdef class MT19937: @property def ctypes(self): """ - Cytpes interface + Ctypes interface Returns ------- diff --git a/_randomgen/randomgen/pcg32.pyx b/_randomgen/randomgen/pcg32.pyx index 0148c4ec18f9..5c83b1040b1d 100644 --- a/_randomgen/randomgen/pcg32.pyx +++ b/_randomgen/randomgen/pcg32.pyx @@ -327,7 +327,7 @@ cdef class PCG32: @property def ctypes(self): """ - Cytpes interface + Ctypes interface Returns ------- diff --git a/_randomgen/randomgen/pcg64.pyx b/_randomgen/randomgen/pcg64.pyx index 226c47a272a0..ae553d3a542a 100644 --- a/_randomgen/randomgen/pcg64.pyx +++ b/_randomgen/randomgen/pcg64.pyx @@ -386,7 +386,7 @@ cdef class PCG64: @property def ctypes(self): """ - Cytpes interface + Ctypes interface Returns ------- diff --git a/_randomgen/randomgen/philox.pyx b/_randomgen/randomgen/philox.pyx index 610f3d055586..c08f54496317 100644 --- a/_randomgen/randomgen/philox.pyx +++ b/_randomgen/randomgen/philox.pyx @@ -394,7 +394,7 @@ cdef class Philox: def ctypes(self): """ - Cytpes interface + Ctypes interface Returns ------- diff --git a/_randomgen/randomgen/threefry.pyx b/_randomgen/randomgen/threefry.pyx index 789c50c44146..e8971ff42161 100644 --- a/_randomgen/randomgen/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -99,8 +99,8 @@ cdef class ThreeFry: ``ThreeFry`` can be used in parallel applications by calling the method ``jump`` which advances the state as-if :math:`2^{128}` random numbers have been generated. Alternatively, - ``advance`` can be used to advance the counter for an abritrary number of - positive steps in [0, 2**256). When using ``jump``, all generators should + ``advance`` can be used to advance the counter for an any + positive step in [0, 2**256). When using ``jump``, all generators should be initialized with the same seed to ensure that the segments come from the same sequence. Alternatively, ``ThreeFry`` can be used in parallel applications by using a sequence of distinct keys where each @@ -387,7 +387,7 @@ cdef class ThreeFry: def ctypes(self): """ - Cytpes interface + Ctypes interface Returns ------- diff --git a/_randomgen/randomgen/threefry32.pyx b/_randomgen/randomgen/threefry32.pyx index 4a11ce693653..512ce9d00d3b 100644 --- a/_randomgen/randomgen/threefry32.pyx +++ b/_randomgen/randomgen/threefry32.pyx @@ -382,7 +382,7 @@ cdef class ThreeFry32: def ctypes(self): """ - Cytpes interface + Ctypes interface Returns ------- diff --git a/_randomgen/randomgen/xoroshiro128.pyx b/_randomgen/randomgen/xoroshiro128.pyx index 061e03f5ff00..d9891e590334 100644 --- a/_randomgen/randomgen/xoroshiro128.pyx +++ b/_randomgen/randomgen/xoroshiro128.pyx @@ -273,7 +273,7 @@ cdef class Xoroshiro128: @property def ctypes(self): """ - Cytpes interface + Ctypes interface Returns ------- diff --git a/_randomgen/randomgen/xorshift1024.pyx b/_randomgen/randomgen/xorshift1024.pyx index 98065d447a90..bf8f32e90de4 100644 --- a/_randomgen/randomgen/xorshift1024.pyx +++ b/_randomgen/randomgen/xorshift1024.pyx @@ -306,7 +306,7 @@ cdef class Xorshift1024: @property def ctypes(self): """ - Cytpes interface + Ctypes interface Returns ------- From 28f66033aa4ed67782dfed1eadcce88b6224a4b2 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 2 Apr 2018 17:05:31 +0100 Subject: [PATCH 119/279] CLN: Remove redeclared type Remove duplicate pcg128_t declaration --- _randomgen/randomgen/pcg64.pyx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/_randomgen/randomgen/pcg64.pyx b/_randomgen/randomgen/pcg64.pyx index ae553d3a542a..e7939314e626 100644 --- a/_randomgen/randomgen/pcg64.pyx +++ b/_randomgen/randomgen/pcg64.pyx @@ -27,12 +27,6 @@ ELSE: cdef extern from "src/pcg64/pcg64.h": ctypedef __uint128_t pcg128_t -cdef extern from "src/pcg64/pcg64.h": - - ctypedef struct pcg128_t: - uint64_t high - uint64_t low - cdef extern from "src/pcg64/pcg64.h": cdef struct pcg_state_setseq_128: From 7c5382727985829383a91ad43e533a4182ab3152 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 3 Apr 2018 12:19:51 +0100 Subject: [PATCH 120/279] BLD: Enable no-sse2 flag Enable no-sse2 flag to be set --- _randomgen/setup.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index c7f193d19734..deb38308d9d2 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -1,5 +1,6 @@ import os import glob +import platform import struct import sys from os.path import join @@ -36,7 +37,16 @@ Cython.Compiler.Options.annotate = True -USE_SSE2 = True if not '--no-sse2' in sys.argv else False +# Make a guess as to whether SSE2 is present for now, TODO: Improve +USE_SSE2 = False +for k in platform.uname(): + for val in ('x86', 'i686', 'i386', 'amd64'): + USE_SSE2 = USE_SSE2 or val in k.lower() +print('Building with SSE?: {0}'.format(USE_SSE2)) +if '--no-sse2' in sys.argv: + USE_SSE2 = False + sys.argv.remove('--no-sse2') + MOD_DIR = './randomgen' DEBUG = False From 657aab02d81a62cc83752a1c01a6cf94f9557728 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 16 Apr 2018 22:03:29 +0100 Subject: [PATCH 121/279] SYNC/CLN: Sync with upstream changes Sync with upstream changes (all doc) Clean flake8 issues --- _randomgen/randomgen/examples/cython/setup.py | 3 +- .../randomgen/examples/numba/extending.py | 8 +- .../examples/numba/extending_distributions.py | 13 ++- _randomgen/randomgen/generator.pyx | 83 +++++++++---------- _randomgen/randomgen/legacy/_legacy.pyx | 54 ++++++------ _randomgen/randomgen/legacy/legacy.py | 13 +-- .../randomgen/tests/test_against_numpy.py | 33 ++++---- .../randomgen/tests/test_numpy_mt19937.py | 9 +- .../tests/test_numpy_mt19937_regressions.py | 7 +- _randomgen/randomgen/tests/test_smoke.py | 4 +- 10 files changed, 114 insertions(+), 113 deletions(-) diff --git a/_randomgen/randomgen/examples/cython/setup.py b/_randomgen/randomgen/examples/cython/setup.py index 480d5f508f8b..bf6fb81486c6 100644 --- a/_randomgen/randomgen/examples/cython/setup.py +++ b/_randomgen/randomgen/examples/cython/setup.py @@ -10,7 +10,8 @@ include_dirs=[np.get_include()]) distributions = Extension("extending_distributions", sources=['extending_distributions.pyx', - join('..', '..', 'randomgen', 'src', 'distributions', 'distributions.c')], + join('..', '..', 'randomgen', 'src', + 'distributions', 'distributions.c')], include_dirs=[np.get_include()]) extensions = [extending, distributions] diff --git a/_randomgen/randomgen/examples/numba/extending.py b/_randomgen/randomgen/examples/numba/extending.py index 09e07a437674..866b4070d05a 100644 --- a/_randomgen/randomgen/examples/numba/extending.py +++ b/_randomgen/randomgen/examples/numba/extending.py @@ -1,3 +1,5 @@ +import datetime as dt + import numpy as np import numba as nb @@ -31,7 +33,7 @@ def bounded_uint(lb, ub, state): def bounded_uints(lb, ub, n, state): out = np.empty(n, dtype=np.uint32) for i in range(n): - bounded_uint(lb, ub, state) + out[i] = bounded_uint(lb, ub, state) bounded_uints(323, 2394691, 10000000, s.value) @@ -57,11 +59,11 @@ def normals(n, state): out[2 * i + 1] = f * x2 return out + print(normals(10, cffi_state).var()) # Warm up normalsj = nb.jit(normals, nopython=True) normalsj(1, state_addr) -import datetime as dt start = dt.datetime.now() normalsj(1000000, state_addr) @@ -69,8 +71,6 @@ def normals(n, state): print('1,000,000 Box-Muller (numba/Xoroshiro128) randoms in ' '{ms:0.1f}ms'.format(ms=ms)) -import numpy as np - start = dt.datetime.now() np.random.standard_normal(1000000) ms = 1000 * (dt.datetime.now() - start).total_seconds() diff --git a/_randomgen/randomgen/examples/numba/extending_distributions.py b/_randomgen/randomgen/examples/numba/extending_distributions.py index 47f811c06d54..c0094bf1b882 100644 --- a/_randomgen/randomgen/examples/numba/extending_distributions.py +++ b/_randomgen/randomgen/examples/numba/extending_distributions.py @@ -1,16 +1,21 @@ r""" On *nix, execute in randomgen/src/distributions -export PYTHON_INCLUDE=#path to Python's include folder, usually ${PYTHON_HOME}/include/python${PYTHON_VERSION}m -export NUMPY_INCLUDE=#path to numpy's include folder, usually ${PYTHON_HOME}/lib/python${PYTHON_VERSION}/site-packages/numpy/core/include -gcc -shared -o libdistributions.so -fPIC distributions.c -I${NUMPY_INCLUDE} -I${PYTHON_INCLUDE} +export PYTHON_INCLUDE=#path to Python's include folder, usually \ + ${PYTHON_HOME}/include/python${PYTHON_VERSION}m +export NUMPY_INCLUDE=#path to numpy's include folder, usually \ + ${PYTHON_HOME}/lib/python${PYTHON_VERSION}/site-packages/numpy/core/include +gcc -shared -o libdistributions.so -fPIC distributions.c -I${NUMPY_INCLUDE} \ + -I${PYTHON_INCLUDE} mv libdistributions.so ../../examples/numba/ On Windows rem PYTHON_HOME is setup dependent, this is an example set PYTHON_HOME=c:\Anaconda -cl.exe /LD .\distributions.c -DDLL_EXPORT -I%PYTHON_HOME%\lib\site-packages\numpy\core\include -I%PYTHON_HOME%\include %PYTHON_HOME%\libs\python36.lib +cl.exe /LD .\distributions.c -DDLL_EXPORT \ + -I%PYTHON_HOME%\lib\site-packages\numpy\core\include \ + -I%PYTHON_HOME%\include %PYTHON_HOME%\libs\python36.lib move distributions.dll ../../examples/numba/ """ import os diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index c996f905de4a..40a876aa48d3 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -552,7 +552,7 @@ cdef class RandomGenerator: array([[[ True, True], [ True, True]], [[ True, True], - [ True, True]]], dtype=bool) + [ True, True]]]) """ cdef np.npy_intp n @@ -959,7 +959,7 @@ cdef class RandomGenerator: probability density function: >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, 15, normed=True) + >>> count, bins, ignored = plt.hist(s, 15, density=True) >>> plt.plot(bins, np.ones_like(bins), linewidth=2, color='r') >>> plt.show() """ @@ -1059,7 +1059,7 @@ cdef class RandomGenerator: argument is provided. This is a convenience function. If you want an interface that takes a - tuple as the first argument, use `numpy.random.standard_normal` instead. + tuple as the first argument, use `standard_normal` instead. Parameters ---------- @@ -1080,7 +1080,7 @@ cdef class RandomGenerator: See Also -------- - random.standard_normal : Similar, but takes a tuple as its argument. + standard_normal : Similar, but takes a tuple as its argument. Notes ----- @@ -1141,7 +1141,7 @@ cdef class RandomGenerator: See Also -------- - random.randint : Similar to `random_integers`, only for the half-open + randint : Similar to `random_integers`, only for the half-open interval [`low`, `high`), and 0 is the lowest value if `high` is omitted. @@ -1179,7 +1179,7 @@ cdef class RandomGenerator: Display results as a histogram: >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(dsums, 11, normed=True) + >>> count, bins, ignored = plt.hist(dsums, 11, density=True) >>> plt.show() """ @@ -1329,7 +1329,7 @@ cdef class RandomGenerator: the probability density function: >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> count, bins, ignored = plt.hist(s, 30, density=True) >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ), ... linewidth=2, color='r') @@ -1573,7 +1573,7 @@ cdef class RandomGenerator: >>> import matplotlib.pyplot as plt >>> import scipy.special as sps - >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> count, bins, ignored = plt.hist(s, 50, density=True) >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ ... (sps.gamma(shape) * scale**shape)) >>> plt.plot(bins, y, linewidth=2, color='r') @@ -1660,7 +1660,7 @@ cdef class RandomGenerator: >>> import matplotlib.pyplot as plt >>> import scipy.special as sps - >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> count, bins, ignored = plt.hist(s, 50, density=True) >>> y = bins**(shape-1)*(np.exp(-bins/scale) / ... (sps.gamma(shape)*scale**shape)) >>> plt.plot(bins, y, linewidth=2, color='r') @@ -1819,9 +1819,9 @@ cdef class RandomGenerator: >>> dfden = 20 # within groups degrees of freedom >>> nonc = 3.0 >>> nc_vals = randomgen.noncentral_f(dfnum, dfden, nonc, 1000000) - >>> NF = np.histogram(nc_vals, bins=50, normed=True) + >>> NF = np.histogram(nc_vals, bins=50, density=True) >>> c_vals = randomgen.f(dfnum, dfden, 1000000) - >>> F = np.histogram(c_vals, bins=50, normed=True) + >>> F = np.histogram(c_vals, bins=50, density=True) >>> plt.plot(F[1][1:], F[0]) >>> plt.plot(NF[1][1:], NF[0]) >>> plt.show() @@ -1957,7 +1957,7 @@ cdef class RandomGenerator: >>> import matplotlib.pyplot as plt >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), - ... bins=200, normed=True) + ... bins=200, density=True) >>> plt.show() Draw values from a noncentral chisquare with very small noncentrality, @@ -1965,9 +1965,9 @@ cdef class RandomGenerator: >>> plt.figure() >>> values = plt.hist(randomgen.noncentral_chisquare(3, .0000001, 100000), - ... bins=np.arange(0., 25, .1), normed=True) + ... bins=np.arange(0., 25, .1), density=True) >>> values2 = plt.hist(randomgen.chisquare(3, 100000), - ... bins=np.arange(0., 25, .1), normed=True) + ... bins=np.arange(0., 25, .1), density=True) >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') >>> plt.show() @@ -1976,7 +1976,7 @@ cdef class RandomGenerator: >>> plt.figure() >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), - ... bins=200, normed=True) + ... bins=200, density=True) >>> plt.show() """ @@ -2125,7 +2125,7 @@ cdef class RandomGenerator: >>> t = (np.mean(intake)-7725)/(intake.std(ddof=1)/np.sqrt(len(intake))) >>> import matplotlib.pyplot as plt - >>> h = plt.hist(s, bins=100, normed=True) + >>> h = plt.hist(s, bins=100, density=True) For a one-sided t-test, how far out in the distribution does the t statistic appear? @@ -2214,7 +2214,7 @@ cdef class RandomGenerator: >>> import matplotlib.pyplot as plt >>> from scipy.special import i0 - >>> plt.hist(s, 50, normed=True) + >>> plt.hist(s, 50, density=True) >>> x = np.linspace(-np.pi, np.pi, num=51) >>> y = np.exp(kappa*np.cos(x-mu))/(2*np.pi*i0(kappa)) >>> plt.plot(x, y, linewidth=2, color='r') @@ -2313,7 +2313,7 @@ cdef class RandomGenerator: density function: >>> import matplotlib.pyplot as plt - >>> count, bins, _ = plt.hist(s, 100, normed=True) + >>> count, bins, _ = plt.hist(s, 100, density=True) >>> fit = a*m**a / bins**(a+1) >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r') >>> plt.show() @@ -2502,17 +2502,17 @@ cdef class RandomGenerator: >>> powpdf = stats.powerlaw.pdf(xx,5) >>> plt.figure() - >>> plt.hist(rvs, bins=50, normed=True) + >>> plt.hist(rvs, bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') >>> plt.title('randomgen.power(5)') >>> plt.figure() - >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) + >>> plt.hist(1./(1.+rvsp), bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') >>> plt.title('inverse of 1 + randomgen.pareto(5)') >>> plt.figure() - >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) + >>> plt.hist(1./(1.+rvsp), bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') >>> plt.title('inverse of stats.pareto(5)') @@ -2589,7 +2589,7 @@ cdef class RandomGenerator: the probability density function: >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> count, bins, ignored = plt.hist(s, 30, density=True) >>> x = np.arange(-8., 8., .01) >>> pdf = np.exp(-abs(x-loc)/scale)/(2.*scale) >>> plt.plot(x, pdf) @@ -2691,7 +2691,7 @@ cdef class RandomGenerator: the probability density function: >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> count, bins, ignored = plt.hist(s, 30, density=True) >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta) ... * np.exp( -np.exp( -(bins - mu) /beta) ), ... linewidth=2, color='r') @@ -2706,7 +2706,7 @@ cdef class RandomGenerator: ... a = randomgen.normal(mu, beta, 1000) ... means.append(a.mean()) ... maxima.append(a.max()) - >>> count, bins, ignored = plt.hist(maxima, 30, normed=True) + >>> count, bins, ignored = plt.hist(maxima, 30, density=True) >>> beta = np.std(maxima) * np.sqrt(6) / np.pi >>> mu = np.mean(maxima) - 0.57721*beta >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta) @@ -2873,7 +2873,7 @@ cdef class RandomGenerator: the probability density function: >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, 100, normed=True, align='mid') + >>> count, bins, ignored = plt.hist(s, 100, density=True, align='mid') >>> x = np.linspace(min(bins), max(bins), 10000) >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) @@ -2895,7 +2895,7 @@ cdef class RandomGenerator: ... b.append(np.product(a)) >>> b = np.array(b) / np.min(b) # scale values to be positive - >>> count, bins, ignored = plt.hist(b, 100, normed=True, align='mid') + >>> count, bins, ignored = plt.hist(b, 100, density=True, align='mid') >>> sigma = np.std(np.log(b)) >>> mu = np.mean(np.log(b)) @@ -2958,7 +2958,7 @@ cdef class RandomGenerator: -------- Draw values from the distribution and plot the histogram - >>> values = hist(randomgen.rayleigh(3, 100000), bins=200, normed=True) + >>> values = hist(randomgen.rayleigh(3, 100000), bins=200, density=True) Wave heights tend to follow a Rayleigh distribution. If the mean wave height is 1 meter, what fraction of waves are likely to be larger than 3 @@ -3038,7 +3038,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(randomgen.wald(3, 2, 100000), bins=200, normed=True) + >>> h = plt.hist(randomgen.wald(3, 2, 100000), bins=200, density=True) >>> plt.show() """ @@ -3106,7 +3106,7 @@ cdef class RandomGenerator: >>> import matplotlib.pyplot as plt >>> h = plt.hist(randomgen.triangular(-3, 0, 8, 100000), bins=200, - ... normed=True) + ... density=True) >>> plt.show() """ @@ -3297,7 +3297,7 @@ cdef class RandomGenerator: Draw samples from a negative binomial distribution. Samples are drawn from a negative binomial distribution with specified - parameters, `n` trials and `p` probability of success where `n` is an + parameters, `n` trials and `p` probability of failure where `n` is an integer > 0 and `p` is in the interval [0, 1]. Parameters @@ -3317,20 +3317,19 @@ cdef class RandomGenerator: ------- out : ndarray or scalar Drawn samples from the parameterized negative binomial distribution, - where each sample is equal to N, the number of trials it took to - achieve n - 1 successes, N - (n - 1) failures, and a success on the, - (N + n)th trial. + where each sample is equal to N, the number of successes that + occurred before n failures, and a failure on the (N + n)th trial. Notes ----- The probability density for the negative binomial distribution is - .. math:: P(N;n,p) = \\binom{N+n-1}{n-1}p^{n}(1-p)^{N}, + .. math:: P(N;n,p) = \\binom{N+n-1}{N}p^{n}(1-p)^{N}, - where :math:`n-1` is the number of successes, :math:`p` is the - probability of success, and :math:`N+n-1` is the number of trials. - The negative binomial distribution gives the probability of n-1 - successes and N failures in N+n-1 trials, and success on the (N+n)th + where :math:`n` is the number of successes, :math:`p` is the + probability of failure, and :math:`N+n` is the number of trials. + The negative binomial distribution gives the probability of n + successes and N failures in N+n trials, and a success on the (N+n)th trial. If one throws a die repeatedly until the third time a "1" appears, @@ -3355,7 +3354,7 @@ cdef class RandomGenerator: for each successive well, that is what is the probability of a single success after drilling 5 wells, after 6 wells, etc.? - >>> s = randomgen.negative_binomial(1, 0.1, 100000) + >>> s = np.random.negative_binomial(1, 0.9, 100000) >>> for i in range(1, 11): ... probability = sum(s>> import matplotlib.pyplot as plt - >>> count, bins, _ = plt.hist(s, 100, normed=True) + >>> count, bins, _ = plt.hist(s, 100, density=True) >>> fit = a*m**a / bins**(a+1) >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r') >>> plt.show() @@ -765,9 +765,9 @@ cdef class _LegacyGenerator: >>> dfden = 20 # within groups degrees of freedom >>> nonc = 3.0 >>> nc_vals = randomgen.noncentral_f(dfnum, dfden, nonc, 1000000) - >>> NF = np.histogram(nc_vals, bins=50, normed=True) + >>> NF = np.histogram(nc_vals, bins=50, density=True) >>> c_vals = randomgen.f(dfnum, dfden, 1000000) - >>> F = np.histogram(c_vals, bins=50, normed=True) + >>> F = np.histogram(c_vals, bins=50, density=True) >>> plt.plot(F[1][1:], F[0]) >>> plt.plot(NF[1][1:], NF[0]) >>> plt.show() @@ -903,7 +903,7 @@ cdef class _LegacyGenerator: >>> import matplotlib.pyplot as plt >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), - ... bins=200, normed=True) + ... bins=200, density=True) >>> plt.show() Draw values from a noncentral chisquare with very small noncentrality, @@ -911,9 +911,9 @@ cdef class _LegacyGenerator: >>> plt.figure() >>> values = plt.hist(randomgen.noncentral_chisquare(3, .0000001, 100000), - ... bins=np.arange(0., 25, .1), normed=True) + ... bins=np.arange(0., 25, .1), density=True) >>> values2 = plt.hist(randomgen.chisquare(3, 100000), - ... bins=np.arange(0., 25, .1), normed=True) + ... bins=np.arange(0., 25, .1), density=True) >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') >>> plt.show() @@ -922,7 +922,7 @@ cdef class _LegacyGenerator: >>> plt.figure() >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), - ... bins=200, normed=True) + ... bins=200, density=True) >>> plt.show() """ @@ -1058,7 +1058,7 @@ cdef class _LegacyGenerator: >>> import matplotlib.pyplot as plt >>> import scipy.special as sps - >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> count, bins, ignored = plt.hist(s, 50, density=True) >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ ... (sps.gamma(shape) * scale**shape)) >>> plt.plot(bins, y, linewidth=2, color='r') @@ -1136,7 +1136,7 @@ cdef class _LegacyGenerator: >>> import matplotlib.pyplot as plt >>> import scipy.special as sps - >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> count, bins, ignored = plt.hist(s, 50, density=True) >>> y = bins**(shape-1)*(np.exp(-bins/scale) / ... (sps.gamma(shape)*scale**shape)) >>> plt.plot(bins, y, linewidth=2, color='r') @@ -1362,7 +1362,7 @@ cdef class _LegacyGenerator: the probability density function: >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> count, bins, ignored = plt.hist(s, 30, density=True) >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ), ... linewidth=2, color='r') @@ -1390,7 +1390,7 @@ cdef class _LegacyGenerator: argument is provided. This is a convenience function. If you want an interface that takes a - tuple as the first argument, use `numpy.random.standard_normal` instead. + tuple as the first argument, use `standard_normal` instead. Parameters ---------- @@ -1407,7 +1407,7 @@ cdef class _LegacyGenerator: See Also -------- - random.standard_normal : Similar, but takes a tuple as its argument. + standard_normal : Similar, but takes a tuple as its argument. Notes ----- @@ -1770,24 +1770,26 @@ cdef class _LegacyGenerator: # # Also check that cov is positive-semidefinite. If so, the u.T and v # matrices should be equal up to roundoff error if cov is - # symmetrical and the singular value of the corresponding row is + # symmetric and the singular value of the corresponding row is # not zero. We continue to use the SVD rather than Cholesky in - # order to preserve current outputs. Note that symmetry has not - # been checked. + # order to preserve current outputs. (u, s, v) = svd(cov) if check_valid != 'ignore': if check_valid != 'warn' and check_valid != 'raise': - raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") + raise ValueError( + "check_valid must equal 'warn', 'raise', or 'ignore'") psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) if not psd: if check_valid == 'warn': - warnings.warn("covariance is not positive-semidefinite.", - RuntimeWarning) + warnings.warn( + "covariance is not positive-semidefinite.", + RuntimeWarning) else: - raise ValueError("covariance is not positive-semidefinite.") + raise ValueError( + "covariance is not positive-semidefinite.") x = np.dot(x, np.sqrt(s)[:, None] * v) x += mean @@ -1959,17 +1961,17 @@ cdef class _LegacyGenerator: >>> powpdf = stats.powerlaw.pdf(xx,5) >>> plt.figure() - >>> plt.hist(rvs, bins=50, normed=True) + >>> plt.hist(rvs, bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') >>> plt.title('randomgen.power(5)') >>> plt.figure() - >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) + >>> plt.hist(1./(1.+rvsp), bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') >>> plt.title('inverse of 1 + randomgen.pareto(5)') >>> plt.figure() - >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) + >>> plt.hist(1./(1.+rvsp), bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') >>> plt.title('inverse of stats.pareto(5)') diff --git a/_randomgen/randomgen/legacy/legacy.py b/_randomgen/randomgen/legacy/legacy.py index e1b04b12bee7..f23464e6069a 100644 --- a/_randomgen/randomgen/legacy/legacy.py +++ b/_randomgen/randomgen/legacy/legacy.py @@ -43,11 +43,12 @@ class LegacyGenerator(with_metaclass(LegacyGeneratorType, RandomGenerator)): ``LegacyGenerator`` exposes a number of methods for generating random numbers for a set of distributions where the method used to produce random - samples has changed. Three core generators have changed: normal, exponential - and gamma. These have been replaced by faster Ziggurat-based methods in - ``RadnomGenerator``. ``LegacyGenerator`` retains the slower methods - to produce samples from these distributions as well as from distributions - that depend on these such as the Chi-square, power or Weibull. + samples has changed. Three core generators have changed: normal, + exponential and gamma. These have been replaced by faster Ziggurat-based + methods in ``RadnomGenerator``. ``LegacyGenerator`` retains the slower + methods to produce samples from these distributions as well as from + distributions that depend on these such as the Chi-square, power or + Weibull. **No Compatibility Guarantee** @@ -65,7 +66,7 @@ class LegacyGenerator(with_metaclass(LegacyGeneratorType, RandomGenerator)): Examples -------- - Exactly reproducing a NumPy stream requires using ``MT19937`` as + Exactly reproducing a NumPy stream requires using ``MT19937`` as the Basic RNG. >>> from randomgen import MT19937 diff --git a/_randomgen/randomgen/tests/test_against_numpy.py b/_randomgen/randomgen/tests/test_against_numpy.py index cce6228a33d7..46350cdd0127 100644 --- a/_randomgen/randomgen/tests/test_against_numpy.py +++ b/_randomgen/randomgen/tests/test_against_numpy.py @@ -1,6 +1,5 @@ import numpy as np import numpy.random -import pytest from numpy.testing import assert_allclose, assert_array_equal, assert_equal import randomgen @@ -9,10 +8,16 @@ def compare_0_input(f1, f2): - inputs = [(tuple([]), {}), (tuple([]), {'size': 10}), + inputs = [(tuple([]), {}), + (tuple([]), {'size': 10}), (tuple([]), {'size': (20, 31)}), (tuple([]), {'size': (20, 31, 5)})] + for i in inputs: + v1 = f1(*i[0], **i[1]) + v2 = f2(*i[0], **i[1]) + assert_allclose(v1, v2) + def compare_1_input(f1, f2, is_small=False): a = 0.3 if is_small else 10 @@ -156,25 +161,25 @@ def test_random_sample(self): assert_array_equal(v1, v2) def test_standard_normal(self): - self._set_common_state() - self._is_state_common() + self._set_common_state_legacy() + self._is_state_common_legacy() compare_0_input(self.nprs.standard_normal, - self.rg.standard_normal) - self._is_state_common() + self.lg.standard_normal) + self._is_state_common_legacy() def test_standard_cauchy(self): - self._set_common_state() - self._is_state_common() + self._set_common_state_legacy() + self._is_state_common_legacy() compare_0_input(self.nprs.standard_cauchy, - self.rg.standard_cauchy) - self._is_state_common() + self.lg.standard_cauchy) + self._is_state_common_legacy() def test_standard_exponential(self): - self._set_common_state() - self._is_state_common() + self._set_common_state_legacy() + self._is_state_common_legacy() compare_0_input(self.nprs.standard_exponential, - self.rg.standard_exponential) - self._is_state_common() + self.lg.standard_exponential) + self._is_state_common_legacy() def test_tomaxint(self): self._set_common_state() diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 468a6232e290..7fb2008cd8a4 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -5,10 +5,9 @@ import numpy as np from numpy.testing import ( - run_module_suite, assert_, assert_raises, assert_equal, + assert_, assert_raises, assert_equal, assert_warns, assert_no_warnings, assert_array_equal, assert_array_almost_equal) -import pytest from randomgen._testing import suppress_warnings from randomgen import RandomGenerator, MT19937 @@ -316,7 +315,7 @@ def test_repeatability(self): res = hashlib.md5(val.view(np.int8)).hexdigest() assert_(tgt[np.dtype(dt).name] == res) - # bools do not depend on endianess + # bools do not depend on endianness mt19937.seed(1234) val = self.rfunc(0, 2, size=1000, dtype=bool).view(np.int8) res = hashlib.md5(val).hexdigest() @@ -1760,7 +1759,3 @@ def test_three_arg_funcs(self): out = func(self.argOne, self.argTwo[0], self.argThree) assert_equal(out.shape, self.tgtShape) - - -if __name__ == "__main__": - run_module_suite() diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py b/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py index 4a972462d2a4..1f082925e589 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py @@ -1,8 +1,7 @@ from __future__ import division, absolute_import, print_function import sys -from numpy.testing import (run_module_suite, assert_, - assert_array_equal, assert_raises) +from numpy.testing import (assert_, assert_array_equal) from numpy.compat import long import numpy as np import pytest @@ -137,7 +136,3 @@ def test_shuffle_of_array_of_objects(self): # Force Garbage Collection - should not segfault. import gc gc.collect() - - -if __name__ == "__main__": - run_module_suite() diff --git a/_randomgen/randomgen/tests/test_smoke.py b/_randomgen/randomgen/tests/test_smoke.py index cc720f1f0d2e..34f95bc10cb0 100644 --- a/_randomgen/randomgen/tests/test_smoke.py +++ b/_randomgen/randomgen/tests/test_smoke.py @@ -424,10 +424,8 @@ def test_randn(self): assert_equal(vals, self.rg.standard_normal((10, 10, 10))) state = self.rg.state - vals_inv = self.rg.randn(10, 10, 10) + self.rg.randn(10, 10, 10) self.rg.state = state - vals_zig = self.rg.randn(10, 10, 10) - vals = self.rg.randn(10, 10, 10, dtype=np.float32) assert_(vals.shape == (10, 10, 10)) From f8786102f9a0dfc9a71c6fde273ff1b5678d5e48 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 2 May 2018 09:14:46 +0100 Subject: [PATCH 122/279] BLD: Add lm flag for non-windows platforms Should be gcc only --- _randomgen/setup.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index deb38308d9d2..75533ddc4a2a 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -54,6 +54,7 @@ EXTRA_INCLUDE_DIRS = [] EXTRA_LINK_ARGS = [] +EXTRA_LIBRARIES = ['m'] if os.name != 'nt' else [] # Undef for manylinux EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else [ '-std=c99', '-U__GNUC_GNU_INLINE__'] @@ -64,6 +65,7 @@ EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] if sys.version_info < (3, 0): EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] + PCG64_DEFS = [] if sys.maxsize < 2 ** 32 or os.name == 'nt': # Force emulated mode here @@ -100,6 +102,7 @@ include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'entropy')], + libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -111,6 +114,7 @@ include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'dsfmt')], + libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, define_macros=DSFMT_DEFS, @@ -122,6 +126,7 @@ include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'mt19937')], + libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -131,6 +136,7 @@ include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'philox')], + libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -140,6 +146,7 @@ include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'pcg64')], + libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, define_macros=PCG64_DEFS, extra_link_args=EXTRA_LINK_ARGS @@ -150,6 +157,7 @@ include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'pcg32')], + libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -159,6 +167,7 @@ include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'threefry')], + libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -168,6 +177,7 @@ include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'threefry32')], + libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -179,6 +189,7 @@ join( MOD_DIR, 'src', 'xoroshiro128')], + libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -189,6 +200,7 @@ include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), join(MOD_DIR, 'src', 'xorshift1024')], + libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), @@ -196,12 +208,14 @@ ["randomgen/generator.pyx", join(MOD_DIR, 'src', 'distributions', 'distributions.c')], + libraries=EXTRA_LIBRARIES, include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), Extension("randomgen.common", ["randomgen/common.pyx"], + libraries=EXTRA_LIBRARIES, include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS @@ -210,6 +224,7 @@ ["randomgen/bounded_integers.pyx", join(MOD_DIR, 'src', 'distributions', 'distributions.c')], + libraries=EXTRA_LIBRARIES, include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS @@ -219,6 +234,7 @@ join(MOD_DIR, 'src', 'legacy', 'distributions-boxmuller.c'), join(MOD_DIR, 'src', 'distributions', 'distributions.c')], + libraries=EXTRA_LIBRARIES, include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()] + [join(MOD_DIR, 'legacy')], extra_compile_args=EXTRA_COMPILE_ARGS, From 2d15ae44a3fc0198f33dae05478b35ce2a3cf288 Mon Sep 17 00:00:00 2001 From: Pierre de Buyl Date: Tue, 22 May 2018 13:24:06 +0200 Subject: [PATCH 123/279] typos in URLs --- _randomgen/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index c90d9e2256ce..f42150fdcd92 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -82,8 +82,8 @@ The RNGs include: generating doubles * [xoroshiro128+](http://xoroshiro.di.unimi.it/) and [xorshift1024*φ](http://xorshift.di.unimi.it/) -* [PCG64](http:w//www.pcg-random.org/) -* ThreeFry and Philox from [Random123](https://www.deshawrsearch.com/resources_random123.html) +* [PCG64](http://www.pcg-random.org/) +* ThreeFry and Philox from [Random123](https://www.deshawresearch.com/resources_random123.html) ## Differences from `numpy.random.RandomState` ### New Features From d16834c72f57996b46233ae336c18d05d3b309ba Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 12 Jun 2018 11:39:56 +0100 Subject: [PATCH 124/279] DOC: Fix doc and example error Ensure cython example works Add cimport for cython example --- _randomgen/doc/source/extending.rst | 2 +- _randomgen/randomgen/examples/cython/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/_randomgen/doc/source/extending.rst b/_randomgen/doc/source/extending.rst index 764e3428b066..c9d987b59ece 100644 --- a/_randomgen/doc/source/extending.rst +++ b/_randomgen/doc/source/extending.rst @@ -76,7 +76,7 @@ removing bounds checks and wrap around, providing array alignment information cimport cython from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from randomgen.common cimport * - from randomgen.distributions import random_gauss_zig + from randomgen.distributions cimport random_gauss_zig from randomgen.xoroshiro128 import Xoroshiro128 diff --git a/_randomgen/randomgen/examples/cython/setup.py b/_randomgen/randomgen/examples/cython/setup.py index bf6fb81486c6..d7a04f75a6c6 100644 --- a/_randomgen/randomgen/examples/cython/setup.py +++ b/_randomgen/randomgen/examples/cython/setup.py @@ -10,7 +10,7 @@ include_dirs=[np.get_include()]) distributions = Extension("extending_distributions", sources=['extending_distributions.pyx', - join('..', '..', 'randomgen', 'src', + join('..', '..', '..', 'randomgen', 'src', 'distributions', 'distributions.c')], include_dirs=[np.get_include()]) From 3bd8ddc3b57e485f82ab4628860269bb932a0ac7 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 14 Jun 2018 23:51:22 +0100 Subject: [PATCH 125/279] REF: Rename min and max macros Use MIN and MAX to avoid issues with c++ compilation --- .../randomgen/src/distributions/distributions.c | 14 +++++++------- .../randomgen/src/distributions/distributions.h | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 0e6e9cd578f5..a0966b6b0635 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -695,7 +695,7 @@ int64_t random_binomial_btpe(brng_t *brng_state, int64_t n, double p, binomial->nsave = n; binomial->psave = p; binomial->has_binomial = 1; - binomial->r = r = min(p, 1.0 - p); + binomial->r = r = MIN(p, 1.0 - p); binomial->q = q = 1.0 - r; binomial->fm = fm = n * r + r; binomial->m = m = (int64_t)floor(binomial->fm); @@ -836,7 +836,7 @@ int64_t random_binomial_inversion(brng_t *brng_state, int64_t n, double p, binomial->q = q = 1.0 - p; binomial->r = qn = exp(n * log(q)); binomial->c = np = n * p; - binomial->m = bound = (int64_t)min(n, np + 10.0 * sqrt(np * q + 1)); + binomial->m = bound = (int64_t)MIN(n, np + 10.0 * sqrt(np * q + 1)); } else { q = binomial->q; qn = binomial->r; @@ -1071,7 +1071,7 @@ int64_t random_hypergeometric_hyp(brng_t *brng_state, int64_t good, int64_t bad, double d2, u, y; d1 = bad + good - sample; - d2 = (double)min(bad, good); + d2 = (double)MIN(bad, good); y = d2; k = sample; @@ -1099,10 +1099,10 @@ int64_t random_hypergeometric_hrua(brng_t *brng_state, int64_t good, int64_t Z; double T, W, X, Y; - mingoodbad = min(good, bad); + mingoodbad = MIN(good, bad); popsize = good + bad; - maxgoodbad = max(good, bad); - m = min(sample, popsize - sample); + maxgoodbad = MAX(good, bad); + m = MIN(sample, popsize - sample); d4 = ((double)mingoodbad) / popsize; d5 = 1.0 - d4; d6 = m * d4 + 0.5; @@ -1111,7 +1111,7 @@ int64_t random_hypergeometric_hrua(brng_t *brng_state, int64_t good, d9 = (int64_t)floor((double)(m + 1) * (mingoodbad + 1) / (popsize + 2)); d10 = (loggam(d9 + 1) + loggam(mingoodbad - d9 + 1) + loggam(m - d9 + 1) + loggam(maxgoodbad - m + d9 + 1)); - d11 = min(min(m, mingoodbad) + 1.0, floor(d6 + 16 * d7)); + d11 = MIN(MIN(m, mingoodbad) + 1.0, floor(d6 + 16 * d7)); /* 16 for 16-decimal-digit precision in D1 and D2 */ while (1) { diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index 2dd453d3a734..707f3b455e35 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -40,9 +40,9 @@ static NPY_INLINE int64_t llabs(int64_t x) { #define DECLDIR extern #endif -#ifndef min -#define min(x, y) ((x < y) ? x : y) -#define max(x, y) ((x > y) ? x : y) +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? x : y) +#define MAX(x, y) (((x) > (y)) ? x : y) #endif #ifndef M_PI From ce22f0c5f507580f3710fcf981e24669c2c05486 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 19 Jun 2018 18:16:07 +0100 Subject: [PATCH 126/279] MAINT: Sync with NumPy changes Sync documentation changes from NumPy for 1.15 release --- _randomgen/README.md | 15 ++-- _randomgen/README.rst | 18 ++--- _randomgen/doc/source/change-log.rst | 2 + _randomgen/randomgen/generator.pyx | 106 ++++++++++++++------------- 4 files changed, 71 insertions(+), 70 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index f42150fdcd92..c2472dc76367 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -120,11 +120,10 @@ the RNG._ ## Status * Builds and passes all tests on: - * Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 (probably works on 2.6 and 3.3) + * Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 * PC-BSD (FreeBSD) 64-bit, Python 2.7 * OSX 64-bit, Python 3.6 - * Windows 32/64 bit (only tested on Python 2.7, 3.5 and 3.6, but - should work on 3.3/3.4) + * Windows 32/64 bit, Python 2.7, 3.5 and 3.6 ## Version The version matched the latest version of NumPy where @@ -148,7 +147,7 @@ need to be smoothed. Building requires: * Python (2.7, 3.4, 3.5, 3.6) - * NumPy (1.10, 1.11, 1.12, 1.13, 1.14) + * NumPy (1.11, 1.12, 1.13, 1.14, 1.15) * Cython (0.26+) * tempita (0.5+), if not provided by Cython @@ -183,10 +182,10 @@ python setup.py install --no-sse2 ### Windows Either use a binary installer, or if building from scratch, use -Python 3.6 with Visual Studio 2015 Community Edition. It can also be -build using Microsoft Visual C++ Compiler for Python 2.7 and Python 2.7, -although some modifications may be needed to `distutils` to find the -compiler. +Python 3.6 with Visual Studio 2015/2017 Community Edition. It can also +be build using Microsoft Visual C++ Compiler for Python 2.7 and +Python 2.7. + ## Using diff --git a/_randomgen/README.rst b/_randomgen/README.rst index 79252abc4347..b3fbc5fd0423 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -85,9 +85,9 @@ addition to the MT19937 that is included in NumPy. The RNGs include: at generating doubles - `xoroshiro128+ `__ and `xorshift1024\*φ `__ -- `PCG64 `__ +- `PCG64 `__ - ThreeFry and Philox from - `Random123 `__ + `Random123 `__ ## Differences from ``numpy.random.RandomState`` New Features @@ -129,12 +129,10 @@ Status ------ - Builds and passes all tests on: -- Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 (probably works on 2.6 and - 3.3) +- Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 - PC-BSD (FreeBSD) 64-bit, Python 2.7 - OSX 64-bit, Python 3.6 -- Windows 32/64 bit (only tested on Python 2.7, 3.5 and 3.6, but should - work on 3.3/3.4) +- Windows 32/64 bit, Python 2.7, 3.5 and 3.6 Version ------- @@ -165,7 +163,7 @@ Requirements Building requires: - Python (2.7, 3.4, 3.5, 3.6) -- NumPy (1.10, 1.11, 1.12, 1.13, 1.14) +- NumPy (1.11, 1.12, 1.13, 1.14, 1.15) - Cython (0.26+) - tempita (0.5+), if not provided by Cython @@ -206,10 +204,8 @@ Windows ~~~~~~~ Either use a binary installer, or if building from scratch, use Python -3.6 with Visual Studio 2015 Community Edition. It can also be build -using Microsoft Visual C++ Compiler for Python 2.7 and Python 2.7, -although some modifications may be needed to ``distutils`` to find the -compiler. +3.6 with Visual Studio 2015/2017 Community Edition. It can also be build +using Microsoft Visual C++ Compiler for Python 2.7 and Python 2.7. Using ----- diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst index 271ee5647e13..6084925289ac 100644 --- a/_randomgen/doc/source/change-log.rst +++ b/_randomgen/doc/source/change-log.rst @@ -4,6 +4,8 @@ Change Log Changes since v1.14 =================== +- Synced upstream changes in permutation +- Synced upstream doc fixes - Added absolute_import to avoid import noise on Python 2.7 - Add legacy generator which allows NumPy replication - Improve type handling of integers diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 40a876aa48d3..1f51e6f48f7e 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -446,9 +446,9 @@ cdef class RandomGenerator: .. [1] Peyton Z. Peebles Jr., "Probability, Random Variables and Random Signal Principles", 4th ed, 2001, p. 57. .. [2] Wikipedia, "Poisson process", - http://en.wikipedia.org/wiki/Poisson_process + https://en.wikipedia.org/wiki/Poisson_process .. [3] Wikipedia, "Exponential distribution", - http://en.wikipedia.org/wiki/Exponential_distribution + https://en.wikipedia.org/wiki/Exponential_distribution """ return cont(&random_exponential, self._brng, size, self.lock, 1, @@ -612,7 +612,7 @@ cdef class RandomGenerator: See Also -------- - random.random_integers : similar to `randint`, only for the closed + random_integers : similar to `randint`, only for the closed interval [`low`, `high`], and 1 is the lowest value if `high` is omitted. In particular, this other one is the one to use to generate uniformly distributed discrete non-integers. @@ -1305,7 +1305,7 @@ cdef class RandomGenerator: References ---------- .. [1] Wikipedia, "Normal distribution", - http://en.wikipedia.org/wiki/Normal_distribution + https://en.wikipedia.org/wiki/Normal_distribution .. [2] P. R. Peebles Jr., "Central Limit Theorem" in "Probability, Random Variables and Random Signal Principles", 4th ed., 2001, pp. 51, 51, 125. @@ -1559,7 +1559,7 @@ cdef class RandomGenerator: Wolfram Web Resource. http://mathworld.wolfram.com/GammaDistribution.html .. [2] Wikipedia, "Gamma distribution", - http://en.wikipedia.org/wiki/Gamma_distribution + https://en.wikipedia.org/wiki/Gamma_distribution Examples -------- @@ -1646,7 +1646,7 @@ cdef class RandomGenerator: Wolfram Web Resource. http://mathworld.wolfram.com/GammaDistribution.html .. [2] Wikipedia, "Gamma distribution", - http://en.wikipedia.org/wiki/Gamma_distribution + https://en.wikipedia.org/wiki/Gamma_distribution Examples -------- @@ -1725,7 +1725,7 @@ cdef class RandomGenerator: .. [1] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, Fifth Edition, 2002. .. [2] Wikipedia, "F-distribution", - http://en.wikipedia.org/wiki/F-distribution + https://en.wikipedia.org/wiki/F-distribution Examples -------- @@ -1805,7 +1805,7 @@ cdef class RandomGenerator: From MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/NoncentralF-Distribution.html .. [2] Wikipedia, "Noncentral F-distribution", - http://en.wikipedia.org/wiki/Noncentral_F-distribution + https://en.wikipedia.org/wiki/Noncentral_F-distribution Examples -------- @@ -1887,7 +1887,7 @@ cdef class RandomGenerator: References ---------- .. [1] NIST "Engineering Statistics Handbook" - http://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm + https://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm Examples -------- @@ -1949,7 +1949,7 @@ cdef class RandomGenerator: the analysis of weapon systems effectiveness", Metrika, Volume 15, Number 1 / December, 1970. .. [2] Wikipedia, "Noncentral chi-square distribution" - http://en.wikipedia.org/wiki/Noncentral_chi-square_distribution + https://en.wikipedia.org/wiki/Noncentral_chi-square_distribution Examples -------- @@ -2034,7 +2034,7 @@ cdef class RandomGenerator: Wolfram Web Resource. http://mathworld.wolfram.com/CauchyDistribution.html .. [3] Wikipedia, "Cauchy distribution" - http://en.wikipedia.org/wiki/Cauchy_distribution + https://en.wikipedia.org/wiki/Cauchy_distribution Examples -------- @@ -2097,7 +2097,7 @@ cdef class RandomGenerator: .. [1] Dalgaard, Peter, "Introductory Statistics With R", Springer, 2002. .. [2] Wikipedia, "Student's t-distribution" - http://en.wikipedia.org/wiki/Student's_t-distribution + https://en.wikipedia.org/wiki/Student's_t-distribution Examples -------- @@ -2300,7 +2300,7 @@ cdef class RandomGenerator: .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme Values, Birkhauser Verlag, Basel, pp 23-30. .. [4] Wikipedia, "Pareto distribution", - http://en.wikipedia.org/wiki/Pareto_distribution + https://en.wikipedia.org/wiki/Pareto_distribution Examples -------- @@ -2393,7 +2393,7 @@ cdef class RandomGenerator: Wide Applicability", Journal Of Applied Mechanics ASME Paper 1951. .. [3] Wikipedia, "Weibull distribution", - http://en.wikipedia.org/wiki/Weibull_distribution + https://en.wikipedia.org/wiki/Weibull_distribution Examples -------- @@ -2576,7 +2576,7 @@ cdef class RandomGenerator: From MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/LaplaceDistribution.html .. [4] Wikipedia, "Laplace distribution", - http://en.wikipedia.org/wiki/Laplace_distribution + https://en.wikipedia.org/wiki/Laplace_distribution Examples -------- @@ -2778,7 +2778,7 @@ cdef class RandomGenerator: MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/LogisticDistribution.html .. [3] Wikipedia, "Logistic-distribution", - http://en.wikipedia.org/wiki/Logistic_distribution + https://en.wikipedia.org/wiki/Logistic_distribution Examples -------- @@ -2858,7 +2858,7 @@ cdef class RandomGenerator: .. [1] Limpert, E., Stahel, W. A., and Abbt, M., "Log-normal Distributions across the Sciences: Keys and Clues," BioScience, Vol. 51, No. 5, May, 2001. - http://stat.ethz.ch/~stahel/lognormal/bioscience.pdf + https://stat.ethz.ch/~stahel/lognormal/bioscience.pdf .. [2] Reiss, R.D. and Thomas, M., "Statistical Analysis of Extreme Values," Basel: Birkhauser Verlag, 2001, pp. 31-32. @@ -2950,9 +2950,9 @@ cdef class RandomGenerator: References ---------- .. [1] Brighton Webs Ltd., "Rayleigh Distribution," - http://www.brighton-webs.co.uk/distributions/rayleigh.asp + https://web.archive.org/web/20090514091424/http://brighton-webs.co.uk:80/distributions/rayleigh.asp .. [2] Wikipedia, "Rayleigh distribution" - http://en.wikipedia.org/wiki/Rayleigh_distribution + https://en.wikipedia.org/wiki/Rayleigh_distribution Examples -------- @@ -3026,12 +3026,12 @@ cdef class RandomGenerator: References ---------- .. [1] Brighton Webs Ltd., Wald Distribution, - http://www.brighton-webs.co.uk/distributions/wald.asp + https://web.archive.org/web/20090423014010/http://www.brighton-webs.co.uk:80/distributions/wald.asp .. [2] Chhikara, Raj S., and Folks, J. Leroy, "The Inverse Gaussian Distribution: Theory : Methodology, and Applications", CRC Press, 1988. .. [3] Wikipedia, "Wald distribution" - http://en.wikipedia.org/wiki/Wald_distribution + https://en.wikipedia.org/wiki/Wald_distribution Examples -------- @@ -3098,7 +3098,7 @@ cdef class RandomGenerator: References ---------- .. [1] Wikipedia, "Triangular distribution" - http://en.wikipedia.org/wiki/Triangular_distribution + https://en.wikipedia.org/wiki/Triangular_distribution Examples -------- @@ -3211,7 +3211,7 @@ cdef class RandomGenerator: Wolfram Web Resource. http://mathworld.wolfram.com/BinomialDistribution.html .. [5] Wikipedia, "Binomial distribution", - http://en.wikipedia.org/wiki/Binomial_distribution + https://en.wikipedia.org/wiki/Binomial_distribution Examples -------- @@ -3297,7 +3297,7 @@ cdef class RandomGenerator: Draw samples from a negative binomial distribution. Samples are drawn from a negative binomial distribution with specified - parameters, `n` trials and `p` probability of failure where `n` is an + parameters, `n` successes and `p` probability of success where `n` is an integer > 0 and `p` is in the interval [0, 1]. Parameters @@ -3317,8 +3317,8 @@ cdef class RandomGenerator: ------- out : ndarray or scalar Drawn samples from the parameterized negative binomial distribution, - where each sample is equal to N, the number of successes that - occurred before n failures, and a failure on the (N + n)th trial. + where each sample is equal to N, the number of failures that + occurred before a total of n successes was reached. Notes ----- @@ -3327,10 +3327,9 @@ cdef class RandomGenerator: .. math:: P(N;n,p) = \\binom{N+n-1}{N}p^{n}(1-p)^{N}, where :math:`n` is the number of successes, :math:`p` is the - probability of failure, and :math:`N+n` is the number of trials. - The negative binomial distribution gives the probability of n - successes and N failures in N+n trials, and a success on the (N+n)th - trial. + probability of success, and :math:`N+n` is the number of trials. + The negative binomial distribution gives the probability of N + failures given n successes, with a success on the last trial. If one throws a die repeatedly until the third time a "1" appears, then the probability distribution of the number of non-"1"s that @@ -3342,7 +3341,7 @@ cdef class RandomGenerator: MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/NegativeBinomialDistribution.html .. [2] Wikipedia, "Negative binomial distribution", - http://en.wikipedia.org/wiki/Negative_binomial_distribution + https://en.wikipedia.org/wiki/Negative_binomial_distribution Examples -------- @@ -3411,7 +3410,7 @@ cdef class RandomGenerator: From MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/PoissonDistribution.html .. [2] Wikipedia, "Poisson distribution", - http://en.wikipedia.org/wiki/Poisson_distribution + https://en.wikipedia.org/wiki/Poisson_distribution Examples -------- @@ -3633,7 +3632,7 @@ cdef class RandomGenerator: MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/HypergeometricDistribution.html .. [3] Wikipedia, "Hypergeometric distribution", - http://en.wikipedia.org/wiki/Hypergeometric_distribution + https://en.wikipedia.org/wiki/Hypergeometric_distribution Examples -------- @@ -3743,7 +3742,7 @@ cdef class RandomGenerator: .. [3] D. J. Hand, F. Daly, D. Lunn, E. Ostrowski, A Handbook of Small Data Sets, CRC Press, 1994. .. [4] Wikipedia, "Logarithmic distribution", - http://en.wikipedia.org/wiki/Logarithmic_distribution + https://en.wikipedia.org/wiki/Logarithmic_distribution Examples -------- @@ -4089,9 +4088,9 @@ cdef class RandomGenerator: ---------- .. [1] David McKay, "Information Theory, Inference and Learning Algorithms," chapter 23, - http://www.inference.phy.cam.ac.uk/mackay/ + http://www.inference.org.uk/mackay/itila/ .. [2] Wikipedia, "Dirichlet distribution", - http://en.wikipedia.org/wiki/Dirichlet_distribution + https://en.wikipedia.org/wiki/Dirichlet_distribution Examples -------- @@ -4264,45 +4263,50 @@ cdef class RandomGenerator: def permutation(self, object x): """ permutation(x) - Randomly permute a sequence, or return a permuted range. - If `x` is a multi-dimensional array, it is only shuffled along its first index. - Parameters ---------- x : int or array_like If `x` is an integer, randomly permute ``np.arange(x)``. If `x` is an array, make a copy and shuffle the elements randomly. - Returns ------- out : ndarray Permuted sequence or array range. - Examples -------- - >>> randomgen.permutation(10) + >>> np.random.permutation(10) array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) - - >>> randomgen.permutation([1, 4, 9, 12, 15]) + >>> np.random.permutation([1, 4, 9, 12, 15]) array([15, 1, 9, 4, 12]) - >>> arr = np.arange(9).reshape((3, 3)) - >>> randomgen.permutation(arr) + >>> np.random.permutation(arr) array([[6, 7, 8], [0, 1, 2], [3, 4, 5]]) - """ if isinstance(x, (int, long, np.integer)): arr = np.arange(x) - else: - arr = np.array(x) - self.shuffle(arr) - return arr + self.shuffle(arr) + return arr + + arr = np.asarray(x) + + # shuffle has fast-path for 1-d + if arr.ndim == 1: + # must return a copy + if arr is x: + arr = np.array(arr) + self.shuffle(arr) + return arr + + # Shuffle index array, dtype to ensure fast path + idx = np.arange(arr.shape[0], dtype=np.intp) + self.shuffle(idx) + return arr[idx] _random_generator = RandomGenerator() From 6ade4aaec4a5ab2a7fa1dc1ab2f8a5dae1e2ac15 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 3 Jul 2018 17:26:27 +0100 Subject: [PATCH 127/279] ENH: Allow empty choice Allow empty choices to sync with upstream changes --- _randomgen/README.md | 193 ++++++++++-------- _randomgen/README.rst | 184 +++++++++-------- _randomgen/randomgen/generator.pyx | 16 +- .../randomgen/tests/test_numpy_mt19937.py | 8 + 4 files changed, 223 insertions(+), 178 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index c2472dc76367..eec9bdc753e5 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -23,14 +23,13 @@ which can fully reproduce the sequence produced by NumPy. * Replacement for NumPy's RandomState -```python -# import numpy.random as rnd -from randomgen import RandomGenerator, MT19937 -rnd = RandomGenerator(MT19937()) -x = rnd.standard_normal(100) -y = rnd.random_sample(100) -z = rnd.randn(10,10) -``` + ```python + from randomgen import RandomGenerator, MT19937 + rnd = RandomGenerator(MT19937()) + x = rnd.standard_normal(100) + y = rnd.random_sample(100) + z = rnd.randn(10,10) + ``` * Default random generator is a fast generator called Xoroshiro128plus * Support for random number generators that support independent streams @@ -38,22 +37,22 @@ z = rnd.randn(10,10) * Faster random number generation, especially for normal, standard exponential and standard gamma using the Ziggurat method -```python -from randomgen import RandomGenerator -# Use Xoroshiro128 -rnd = RandomGenerator() -w = rnd.standard_normal(10000, method='zig') -x = rnd.standard_exponential(10000, method='zig') -y = rnd.standard_gamma(5.5, 10000, method='zig') -``` + ```python + from randomgen import RandomGenerator + # Default basic PRNG is Xoroshiro128 + rnd = RandomGenerator() + w = rnd.standard_normal(10000, method='zig') + x = rnd.standard_exponential(10000, method='zig') + y = rnd.standard_gamma(5.5, 10000, method='zig') + ``` * Support for 32-bit floating randoms for core generators. Currently supported: - * Uniforms (`random_sample`) - * Exponentials (`standard_exponential`, both Inverse CDF and Ziggurat) - * Normals (`standard_normal`) - * Standard Gammas (via `standard_gamma`) + * Uniforms (`random_sample`) + * Exponentials (`standard_exponential`, both Inverse CDF and Ziggurat) + * Normals (`standard_normal`) + * Standard Gammas (via `standard_gamma`) **WARNING**: The 32-bit generators are **experimental** and subject to change. @@ -64,10 +63,10 @@ y = rnd.standard_gamma(5.5, 10000, method='zig') * Support for filling existing arrays using `out` keyword argument. Currently supported in (both 32- and 64-bit outputs) - * Uniforms (`random_sample`) - * Exponentials (`standard_exponential`) - * Normals (`standard_normal`) - * Standard Gammas (via `standard_gamma`) + * Uniforms (`random_sample`) + * Exponentials (`standard_exponential`) + * Normals (`standard_normal`) + * Standard Gammas (via `standard_gamma`) ## Included Pseudo Random Number Generators @@ -84,9 +83,11 @@ The RNGs include: [xorshift1024*φ](http://xorshift.di.unimi.it/) * [PCG64](http://www.pcg-random.org/) * ThreeFry and Philox from [Random123](https://www.deshawresearch.com/resources_random123.html) + ## Differences from `numpy.random.RandomState` ### New Features + * `standard_normal`, `normal`, `randn` and `multivariate_normal` all use the much faster (100%+) Ziggurat method. * `standard_gamma` and `gamma` both use the much faster Ziggurat method. @@ -101,21 +102,20 @@ The RNGs include: `out` keyword argument * Standardizes integer-values random values as int64 for all platforms. - ### New Functions -* `random_entropy` - Read from the system entropy provider, which is -commonly used in cryptographic applications -* `random_raw` - Direct access to the values produced by the underlying -PRNG. The range of the values returned depends on the specifics of the -PRNG implementation. +* `random_entropy` - Read from the system entropy provider, which is + commonly used in cryptographic applications +* `random_raw` - Direct access to the values produced by the underlying + PRNG. The range of the values returned depends on the specifics of the + PRNG implementation. * `random_uintegers` - unsigned integers, either 32- (`[0, 2**32-1]`) -or 64-bit (`[0, 2**64-1]`) -* `jump` - Jumps RNGs that support it. `jump` moves the state a great -distance. _Only available if supported by the RNG._ -* `advance` - Advanced the RNG 'as-if' a number of draws were made, -without actually drawing the numbers. _Only available if supported by -the RNG._ + or 64-bit (`[0, 2**64-1]`) +* `jump` - Jumps RNGs that support it. `jump` moves the state a great + distance. _Only available if supported by the RNG._ +* `advance` - Advanced the RNG 'as-if' a number of draws were made, + without actually drawing the numbers. _Only available if supported by + the RNG._ ## Status @@ -126,53 +126,70 @@ the RNG._ * Windows 32/64 bit, Python 2.7, 3.5 and 3.6 ## Version -The version matched the latest version of NumPy where + +The version matched the latest version of NumPy where `RandomGenerator(MT19937())` passes all NumPy test. ## Documentation Documentation for the latest release is available on -[my GitHub pages](http://bashtage.github.io/randomgen/). Documentation for -the latest commit (unreleased) is available under +[my GitHub pages](http://bashtage.github.io/randomgen/). Documentation for +the latest commit (unreleased) is available under [devel](http://bashtage.github.io/randomgen/devel/). ## Plans + This module is essentially complete. There are a few rough edges that need to be smoothed. -* Creation of additional streams from where supported +* Creation of additional streams from where supported (i.e. a `next_stream()` method) ## Requirements Building requires: - * Python (2.7, 3.4, 3.5, 3.6) - * NumPy (1.11, 1.12, 1.13, 1.14, 1.15) - * Cython (0.26+) - * tempita (0.5+), if not provided by Cython +* Python (2.7, 3.4, 3.5, 3.6) +* NumPy (1.11, 1.12, 1.13, 1.14, 1.15) +* Cython (0.26+) +* tempita (0.5+), if not provided by Cython Testing requires pytest (3.0+). -**Note:** it might work with other versions but only tested with these -versions. +**Note:** it might work with other versions but only tested with these +versions. ## Development and Testing -All development has been on 64-bit Linux, and it is regularly tested on +All development has been on 64-bit Linux, and it is regularly tested on Travis-CI (Linux/OSX) and Appveyor (Windows). The library is occasionally tested on Linux 32-bit and Free BSD 11.1. -Basic tests are in place for all RNGs. The MT19937 is tested against +Basic tests are in place for all RNGs. The MT19937 is tested against NumPy's implementation for identical results. It also passes NumPy's test suite where still relevant. ## Installing +Either install from PyPi using + +```bash +pip install randomgen +``` + +or, if you want the latest version, + +```bash +pip install git+https://github.com/bashtage/randomgen.git +``` + +or from a cloned repo, + ```bash python setup.py install ``` ### SSE2 + `dSFTM` makes use of SSE2 by default. If you have a very old computer or are building on non-x86, you can install using: @@ -181,12 +198,12 @@ python setup.py install --no-sse2 ``` ### Windows + Either use a binary installer, or if building from scratch, use Python 3.6 with Visual Studio 2015/2017 Community Edition. It can also be build using Microsoft Visual C++ Compiler for Python 2.7 and Python 2.7. - ## Using The separate generators are importable from `randomgen` @@ -205,46 +222,46 @@ rg.random_sample(100) ``` ## License + Standard NCSA, plus sub licenses for components. ## Performance -Performance is promising, and even the mt19937 seems to be faster than -NumPy's mt19937. -``` -Speed-up relative to NumPy (Uniform Doubles) -************************************************************ -DSFMT 137.1% -MT19937 21.0% -PCG32 101.2% -PCG64 110.7% -Philox -2.7% -ThreeFry -11.4% -ThreeFry32 -62.3% -Xoroshiro128 181.4% -Xorshift1024 141.8% - -Speed-up relative to NumPy (64-bit unsigned integers) -************************************************************ -DSFMT 24.8% -MT19937 15.0% -PCG32 92.6% -PCG64 99.0% -Philox -20.4% -ThreeFry -21.7% -ThreeFry32 -64.4% -Xoroshiro128 164.2% -Xorshift1024 120.8% - -Speed-up relative to NumPy (Standard normals) -************************************************************ -DSFMT 299.4% -MT19937 271.2% -PCG32 364.5% -PCG64 364.2% -Philox 256.9% -ThreeFry 236.0% -ThreeFry32 97.0% -Xoroshiro128 477.4% -Xorshift1024 360.7% -``` +Performance is promising, and even the mt19937 seems to be faster than +NumPy's mt19937. + + Speed-up relative to NumPy (Uniform Doubles) + ************************************************************ + DSFMT 137.1% + MT19937 21.0% + PCG32 101.2% + PCG64 110.7% + Philox -2.7% + ThreeFry -11.4% + ThreeFry32 -62.3% + Xoroshiro128 181.4% + Xorshift1024 141.8% + + Speed-up relative to NumPy (64-bit unsigned integers) + ************************************************************ + DSFMT 24.8% + MT19937 15.0% + PCG32 92.6% + PCG64 99.0% + Philox -20.4% + ThreeFry -21.7% + ThreeFry32 -64.4% + Xoroshiro128 164.2% + Xorshift1024 120.8% + + Speed-up relative to NumPy (Standard normals) + ************************************************************ + DSFMT 299.4% + MT19937 271.2% + PCG32 364.5% + PCG64 364.2% + Philox 256.9% + ThreeFry 236.0% + ThreeFry32 97.0% + Xoroshiro128 477.4% + Xorshift1024 360.7% diff --git a/_randomgen/README.rst b/_randomgen/README.rst index b3fbc5fd0423..335a678b1a19 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -1,7 +1,10 @@ RandomGen ========= -|Travis Build Status| |Appveyor Build Status| |PyPI version| +`Travis Build Status `__ +`Appveyor Build +Status `__ +`PyPI version `__ Random Number Generator using settable Basic RNG interface for future NumPy RandomState evolution. @@ -23,16 +26,15 @@ NumPy. Features -------- -- Replacement for NumPy's RandomState +- Replacement for NumPy’s RandomState -.. code:: python + .. code:: python - # import numpy.random as rnd - from randomgen import RandomGenerator, MT19937 - rnd = RandomGenerator(MT19937()) - x = rnd.standard_normal(100) - y = rnd.random_sample(100) - z = rnd.randn(10,10) + from randomgen import RandomGenerator, MT19937 + rnd = RandomGenerator(MT19937()) + x = rnd.standard_normal(100) + y = rnd.random_sample(100) + z = rnd.randn(10,10) - Default random generator is a fast generator called Xoroshiro128plus - Support for random number generators that support independent streams @@ -40,14 +42,14 @@ Features - Faster random number generation, especially for normal, standard exponential and standard gamma using the Ziggurat method -.. code:: python + .. code:: python - from randomgen import RandomGenerator - # Use Xoroshiro128 - rnd = RandomGenerator() - w = rnd.standard_normal(10000, method='zig') - x = rnd.standard_exponential(10000, method='zig') - y = rnd.standard_gamma(5.5, 10000, method='zig') + from randomgen import RandomGenerator + # Default basic PRNG is Xoroshiro128 + rnd = RandomGenerator() + w = rnd.standard_normal(10000, method='zig') + x = rnd.standard_exponential(10000, method='zig') + y = rnd.standard_gamma(5.5, 10000, method='zig') - Support for 32-bit floating randoms for core generators. Currently supported: @@ -58,11 +60,11 @@ Features - Normals (``standard_normal``) - Standard Gammas (via ``standard_gamma``) -**WARNING**: The 32-bit generators are **experimental** and subject to -change. + **WARNING**: The 32-bit generators are **experimental** and subject + to change. -**Note**: There are *no* plans to extend the alternative precision -generation to all distributions. + **Note**: There are *no* plans to extend the alternative precision + generation to all distributions. - Support for filling existing arrays using ``out`` keyword argument. Currently supported in (both 32- and 64-bit outputs) @@ -84,11 +86,13 @@ addition to the MT19937 that is included in NumPy. The RNGs include: SSE2-aware version of the MT19937 generator that is especially fast at generating doubles - `xoroshiro128+ `__ and - `xorshift1024\*φ `__ + `xorshift1024*φ `__ - `PCG64 `__ - ThreeFry and Philox from `Random123 `__ - ## Differences from ``numpy.random.RandomState`` + +Differences from ``numpy.random.RandomState`` +--------------------------------------------- New Features ~~~~~~~~~~~~ @@ -121,7 +125,7 @@ New Functions (``[0, 2**32-1]``) or 64-bit (``[0, 2**64-1]``) - ``jump`` - Jumps RNGs that support it. ``jump`` moves the state a great distance. *Only available if supported by the RNG.* -- ``advance`` - Advanced the RNG 'as-if' a number of draws were made, +- ``advance`` - Advanced the RNG ‘as-if’ a number of draws were made, without actually drawing the numbers. *Only available if supported by the RNG.* @@ -129,10 +133,11 @@ Status ------ - Builds and passes all tests on: -- Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 -- PC-BSD (FreeBSD) 64-bit, Python 2.7 -- OSX 64-bit, Python 3.6 -- Windows 32/64 bit, Python 2.7, 3.5 and 3.6 + + - Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 + - PC-BSD (FreeBSD) 64-bit, Python 2.7 + - OSX 64-bit, Python 3.6 + - Windows 32/64 bit, Python 2.7, 3.5 and 3.6 Version ------- @@ -143,10 +148,10 @@ The version matched the latest version of NumPy where Documentation ------------- -| Documentation for the latest release is available on `my GitHub - pages `__. Documentation for the - latest commit (unreleased) is available under -| `devel `__. +Documentation for the latest release is available on `my GitHub +pages `__. Documentation for the +latest commit (unreleased) is available under +`devel `__. Plans ----- @@ -154,7 +159,7 @@ Plans This module is essentially complete. There are a few rough edges that need to be smoothed. -- Creation of additional streams from where supported (i.e. a +- Creation of additional streams from where supported (i.e. a ``next_stream()`` method) Requirements @@ -180,15 +185,29 @@ Travis-CI (Linux/OSX) and Appveyor (Windows). The library is occasionally tested on Linux 32-bit and Free BSD 11.1. Basic tests are in place for all RNGs. The MT19937 is tested against -NumPy's implementation for identical results. It also passes NumPy's +NumPy’s implementation for identical results. It also passes NumPy’s test suite where still relevant. Installing ---------- +Either install from PyPi using + +.. code:: bash + + pip install randomgen + +or, if you want the latest version, + +.. code:: bash + + pip install git+https://github.com/bashtage/randomgen.git + +or from a cloned repo, + .. code:: bash - python setup.py install + python setup.py install SSE2 ~~~~ @@ -198,7 +217,7 @@ or are building on non-x86, you can install using: .. code:: bash - python setup.py install --no-sse2 + python setup.py install --no-sse2 Windows ~~~~~~~ @@ -214,16 +233,16 @@ The separate generators are importable from ``randomgen`` .. code:: python - from randomgen import RandomGenerator, ThreeFry, PCG64, MT19937 - rg = RandomGenerator(ThreeFry()) - rg.random_sample(100) + from randomgen import RandomGenerator, ThreeFry, PCG64, MT19937 + rg = RandomGenerator(ThreeFry()) + rg.random_sample(100) - rg = RandomGenerator(PCG64()) - rg.random_sample(100) + rg = RandomGenerator(PCG64()) + rg.random_sample(100) - # Identical to NumPy - rg = RandomGenerator(MT19937()) - rg.random_sample(100) + # Identical to NumPy + rg = RandomGenerator(MT19937()) + rg.random_sample(100) License ------- @@ -234,49 +253,42 @@ Performance ----------- Performance is promising, and even the mt19937 seems to be faster than -NumPy's mt19937. +NumPy’s mt19937. :: - Speed-up relative to NumPy (Uniform Doubles) - ************************************************************ - DSFMT 137.1% - MT19937 21.0% - PCG32 101.2% - PCG64 110.7% - Philox -2.7% - ThreeFry -11.4% - ThreeFry32 -62.3% - Xoroshiro128 181.4% - Xorshift1024 141.8% - - Speed-up relative to NumPy (64-bit unsigned integers) - ************************************************************ - DSFMT 24.8% - MT19937 15.0% - PCG32 92.6% - PCG64 99.0% - Philox -20.4% - ThreeFry -21.7% - ThreeFry32 -64.4% - Xoroshiro128 164.2% - Xorshift1024 120.8% - - Speed-up relative to NumPy (Standard normals) - ************************************************************ - DSFMT 299.4% - MT19937 271.2% - PCG32 364.5% - PCG64 364.2% - Philox 256.9% - ThreeFry 236.0% - ThreeFry32 97.0% - Xoroshiro128 477.4% - Xorshift1024 360.7% - -.. |Travis Build Status| image:: https://travis-ci.org/bashtage/randomgen.svg?branch=master - :target: https://travis-ci.org/bashtage/randomgen -.. |Appveyor Build Status| image:: https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true - :target: https://ci.appveyor.com/project/bashtage/randomgen/branch/master -.. |PyPI version| image:: https://badge.fury.io/py/randomgen.svg - :target: https://pypi.org/project/randomgen/ + Speed-up relative to NumPy (Uniform Doubles) + ************************************************************ + DSFMT 137.1% + MT19937 21.0% + PCG32 101.2% + PCG64 110.7% + Philox -2.7% + ThreeFry -11.4% + ThreeFry32 -62.3% + Xoroshiro128 181.4% + Xorshift1024 141.8% + + Speed-up relative to NumPy (64-bit unsigned integers) + ************************************************************ + DSFMT 24.8% + MT19937 15.0% + PCG32 92.6% + PCG64 99.0% + Philox -20.4% + ThreeFry -21.7% + ThreeFry32 -64.4% + Xoroshiro128 164.2% + Xorshift1024 120.8% + + Speed-up relative to NumPy (Standard normals) + ************************************************************ + DSFMT 299.4% + MT19937 271.2% + PCG32 364.5% + PCG64 364.2% + Philox 256.9% + ThreeFry 236.0% + ThreeFry32 97.0% + Xoroshiro128 477.4% + Xorshift1024 360.7% diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 1f51e6f48f7e..88ca7090be68 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -791,14 +791,14 @@ cdef class RandomGenerator: pop_size = operator.index(a.item()) except TypeError: raise ValueError("a must be 1-dimensional or an integer") - if pop_size <= 0: - raise ValueError("a must be greater than 0") + if pop_size <= 0 and np.prod(size) != 0: + raise ValueError("a must be greater than 0 unless no samples are taken") elif a.ndim != 1: raise ValueError("a must be 1-dimensional") else: pop_size = a.shape[0] - if pop_size is 0: - raise ValueError("a must be non-empty") + if pop_size is 0 and np.prod(size) != 0: + raise ValueError("a cannot be empty unless no samples are taken") if p is not None: d = len(p) @@ -4263,30 +4263,38 @@ cdef class RandomGenerator: def permutation(self, object x): """ permutation(x) + Randomly permute a sequence, or return a permuted range. + If `x` is a multi-dimensional array, it is only shuffled along its first index. + Parameters ---------- x : int or array_like If `x` is an integer, randomly permute ``np.arange(x)``. If `x` is an array, make a copy and shuffle the elements randomly. + Returns ------- out : ndarray Permuted sequence or array range. + Examples -------- >>> np.random.permutation(10) array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) + >>> np.random.permutation([1, 4, 9, 12, 15]) array([15, 1, 9, 4, 12]) + >>> arr = np.arange(9).reshape((3, 3)) >>> np.random.permutation(arr) array([[6, 7, 8], [0, 1, 2], [3, 4, 5]]) + """ if isinstance(x, (int, long, np.integer)): arr = np.arange(x) diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 7fb2008cd8a4..6b3104d64c53 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -566,6 +566,14 @@ def test_choice_return_shape(self): assert_(mt19937.choice(6, s, replace=False, p=p).shape, s) assert_(mt19937.choice(np.arange(6), s, replace=True).shape, s) + # Check zero-size + assert_equal(mt19937.randint(0,0,(3,0,4)).shape, (3,0,4)) + assert_equal(mt19937.randint(0,-10,0).shape, (0,)) + assert_equal(mt19937.choice(0,0).shape, (0,)) + assert_equal(mt19937.choice([],(0,)).shape, (0,)) + assert_equal(mt19937.choice(['a', 'b'], size=(3, 0, 4)).shape, (3, 0, 4)) + assert_raises(ValueError, mt19937.choice, [], 10) + def test_bytes(self): mt19937.seed(self.seed) actual = mt19937.bytes(10) From f8dc0aeff688de2c1d3fdf9161187cefb1b10c5d Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 22 Sep 2018 06:28:02 +0100 Subject: [PATCH 128/279] DOC: Provide a better explanation of bounded int generation Clarify that the internal generator is closed on [low, high-1] even though the external interface is open [low, high) closes #26 --- _randomgen/randomgen/bounded_integers.pyx.in | 36 ++++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/_randomgen/randomgen/bounded_integers.pyx.in b/_randomgen/randomgen/bounded_integers.pyx.in index bdd31a84410c..d6a764590aa4 100644 --- a/_randomgen/randomgen/bounded_integers.pyx.in +++ b/_randomgen/randomgen/bounded_integers.pyx.in @@ -23,7 +23,14 @@ type_info = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000U {{ py: otype = nptype + '_' if nptype == 'bool' else nptype }} cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): - """Array path for smaller integer types""" + """ + Array path for smaller integer types + + This path is simpler since the high value in the open interval [low, high) + must be in-range for the next larger type, {{nptype_up}}. Here we case to + this type for checking and the recast to {{nptype}} when producing the + random integers. + """ cdef {{utype}}_t rng, last_rng, off, val, mask, out_val cdef uint32_t buf cdef {{utype}}_t *out_data @@ -61,6 +68,7 @@ cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object s for i in range(cnt): low_v = (<{{nptype_up}}_t*>np.PyArray_MultiIter_DATA(it, 0))[0] high_v = (<{{nptype_up}}_t*>np.PyArray_MultiIter_DATA(it, 1))[0] + # Subtract 1 since generator produces values on the closed int [off, off+rng] rng = <{{utype}}_t>((high_v - 1) - low_v) off = <{{utype}}_t>(<{{nptype_up}}_t>low_v) @@ -82,7 +90,18 @@ big_type_info = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFF {{for nptype, utype, npctype, lb, ub in big_type_info}} {{ py: otype = nptype}} cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, brng_t *state, object lock): - """Array path for 64-bit integer types""" + """ + Array path for 64-bit integer types + + Requires special treatment since the high value can be out-of-range for + the largest (64 bit) integer type since the generator is specified on the + interval [low,high). + + The internal generator does not have this issue since it generates from + the closes interval [low, high-1] and high-1 is always in range for the + 64 bit integer type. + """ + cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr cdef np.npy_intp i, cnt, n cdef np.broadcast it @@ -103,6 +122,7 @@ cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, brn cnt = np.PyArray_SIZE(high_arr) flat = high_arr.flat for i in range(cnt): + # Subtract 1 since generator produces values on the closed int [off, off+rng] closed_upper = int(flat[i]) - 1 if closed_upper > {{ub}}: raise ValueError('high is out of bounds for {{nptype}}') @@ -130,7 +150,8 @@ cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, brn for i in range(n): low_v = (<{{nptype}}_t*>np.PyArray_MultiIter_DATA(it, 0))[0] high_v = (<{{nptype}}_t*>np.PyArray_MultiIter_DATA(it, 1))[0] - rng = <{{utype}}_t>(high_v - low_v) # No -1 here since implemented above + # Generator produces values on the closed int [off, off+rng], -1 subtracted above + rng = <{{utype}}_t>(high_v - low_v) off = <{{utype}}_t>(<{{nptype}}_t>low_v) if rng != last_rng: @@ -190,6 +211,14 @@ cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state out : python scalar or ndarray of np.{{nptype}} `size`-shaped array of random integers from the appropriate distribution, or a single such random int if `size` not provided. + + Notes + ----- + The internal integer generator produces values from the closed + interval [low, high-1]. This requires some care since high can be + out-of-range for {{utype}}. The scalar path leaves integers as Python + integers until the 1 has been subtracted to avoid needing to cast + to a larger type. """ cdef np.ndarray out_arr, low_arr, high_arr cdef {{utype}}_t rng, off, out_val @@ -208,6 +237,7 @@ cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): low = int(low_arr) high = int(high_arr) + # Subtract 1 since internal generator produces on closed interval [low, high] high -= 1 if low < {{lb}}: From 8d9883a4786c69dde9f9ce24d7fe77b057e67d75 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 22 Sep 2018 07:45:02 +0100 Subject: [PATCH 129/279] MAINT: Sync with recent upstream changes Sync with Numpy 1.15 changes --- _randomgen/README.rst | 12 ++++++++---- _randomgen/randomgen/examples/numba/extending.py | 4 ++-- _randomgen/randomgen/generator.pyx | 12 ++++++------ _randomgen/randomgen/legacy/_legacy.pyx | 5 +++-- .../randomgen/src/distributions/distributions.c | 16 ++++++++-------- .../src/legacy/distributions-boxmuller.c | 2 +- _randomgen/randomgen/src/mt19937/randomkit.c | 2 +- _randomgen/randomgen/tests/test_against_numpy.py | 9 ++++++--- _randomgen/randomgen/tests/test_direct.py | 4 ++-- _randomgen/randomgen/tests/test_numpy_mt19937.py | 11 ++++++----- _randomgen/randomgen/tests/test_smoke.py | 5 ++++- 11 files changed, 47 insertions(+), 35 deletions(-) diff --git a/_randomgen/README.rst b/_randomgen/README.rst index 335a678b1a19..a0e35d584bc2 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -1,10 +1,7 @@ RandomGen ========= -`Travis Build Status `__ -`Appveyor Build -Status `__ -`PyPI version `__ +|Travis Build Status| |Appveyor Build Status| |PyPI version| Random Number Generator using settable Basic RNG interface for future NumPy RandomState evolution. @@ -292,3 +289,10 @@ NumPy’s mt19937. ThreeFry32 97.0% Xoroshiro128 477.4% Xorshift1024 360.7% + +.. |Travis Build Status| image:: https://travis-ci.org/bashtage/randomgen.svg?branch=master + :target: https://travis-ci.org/bashtage/randomgen +.. |Appveyor Build Status| image:: https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true + :target: https://ci.appveyor.com/project/bashtage/randomgen/branch/master +.. |PyPI version| image:: https://badge.fury.io/py/randomgen.svg + :target: https://pypi.org/project/randomgen/ diff --git a/_randomgen/randomgen/examples/numba/extending.py b/_randomgen/randomgen/examples/numba/extending.py index 866b4070d05a..4dafeb5c4d12 100644 --- a/_randomgen/randomgen/examples/numba/extending.py +++ b/_randomgen/randomgen/examples/numba/extending.py @@ -68,10 +68,10 @@ def normals(n, state): start = dt.datetime.now() normalsj(1000000, state_addr) ms = 1000 * (dt.datetime.now() - start).total_seconds() -print('1,000,000 Box-Muller (numba/Xoroshiro128) randoms in ' +print('1,000,000 Polar-transform (numba/Xoroshiro128) randoms in ' '{ms:0.1f}ms'.format(ms=ms)) start = dt.datetime.now() np.random.standard_normal(1000000) ms = 1000 * (dt.datetime.now() - start).total_seconds() -print('1,000,000 Box-Muller (NumPy) randoms in {ms:0.1f}ms'.format(ms=ms)) +print('1,000,000 Polar-transform (NumPy) randoms in {ms:0.1f}ms'.format(ms=ms)) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 88ca7090be68..a752aa84c285 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -798,7 +798,7 @@ cdef class RandomGenerator: else: pop_size = a.shape[0] if pop_size is 0 and np.prod(size) != 0: - raise ValueError("a cannot be empty unless no samples are taken") + raise ValueError("'a' cannot be empty unless no samples are taken") if p is not None: d = len(p) @@ -2102,7 +2102,7 @@ cdef class RandomGenerator: Examples -------- From Dalgaard page 83 [1]_, suppose the daily energy intake for 11 - women in Kj is: + women in kilojoules (kJ) is: >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\ ... 7515, 8230, 8770]) @@ -3606,12 +3606,12 @@ cdef class RandomGenerator: ----- The probability density for the Hypergeometric distribution is - .. math:: P(x) = \\frac{\\binom{m}{n}\\binom{N-m}{n-x}}{\\binom{N}{n}}, + .. math:: P(x) = \\frac{\\binom{g}{x}\\binom{b}{n-x}}{\\binom{g+b}{n}}, - where :math:`0 \\le x \\le m` and :math:`n+m-N \\le x \\le n` + where :math:`0 \\le x \\le n` and :math:`n-b \\le x \\le g` - for P(x) the probability of x successes, n = ngood, m = nbad, and - N = number of samples. + for P(x) the probability of x successes, g = ngood, b = nbad, and + n = number of samples. Consider an urn with black and white marbles in it, ngood of them black and nbad are white. If you draw nsample balls without diff --git a/_randomgen/randomgen/legacy/_legacy.pyx b/_randomgen/randomgen/legacy/_legacy.pyx index c264bd904ec9..a45ee829fbe5 100644 --- a/_randomgen/randomgen/legacy/_legacy.pyx +++ b/_randomgen/randomgen/legacy/_legacy.pyx @@ -171,14 +171,15 @@ cdef class _LegacyGenerator: Get or set the augmented state Returns the basic RNGs state as well as two values added to track - normal generation using the Box-Muller method. + normal generation using the Polar (Box-Muller-like) method. Returns ------- state : dict Dictionary containing the information required to describe the state of the Basic RNG with two additional fields, gauss and - has_gauss, required to store generated Box-Muller normals. + has_gauss, required to store generated Polar transformation + (Box-Muller-like) normals. """ st = self._basicrng.state st['has_gauss'] = self._aug_state.has_gauss diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index a0966b6b0635..26b6232c2915 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -49,9 +49,9 @@ double random_gauss(brng_t *brng_state) { r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); - // Box-Muller transform + /* Polar method, a more efficient version of the Box-Muller approach. f = sqrt(-2.0 * log(r2) / r2); - // Keep for next call + /* Keep for next call brng_state->gauss = f * x1; brng_state->has_gauss = true; return f * x2; @@ -73,9 +73,9 @@ float random_gauss_f(brng_t *brng_state) { r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); - // Box-Muller transform + /* Polar method, a more efficient version of the Box-Muller approach. f = sqrtf(-2.0f * logf(r2) / r2); - // Keep for next call + /* Keep for next call brng_state->gauss_f = f * x1; brng_state->has_gauss_f = true; return f * x2; @@ -108,7 +108,7 @@ static NPY_INLINE double standard_exponential_zig(brng_t *brng_state) { ri >>= 8; x = ri * we_double[idx]; if (ri < ke_double[idx]) { - return x; // 98.9% of the time we return here 1st try + return x; /* 98.9% of the time we return here 1st try */ } return standard_exponential_zig_unlikely(brng_state, idx, x); } @@ -150,7 +150,7 @@ static NPY_INLINE float standard_exponential_zig_f(brng_t *brng_state) { ri >>= 8; x = ri * we_float[idx]; if (ri < ke_float[idx]) { - return x; // 98.9% of the time we return here 1st try + return x; /* 98.9% of the time we return here 1st try */ } return standard_exponential_zig_unlikely_f(brng_state, idx, x); } @@ -176,7 +176,7 @@ static NPY_INLINE double next_gauss_zig(brng_t *brng_state) { if (sign & 0x1) x = -x; if (rabs < ki_double[idx]) - return x; // # 99.3% of the time return here + return x; /* 99.3% of the time return here */ if (idx == 0) { for (;;) { xx = -ziggurat_nor_inv_r * log(next_double(brng_state)); @@ -220,7 +220,7 @@ float random_gauss_zig_f(brng_t *brng_state) { if (sign & 0x1) x = -x; if (rabs < ki_float[idx]) - return x; // # 99.3% of the time return here + return x; /* # 99.3% of the time return here */ if (idx == 0) { for (;;) { xx = -ziggurat_nor_inv_r_f * logf(next_float(brng_state)); diff --git a/_randomgen/randomgen/src/legacy/distributions-boxmuller.c b/_randomgen/randomgen/src/legacy/distributions-boxmuller.c index 8d3d94095cc8..7ad1742cc585 100644 --- a/_randomgen/randomgen/src/legacy/distributions-boxmuller.c +++ b/_randomgen/randomgen/src/legacy/distributions-boxmuller.c @@ -19,7 +19,7 @@ double legacy_gauss(aug_brng_t *aug_state) { r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); - /* Box-Muller transform */ + /* Polar method, a more efficient version of the Box-Muller approach. */ f = sqrt(-2.0 * log(r2) / r2); /* Keep for next call */ aug_state->gauss = f * x1; diff --git a/_randomgen/randomgen/src/mt19937/randomkit.c b/_randomgen/randomgen/src/mt19937/randomkit.c index 947d2adb1067..f8ed4b49e2fd 100644 --- a/_randomgen/randomgen/src/mt19937/randomkit.c +++ b/_randomgen/randomgen/src/mt19937/randomkit.c @@ -568,7 +568,7 @@ double rk_gauss(rk_state *state) { r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); - /* Box-Muller transform */ + /* Polar method, a more efficient version of the Box-Muller approach. */ f = sqrt(-2.0 * log(r2) / r2); /* Keep for next call */ state->gauss = f * x1; diff --git a/_randomgen/randomgen/tests/test_against_numpy.py b/_randomgen/randomgen/tests/test_against_numpy.py index 46350cdd0127..ea2656e83fdc 100644 --- a/_randomgen/randomgen/tests/test_against_numpy.py +++ b/_randomgen/randomgen/tests/test_against_numpy.py @@ -4,6 +4,7 @@ import randomgen from randomgen import RandomGenerator, MT19937 +from randomgen._testing import suppress_warnings from randomgen.legacy import LegacyGenerator @@ -263,9 +264,11 @@ def test_vonmises(self): def test_random_integers(self): self._set_common_state() self._is_state_common() - compare_2_input(self.nprs.random_integers, - self.rg.random_integers, - is_scalar=True) + with suppress_warnings() as sup: + sup.record(DeprecationWarning) + compare_2_input(self.nprs.random_integers, + self.rg.random_integers, + is_scalar=True) self._is_state_common() def test_binomial(self): diff --git a/_randomgen/randomgen/tests/test_direct.py b/_randomgen/randomgen/tests/test_direct.py index c6cd00bd56d4..be4f533eadc5 100644 --- a/_randomgen/randomgen/tests/test_direct.py +++ b/_randomgen/randomgen/tests/test_direct.py @@ -146,7 +146,7 @@ def test_raw(self): uints = rs.random_raw(1000) assert_equal(uints, self.data2['data']) - @pytest.mark.skip(reason='Box-Muller no longer supported') + @pytest.mark.skip(reason='Polar transform no longer supported') def test_gauss_inv(self): n = 25 rs = RandomGenerator(self.brng(*self.data1['seed'])) @@ -352,7 +352,7 @@ def test_uniform_double(self): assert_equal(uniform_from_dsfmt(self.data2['data']), rs.random_sample(1000)) - @pytest.mark.skip(reason='Box-Muller no longer supported') + @pytest.mark.skip(reason='Polar transform no longer supported') def test_gauss_inv(self): n = 25 rs = RandomGenerator(self.brng(*self.data1['seed'])) diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 6b3104d64c53..2ab6bd2d326f 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -567,12 +567,13 @@ def test_choice_return_shape(self): assert_(mt19937.choice(np.arange(6), s, replace=True).shape, s) # Check zero-size - assert_equal(mt19937.randint(0,0,(3,0,4)).shape, (3,0,4)) - assert_equal(mt19937.randint(0,-10,0).shape, (0,)) - assert_equal(mt19937.choice(0,0).shape, (0,)) - assert_equal(mt19937.choice([],(0,)).shape, (0,)) + assert_equal(mt19937.randint(0, 0, size=(3, 0, 4)).shape, (3, 0, 4)) + assert_equal(mt19937.randint(0, -10, size=0).shape, (0,)) + assert_equal(mt19937.randint(10, 10, size=0).shape, (0,)) + assert_equal(mt19937.choice(0, size=0).shape, (0,)) + assert_equal(mt19937.choice([], size=(0,)).shape, (0,)) assert_equal(mt19937.choice(['a', 'b'], size=(3, 0, 4)).shape, (3, 0, 4)) - assert_raises(ValueError, mt19937.choice, [], 10) + assert_raises(ValueError, mt19937.choice, [], 10) def test_bytes(self): mt19937.seed(self.seed) diff --git a/_randomgen/randomgen/tests/test_smoke.py b/_randomgen/randomgen/tests/test_smoke.py index 34f95bc10cb0..99f218181d89 100644 --- a/_randomgen/randomgen/tests/test_smoke.py +++ b/_randomgen/randomgen/tests/test_smoke.py @@ -8,6 +8,7 @@ from numpy.testing import assert_almost_equal, assert_equal, assert_, \ assert_array_equal +from randomgen._testing import suppress_warnings from randomgen import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024 from randomgen import entropy @@ -467,7 +468,9 @@ def test_randint(self): assert_(len(vals) == 10) def test_random_integers(self): - vals = self.rg.random_integers(10, 20, 10) + with suppress_warnings() as sup: + sup.record(DeprecationWarning) + vals = self.rg.random_integers(10, 20, 10) assert_(len(vals) == 10) def test_rayleigh(self): From d1d3d10b6e674d7e70c5d63fcacf120902f71d3e Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 22 Sep 2018 08:07:49 +0100 Subject: [PATCH 130/279] DOC: Update docs for 1.15 release [skip ci] --- _randomgen/doc/source/change-log.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst index 6084925289ac..9cb5f0128081 100644 --- a/_randomgen/doc/source/change-log.rst +++ b/_randomgen/doc/source/change-log.rst @@ -1,9 +1,10 @@ Change Log ---------- -Changes since v1.14 -=================== - +v1.15 +===== +- Synced empty choice changes +- Synced upstream docstring changes - Synced upstream changes in permutation - Synced upstream doc fixes - Added absolute_import to avoid import noise on Python 2.7 @@ -12,5 +13,3 @@ Changes since v1.14 - Switch to array-fillers for 0 parameter distribution to improve performance - Small changes to build on manylinux - Build wheels using multibuild - - From 2e6c2d641ea8be76266c076b6f9618761b2c5370 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Wed, 3 Oct 2018 07:41:47 +0200 Subject: [PATCH 131/279] Added an alternative interval generator using Lemire's algorithm. he interval generator is used when generating 32-bit bounded random numbers. The speedup is 10% to 220% across the various RNGs compared to my pip Numpy. --- ...ation in an Interval - arxiv 1805.10941.pdf | Bin 0 -> 972756 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 _randomgen/papers/Fast Random Integer Generation in an Interval - arxiv 1805.10941.pdf diff --git a/_randomgen/papers/Fast Random Integer Generation in an Interval - arxiv 1805.10941.pdf b/_randomgen/papers/Fast Random Integer Generation in an Interval - arxiv 1805.10941.pdf new file mode 100644 index 0000000000000000000000000000000000000000..788cb2bec5b15ff65095194bed13df5a31f0d8ae GIT binary patch literal 972756 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 H|wh@Z0$_|s?!1%C6s@(|Gn zZC&=um*g5qNLM0_jyKCqkh~7Kjz4DjS=zs$tDl(<#DIh^ebn?gX(G>#AeCB*msg`- zIjyMq+c4II014FhrlpXVQEgsacAs~QB;Q27PGUHVnQg>!zly;*`(i~^s(386moy~~ z>zibjJ|Y0oJYbqMf_P?e|5X*Z{D`roA1czsJ6%sl=$>PzvkIrXGIXMSOY4LNZ!sk8 zI9D;6n*geIm*^Sl75F+asRmpNwXzs2> z9zJ<%(uNX&C8GTzU35V}xh`c!ttS~#=p12kXHir1x*!serSc`+fUM90qCA^)db={m zHm5SyE^w^|37H9#z=0#4;C=~rux<=(&}L{4EOdA*NB!EV34;zX!e!)U+;0&hlx>z| z0GIWbeU?(`M7oOTFpKT{ztR%f{13t?cP1lac@6Saq!r1=W* z366Ik_j9g*oy^g{z7`XgWZ_ZB$-+W{4WKn-1SU*Q1ne$Zc4>WGc4@fVIYx?{<@DW% zQg}`$7~RawYHP^8-R2>GDbh%yWX4=zI&Hj(ny?5XSNItRA8E+93vFWWgtrIQ)dfdj z8KvTmkw>M=2&^XZCfuXS&eoNV`!xQlvxM$07RWoX#p$T#+5r4zvJ?Of_@Whv1o8U-N9W@JCK;eX!m1^D8I35fskNT$DcD zym{~n_TIed1mJz81u8GmXUE+j$78;!xWQri1lKsjb==AyFM4k3@Imu7nSMaR;wg!J zbt}Wg^%}mW5VyR1Na^Eg{dtK7STOWeHvFdyax+yduhUSH7#42=01_-Pae)#HTqhLl z8F(6FV4f5h+#6&tO3r(Tn7^Vafq5LY`2tPS`olD8yN$8bvIyTkAJtL(OQ_)0ZT8`B z1Jo0>Ql2TmyAxUw--(d@lA#50?@gb!4B0~U1WJOh!BCjOZ^yKjTJ3PUnQJ$hZKZkr zvON8};WO4~see~X+iChSpLF7dfBM{c&Na$D(S9qhl09VizE%U-r}x~#jwwx1kL(=n z`b0TlVcZ+4XYT!W`E1%O-!9!}L-?%G7+0cUf->}Ac13|kt*FXWV#hK+ls_KRK;;Tv z4RPLCU!hh^0CMq}VIKXBU1+MmcEc{ za_Fjhw(Vx2%It3XWsfy|AS9e?^tcOfFAa_sNQH?-p-4O{NN#h*|cV2~*k?HI)h%e;Ty6}YC zAEI$RT~Wkp4N%k8WX&EQK$cIUfNREFfl^fgnyJs8w8d+2o9@I`(sNDWFOreEklc zu#56r-%D)J2emFyk?V`rYapJVB!qGLv;^0P$pQ2e1g9wii>A->e1AZAd(VddGYiSW z@c*-FkBQ}<+VcPGVtB13>3qnB*88b`N1+~za0TFP1}ABn`DBtLb)fAI*F>_JBaxzA zUuxYHoY*Iq-3qBv&~W1 zv=n-hEVzb5Y%Tupo~5kU{t^P|R6(Ntm*>t^^>t}3 zjXnuC_N7uvi00o5r?&Mj&c}+}8QJR63$te3dOjKS<+^pX)z6awD(II*n+CFG(t*6g ztojbbYYIk;5lKr|?ub!DGY%mnD=v&LR&rs1!(13VF^+!BLD>E)QwK_hxN3+Yd?)U- z;U*(4j8NIfMm^*%nT{3_24xvc;+XStt+Gs8`*c|_kB)09NtMcc(E+y_{UM}pC}Xa> zqgEj36r%>@JZB40j@#kx;JK3(qcjU!dAhR5r6Ts%l=PRgbIcKgAI-ZF{E+%bfZ$me zN?21o0~zHaktljMfJ%{2(#DiOo4)y*5E>$`X&$nqGnvrTQak6Ihu`Hn`r1U5Uo2~1 zk85F=LBeu?O-iC_C#N>W6;^Fsv$i1nLuN9`T#(pSuMv@zSmT8}VdxUw2S6wYlg(GBRP5 z4bm-e2RDtC;!WY~W({u-8cXs>XZpEg*v&HK}J zKu^Zv4vwIi_ zOrsJ^2?xx{G(8L+Cc9$33kN%oO5vv{g?H`@7gNp^62{^U^WiIq+WG0CSxm<;mbL$( zQI)3VQ<5j*Vw)Fn(sItK z=4g+){4F=kCxk`DdQ`Q-^B&J~Vx&eG!D97G)^6H7KR#{WI8+}sVVu&J<@mB%NoM|_9T06*kH5+Bl01C_u6PnjBT8VMEP$B6Pcm4jT z5Yp&)M!a_4!5ZDq{c_zZ6(iZYt(PWb^yGkzN7&S5Dw2s@)fxghxJF_;ClwRCK8G3& z*40rT7*3KcW36HetjjR(v#6;%x(gX<6;d21F~gqMTfbKOTEw~0f-dhqM{aykryTiF z(r1h>`1Wq>Q!Wi5ROmXg#ako-3CkCRkm$vk#0BD}UuN3d4~na<@8kKhfDK-KHTgpC z1++En{cf)L?N-$3eJ=XoU%wnABYQ*^(f!ixF5qg4f7Et@Wzr5EEE4}Ti;C6Tv*WAl zs|oGI^;(y-o7`YYDU2lw0FhLVM1iI&DnAm#ovfx1f8^W}t;kx9iAYga*bPy=%CS+U zD)uyQ?Mrr^7S+yrIgCj>#k_UQv002Y2c0WeNq~SnII#{r$&JEu@GiA3Ovg!Kbll0n zdQxjL-sF@LjE7;Hiu3S*tXWX3THgg2<0=Uwnp2OJf|RR@)MFA^MUte2OBhu9r&QmP zwDs>EFdO*@MUWtA-L{#uBc$R3Z`;_2%w=mWsED6z_LxG z!xCql0zyT~mbmta23u`ImLwofx-5 z4vtGQWwn`GuBvTD=^aH8jwr=Uqt|NwZsg!1*7DbI~3{$*xTdi%RJ2m2uT zdg`(trV?5TrMB^cWgY>1943;Y3jV6?&e^k-6e4FT3swHE33`$lFkzzy`UThM1$|*s;rVp6@VbAp12H4ECs?+nN$?n zC9lT?-pY_&j73IW1kzzO zv-*RBKgZ?zYmP$d(lf#ksLAWS>otN>&M6A`os@=aKF!vHwRd)jciK{r&)~@VhzJw)7l5r5lTy?MaBCcDb zGk(#JVx~AZtvf8&Zm+J$URo7Cn}L5jSMk9vI0;TwLVfw8L$H0>Zvs1_A{;xXR2SUz z-^%``NBul8@5YIu+&NwwT1)Wh5pTJOWq0^(GDXD5a=eDadoW6Ma&L=AbvfXExM6f` zwYCXG*C!8(ky6{W5Rc+Y_{|53^mJVrJrRA$GhLgLB;F{G6b?xa`yF~IjZYR;UpiV} z!T(*WM*KgcIcAps5zYNCDznBvF0-kz3jw{dtC7op$<1Q+PXDOQLPGW)1ls?WGY~Md zF%U2@vJvP){lB-d{?7;h-RvL9S=`Cq)q#MC^*;?#mHux6G$SK36DJhCf{LgH-9ISX zRL;=Wlz@Vc-pvn{81K7jb2me=WBEYZ)^9_aQ7u@Xs@2!+#?m z-+y9MdNF%Dm;X+g(K68fI~*(L|8m!imhnI4zw`drdox<5|C;|1RQ-1tGg{{VnoR%8 z88cdz|C-GIo&E35|1$v2snykJ!}*AdKug0|9SlPzmHw@M}EeoG5Z~SO1@7_Ji{aN z&Y#bpL?{1NqCxj~f4{Fo$GTfx{%88t$GpeL{MVWX8q%+$Wact`kwcXw`k_CP@;Kf z832C2S#kDYoc!x%TY{gO>GGeNPqTn~^oCn`rXT+UN&IF1F1MRG^!~Y;-fu8*8UqP$8%}2eIkT=6omLnm6Vjoqb;$I>Qjs@p$OQ zmD4lg*%9PC#^-rvleZ=Xy4V=S`nj1~%lW#V$}x_%?k}6q)nfmiUmhU%<#uN}$#>_G z=X-KrEd%uy$BFYP(pDVrkCgGzxfX`of%SCy*?6AQ#RDl$-pk*iex=@%4@zihsH^dr za`z1HtM~2vDC5}Ti5d0eTE~t<=8~83_e^cO)?x zXva3_r#d`wSFghVEgKN3Tq4gPz6XL?G89g00Mm+E_XqxwpW0ZOG!5xAyg{^P6X>iodFF$RE=ouE3 zFhy*#J&l~YCJJFhGrV_*UG!NaneL#OjKVvdCs%Xu+t|%xZbUH{dfzf`G{Jd&9y7AsLwt+>$o;c9J(o&u+FSDUk;Y$Y##!$kf-Ap|i6sn^+Ow<3U~-$1<^;yCNjk$=JvZYoIVy zzGc+`Gyh-(GKY0V*=2MZ2$|#T8=_z{uIrnQ$)LU?S_>*eiFyL3TzVgCj4l*fLJ|(0 zk%Us!RySbbRZfy^G$dcUxU7Wrk$PnG*Q+ZFV9GfA+BBPsd(cgVZwR0nfKL32+ ziy3^@eMhZB9rwSI{-^KTVR+2?Ypi|mY2mBl7xM7OGacD195C(C@fHT5QZrnAAX0S&4MK;tpo`J84KX;LJ-i`h&=Ta;?7=!_EgCu)4oQ zAqm73Oeu|-n+=-syyF%Ube6{L_tg%K5!}J#FNyFR)#JOVGUd&L4P^?Apdj5y zTCBDNWfM3=nS>I8jPIMC=24*yfp&n(SzddBRA~mo2-Rl)++R`JOU@Xi*YDDKQA2@3 zLpKL`<*1i?(!}QiJE}qm@<3_0=1U}uGVs$Qq^lFxt(CARphUP0SQ^_$Ikur0?t!L% zia2?jH>&d2A2UCSX*PZ8=Q(oP^UK@G-+HdECS{u2+?eUAJCJ>tJY-GyuuX1X76$8o z!OT>*%i#G@HGMg$a8hZy=)_%NXCACmQe@3o7ak^rnO=OlY9v?mZ6r3^@M|Tz#D>5( zXss$F3vv8d`fT#1ZBWIQV1A(*Y2{t7CY{tx`L$Y0m7;YjGxce;aGZ;|$pXE{`@wIb zi`DdTULanj6Ksxy(yFS|B=+3fh5FUBff+>mmd**OaFNqBN{tVYx*$+@F?}F}IUXzi z3>7;m*XMTeEv^4KKg_?~SGeAIq({`%E4ta#C{^dO?MDR)178Aj3m+s3S$7?e&&t_6 zpEcku%5?%G=j$gJGMkr!kCx*L{^7sFB))A_g?2(LyG1LJ9q$FDv6CV8sF@aL@bBl@ z8#Qtk(h&p(Yn8HqhP9({QYNXJT_=+qR8~ZBCM3Y-eImoXpMtob%zFd){@|`~7~X z>fLK~RrlJvt7>)iexAqcFT)1siza692AGXYNKk?@OxKFGE0;BVDaT?7=hX^EkSIU_ z6%YzE51Ln~D65qjB&-+cS-|9^zn9cnd$jmI5FNqsxyu;=9z?6h^2!IXyZjN?i5UW{ zJ*)ko6r5z*3tX7WHv)h$n}trhJofUdXm>xd3nqU->-?v>mM`B{w5sIp@vXNkJ`3uz zxJC6`1-38E#`gJMTRxbcTe@_HM-SOo;>=J<1XfnoQsa_RrL{_!Xv$newWuD9$xvP? zb5?zrh6=nxSquxZQm42qZ(Ylhcljjuc~a+M6zzZJC;d zcVuRwbxldRI2#+v)Py{k_Ofmm%eI;RMdTd{U*NrYg}e- z=Coe?JE2d6Id}LqbIcswfQ&9$^xOu@WhMRV<-Sq1PaT=?hnEpyN%2#~ zF$?W5qI_dtZTy0^VDsP)XMz$Nci}6A1*ntNR(@tFCVC_#Xq7hnd}Pyr?-KlQj{zrKc6BZ?<5Cx6{N@LwU&7?yu`19s83RUDkI~&!2;`h!ZJ>mh}uqO z#Vx>q;8lM=q|Iyz6*A+V++lD3l@jbeeB-p9iK!oaH#LDa#Uk^}ZmH^_#WIfIFahE^ zQf;J}tbMmRgIW`iV`Dn%s1#k*abA%`qse$7(}Yr5r?Nr|=VhCo1M6iQZozr#tvbV_ zh<1|m3w+J3$>(mqnDD19WAs98J|7Jn5UxK=;ioCBuIdt7Z|V9!6N(WVWw*cFh;!~* zS$D?IX-|0`_I96mKA0e^&WNO37zadzhT|)&f|UjJ9c|;Eyr|!Q2fLlG8oL7GwGZ zo-h~s+vGNgoPf35as{E#_k5IKpmC-wOnQU8uc(s{93+HiY2#lMe=Y7;2Fl@Y>&Crb zX0HzL)f3`Ax05{4 zqH~2d|4i=}AtdkWw_#G_#khr8omrkxw>Bg8YZk_~W@C}t_iepx#ieoso%^$TChnmj zI`_w5M7h9^_5CL4Ci}ZF3MZw*OMI+s&N|`1&DQpaJ_!=i`7=(1T{fljnvzgq^2;rZ zE-cm6dMGIVzonx5&m+i)m_m&&4wKY?=Ob5Dhjpt+y*KarhiDm9#E}46GWgNm=Yx|{ zd&)!!Si>FmfZ}H5M)c1Sln-$wu~$sfFb$MO^pYo@#$jM>TPIEyYHa}zRZ(>Z zr_}Re2g>3FC$<1~*x=}h^*e@`3QCD^f_R&EplD_yhtMmX9%k=pp=Odl<{J4RW1_OErDCv@ z9DUiA`hSc&`D}Xhr24}?4(#RsRdLLJLan;WagNS^H;Iv1s38y8J>X1OPCn@6M~kfA zf8wvBwJC@Qk8HYQ*bwF%Ix4e$cuz%<^?@>=}pF=nQ_Mh|&4^vZ|0 zzCCIHI8cVj8Yzg3ld-r^hUAYXf8&BDP0K7cCJ^B9y{e-jCQUVTrLk%_y&JVLJL}bU zWmFmIh|=bhC6ufuO&6(z{`ulWHPO$y>@K8K{5o1))ZMVQ0?4Iz2a9aj1Xg{9vKvMV z4JL9&L}#YlqWvyk{ow2|c0TdiJjy7&Pv75g{PW8 zy+U#9MF{W(zf81icu%(D-iQP>)j8k_5$4lLu?o-O@U-mEY0>&NJ`vPrRrPep0dX`A zC!#a*&MnD~L!M;)z!_*2BZ+)?I~KP7wC-t4D`N=)%~wX+SXc+t2#vn!fUbqr^`7i4 zERA7^jNgpihh-jHcZ}BgNfRK;i^n|^<`oY^x)kvdG?Puzf4BTeg81`Gj*ucqsHM3R zTvEx+d5mb%kur7Nq2=qk{&D<9+;_dqZ=L`hW{lx8W@ao+=&|5ATXf1t5B;mcsurvY zXVwGJ$$X+TtwX%-%a?KyMAQ$wc4Ty9kUJ=0c)R(2SL-+%WNS;+iQ ze7;TNs)7AHl`4{?S8{)G?M4ke4c~zc#-F^v@|;=f;j@e$6kr=QKJfsg(B4mDguGis zn>qS0)hE4MtOdPWOce@6u_KlF&Zd*C`LUMYkr!OvlFJVG-8b8-d|QS z1*KZ<&B+{LGjJ(pQ8%?o$t?fIitj5WCLjOd9AZowU=?sdn|7O!vB$=;M$-Z>l1pDy z0_$}_%K-3Fv*>UHvgkC;G^ZM2sw%(EN}_;myObZ`d%})#p%0jw&4e22EX0Axh6e<1!dx( z{i^MNgD>$I#U*2Ctnvlp zZPiHa*9&L_3*m;v=IWy5#%*Y?ZMl&(Odmf6HMa&-F{C^WQ-|;oI#>?OE-^2f@YV>q zZP4yD41|K#T}K#$LIWJB3M+k5RnHN|u)R@ZJgH|}=GYQnj!c(HxImJ0Js1n&GD1or z8Ge@v`HyT^qM|+MHqjm+mMCh|5vh7Z>@J|P`gPc+y11RP(=6%QlXFO%(L1Z8Mm%=m zGhne4CeG_8NhspUGDeEBwSiR#imsJ6pR=JqG{PQR>^7ji{+_eo-i3J$6muJ_P7tG8 z#UbDV!W55btp(%}*d(EQ`1lqDs|Z7-AqS;o{u*bI+?9_KX&n7=jM^Cdk#UClX*ENB zFBLD-h>3AG*XFY}N{)apf*;byB>EIm&qVtU{*y*><5J@E11b4>slL41iu1!YvTCB)TJoz$z?pZ9ddUR-9fDEm&H+Oj#bz z8`4acU34(h9ywbh6VhBZ8Qy>_*jOYB10vyEgjroR5Ca1K_XvsCJUNw)q#8EHlY#NL$#KVg3BwLIymSj1 z(@WD)UYHqd2N!MQl9#qXrQKyf_=< zR7#8kR}}M5Plr9cF+-w4F2*F`og7pF?%nKGj}^td(DRq5jlMNi%pK{3@a_~p3EJ;c zeiA6A3)85G&`n)=L{qO`2ws}!#VMTHTDeXi9qg(hir2VEoR4M%${Y=huso=@4bnlZ z{w9fataJ&|jpAy+C3`Bimk)yBa#n;I@{g$m z676L-n$;6n=^$@!m5iak#f))nO{`s#1{x|;Z4a3@sZJ`(Y1W^OX~|c#F`})8s}kH? zG7!tkZJRc9fVy z@cSN{BVkBC)wv{>9pJ;C@pGhN4ZF(tTk1DWn|0Je9-CdrWRZ`5MAySSh)wc{MkPO7 zlqn7-fe|-T;kUM;fYZa3TmI&7!bNQ|m+k~FwQw`B_He2fxqx9zb?TBSaur|^wf=^) z&vx2k!nTyULwL3T=2`fw8nUI0sx`5q;NtG963rWGN$N*B5+zQgj+Mth0PL<;pJ-Mg=L*?BCJ4mt(RXY#EY1DExEX`?# z>)DJtLVG_eW^Z?v{_h{@Ma~8DGps$XD)0!y+o6gkD}?4EHz9%?E;!c*T0iul&_|Zn`tTJ zdFv!shTj`U+n%mP6`MNP@OV)q1E@3!sjGDE<kIW=|Msa z{&iAK8}zAq2-NKB9}EH9hMTcOZ!UJ0&h7ZapZQaGg97!fNNE2o7VJWJA?U&;v0=m3b-kz`eVE1g~J zB@HoU3o3F^$vle|29;UgS{)BubJlmJB#LWLMX-a@~I4rR*mEcgl`qymIx@?Kue2fg|o z@TZMSz%(eQF3yfhL97(wULdipOY`ZGn*l2A53**3=RK-sX$*Qr@gM&e(?ek9#&*1IaD+f3aLISfdHx60Cm`7bq$KjsPb$Gj;3E#5L`b<*Bl|R zG%E8w?AFnu_U}}szEf|UrpY45YltE4ygo}jR@5sAe-Q)IB_`rmg_go1Y4HN6Vd)VR zGWAwgB4K3hc$-E}k>YbOEI;Sf_>2aeoiD`2WpA^i?^^$ou?qb9nLBeq8G7dxWPTwf zK2@g={CEP?pC|%%NZ8RvTHO>sRWFdJx6g4hJ8~e+<#87GmlMw_Cy1uEhK5!2`{aU%+rD)tICjYq1$K{1m@P*V09%opQ|9-aEWXcGxCjNtnsz!6C;HS@tKe=!0a zOV{g2Axy|Xeql-CcN+|Ilr?mcN{y-3e&eKQj>uD3IL^2G1d*iheNQAqhJ1{M4AtM& z8LBf*(IP?O&ptE?y}pB~!Oy`}pQ?*~G`26|nvMw)w7z%gfc!%4;$iCQd^wakMdn(y zc^Oz0e#1S==yCX-ZNK7GPtZdi<-M!RgW5NT=j>`V2h81T4vmwS?V9Q}-LX!|@`U|m zwaCCmpDwjp@v3=~LXmQ<(6Bv`Q<9H((TG9yMKNenFAM;J+vFBN1=0xp`R8*C5iiVC ziL!}!S|6!{h&Ki{%#`bSqYue2!i(pM66wzVUp1VUbKz1LWAm{@KAIwNgdnyob$Jqk z1Tv64ulTw~{!GQ{4tat(MdQ&fV|^74%U304BFJyyiPCSpKR>My{4_blD#f~^7_|ny zF=T8tkXr*d0(w0uCF+dP`w&AlH?kE}Z}g0XBoCjf(e8c`Ku8L)gQdfWp_s{Q20cpw zNmC&YOf*6Y3Wtlnz;g*$l3M;y#*+RsEs!WbM{W@GeKX5pnwCN1nZSY&#)k2 zX%j`1+^($3O;T0zmK9SpkQt!dNLbb1Y8@C>^7 zSfD}2;>IGv;K96aMudkEI|<4$sTj!XCq43K3t-C$J$5EogH`djrB7`lyT zSl&03AZWsQ^HOMcSs#cY@s;@m-T@+izy)L!L%0J*K6>q8iugc05~pe@^fpa;6jDp|Oc6d?_;jMKI)656({V?Hmm1gWws67u{POpy%S`zs;NzA-p?KCE)x z`H&3dJ@X-L_2z)@HyNtwbP42n-X~Qc4#>6MYid_J!hpCj!T8TkiQtPUQX> z&Cmmgz?RSyM7s{7SBOJHUtaqzm!XW6hld$JEu4}OCQU-OAB#T;YHlLMV5o{s~@!At+8$_+!3OPQ!p%IZvfDEr!I8E3LDK!GbIrWg?Q6&SUm+$!_ReE(9RIn3K z8IQ>Qz`5TGDWCtig({!-y4{D!-=07-G!jXTMD0?E{-zB+Y9L9bFqaF zbx`nC^SGp=C-sd{tZ*9Z5YAuv_Dzw@;9xGg(^C*ClHdy9?s1~yVHHbce4V91aRC** zL+;&OMDR4gh}j|#v*1hs9=e8wrMopG*WCamdk!hiJvy5y$Vh6ucwcS`DItvEXy`-^ zCkZ_MCXXoDBqAOg4LOShH&B51ui@xVwVsBTZ_fOmlwMLos9rcyVta84#5Im29*Cw9 zZn|mByK8Q6bBB#GIJu`@q*;CBk~Kg%%DQ%c!G@U%gXWH}MlNB)Hf-6eziJJ^1U`;D z=PBg2|C-K_-zu~! zb|D-MW=y*E#zUnyp<}`4?U(FqHLIl`b?qRSt~4d^5!pU*@gW&Iy-cg}?y`Zou8%dH zuJrY1m{ZSmNn5$i>b>xp$kd`skG2P2Lfrq{i@Ui!jeYdCUAdEu?D?dDn)!ICkFBr2 z=Py3@=@iFACsUrc4D=HjRcs8cy-33}2!;fe;vkGdSJLNRfhT=a7Sr$PEUI~ccI5TE z$srz1P`f3p;k?*}A-mg#F))zwVtbJcT3U^?I>9O4mC)McS~+vXNGa~e1Q|QHI$V3~ zuL+6P7;`jhf%@ft45_XfAEA5U>0!D5Lxs8!UPY^$?^_rLqx*if_Xl^KRYfM)5+Hn) z+7W|Z>_%DlSS^PIk3J!vPdtk%kIQx?N z)n!;ICj1d+davHEjian_BcJNpg;$Mx^ufugQ_aWsE}HC8$Z{0Ikka>n6pv3?hnj;A zEY3~t+*NlMM|d%bpG4?})|}j=$<6kW5W7Td|Oxle{+AOplXPT_F zc={W?0DqDb`>(b+awC4(!NO(os226MG+}Tft_O?pA*o689qNw?z)$0t+Iq$$@!@Si zSZ%FyDioSNp2`mcfsQEYZWUgl*nIKInHz}E6x(Y7KCUbBrjg%LP}5zg0QojPdihGyIL>#}n~Z!iqwN&E7JVgNe7!`TQQ}WK4O-(AbJ*Qj{Om z@Je3At?S-qDc0F}#xB&B;{JBxJY-4C2JK=|#_Irfz&4GA9gYgpQ+O7I#|!hr`Z#8S z&I9>(-%K!8)R~eBs+_WI%a+BIk)|aWQ3V-|k?yBmw$qjrd8fo}sGX=2hz>`%*@X{^ zOx^x&2JaF|@%TZ(=62vu%^T7p_s?zE=KDJ^W~yrvL6{@>u<~_D@-XBnJ=eS~G2&Wk zI}_-q^%o2FFHR*ma$V}PB|G_U!(dlybe}}$@jyXGg;oqN5l_H|6n2!0uJAk9< zceK`f(SenN)yW5c2sJ8OMFUU=3@7seIm16UJtKYbS6xOfjt65jm~%(VUYub4NxVcC zT<3%F=#?Ob?nngd5(gw6*BNu3V51Z7eKMEyQ~RqE-9BLE?W7g+{2yuaZ|u8oL?0685}2;4P}*Z0Q+_S~dQN0U?gpx@QS< zRSfry9=5yh5vA4^!@2Fn&-YfYU>T!4lBJt3$)ODS`kp4A5;vHj4AJg#B?^v)^ry<2 zQtdGoJrD)dqv{MZ9D=K zrpI8ZcU2?2^z8djF4>`!b%!!wxEG?!grH&l-ZsEe!){=e-jw_Je0AKKi_ZdgEa1-! zH|)sOnW^q`jcsdwp6Z=>Ke=XG(=NY239OlnWF)>$Y#e!A6uH6pqDp2Y~(xHEc{^Ak+MvsLrd0^pQ4+Dr3G%LwPo60L8 zNm26+1@mqm(RVIW^6QnY?*drmt^uoIdJBrMUhJZ}27psA$y-4Y>g-@GP!G|;5L6&s zCsXpzcY^^$(MvAb6$HrX-=?txmtW6MA5w`+u>T~DN)Fp*b6@>00cmu`UzhvM6r3KvSQLy|2c5gPbH^GK2-7LPeq>gsH6jO=B>lWj$WMjEe~IDL{hkhnh&Wc2&Q+63E;2S zV9G-7><=lQPWHMhC;3J_(oawXwddkQ17Kc*Keqsye)jyd=snkxq;kSJ9I*PKKcUIB zQ6lSja+_jUib=Mkb49^L8cD3R(Q}jM8>uEJRSdr$!#obSA2`GbaYIpgE}2Ew0!t}- zszy+ix*Tk0OibIB(l0y|Ih#BB&a09+7Tc%yGLgX z6zcKy^UsB+bn|~)b&PNOazM9a+rZpg)=0MbbIKvG(<2n{_pjD|%`^(JW1nEa9kNi* z``7BfkJWy^hi(}mnSbAjtz}6cC4qmpx%&UzUJ?I0{QS7x?cqVldPGeG`i#F0xz5t` zKWmXt|GBB4@|QTilINfp2nuik20lOa?*{D07Fb<)?=W-{gbmgS4uZU4@Iu?_zp!9g zjtJS>Jtzl`$q6w$|9iXTA?W$sk3jAZe9!p@0v;%+EpML*>tKJIY1@34F#Zoz#$tEl z|IXg#{O>a8f9p;CubgB!S2q_6lOJ$ixdw>}4kIK8Vb8fk(`Tj-lf0tUgQnQ4?9)@^p2l$#C}k(g9}KhgRej3<@DFlV%c9wva#kjKTgko zSfzy0-!?L2od|XSx{!{nP%~!m_48TcA1OeD``FOlnFo*GISG`8vw?Y*aJZ@Sc!~PB z&$hsvELiif1_7+?KUcbqLgTCHFdG|OQWW?}>E`rJu;@{WG>Cbwy2=BAy1pnSEkfZ+ z6=DYGWBuk& z`%i-R|At=7HBg;)2w_I)d8hM}M@D5bqec_02Es=Os&61WT~dnBj^Kxr%j5CKZ+7s(^0VO_o`H_E1?%f&0M{h`q# zajY4G5KDd6(SVvUh&$JX^dco&pX9;KZzHr14i54qi8tAWi)6Ig6cG2FrruE)L!!MK zBAK$$J8?^k4PiJkE>h7G_s%l;MJxFHbN*Y~k%6Yc8Bvu~hKu|n^t6br-0JkPf6Gim zUeaIA)L^qzmK2!sqW_xvs`{GTS+`}0l_qiKf00~qb1h5k_X1tBdxjP<8kF+d$h(o=FF z-2%FfB~Q5G-)MEXnxdq^7>Vv{W~oJ1taVPs%p?V4*7S(WcsAkd^W|b^5qKx`2Xs9iaVJq5MyP{(EESe*%d9_fWFUv$1luGjpo`k4Iz#VRQ$- z_%Gg;|1|t>-Gb+Tfs*7c9IV`|Sx8t|xjFw2ot)fbU2i{)GG*H3GB!kSMxR9X$b!J)^adAjoh?>GQ6$*${_{s!Yn7)l@O#+lUP3yWJ zwwn=RL0j)DJY0i&Engoc{a+8iC-a}zhuiympLE}$U_dGh39WAxviNLvA{vBPhzIIG z3&)gf^iF+ml|l+YZhwOm{*lk&^1uEwQ@#sU+7m+DSuv->eGW&HI*;9b zv4P2y_Ymy_^Y;LP2Amc`Vph=E60R%uj(5LkFZ|-)Oosy3%~ToT9fOcFwoF4oPhj4| z3z9pP@QSwl`w4?}-t&Qf`-!O!>C-^opjAu{B!EGud19cHWk-)&aThG@2~H#w{nYOMnU(M zpkxM6)uGmmn}1_LvEdAlOq$6z3}kAU!J?ywbWeU-~%^@VK#0aDaoMKoO_eq*)Up56L&I zh*{pc0bIObj61KYv90?6PfZx|#yr;hc;EH8*yRx;V$1#}!PHm*(?~6iM7rAM&D-Q=jxvGstJu;7*ShRL zjP|GD5CxlQ=u#rd-aZx>OTL89=t3Mr3$BOwr)gQnv|JFn6T3x#KSbE(9hD3RB!W2{ z=n-5Q4T}PX6Wy_zD043yUR5&(L5#ey`s0$tqHyITqfYk>1%rwNMhC-ZLBt4SV_}~B zVZmafEG-T9iIp2|+H50ma5PN%e9=FD$ft%rwpf|tmxRDp6avHVRy)6 zD?zCsgsq3d4%?&^i1~h#;yA&bCrp-Su?mX(1u zUUn)f^XwI)rfT;AyT#;w(SP0ta%>@Bag27pE?I-XF8V_lIorag8>gGf7^XU|iy1Hr z(~`Gvj%v7*JfPh`-HXA7M`Kz6c7vVEg6%gMu7@xNwPJp^>P0q06u1~?^8-O zK~PSIm2|sWz)&9$@b~DT3Q5e7HwX zyI-BZgVodNCYCoi!)Xy!SoP&qF|D>Gy~+E0Pf^m0QdW^MACD2^3-!-mL;Cb~$7OMo zhb{?xQBv*a38i6ae9JhdaS&arzJqMrA_g!HQ1h7?PEW%Z$Xb zv#E=Gx%bfDCVun;Fe4=z%cmP3@sF573CZ-m6jSN@dtJ56IdVbC*BiTBBtqusA!|Uc zGu~;MzTP@=;4VMh#D5-cqBP|P6#9Lg@DcwYKa$D5#}wlC-Ot06Yn$c!JWo0{yWidc zzv_=4Mf3IJaPcHm1BdDmK?pxBY>TWn!69s@aFY#DML*C%!hpiOVNRm=9|7?wp^>dd zf=kJmJSeeOp9|v^h)%dyIi~hel*Z=-#bM96X9#gtoYa)V8pPE__*(X5=+B(p*z&0e zSnd*&e@Ysv!}w%XxH6h=!Icn-74cRZMiA4{hqJg%(#}m6Q}_9$b_jR8dTvE)b=HZt zQ>g;{&CjTDwqmzccBZab`shTXk)46Xe9n{Z8KzoW4>&{l)NIdy?`&C0?G`o|OH1pV z(Wm&KRc+SDc7T_ULEDCm_d&J}0Y*TIPf7}(1mgbIAZ2jM6NE9q<1WVp9Q^59id&Jk zoVU!NFlVfwOs21GE(2 zqQ_M4UUSS3sQQt_QFw;~WDTCRnVc%#-TJj(R+7WJLr}nCKTeL7AzI;Xp+xQaf}nR2 z8lGf>*zlvSZhNa`GEH=mjy)Q#Uz_jZRRcf3gbcg%!I_6qo~u5JkbqfbMxd6vtPm$m z2bHy*2Fs;ZM=a}yPrEo;j_&au0n)s9DiZc&v&5yb=eKZNB0c8k#QopOYltojm`2do zq7~eiLCpP*}WiH2p50%Umq{U)+dop6QW^+XMMOq|GUlJN(WwDTn#zxC#OS zo%Yq7oyEpqGx=Q3jT2=eO{#CMu|A~e&3ld9)${zZ#O3x!IjJ@5-Fe+x-C}&e1ny-r zCF%-sH)?enX>3VU=S>aCc3PU4=_ykKH%%8!%TV_tYd6xXJ>v5qTR6k@qD$)Vmj5!OMKR7eT7 zoA;7-^E83s47Vs4LUt3QNV=Ye+^DdJOmz0z^A6?dmv}+B0S{efM!6-&{0r$sr1E@IAVTb zBx*)Nh&B6BFBN?=EXTdo7&Rk1`Z(Fgzk+y*U1yGpjpfGsi`e&58@hYF^mThQjm$00 z^f^D~?kfrSH+MFcKPJ`sWaPg@1uK`5Vd<;;-wYzT5SefP;tq(vwlo6e=-5YMX^_?` z!LQhyy!2=W-I1s4{5#OSohu{JS!c^RO)=?MGF*eib4lbVgh!qX{M`e>>N|~C2|Y2u zW6xLy2h&t_x8_;|?LiAeOHE91A4SEs^snY3mrJXh%V+?#{={$aTHvG3-WA&9oi?@d>(#eFp!(5hRZuk`(JM8^y)WIBV zf`iaj1b#Gj`$Lfq^TeMqL~*~(Nd_)&vrKV8g*1m;Bdu%>jf_UdBk){yzwE@$lu86S z3ne-6tSp#r9k!Ny0%A}G5;iB6sOchDSP!$;RrWNtin~PlW@U&$>Ykx_$XeXMfHcN5 zq`>EgRpHxdQ#Hujw+2<%!K{!ksfX8o`ly+UEHcB_)#epC5|Mi*B;6lv~;%kN;%X<0xJC8zp2GJKM z)2SBKR_bm#e^$HqfimE%d!6%fg+NY>e;6=bZsWHe*$Pa3jNoS4{;=5h#Hs>5QO_3Le5DvVp>fH zOD;TOHpe!5MYT{h@FLM7-Ab7{*zHtaMs@~wAEzeECXc52*?wks6Jryn2rI4dD9NTV zOI95!C+%F#jM-$H-*D7bR`-L#CO_dytu^GkCZDpWe;nX=uB5xUb5<;!(I7R4*+;CV z+r#TXM}+7DE+>|~#oh){rkej8c^IUOO4p6>Xcv!XQpCzNQ&LumH+ywaBFYwT_<2Le zQ)H>n2V1rjKEM?sxPTS0DMOnrGM{jo<}cc#M>5e!fRIX59E;HgL4eC*PMSj~i_bsc z=z}#;ccbZQ3;|PmFX-)L3QpA;#RlzV5K7J|P;(xr#hY7y^@=BNS#B*2qP!*}t6yh# zc`KhjMQ9@HyzD0h&Jf97nS_K8=Ww>r>U)mUVX_ImyiBVR@W`K!|B1!-bk(5EH>I%| zzFz-0*tlbZI$mCiTDI{>;o~bgUx@ha*BJLkeP4z4YAzv|Rj9ml3&pIHs5CP{ks?k5 zLa8b{xjCEe78OWTK? zGYO;KKcVp8wOvZ)ezm=wv6o%w>FW=^De<(Gr~e22JC85wUt8+@T|(0_*(Z!#vIf

)2DZ%{K?(`vKDJpN~6%M>5aE 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�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

2MH0@E4Z!7nNHci^fk(s@E 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

+uovV6;0Dkw)HBCd2@j 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¥ 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�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 Oww0dv#H$YPDgD0;7_yH5 literal 0 HcmV?d00001 From 88fd0f7d61c215cb22744e5490565c8c16e67275 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Wed, 3 Oct 2018 07:42:16 +0200 Subject: [PATCH 132/279] Added an alternative interval generator using Lemire's algorithm. he interval generator is used when generating 32-bit bounded random numbers. The speedup is 10% to 220% across the various RNGs compared to my pip Numpy. --- _randomgen/benchmark.py | 17 +++++ _randomgen/randomgen/bounded_integers.pyx.in | 6 +- .../src/distributions/distributions.c | 73 ++++++++++++++++--- 3 files changed, 84 insertions(+), 12 deletions(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 665f63c26570..3b41171c7278 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -93,6 +93,22 @@ def timer_32bit(): run_timer(dist, command, command_numpy, SETUP, '32-bit unsigned integers') +def timer_32bit_bounded(): + # info = np.iinfo(np.uint32) + # min, max = info.min, info.max + min, max = 0, 1500 + + dist = 'random_uintegers' + + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32)' + command = command.format(min=min, max=max) + + command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32)' + command_numpy = command_numpy.format(min=min, max=max) + + run_timer(dist, command, command_numpy, SETUP, '32-bit bounded unsigned integers') + + def timer_64bit(): info = np.iinfo(np.uint64) min, max = info.min, info.max @@ -121,5 +137,6 @@ def timer_normal_zig(): if args.full: timer_raw() timer_32bit() + timer_32bit_bounded() timer_64bit() timer_normal_zig() diff --git a/_randomgen/randomgen/bounded_integers.pyx.in b/_randomgen/randomgen/bounded_integers.pyx.in index d6a764590aa4..f5fc56bc17d1 100644 --- a/_randomgen/randomgen/bounded_integers.pyx.in +++ b/_randomgen/randomgen/bounded_integers.pyx.in @@ -181,10 +181,10 @@ cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state """ _rand_{{nptype}}(low, high, size, *state, lock) - Return random np.{{nptype}} integers between `low` and `high`, inclusive. + Return random np.{{nptype}} integers from `low` (inclusive) to `high` (exclusive). Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), + interval [`low`, `high`). If `high` is None (the default), then results are from [0, `low`). On entry the arguments are presumed to have been validated for size and order for the np.{{nptype}} type. @@ -195,7 +195,7 @@ cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state ``high=None``, in which case this parameter is the *highest* such integer). high : int or array-like - If provided, the largest (signed) integer to be drawn from the + If provided, one above the largest (signed) integer to be drawn from the distribution (see above for behavior if ``high=None``). size : int or tuple of ints Output shape. If the given shape is, e.g., ``(m, n, k)``, then diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 26b6232c2915..ec3cbf791bbb 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -2,6 +2,12 @@ #include "ziggurat.h" #include "ziggurat_constants.h" + +/* Only uncomment one of the defines below to choose which interval generator to test. */ +/* #define USE_MASK_BASED_GENERATOR 1 */ +#define USE_LEMIRE_INTERVAL_GENERATOR 1 + + /* Random generators for external use */ float random_float(brng_t *brng_state) { return next_float(brng_state); } @@ -1225,23 +1231,49 @@ uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, return bounded_uint64(brng_state, off, rng, mask); } -static NPY_INLINE uint32_t bounded_uint32(brng_t *brng_state, uint32_t off, - uint32_t rng, uint32_t mask) { +static NPY_INLINE uint32_t bounded_mask_uint32(brng_t *brng_state, uint32_t off, + uint32_t rng, uint32_t mask) { /* * The buffer and buffer count are not used here but are included to allow * this function to be templated with the similar uint8 and uint16 * functions */ - uint32_t val; - if (rng == 0) - return off; while ((val = (next_uint32(brng_state) & mask)) > rng) ; return off + val; } +static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, uint32_t off, + uint32_t rng) { + /* + * The buffer and buffer count are not used here but are included to allow + * this function to be templated with the similar uint8 and uint16 + * functions + */ + + if (rng == 0xFFFFFFFF) { + return next_uint32(brng_state); + /* ToDo: Move this code to caller to prevent this check on each call when generating arrays of numbers. */ + } + + const uint32_t rng_excl = rng + 1; + uint64_t m = ((uint64_t)next_uint32(brng_state)) * rng_excl; + uint32_t leftover = m & ((uint32_t)((1ULL << 32) - 1)); + + if (leftover < rng_excl) { + const uint32_t threshold = ((uint32_t)((1ULL << 32) - rng_excl)) % rng_excl; + + while (leftover < threshold) { + m = ((uint64_t)next_uint32(brng_state)) * rng_excl; + leftover = m & ((uint32_t)((1ULL << 32) - 1)); + } + } + + return off + (m >> 32); +} + uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask, int *bcnt, uint32_t *buf) { @@ -1249,7 +1281,16 @@ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, * Unused bcnt and buf are here only to allow templating with other uint * generators */ - return bounded_uint32(brng_state, off, rng, mask); + if (rng == 0) { + return off; + } else { +#ifdef USE_MASK_BASED_GENERATOR + return bounded_mask_uint32(brng_state, off, rng, mask); +#endif +#ifdef USE_LEMIRE_INTERVAL_GENERATOR + return bounded_lemire_uint32(brng_state, off, rng); +#endif + } } static NPY_INLINE uint16_t buffered_bounded_uint16(brng_t *brng_state, @@ -1345,14 +1386,28 @@ void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, */ void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, npy_intp cnt, uint32_t *out) { - uint32_t mask; npy_intp i; - /* Smallest bit mask >= max */ + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + +#ifdef USE_MASK_BASED_GENERATOR + uint32_t mask; + // Smallest bit mask >= max mask = (uint32_t)gen_mask(rng); for (i = 0; i < cnt; i++) { - out[i] = bounded_uint32(brng_state, off, rng, mask); + out[i] = bounded_mask_uint32(brng_state, off, rng, mask); } +#endif +#ifdef USE_LEMIRE_INTERVAL_GENERATOR + for (i = 0; i < cnt; i++) { + out[i] = bounded_lemire_uint32(brng_state, off, rng); + } +#endif } /* From 726fdc96bda1ff1a854b408e20f3ef7b442fa749 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Wed, 3 Oct 2018 14:31:35 +0200 Subject: [PATCH 133/279] Added a param to RandomGenerator.randint(...) to allow one to choose which algorithm to use to generate a random number in an interval. --- _randomgen/benchmark.py | 11 +++- _randomgen/randomgen/bounded_integers.pxd.in | 2 +- _randomgen/randomgen/bounded_integers.pyx.in | 21 +++--- _randomgen/randomgen/distributions.pxd | 20 +++--- _randomgen/randomgen/generator.pyx | 25 +++++--- .../src/distributions/distributions.c | 64 +++++++++---------- .../src/distributions/distributions.h | 28 +++++--- 7 files changed, 98 insertions(+), 73 deletions(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 3b41171c7278..34b843c98508 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -96,11 +96,18 @@ def timer_32bit(): def timer_32bit_bounded(): # info = np.iinfo(np.uint32) # min, max = info.min, info.max - min, max = 0, 1500 + min, max = 0, 1024 # Worst case for masking & rejection algorithm! dist = 'random_uintegers' - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32)' + # Note on performance of generating random numbers in an interval: + # use_masked_generator=True : masking and rejection is used sampling to generate a random number in an interval. + # use_masked_generator=False : Lemire's algorithm is used if available to generate a random number in an interval. + # Lemire's algorithm has improved performance when {max}+1 is not a power of two. + + # command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked_generator=True)' # Use masking & rejection. + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked_generator=False)' # Use Lemire's algo. + command = command.format(min=min, max=max) command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32)' diff --git a/_randomgen/randomgen/bounded_integers.pxd.in b/_randomgen/randomgen/bounded_integers.pxd.in index 69d2fc0e7242..c61c6a4a3ff6 100644 --- a/_randomgen/randomgen/bounded_integers.pxd.in +++ b/_randomgen/randomgen/bounded_integers.pxd.in @@ -35,5 +35,5 @@ py: inttypes = ('uint64','uint32','uint16','uint8','bool','int64','int32','int16','int8') }} {{for inttype in inttypes}} -cdef object _rand_{{inttype}}(object low, object high, object size, brng_t *state, object lock) +cdef object _rand_{{inttype}}(object low, object high, object size, brng_t *state, object lock, bint use_masked_generator) {{endfor}} diff --git a/_randomgen/randomgen/bounded_integers.pyx.in b/_randomgen/randomgen/bounded_integers.pyx.in index f5fc56bc17d1..aa1511673bc9 100644 --- a/_randomgen/randomgen/bounded_integers.pyx.in +++ b/_randomgen/randomgen/bounded_integers.pyx.in @@ -22,7 +22,8 @@ type_info = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000U {{for nptype, utype, nptype_up, npctype, remaining, bitshift, lb, ub in type_info}} {{ py: otype = nptype + '_' if nptype == 'bool' else nptype }} -cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock): +cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock, + bint use_masked_generator): """ Array path for smaller integer types @@ -76,7 +77,7 @@ cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object s # Smallest bit mask >= max mask = <{{utype}}_t>_gen_mask(rng) - out_data[i] = random_buffered_bounded_{{utype}}(state, off, rng, mask, &buf_rem, &buf) + out_data[i] = random_buffered_bounded_{{utype}}(state, off, rng, mask, &buf_rem, &buf, use_masked_generator) np.PyArray_MultiIter_NEXT(it) return out_arr @@ -89,7 +90,8 @@ big_type_info = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFF )}} {{for nptype, utype, npctype, lb, ub in big_type_info}} {{ py: otype = nptype}} -cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, brng_t *state, object lock): +cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, brng_t *state, object lock, + bint use_masked_generator): """ Array path for 64-bit integer types @@ -100,6 +102,8 @@ cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, brn The internal generator does not have this issue since it generates from the closes interval [low, high-1] and high-1 is always in range for the 64 bit integer type. + + Note: use_masked_generator currently ignored for 64bit generators. """ cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr @@ -177,9 +181,10 @@ type_info = (('uint64', 'uint64', '0x0ULL', '0xFFFFFFFFFFFFFFFFULL'), )}} {{for nptype, utype, lb, ub in type_info}} {{ py: otype = nptype + '_' if nptype == 'bool' else nptype }} -cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state, object lock): +cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state, object lock, + bint use_masked_generator): """ - _rand_{{nptype}}(low, high, size, *state, lock) + _rand_{{nptype}}(low, high, size, *state, lock, use_masked_generator) Return random np.{{nptype}} integers from `low` (inclusive) to `high` (exclusive). @@ -251,14 +256,14 @@ cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state off = <{{utype}}_t>(<{{nptype}}_t>low) if size is None: with lock: - random_bounded_{{utype}}_fill(state, off, rng, 1, &out_val) + random_bounded_{{utype}}_fill(state, off, rng, 1, &out_val, use_masked_generator) return np.{{otype}}(<{{nptype}}_t>out_val) else: out_arr = np.empty(size, np.{{nptype}}) cnt = np.PyArray_SIZE(out_arr) out_data = <{{utype}}_t *>np.PyArray_DATA(out_arr) with lock, nogil: - random_bounded_{{utype}}_fill(state, off, rng, cnt, out_data) + random_bounded_{{utype}}_fill(state, off, rng, cnt, out_data, use_masked_generator) return out_arr - return _rand_{{nptype}}_broadcast(low_arr, high_arr, size, state, lock) + return _rand_{{nptype}}_broadcast(low_arr, high_arr, size, state, lock, use_masked_generator) {{endfor}} diff --git a/_randomgen/randomgen/distributions.pxd b/_randomgen/randomgen/distributions.pxd index 6b13733d3e25..add23358dd07 100644 --- a/_randomgen/randomgen/distributions.pxd +++ b/_randomgen/randomgen/distributions.pxd @@ -101,27 +101,29 @@ cdef extern from "src/distributions/distributions.h": uint64_t rng, uint64_t mask) nogil uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask, - int *bcnt, uint32_t *buf) nogil + int *bcnt, uint32_t *buf, bint use_masked_generator) nogil uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, uint16_t mask, - int *bcnt, uint32_t *buf) nogil + int *bcnt, uint32_t *buf, bint use_masked_generator) nogil uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, uint8_t rng, uint8_t mask, - int *bcnt, uint32_t *buf) nogil + int *bcnt, uint32_t *buf, bint use_masked_generator) nogil np.npy_bool random_buffered_bounded_bool(brng_t *brng_state, np.npy_bool off, np.npy_bool rng, np.npy_bool mask, - int *bcnt, uint32_t *buf) nogil + int *bcnt, uint32_t *buf, bint use_masked_generator) nogil void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, np.npy_intp cnt, - uint64_t *out) nogil + uint64_t *out, bint use_masked_generator) nogil void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, np.npy_intp cnt, - uint32_t *out) nogil + uint32_t *out, bint use_masked_generator) nogil void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, np.npy_intp cnt, - uint16_t *out) nogil + uint16_t *out, bint use_masked_generator) nogil void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, - uint8_t rng, np.npy_intp cnt, uint8_t *out) nogil + uint8_t rng, np.npy_intp cnt, + uint8_t *out, bint use_masked_generator) nogil void random_bounded_bool_fill(brng_t *brng_state, np.npy_bool off, - np.npy_bool rng, np.npy_intp cnt, np.npy_bool *out) nogil + np.npy_bool rng, np.npy_intp cnt, + np.npy_bool *out, bint use_masked_generator) nogil diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index a752aa84c285..415eeaffc1d4 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -572,7 +572,7 @@ cdef class RandomGenerator: randoms_data[i] = random_positive_int(self._brng) return randoms - def randint(self, low, high=None, size=None, dtype=int): + def randint(self, low, high=None, size=None, dtype=int, bint use_masked_generator=True): """ randint(low, high=None, size=None, dtype='l') @@ -604,6 +604,11 @@ cdef class RandomGenerator: .. versionadded:: 1.11.0 + use_masked_generator : bool + If True the generator uses rejection sampling with a bit mask to + reject random numbers that are out of bounds. If False the generator + will use Lemire's rejection sampling algorithm when available. + Returns ------- out : int or ndarray of ints @@ -655,23 +660,23 @@ cdef class RandomGenerator: raise TypeError('Unsupported dtype "%s" for randint' % key) if key == 'int32': - ret = _rand_int32(low, high, size, self._brng, self.lock) + ret = _rand_int32(low, high, size, self._brng, self.lock, use_masked_generator) elif key == 'int64': - ret = _rand_int64(low, high, size, self._brng, self.lock) + ret = _rand_int64(low, high, size, self._brng, self.lock, use_masked_generator) elif key == 'int16': - ret = _rand_int16(low, high, size, self._brng, self.lock) + ret = _rand_int16(low, high, size, self._brng, self.lock, use_masked_generator) elif key == 'int8': - ret = _rand_int8(low, high, size, self._brng, self.lock) + ret = _rand_int8(low, high, size, self._brng, self.lock, use_masked_generator) elif key == 'uint64': - ret = _rand_uint64(low, high, size, self._brng, self.lock) + ret = _rand_uint64(low, high, size, self._brng, self.lock, use_masked_generator) elif key == 'uint32': - ret = _rand_uint32(low, high, size, self._brng, self.lock) + ret = _rand_uint32(low, high, size, self._brng, self.lock, use_masked_generator) elif key == 'uint16': - ret = _rand_uint16(low, high, size, self._brng, self.lock) + ret = _rand_uint16(low, high, size, self._brng, self.lock, use_masked_generator) elif key == 'uint8': - ret = _rand_uint8(low, high, size, self._brng, self.lock) + ret = _rand_uint8(low, high, size, self._brng, self.lock, use_masked_generator) elif key == 'bool': - ret = _rand_bool(low, high, size, self._brng, self.lock) + ret = _rand_bool(low, high, size, self._brng, self.lock, use_masked_generator) if size is None and dtype in (np.bool, np.int, np.long): if np.array(ret).shape == (): diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index ec3cbf791bbb..d296c523e406 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -3,11 +3,6 @@ #include "ziggurat_constants.h" -/* Only uncomment one of the defines below to choose which interval generator to test. */ -/* #define USE_MASK_BASED_GENERATOR 1 */ -#define USE_LEMIRE_INTERVAL_GENERATOR 1 - - /* Random generators for external use */ float random_float(brng_t *brng_state) { return next_float(brng_state); } @@ -1231,7 +1226,7 @@ uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, return bounded_uint64(brng_state, off, rng, mask); } -static NPY_INLINE uint32_t bounded_mask_uint32(brng_t *brng_state, uint32_t off, +static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask) { /* * The buffer and buffer count are not used here but are included to allow @@ -1248,6 +1243,8 @@ static NPY_INLINE uint32_t bounded_mask_uint32(brng_t *brng_state, uint32_t off, static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, uint32_t off, uint32_t rng) { /* + * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 + * * The buffer and buffer count are not used here but are included to allow * this function to be templated with the similar uint8 and uint16 * functions @@ -1259,7 +1256,10 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, uint32_t of } const uint32_t rng_excl = rng + 1; + /* Generate a scaled random number. */ uint64_t m = ((uint64_t)next_uint32(brng_state)) * rng_excl; + + /* Rejection sampling to remove any bias */ uint32_t leftover = m & ((uint32_t)((1ULL << 32) - 1)); if (leftover < rng_excl) { @@ -1276,7 +1276,7 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, uint32_t of uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask, int *bcnt, - uint32_t *buf) { + uint32_t *buf, bool use_masked_generator) { /* * Unused bcnt and buf are here only to allow templating with other uint * generators @@ -1284,12 +1284,11 @@ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, if (rng == 0) { return off; } else { -#ifdef USE_MASK_BASED_GENERATOR - return bounded_mask_uint32(brng_state, off, rng, mask); -#endif -#ifdef USE_LEMIRE_INTERVAL_GENERATOR - return bounded_lemire_uint32(brng_state, off, rng); -#endif + if (use_masked_generator) { + return bounded_masked_uint32(brng_state, off, rng, mask); + } else { + return bounded_lemire_uint32(brng_state, off, rng); + } } } @@ -1316,7 +1315,7 @@ static NPY_INLINE uint16_t buffered_bounded_uint16(brng_t *brng_state, uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, uint16_t mask, int *bcnt, - uint32_t *buf) { + uint32_t *buf, bool use_masked_generator) { return buffered_bounded_uint16(brng_state, off, rng, mask, bcnt, buf); } @@ -1342,7 +1341,7 @@ static NPY_INLINE uint8_t buffered_bounded_uint8(brng_t *brng_state, uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, uint8_t rng, uint8_t mask, int *bcnt, - uint32_t *buf) { + uint32_t *buf, bool use_masked_generator) { return buffered_bounded_uint8(brng_state, off, rng, mask, bcnt, buf); } @@ -1364,12 +1363,12 @@ static NPY_INLINE npy_bool buffered_bounded_bool(brng_t *brng_state, npy_bool random_buffered_bounded_bool(brng_t *brng_state, npy_bool off, npy_bool rng, npy_bool mask, int *bcnt, - uint32_t *buf) { + uint32_t *buf, bool use_masked_generator) { return buffered_bounded_bool(brng_state, off, rng, mask, bcnt, buf); } void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, - npy_intp cnt, uint64_t *out) { + npy_intp cnt, uint64_t *out, bool use_masked_generator) { uint64_t mask; npy_intp i; @@ -1385,7 +1384,7 @@ void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, * inclusive. The numbers wrap if rng is sufficiently large. */ void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, - npy_intp cnt, uint32_t *out) { + npy_intp cnt, uint32_t *out, bool use_masked_generator) { npy_intp i; if (rng == 0) { @@ -1395,19 +1394,18 @@ void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, return; } -#ifdef USE_MASK_BASED_GENERATOR - uint32_t mask; - // Smallest bit mask >= max - mask = (uint32_t)gen_mask(rng); - for (i = 0; i < cnt; i++) { - out[i] = bounded_mask_uint32(brng_state, off, rng, mask); - } -#endif -#ifdef USE_LEMIRE_INTERVAL_GENERATOR - for (i = 0; i < cnt; i++) { - out[i] = bounded_lemire_uint32(brng_state, off, rng); + if (use_masked_generator) { + uint32_t mask; + // Smallest bit mask >= max + mask = (uint32_t)gen_mask(rng); + for (i = 0; i < cnt; i++) { + out[i] = bounded_masked_uint32(brng_state, off, rng, mask); + } + } else { + for (i = 0; i < cnt; i++) { + out[i] = bounded_lemire_uint32(brng_state, off, rng); + } } -#endif } /* @@ -1415,7 +1413,7 @@ void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, * inclusive. The numbers wrap if rng is sufficiently large. */ void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, - npy_intp cnt, uint16_t *out) { + npy_intp cnt, uint16_t *out, bool use_masked_generator) { uint16_t mask; npy_intp i; uint32_t buf = 0; @@ -1433,7 +1431,7 @@ void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, * inclusive. The numbers wrap if rng is sufficiently large. */ void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, uint8_t rng, - npy_intp cnt, uint8_t *out) { + npy_intp cnt, uint8_t *out, bool use_masked_generator) { uint8_t mask; npy_intp i; uint32_t buf = 0; @@ -1451,7 +1449,7 @@ void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, uint8_t rng, * inclusive. */ void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, npy_bool rng, - npy_intp cnt, npy_bool *out) { + npy_intp cnt, npy_bool *out, bool use_masked_generator) { npy_bool mask = 0; npy_intp i; uint32_t buf = 0; diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index 707f3b455e35..0406318e73a3 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -179,29 +179,37 @@ DECLDIR uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, DECLDIR uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask, int *bcnt, - uint32_t *buf); - + uint32_t *buf, + bool use_masked_generator); DECLDIR uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, uint16_t mask, int *bcnt, - uint32_t *buf); + uint32_t *buf, + bool use_masked_generator); DECLDIR uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, uint8_t rng, uint8_t mask, - int *bcnt, uint32_t *buf); + int *bcnt, uint32_t *buf, + bool use_masked_generator); DECLDIR npy_bool random_buffered_bounded_bool(brng_t *brng_state, npy_bool off, npy_bool rng, npy_bool mask, - int *bcnt, uint32_t *buf); + int *bcnt, uint32_t *buf, + bool use_masked_generator); DECLDIR void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, npy_intp cnt, - uint64_t *out); + uint64_t *out, + bool use_masked_generator); DECLDIR void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, npy_intp cnt, - uint32_t *out); + uint32_t *out, + bool use_masked_generator); DECLDIR void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, npy_intp cnt, - uint16_t *out); + uint16_t *out, + bool use_masked_generator); DECLDIR void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, - uint8_t rng, npy_intp cnt, uint8_t *out); + uint8_t rng, npy_intp cnt, uint8_t *out, + bool use_masked_generator); DECLDIR void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, npy_bool rng, npy_intp cnt, - npy_bool *out); + npy_bool *out, + bool use_masked_generator); From 01ada411352370230bdb5fc6376d4077a005ec10 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Wed, 3 Oct 2018 22:16:19 +0200 Subject: [PATCH 134/279] Fix C errors on VS. --- _randomgen/appveyor.yml | 8 ++++---- _randomgen/randomgen/src/distributions/distributions.c | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/_randomgen/appveyor.yml b/_randomgen/appveyor.yml index 8280f54b64e7..d5454eb14177 100644 --- a/_randomgen/appveyor.yml +++ b/_randomgen/appveyor.yml @@ -7,10 +7,10 @@ environment: matrix: - PY_MAJOR_VER: 2 PYTHON_ARCH: "x86" - - PY_MAJOR_VER: 3 - PYTHON_ARCH: "x86_64" - - PY_MAJOR_VER: 3 - PYTHON_ARCH: "x86" +# - PY_MAJOR_VER: 3 +# PYTHON_ARCH: "x86_64" +# - PY_MAJOR_VER: 3 +# PYTHON_ARCH: "x86" platform: - x64 diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index d296c523e406..4ad99158c5e6 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1249,18 +1249,20 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, uint32_t of * this function to be templated with the similar uint8 and uint16 * functions */ + const uint32_t rng_excl = rng + 1; + uint64_t m; + uint32_t leftover; if (rng == 0xFFFFFFFF) { return next_uint32(brng_state); /* ToDo: Move this code to caller to prevent this check on each call when generating arrays of numbers. */ } - const uint32_t rng_excl = rng + 1; /* Generate a scaled random number. */ - uint64_t m = ((uint64_t)next_uint32(brng_state)) * rng_excl; + m = ((uint64_t)next_uint32(brng_state)) * rng_excl; /* Rejection sampling to remove any bias */ - uint32_t leftover = m & ((uint32_t)((1ULL << 32) - 1)); + leftover = m & ((uint32_t)((1ULL << 32) - 1)); if (leftover < rng_excl) { const uint32_t threshold = ((uint32_t)((1ULL << 32) - rng_excl)) % rng_excl; From 658fae6e74c53eaf725c383e1c6a58fd528ceccb Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Wed, 3 Oct 2018 22:18:20 +0200 Subject: [PATCH 135/279] Setup travis to run fewer environments while testing. --- _randomgen/.travis.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 052681727ab9..e5f0fe12413f 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -21,17 +21,17 @@ matrix: include: - os: linux env: [PYTHON=2.7, NUMPY=1.10, CYTHON=0.26] - - os: linux - env: [PYTHON=3.5, NUMPY=1.11] +# - os: linux +# env: [PYTHON=3.5, NUMPY=1.11] - os: linux env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.27] - - os: linux - env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.26] - - os: linux - env: [PYTHON=3.6, DOCBUILD=true] - - os: osx - language: generic - env: [PYTHON=3.6] +# - os: linux +# env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.26] +# - os: linux +# env: [PYTHON=3.6, DOCBUILD=true] +# - os: osx +# language: generic +# env: [PYTHON=3.6] before_install: From 450ea5a480b40b697d2f07ce7d2f9f4a07337923 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Wed, 3 Oct 2018 22:24:14 +0200 Subject: [PATCH 136/279] Restore travis and appveyor settings. --- _randomgen/.travis.yml | 18 +++++++++--------- _randomgen/appveyor.yml | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index e5f0fe12413f..052681727ab9 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -21,17 +21,17 @@ matrix: include: - os: linux env: [PYTHON=2.7, NUMPY=1.10, CYTHON=0.26] -# - os: linux -# env: [PYTHON=3.5, NUMPY=1.11] + - os: linux + env: [PYTHON=3.5, NUMPY=1.11] - os: linux env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.27] -# - os: linux -# env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.26] -# - os: linux -# env: [PYTHON=3.6, DOCBUILD=true] -# - os: osx -# language: generic -# env: [PYTHON=3.6] + - os: linux + env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.26] + - os: linux + env: [PYTHON=3.6, DOCBUILD=true] + - os: osx + language: generic + env: [PYTHON=3.6] before_install: diff --git a/_randomgen/appveyor.yml b/_randomgen/appveyor.yml index d5454eb14177..8280f54b64e7 100644 --- a/_randomgen/appveyor.yml +++ b/_randomgen/appveyor.yml @@ -7,10 +7,10 @@ environment: matrix: - PY_MAJOR_VER: 2 PYTHON_ARCH: "x86" -# - PY_MAJOR_VER: 3 -# PYTHON_ARCH: "x86_64" -# - PY_MAJOR_VER: 3 -# PYTHON_ARCH: "x86" + - PY_MAJOR_VER: 3 + PYTHON_ARCH: "x86_64" + - PY_MAJOR_VER: 3 + PYTHON_ARCH: "x86" platform: - x64 From 5f18b4f98711cda79b3ec62b1a94371710da075b Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 4 Oct 2018 15:13:27 +0200 Subject: [PATCH 137/279] 1) Made the parameter order and randint callees consistent. 2) Rename use_masked_generator to use_masked. 3) Added tests for generating uint32 numbers in an interval using the masked and lemire algorithms. --- _randomgen/benchmark.py | 8 +- _randomgen/randomgen/bounded_integers.pxd.in | 2 +- _randomgen/randomgen/bounded_integers.pyx.in | 29 +++--- _randomgen/randomgen/distributions.pxd | 73 +++++++++------ _randomgen/randomgen/generator.pyx | 24 ++--- .../src/distributions/distributions.c | 91 +++++++++++-------- .../src/distributions/distributions.h | 73 ++++++++------- .../randomgen/tests/test_numpy_mt19937.py | 18 ++++ 8 files changed, 188 insertions(+), 130 deletions(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 34b843c98508..3c86f72959f0 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -101,12 +101,12 @@ def timer_32bit_bounded(): dist = 'random_uintegers' # Note on performance of generating random numbers in an interval: - # use_masked_generator=True : masking and rejection is used sampling to generate a random number in an interval. - # use_masked_generator=False : Lemire's algorithm is used if available to generate a random number in an interval. + # use_masked=True : masking and rejection sampling is used to generate a random number in an interval. + # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. # Lemire's algorithm has improved performance when {max}+1 is not a power of two. - # command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked_generator=True)' # Use masking & rejection. - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked_generator=False)' # Use Lemire's algo. + # command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=True)' # Use masking & rejection. + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=False)' # Use Lemire's algo. command = command.format(min=min, max=max) diff --git a/_randomgen/randomgen/bounded_integers.pxd.in b/_randomgen/randomgen/bounded_integers.pxd.in index c61c6a4a3ff6..5f723733cca6 100644 --- a/_randomgen/randomgen/bounded_integers.pxd.in +++ b/_randomgen/randomgen/bounded_integers.pxd.in @@ -35,5 +35,5 @@ py: inttypes = ('uint64','uint32','uint16','uint8','bool','int64','int32','int16','int8') }} {{for inttype in inttypes}} -cdef object _rand_{{inttype}}(object low, object high, object size, brng_t *state, object lock, bint use_masked_generator) +cdef object _rand_{{inttype}}(object low, object high, object size, bint use_masked, brng_t *state, object lock) {{endfor}} diff --git a/_randomgen/randomgen/bounded_integers.pyx.in b/_randomgen/randomgen/bounded_integers.pyx.in index aa1511673bc9..becf18a1afae 100644 --- a/_randomgen/randomgen/bounded_integers.pyx.in +++ b/_randomgen/randomgen/bounded_integers.pyx.in @@ -22,8 +22,9 @@ type_info = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000U {{for nptype, utype, nptype_up, npctype, remaining, bitshift, lb, ub in type_info}} {{ py: otype = nptype + '_' if nptype == 'bool' else nptype }} -cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, brng_t *state, object lock, - bint use_masked_generator): +cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, + bint use_masked, + brng_t *state, object lock): """ Array path for smaller integer types @@ -77,7 +78,7 @@ cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object s # Smallest bit mask >= max mask = <{{utype}}_t>_gen_mask(rng) - out_data[i] = random_buffered_bounded_{{utype}}(state, off, rng, mask, &buf_rem, &buf, use_masked_generator) + out_data[i] = random_buffered_bounded_{{utype}}(state, off, rng, mask, use_masked, &buf_rem, &buf) np.PyArray_MultiIter_NEXT(it) return out_arr @@ -90,8 +91,9 @@ big_type_info = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFF )}} {{for nptype, utype, npctype, lb, ub in big_type_info}} {{ py: otype = nptype}} -cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, brng_t *state, object lock, - bint use_masked_generator): +cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, + bint use_masked, + brng_t *state, object lock): """ Array path for 64-bit integer types @@ -103,7 +105,7 @@ cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, brn the closes interval [low, high-1] and high-1 is always in range for the 64 bit integer type. - Note: use_masked_generator currently ignored for 64bit generators. + Note: use_masked currently ignored for 64bit generators. """ cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr @@ -181,10 +183,11 @@ type_info = (('uint64', 'uint64', '0x0ULL', '0xFFFFFFFFFFFFFFFFULL'), )}} {{for nptype, utype, lb, ub in type_info}} {{ py: otype = nptype + '_' if nptype == 'bool' else nptype }} -cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state, object lock, - bint use_masked_generator): +cdef object _rand_{{nptype}}(object low, object high, object size, + bint use_masked, + brng_t *state, object lock): """ - _rand_{{nptype}}(low, high, size, *state, lock, use_masked_generator) + _rand_{{nptype}}(low, high, size, use_masked, *state, lock) Return random np.{{nptype}} integers from `low` (inclusive) to `high` (exclusive). @@ -206,6 +209,8 @@ cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. + use_masked : bool + If True then rejection sampling with a range mask is used else Lemire's algorithm is used. state : basic random state State to use in the core random number generators lock : threading.Lock @@ -256,14 +261,14 @@ cdef object _rand_{{nptype}}(object low, object high, object size, brng_t *state off = <{{utype}}_t>(<{{nptype}}_t>low) if size is None: with lock: - random_bounded_{{utype}}_fill(state, off, rng, 1, &out_val, use_masked_generator) + random_bounded_{{utype}}_fill(state, off, rng, 1, use_masked, &out_val) return np.{{otype}}(<{{nptype}}_t>out_val) else: out_arr = np.empty(size, np.{{nptype}}) cnt = np.PyArray_SIZE(out_arr) out_data = <{{utype}}_t *>np.PyArray_DATA(out_arr) with lock, nogil: - random_bounded_{{utype}}_fill(state, off, rng, cnt, out_data, use_masked_generator) + random_bounded_{{utype}}_fill(state, off, rng, cnt, use_masked, out_data) return out_arr - return _rand_{{nptype}}_broadcast(low_arr, high_arr, size, state, lock, use_masked_generator) + return _rand_{{nptype}}_broadcast(low_arr, high_arr, size, use_masked, state, lock) {{endfor}} diff --git a/_randomgen/randomgen/distributions.pxd b/_randomgen/randomgen/distributions.pxd index add23358dd07..67835cde697d 100644 --- a/_randomgen/randomgen/distributions.pxd +++ b/_randomgen/randomgen/distributions.pxd @@ -96,34 +96,47 @@ cdef extern from "src/distributions/distributions.h": int64_t random_zipf(brng_t *brng_state, double a) nogil int64_t random_hypergeometric(brng_t *brng_state, int64_t good, int64_t bad, int64_t sample) nogil + uint64_t random_interval(brng_t *brng_state, uint64_t max) nogil - uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, - uint64_t rng, uint64_t mask) nogil - uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, - uint32_t rng, uint32_t mask, - int *bcnt, uint32_t *buf, bint use_masked_generator) nogil - - uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, - uint16_t rng, uint16_t mask, - int *bcnt, uint32_t *buf, bint use_masked_generator) nogil - uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, - uint8_t rng, uint8_t mask, - int *bcnt, uint32_t *buf, bint use_masked_generator) nogil - np.npy_bool random_buffered_bounded_bool(brng_t *brng_state, np.npy_bool off, - np.npy_bool rng, np.npy_bool mask, - int *bcnt, uint32_t *buf, bint use_masked_generator) nogil - void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, - uint64_t rng, np.npy_intp cnt, - uint64_t *out, bint use_masked_generator) nogil - void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, - uint32_t rng, np.npy_intp cnt, - uint32_t *out, bint use_masked_generator) nogil - void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, - uint16_t rng, np.npy_intp cnt, - uint16_t *out, bint use_masked_generator) nogil - void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, - uint8_t rng, np.npy_intp cnt, - uint8_t *out, bint use_masked_generator) nogil - void random_bounded_bool_fill(brng_t *brng_state, np.npy_bool off, - np.npy_bool rng, np.npy_intp cnt, - np.npy_bool *out, bint use_masked_generator) nogil + + uint64_t random_bounded_uint64(brng_t *brng_state, + uint64_t off, uint64_t rng, + uint64_t mask) nogil + + uint32_t random_buffered_bounded_uint32(brng_t *brng_state, + uint32_t off, uint32_t rng, + uint32_t mask, bint use_masked, + int *bcnt, uint32_t *buf) nogil + uint16_t random_buffered_bounded_uint16(brng_t *brng_state, + uint16_t off, uint16_t rng, + uint16_t mask, bint use_masked, + int *bcnt, uint32_t *buf) nogil + uint8_t random_buffered_bounded_uint8(brng_t *brng_state, + uint8_t off, uint8_t rng, + uint8_t mask, bint use_masked, + int *bcnt, uint32_t *buf) nogil + np.npy_bool random_buffered_bounded_bool(brng_t *brng_state, + np.npy_bool off, np.npy_bool rng, + np.npy_bool mask, bint use_masked, + int *bcnt, uint32_t *buf) nogil + + void random_bounded_uint64_fill(brng_t *brng_state, + uint64_t off, uint64_t rng, np.npy_intp cnt, + bint use_masked, + uint64_t *out) nogil + void random_bounded_uint32_fill(brng_t *brng_state, + uint32_t off, uint32_t rng, np.npy_intp cnt, + bint use_masked, + uint32_t *out) nogil + void random_bounded_uint16_fill(brng_t *brng_state, + uint16_t off, uint16_t rng, np.npy_intp cnt, + bint use_masked, + uint16_t *out) nogil + void random_bounded_uint8_fill(brng_t *brng_state, + uint8_t off, uint8_t rng, np.npy_intp cnt, + bint use_masked, + uint8_t *out) nogil + void random_bounded_bool_fill(brng_t *brng_state, + np.npy_bool off, np.npy_bool rng, np.npy_intp cnt, + bint use_masked, + np.npy_bool *out) nogil diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 415eeaffc1d4..1e87f001f59b 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -572,7 +572,7 @@ cdef class RandomGenerator: randoms_data[i] = random_positive_int(self._brng) return randoms - def randint(self, low, high=None, size=None, dtype=int, bint use_masked_generator=True): + def randint(self, low, high=None, size=None, dtype=int, use_masked=True): """ randint(low, high=None, size=None, dtype='l') @@ -604,11 +604,13 @@ cdef class RandomGenerator: .. versionadded:: 1.11.0 - use_masked_generator : bool + use_masked : bool If True the generator uses rejection sampling with a bit mask to reject random numbers that are out of bounds. If False the generator will use Lemire's rejection sampling algorithm when available. + .. versionadded:: 1.15.1 + Returns ------- out : int or ndarray of ints @@ -660,23 +662,23 @@ cdef class RandomGenerator: raise TypeError('Unsupported dtype "%s" for randint' % key) if key == 'int32': - ret = _rand_int32(low, high, size, self._brng, self.lock, use_masked_generator) + ret = _rand_int32(low, high, size, use_masked, self._brng, self.lock) elif key == 'int64': - ret = _rand_int64(low, high, size, self._brng, self.lock, use_masked_generator) + ret = _rand_int64(low, high, size, use_masked, self._brng, self.lock) elif key == 'int16': - ret = _rand_int16(low, high, size, self._brng, self.lock, use_masked_generator) + ret = _rand_int16(low, high, size, use_masked, self._brng, self.lock) elif key == 'int8': - ret = _rand_int8(low, high, size, self._brng, self.lock, use_masked_generator) + ret = _rand_int8(low, high, size, use_masked, self._brng, self.lock) elif key == 'uint64': - ret = _rand_uint64(low, high, size, self._brng, self.lock, use_masked_generator) + ret = _rand_uint64(low, high, size, use_masked, self._brng, self.lock) elif key == 'uint32': - ret = _rand_uint32(low, high, size, self._brng, self.lock, use_masked_generator) + ret = _rand_uint32(low, high, size, use_masked, self._brng, self.lock) elif key == 'uint16': - ret = _rand_uint16(low, high, size, self._brng, self.lock, use_masked_generator) + ret = _rand_uint16(low, high, size, use_masked, self._brng, self.lock) elif key == 'uint8': - ret = _rand_uint8(low, high, size, self._brng, self.lock, use_masked_generator) + ret = _rand_uint8(low, high, size, use_masked, self._brng, self.lock) elif key == 'bool': - ret = _rand_bool(low, high, size, self._brng, self.lock, use_masked_generator) + ret = _rand_bool(low, high, size, use_masked, self._brng, self.lock) if size is None and dtype in (np.bool, np.int, np.long): if np.array(ret).shape == (): diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 4ad99158c5e6..b16367325c55 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1205,8 +1205,9 @@ static NPY_INLINE uint64_t gen_mask(uint64_t max) { * inclusive. The numbers wrap if rng is sufficiently large. */ -static NPY_INLINE uint64_t bounded_uint64(brng_t *brng_state, uint64_t off, - uint64_t rng, uint64_t mask) { +static NPY_INLINE uint64_t bounded_uint64(brng_t *brng_state, + uint64_t off, uint64_t rng, + uint64_t mask) { uint64_t val; if (rng == 0) return off; @@ -1221,13 +1222,15 @@ static NPY_INLINE uint64_t bounded_uint64(brng_t *brng_state, uint64_t off, return off + val; } -uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, +uint64_t random_bounded_uint64(brng_t *brng_state, + uint64_t off, uint64_t rng, uint64_t mask) { return bounded_uint64(brng_state, off, rng, mask); } -static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, uint32_t off, - uint32_t rng, uint32_t mask) { +static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, + uint32_t off, uint32_t rng, + uint32_t mask) { /* * The buffer and buffer count are not used here but are included to allow * this function to be templated with the similar uint8 and uint16 @@ -1240,8 +1243,8 @@ static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, uint32_t of return off + val; } -static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, uint32_t off, - uint32_t rng) { +static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, + uint32_t off, uint32_t rng) { /* * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 * @@ -1276,9 +1279,10 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, uint32_t of return off + (m >> 32); } -uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, - uint32_t rng, uint32_t mask, int *bcnt, - uint32_t *buf, bool use_masked_generator) { +uint32_t random_buffered_bounded_uint32(brng_t *brng_state, + uint32_t off, uint32_t rng, + uint32_t mask, bool use_masked, + int *bcnt, uint32_t *buf) { /* * Unused bcnt and buf are here only to allow templating with other uint * generators @@ -1286,7 +1290,7 @@ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, if (rng == 0) { return off; } else { - if (use_masked_generator) { + if (use_masked) { return bounded_masked_uint32(brng_state, off, rng, mask); } else { return bounded_lemire_uint32(brng_state, off, rng); @@ -1296,8 +1300,8 @@ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, static NPY_INLINE uint16_t buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, - uint16_t mask, int *bcnt, - uint32_t *buf) { + uint16_t mask, + int *bcnt, uint32_t *buf) { uint16_t val; if (rng == 0) return off; @@ -1315,16 +1319,17 @@ static NPY_INLINE uint16_t buffered_bounded_uint16(brng_t *brng_state, return off + val; } -uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, - uint16_t rng, uint16_t mask, int *bcnt, - uint32_t *buf, bool use_masked_generator) { +uint16_t random_buffered_bounded_uint16(brng_t *brng_state, + uint16_t off, uint16_t rng, + uint16_t mask, bool use_masked, + int *bcnt, uint32_t *buf) { return buffered_bounded_uint16(brng_state, off, rng, mask, bcnt, buf); } static NPY_INLINE uint8_t buffered_bounded_uint8(brng_t *brng_state, uint8_t off, uint8_t rng, - uint8_t mask, int *bcnt, - uint32_t *buf) { + uint8_t mask, + int *bcnt, uint32_t *buf) { uint8_t val; if (rng == 0) return off; @@ -1341,16 +1346,17 @@ static NPY_INLINE uint8_t buffered_bounded_uint8(brng_t *brng_state, return off + val; } -uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, - uint8_t rng, uint8_t mask, int *bcnt, - uint32_t *buf, bool use_masked_generator) { +uint8_t random_buffered_bounded_uint8(brng_t *brng_state, + uint8_t off, uint8_t rng, + uint8_t mask, bool use_masked, + int *bcnt, uint32_t *buf) { return buffered_bounded_uint8(brng_state, off, rng, mask, bcnt, buf); } static NPY_INLINE npy_bool buffered_bounded_bool(brng_t *brng_state, npy_bool off, npy_bool rng, - npy_bool mask, int *bcnt, - uint32_t *buf) { + npy_bool mask, + int *bcnt, uint32_t *buf) { if (rng == 0) return off; if (!(bcnt[0])) { @@ -1363,14 +1369,17 @@ static NPY_INLINE npy_bool buffered_bounded_bool(brng_t *brng_state, return (buf[0] & 0x00000001UL) != 0; } -npy_bool random_buffered_bounded_bool(brng_t *brng_state, npy_bool off, - npy_bool rng, npy_bool mask, int *bcnt, - uint32_t *buf, bool use_masked_generator) { +npy_bool random_buffered_bounded_bool(brng_t *brng_state, + npy_bool off, npy_bool rng, + npy_bool mask, bool use_masked, + int *bcnt, uint32_t *buf) { return buffered_bounded_bool(brng_state, off, rng, mask, bcnt, buf); } -void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, - npy_intp cnt, uint64_t *out, bool use_masked_generator) { +void random_bounded_uint64_fill(brng_t *brng_state, + uint64_t off, uint64_t rng, npy_intp cnt, + bool use_masked, + uint64_t *out) { uint64_t mask; npy_intp i; @@ -1385,8 +1394,10 @@ void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, * Fills an array with cnt random npy_uint32 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, - npy_intp cnt, uint32_t *out, bool use_masked_generator) { +void random_bounded_uint32_fill(brng_t *brng_state, + uint32_t off, uint32_t rng, npy_intp cnt, + bool use_masked, + uint32_t *out) { npy_intp i; if (rng == 0) { @@ -1396,7 +1407,7 @@ void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, return; } - if (use_masked_generator) { + if (use_masked) { uint32_t mask; // Smallest bit mask >= max mask = (uint32_t)gen_mask(rng); @@ -1414,8 +1425,10 @@ void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, * Fills an array with cnt random npy_uint16 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, - npy_intp cnt, uint16_t *out, bool use_masked_generator) { +void random_bounded_uint16_fill(brng_t *brng_state, + uint16_t off, uint16_t rng, npy_intp cnt, + bool use_masked, + uint16_t *out) { uint16_t mask; npy_intp i; uint32_t buf = 0; @@ -1432,8 +1445,10 @@ void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, * Fills an array with cnt random npy_uint8 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, uint8_t rng, - npy_intp cnt, uint8_t *out, bool use_masked_generator) { +void random_bounded_uint8_fill(brng_t *brng_state, + uint8_t off, uint8_t rng, npy_intp cnt, + bool use_masked, + uint8_t *out) { uint8_t mask; npy_intp i; uint32_t buf = 0; @@ -1450,8 +1465,10 @@ void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, uint8_t rng, * Fills an array with cnt random npy_bool between off and off + rng * inclusive. */ -void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, npy_bool rng, - npy_intp cnt, npy_bool *out, bool use_masked_generator) { +void random_bounded_bool_fill(brng_t *brng_state, + npy_bool off, npy_bool rng, npy_intp cnt, + bool use_masked, + npy_bool *out) { npy_bool mask = 0; npy_intp i; uint32_t buf = 0; diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index 0406318e73a3..bbd80ac8ee71 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -174,42 +174,45 @@ DECLDIR int64_t random_hypergeometric(brng_t *brng_state, int64_t good, int64_t bad, int64_t sample); DECLDIR uint64_t random_interval(brng_t *brng_state, uint64_t max); -DECLDIR uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, - uint64_t rng, uint64_t mask); + +DECLDIR uint64_t random_bounded_uint64(brng_t *brng_state, + uint64_t off, uint64_t rng, + uint64_t mask); + DECLDIR uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, - uint32_t mask, int *bcnt, - uint32_t *buf, - bool use_masked_generator); + uint32_t mask, bool use_masked, + int *bcnt, uint32_t *buf); DECLDIR uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, - uint16_t mask, int *bcnt, - uint32_t *buf, - bool use_masked_generator); -DECLDIR uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, - uint8_t rng, uint8_t mask, - int *bcnt, uint32_t *buf, - bool use_masked_generator); -DECLDIR npy_bool random_buffered_bounded_bool(brng_t *brng_state, npy_bool off, - npy_bool rng, npy_bool mask, - int *bcnt, uint32_t *buf, - bool use_masked_generator); -DECLDIR void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, - uint64_t rng, npy_intp cnt, - uint64_t *out, - bool use_masked_generator); -DECLDIR void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, - uint32_t rng, npy_intp cnt, - uint32_t *out, - bool use_masked_generator); -DECLDIR void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, - uint16_t rng, npy_intp cnt, - uint16_t *out, - bool use_masked_generator); -DECLDIR void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, - uint8_t rng, npy_intp cnt, uint8_t *out, - bool use_masked_generator); -DECLDIR void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, - npy_bool rng, npy_intp cnt, - npy_bool *out, - bool use_masked_generator); + uint16_t mask, bool use_masked, + int *bcnt, uint32_t *buf); +DECLDIR uint8_t random_buffered_bounded_uint8(brng_t *brng_state, + uint8_t off, uint8_t rng, + uint8_t mask, bool use_masked, + int *bcnt, uint32_t *buf); +DECLDIR npy_bool random_buffered_bounded_bool(brng_t *brng_state, + npy_bool off, npy_bool rng, + npy_bool mask, bool use_masked, + int *bcnt, uint32_t *buf); + +DECLDIR void random_bounded_uint64_fill(brng_t *brng_state, + uint64_t off, uint64_t rng, npy_intp cnt, + bool use_masked, + uint64_t *out); +DECLDIR void random_bounded_uint32_fill(brng_t *brng_state, + uint32_t off, uint32_t rng, npy_intp cnt, + bool use_masked, + uint32_t *out); +DECLDIR void random_bounded_uint16_fill(brng_t *brng_state, + uint16_t off, uint16_t rng, npy_intp cnt, + bool use_masked, + uint16_t *out); +DECLDIR void random_bounded_uint8_fill(brng_t *brng_state, + npy_bool off, uint8_t rng, npy_intp cnt, + bool use_masked, + uint8_t *out); +DECLDIR void random_bounded_bool_fill(brng_t *brng_state, + npy_bool off, npy_bool rng, npy_intp cnt, + bool use_masked, + npy_bool *out); diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 2ab6bd2d326f..01c51c449114 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -436,6 +436,24 @@ def test_randint(self): [-48, -66]]) assert_array_equal(actual, desired) + def test_randint_masked(self): + """ Test masked rejection sampling algorithm to generate array of uint32 in an interval. """ + mt19937.seed(self.seed) + actual = mt19937.randint(0, 99, size=(3, 2), dtype=np.uint32, use_masked=True) + desired = np.array([[2, 47], + [12, 51], + [33, 43]], dtype=np.uint32) + assert_array_equal(actual, desired) + + def test_randint_lemire(self): + """ Test lemire algorithm to generate array of uint32 in an interval. """ + mt19937.seed(self.seed) + actual = mt19937.randint(0, 99, size=(3, 2), dtype=np.uint32, use_masked=False) + desired = np.array([[61, 33], + [58, 14], + [87, 23]], dtype=np.uint32) + assert_array_equal(actual, desired) + def test_random_integers(self): mt19937.seed(self.seed) with suppress_warnings() as sup: From d105c4327651434718db3bdfb0aadd2579c1e40a Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 5 Oct 2018 09:16:21 +0100 Subject: [PATCH 138/279] DOC: Add license files Add license files for project and components closes #25 --- _randomgen/LICENSE.md | 71 +++++++++++++++++++ _randomgen/MANIFEST.in | 3 +- _randomgen/randomgen/src/common/LICENSE.md | 29 ++++++++ .../randomgen/src/distributions/LICENSE.md | 30 ++++++++ .../src/dsfmt/{LICENSE.txt => LICENSE.md} | 22 +++--- _randomgen/randomgen/src/entropy/LICENSE.md | 25 +++++++ _randomgen/randomgen/src/legacy/LICENSE.md | 30 ++++++++ _randomgen/randomgen/src/mt19937/LICENSE.md | 61 ++++++++++++++++ _randomgen/randomgen/src/pcg32/LICENSE.md | 22 ++++++ _randomgen/randomgen/src/pcg64/LICENSE.md | 22 ++++++ _randomgen/randomgen/src/philox/LICENSE.md | 31 ++++++++ .../randomgen/src/splitmix64/LICENSE.md | 9 +++ _randomgen/randomgen/src/threefry/LICENSE.md | 31 ++++++++ .../randomgen/src/threefry32/LICENSE.md | 31 ++++++++ .../randomgen/src/xoroshiro128/LICENSE.md | 9 +++ .../randomgen/src/xorshift1024/LICENSE.md | 9 +++ _randomgen/setup.cfg | 4 ++ 17 files changed, 428 insertions(+), 11 deletions(-) create mode 100644 _randomgen/LICENSE.md create mode 100644 _randomgen/randomgen/src/common/LICENSE.md create mode 100644 _randomgen/randomgen/src/distributions/LICENSE.md rename _randomgen/randomgen/src/dsfmt/{LICENSE.txt => LICENSE.md} (65%) create mode 100644 _randomgen/randomgen/src/entropy/LICENSE.md create mode 100644 _randomgen/randomgen/src/legacy/LICENSE.md create mode 100644 _randomgen/randomgen/src/mt19937/LICENSE.md create mode 100644 _randomgen/randomgen/src/pcg32/LICENSE.md create mode 100644 _randomgen/randomgen/src/pcg64/LICENSE.md create mode 100644 _randomgen/randomgen/src/philox/LICENSE.md create mode 100644 _randomgen/randomgen/src/splitmix64/LICENSE.md create mode 100644 _randomgen/randomgen/src/threefry/LICENSE.md create mode 100644 _randomgen/randomgen/src/threefry32/LICENSE.md create mode 100644 _randomgen/randomgen/src/xoroshiro128/LICENSE.md create mode 100644 _randomgen/randomgen/src/xorshift1024/LICENSE.md diff --git a/_randomgen/LICENSE.md b/_randomgen/LICENSE.md new file mode 100644 index 000000000000..e159d505e845 --- /dev/null +++ b/_randomgen/LICENSE.md @@ -0,0 +1,71 @@ +**Copyright (c) 2018 Kevin Sheppard. All rights reserved.** + +Developed by: Kevin Sheppard (, +) +[http://www.kevinsheppard.com](http://www.kevinsheppard.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimers. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimers in the documentation and/or +other materials provided with the distribution. + +Neither the names of Kevin Sheppard, nor the names of any contributors may be +used to endorse or promote products derived from this Software without specific +prior written permission. + +**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH +THE SOFTWARE.** + +## NumPy + +Many parts of this module have been derived from NumPy. + +Copyright (c) 2005-2017, NumPy Developers. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the NumPy Developers nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## Components + +Many of the components have their own license terms which are stored +with the source for the component. \ No newline at end of file diff --git a/_randomgen/MANIFEST.in b/_randomgen/MANIFEST.in index b6a20a4feaa1..61fffb8db518 100644 --- a/_randomgen/MANIFEST.in +++ b/_randomgen/MANIFEST.in @@ -5,5 +5,6 @@ include randomgen/_version.py include requirements.txt include README.md include README.rst -recursive-include randomgen *.py *.pyx *.px[di] *.h *.in *.csv +include LICENSE.md +recursive-include randomgen *.py *.pyx *.px[di] *.h *.in *.csv *.md graft randomgen/src diff --git a/_randomgen/randomgen/src/common/LICENSE.md b/_randomgen/randomgen/src/common/LICENSE.md new file mode 100644 index 000000000000..71bf8cf4624b --- /dev/null +++ b/_randomgen/randomgen/src/common/LICENSE.md @@ -0,0 +1,29 @@ +ISO C9x compliant stdint.h for Microsoft Visual Studio +Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 + +Copyright (c) 2006-2013 Alexander Chemeris + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the product nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/_randomgen/randomgen/src/distributions/LICENSE.md b/_randomgen/randomgen/src/distributions/LICENSE.md new file mode 100644 index 000000000000..88b1791b200f --- /dev/null +++ b/_randomgen/randomgen/src/distributions/LICENSE.md @@ -0,0 +1,30 @@ +Copyright (c) 2005-2017, NumPy Developers. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +* Neither the name of the NumPy Developers nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/_randomgen/randomgen/src/dsfmt/LICENSE.txt b/_randomgen/randomgen/src/dsfmt/LICENSE.md similarity index 65% rename from _randomgen/randomgen/src/dsfmt/LICENSE.txt rename to _randomgen/randomgen/src/dsfmt/LICENSE.md index 4570c4603b21..d59568f6b16c 100644 --- a/_randomgen/randomgen/src/dsfmt/LICENSE.txt +++ b/_randomgen/randomgen/src/dsfmt/LICENSE.md @@ -1,3 +1,5 @@ +# DSFMT + Copyright (c) 2007, 2008, 2009 Mutsuo Saito, Makoto Matsumoto and Hiroshima University. Copyright (c) 2011, 2002 Mutsuo Saito, Makoto Matsumoto, Hiroshima @@ -8,16 +10,16 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of the Hiroshima University nor the names of - its contributors may be used to endorse or promote products - derived from this software without specific prior written - permission. +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. +* Neither the name of the Hiroshima University nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT diff --git a/_randomgen/randomgen/src/entropy/LICENSE.md b/_randomgen/randomgen/src/entropy/LICENSE.md new file mode 100644 index 000000000000..b7276aad786e --- /dev/null +++ b/_randomgen/randomgen/src/entropy/LICENSE.md @@ -0,0 +1,25 @@ +# ENTROPY + +_Parts of this module were derived from PCG_ + + +PCG Random Number Generation for C. + +Copyright 2014 Melissa O'Neill + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +For additional information about the PCG random number generation scheme, +including its license and other licensing options, visit + + http://www.pcg-random.org diff --git a/_randomgen/randomgen/src/legacy/LICENSE.md b/_randomgen/randomgen/src/legacy/LICENSE.md new file mode 100644 index 000000000000..88b1791b200f --- /dev/null +++ b/_randomgen/randomgen/src/legacy/LICENSE.md @@ -0,0 +1,30 @@ +Copyright (c) 2005-2017, NumPy Developers. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +* Neither the name of the NumPy Developers nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/_randomgen/randomgen/src/mt19937/LICENSE.md b/_randomgen/randomgen/src/mt19937/LICENSE.md new file mode 100644 index 000000000000..f65c3d46e624 --- /dev/null +++ b/_randomgen/randomgen/src/mt19937/LICENSE.md @@ -0,0 +1,61 @@ +# MT19937 + +Copyright (c) 2003-2005, Jean-Sebastien Roy (js@jeannot.org) + +The rk_random and rk_seed functions algorithms and the original design of +the Mersenne Twister RNG: + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Original algorithm for the implementation of rk_interval function from +Richard J. Wagner's implementation of the Mersenne Twister RNG, optimised by +Magnus Jonsson. + +Constants used in the rk_double implementation by Isaku Wada. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/_randomgen/randomgen/src/pcg32/LICENSE.md b/_randomgen/randomgen/src/pcg32/LICENSE.md new file mode 100644 index 000000000000..3db2ac2e8e78 --- /dev/null +++ b/_randomgen/randomgen/src/pcg32/LICENSE.md @@ -0,0 +1,22 @@ +# PCG32 + +PCG Random Number Generation for C. + +Copyright 2014 Melissa O'Neill + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +For additional information about the PCG random number generation scheme, +including its license and other licensing options, visit + + http://www.pcg-random.org diff --git a/_randomgen/randomgen/src/pcg64/LICENSE.md b/_randomgen/randomgen/src/pcg64/LICENSE.md new file mode 100644 index 000000000000..dd6a17ee8a86 --- /dev/null +++ b/_randomgen/randomgen/src/pcg64/LICENSE.md @@ -0,0 +1,22 @@ +# PCG64 + +PCG Random Number Generation for C. + +Copyright 2014 Melissa O'Neill + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +For additional information about the PCG random number generation scheme, +including its license and other licensing options, visit + + http://www.pcg-random.org diff --git a/_randomgen/randomgen/src/philox/LICENSE.md b/_randomgen/randomgen/src/philox/LICENSE.md new file mode 100644 index 000000000000..4a9f6bb29490 --- /dev/null +++ b/_randomgen/randomgen/src/philox/LICENSE.md @@ -0,0 +1,31 @@ +# THREEFRY + +Copyright 2010-2012, D. E. Shaw Research. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of D. E. Shaw Research nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/_randomgen/randomgen/src/splitmix64/LICENSE.md b/_randomgen/randomgen/src/splitmix64/LICENSE.md new file mode 100644 index 000000000000..3c4d73b920f6 --- /dev/null +++ b/_randomgen/randomgen/src/splitmix64/LICENSE.md @@ -0,0 +1,9 @@ +# SPLITMIX64 + +Written in 2015 by Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . \ No newline at end of file diff --git a/_randomgen/randomgen/src/threefry/LICENSE.md b/_randomgen/randomgen/src/threefry/LICENSE.md new file mode 100644 index 000000000000..4a9f6bb29490 --- /dev/null +++ b/_randomgen/randomgen/src/threefry/LICENSE.md @@ -0,0 +1,31 @@ +# THREEFRY + +Copyright 2010-2012, D. E. Shaw Research. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of D. E. Shaw Research nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/_randomgen/randomgen/src/threefry32/LICENSE.md b/_randomgen/randomgen/src/threefry32/LICENSE.md new file mode 100644 index 000000000000..591cd75f4e79 --- /dev/null +++ b/_randomgen/randomgen/src/threefry32/LICENSE.md @@ -0,0 +1,31 @@ +# THREEFRY32 + +Copyright 2010-2012, D. E. Shaw Research. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of D. E. Shaw Research nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/_randomgen/randomgen/src/xoroshiro128/LICENSE.md b/_randomgen/randomgen/src/xoroshiro128/LICENSE.md new file mode 100644 index 000000000000..969430149615 --- /dev/null +++ b/_randomgen/randomgen/src/xoroshiro128/LICENSE.md @@ -0,0 +1,9 @@ +# XOROSHIRO128 + +Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . \ No newline at end of file diff --git a/_randomgen/randomgen/src/xorshift1024/LICENSE.md b/_randomgen/randomgen/src/xorshift1024/LICENSE.md new file mode 100644 index 000000000000..3ca8ed4b9898 --- /dev/null +++ b/_randomgen/randomgen/src/xorshift1024/LICENSE.md @@ -0,0 +1,9 @@ +# XORSHIFT1024 + +Written in 2017 by Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . \ No newline at end of file diff --git a/_randomgen/setup.cfg b/_randomgen/setup.cfg index 7e46c5c532af..b25ab5078a40 100644 --- a/_randomgen/setup.cfg +++ b/_randomgen/setup.cfg @@ -1,3 +1,7 @@ +[metadata] +description-file = README.md +license_file = LICENSE.md + [versioneer] VCS = git style = pep440 From 0613607cfefc117a3f0a212e389d4a6d0d39a683 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 5 Oct 2018 09:18:48 +0100 Subject: [PATCH 139/279] MAINT: Remove invalid escape Use raw string to avoid escape warning in regex --- _randomgen/randomgen/_testing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_randomgen/randomgen/_testing.py b/_randomgen/randomgen/_testing.py index 86c5ea2b157a..07d41677b7c4 100644 --- a/_randomgen/randomgen/_testing.py +++ b/_randomgen/randomgen/_testing.py @@ -136,7 +136,7 @@ def _filter(self, category=Warning, message="", module=None, warnings.filterwarnings( "always", category=category, message=message) else: - module_regex = module.__name__.replace('.', '\.') + '$' + module_regex = module.__name__.replace('.', r'\.') + '$' warnings.filterwarnings( "always", category=category, message=message, module=module_regex) @@ -224,7 +224,7 @@ def __enter__(self): warnings.filterwarnings( "always", category=cat, message=mess) else: - module_regex = mod.__name__.replace('.', '\.') + '$' + module_regex = mod.__name__.replace('.', r'\.') + '$' warnings.filterwarnings( "always", category=cat, message=mess, module=module_regex) From 70f7c110ab62405df691d22d5a16b503ae2b93b0 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 5 Oct 2018 21:19:05 +0100 Subject: [PATCH 140/279] REF: Add path using umul Add umul128 intrinsic support for 64bit windows --- _randomgen/randomgen/src/pcg64/pcg64.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/_randomgen/randomgen/src/pcg64/pcg64.h b/_randomgen/randomgen/src/pcg64/pcg64.h index f3611ce08d2f..854930176f09 100644 --- a/_randomgen/randomgen/src/pcg64/pcg64.h +++ b/_randomgen/randomgen/src/pcg64/pcg64.h @@ -32,6 +32,10 @@ #define inline __inline __forceinline #else #include +#if _MSC_VER >= 1900 && _M_AMD64 +#include +#pragma intrinsic(_umul128) +#endif #endif #if __GNUC_GNU_INLINE__ && !defined(__cplusplus) @@ -94,6 +98,10 @@ static inline pcg128_t _pcg128_add(pcg128_t a, pcg128_t b) { static inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t *z1, uint64_t *z0) { + +#if defined _WIN32 && _MSC_VER >= 1900 && _M_AMD64 + z0[0] = _umul128(x, y, z1); +#else uint64_t x0, x1, y0, y1; uint64_t w0, w1, w2, t; /* Lower 64 bits are straightforward clock-arithmetic. */ @@ -109,6 +117,8 @@ static inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t *z1, w2 = t >> 32; w1 += x0 * y1; *z1 = x1 * y1 + w2 + (w1 >> 32); +#endif + } static inline pcg128_t _pcg128_mult(pcg128_t a, pcg128_t b) { From e21778d418c7ee71b5e36c609c74d3de15ed032e Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 11 Oct 2018 12:12:46 +0200 Subject: [PATCH 141/279] Added Lemire algorithms for generating random numbers within an interval for 64 unsigned integers. --- _randomgen/benchmark.py | 26 ++++- _randomgen/randomgen/bounded_integers.pyx.in | 4 +- _randomgen/randomgen/distributions.pxd | 2 +- .../src/distributions/distributions.c | 94 +++++++++++++++---- .../src/distributions/distributions.h | 2 +- .../randomgen/tests/test_numpy_mt19937.py | 11 ++- 6 files changed, 114 insertions(+), 25 deletions(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 3c86f72959f0..26ab84257c37 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -96,7 +96,7 @@ def timer_32bit(): def timer_32bit_bounded(): # info = np.iinfo(np.uint32) # min, max = info.min, info.max - min, max = 0, 1024 # Worst case for masking & rejection algorithm! + min, max = 0, 1536 - 1 # Worst case for masking & rejection algorithm! dist = 'random_uintegers' @@ -116,6 +116,29 @@ def timer_32bit_bounded(): run_timer(dist, command, command_numpy, SETUP, '32-bit bounded unsigned integers') +def timer_64bit_bounded(): + # info = np.iinfo(np.uint64) + # min, max = info.min, info.max + min, max = 0, 1536 - 1 # Worst case for masking & rejection algorithm! + + dist = 'random_uintegers' + + # Note on performance of generating random numbers in an interval: + # use_masked=True : masking and rejection sampling is used to generate a random number in an interval. + # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. + # Lemire's algorithm has improved performance when {max}+1 is not a power of two. + + # command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64, use_masked=True)' # Use masking & rejection. + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64, use_masked=False)' # Use Lemire's algo. + + command = command.format(min=min, max=max) + + command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64)' + command_numpy = command_numpy.format(min=min, max=max) + + run_timer(dist, command, command_numpy, SETUP, '64-bit bounded unsigned integers') + + def timer_64bit(): info = np.iinfo(np.uint64) min, max = info.min, info.max @@ -145,5 +168,6 @@ def timer_normal_zig(): timer_raw() timer_32bit() timer_32bit_bounded() + timer_64bit_bounded() timer_64bit() timer_normal_zig() diff --git a/_randomgen/randomgen/bounded_integers.pyx.in b/_randomgen/randomgen/bounded_integers.pyx.in index becf18a1afae..eb8555b310d0 100644 --- a/_randomgen/randomgen/bounded_integers.pyx.in +++ b/_randomgen/randomgen/bounded_integers.pyx.in @@ -104,8 +104,6 @@ cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, The internal generator does not have this issue since it generates from the closes interval [low, high-1] and high-1 is always in range for the 64 bit integer type. - - Note: use_masked currently ignored for 64bit generators. """ cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr @@ -162,7 +160,7 @@ cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, if rng != last_rng: mask = _gen_mask(rng) - out_data[i] = random_bounded_uint64(state, off, rng, mask) + out_data[i] = random_bounded_uint64(state, off, rng, mask, use_masked) np.PyArray_MultiIter_NEXT(it) diff --git a/_randomgen/randomgen/distributions.pxd b/_randomgen/randomgen/distributions.pxd index 67835cde697d..3a25a318ddfb 100644 --- a/_randomgen/randomgen/distributions.pxd +++ b/_randomgen/randomgen/distributions.pxd @@ -101,7 +101,7 @@ cdef extern from "src/distributions/distributions.h": uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, - uint64_t mask) nogil + uint64_t mask, bint use_masked) nogil uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index b16367325c55..7d9f180c0b56 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1205,12 +1205,10 @@ static NPY_INLINE uint64_t gen_mask(uint64_t max) { * inclusive. The numbers wrap if rng is sufficiently large. */ -static NPY_INLINE uint64_t bounded_uint64(brng_t *brng_state, - uint64_t off, uint64_t rng, - uint64_t mask) { +static NPY_INLINE uint64_t bounded_masked_uint64(brng_t *brng_state, + uint64_t off, uint64_t rng, + uint64_t mask) { uint64_t val; - if (rng == 0) - return off; if (rng <= 0xffffffffUL) { while ((val = (next_uint32(brng_state) & mask)) > rng) @@ -1222,10 +1220,56 @@ static NPY_INLINE uint64_t bounded_uint64(brng_t *brng_state, return off + val; } +static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, + uint64_t off, uint64_t rng) { + /* + * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 + * + * The buffer and buffer count are not used here but are included to allow + * this function to be templated with the similar uint8 and uint16 + * functions + */ + const uint64_t rng_excl = rng + 1; + + __uint128_t m; + uint64_t leftover; + + if (rng == 0xFFFFFFFFFFFFFFFFULL) { + return next_uint64(brng_state); + /* ToDo: Move this code to caller to prevent this check on each call when generating arrays of numbers. */ + } + + /* Generate a scaled random number. */ + m = ((__uint128_t)next_uint64(brng_state)) * rng_excl; + + /* Rejection sampling to remove any bias */ + leftover = m & 0xFFFFFFFFFFFFFFFFULL; + + if (leftover < rng_excl) { + const uint64_t threshold = -rng_excl % rng_excl; //same as:((uint64_t)(0x10000000000000000ULLL - rng_excl)) % rng_excl; + + while (leftover < threshold) { + m = ((__uint128_t)next_uint64(brng_state)) * rng_excl; + leftover = m & 0xFFFFFFFFFFFFFFFFULL; + /* ToDo: It isn't strictly necessary to compute the entire 128 bit in each draw, only the lower 64 bits. */ + } + } + + return off + (m >> 64); +} + uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, - uint64_t mask) { - return bounded_uint64(brng_state, off, rng, mask); + uint64_t mask, bool use_masked) { + if (rng == 0) { + return off; + } else { + if (use_masked) { + return bounded_masked_uint64(brng_state, off, rng, mask); + } else { + return bounded_lemire_uint64(brng_state, off, rng); + } + } } static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, @@ -1253,10 +1297,11 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, * functions */ const uint32_t rng_excl = rng + 1; + uint64_t m; uint32_t leftover; - if (rng == 0xFFFFFFFF) { + if (rng == 0xFFFFFFFFUL) { return next_uint32(brng_state); /* ToDo: Move this code to caller to prevent this check on each call when generating arrays of numbers. */ } @@ -1265,14 +1310,14 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, m = ((uint64_t)next_uint32(brng_state)) * rng_excl; /* Rejection sampling to remove any bias */ - leftover = m & ((uint32_t)((1ULL << 32) - 1)); + leftover = m & 0xFFFFFFFFUL; if (leftover < rng_excl) { - const uint32_t threshold = ((uint32_t)((1ULL << 32) - rng_excl)) % rng_excl; + const uint32_t threshold = -rng_excl % rng_excl; //same as:((uint64_t)(0x100000000ULL - rng_excl)) % rng_excl; while (leftover < threshold) { m = ((uint64_t)next_uint32(brng_state)) * rng_excl; - leftover = m & ((uint32_t)((1ULL << 32) - 1)); + leftover = m & 0xFFFFFFFFUL; } } @@ -1380,13 +1425,26 @@ void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, npy_intp cnt, bool use_masked, uint64_t *out) { - uint64_t mask; npy_intp i; - /* Smallest bit mask >= max */ - mask = gen_mask(rng); - for (i = 0; i < cnt; i++) { - out[i] = bounded_uint64(brng_state, off, rng, mask); + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + if (use_masked) { + // Smallest bit mask >= max + uint64_t mask = gen_mask(rng); + + for (i = 0; i < cnt; i++) { + out[i] = bounded_masked_uint64(brng_state, off, rng, mask); + } + } else { + for (i = 0; i < cnt; i++) { + out[i] = bounded_lemire_uint64(brng_state, off, rng); + } } } @@ -1408,9 +1466,9 @@ void random_bounded_uint32_fill(brng_t *brng_state, } if (use_masked) { - uint32_t mask; // Smallest bit mask >= max - mask = (uint32_t)gen_mask(rng); + uint32_t mask = (uint32_t)gen_mask(rng); + for (i = 0; i < cnt; i++) { out[i] = bounded_masked_uint32(brng_state, off, rng, mask); } diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index bbd80ac8ee71..3bfea33e6c44 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -177,7 +177,7 @@ DECLDIR uint64_t random_interval(brng_t *brng_state, uint64_t max); DECLDIR uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, - uint64_t mask); + uint64_t mask, bool use_masked); DECLDIR uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 01c51c449114..7ee896d352fa 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -445,7 +445,7 @@ def test_randint_masked(self): [33, 43]], dtype=np.uint32) assert_array_equal(actual, desired) - def test_randint_lemire(self): + def test_randint_lemire_32(self): """ Test lemire algorithm to generate array of uint32 in an interval. """ mt19937.seed(self.seed) actual = mt19937.randint(0, 99, size=(3, 2), dtype=np.uint32, use_masked=False) @@ -454,6 +454,15 @@ def test_randint_lemire(self): [87, 23]], dtype=np.uint32) assert_array_equal(actual, desired) + def test_randint_lemire_64(self): + """ Test lemire algorithm to generate array of uint64 in an interval. """ + mt19937.seed(self.seed) + actual = mt19937.randint(0, 99 + 0xFFFFFFFFF, size=(3, 2), dtype=np.uint64, use_masked=False) + desired = np.array([[42523252834, 40656066204], + [61069871386, 61274051182], + [31443797706, 53476677934]], dtype=np.uint64) + assert_array_equal(actual, desired) + def test_random_integers(self): mt19937.seed(self.seed) with suppress_warnings() as sup: From 8bd04b486448130401d9ffeb03ad81a8de7c83f1 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 11 Oct 2018 12:18:51 +0200 Subject: [PATCH 142/279] Comment update. Still need to add cross platform AND architecture alternative for 128 bit multiply. --- _randomgen/randomgen/generator.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 1e87f001f59b..dda4fa38a67a 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -607,7 +607,7 @@ cdef class RandomGenerator: use_masked : bool If True the generator uses rejection sampling with a bit mask to reject random numbers that are out of bounds. If False the generator - will use Lemire's rejection sampling algorithm when available. + will use Lemire's rejection sampling algorithm. .. versionadded:: 1.15.1 From 011f6a28b4ec57a529499c094fd7dcf010a37305 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Fri, 12 Oct 2018 10:01:33 +0200 Subject: [PATCH 143/279] Some small shuffles and a ToDo comment while testing. bounded_lemire_uint64 should do a check for rng below 32bit limit in which case the 32 bit generator can be used. --- _randomgen/benchmark.py | 14 +++++++++----- .../randomgen/src/distributions/distributions.c | 8 +++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 26ab84257c37..91fa50d828d3 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -96,7 +96,9 @@ def timer_32bit(): def timer_32bit_bounded(): # info = np.iinfo(np.uint32) # min, max = info.min, info.max - min, max = 0, 1536 - 1 # Worst case for masking & rejection algorithm! + + min, max = 0, 1025 - 1 # WORST case for masking & rejection algorithm! + # min, max = 0, 1536 - 1 # AVERAGE case for masking & rejection algorithm! dist = 'random_uintegers' @@ -105,8 +107,8 @@ def timer_32bit_bounded(): # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. # Lemire's algorithm has improved performance when {max}+1 is not a power of two. - # command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=True)' # Use masking & rejection. - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=False)' # Use Lemire's algo. + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=True)' # Use masking & rejection. + # command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=False)' # Use Lemire's algo. command = command.format(min=min, max=max) @@ -119,7 +121,9 @@ def timer_32bit_bounded(): def timer_64bit_bounded(): # info = np.iinfo(np.uint64) # min, max = info.min, info.max - min, max = 0, 1536 - 1 # Worst case for masking & rejection algorithm! + + min, max = 0, 1025 - 1 # WORST case for masking & rejection algorithm! + # min, max = 0, 1536 - 1 # AVERAGE case for masking & rejection algorithm! dist = 'random_uintegers' @@ -168,6 +172,6 @@ def timer_normal_zig(): timer_raw() timer_32bit() timer_32bit_bounded() - timer_64bit_bounded() timer_64bit() + timer_64bit_bounded() timer_normal_zig() diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 7d9f180c0b56..8d6dc6174dde 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1210,6 +1210,8 @@ static NPY_INLINE uint64_t bounded_masked_uint64(brng_t *brng_state, uint64_t mask) { uint64_t val; + /* ToDo: Add this if condition to bounded_lemire_uint64 OR move to caller to save overhead. */ + if (rng <= 0xffffffffUL) { while ((val = (next_uint32(brng_state) & mask)) > rng) ; @@ -1282,8 +1284,12 @@ static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, */ uint32_t val; + /* printf("\n"); */ while ((val = (next_uint32(brng_state) & mask)) > rng) - ; + /*printf("reject: %u \n", val)*/; + + /* printf("accept: %u \n", val); */ + return off + val; } From f346c91fec4d590726de4a5652a8dd52c56524f6 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 18 Oct 2018 00:40:03 +0200 Subject: [PATCH 144/279] Test non 128bit code. --- .../src/distributions/distributions.c | 92 ++++++++++++++----- 1 file changed, 70 insertions(+), 22 deletions(-) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 8d6dc6174dde..57261502474e 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1230,21 +1230,19 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, * The buffer and buffer count are not used here but are included to allow * this function to be templated with the similar uint8 and uint16 * functions + * + * Note: `rng` should not be 0xFFFFFFFFFFFFFFFF. When this happens `rng_excl` becomes zero and `off` is returned. */ const uint64_t rng_excl = rng + 1; - +/* +#if __SIZEOF_INT128__ __uint128_t m; uint64_t leftover; - if (rng == 0xFFFFFFFFFFFFFFFFULL) { - return next_uint64(brng_state); - /* ToDo: Move this code to caller to prevent this check on each call when generating arrays of numbers. */ - } - - /* Generate a scaled random number. */ + // Generate a scaled random number. m = ((__uint128_t)next_uint64(brng_state)) * rng_excl; - /* Rejection sampling to remove any bias */ + // Rejection sampling to remove any bias. leftover = m & 0xFFFFFFFFFFFFFFFFULL; if (leftover < rng_excl) { @@ -1253,11 +1251,47 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, while (leftover < threshold) { m = ((__uint128_t)next_uint64(brng_state)) * rng_excl; leftover = m & 0xFFFFFFFFFFFFFFFFULL; - /* ToDo: It isn't strictly necessary to compute the entire 128 bit in each draw, only the lower 64 bits. */ } } return off + (m >> 64); +#else*/ + uint64_t m1; + uint64_t x; + uint64_t leftover; + + x = next_uint64(brng_state); + + // Rejection sampling to remove any bias/. + leftover = x * rng_excl; + + if (leftover < rng_excl) { + const uint64_t threshold = -rng_excl % rng_excl; //same as:((uint64_t)(0x10000000000000000ULLL - rng_excl)) % rng_excl; + + while (leftover < threshold) { + x = next_uint64(brng_state); + leftover = x * rng_excl; + } + } + + { /* Calc high 64 bits of x * rng_excl. */ + uint64_t x0, x1, rng_excl0, rng_excl1; + uint64_t w0, w1, w2, t; + + x0 = x & 0xFFFFFFFFULL; + x1 = x >> 32; + rng_excl0 = rng_excl & 0xFFFFFFFFULL; + rng_excl1 = rng_excl >> 32; + w0 = x0 * rng_excl0; + t = x1 * rng_excl0 + (w0 >> 32); + w1 = t & 0xFFFFFFFFULL; + w2 = t >> 32; + w1 += x0 * rng_excl1; + m1 = x1 * rng_excl1 + w2 + (w1 >> 32); + } + + return off + m1; +//#endif } uint64_t random_bounded_uint64(brng_t *brng_state, @@ -1269,6 +1303,10 @@ uint64_t random_bounded_uint64(brng_t *brng_state, if (use_masked) { return bounded_masked_uint64(brng_state, off, rng, mask); } else { + if (rng == 0xFFFFFFFFFFFFFFFFULL) { /* Lemire64 doesn't support rng = 0xFFFFFFFFFFFFFFFF. */ + return off + next_uint64(brng_state); + } + return bounded_lemire_uint64(brng_state, off, rng); } } @@ -1284,11 +1322,8 @@ static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, */ uint32_t val; - /* printf("\n"); */ while ((val = (next_uint32(brng_state) & mask)) > rng) - /*printf("reject: %u \n", val)*/; - - /* printf("accept: %u \n", val); */ + ; return off + val; } @@ -1301,17 +1336,14 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, * The buffer and buffer count are not used here but are included to allow * this function to be templated with the similar uint8 and uint16 * functions + * + * Note: `rng` should not be 0xFFFFFFFF. When this happens `rng_excl` becomes zero and `off` is returned. */ const uint32_t rng_excl = rng + 1; uint64_t m; uint32_t leftover; - if (rng == 0xFFFFFFFFUL) { - return next_uint32(brng_state); - /* ToDo: Move this code to caller to prevent this check on each call when generating arrays of numbers. */ - } - /* Generate a scaled random number. */ m = ((uint64_t)next_uint32(brng_state)) * rng_excl; @@ -1344,6 +1376,10 @@ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, if (use_masked) { return bounded_masked_uint32(brng_state, off, rng, mask); } else { + if (rng == 0xFFFFFFFFUL) { /* Lemire32 doesn't support rng = 0xFFFFFFFF. */ + return off + next_uint32(brng_state); + } + return bounded_lemire_uint32(brng_state, off, rng); } } @@ -1448,8 +1484,14 @@ void random_bounded_uint64_fill(brng_t *brng_state, out[i] = bounded_masked_uint64(brng_state, off, rng, mask); } } else { - for (i = 0; i < cnt; i++) { - out[i] = bounded_lemire_uint64(brng_state, off, rng); + if (rng == 0xFFFFFFFFFFFFFFFFULL) { /* Lemire64 doesn't support rng = 0xFFFFFFFFFFFFFFFF. */ + for (i = 0; i < cnt; i++) { + out[i] = off + next_uint64(brng_state); + } + } else { + for (i = 0; i < cnt; i++) { + out[i] = bounded_lemire_uint64(brng_state, off, rng); + } } } } @@ -1479,8 +1521,14 @@ void random_bounded_uint32_fill(brng_t *brng_state, out[i] = bounded_masked_uint32(brng_state, off, rng, mask); } } else { - for (i = 0; i < cnt; i++) { - out[i] = bounded_lemire_uint32(brng_state, off, rng); + if (rng == 0xFFFFFFFFUL) { /* Lemire32 doesn't support rng = 0xFFFFFFFF. */ + for (i = 0; i < cnt; i++) { + out[i] = off + next_uint32(brng_state); + } + } else { + for (i = 0; i < cnt; i++) { + out[i] = bounded_lemire_uint32(brng_state, off, rng); + } } } } From 04952c9f7d72e434b3698f10f06a9271cacbfd9a Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 18 Oct 2018 01:09:20 +0200 Subject: [PATCH 145/279] Test non 128bit code path when 128bit not available. --- _randomgen/benchmark.py | 4 ++-- _randomgen/randomgen/src/distributions/distributions.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 91fa50d828d3..df5e26a3d65b 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -107,8 +107,8 @@ def timer_32bit_bounded(): # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. # Lemire's algorithm has improved performance when {max}+1 is not a power of two. - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=True)' # Use masking & rejection. - # command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=False)' # Use Lemire's algo. + # command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=True)' # Use masking & rejection. + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=False)' # Use Lemire's algo. command = command.format(min=min, max=max) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 57261502474e..ebfae1d2ed3b 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1234,7 +1234,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, * Note: `rng` should not be 0xFFFFFFFFFFFFFFFF. When this happens `rng_excl` becomes zero and `off` is returned. */ const uint64_t rng_excl = rng + 1; -/* + #if __SIZEOF_INT128__ __uint128_t m; uint64_t leftover; @@ -1255,7 +1255,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, } return off + (m >> 64); -#else*/ +#else uint64_t m1; uint64_t x; uint64_t leftover; @@ -1291,7 +1291,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, } return off + m1; -//#endif +#endif } uint64_t random_bounded_uint64(brng_t *brng_state, From 9efa940511c2498ba17cc2cfd3ff31f88dedd698 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 18 Oct 2018 01:49:32 +0200 Subject: [PATCH 146/279] Added use_masked as param to _bounded tests in benchmark and enabled --full testing in travis and appveyor. --- _randomgen/.travis.yml | 2 +- _randomgen/appveyor.yml | 2 +- _randomgen/benchmark.py | 28 ++++++++++++++++++---------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 052681727ab9..6c88642d3767 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -80,6 +80,6 @@ after_success: - | if [[ ${DOCBUILD} == true ]]; then cd ${BUILD_DIR} - python benchmark.py; + python benchmark.py --full; fi \ No newline at end of file diff --git a/_randomgen/appveyor.yml b/_randomgen/appveyor.yml index 8280f54b64e7..6434e832e627 100644 --- a/_randomgen/appveyor.yml +++ b/_randomgen/appveyor.yml @@ -30,4 +30,4 @@ test_script: on_success: - cd %GIT_DIR%\ - - python benchmark.py \ No newline at end of file + - python benchmark.py --full \ No newline at end of file diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index df5e26a3d65b..0c02dc237c05 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -93,7 +93,7 @@ def timer_32bit(): run_timer(dist, command, command_numpy, SETUP, '32-bit unsigned integers') -def timer_32bit_bounded(): +def timer_32bit_bounded(use_masked=True): # info = np.iinfo(np.uint32) # min, max = info.min, info.max @@ -107,18 +107,21 @@ def timer_32bit_bounded(): # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. # Lemire's algorithm has improved performance when {max}+1 is not a power of two. - # command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=True)' # Use masking & rejection. - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=False)' # Use Lemire's algo. + if use_masked: + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=True)' # Use masking & rejection. + else: + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=False)' # Use Lemire's algo. command = command.format(min=min, max=max) command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32)' command_numpy = command_numpy.format(min=min, max=max) - run_timer(dist, command, command_numpy, SETUP, '32-bit bounded unsigned integers') + run_timer(dist, command, command_numpy, SETUP, + '32-bit bounded unsigned integers; use_masked={use_masked}'.format(use_masked=use_masked)) -def timer_64bit_bounded(): +def timer_64bit_bounded(use_masked=True): # info = np.iinfo(np.uint64) # min, max = info.min, info.max @@ -132,15 +135,18 @@ def timer_64bit_bounded(): # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. # Lemire's algorithm has improved performance when {max}+1 is not a power of two. - # command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64, use_masked=True)' # Use masking & rejection. - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64, use_masked=False)' # Use Lemire's algo. + if use_masked: + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64, use_masked=True)' # Use masking & rejection. + else: + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64, use_masked=False)' # Use Lemire's algo. command = command.format(min=min, max=max) command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64)' command_numpy = command_numpy.format(min=min, max=max) - run_timer(dist, command, command_numpy, SETUP, '64-bit bounded unsigned integers') + run_timer(dist, command, command_numpy, SETUP, + '64-bit bounded unsigned integers; use_masked={use_masked}'.format(use_masked=use_masked)) def timer_64bit(): @@ -171,7 +177,9 @@ def timer_normal_zig(): if args.full: timer_raw() timer_32bit() - timer_32bit_bounded() + timer_32bit_bounded(use_masked=True) + timer_32bit_bounded(use_masked=False) timer_64bit() - timer_64bit_bounded() + timer_64bit_bounded(use_masked=True) + timer_64bit_bounded(use_masked=False) timer_normal_zig() From f3f427de873b26fbc1c71b6b79f5bce5ad89f160 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 18 Oct 2018 02:19:49 +0200 Subject: [PATCH 147/279] Added __umulh instrinsic when on _WIN64 architecture. --- .../randomgen/src/distributions/distributions.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index ebfae1d2ed3b..fd6edb85d7b5 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -2,6 +2,10 @@ #include "ziggurat.h" #include "ziggurat_constants.h" +#if defined(_MSC_VER) && defined(_WIN64) +#include +#endif + /* Random generators for external use */ float random_float(brng_t *brng_state) { return next_float(brng_state); } @@ -1236,6 +1240,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, const uint64_t rng_excl = rng + 1; #if __SIZEOF_INT128__ +/* 128-bit uint available (e.g. GCC/clang). `m` is the __uint128_t scaled integer. */ __uint128_t m; uint64_t leftover; @@ -1256,6 +1261,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, return off + (m >> 64); #else +/* 128-bit uint NOT available (e.g. MSVS). `m1` is the upper 64-bits of the scaled integer. */ uint64_t m1; uint64_t x; uint64_t leftover; @@ -1274,7 +1280,14 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, } } - { /* Calc high 64 bits of x * rng_excl. */ +#if defined(_MSC_VER) && defined(_WIN64) +/* _WIN64 architecture. Use the __umulh intrinsic to calc `m1`. */ + { + m1 = __umulh(x, rng_excl); + } +#else +/* 32-bit architecture. Emulate __umulh to calc `m1`. */ + { uint64_t x0, x1, rng_excl0, rng_excl1; uint64_t w0, w1, w2, t; @@ -1289,6 +1302,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, w1 += x0 * rng_excl1; m1 = x1 * rng_excl1 + w2 + (w1 >> 32); } +#endif return off + m1; #endif From ddb6208feecea8b3a2f60e86bdcb0e55d2cce70f Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 18 Oct 2018 11:29:42 +0200 Subject: [PATCH 148/279] Moved condition to use 32-bit generator if range in 32-bit to callee level to also apply to the lemire functions. --- .../src/distributions/distributions.c | 157 ++++++++++-------- 1 file changed, 86 insertions(+), 71 deletions(-) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index fd6edb85d7b5..bee6e1198381 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1204,30 +1204,22 @@ static NPY_INLINE uint64_t gen_mask(uint64_t max) { return mask; } -/* - * Fills an array with cnt random npy_uint64 between off and off + rng - * inclusive. The numbers wrap if rng is sufficiently large. - */ +/* Static function called by random_bounded_uint64(...) */ static NPY_INLINE uint64_t bounded_masked_uint64(brng_t *brng_state, - uint64_t off, uint64_t rng, + uint64_t rng, uint64_t mask) { uint64_t val; - /* ToDo: Add this if condition to bounded_lemire_uint64 OR move to caller to save overhead. */ + while ((val = (next_uint64(brng_state) & mask)) > rng) + ; - if (rng <= 0xffffffffUL) { - while ((val = (next_uint32(brng_state) & mask)) > rng) - ; - } else { - while ((val = (next_uint64(brng_state) & mask)) > rng) - ; - } - return off + val; + return val; } +/* Static function called by random_bounded_uint64(...) */ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, - uint64_t off, uint64_t rng) { + uint64_t rng) { /* * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 * @@ -1235,7 +1227,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, * this function to be templated with the similar uint8 and uint16 * functions * - * Note: `rng` should not be 0xFFFFFFFFFFFFFFFF. When this happens `rng_excl` becomes zero and `off` is returned. + * Note: `rng` should not be 0xFFFFFFFFFFFFFFFF. When this happens `rng_excl` becomes zero. */ const uint64_t rng_excl = rng + 1; @@ -1259,7 +1251,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, } } - return off + (m >> 64); + return (m >> 64); #else /* 128-bit uint NOT available (e.g. MSVS). `m1` is the upper 64-bits of the scaled integer. */ uint64_t m1; @@ -1282,9 +1274,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, #if defined(_MSC_VER) && defined(_WIN64) /* _WIN64 architecture. Use the __umulh intrinsic to calc `m1`. */ - { - m1 = __umulh(x, rng_excl); - } + m1 = __umulh(x, rng_excl); #else /* 32-bit architecture. Emulate __umulh to calc `m1`. */ { @@ -1304,30 +1294,13 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, } #endif - return off + m1; + return m1; #endif } -uint64_t random_bounded_uint64(brng_t *brng_state, - uint64_t off, uint64_t rng, - uint64_t mask, bool use_masked) { - if (rng == 0) { - return off; - } else { - if (use_masked) { - return bounded_masked_uint64(brng_state, off, rng, mask); - } else { - if (rng == 0xFFFFFFFFFFFFFFFFULL) { /* Lemire64 doesn't support rng = 0xFFFFFFFFFFFFFFFF. */ - return off + next_uint64(brng_state); - } - - return bounded_lemire_uint64(brng_state, off, rng); - } - } -} - +/* Static function called by random_buffered_bounded_uint32(...) */ static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, - uint32_t off, uint32_t rng, + uint32_t rng, uint32_t mask) { /* * The buffer and buffer count are not used here but are included to allow @@ -1339,11 +1312,12 @@ static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, while ((val = (next_uint32(brng_state) & mask)) > rng) ; - return off + val; + return val; } +/* Static function called by random_buffered_bounded_uint32(...) */ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, - uint32_t off, uint32_t rng) { + uint32_t rng) { /* * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 * @@ -1351,7 +1325,7 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, * this function to be templated with the similar uint8 and uint16 * functions * - * Note: `rng` should not be 0xFFFFFFFF. When this happens `rng_excl` becomes zero and `off` is returned. + * Note: `rng` should not be 0xFFFFFFFF. When this happens `rng_excl` becomes zero. */ const uint32_t rng_excl = rng + 1; @@ -1373,9 +1347,40 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, } } - return off + (m >> 32); + return (m >> 32); } + +/* + * Fills an array with cnt random npy_uint64 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +uint64_t random_bounded_uint64(brng_t *brng_state, + uint64_t off, uint64_t rng, + uint64_t mask, bool use_masked) { + if (rng == 0) { + return off; + } else if (rng < 0xFFFFFFFFUL) { /* Call 32-bit generator if range in 32-bit. */ + if (use_masked) { + return off + bounded_masked_uint32(brng_state, rng, mask); + } else { + return off + bounded_lemire_uint32(brng_state, rng); + } + } else if (rng == 0xFFFFFFFFFFFFFFFFULL) { /* Lemire64 doesn't support inclusive rng = 0xFFFFFFFFFFFFFFFF. */ + return off + next_uint64(brng_state); + } else { + if (use_masked) { + return off + bounded_masked_uint64(brng_state, rng, mask); + } else { + return off + bounded_lemire_uint64(brng_state, rng); + } + } +} + +/* + * Fills an array with cnt random npy_uint32 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask, bool use_masked, @@ -1386,19 +1391,18 @@ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, */ if (rng == 0) { return off; + } else if (rng == 0xFFFFFFFFUL) { /* Lemire32 doesn't support inclusive rng = 0xFFFFFFFF. */ + return off + next_uint32(brng_state); } else { if (use_masked) { - return bounded_masked_uint32(brng_state, off, rng, mask); + return off + bounded_masked_uint32(brng_state, rng, mask); } else { - if (rng == 0xFFFFFFFFUL) { /* Lemire32 doesn't support rng = 0xFFFFFFFF. */ - return off + next_uint32(brng_state); - } - - return bounded_lemire_uint32(brng_state, off, rng); + return off + bounded_lemire_uint32(brng_state, rng); } } } + static NPY_INLINE uint16_t buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, uint16_t mask, @@ -1477,6 +1481,10 @@ npy_bool random_buffered_bounded_bool(brng_t *brng_state, return buffered_bounded_bool(brng_state, off, rng, mask, bcnt, buf); } +/* + * Fills an array with cnt random npy_uint64 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, npy_intp cnt, bool use_masked, @@ -1487,24 +1495,34 @@ void random_bounded_uint64_fill(brng_t *brng_state, for (i = 0; i < cnt; i++) { out[i] = off; } - return; - } - - if (use_masked) { - // Smallest bit mask >= max - uint64_t mask = gen_mask(rng); + } else if (rng < 0xFFFFFFFFUL) { /* Call 32-bit generator if range in 32-bit. */ + if (use_masked) { + // Smallest bit mask >= max + uint64_t mask = gen_mask(rng); + for (i = 0; i < cnt; i++) { + out[i] = off + bounded_masked_uint32(brng_state, rng, mask); + } + } else { + for (i = 0; i < cnt; i++) { + out[i] = off + bounded_lemire_uint32(brng_state, rng); + } + } + } else if (rng == 0xFFFFFFFFFFFFFFFFULL) { /* Lemire64 doesn't support rng = 0xFFFFFFFFFFFFFFFF. */ for (i = 0; i < cnt; i++) { - out[i] = bounded_masked_uint64(brng_state, off, rng, mask); + out[i] = off + next_uint64(brng_state); } } else { - if (rng == 0xFFFFFFFFFFFFFFFFULL) { /* Lemire64 doesn't support rng = 0xFFFFFFFFFFFFFFFF. */ + if (use_masked) { + // Smallest bit mask >= max + uint64_t mask = gen_mask(rng); + for (i = 0; i < cnt; i++) { - out[i] = off + next_uint64(brng_state); + out[i] = off + bounded_masked_uint64(brng_state, rng, mask); } } else { for (i = 0; i < cnt; i++) { - out[i] = bounded_lemire_uint64(brng_state, off, rng); + out[i] = off + bounded_lemire_uint64(brng_state, rng); } } } @@ -1524,24 +1542,21 @@ void random_bounded_uint32_fill(brng_t *brng_state, for (i = 0; i < cnt; i++) { out[i] = off; } - return; - } - - if (use_masked) { - // Smallest bit mask >= max - uint32_t mask = (uint32_t)gen_mask(rng); - + } else if (rng == 0xFFFFFFFFUL) { /* Lemire32 doesn't support rng = 0xFFFFFFFF. */ for (i = 0; i < cnt; i++) { - out[i] = bounded_masked_uint32(brng_state, off, rng, mask); + out[i] = off + next_uint32(brng_state); } } else { - if (rng == 0xFFFFFFFFUL) { /* Lemire32 doesn't support rng = 0xFFFFFFFF. */ + if (use_masked) { + // Smallest bit mask >= max + uint32_t mask = (uint32_t)gen_mask(rng); + for (i = 0; i < cnt; i++) { - out[i] = off + next_uint32(brng_state); + out[i] = off + bounded_masked_uint32(brng_state, rng, mask); } } else { for (i = 0; i < cnt; i++) { - out[i] = bounded_lemire_uint32(brng_state, off, rng); + out[i] = off + bounded_lemire_uint32(brng_state, rng); } } } From 3538ab553356dc278c6e317a19cba09ca831f9e6 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 18 Oct 2018 15:47:06 +0200 Subject: [PATCH 149/279] Added and updated some comments. --- _randomgen/.travis.yml | 1 - _randomgen/appveyor.yml | 2 +- _randomgen/randomgen/distributions.pxd | 2 ++ _randomgen/randomgen/src/distributions/distributions.c | 4 ++-- _randomgen/randomgen/src/distributions/distributions.h | 2 ++ 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 6c88642d3767..8a39ee161706 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -82,4 +82,3 @@ after_success: cd ${BUILD_DIR} python benchmark.py --full; fi - \ No newline at end of file diff --git a/_randomgen/appveyor.yml b/_randomgen/appveyor.yml index 6434e832e627..1520687ce3c6 100644 --- a/_randomgen/appveyor.yml +++ b/_randomgen/appveyor.yml @@ -30,4 +30,4 @@ test_script: on_success: - cd %GIT_DIR%\ - - python benchmark.py --full \ No newline at end of file + - python benchmark.py --full diff --git a/_randomgen/randomgen/distributions.pxd b/_randomgen/randomgen/distributions.pxd index 3a25a318ddfb..a50d5d821173 100644 --- a/_randomgen/randomgen/distributions.pxd +++ b/_randomgen/randomgen/distributions.pxd @@ -99,10 +99,12 @@ cdef extern from "src/distributions/distributions.h": uint64_t random_interval(brng_t *brng_state, uint64_t max) nogil + # Generate random uint64 numbers in closed interval [off, off + rng]. uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, uint64_t mask, bint use_masked) nogil + # Generate random uint32 numbers in closed interval [off, off + rng]. uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask, bint use_masked, diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index bee6e1198381..63f3d728565a 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1352,7 +1352,7 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, /* - * Fills an array with cnt random npy_uint64 between off and off + rng + * Returns a single random npy_uint64 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ uint64_t random_bounded_uint64(brng_t *brng_state, @@ -1378,7 +1378,7 @@ uint64_t random_bounded_uint64(brng_t *brng_state, } /* - * Fills an array with cnt random npy_uint32 between off and off + rng + * Returns a single random npy_uint64 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index 3bfea33e6c44..fcebe1311b0f 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -175,10 +175,12 @@ DECLDIR int64_t random_hypergeometric(brng_t *brng_state, int64_t good, DECLDIR uint64_t random_interval(brng_t *brng_state, uint64_t max); +/* Generate random uint64 numbers in closed interval [off, off + rng]. */ DECLDIR uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, uint64_t mask, bool use_masked); +/* Generate random uint32 numbers in closed interval [off, off + rng]. */ DECLDIR uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask, bool use_masked, From 3ba347ec97d76ea9909324f4a4e17e9c2c79c57f Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 18 Oct 2018 18:05:29 +0200 Subject: [PATCH 150/279] Manual fixes to comments and indents. --- .../src/distributions/distributions.c | 79 ++++++++++--------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 63f3d728565a..cb84429b922e 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1236,19 +1236,20 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, __uint128_t m; uint64_t leftover; - // Generate a scaled random number. + /* Generate a scaled random number. */ m = ((__uint128_t)next_uint64(brng_state)) * rng_excl; - // Rejection sampling to remove any bias. + /* Rejection sampling to remove any bias. */ leftover = m & 0xFFFFFFFFFFFFFFFFULL; - if (leftover < rng_excl) { - const uint64_t threshold = -rng_excl % rng_excl; //same as:((uint64_t)(0x10000000000000000ULLL - rng_excl)) % rng_excl; + if (leftover < rng_excl) { /* `rng_excl` is a simple upper bound for `threshold`. */ + const uint64_t threshold = -rng_excl % rng_excl; + /* Same as: threshold=((uint64_t)(0x10000000000000000ULLL - rng_excl)) % rng_excl; */ - while (leftover < threshold) { - m = ((__uint128_t)next_uint64(brng_state)) * rng_excl; - leftover = m & 0xFFFFFFFFFFFFFFFFULL; - } + while (leftover < threshold) { + m = ((__uint128_t)next_uint64(brng_state)) * rng_excl; + leftover = m & 0xFFFFFFFFFFFFFFFFULL; + } } return (m >> 64); @@ -1260,16 +1261,17 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, x = next_uint64(brng_state); - // Rejection sampling to remove any bias/. - leftover = x * rng_excl; + /* Rejection sampling to remove any bias. */ + leftover = x * rng_excl; /* The lower 64-bits of the mult. */ - if (leftover < rng_excl) { - const uint64_t threshold = -rng_excl % rng_excl; //same as:((uint64_t)(0x10000000000000000ULLL - rng_excl)) % rng_excl; + if (leftover < rng_excl) { /* `rng_excl` is a simple upper bound for `threshold`. */ + const uint64_t threshold = -rng_excl % rng_excl; + /* Same as:threshold=((uint64_t)(0x10000000000000000ULLL - rng_excl)) % rng_excl; */ - while (leftover < threshold) { - x = next_uint64(brng_state); - leftover = x * rng_excl; - } + while (leftover < threshold) { + x = next_uint64(brng_state); + leftover = x * rng_excl; + } } #if defined(_MSC_VER) && defined(_WIN64) @@ -1278,19 +1280,19 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, #else /* 32-bit architecture. Emulate __umulh to calc `m1`. */ { - uint64_t x0, x1, rng_excl0, rng_excl1; - uint64_t w0, w1, w2, t; - - x0 = x & 0xFFFFFFFFULL; - x1 = x >> 32; - rng_excl0 = rng_excl & 0xFFFFFFFFULL; - rng_excl1 = rng_excl >> 32; - w0 = x0 * rng_excl0; - t = x1 * rng_excl0 + (w0 >> 32); - w1 = t & 0xFFFFFFFFULL; - w2 = t >> 32; - w1 += x0 * rng_excl1; - m1 = x1 * rng_excl1 + w2 + (w1 >> 32); + uint64_t x0, x1, rng_excl0, rng_excl1; + uint64_t w0, w1, w2, t; + + x0 = x & 0xFFFFFFFFULL; + x1 = x >> 32; + rng_excl0 = rng_excl & 0xFFFFFFFFULL; + rng_excl1 = rng_excl >> 32; + w0 = x0 * rng_excl0; + t = x1 * rng_excl0 + (w0 >> 32); + w1 = t & 0xFFFFFFFFULL; + w2 = t >> 32; + w1 += x0 * rng_excl1; + m1 = x1 * rng_excl1 + w2 + (w1 >> 32); } #endif @@ -1338,13 +1340,14 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, /* Rejection sampling to remove any bias */ leftover = m & 0xFFFFFFFFUL; - if (leftover < rng_excl) { - const uint32_t threshold = -rng_excl % rng_excl; //same as:((uint64_t)(0x100000000ULL - rng_excl)) % rng_excl; + if (leftover < rng_excl) { /* `rng_excl` is a simple upper bound for `threshold`. */ + const uint32_t threshold = -rng_excl % rng_excl; + /* Same as: threshold=((uint64_t)(0x100000000ULL - rng_excl)) % rng_excl; */ - while (leftover < threshold) { - m = ((uint64_t)next_uint32(brng_state)) * rng_excl; - leftover = m & 0xFFFFFFFFUL; - } + while (leftover < threshold) { + m = ((uint64_t)next_uint32(brng_state)) * rng_excl; + leftover = m & 0xFFFFFFFFUL; + } } return (m >> 32); @@ -1497,7 +1500,7 @@ void random_bounded_uint64_fill(brng_t *brng_state, } } else if (rng < 0xFFFFFFFFUL) { /* Call 32-bit generator if range in 32-bit. */ if (use_masked) { - // Smallest bit mask >= max + /* Smallest bit mask >= max */ uint64_t mask = gen_mask(rng); for (i = 0; i < cnt; i++) { @@ -1514,7 +1517,7 @@ void random_bounded_uint64_fill(brng_t *brng_state, } } else { if (use_masked) { - // Smallest bit mask >= max + /* Smallest bit mask >= max */ uint64_t mask = gen_mask(rng); for (i = 0; i < cnt; i++) { @@ -1548,7 +1551,7 @@ void random_bounded_uint32_fill(brng_t *brng_state, } } else { if (use_masked) { - // Smallest bit mask >= max + /* Smallest bit mask >= max */ uint32_t mask = (uint32_t)gen_mask(rng); for (i = 0; i < cnt; i++) { From d198f07c901f1f6ff823bbbfd81528e1cce71162 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Thu, 18 Oct 2018 19:26:46 +0200 Subject: [PATCH 151/279] clang-format with .clang-format file: BasedOnStyle: llvm IndentWidth: 2 AllowShortFunctionsOnASingleLine: None KeepEmptyLinesAtTheStartOfBlocks: false --- .../src/distributions/distributions.c | 150 +++++++++--------- .../src/distributions/distributions.h | 59 ++++--- 2 files changed, 104 insertions(+), 105 deletions(-) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index cb84429b922e..813f6abfecc5 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -6,11 +6,14 @@ #include #endif - /* Random generators for external use */ -float random_float(brng_t *brng_state) { return next_float(brng_state); } +float random_float(brng_t *brng_state) { + return next_float(brng_state); +} -double random_double(brng_t *brng_state) { return next_double(brng_state); } +double random_double(brng_t *brng_state) { + return next_double(brng_state); +} static NPY_INLINE double next_standard_exponential(brng_t *brng_state) { return -log(1.0 - next_double(brng_state)); @@ -1204,11 +1207,9 @@ static NPY_INLINE uint64_t gen_mask(uint64_t max) { return mask; } - /* Static function called by random_bounded_uint64(...) */ static NPY_INLINE uint64_t bounded_masked_uint64(brng_t *brng_state, - uint64_t rng, - uint64_t mask) { + uint64_t rng, uint64_t mask) { uint64_t val; while ((val = (next_uint64(brng_state) & mask)) > rng) @@ -1227,12 +1228,14 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, * this function to be templated with the similar uint8 and uint16 * functions * - * Note: `rng` should not be 0xFFFFFFFFFFFFFFFF. When this happens `rng_excl` becomes zero. + * Note: `rng` should not be 0xFFFFFFFFFFFFFFFF. When this happens `rng_excl` + * becomes zero. */ const uint64_t rng_excl = rng + 1; #if __SIZEOF_INT128__ -/* 128-bit uint available (e.g. GCC/clang). `m` is the __uint128_t scaled integer. */ + /* 128-bit uint available (e.g. GCC/clang). `m` is the __uint128_t scaled + * integer. */ __uint128_t m; uint64_t leftover; @@ -1242,9 +1245,12 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, /* Rejection sampling to remove any bias. */ leftover = m & 0xFFFFFFFFFFFFFFFFULL; - if (leftover < rng_excl) { /* `rng_excl` is a simple upper bound for `threshold`. */ + if (leftover < rng_excl) { + /* `rng_excl` is a simple upper bound for `threshold`. */ + const uint64_t threshold = -rng_excl % rng_excl; - /* Same as: threshold=((uint64_t)(0x10000000000000000ULLL - rng_excl)) % rng_excl; */ + /* Same as: threshold=((uint64_t)(0x10000000000000000ULLL - rng_excl)) % + * rng_excl; */ while (leftover < threshold) { m = ((__uint128_t)next_uint64(brng_state)) * rng_excl; @@ -1254,7 +1260,8 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, return (m >> 64); #else -/* 128-bit uint NOT available (e.g. MSVS). `m1` is the upper 64-bits of the scaled integer. */ + /* 128-bit uint NOT available (e.g. MSVS). `m1` is the upper 64-bits of the + * scaled integer. */ uint64_t m1; uint64_t x; uint64_t leftover; @@ -1264,9 +1271,12 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, /* Rejection sampling to remove any bias. */ leftover = x * rng_excl; /* The lower 64-bits of the mult. */ - if (leftover < rng_excl) { /* `rng_excl` is a simple upper bound for `threshold`. */ + if (leftover < rng_excl) { + /* `rng_excl` is a simple upper bound for `threshold`. */ + const uint64_t threshold = -rng_excl % rng_excl; - /* Same as:threshold=((uint64_t)(0x10000000000000000ULLL - rng_excl)) % rng_excl; */ + /* Same as:threshold=((uint64_t)(0x10000000000000000ULLL - rng_excl)) % + * rng_excl; */ while (leftover < threshold) { x = next_uint64(brng_state); @@ -1275,10 +1285,10 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, } #if defined(_MSC_VER) && defined(_WIN64) -/* _WIN64 architecture. Use the __umulh intrinsic to calc `m1`. */ - m1 = __umulh(x, rng_excl); + /* _WIN64 architecture. Use the __umulh intrinsic to calc `m1`. */ + m1 = __umulh(x, rng_excl); #else -/* 32-bit architecture. Emulate __umulh to calc `m1`. */ + /* 32-bit architecture. Emulate __umulh to calc `m1`. */ { uint64_t x0, x1, rng_excl0, rng_excl1; uint64_t w0, w1, w2, t; @@ -1302,8 +1312,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, /* Static function called by random_buffered_bounded_uint32(...) */ static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, - uint32_t rng, - uint32_t mask) { + uint32_t rng, uint32_t mask) { /* * The buffer and buffer count are not used here but are included to allow * this function to be templated with the similar uint8 and uint16 @@ -1312,7 +1321,7 @@ static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, uint32_t val; while ((val = (next_uint32(brng_state) & mask)) > rng) - ; + ; return val; } @@ -1327,7 +1336,8 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, * this function to be templated with the similar uint8 and uint16 * functions * - * Note: `rng` should not be 0xFFFFFFFF. When this happens `rng_excl` becomes zero. + * Note: `rng` should not be 0xFFFFFFFF. When this happens `rng_excl` becomes + * zero. */ const uint32_t rng_excl = rng + 1; @@ -1340,7 +1350,8 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, /* Rejection sampling to remove any bias */ leftover = m & 0xFFFFFFFFUL; - if (leftover < rng_excl) { /* `rng_excl` is a simple upper bound for `threshold`. */ + if (leftover < rng_excl) { + /* `rng_excl` is a simple upper bound for `threshold`. */ const uint32_t threshold = -rng_excl % rng_excl; /* Same as: threshold=((uint64_t)(0x100000000ULL - rng_excl)) % rng_excl; */ @@ -1353,23 +1364,23 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, return (m >> 32); } - /* * Returns a single random npy_uint64 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -uint64_t random_bounded_uint64(brng_t *brng_state, - uint64_t off, uint64_t rng, +uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, uint64_t mask, bool use_masked) { if (rng == 0) { return off; - } else if (rng < 0xFFFFFFFFUL) { /* Call 32-bit generator if range in 32-bit. */ + } else if (rng < 0xFFFFFFFFUL) { + /* Call 32-bit generator if range in 32-bit. */ if (use_masked) { return off + bounded_masked_uint32(brng_state, rng, mask); } else { return off + bounded_lemire_uint32(brng_state, rng); } - } else if (rng == 0xFFFFFFFFFFFFFFFFULL) { /* Lemire64 doesn't support inclusive rng = 0xFFFFFFFFFFFFFFFF. */ + } else if (rng == 0xFFFFFFFFFFFFFFFFULL) { + /* Lemire64 doesn't support inclusive rng = 0xFFFFFFFFFFFFFFFF. */ return off + next_uint64(brng_state); } else { if (use_masked) { @@ -1384,17 +1395,18 @@ uint64_t random_bounded_uint64(brng_t *brng_state, * Returns a single random npy_uint64 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -uint32_t random_buffered_bounded_uint32(brng_t *brng_state, - uint32_t off, uint32_t rng, - uint32_t mask, bool use_masked, - int *bcnt, uint32_t *buf) { +uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, + uint32_t rng, uint32_t mask, + bool use_masked, int *bcnt, + uint32_t *buf) { /* * Unused bcnt and buf are here only to allow templating with other uint * generators */ if (rng == 0) { return off; - } else if (rng == 0xFFFFFFFFUL) { /* Lemire32 doesn't support inclusive rng = 0xFFFFFFFF. */ + } else if (rng == 0xFFFFFFFFUL) { + /* Lemire32 doesn't support inclusive rng = 0xFFFFFFFF. */ return off + next_uint32(brng_state); } else { if (use_masked) { @@ -1405,11 +1417,10 @@ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, } } - static NPY_INLINE uint16_t buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, - uint16_t mask, - int *bcnt, uint32_t *buf) { + uint16_t mask, int *bcnt, + uint32_t *buf) { uint16_t val; if (rng == 0) return off; @@ -1427,17 +1438,17 @@ static NPY_INLINE uint16_t buffered_bounded_uint16(brng_t *brng_state, return off + val; } -uint16_t random_buffered_bounded_uint16(brng_t *brng_state, - uint16_t off, uint16_t rng, - uint16_t mask, bool use_masked, - int *bcnt, uint32_t *buf) { +uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, + uint16_t rng, uint16_t mask, + bool use_masked, int *bcnt, + uint32_t *buf) { return buffered_bounded_uint16(brng_state, off, rng, mask, bcnt, buf); } static NPY_INLINE uint8_t buffered_bounded_uint8(brng_t *brng_state, uint8_t off, uint8_t rng, - uint8_t mask, - int *bcnt, uint32_t *buf) { + uint8_t mask, int *bcnt, + uint32_t *buf) { uint8_t val; if (rng == 0) return off; @@ -1454,17 +1465,17 @@ static NPY_INLINE uint8_t buffered_bounded_uint8(brng_t *brng_state, return off + val; } -uint8_t random_buffered_bounded_uint8(brng_t *brng_state, - uint8_t off, uint8_t rng, - uint8_t mask, bool use_masked, - int *bcnt, uint32_t *buf) { +uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, + uint8_t rng, uint8_t mask, + bool use_masked, int *bcnt, + uint32_t *buf) { return buffered_bounded_uint8(brng_state, off, rng, mask, bcnt, buf); } static NPY_INLINE npy_bool buffered_bounded_bool(brng_t *brng_state, npy_bool off, npy_bool rng, - npy_bool mask, - int *bcnt, uint32_t *buf) { + npy_bool mask, int *bcnt, + uint32_t *buf) { if (rng == 0) return off; if (!(bcnt[0])) { @@ -1477,10 +1488,10 @@ static NPY_INLINE npy_bool buffered_bounded_bool(brng_t *brng_state, return (buf[0] & 0x00000001UL) != 0; } -npy_bool random_buffered_bounded_bool(brng_t *brng_state, - npy_bool off, npy_bool rng, - npy_bool mask, bool use_masked, - int *bcnt, uint32_t *buf) { +npy_bool random_buffered_bounded_bool(brng_t *brng_state, npy_bool off, + npy_bool rng, npy_bool mask, + bool use_masked, int *bcnt, + uint32_t *buf) { return buffered_bounded_bool(brng_state, off, rng, mask, bcnt, buf); } @@ -1488,17 +1499,16 @@ npy_bool random_buffered_bounded_bool(brng_t *brng_state, * Fills an array with cnt random npy_uint64 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -void random_bounded_uint64_fill(brng_t *brng_state, - uint64_t off, uint64_t rng, npy_intp cnt, - bool use_masked, - uint64_t *out) { +void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, + npy_intp cnt, bool use_masked, uint64_t *out) { npy_intp i; if (rng == 0) { for (i = 0; i < cnt; i++) { out[i] = off; } - } else if (rng < 0xFFFFFFFFUL) { /* Call 32-bit generator if range in 32-bit. */ + } else if (rng < 0xFFFFFFFFUL) { + /* Call 32-bit generator if range in 32-bit. */ if (use_masked) { /* Smallest bit mask >= max */ uint64_t mask = gen_mask(rng); @@ -1511,7 +1521,8 @@ void random_bounded_uint64_fill(brng_t *brng_state, out[i] = off + bounded_lemire_uint32(brng_state, rng); } } - } else if (rng == 0xFFFFFFFFFFFFFFFFULL) { /* Lemire64 doesn't support rng = 0xFFFFFFFFFFFFFFFF. */ + } else if (rng == 0xFFFFFFFFFFFFFFFFULL) { + /* Lemire64 doesn't support rng = 0xFFFFFFFFFFFFFFFF. */ for (i = 0; i < cnt; i++) { out[i] = off + next_uint64(brng_state); } @@ -1535,17 +1546,16 @@ void random_bounded_uint64_fill(brng_t *brng_state, * Fills an array with cnt random npy_uint32 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -void random_bounded_uint32_fill(brng_t *brng_state, - uint32_t off, uint32_t rng, npy_intp cnt, - bool use_masked, - uint32_t *out) { +void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, + npy_intp cnt, bool use_masked, uint32_t *out) { npy_intp i; if (rng == 0) { for (i = 0; i < cnt; i++) { out[i] = off; } - } else if (rng == 0xFFFFFFFFUL) { /* Lemire32 doesn't support rng = 0xFFFFFFFF. */ + } else if (rng == 0xFFFFFFFFUL) { + /* Lemire32 doesn't support rng = 0xFFFFFFFF. */ for (i = 0; i < cnt; i++) { out[i] = off + next_uint32(brng_state); } @@ -1569,10 +1579,8 @@ void random_bounded_uint32_fill(brng_t *brng_state, * Fills an array with cnt random npy_uint16 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -void random_bounded_uint16_fill(brng_t *brng_state, - uint16_t off, uint16_t rng, npy_intp cnt, - bool use_masked, - uint16_t *out) { +void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, + npy_intp cnt, bool use_masked, uint16_t *out) { uint16_t mask; npy_intp i; uint32_t buf = 0; @@ -1589,10 +1597,8 @@ void random_bounded_uint16_fill(brng_t *brng_state, * Fills an array with cnt random npy_uint8 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. */ -void random_bounded_uint8_fill(brng_t *brng_state, - uint8_t off, uint8_t rng, npy_intp cnt, - bool use_masked, - uint8_t *out) { +void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, uint8_t rng, + npy_intp cnt, bool use_masked, uint8_t *out) { uint8_t mask; npy_intp i; uint32_t buf = 0; @@ -1609,10 +1615,8 @@ void random_bounded_uint8_fill(brng_t *brng_state, * Fills an array with cnt random npy_bool between off and off + rng * inclusive. */ -void random_bounded_bool_fill(brng_t *brng_state, - npy_bool off, npy_bool rng, npy_intp cnt, - bool use_masked, - npy_bool *out) { +void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, npy_bool rng, + npy_intp cnt, bool use_masked, npy_bool *out) { npy_bool mask = 0; npy_intp i; uint32_t buf = 0; diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index fcebe1311b0f..7a417b11710d 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -176,9 +176,9 @@ DECLDIR int64_t random_hypergeometric(brng_t *brng_state, int64_t good, DECLDIR uint64_t random_interval(brng_t *brng_state, uint64_t max); /* Generate random uint64 numbers in closed interval [off, off + rng]. */ -DECLDIR uint64_t random_bounded_uint64(brng_t *brng_state, - uint64_t off, uint64_t rng, - uint64_t mask, bool use_masked); +DECLDIR uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, + uint64_t rng, uint64_t mask, + bool use_masked); /* Generate random uint32 numbers in closed interval [off, off + rng]. */ DECLDIR uint32_t random_buffered_bounded_uint32(brng_t *brng_state, @@ -189,32 +189,27 @@ DECLDIR uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, uint16_t mask, bool use_masked, int *bcnt, uint32_t *buf); -DECLDIR uint8_t random_buffered_bounded_uint8(brng_t *brng_state, - uint8_t off, uint8_t rng, - uint8_t mask, bool use_masked, - int *bcnt, uint32_t *buf); -DECLDIR npy_bool random_buffered_bounded_bool(brng_t *brng_state, - npy_bool off, npy_bool rng, - npy_bool mask, bool use_masked, - int *bcnt, uint32_t *buf); - -DECLDIR void random_bounded_uint64_fill(brng_t *brng_state, - uint64_t off, uint64_t rng, npy_intp cnt, - bool use_masked, - uint64_t *out); -DECLDIR void random_bounded_uint32_fill(brng_t *brng_state, - uint32_t off, uint32_t rng, npy_intp cnt, - bool use_masked, - uint32_t *out); -DECLDIR void random_bounded_uint16_fill(brng_t *brng_state, - uint16_t off, uint16_t rng, npy_intp cnt, - bool use_masked, - uint16_t *out); -DECLDIR void random_bounded_uint8_fill(brng_t *brng_state, - npy_bool off, uint8_t rng, npy_intp cnt, - bool use_masked, - uint8_t *out); -DECLDIR void random_bounded_bool_fill(brng_t *brng_state, - npy_bool off, npy_bool rng, npy_intp cnt, - bool use_masked, - npy_bool *out); +DECLDIR uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, + uint8_t rng, uint8_t mask, + bool use_masked, int *bcnt, + uint32_t *buf); +DECLDIR npy_bool random_buffered_bounded_bool(brng_t *brng_state, npy_bool off, + npy_bool rng, npy_bool mask, + bool use_masked, int *bcnt, + uint32_t *buf); + +DECLDIR void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, + uint64_t rng, npy_intp cnt, + bool use_masked, uint64_t *out); +DECLDIR void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, + uint32_t rng, npy_intp cnt, + bool use_masked, uint32_t *out); +DECLDIR void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, + uint16_t rng, npy_intp cnt, + bool use_masked, uint16_t *out); +DECLDIR void random_bounded_uint8_fill(brng_t *brng_state, npy_bool off, + uint8_t rng, npy_intp cnt, + bool use_masked, uint8_t *out); +DECLDIR void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, + npy_bool rng, npy_intp cnt, + bool use_masked, npy_bool *out); From dd6a1368538c13a9a97015dd9c292a8c575a5ceb Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Fri, 19 Oct 2018 18:07:21 +0200 Subject: [PATCH 152/279] Example of how buffered_uint8 could be abstracted in disributions.c. --- .../src/distributions/distributions.c | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 813f6abfecc5..499694ce732a 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1445,23 +1445,35 @@ uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, return buffered_bounded_uint16(brng_state, off, rng, mask, bcnt, buf); } +static NPY_INLINE uint8_t buffered_uint8(brng_t *brng_state, int *bcnt, + uint32_t *buf) { + uint8_t val; + + if (!(bcnt[0])) { + buf[0] = next_uint32(brng_state); + bcnt[0] = 3; + } else { + buf[0] >>= 8; + bcnt[0] -= 1; + } + + val = (uint8_t)buf[0]; + + return val; +} + static NPY_INLINE uint8_t buffered_bounded_uint8(brng_t *brng_state, uint8_t off, uint8_t rng, uint8_t mask, int *bcnt, uint32_t *buf) { uint8_t val; + if (rng == 0) return off; - do { - if (!(bcnt[0])) { - buf[0] = next_uint32(brng_state); - bcnt[0] = 3; - } else { - buf[0] >>= 8; - bcnt[0] -= 1; - } - val = (uint8_t)buf[0] & mask; - } while (val > rng); + + while ((val = (buffered_uint8(brng_state, bcnt, buf) & mask)) > rng) + ; + return off + val; } From 30418cd6603d59c66d19379169ab13c2c9a9da75 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Sat, 20 Oct 2018 02:04:31 +0200 Subject: [PATCH 153/279] Added Lemire rejection sampling for 8 and 16 bit random numbers. --- _randomgen/benchmark.py | 80 ++++- .../src/distributions/distributions.c | 313 +++++++++++++----- 2 files changed, 293 insertions(+), 100 deletions(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 0c02dc237c05..793f9230af23 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -83,6 +83,62 @@ def timer_uniform(): run_timer(dist, command, None, SETUP, 'Uniforms') +def timer_8bit_bounded(use_masked=True): + # info = np.iinfo(np.uint8) + # min, max = info.min, info.max + + min, max = 0, 65 - 1 # WORST case for masking & rejection algorithm! + # min, max = 0, 48 - 1 # AVERAGE case for masking & rejection algorithm! + + dist = 'random_uintegers' + + # Note on performance of generating random numbers in an interval: + # use_masked=True : masking and rejection sampling is used to generate a random number in an interval. + # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. + # Lemire's algorithm has improved performance when {max}+1 is not a power of two. + + if use_masked: + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint8, use_masked=True)' # Use masking & rejection. + else: + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint8, use_masked=False)' # Use Lemire's algo. + + command = command.format(min=min, max=max) + + command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint8)' + command_numpy = command_numpy.format(min=min, max=max) + + run_timer(dist, command, command_numpy, SETUP, + '8-bit bounded unsigned integers; use_masked={use_masked}'.format(use_masked=use_masked)) + + +def timer_16bit_bounded(use_masked=True): + # info = np.iinfo(np.uint16) + # min, max = info.min, info.max + + min, max = 0, 1025 - 1 # WORST case for masking & rejection algorithm! + # min, max = 0, 1536 - 1 # AVERAGE case for masking & rejection algorithm! + + dist = 'random_uintegers' + + # Note on performance of generating random numbers in an interval: + # use_masked=True : masking and rejection sampling is used to generate a random number in an interval. + # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. + # Lemire's algorithm has improved performance when {max}+1 is not a power of two. + + if use_masked: + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint16, use_masked=True)' # Use masking & rejection. + else: + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint16, use_masked=False)' # Use Lemire's algo. + + command = command.format(min=min, max=max) + + command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint16)' + command_numpy = command_numpy.format(min=min, max=max) + + run_timer(dist, command, command_numpy, SETUP, + '16-bit bounded unsigned integers; use_masked={use_masked}'.format(use_masked=use_masked)) + + def timer_32bit(): info = np.iinfo(np.uint32) min, max = info.min, info.max @@ -121,6 +177,16 @@ def timer_32bit_bounded(use_masked=True): '32-bit bounded unsigned integers; use_masked={use_masked}'.format(use_masked=use_masked)) +def timer_64bit(): + info = np.iinfo(np.uint64) + min, max = info.min, info.max + dist = 'random_uintegers' + command = 'rg.random_uintegers(1000000)' + command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64)' + command_numpy = command_numpy.format(min=min, max=max) + run_timer(dist, command, command_numpy, SETUP, '64-bit unsigned integers') + + def timer_64bit_bounded(use_masked=True): # info = np.iinfo(np.uint64) # min, max = info.min, info.max @@ -149,16 +215,6 @@ def timer_64bit_bounded(use_masked=True): '64-bit bounded unsigned integers; use_masked={use_masked}'.format(use_masked=use_masked)) -def timer_64bit(): - info = np.iinfo(np.uint64) - min, max = info.min, info.max - dist = 'random_uintegers' - command = 'rg.random_uintegers(1000000)' - command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64)' - command_numpy = command_numpy.format(min=min, max=max) - run_timer(dist, command, command_numpy, SETUP, '64-bit unsigned integers') - - def timer_normal_zig(): dist = 'standard_normal' command = 'rg.standard_normal(1000000)' @@ -176,6 +232,10 @@ def timer_normal_zig(): timer_uniform() if args.full: timer_raw() + timer_8bit_bounded(use_masked=True) + timer_8bit_bounded(use_masked=False) + timer_16bit_bounded(use_masked=True) + timer_16bit_bounded(use_masked=False) timer_32bit() timer_32bit_bounded(use_masked=True) timer_32bit_bounded(use_masked=False) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 499694ce732a..312d39e8ab67 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1207,7 +1207,35 @@ static NPY_INLINE uint64_t gen_mask(uint64_t max) { return mask; } -/* Static function called by random_bounded_uint64(...) */ +/* Generate 16 bit random numbers using a 32 bit buffer. */ +static NPY_INLINE uint16_t buffered_uint16(brng_t *brng_state, int *bcnt, + uint32_t *buf) { + if (!(bcnt[0])) { + buf[0] = next_uint32(brng_state); + bcnt[0] = 1; + } else { + buf[0] >>= 16; + bcnt[0] -= 1; + } + + return (uint16_t)buf[0]; +} + +/* Generate 16 bit random numbers using a 32 bit buffer. */ +static NPY_INLINE uint8_t buffered_uint8(brng_t *brng_state, int *bcnt, + uint32_t *buf) { + if (!(bcnt[0])) { + buf[0] = next_uint32(brng_state); + bcnt[0] = 3; + } else { + buf[0] >>= 8; + bcnt[0] -= 1; + } + + return (uint8_t)buf[0]; +} + +/* Static `masked rejection` function called by random_bounded_uint64(...) */ static NPY_INLINE uint64_t bounded_masked_uint64(brng_t *brng_state, uint64_t rng, uint64_t mask) { uint64_t val; @@ -1218,16 +1246,50 @@ static NPY_INLINE uint64_t bounded_masked_uint64(brng_t *brng_state, return val; } -/* Static function called by random_bounded_uint64(...) */ +/* Static `masked rejection` function called by + * random_buffered_bounded_uint32(...) */ +static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, + uint32_t rng, uint32_t mask) { + uint32_t val; + + while ((val = (next_uint32(brng_state) & mask)) > rng) + ; + + return val; +} + +/* Static `masked rejection` function called by + * random_buffered_bounded_uint16(...) */ +static NPY_INLINE uint16_t buffered_bounded_masked_uint16( + brng_t *brng_state, uint16_t rng, uint16_t mask, int *bcnt, uint32_t *buf) { + uint16_t val; + + while ((val = (buffered_uint16(brng_state, bcnt, buf) & mask)) > rng) + ; + + return val; +} + +/* Static `masked rejection` function called by + * random_buffered_bounded_uint8(...) */ +static NPY_INLINE uint8_t buffered_bounded_masked_uint8(brng_t *brng_state, + uint8_t rng, + uint8_t mask, int *bcnt, + uint32_t *buf) { + uint8_t val; + + while ((val = (buffered_uint8(brng_state, bcnt, buf) & mask)) > rng) + ; + + return val; +} + +/* Static `Lemire rejection` function called by random_bounded_uint64(...) */ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, uint64_t rng) { /* * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 * - * The buffer and buffer count are not used here but are included to allow - * this function to be templated with the similar uint8 and uint16 - * functions - * * Note: `rng` should not be 0xFFFFFFFFFFFFFFFF. When this happens `rng_excl` * becomes zero. */ @@ -1310,32 +1372,13 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, #endif } -/* Static function called by random_buffered_bounded_uint32(...) */ -static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, - uint32_t rng, uint32_t mask) { - /* - * The buffer and buffer count are not used here but are included to allow - * this function to be templated with the similar uint8 and uint16 - * functions - */ - uint32_t val; - - while ((val = (next_uint32(brng_state) & mask)) > rng) - ; - - return val; -} - -/* Static function called by random_buffered_bounded_uint32(...) */ +/* Static `Lemire rejection` function called by + * random_buffered_bounded_uint32(...) */ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, uint32_t rng) { /* * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 * - * The buffer and buffer count are not used here but are included to allow - * this function to be templated with the similar uint8 and uint16 - * functions - * * Note: `rng` should not be 0xFFFFFFFF. When this happens `rng_excl` becomes * zero. */ @@ -1364,6 +1407,79 @@ static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, return (m >> 32); } +/* Static `Lemire rejection` function called by + * random_buffered_bounded_uint16(...) */ +static NPY_INLINE uint16_t buffered_bounded_lemire_uint16(brng_t *brng_state, + uint16_t rng, + int *bcnt, + uint32_t *buf) { + /* + * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 + * + * Note: `rng` should not be 0xFFFF. When this happens `rng_excl` becomes + * zero. + */ + const uint16_t rng_excl = rng + 1; + + uint32_t m; + uint16_t leftover; + + /* Generate a scaled random number. */ + m = ((uint32_t)buffered_uint16(brng_state, bcnt, buf)) * rng_excl; + + /* Rejection sampling to remove any bias */ + leftover = m & 0xFFFFUL; + + if (leftover < rng_excl) { + /* `rng_excl` is a simple upper bound for `threshold`. */ + const uint16_t threshold = -rng_excl % rng_excl; + /* Same as: threshold=((uint32_t)(0x10000ULL - rng_excl)) % rng_excl; */ + + while (leftover < threshold) { + m = ((uint32_t)buffered_uint16(brng_state, bcnt, buf)) * rng_excl; + leftover = m & 0xFFFFUL; + } + } + + return (m >> 16); +} + +/* Static `Lemire rejection` function called by + * random_buffered_bounded_uint8(...) */ +static NPY_INLINE uint8_t buffered_bounded_lemire_uint8(brng_t *brng_state, + uint8_t rng, int *bcnt, + uint32_t *buf) { + /* + * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 + * + * Note: `rng` should not be 0xFF. When this happens `rng_excl` becomes + * zero. + */ + const uint8_t rng_excl = rng + 1; + + uint16_t m; + uint8_t leftover; + + /* Generate a scaled random number. */ + m = ((uint16_t)buffered_uint8(brng_state, bcnt, buf)) * rng_excl; + + /* Rejection sampling to remove any bias */ + leftover = m & 0xFFUL; + + if (leftover < rng_excl) { + /* `rng_excl` is a simple upper bound for `threshold`. */ + const uint8_t threshold = -rng_excl % rng_excl; + /* Same as: threshold=((uint16_t)(0x100ULL - rng_excl)) % rng_excl; */ + + while (leftover < threshold) { + m = ((uint16_t)buffered_uint8(brng_state, bcnt, buf)) * rng_excl; + leftover = m & 0xFFUL; + } + } + + return (m >> 8); +} + /* * Returns a single random npy_uint64 between off and off + rng * inclusive. The numbers wrap if rng is sufficiently large. @@ -1417,71 +1533,50 @@ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, } } -static NPY_INLINE uint16_t buffered_bounded_uint16(brng_t *brng_state, - uint16_t off, uint16_t rng, - uint16_t mask, int *bcnt, - uint32_t *buf) { - uint16_t val; - if (rng == 0) - return off; - - do { - if (!(bcnt[0])) { - buf[0] = next_uint32(brng_state); - bcnt[0] = 1; - } else { - buf[0] >>= 16; - bcnt[0] -= 1; - } - val = (uint16_t)buf[0] & mask; - } while (val > rng); - return off + val; -} - +/* + * Returns a single random npy_uint16 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ uint16_t random_buffered_bounded_uint16(brng_t *brng_state, uint16_t off, uint16_t rng, uint16_t mask, bool use_masked, int *bcnt, uint32_t *buf) { - return buffered_bounded_uint16(brng_state, off, rng, mask, bcnt, buf); -} - -static NPY_INLINE uint8_t buffered_uint8(brng_t *brng_state, int *bcnt, - uint32_t *buf) { - uint8_t val; - - if (!(bcnt[0])) { - buf[0] = next_uint32(brng_state); - bcnt[0] = 3; + if (rng == 0) { + return off; + } else if (rng == 0xFFFFUL) { + /* Lemire16 doesn't support inclusive rng = 0xFFFF. */ + return off + buffered_uint16(brng_state, bcnt, buf); } else { - buf[0] >>= 8; - bcnt[0] -= 1; + if (use_masked) { + return off + + buffered_bounded_masked_uint16(brng_state, rng, mask, bcnt, buf); + } else { + return off + buffered_bounded_lemire_uint16(brng_state, rng, bcnt, buf); + } } - - val = (uint8_t)buf[0]; - - return val; -} - -static NPY_INLINE uint8_t buffered_bounded_uint8(brng_t *brng_state, - uint8_t off, uint8_t rng, - uint8_t mask, int *bcnt, - uint32_t *buf) { - uint8_t val; - - if (rng == 0) - return off; - - while ((val = (buffered_uint8(brng_state, bcnt, buf) & mask)) > rng) - ; - - return off + val; } +/* + * Returns a single random npy_uint8 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ uint8_t random_buffered_bounded_uint8(brng_t *brng_state, uint8_t off, uint8_t rng, uint8_t mask, bool use_masked, int *bcnt, uint32_t *buf) { - return buffered_bounded_uint8(brng_state, off, rng, mask, bcnt, buf); + if (rng == 0) { + return off; + } else if (rng == 0xFFUL) { + /* Lemire8 doesn't support inclusive rng = 0xFF. */ + return off + buffered_uint8(brng_state, bcnt, buf); + } else { + if (use_masked) { + return off + + buffered_bounded_masked_uint8(brng_state, rng, mask, bcnt, buf); + } else { + return off + buffered_bounded_lemire_uint8(brng_state, rng, bcnt, buf); + } + } } static NPY_INLINE npy_bool buffered_bounded_bool(brng_t *brng_state, @@ -1593,15 +1688,34 @@ void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, */ void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, npy_intp cnt, bool use_masked, uint16_t *out) { - uint16_t mask; npy_intp i; uint32_t buf = 0; int bcnt = 0; - /* Smallest bit mask >= max */ - mask = (uint16_t)gen_mask(rng); - for (i = 0; i < cnt; i++) { - out[i] = buffered_bounded_uint16(brng_state, off, rng, mask, &bcnt, &buf); + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + } else if (rng == 0xFFFFUL) { + /* Lemire16 doesn't support rng = 0xFFFF. */ + for (i = 0; i < cnt; i++) { + out[i] = off + buffered_uint16(brng_state, &bcnt, &buf); + } + } else { + if (use_masked) { + /* Smallest bit mask >= max */ + uint16_t mask = (uint16_t)gen_mask(rng); + + for (i = 0; i < cnt; i++) { + out[i] = off + buffered_bounded_masked_uint16(brng_state, rng, mask, + &bcnt, &buf); + } + } else { + for (i = 0; i < cnt; i++) { + out[i] = + off + buffered_bounded_lemire_uint16(brng_state, rng, &bcnt, &buf); + } + } } } @@ -1611,15 +1725,34 @@ void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, */ void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, uint8_t rng, npy_intp cnt, bool use_masked, uint8_t *out) { - uint8_t mask; npy_intp i; uint32_t buf = 0; int bcnt = 0; - /* Smallest bit mask >= max */ - mask = (uint8_t)gen_mask(rng); - for (i = 0; i < cnt; i++) { - out[i] = buffered_bounded_uint8(brng_state, off, rng, mask, &bcnt, &buf); + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + } else if (rng == 0xFFUL) { + /* Lemire8 doesn't support rng = 0xFF. */ + for (i = 0; i < cnt; i++) { + out[i] = off + buffered_uint8(brng_state, &bcnt, &buf); + } + } else { + if (use_masked) { + /* Smallest bit mask >= max */ + uint8_t mask = (uint8_t)gen_mask(rng); + + for (i = 0; i < cnt; i++) { + out[i] = off + buffered_bounded_masked_uint8(brng_state, rng, mask, + &bcnt, &buf); + } + } else { + for (i = 0; i < cnt; i++) { + out[i] = + off + buffered_bounded_lemire_uint8(brng_state, rng, &bcnt, &buf); + } + } } } From 9d1b60e9ae4e173790fcc8078ed3178e8b96ec6a Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Sat, 20 Oct 2018 08:12:42 +0200 Subject: [PATCH 154/279] Fixed one or two comments and added the unused buffer back to the uint32 functions that was in the code before branching. The argument for having it is 'to allow templating with other uint generators'. --- .../src/distributions/distributions.c | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 312d39e8ab67..89bb8f090a28 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1221,7 +1221,7 @@ static NPY_INLINE uint16_t buffered_uint16(brng_t *brng_state, int *bcnt, return (uint16_t)buf[0]; } -/* Generate 16 bit random numbers using a 32 bit buffer. */ +/* Generate 8 bit random numbers using a 32 bit buffer. */ static NPY_INLINE uint8_t buffered_uint8(brng_t *brng_state, int *bcnt, uint32_t *buf) { if (!(bcnt[0])) { @@ -1248,8 +1248,14 @@ static NPY_INLINE uint64_t bounded_masked_uint64(brng_t *brng_state, /* Static `masked rejection` function called by * random_buffered_bounded_uint32(...) */ -static NPY_INLINE uint32_t bounded_masked_uint32(brng_t *brng_state, - uint32_t rng, uint32_t mask) { +static NPY_INLINE uint32_t buffered_bounded_masked_uint32( + brng_t *brng_state, uint32_t rng, uint32_t mask, int *bcnt, uint32_t *buf) { + /* + * The buffer and buffer count are not used here but are included to allow + * this function to be templated with the similar uint8 and uint16 + * functions + */ + uint32_t val; while ((val = (next_uint32(brng_state) & mask)) > rng) @@ -1374,11 +1380,17 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(brng_t *brng_state, /* Static `Lemire rejection` function called by * random_buffered_bounded_uint32(...) */ -static NPY_INLINE uint32_t bounded_lemire_uint32(brng_t *brng_state, - uint32_t rng) { +static NPY_INLINE uint32_t buffered_bounded_lemire_uint32(brng_t *brng_state, + uint32_t rng, + int *bcnt, + uint32_t *buf) { /* * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 * + * The buffer and buffer count are not used here but are included to allow + * this function to be templated with the similar uint8 and uint16 + * functions + * * Note: `rng` should not be 0xFFFFFFFF. When this happens `rng_excl` becomes * zero. */ @@ -1490,10 +1502,14 @@ uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, return off; } else if (rng < 0xFFFFFFFFUL) { /* Call 32-bit generator if range in 32-bit. */ + uint32_t buf = 0; + int bcnt = 0; + if (use_masked) { - return off + bounded_masked_uint32(brng_state, rng, mask); + return off + + buffered_bounded_masked_uint32(brng_state, rng, mask, &bcnt, &buf); } else { - return off + bounded_lemire_uint32(brng_state, rng); + return off + buffered_bounded_lemire_uint32(brng_state, rng, &bcnt, &buf); } } else if (rng == 0xFFFFFFFFFFFFFFFFULL) { /* Lemire64 doesn't support inclusive rng = 0xFFFFFFFFFFFFFFFF. */ @@ -1516,8 +1532,8 @@ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, bool use_masked, int *bcnt, uint32_t *buf) { /* - * Unused bcnt and buf are here only to allow templating with other uint - * generators + * Unused bcnt and buf are here only to allow templating with other uint + * generators. */ if (rng == 0) { return off; @@ -1526,9 +1542,10 @@ uint32_t random_buffered_bounded_uint32(brng_t *brng_state, uint32_t off, return off + next_uint32(brng_state); } else { if (use_masked) { - return off + bounded_masked_uint32(brng_state, rng, mask); + return off + + buffered_bounded_masked_uint32(brng_state, rng, mask, bcnt, buf); } else { - return off + bounded_lemire_uint32(brng_state, rng); + return off + buffered_bounded_lemire_uint32(brng_state, rng, bcnt, buf); } } } @@ -1615,17 +1632,22 @@ void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, out[i] = off; } } else if (rng < 0xFFFFFFFFUL) { + uint32_t buf = 0; + int bcnt = 0; + /* Call 32-bit generator if range in 32-bit. */ if (use_masked) { /* Smallest bit mask >= max */ uint64_t mask = gen_mask(rng); for (i = 0; i < cnt; i++) { - out[i] = off + bounded_masked_uint32(brng_state, rng, mask); + out[i] = off + buffered_bounded_masked_uint32(brng_state, rng, mask, + &bcnt, &buf); } } else { for (i = 0; i < cnt; i++) { - out[i] = off + bounded_lemire_uint32(brng_state, rng); + out[i] = + off + buffered_bounded_lemire_uint32(brng_state, rng, &bcnt, &buf); } } } else if (rng == 0xFFFFFFFFFFFFFFFFULL) { @@ -1656,6 +1678,8 @@ void random_bounded_uint64_fill(brng_t *brng_state, uint64_t off, uint64_t rng, void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, npy_intp cnt, bool use_masked, uint32_t *out) { npy_intp i; + uint32_t buf = 0; + int bcnt = 0; if (rng == 0) { for (i = 0; i < cnt; i++) { @@ -1672,11 +1696,13 @@ void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, uint32_t rng, uint32_t mask = (uint32_t)gen_mask(rng); for (i = 0; i < cnt; i++) { - out[i] = off + bounded_masked_uint32(brng_state, rng, mask); + out[i] = off + buffered_bounded_masked_uint32(brng_state, rng, mask, + &bcnt, &buf); } } else { for (i = 0; i < cnt; i++) { - out[i] = off + bounded_lemire_uint32(brng_state, rng); + out[i] = + off + buffered_bounded_lemire_uint32(brng_state, rng, &bcnt, &buf); } } } From ef49be983e94985a082a74d0a21989a5eafbe053 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Sun, 21 Oct 2018 08:13:06 +0200 Subject: [PATCH 155/279] Removed unused 32-bit random buffer. --- _randomgen/randomgen/src/distributions/distributions.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 89bb8f090a28..e04259136e93 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -1502,14 +1502,11 @@ uint64_t random_bounded_uint64(brng_t *brng_state, uint64_t off, uint64_t rng, return off; } else if (rng < 0xFFFFFFFFUL) { /* Call 32-bit generator if range in 32-bit. */ - uint32_t buf = 0; - int bcnt = 0; - if (use_masked) { return off + - buffered_bounded_masked_uint32(brng_state, rng, mask, &bcnt, &buf); + buffered_bounded_masked_uint32(brng_state, rng, mask, NULL, NULL); } else { - return off + buffered_bounded_lemire_uint32(brng_state, rng, &bcnt, &buf); + return off + buffered_bounded_lemire_uint32(brng_state, rng, NULL, NULL); } } else if (rng == 0xFFFFFFFFFFFFFFFFULL) { /* Lemire64 doesn't support inclusive rng = 0xFFFFFFFFFFFFFFFF. */ From 531747b5f8842d2910553ab8d1e93bdcc9c6df42 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 22 Oct 2018 00:20:13 +0100 Subject: [PATCH 156/279] CLN: Add guards to headers Add header guards --- _randomgen/randomgen/src/aligned_malloc/aligned_malloc.h | 7 ++++++- _randomgen/randomgen/src/distributions/distributions.h | 5 +++++ _randomgen/randomgen/src/entropy/entropy.h | 5 +++++ _randomgen/randomgen/src/legacy/distributions-boxmuller.h | 6 ++++++ _randomgen/randomgen/src/philox/philox.h | 5 +++++ _randomgen/randomgen/src/threefry/threefry.h | 4 ++++ _randomgen/randomgen/src/threefry32/threefry32.h | 4 ++++ _randomgen/randomgen/src/xoroshiro128/xoroshiro128.h | 5 +++++ _randomgen/randomgen/src/xorshift1024/xorshift1024.h | 5 +++++ 9 files changed, 45 insertions(+), 1 deletion(-) diff --git a/_randomgen/randomgen/src/aligned_malloc/aligned_malloc.h b/_randomgen/randomgen/src/aligned_malloc/aligned_malloc.h index 55716525338b..ea24f6d23052 100644 --- a/_randomgen/randomgen/src/aligned_malloc/aligned_malloc.h +++ b/_randomgen/randomgen/src/aligned_malloc/aligned_malloc.h @@ -1,3 +1,6 @@ +#ifndef _RANDOMDGEN__ALIGNED_MALLOC_H_ +#define _RANDOMDGEN__ALIGNED_MALLOC_H_ + #include "Python.h" #include "numpy/npy_common.h" @@ -46,4 +49,6 @@ static NPY_INLINE void PyArray_free_aligned(void *p) { void *base = *(((void **)p) - 1); PyMem_Free(base); -} \ No newline at end of file +} + +#endif diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index 707f3b455e35..9e091e1b3d25 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -1,3 +1,6 @@ +#ifndef _RANDOMDGEN__DISTRIBUTIONS_H_ +#define _RANDOMDGEN__DISTRIBUTIONS_H_ + #pragma once #include #ifdef _WIN32 @@ -205,3 +208,5 @@ DECLDIR void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, DECLDIR void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, npy_bool rng, npy_intp cnt, npy_bool *out); + +#endif diff --git a/_randomgen/randomgen/src/entropy/entropy.h b/_randomgen/randomgen/src/entropy/entropy.h index 0c33edbe4b5e..785603dd3d75 100644 --- a/_randomgen/randomgen/src/entropy/entropy.h +++ b/_randomgen/randomgen/src/entropy/entropy.h @@ -1,3 +1,5 @@ +#ifndef _RANDOMDGEN__ENTROPY_H_ +#define _RANDOMDGEN__ENTROPY_H_ /* * PCG Random Number Generation for C. * @@ -20,6 +22,7 @@ * * http://www.pcg-random.org */ + #include #ifdef _WIN32 #if _MSC_VER == 1500 @@ -41,3 +44,5 @@ extern void entropy_fill(void *dest, size_t size); extern bool entropy_getbytes(void *dest, size_t size); extern bool entropy_fallback_getbytes(void *dest, size_t size); + +#endif diff --git a/_randomgen/randomgen/src/legacy/distributions-boxmuller.h b/_randomgen/randomgen/src/legacy/distributions-boxmuller.h index 2c0615bdb868..445686e6c85b 100644 --- a/_randomgen/randomgen/src/legacy/distributions-boxmuller.h +++ b/_randomgen/randomgen/src/legacy/distributions-boxmuller.h @@ -1,3 +1,7 @@ +#ifndef _RANDOMDGEN__DISTRIBUTIONS_LEGACY_H_ +#define _RANDOMDGEN__DISTRIBUTIONS_LEGACY_H_ + + #include "../distributions/distributions.h" typedef struct aug_brng { @@ -32,3 +36,5 @@ extern double legacy_f(aug_brng_t *aug_state, double dfnum, double dfden); extern double legacy_normal(aug_brng_t *aug_state, double loc, double scale); extern double legacy_standard_gamma(aug_brng_t *aug_state, double shape); extern double legacy_exponential(aug_brng_t *aug_state, double scale); + +#endif diff --git a/_randomgen/randomgen/src/philox/philox.h b/_randomgen/randomgen/src/philox/philox.h index a130010e626b..411404b55787 100644 --- a/_randomgen/randomgen/src/philox/philox.h +++ b/_randomgen/randomgen/src/philox/philox.h @@ -1,3 +1,6 @@ +#ifndef _RANDOMDGEN__PHILOX_H_ +#define _RANDOMDGEN__PHILOX_H_ + #include #ifdef _WIN32 @@ -246,3 +249,5 @@ static INLINE uint32_t philox_next32(philox_state *state) { extern void philox_jump(philox_state *state); extern void philox_advance(uint64_t *step, philox_state *state); + +#endif diff --git a/_randomgen/randomgen/src/threefry/threefry.h b/_randomgen/randomgen/src/threefry/threefry.h index e0e4c21a57b7..297c1241a698 100644 --- a/_randomgen/randomgen/src/threefry/threefry.h +++ b/_randomgen/randomgen/src/threefry/threefry.h @@ -1,6 +1,8 @@ /* Adapted from random123's threefry.h */ +#ifndef _RANDOMDGEN__THREEFRY_H_ +#define _RANDOMDGEN__THREEFRY_H_ #ifdef _WIN32 #if _MSC_VER == 1500 @@ -335,3 +337,5 @@ static INLINE uint32_t threefry_next32(threefry_state *state) { extern void threefry_jump(threefry_state *state); extern void threefry_advance(uint64_t *step, threefry_state *state); + +#endif diff --git a/_randomgen/randomgen/src/threefry32/threefry32.h b/_randomgen/randomgen/src/threefry32/threefry32.h index 9e4cdf2fc3ac..74a85c42b453 100644 --- a/_randomgen/randomgen/src/threefry32/threefry32.h +++ b/_randomgen/randomgen/src/threefry32/threefry32.h @@ -1,6 +1,8 @@ /* Adapted from random123's threefry.h */ +#ifndef _RANDOMDGEN__THREEFRY32_H_ +#define _RANDOMDGEN__THREEFRY32_H_ #ifdef _WIN32 #if _MSC_VER == 1500 @@ -836,3 +838,5 @@ static INLINE double threefry32_next_double(threefry32_state *state) { extern void threefry32_jump(threefry32_state *state); extern void threefry32_advance(uint32_t *step, threefry32_state *state); + +#endif diff --git a/_randomgen/randomgen/src/xoroshiro128/xoroshiro128.h b/_randomgen/randomgen/src/xoroshiro128/xoroshiro128.h index 3fa5b32e9a46..40cb39218908 100644 --- a/_randomgen/randomgen/src/xoroshiro128/xoroshiro128.h +++ b/_randomgen/randomgen/src/xoroshiro128/xoroshiro128.h @@ -1,3 +1,6 @@ +#ifndef _RANDOMDGEN__XOROSHIRO128_H_ +#define _RANDOMDGEN__XOROSHIRO128_H_ + #ifdef _WIN32 #if _MSC_VER == 1500 #include "../common/inttypes.h" @@ -50,3 +53,5 @@ static INLINE uint32_t xoroshiro128_next32(xoroshiro128_state *state) { } void xoroshiro128_jump(xoroshiro128_state *state); + +#endif diff --git a/_randomgen/randomgen/src/xorshift1024/xorshift1024.h b/_randomgen/randomgen/src/xorshift1024/xorshift1024.h index 998dde06c6b3..e0ef7782652f 100644 --- a/_randomgen/randomgen/src/xorshift1024/xorshift1024.h +++ b/_randomgen/randomgen/src/xorshift1024/xorshift1024.h @@ -1,3 +1,6 @@ +#ifndef _RANDOMDGEN__XORSHIFT1024_H_ +#define _RANDOMDGEN__XORSHIFT1024_H_ + #ifdef _WIN32 #if _MSC_VER == 1500 #include "../common/inttypes.h" @@ -43,3 +46,5 @@ static INLINE uint32_t xorshift1024_next32(xorshift1024_state *state) { } void xorshift1024_jump(xorshift1024_state *state); + +#endif From bd7127d13d5b194777e37979d1d4de62f2b53959 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Mon, 22 Oct 2018 03:32:08 +0200 Subject: [PATCH 157/279] Updated benchmark to test Lemire sampling in the worst, typical average and best bounded cases for Numpy's masked rejection sampling. --- _randomgen/benchmark.py | 62 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 793f9230af23..c8358c62f569 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -83,12 +83,8 @@ def timer_uniform(): run_timer(dist, command, None, SETUP, 'Uniforms') -def timer_8bit_bounded(use_masked=True): - # info = np.iinfo(np.uint8) - # min, max = info.min, info.max - - min, max = 0, 65 - 1 # WORST case for masking & rejection algorithm! - # min, max = 0, 48 - 1 # AVERAGE case for masking & rejection algorithm! +def timer_8bit_bounded(max=127, use_masked=True): + min = 0 dist = 'random_uintegers' @@ -108,15 +104,11 @@ def timer_8bit_bounded(use_masked=True): command_numpy = command_numpy.format(min=min, max=max) run_timer(dist, command, command_numpy, SETUP, - '8-bit bounded unsigned integers; use_masked={use_masked}'.format(use_masked=use_masked)) - + '8-bit bounded unsigned integers (max={max}, use_masked={use_masked})'.format(max=max, use_masked=use_masked)) -def timer_16bit_bounded(use_masked=True): - # info = np.iinfo(np.uint16) - # min, max = info.min, info.max - min, max = 0, 1025 - 1 # WORST case for masking & rejection algorithm! - # min, max = 0, 1536 - 1 # AVERAGE case for masking & rejection algorithm! +def timer_16bit_bounded(max=1535, use_masked=True): + min = 0 dist = 'random_uintegers' @@ -136,7 +128,7 @@ def timer_16bit_bounded(use_masked=True): command_numpy = command_numpy.format(min=min, max=max) run_timer(dist, command, command_numpy, SETUP, - '16-bit bounded unsigned integers; use_masked={use_masked}'.format(use_masked=use_masked)) + '16-bit bounded unsigned integers (max={max}, use_masked={use_masked})'.format(max=max, use_masked=use_masked)) def timer_32bit(): @@ -149,12 +141,8 @@ def timer_32bit(): run_timer(dist, command, command_numpy, SETUP, '32-bit unsigned integers') -def timer_32bit_bounded(use_masked=True): - # info = np.iinfo(np.uint32) - # min, max = info.min, info.max - - min, max = 0, 1025 - 1 # WORST case for masking & rejection algorithm! - # min, max = 0, 1536 - 1 # AVERAGE case for masking & rejection algorithm! +def timer_32bit_bounded(max=1535, use_masked=True): + min = 0 dist = 'random_uintegers' @@ -174,7 +162,7 @@ def timer_32bit_bounded(use_masked=True): command_numpy = command_numpy.format(min=min, max=max) run_timer(dist, command, command_numpy, SETUP, - '32-bit bounded unsigned integers; use_masked={use_masked}'.format(use_masked=use_masked)) + '32-bit bounded unsigned integers (max={max}, use_masked={use_masked})'.format(max=max, use_masked=use_masked)) def timer_64bit(): @@ -187,12 +175,8 @@ def timer_64bit(): run_timer(dist, command, command_numpy, SETUP, '64-bit unsigned integers') -def timer_64bit_bounded(use_masked=True): - # info = np.iinfo(np.uint64) - # min, max = info.min, info.max - - min, max = 0, 1025 - 1 # WORST case for masking & rejection algorithm! - # min, max = 0, 1536 - 1 # AVERAGE case for masking & rejection algorithm! +def timer_64bit_bounded(max=1535, use_masked=True): + min = 0 dist = 'random_uintegers' @@ -212,7 +196,7 @@ def timer_64bit_bounded(use_masked=True): command_numpy = command_numpy.format(min=min, max=max) run_timer(dist, command, command_numpy, SETUP, - '64-bit bounded unsigned integers; use_masked={use_masked}'.format(use_masked=use_masked)) + '64-bit bounded unsigned integers (max={max}, use_masked={use_masked})'.format(max=max, use_masked=use_masked)) def timer_normal_zig(): @@ -233,13 +217,27 @@ def timer_normal_zig(): if args.full: timer_raw() timer_8bit_bounded(use_masked=True) - timer_8bit_bounded(use_masked=False) + timer_8bit_bounded(max=64, use_masked=False) # Worst case for Numpy. + timer_8bit_bounded(max=95, use_masked=False) # Typ. avrg. case for Numpy. + timer_8bit_bounded(max=127, use_masked=False) # Best case for Numpy. + timer_16bit_bounded(use_masked=True) - timer_16bit_bounded(use_masked=False) + timer_16bit_bounded(max=1024, use_masked=False) # Worst case for Numpy. + timer_16bit_bounded(max=1535, use_masked=False) # Typ. avrg. case for Numpy. + timer_16bit_bounded(max=2047, use_masked=False) # Best case for Numpy. + timer_32bit() + timer_32bit_bounded(use_masked=True) - timer_32bit_bounded(use_masked=False) + timer_32bit_bounded(max=1024, use_masked=False) # Worst case for Numpy. + timer_32bit_bounded(max=1535, use_masked=False) # Typ. avrg. case for Numpy. + timer_32bit_bounded(max=2047, use_masked=False) # Best case for Numpy. + timer_64bit() + timer_64bit_bounded(use_masked=True) - timer_64bit_bounded(use_masked=False) + timer_64bit_bounded(max=1024, use_masked=False) # Worst case for Numpy. + timer_64bit_bounded(max=1535, use_masked=False) # Typ. avrg. case for Numpy. + timer_64bit_bounded(max=2047, use_masked=False) # Best case for Numpy. + timer_normal_zig() From f3b0a2cee6bc273514d8e624becd890a20f7e709 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Mon, 22 Oct 2018 17:51:52 +0200 Subject: [PATCH 158/279] Updated the default max bound for benchmark timer_8bit_bounded. --- _randomgen/benchmark.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index c8358c62f569..52c8980616b2 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -83,7 +83,7 @@ def timer_uniform(): run_timer(dist, command, None, SETUP, 'Uniforms') -def timer_8bit_bounded(max=127, use_masked=True): +def timer_8bit_bounded(max=95, use_masked=True): min = 0 dist = 'random_uintegers' From 5aea934156c6d5a021bd23b7ebb8e7bf64d524d3 Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Mon, 22 Oct 2018 20:06:36 +0200 Subject: [PATCH 159/279] Trigger CI tests. From 5fdedc994122c5fccf47fe69b609e59c6fd2c79c Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Mon, 22 Oct 2018 22:44:07 +0200 Subject: [PATCH 160/279] Removed --full benchmark from CI tests. --- _randomgen/.travis.yml | 2 +- _randomgen/appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 8a39ee161706..bc483fb97ec4 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -80,5 +80,5 @@ after_success: - | if [[ ${DOCBUILD} == true ]]; then cd ${BUILD_DIR} - python benchmark.py --full; + python benchmark.py; fi diff --git a/_randomgen/appveyor.yml b/_randomgen/appveyor.yml index 1520687ce3c6..88544620de73 100644 --- a/_randomgen/appveyor.yml +++ b/_randomgen/appveyor.yml @@ -30,4 +30,4 @@ test_script: on_success: - cd %GIT_DIR%\ - - python benchmark.py --full + - python benchmark.py From 87751ff2f4cd32f429147d7dfc8626b4cd4c7f6d Mon Sep 17 00:00:00 2001 From: bduvenhage Date: Tue, 23 Oct 2018 06:22:39 +0200 Subject: [PATCH 161/279] Trigger CI tests. From 9ca841326c4889553d0ed6812b85a6191e586cb5 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 21 Oct 2018 00:05:09 +0100 Subject: [PATCH 162/279] ENH/BUG: Add Xoshiro256starstar generator Add recently introduced improved generator Xoshiro256** Add recently introduced improved generator Xoshiro512** Fix bug in jump for Random123 generators Fix test to run jump and advance --- _randomgen/benchmark.py | 3 +- _randomgen/randomgen/__init__.py | 5 +- _randomgen/randomgen/common.pyx | 2 +- .../examples/numba/extending_distributions.py | 2 +- _randomgen/randomgen/generator.pyx | 2 +- _randomgen/randomgen/legacy/_legacy.pyx | 2 +- _randomgen/randomgen/philox.pyx | 2 +- _randomgen/randomgen/pickle.py | 7 +- .../src/xoshiro256starstar/LICENSE.md | 9 + .../xoshiro256starstar-test-data-gen.c | 72 ++ .../xoshiro256starstar/xoshiro256starstar.c | 55 + .../xoshiro256starstar/xoshiro256starstar.h | 63 ++ .../xoshiro256starstar.orig.c | 103 ++ .../xoshiro256starstar.orig.h | 5 + .../xoshiro512starstar-test-data-gen.c | 72 ++ .../xoshiro512starstar/xoshiro512starstar.c | 53 + .../xoshiro512starstar/xoshiro512starstar.h | 75 ++ .../xoshiro512starstar.orig.c | 67 ++ .../xoshiro512starstar.orig.h | 6 + .../data/xoshiro256starstar-testset-1.csv | 1001 +++++++++++++++++ .../data/xoshiro256starstar-testset-2.csv | 1001 +++++++++++++++++ .../data/xoshiro512starstar-testset-1.csv | 1001 +++++++++++++++++ .../data/xoshiro512starstar-testset-2.csv | 1001 +++++++++++++++++ _randomgen/randomgen/tests/test_direct.py | 29 +- .../randomgen/tests/test_numpy_mt19937.py | 3 +- _randomgen/randomgen/tests/test_smoke.py | 64 +- _randomgen/randomgen/threefry.pyx | 2 +- _randomgen/randomgen/threefry32.pyx | 2 +- _randomgen/randomgen/xoshiro256starstar.pyx | 362 ++++++ _randomgen/randomgen/xoshiro512starstar.pyx | 356 ++++++ _randomgen/setup.py | 29 +- 31 files changed, 5430 insertions(+), 26 deletions(-) create mode 100644 _randomgen/randomgen/src/xoshiro256starstar/LICENSE.md create mode 100644 _randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c create mode 100644 _randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.c create mode 100644 _randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.h create mode 100644 _randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c create mode 100644 _randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h create mode 100644 _randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c create mode 100644 _randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.c create mode 100644 _randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.h create mode 100644 _randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c create mode 100644 _randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h create mode 100644 _randomgen/randomgen/tests/data/xoshiro256starstar-testset-1.csv create mode 100644 _randomgen/randomgen/tests/data/xoshiro256starstar-testset-2.csv create mode 100644 _randomgen/randomgen/tests/data/xoshiro512starstar-testset-1.csv create mode 100644 _randomgen/randomgen/tests/data/xoshiro512starstar-testset-2.csv create mode 100644 _randomgen/randomgen/xoshiro256starstar.pyx create mode 100644 _randomgen/randomgen/xoshiro512starstar.pyx diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 665f63c26570..1a76d30c544b 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -27,7 +27,8 @@ scale_64 = 2 PRNGS = ['DSFMT', 'PCG64', 'PCG32', 'MT19937', 'Xoroshiro128', 'Xorshift1024', - 'Philox', 'ThreeFry', 'ThreeFry32', 'numpy'] + 'Xoshiro256StarStar', 'Xoshiro512StarStar', 'Philox', 'ThreeFry', + 'ThreeFry32', 'numpy'] def timer(code, setup): diff --git a/_randomgen/randomgen/__init__.py b/_randomgen/randomgen/__init__.py index 49094dffcd16..7529922195b0 100644 --- a/_randomgen/randomgen/__init__.py +++ b/_randomgen/randomgen/__init__.py @@ -8,9 +8,12 @@ from randomgen.threefry32 import ThreeFry32 from randomgen.xoroshiro128 import Xoroshiro128 from randomgen.xorshift1024 import Xorshift1024 +from randomgen.xoshiro256starstar import Xoshiro256StarStar +from randomgen.xoshiro512starstar import Xoshiro512StarStar __all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'PCG32', 'Philox', - 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024'] + 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024', + 'Xoshiro256StarStar', 'Xoshiro512StarStar'] from ._version import get_versions diff --git a/_randomgen/randomgen/common.pyx b/_randomgen/randomgen/common.pyx index 73638aaa32bb..b152099eb0cb 100644 --- a/_randomgen/randomgen/common.pyx +++ b/_randomgen/randomgen/common.pyx @@ -1,5 +1,5 @@ #!python -#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True +#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3 from __future__ import absolute_import from collections import namedtuple diff --git a/_randomgen/randomgen/examples/numba/extending_distributions.py b/_randomgen/randomgen/examples/numba/extending_distributions.py index c0094bf1b882..17ba2704c2e4 100644 --- a/_randomgen/randomgen/examples/numba/extending_distributions.py +++ b/_randomgen/randomgen/examples/numba/extending_distributions.py @@ -14,7 +14,7 @@ rem PYTHON_HOME is setup dependent, this is an example set PYTHON_HOME=c:\Anaconda cl.exe /LD .\distributions.c -DDLL_EXPORT \ - -I%PYTHON_HOME%\lib\site-packages\numpy\core\include \ + -I%PYTHON_HOME%\lib\site-packages\numpy\core\include \ -I%PYTHON_HOME%\include %PYTHON_HOME%\libs\python36.lib move distributions.dll ../../examples/numba/ """ diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index a752aa84c285..a016e7262deb 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -1,5 +1,5 @@ #!python -#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True +#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3 from __future__ import absolute_import import operator diff --git a/_randomgen/randomgen/legacy/_legacy.pyx b/_randomgen/randomgen/legacy/_legacy.pyx index a45ee829fbe5..030c057de657 100644 --- a/_randomgen/randomgen/legacy/_legacy.pyx +++ b/_randomgen/randomgen/legacy/_legacy.pyx @@ -1,5 +1,5 @@ #!python -#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True +#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3 from __future__ import absolute_import import warnings diff --git a/_randomgen/randomgen/philox.pyx b/_randomgen/randomgen/philox.pyx index c08f54496317..26ece5e14b2c 100644 --- a/_randomgen/randomgen/philox.pyx +++ b/_randomgen/randomgen/philox.pyx @@ -327,7 +327,7 @@ cdef class Philox: self.rng_state.uinteger = value['uinteger'] self.rng_state.buffer_pos = value['buffer_pos'] - def jump(self, np.npy_intp iter): + def jump(self, np.npy_intp iter=1): """ jump(iter=1) diff --git a/_randomgen/randomgen/pickle.py b/_randomgen/randomgen/pickle.py index ca6f9cd4c83d..4dde4c2c85ec 100644 --- a/_randomgen/randomgen/pickle.py +++ b/_randomgen/randomgen/pickle.py @@ -8,6 +8,8 @@ from randomgen.threefry32 import ThreeFry32 from randomgen.xoroshiro128 import Xoroshiro128 from randomgen.xorshift1024 import Xorshift1024 +from randomgen.xoshiro256starstar import Xoshiro256StarStar +from randomgen.xoshiro512starstar import Xoshiro512StarStar from randomgen.legacy import LegacyGenerator BasicRNGS = {'MT19937': MT19937, @@ -18,7 +20,10 @@ 'ThreeFry': ThreeFry, 'ThreeFry32': ThreeFry32, 'Xorshift1024': Xorshift1024, - 'Xoroshiro128': Xoroshiro128} + 'Xoroshiro128': Xoroshiro128, + 'Xoshiro256StarStar': Xoshiro256StarStar, + 'Xoshiro512StarStar': Xoshiro512StarStar, + } def __generator_ctor(brng_name='mt19937'): diff --git a/_randomgen/randomgen/src/xoshiro256starstar/LICENSE.md b/_randomgen/randomgen/src/xoshiro256starstar/LICENSE.md new file mode 100644 index 000000000000..d863f3b29a79 --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro256starstar/LICENSE.md @@ -0,0 +1,9 @@ +# XOSHIRO256STARSTAR + +Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . \ No newline at end of file diff --git a/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c b/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c new file mode 100644 index 000000000000..8522229ddd89 --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c @@ -0,0 +1,72 @@ +/* + * Generate testing csv files + * + * cl xoshiro256starstar-test-data-gen.c xoshiro256starstar.orig.c / + * ../splitmix64/splitmix64.c /Ox + * xoshiro256starstar-test-data-gen.exe * + * + * gcc xoshiro256starstar-test-data-gen.c xoshiro256starstar.orig.c / + * ../splitmix64/splitmix64.c -o xoshiro256starstar-test-data-gen + * ./xoshiro256starstar-test-data-gen + * + * Requres the Random123 directory containing header files to be located in the + * same directory (not included). + * + */ + +#include "../splitmix64/splitmix64.h" +#include "xoshiro256starstar.orig.h" +#include +#include + +#define N 1000 + +int main() { + uint64_t sum = 0; + uint64_t state, seed = 0xDEADBEAF; + state = seed; + int i; + for (i = 0; i < 4; i++) { + s[i] = splitmix64_next(&state); + } + uint64_t store[N]; + for (i = 0; i < N; i++) { + store[i] = next(); + } + + FILE *fp; + fp = fopen("xoshiro256starstar-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); + + seed = state = 0; + for (i = 0; i < 4; i++) { + s[i] = splitmix64_next(&state); + } + for (i = 0; i < N; i++) { + store[i] = next(); + } + fp = fopen("xoshiro256starstar-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); +} diff --git a/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.c b/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.c new file mode 100644 index 000000000000..30b6c7d85aef --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.c @@ -0,0 +1,55 @@ +/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . */ + +#include "xoshiro256starstar.h" + +/* This is xoshiro256** 1.0, our all-purpose, rock-solid generator. It has + excellent (sub-ns) speed, a state (256 bits) that is large enough for + any parallel application, and it passes all tests we are aware of. + + For generating just floating-point numbers, xoshiro256+ is even faster. + + The state must be seeded so that it is not everywhere zero. If you have + a 64-bit seed, we suggest to seed a splitmix64 generator and use its + output to fill s. */ + +extern INLINE uint64_t xoshiro256starstar_next64(xoshiro256starstar_state *state); + +extern INLINE uint32_t xoshiro256starstar_next32(xoshiro256starstar_state *state); + +/* This is the jump function for the generator. It is equivalent + to 2^128 calls to next(); it can be used to generate 2^128 + non-overlapping subsequences for parallel computations. */ + +void xoshiro256starstar_jump(xoshiro256starstar_state *state) +{ + int i, b; + static const uint64_t JUMP[] = {0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c}; + + uint64_t s0 = 0; + uint64_t s1 = 0; + uint64_t s2 = 0; + uint64_t s3 = 0; + for (i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for (b = 0; b < 64; b++) + { + if (JUMP[i] & UINT64_C(1) << b) + { + s0 ^= state->s[0]; + s1 ^= state->s[1]; + s2 ^= state->s[2]; + s3 ^= state->s[3]; + } + xoshiro256starstar_next(&state->s[0]); + } + + state->s[0] = s0; + state->s[1] = s1; + state->s[2] = s2; + state->s[3] = s3; +} diff --git a/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.h b/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.h new file mode 100644 index 000000000000..1d7d8ea40485 --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.h @@ -0,0 +1,63 @@ +#ifndef _RANDOMDGEN__XOSHIRO256STARSTAR_H_ +#define _RANDOMDGEN__XOSHIRO256STARSTAR_H_ + +#ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/inttypes.h" +#define INLINE __forceinline +#else +#include +#define INLINE __inline __forceinline +#endif +#else +#include +#define INLINE inline +#endif + +typedef struct s_xoshiro256starstar_state { + uint64_t s[4]; + int has_uint32; + uint32_t uinteger; +} xoshiro256starstar_state; + +static INLINE uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + +static INLINE uint64_t xoshiro256starstar_next(uint64_t *s) { + const uint64_t result_starstar = rotl(s[1] * 5, 7) * 9; + const uint64_t t = s[1] << 17; + + s[2] ^= s[0]; + s[3] ^= s[1]; + s[1] ^= s[2]; + s[0] ^= s[3]; + + s[2] ^= t; + + s[3] = rotl(s[3], 45); + + return result_starstar; +} + +static INLINE uint64_t +xoshiro256starstar_next64(xoshiro256starstar_state *state) { + return xoshiro256starstar_next(&state->s[0]); +} + +static INLINE uint32_t +xoshiro256starstar_next32(xoshiro256starstar_state *state) { + uint64_t next; + if (state->has_uint32) { + state->has_uint32 = 0; + return state->uinteger; + } + next = xoshiro256starstar_next(&state->s[0]); + state->has_uint32 = 1; + state->uinteger = (uint32_t)(next >> 32); + return (uint32_t)(next & 0xffffffff); +} + +void xoshiro256starstar_jump(xoshiro256starstar_state *state); + +#endif diff --git a/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c b/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c new file mode 100644 index 000000000000..ecf87bab95bb --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c @@ -0,0 +1,103 @@ +/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . */ + +#include + +/* This is xoshiro256** 1.0, our all-purpose, rock-solid generator. It has + excellent (sub-ns) speed, a state (256 bits) that is large enough for + any parallel application, and it passes all tests we are aware of. + + For generating just floating-point numbers, xoshiro256+ is even faster. + + The state must be seeded so that it is not everywhere zero. If you have + a 64-bit seed, we suggest to seed a splitmix64 generator and use its + output to fill s. */ + +static inline uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + + +uint64_t s[4]; + +uint64_t next(void) { + const uint64_t result_starstar = rotl(s[1] * 5, 7) * 9; + + const uint64_t t = s[1] << 17; + + s[2] ^= s[0]; + s[3] ^= s[1]; + s[1] ^= s[2]; + s[0] ^= s[3]; + + s[2] ^= t; + + s[3] = rotl(s[3], 45); + + return result_starstar; +} + + +/* This is the jump function for the generator. It is equivalent + to 2^128 calls to next(); it can be used to generate 2^128 + non-overlapping subsequences for parallel computations. */ + +void jump(void) { + static const uint64_t JUMP[] = { 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c }; + + uint64_t s0 = 0; + uint64_t s1 = 0; + uint64_t s2 = 0; + uint64_t s3 = 0; + for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for(int b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) { + s0 ^= s[0]; + s1 ^= s[1]; + s2 ^= s[2]; + s3 ^= s[3]; + } + next(); + } + + s[0] = s0; + s[1] = s1; + s[2] = s2; + s[3] = s3; +} + + + +/* This is the long-jump function for the generator. It is equivalent to + 2^192 calls to next(); it can be used to generate 2^64 starting points, + from each of which jump() will generate 2^64 non-overlapping + subsequences for parallel distributed computations. */ + +void long_jump(void) { + static const uint64_t LONG_JUMP[] = { 0x76e15d3efefdcbbf, 0xc5004e441c522fb3, 0x77710069854ee241, 0x39109bb02acbe635 }; + + uint64_t s0 = 0; + uint64_t s1 = 0; + uint64_t s2 = 0; + uint64_t s3 = 0; + for(int i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++) + for(int b = 0; b < 64; b++) { + if (LONG_JUMP[i] & UINT64_C(1) << b) { + s0 ^= s[0]; + s1 ^= s[1]; + s2 ^= s[2]; + s3 ^= s[3]; + } + next(); + } + + s[0] = s0; + s[1] = s1; + s[2] = s2; + s[3] = s3; +} \ No newline at end of file diff --git a/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h b/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h new file mode 100644 index 000000000000..3aa788ec92e0 --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h @@ -0,0 +1,5 @@ +#include + +uint64_t s[4]; +uint64_t next(void); +void jump(void); diff --git a/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c b/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c new file mode 100644 index 000000000000..bcc3574e4a6c --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c @@ -0,0 +1,72 @@ +/* + * Generate testing csv files + * + * cl xoshiro512starstar-test-data-gen.c xoshiro512starstar.orig.c / + * ../splitmix64/splitmix64.c /Ox + * xoshiro512starstar-test-data-gen.exe * + * + * gcc xoshiro512starstar-test-data-gen.c xoshiro512starstar.orig.c / + * ../splitmix64/splitmix64.c -o xoshiro512starstar-test-data-gen + * ./xoshiro512starstar-test-data-gen + * + * Requres the Random123 directory containing header files to be located in the + * same directory (not included). + * + */ + +#include "../splitmix64/splitmix64.h" +#include "xoshiro512starstar.orig.h" +#include +#include + +#define N 1000 + +int main() { + uint64_t sum = 0; + uint64_t state, seed = 0xDEADBEAF; + state = seed; + int i; + for (i = 0; i < 8; i++) { + s[i] = splitmix64_next(&state); + } + uint64_t store[N]; + for (i = 0; i < N; i++) { + store[i] = next(); + } + + FILE *fp; + fp = fopen("xoshiro512starstar-testset-1.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); + + seed = state = 0; + for (i = 0; i < 8; i++) { + s[i] = splitmix64_next(&state); + } + for (i = 0; i < N; i++) { + store[i] = next(); + } + fp = fopen("xoshiro512starstar-testset-2.csv", "w"); + if (fp == NULL) { + printf("Couldn't open file\n"); + return -1; + } + fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); + for (i = 0; i < N; i++) { + fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); + if (i == 999) { + printf("%d, 0x%" PRIx64 "\n", i, store[i]); + } + } + fclose(fp); +} diff --git a/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.c b/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.c new file mode 100644 index 000000000000..a9f56699f51d --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.c @@ -0,0 +1,53 @@ +/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . */ + +#include "xoshiro512starstar.h" + +/* This is xoshiro512** 1.0, an all-purpose, rock-solid generator. It has + excellent (about 1ns) speed, an increased state (512 bits) that is + large enough for any parallel application, and it passes all tests we + are aware of. + + For generating just floating-point numbers, xoshiro512+ is even faster. + + The state must be seeded so that it is not everywhere zero. If you have + a 64-bit seed, we suggest to seed a splitmix64 generator and use its + output to fill s. */ + +extern INLINE uint64_t +xoshiro512starstar_next64(xoshiro512starstar_state *state); + +extern INLINE uint32_t +xoshiro512starstar_next32(xoshiro512starstar_state *state); + +/* This is the jump function for the generator. It is equivalent + to 2^256 calls to next(); it can be used to generate 2^256 + non-overlapping subsequences for parallel computations. */ + +static uint64_t s_placeholder[8]; + +void xoshiro512starstar_jump(xoshiro512starstar_state *state) { + + int i, b, w; + static const uint64_t JUMP[] = {0x33ed89b6e7a353f9, 0x760083d7955323be, + 0x2837f2fbb5f22fae, 0x4b8c5674d309511c, + 0xb11ac47a7ba28c25, 0xf1be7667092bcc1c, + 0x53851efdb6df0aaf, 0x1ebbc8b23eaf25db}; + + uint64_t t[sizeof s_placeholder / sizeof *s_placeholder]; + memset(t, 0, sizeof t); + for (i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for (b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) + for (w = 0; w < sizeof s_placeholder / sizeof *s_placeholder; w++) + t[w] ^= state->s[w]; + xoshiro512starstar_next(&state->s[0]); + } + + memcpy(state->s, t, sizeof s_placeholder); +} diff --git a/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.h b/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.h new file mode 100644 index 000000000000..0fa0ba3cda1a --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.h @@ -0,0 +1,75 @@ +#ifndef _RANDOMDGEN__XOSHIRO512STARSTAR_H_ +#define _RANDOMDGEN__XOSHIRO512STARSTAR_H_ + +#ifdef _WIN32 +#if _MSC_VER == 1500 +#include "../common/inttypes.h" +#define INLINE __forceinline +#else +#include +#define INLINE __inline __forceinline +#endif +#else +#include +#define INLINE inline +#endif +#include + +typedef struct s_xoshiro512starstar_state +{ + uint64_t s[8]; + int has_uint32; + uint32_t uinteger; +} xoshiro512starstar_state; + +static INLINE uint64_t rotl(const uint64_t x, int k) +{ + return (x << k) | (x >> (64 - k)); +} + +static INLINE uint64_t xoshiro512starstar_next(uint64_t *s) +{ + const uint64_t result_starstar = rotl(s[1] * 5, 7) * 9; + + const uint64_t t = s[1] << 11; + + s[2] ^= s[0]; + s[5] ^= s[1]; + s[1] ^= s[2]; + s[7] ^= s[3]; + s[3] ^= s[4]; + s[4] ^= s[5]; + s[0] ^= s[6]; + s[6] ^= s[7]; + + s[6] ^= t; + + s[7] = rotl(s[7], 21); + + return result_starstar; +} + +static INLINE uint64_t +xoshiro512starstar_next64(xoshiro512starstar_state *state) +{ + return xoshiro512starstar_next(&state->s[0]); +} + +static INLINE uint32_t +xoshiro512starstar_next32(xoshiro512starstar_state *state) +{ + uint64_t next; + if (state->has_uint32) + { + state->has_uint32 = 0; + return state->uinteger; + } + next = xoshiro512starstar_next(&state->s[0]); + state->has_uint32 = 1; + state->uinteger = (uint32_t)(next >> 32); + return (uint32_t)(next & 0xffffffff); +} + +void xoshiro512starstar_jump(xoshiro512starstar_state *state); + +#endif diff --git a/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c b/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c new file mode 100644 index 000000000000..0cf884edb036 --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c @@ -0,0 +1,67 @@ +/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . */ + +#include "xoshiro512starstar.orig.h" + +/* This is xoshiro512** 1.0, an all-purpose, rock-solid generator. It has + excellent (about 1ns) speed, an increased state (512 bits) that is + large enough for any parallel application, and it passes all tests we + are aware of. + + For generating just floating-point numbers, xoshiro512+ is even faster. + + The state must be seeded so that it is not everywhere zero. If you have + a 64-bit seed, we suggest to seed a splitmix64 generator and use its + output to fill s. */ + +static inline uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + + +uint64_t next(void) { + const uint64_t result_starstar = rotl(s[1] * 5, 7) * 9; + + const uint64_t t = s[1] << 11; + + s[2] ^= s[0]; + s[5] ^= s[1]; + s[1] ^= s[2]; + s[7] ^= s[3]; + s[3] ^= s[4]; + s[4] ^= s[5]; + s[0] ^= s[6]; + s[6] ^= s[7]; + + s[6] ^= t; + + s[7] = rotl(s[7], 21); + + return result_starstar; +} + + +/* This is the jump function for the generator. It is equivalent + to 2^256 calls to next(); it can be used to generate 2^256 + non-overlapping subsequences for parallel computations. */ + +void jump(void) { + static const uint64_t JUMP[] = { 0x33ed89b6e7a353f9, 0x760083d7955323be, 0x2837f2fbb5f22fae, 0x4b8c5674d309511c, 0xb11ac47a7ba28c25, 0xf1be7667092bcc1c, 0x53851efdb6df0aaf, 0x1ebbc8b23eaf25db }; + + uint64_t t[sizeof s / sizeof *s]; + memset(t, 0, sizeof t); + for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for(int b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) + for(int w = 0; w < sizeof s / sizeof *s; w++) + t[w] ^= s[w]; + next(); + } + + memcpy(s, t, sizeof s); +} \ No newline at end of file diff --git a/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h b/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h new file mode 100644 index 000000000000..0b7892473d44 --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h @@ -0,0 +1,6 @@ +#include +#include + +uint64_t s[8]; +uint64_t next(void); +void jump(void); diff --git a/_randomgen/randomgen/tests/data/xoshiro256starstar-testset-1.csv b/_randomgen/randomgen/tests/data/xoshiro256starstar-testset-1.csv new file mode 100644 index 000000000000..534799b04281 --- /dev/null +++ b/_randomgen/randomgen/tests/data/xoshiro256starstar-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 0xdeadbeaf +0, 0x876912846bc23b4b +1, 0xc392a0d7b1e2ce1d +2, 0x3a77bd8137033383 +3, 0x3f9bb87b973f5364 +4, 0x512bacc4fc06efaa +5, 0xd46c8d8fcbdcf201 +6, 0x377867a5134b9398 +7, 0xaaad55c3f16b804f +8, 0x8d0073c1156e04b3 +9, 0x636fbcd73be174a3 +10, 0x5e1b4e1dee91170e +11, 0x730f46db723ad8c7 +12, 0x10b330f0fad1bf5c +13, 0x88cc7f11032dbf1 +14, 0x988c1508b1baf298 +15, 0xe95976be578a5817 +16, 0x858fe732639b48ec +17, 0x5b64491ba03516e1 +18, 0x3546e28c5de1358a +19, 0x384c66cde49bd1a6 +20, 0xdbc3ca974f85cf87 +21, 0xf540c65c435d9ae0 +22, 0xe037047fd8120ac6 +23, 0x9970c031b58d7d63 +24, 0x5dae4898619ad11e +25, 0xdf3232cc92ccc65e +26, 0xa16beb0132ddff72 +27, 0x34d1995264d4c508 +28, 0x62da0bb6460ac302 +29, 0x40d2691b6746a05 +30, 0x7fb2ff58185cd1c0 +31, 0xc6e06bc2fe11d4b4 +32, 0x7116e104e2f75ff0 +33, 0xb1595e1cedf7141e +34, 0x29ebcf708d3bd9b +35, 0x628b49afc2d944cc +36, 0xab104fe5d2bf804d +37, 0x57ee3653bf484fe2 +38, 0xbf4d601f70f7f9ac +39, 0x2af4545067b5c32c +40, 0x34f14b2f8fa98e75 +41, 0x9b585ee1c787c12a +42, 0xc2e4f8a4e27f80e +43, 0xeb9876161a0b619d +44, 0x8ea0af67974da802 +45, 0x6e003252a09ed65 +46, 0x97526de03c99ffc5 +47, 0xb8bcd950ba3f2913 +48, 0x5da355c049c286b8 +49, 0xb50e613d8186312a +50, 0x945c21f6c4d7ed77 +51, 0xa7239005836ad3fd +52, 0x2129afecc78a928f +53, 0x9ae55d1d91c75ac6 +54, 0xf50bb42f77b43ad5 +55, 0x576f324976a7672b +56, 0xfa6df7e9660cfeff +57, 0x806144cc58601f9d +58, 0x85b39b38330f7af8 +59, 0xb7d0c116d3f9e866 +60, 0x35dfac0003ca608e +61, 0x9b6320f46d3926c4 +62, 0x4242bbd0776236d7 +63, 0x8aebcd05dd117b2 +64, 0x70df852ded653924 +65, 0x11ae5f39da26fe1c +66, 0x312e11e7aa00c4f9 +67, 0x1f038c235ae539f1 +68, 0xb997522615f4a73b +69, 0xb51bd427274c0935 +70, 0x55e7843d0749c8c2 +71, 0x37c3a6b0d4352cb5 +72, 0x2df190f46312134 +73, 0xc2ecce075d612185 +74, 0x6b490f64cd1f6d92 +75, 0x8a548dad9af41d4a +76, 0xc7a4454c7debc6bd +77, 0xdc2892cd77b00030 +78, 0xb760ac60c94d2b18 +79, 0xe35231cb73492527 +80, 0x55c9f1ee4910e683 +81, 0x97a202d0ad5fdb1 +82, 0x8ff5184631a2b156 +83, 0xcf942173d034770b +84, 0x9a06010116e675d9 +85, 0xa217423b96ae34c0 +86, 0x722e29ffb7567065 +87, 0xbea7d7060cd1a4c0 +88, 0xbcbad83a19de8545 +89, 0xa88c0985b701818c +90, 0x6c1fb7fc4ca8034 +91, 0xb9e24b68f54fb1b0 +92, 0xd925a8a4b8277771 +93, 0xc33beadd812f9876 +94, 0x7b512eae51ab25c7 +95, 0x3a5436f701a0064 +96, 0x6fa2dbfe047f973d +97, 0xa21076a7f59bef78 +98, 0x3c45f50a3e6f06d4 +99, 0x6cd17ca1a4fe09d +100, 0x8121cf3ffc6a1dd7 +101, 0x7b74926ec6d5a7e7 +102, 0x51eb9833ab8da289 +103, 0xaeb2a89fc9beff8 +104, 0x9fcd9cd992f8c183 +105, 0x5190d2596093217c +106, 0xf954156453009abc +107, 0x2bc45642def07a82 +108, 0xa8e3aaff7419393d +109, 0xff66dbc36b6f4899 +110, 0x7b4481a28034b8fb +111, 0xfc1c059bcaf7021 +112, 0x699b4509593d9079 +113, 0xf2c3cd6bb60ad015 +114, 0x76d11b5fc81c9ead +115, 0x5f28d4878bb011e4 +116, 0x62384630f3e25d61 +117, 0x260445ad18a3738 +118, 0xf92f0a2148f340d2 +119, 0xcb502f1bbdf45006 +120, 0xed89ca318747a00f +121, 0x37597ed2125b038e +122, 0xaee1e4927f412f8d +123, 0x18168368f58eccd9 +124, 0x89db16f70186a9c6 +125, 0x6f428e8fcc8a6ad9 +126, 0xb3865b982fe6b986 +127, 0xc1fae9d75ee9bda2 +128, 0xa0b8256d2615e34 +129, 0xd15c4642cc470639 +130, 0xf7f644305154bb69 +131, 0x65592281bae36127 +132, 0x840ebd2e2d314c8c +133, 0xdb08b0bec618b8de +134, 0xaec9540e4eabc7a1 +135, 0x2473da693e1ec36e +136, 0x6be6fdcfccd55dc2 +137, 0xce279e14163df56b +138, 0xc55baabca12406eb +139, 0x7283920d8e00779e +140, 0xea67175f9bd0ce52 +141, 0xe86bc373ed2f7e55 +142, 0xac3acc2569a30892 +143, 0xc749fc876e37766f +144, 0xddc74e16941b8d6e +145, 0xb9c8f5b769849f7b +146, 0xbab826c423a209a5 +147, 0xf1c1b54021fe6418 +148, 0xdad8586480fd30b0 +149, 0x8f713802438a6a1c +150, 0xc3c2f2b83c7d60c9 +151, 0x9697fdffad622052 +152, 0xcb72a8d5150d0507 +153, 0xc1371661bc3c9721 +154, 0x88ca5be46f1d728e +155, 0xdeb9ae3295bb0e4 +156, 0x2d83f4159ad3e2b8 +157, 0xb30c4ada3b396a15 +158, 0x5aac4c5e77f1d4d4 +159, 0x529374c779ee531 +160, 0xb5919e58de0d772a +161, 0x820809cc936741fb +162, 0x53bbba6d2a08acde +163, 0x9a59ed5a21be8fc0 +164, 0x88aa7be1658d60ef +165, 0xbcb7fc1ad8c7d828 +166, 0x11ab2e78229e89fa +167, 0x2056ea8f9c5867f3 +168, 0xfa27e3857ecc3b94 +169, 0x1e42b81f1d84f464 +170, 0x5e1014b09c812c14 +171, 0x9aaa9d8468d9e341 +172, 0x1bfb091f9815ee21 +173, 0x5caacbb9cc7aa2fe +174, 0x58d8a864c538e3c5 +175, 0x539382e5be9cc79 +176, 0xbd89db78d603a58 +177, 0x39e1a6cbda31f0e0 +178, 0x466a59433990edbf +179, 0x56d18c76058e2ce7 +180, 0x2602ce3675d0bdc1 +181, 0x1739af88af931f1b +182, 0x862a947f2809512e +183, 0x6f18216e0710069d +184, 0x5f6e251768ff8b2a +185, 0x3a3be0c1955b088a +186, 0x22b96dd914c79b47 +187, 0x18051e8fcfce2edf +188, 0x80b0f2cceec301d9 +189, 0x868586cb1388e737 +190, 0x22f7c668c6e0da2d +191, 0x13509ef57125f1e7 +192, 0xb91dce92077fb2d1 +193, 0x31b4841411853ad0 +194, 0x32e2ddc8b722c29f +195, 0x5ca01b204c0b166f +196, 0xa2e337cd3dd5a9d1 +197, 0x4131b472c753075d +198, 0x7efcc7a894c9a981 +199, 0xc1d9c33d90e01db3 +200, 0x9053f0abe677615d +201, 0xd2034c8d4e1aa8af +202, 0x227275362bffc8f8 +203, 0x8d5a9d405ecd0179 +204, 0x7b30ddf5440f02d1 +205, 0x3620f9d1867ad68d +206, 0x747ed65beeeba258 +207, 0x1691d5d4a7786e03 +208, 0xf50455cc65243abb +209, 0x4aa91863da8b65d5 +210, 0xa69807c0a08dfafe +211, 0x4fcc33b50b00b3d3 +212, 0xe0671f97db7a35d +213, 0x263f8eabf8f9044a +214, 0x27c85ae64e97e89 +215, 0x4520b74f57c7df51 +216, 0xa37c38ec047eb0b8 +217, 0xcabd6e3e95e72d25 +218, 0xe4bb620d2e3a16d9 +219, 0xda87a4272a6ad108 +220, 0xc867f3fbecd0384b +221, 0x8691f46246273ef7 +222, 0x5ce4229e2422943e +223, 0x8c40ee86a9691904 +224, 0xcb9b83f846c9c9e4 +225, 0xa931ac81531e1529 +226, 0x534cebd4cd8fd2d9 +227, 0x2e3cf1c29aeaba0d +228, 0xa3d2e692301343dc +229, 0x1ef408da84681a8c +230, 0x64f7f2f7d3c02da7 +231, 0x541c50b180553eec +232, 0x536194b38f566c5b +233, 0xbb7a282cd9f36f9d +234, 0x527010351098538b +235, 0xfe30504c6e499b4d +236, 0xa7c3602410a59e53 +237, 0x8f44cacb7b7d1267 +238, 0xe40bf315dc5df184 +239, 0xde7eb3b70c1f41c1 +240, 0xc41aecca30a4bb9c +241, 0x3bc0e028ccb19d93 +242, 0xe166010bfe275442 +243, 0xa70abd28e44af7ca +244, 0xd4504f4548d0d888 +245, 0xa55e4eecb4d88bb5 +246, 0xb6ec6442a017ef5c +247, 0x1c62a5d488494ff6 +248, 0x1c09e177b467f30d +249, 0xb9c90e7ad2f47ecd +250, 0xde2c186b02cc341e +251, 0x1a82ff0a466db4dc +252, 0x61db3602688eb096 +253, 0x920df7c1d2b0e8f1 +254, 0x34a2f18c92e9b6ff +255, 0x14830c36acd9ae19 +256, 0xc321ad1ffbfc54ff +257, 0x9e4b1c6799ff696f +258, 0x1780ce1f22fd9395 +259, 0x26c50c518a484cc1 +260, 0x7461330b1fe01211 +261, 0xd81e75bc84a15cf1 +262, 0x86ca81452380da38 +263, 0xe6b956498fa9f351 +264, 0x9ac04fe965ce35cd +265, 0xa4ec6641c5518519 +266, 0xa03e3054f706bb49 +267, 0xacb9b452fd8267ed +268, 0x302282d4ce222225 +269, 0x8b56489048399d5 +270, 0x1feadce5b06b509b +271, 0x7cee1475ce616c7f +272, 0xd414bce3075397b3 +273, 0xc71f6a8a8eff334a +274, 0x99b3df4a89d93e +275, 0xc702c1e101f4f2dd +276, 0xfe3a7177f2ec77c2 +277, 0xe080a478564afac9 +278, 0x665d0087841f481b +279, 0x4dab6f59d3c1a144 +280, 0x1ce185d7d140c8f5 +281, 0xb007fa8eca9036c0 +282, 0xf18f48ac88312c95 +283, 0x79550ca0c88204cc +284, 0x9970ba85bdb15f27 +285, 0x2b55457ead5f009e +286, 0xc4f24923b930e27a +287, 0x8c3018e3bad3b6d6 +288, 0x790837a25c10ee7 +289, 0xb2dd8ab9f1def8a8 +290, 0x363ec10ac55a521a +291, 0x971af7eb3b1560ad +292, 0xe1a3cb1562833819 +293, 0x6e60e9949b6af18a +294, 0xc379834ba34f6820 +295, 0xb668c3b288a5f926 +296, 0x9ffa1bd130c914c9 +297, 0xe6b93d5188a06452 +298, 0x9c520f67b97dfdf0 +299, 0x50c2a9973c08139a +300, 0x59851ffaf533706e +301, 0x2e5eff12d660fb5c +302, 0xeaa1ff394919a29 +303, 0x9846f6684ff28cd2 +304, 0xeda270a0cd0cd09d +305, 0xc0a319acd516a45d +306, 0x6b5e013c4c4e1efa +307, 0x76faab2a47dc7b68 +308, 0x10d5c15c81514814 +309, 0x3783ee8be5024e54 +310, 0xa4cdb957e5844ce2 +311, 0xd20ca72588a28e27 +312, 0xd7f16a0dcc7f77dc +313, 0xd7e945262b79f2b6 +314, 0xe789e1213d3c62ed +315, 0xba2cbc2fa27b9806 +316, 0x1d39cb2e5d96965 +317, 0x4526e9965c23273a +318, 0x23b4c26eb5166240 +319, 0xaf0f404d70dc5638 +320, 0x8933061cb36229e0 +321, 0x69cec3a72559600 +322, 0xf891d9d259e44209 +323, 0x2e49b1c932ba1d66 +324, 0x333f1bc8321c60f +325, 0x53bad1fb53c8c7cd +326, 0x392f1562e71aac52 +327, 0xa9f6d47f02e8b0d7 +328, 0x39f9c3b1feec67d8 +329, 0x669009ed80083055 +330, 0xab063271b9538170 +331, 0x56678abcd6d3864c +332, 0xde74b0617e61cbd8 +333, 0xbb4f24b9395938a6 +334, 0xc56dfbd143423466 +335, 0x4cb5a4a7ff276754 +336, 0xfb7b814159202ccc +337, 0xf7bbd8fce5320160 +338, 0x218d0ad6343402e7 +339, 0xc8f1bb14eea39aa7 +340, 0x92d7e7256dcab678 +341, 0x8f13ff680747d33 +342, 0x7706151f442ce1dd +343, 0xe902f2633656eb91 +344, 0x69cdf1a57b9424bb +345, 0x9775cad17cd05d1b +346, 0xccf9b27b7dd64f7f +347, 0x1a912eedead72feb +348, 0xc1e26527c077acbd +349, 0xc71692a375f3c720 +350, 0xef1e5b57c2054419 +351, 0xa6b72781c1fc92c0 +352, 0x38318f277f1ef07e +353, 0xe5ba934657bd23b4 +354, 0x792b67250dbc761f +355, 0x785df3106f3610ff +356, 0xfa80a926eae8d94f +357, 0x2c0a95d66d691c70 +358, 0x5c7006e181d4a6ac +359, 0x43e8b7dee8fe5379 +360, 0x87f509b549c83695 +361, 0x32599937b8fcd560 +362, 0xb9931fed6f066f24 +363, 0xf2a6ebcb697508ba +364, 0xc0a3c1ba9a67600a +365, 0xc8badd949bd0e30a +366, 0xcafc4c1611c002a7 +367, 0xc4b5310f493c8f20 +368, 0xc51ff1b5bdb380ac +369, 0xa9c73b25f03868f5 +370, 0x9edfdcc90d558540 +371, 0xd3d6333855161133 +372, 0xcbbd5d9ace516738 +373, 0xcb7e692a0f9fe6fa +374, 0x6a21b61cd8fbb617 +375, 0xfc31d9554c519f86 +376, 0x76ea0f8ef0a354a3 +377, 0xadc8a62ec6b08390 +378, 0x66eeb2fe10131429 +379, 0x12ee14e3a238353a +380, 0xbe3447a29c425e72 +381, 0xaaa368536635fb9a +382, 0xad2ed0d14e4c413f +383, 0x217b489205384ccc +384, 0x4f22392204e47cb6 +385, 0x9b073c7bc6fc086 +386, 0x291abda48636aa3c +387, 0x755ecf4077a77de2 +388, 0x34a5d238de636b33 +389, 0x8989d30fc37b325 +390, 0xd0b9fa38231bdf67 +391, 0x72461fe9b5055361 +392, 0xb25bd2fd4a1bfd09 +393, 0x9ed651e16289afac +394, 0xd02d8c13301d3d2e +395, 0x3d5bbed8ed8856bf +396, 0xc44f594ac43fdbb2 +397, 0x9ada629d96abe651 +398, 0x901bec1095df9927 +399, 0x8597db9a0e29e2f0 +400, 0x97194dc163ca609 +401, 0x90c00a05f753a86b +402, 0x426af3db2a4ac0fb +403, 0x8acda542a69f22c2 +404, 0x674cf92ffcd455ac +405, 0x6136bc48b45959d5 +406, 0xb90b38cd1ff9279d +407, 0x4e6c9b5ecae724d9 +408, 0xcf30abb9df98cc0 +409, 0xddee0179acdaf635 +410, 0xafc739ce5a1e5b9c +411, 0x646a8817ddc44ab5 +412, 0xd34ab42bcb8cdb93 +413, 0xdee4cbee62f81c86 +414, 0xc2221ab03185fdfa +415, 0x7c9f570c313fab96 +416, 0xf1b366adbfee1326 +417, 0x7f096df1a4b284e3 +418, 0x41ed5c325a684c02 +419, 0x177d8012ec68bf1e +420, 0x723ef03bbc899b8d +421, 0x4b133232b7b75961 +422, 0xdf26aaf400d56c4 +423, 0xdfdb1c617a5a9794 +424, 0x9ff2f6d5ff5ce426 +425, 0xa902670b191b5b6b +426, 0x6c9b17049b00578e +427, 0x698c0c675043a17b +428, 0x7a39ef3ca26d128d +429, 0x684d4a467f04e43f +430, 0xe2650c63fde538c8 +431, 0xd68d21f5390269e1 +432, 0x128f6856693a6f91 +433, 0xf16e391706e58b04 +434, 0x77487c06bb8213fb +435, 0x6fcd5a620a122728 +436, 0x505c93b08cca8734 +437, 0x9a1132efe64d531c +438, 0x7fffd4b9c31c6ecb +439, 0x18974137a14e2c8 +440, 0x2aff5858af3e3dec +441, 0x37c2c46feb19f7f1 +442, 0x69ff86ca141d00c9 +443, 0x94dabd547190bf71 +444, 0x5fbb969adddaa7c0 +445, 0xa0775e468c054ab8 +446, 0x632e6a69a80b7be4 +447, 0xba23d74ff6f179a6 +448, 0xdc80b0b9a70432a7 +449, 0xe012f4b1362a90f4 +450, 0x7f132473e42cbef +451, 0xfb182eefc0dad8ac +452, 0xf3fb712546ae256c +453, 0x8ac69f2735229dac +454, 0x564cafdaad77f80c +455, 0x876c4ab2647401d0 +456, 0x2baf5f31018e5c1e +457, 0xae1aaf82b13b7597 +458, 0x65944d8b8cabbb95 +459, 0xc7c01bfe1e0fbc00 +460, 0xf6dd901e7bbe8365 +461, 0x94e1050634114f11 +462, 0x47cab1cd353b7f81 +463, 0xa8775049b2696902 +464, 0xb186dc021a9110ea +465, 0xf28259ce664afa40 +466, 0x67558a2beab5b7b1 +467, 0xb117438f266ec05e +468, 0xf9da8468bb4cb968 +469, 0x2af756738bfc47b +470, 0xd5842c66749f950e +471, 0x953373bd7e97e4b +472, 0x49a929314667f184 +473, 0xe64daee7102ddb89 +474, 0xe459bd3f9acdea67 +475, 0x5b9b04066b20c49d +476, 0x5d82abef2d8487fc +477, 0x4f6236c778a5ed31 +478, 0xdcee2584cd287c46 +479, 0x31c53b48310c8c84 +480, 0xb9cd90102e158a63 +481, 0xe57be85d8e42deeb +482, 0x6582541962888815 +483, 0x845fd1538efbe310 +484, 0xaedc7db39263eaad +485, 0xc0ea0704dea093fd +486, 0x7d3e5c4a245ef295 +487, 0xfe651efbca41d1d8 +488, 0x5275c62cc60f26c1 +489, 0x4eb23a86fd35bd79 +490, 0xd3fccb059f30bb9d +491, 0xc9b6267a16be945a +492, 0x8fa963e267e0791a +493, 0x64e7ef9097602cad +494, 0x13a0d7ba848311ef +495, 0x88878d9ebd8381f +496, 0x4556a6258ccd7aa8 +497, 0x1321af0ffa57b4b2 +498, 0x271c1fc481143191 +499, 0xb09b8888fc206dae +500, 0x1fdb714c88aa8318 +501, 0xdadb65138cf1a785 +502, 0x5c25349014f20584 +503, 0xdde1241c9c5a58cd +504, 0xd93741fab3d630e1 +505, 0xe895c89a575d11f5 +506, 0x4f0b79334c81403c +507, 0xd8a9850c307c591a +508, 0x3621e4b8e12c9a19 +509, 0xb9db6231c6fa3793 +510, 0x659a34f2e8b13a30 +511, 0x3f7f65d4138a3ece +512, 0xc68a3b4193c7ddb +513, 0xfedb2ff6f59b308d +514, 0x91a49785126b2707 +515, 0xcd897846c2da401c +516, 0x3174aeb2ef45125a +517, 0xfc93e91769875bea +518, 0x20dc156b32d376bc +519, 0x55b332e7395ae006 +520, 0x898b4d9889ab42d7 +521, 0x80e8b4fa60d67e52 +522, 0x751bb9a5c4f43263 +523, 0x4ef12c7d48b02305 +524, 0xe9b2f6da9932279c +525, 0x28166b1bb0083fe +526, 0xd66ede9e1175436c +527, 0xe1600bfe3543967c +528, 0x9e82c1de27917b7e +529, 0x1a6a6a36eee4e0d3 +530, 0x4fd5e445d2ff89a6 +531, 0xb167da8a45a041b4 +532, 0x90421abd6d6b657 +533, 0xac2d084ffe30c155 +534, 0xaf6d71f79d0250a +535, 0x2d2ba07fc90eaba2 +536, 0xee44751087f49162 +537, 0xd9a125da1f2bcd5b +538, 0x1710b671e85149e2 +539, 0x6345319547b83ad1 +540, 0x68b4495241b6c0e7 +541, 0x74fa064e23915490 +542, 0x994254c5ef7484ff +543, 0x767ce73cb64a3828 +544, 0xc44be811238ec768 +545, 0x49bcfd08e26f93ca +546, 0x8506215301976fbe +547, 0x17d72c4c22b48cc9 +548, 0xf482dc265fc66423 +549, 0x81515cd9ee472156 +550, 0xffc3716cab24bdce +551, 0x4f272ed4fdd1cc65 +552, 0xa5fbe307e8a95706 +553, 0x4f489ae4435d271a +554, 0xc32af641a427871e +555, 0x481501cd6e76b046 +556, 0x7fdb10595e105959 +557, 0xc231d1fbcd7f9905 +558, 0x7f8af2f02dc96527 +559, 0xee1829cff220d07f +560, 0x69cec4a31d43a06a +561, 0x7ec964a98e091334 +562, 0x267d4751786ed827 +563, 0x3ff2a3fa95f49992 +564, 0x4db020a1aaa91126 +565, 0xf0a52fbc2ecbe5e6 +566, 0x22b4a6f29b420436 +567, 0x3baee23caf4332c7 +568, 0xf25b4154d1337b22 +569, 0xa1fc227fdb94fd5c +570, 0x1c8d1858a14c79c7 +571, 0xdee05236f275cd72 +572, 0xbd2feb9b5bfea570 +573, 0x96d3d6d1189b458c +574, 0xbfe1c60f48c2a834 +575, 0x590b91cf41e7f1c +576, 0xa230cd61d4aace50 +577, 0x9b15a3dbd0129922 +578, 0x5a6cd3333e77adea +579, 0x41825f9a09221129 +580, 0x713d20fbbb133600 +581, 0xde695bc734434fc2 +582, 0x80022a312ccfd484 +583, 0xfebe989fbe2d7f33 +584, 0xeacb2fc50aa3ce4b +585, 0xb7bde6fa12d0db67 +586, 0xc5e52e74fd2fcf5e +587, 0xccc74d9803ec269f +588, 0x9f9f1bd42ceed664 +589, 0x5892c340c9b3e3f3 +590, 0x306260b57f475e42 +591, 0x20ba283b7feec8fd +592, 0x8258f0179d4c1aac +593, 0xf4f89922b5afe031 +594, 0xfdba45233cdd04a +595, 0xce0f81c48bfd0d58 +596, 0x4b0cbebe17263b16 +597, 0xfee1fd8f3abf3ee0 +598, 0xfc5194839696ca5d +599, 0xb2106fc284f8cfed +600, 0x3be13181cdac454f +601, 0x1dfea888cdb8755 +602, 0xe1df7e41e646b676 +603, 0x72e16234c51caa19 +604, 0x367a508bf361b3c9 +605, 0x3e8d10a40879846d +606, 0x72540d5ed7c59a5e +607, 0x49d00e4543ebd93d +608, 0xf889e0dfb47c5a24 +609, 0xf6b166031a98e3f0 +610, 0x6ec9c4ac1f367f6e +611, 0x81c322bfb5b4963b +612, 0xe43618859ee305b6 +613, 0x5c0849263dff8bd8 +614, 0xca60ef338ca33c75 +615, 0x96dc953cd8229dfb +616, 0xd33d8edd653f9411 +617, 0x398f97e5a17e9d21 +618, 0xa679fb8f7359cdd3 +619, 0x1a079b224822d2ae +620, 0xd6f973d320aea3bd +621, 0x8147d823ddca9fdb +622, 0x7a15b31891283335 +623, 0x1ddff9012d02fbd7 +624, 0xf8822faf5627a945 +625, 0x41be97afe83c9b99 +626, 0xfc6c03f323a40cf0 +627, 0x40a3547fbda709fa +628, 0xdabf18e62533b8dc +629, 0x3df9047875ad057 +630, 0xaf3cb3461b5ce9a1 +631, 0x372859b34b493176 +632, 0x2fca17f51fa0f9eb +633, 0xc7029f122beba37f +634, 0x3f4e9ea4b4f4e36e +635, 0x63d22717f8c9118d +636, 0xc85fff0d3f30946f +637, 0xfaf6a8680c3327b7 +638, 0x7cc6ff76d32736cf +639, 0xed7066e55443e1d5 +640, 0xf8698e4c0986e3a4 +641, 0xfd8d1e5a65a86bae +642, 0xe52f0012446decc8 +643, 0x5057fe700548fd6c +644, 0x4529015264cdb296 +645, 0xf0bfc50ab6700a9b +646, 0xf42ac8161980025d +647, 0xd4eda173955d8472 +648, 0x37b042b1e5a10dd +649, 0xe325a690ab12eb81 +650, 0x7fcf9f4d85db4127 +651, 0xbacbd13cba440c75 +652, 0xbaaab45fa3ec6721 +653, 0x621a8fb360e704d7 +654, 0x8e97eb1966466330 +655, 0xda7f0a06440024c0 +656, 0xe32b44177201fb54 +657, 0x81426b2259d306df +658, 0xcc12d49f57a2a60d +659, 0x43d840cb2c1b96f3 +660, 0x2f5190397dd5f5fc +661, 0x37ca67cb906f8840 +662, 0x84bdcca3f926b24d +663, 0x833e6cc4f6846646 +664, 0x3d046e6375412bf0 +665, 0x8678ca4ef2e3f721 +666, 0x62d9c438d39748cd +667, 0x750fb4b000895aaf +668, 0x7b760b873d0bfce0 +669, 0x3cc79186f7e7528e +670, 0xe1e304d26bc14e90 +671, 0xe855ed09d88a5b86 +672, 0x99ae65ccd9d9ff9 +673, 0xd9bea1d3d04c6432 +674, 0x6871fc86fccce7a5 +675, 0xca6f22983e5d892b +676, 0x7e29222169c094bc +677, 0xbb6bb434e7225ce2 +678, 0x3b907684d5342268 +679, 0x5e5328163653a332 +680, 0xf56453da8399ea50 +681, 0x4691e0f9a0c6625 +682, 0x11a6cee0f014d630 +683, 0xdff740d94007b83a +684, 0x6744032172a60cb1 +685, 0x8d311639fb358a47 +686, 0xe77ae7a767d74301 +687, 0x994184353b84ffd5 +688, 0x9faa8b6852c8b9ec +689, 0xed5d549c40fd7b31 +690, 0x6bff41b829143500 +691, 0x95cd1f944b72360e +692, 0x966e8976a79bd4f7 +693, 0x5f73608f2069b1f3 +694, 0x20c03970af7c205f +695, 0x9a0e0928bc29f5fa +696, 0xdc80d66b7ec92bc3 +697, 0x558745e23c9e413d +698, 0x32dae13bef9e4398 +699, 0x1af3f745e7ca19b4 +700, 0x1cbb10f2f21417a2 +701, 0x37c03955556e6f6 +702, 0x852afdad0d2459fc +703, 0xee72e7019e217ec4 +704, 0x6854606758560380 +705, 0x9284eba641a65dfc +706, 0x446b92d6b8f3f53a +707, 0xbe360ebdf10ded26 +708, 0x1048ecaabfe15b93 +709, 0x25d1762c447cca8c +710, 0x6cf6151bdd266aa8 +711, 0x2e8fcc480b9d228 +712, 0xeb6b1cbea3c65d63 +713, 0x7a883b88ef974ee5 +714, 0x9f52f4081ea085f0 +715, 0x75fa5e7cbf0c55a5 +716, 0x2bfedfe0e029b818 +717, 0xebaec3bcde2e43b1 +718, 0xeaa3aa06bf8a67e1 +719, 0x4deacc579051e8c0 +720, 0xec44abbc73b62bf4 +721, 0xb9a339ae805270b7 +722, 0xf9eb47d4cba2877 +723, 0x6105cdeb6a7e678e +724, 0x242351322affd465 +725, 0x111fe30cf81b2f70 +726, 0x25b5ae64c741738a +727, 0xfb425508ba96049e +728, 0xe0fbf9619e3a1aee +729, 0xa0fcb4f5f0c32ee9 +730, 0x1e69787a387b30a +731, 0xe89a8480884263d9 +732, 0x4c02fe1f82aac874 +733, 0xb576e8a44017bee9 +734, 0x5e7b98878c6537ab +735, 0x6d291feb307f3740 +736, 0x7d00feb09e768b54 +737, 0x71bb0170d659119a +738, 0x7bb2ff7d0a61dda3 +739, 0x2c6a16824290b7f3 +740, 0xb96623628a2917ea +741, 0x14489300ff071e92 +742, 0xdedd6422224f3748 +743, 0xa6e1071c454da244 +744, 0x1c4b1edef803ffec +745, 0xa5f8e7c79d02be10 +746, 0x9b8309dddcbd21bc +747, 0x6f57e425d2808563 +748, 0xd7d49cab22729386 +749, 0xd0dab40fd019b301 +750, 0x6808b10401cda8fb +751, 0xfa51b53ceceb08b8 +752, 0xb90e4574b2745b68 +753, 0x470707ab3da1f1a2 +754, 0xbc76e852147fe684 +755, 0x82f7e418e4454b7e +756, 0x6aa5fec0a5dbb4b9 +757, 0x2695d285a10e05c2 +758, 0xd15219b5dcc6db09 +759, 0x8ece31d881c4e1e5 +760, 0x1bea39be5b09c080 +761, 0x19e1d4897394d0f8 +762, 0x8bb735c6dcade9e9 +763, 0x5df3789e52d93a64 +764, 0xcd6aae13791d95df +765, 0x188ce0105b17920a +766, 0x3fa30c09840f615e +767, 0x7c201465bc6301e4 +768, 0xa9a00e2757807982 +769, 0x122e0fc0c79782fe +770, 0xabff396bc21271b +771, 0x7d54d41d59c99fe4 +772, 0xe2d5b1393b081928 +773, 0x45165a925412ed4e +774, 0x96c945ed58ba2bab +775, 0xde05a1d6fb9ced45 +776, 0x496cad57600fe9ff +777, 0xc3846b63bfc1062c +778, 0x9055ccd5f729b1f7 +779, 0x8fa87030e7e623a4 +780, 0x7e6ee59d4fb11784 +781, 0xb5b151c0d892955e +782, 0xeeaa87699ff69dfc +783, 0xa6d485e04ce2dd71 +784, 0x69c53b89eec70119 +785, 0x3732533c7df25f53 +786, 0x275d37a0c68e7a42 +787, 0x3a88f16ac812bad8 +788, 0xb0f92536c7c763 +789, 0x27a32d261274ee83 +790, 0x3fd5ae8a771adf89 +791, 0x23feb68f4819e4f +792, 0x4d4c7be0e84aa024 +793, 0x41a80d994fc0a41c +794, 0x718321ae9282c3b3 +795, 0xd551e149c01af06c +796, 0xbcb93735c6eac744 +797, 0xe59f03655f9180f8 +798, 0x6e96a0431ed2e0cb +799, 0x5866d0755ecf3c6e +800, 0xd9f473c16bbec85f +801, 0x38b2070194506205 +802, 0x98aaa714c80a21af +803, 0xdb7853e1515cb5b +804, 0x32532dd0c0e1920b +805, 0xf5d440e12b584cfc +806, 0xe67397ec029cda3e +807, 0x2d51f19fcbc86346 +808, 0xb5e46840c44c80b0 +809, 0x6d39c237e90744be +810, 0x3535938a21e6e293 +811, 0x7b8a87d2b539e50 +812, 0xf4e74d0346ccdb48 +813, 0x1640fb85b5f11965 +814, 0x2a99ba02ff6b5ccd +815, 0x12dbbd81a6ca75ad +816, 0xff72053bbfd9490f +817, 0xf5470d1e0ff5888f +818, 0xd7d3e1ca8d79382d +819, 0xd437182225fda535 +820, 0xde44396868fad24c +821, 0xeafa4c86c0c578b4 +822, 0x788a1e34983fc51f +823, 0x396563f750981e64 +824, 0xeee9e79937487d52 +825, 0x12871390ffe443a9 +826, 0x96b07429b4a54778 +827, 0xb0506605d66bebce +828, 0x1b5878bc242f0158 +829, 0xea46c8e2d9ca3dbe +830, 0xa94a8750612bc68 +831, 0x864ccfa5796f590b +832, 0x4d1d2609563b8063 +833, 0xec62387e7f258abe +834, 0xb2726f3d37ba75b1 +835, 0x2067494d0dd41024 +836, 0xf75839382e176d99 +837, 0xf0c83dd9ed0aaf23 +838, 0xfa8a581e28780483 +839, 0xc461e40cda6d4ba4 +840, 0xaebdb6c7da47946b +841, 0xd380bbdf27718424 +842, 0xd31504078e3a9a9 +843, 0x4fc0eee024e9a5a9 +844, 0x18714e84611ae719 +845, 0x7503c0ee7ce5608c +846, 0xef1abc4a7543b398 +847, 0xd1e7ad19597d9cb5 +848, 0x77fb8e61dec1dff5 +849, 0x6d6504f8f1cd19ff +850, 0x7d7e1a6b8d21b29a +851, 0xc0504f78e1744ba0 +852, 0xbe3aefe760c2025f +853, 0xbeba2fd08acd9166 +854, 0x5c140d358435d3b9 +855, 0xc550467f426d4bb9 +856, 0xfcf1c8674b415f75 +857, 0xc81721303ee733e0 +858, 0xe4b0c096d8c54e7e +859, 0xa963e1fa39f44bc +860, 0xfc6fb6ad0317aa76 +861, 0xdf7c4217eeb378f9 +862, 0x69639f8b6c1c765e +863, 0x23d8874dfac843f4 +864, 0x323e6cfed1af5406 +865, 0xdf34a5b2df24c44f +866, 0x52c88f39e1f1017c +867, 0x9b780cb0ffd8e0ae +868, 0x17bdfe024bf483fe +869, 0x1bdc2d6b57afb0d7 +870, 0xe5cfe8cf4f301238 +871, 0x466caae45214f84b +872, 0xefa9e39d81d0f263 +873, 0xf9e330742b518177 +874, 0xea36033c02f97e71 +875, 0x37f90271cfa76be9 +876, 0x313e5ad81eb57d98 +877, 0xc0741d6410e19347 +878, 0x77567253b48ea919 +879, 0xa0b196d776905b46 +880, 0x81848e866c958c22 +881, 0x5defd26f7e313de1 +882, 0xebbf740f85d0a413 +883, 0xb43c6ca7dda9c7c3 +884, 0x3a38024f6076bce1 +885, 0xc9a4d739dd7a58d5 +886, 0x4a0036e594c30291 +887, 0xb67d467a13271850 +888, 0x26d4333f67ec5658 +889, 0x8683441959b6fca0 +890, 0xb4c3173d217788e1 +891, 0x3fca2876508b0037 +892, 0x4fd7ac0912a08d26 +893, 0x3990c299fd77d3cd +894, 0x388bfe456f0ee713 +895, 0xa17d56851d0aa9ad +896, 0xae6e173a38e92688 +897, 0xcae6f7387868f4c0 +898, 0x5deb567e87b682ed +899, 0x5bb2a3cbc6ad9aa7 +900, 0x4054518b25a4e546 +901, 0x8399534e3156fcc1 +902, 0x288ff48845b1cd34 +903, 0xc7d6f2e48f1799d0 +904, 0x968a3ed47b71e9c5 +905, 0xc06011209519bbee +906, 0xe2a80df93233bcf5 +907, 0x20b9afd489292293 +908, 0xf0ce32e84bdf040a +909, 0xbed405bc7fe1e795 +910, 0x86f7b1542f6b195e +911, 0xcbb6cb657318a436 +912, 0xcabf1276e3e6d85a +913, 0x42a331a4b5939d3c +914, 0x80cfa20e1ca1d0fa +915, 0x768bb2ab2504a2cb +916, 0x38a6f71b6865c85c +917, 0xdc4142ff4a656c94 +918, 0x91541ea1cece2095 +919, 0xbe03be2fc0073de0 +920, 0xe21d0d35ce487214 +921, 0x4681e310b4117bd7 +922, 0xf2253c6efd0ed606 +923, 0x702db3cd3ba7c127 +924, 0x8d3175ccb5e08f38 +925, 0xdafca1a22f02d177 +926, 0xb6fb797078eed6d6 +927, 0x10120f45ab02ea09 +928, 0xfd4cd6ff70fe60d6 +929, 0xaf70101012b33e44 +930, 0x6e4321ef1a47aed2 +931, 0x859676a49e1dca4f +932, 0x8065316b96ff29a0 +933, 0x44d05376ed2d0fdc +934, 0x7343def61d2425cc +935, 0x86113b555152aac5 +936, 0xba339a0e137c5ce6 +937, 0x1d2d89d9de5460d8 +938, 0x7ed9d48c61257119 +939, 0xcad2b91ab20da148 +940, 0x656377284c5e195c +941, 0x94e734e8a480a4a7 +942, 0x5bdacbc607ec7c4f +943, 0xec1241717db1ad5b +944, 0xe6eb7fbcf5b4b66b +945, 0x3512345a3554e6b6 +946, 0x58c77d926e9a528b +947, 0xf3e782be535f9b9 +948, 0x9d3b3a53ea1530a5 +949, 0x3df1eddab09a2ac2 +950, 0x86440868ee975e20 +951, 0x35e2f24867978c7 +952, 0xd3a6219dec1a447d +953, 0x4427eaeeb50643d3 +954, 0x1eac58507e33223e +955, 0x10fb299eab3112ac +956, 0xaa01a8b779062117 +957, 0x552c4559a7e5c22c +958, 0x2e10ac501d21242a +959, 0xbabf9866c8d7d061 +960, 0x94f03b79de712060 +961, 0x4a70ef01b76bf68e +962, 0xd1fcf4d2226ae986 +963, 0xcc53d27dcb2ab8bb +964, 0xe169d46e9a968cd2 +965, 0xdd3baeab560e1eb7 +966, 0x62e325462270d89 +967, 0x717dade9cf46c1ff +968, 0x229552ce0bb04970 +969, 0xa6ebda4d2eca3cbc +970, 0x80d3bd7426882137 +971, 0xfbc3243079309847 +972, 0x664f4a88f2c7bc55 +973, 0x750baa49d93df131 +974, 0x8f0a87416f41c64f +975, 0x5d01ca38b0484512 +976, 0x743fdfbdd79e82f3 +977, 0x69c3c2f9296fecaf +978, 0x3d945260849578e7 +979, 0x21aadd4d1956a540 +980, 0x17a2d7868afbf606 +981, 0xa945ff7af593e961 +982, 0x499c7abc8df892fc +983, 0x599c1a937b547e43 +984, 0xc6f0c1d6eec5cf12 +985, 0x425c576116b8bf5d +986, 0x5a9d64a33ba615a6 +987, 0x85f1341ef79fc27f +988, 0x75c151fd5787305a +989, 0xf56789cbc4c1a1ed +990, 0x1d547a0b47eab748 +991, 0xccc539d7a777e60c +992, 0x39d3177b7f18e15e +993, 0x9d9911afa8441757 +994, 0xe163b0cae65e074c +995, 0xb75ff4c843626bed +996, 0x696089f87bf020b5 +997, 0x78c5c7971b74ce1e +998, 0x2ed5aa6e489c3684 +999, 0xaf1b049e483011c3 diff --git a/_randomgen/randomgen/tests/data/xoshiro256starstar-testset-2.csv b/_randomgen/randomgen/tests/data/xoshiro256starstar-testset-2.csv new file mode 100644 index 000000000000..b688fcb2a551 --- /dev/null +++ b/_randomgen/randomgen/tests/data/xoshiro256starstar-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 0x0 +0, 0x99ec5f36cb75f2b4 +1, 0xbf6e1f784956452a +2, 0x1a5f849d4933e6e0 +3, 0x6aa594f1262d2d2c +4, 0xbba5ad4a1f842e59 +5, 0xffef8375d9ebcaca +6, 0x6c160deed2f54c98 +7, 0x8920ad648fc30a3f +8, 0xdb032c0ba7539731 +9, 0xeb3a475a3e749a3d +10, 0x1d42993fa43f2a54 +11, 0x11361bf526a14bb5 +12, 0x1b4f07a5ab3d8e9c +13, 0xa7a3257f6986db7f +14, 0x7efdaa95605dfc9c +15, 0x4bde97c0a78eaab8 +16, 0xb455eac43518666c +17, 0x304dbf6c06730690 +18, 0x8cbe7776598a798c +19, 0xecbdf7ffcd727e5 +20, 0x4ff52157533fe270 +21, 0x7e61475b87242f2e +22, 0x52558c68a9316824 +23, 0xa0bd00c592471176 +24, 0xfc9b83a3a0c63b9e +25, 0x4d786c0f0a8b88ef +26, 0xa52473c4f62f2338 +27, 0xe9dc0037db25d6d9 +28, 0xfce5eba9d25094c3 +29, 0xe3dbe61ee2d64b51 +30, 0x23f62e432b1272df +31, 0x4ac7443a342c4913 +32, 0xc31cf1a9658c1991 +33, 0x290c97ffce918b1d +34, 0xf54455e02e90636a +35, 0xf57745758bb8f33f +36, 0xe5e1b685122823d9 +37, 0x2c16cde0fd8097ec +38, 0x3cdebc44a5bc1936 +39, 0x6833bafa723c2dbd +40, 0xb6fa6c4ba1d3d39e +41, 0xe5b932b656c2edc3 +42, 0x9cf0b6121615c9f +43, 0x214e25d57fc636d5 +44, 0xcf3d1721806e2537 +45, 0xcf796fc6335ddc02 +46, 0x353c8b86489b0322 +47, 0xfc4865822547b6aa +48, 0xe8c93d84ee8b3f8c +49, 0xd1b42120a323f2d6 +50, 0xa73a11d247ff36b2 +51, 0xae42236958bba58c +52, 0xb622679e2affcf3a +53, 0xcc3bab0060f645f4 +54, 0x2e01e45c78f0daa7 +55, 0x8566c5f16be948a +56, 0x73beac2187e1f640 +57, 0x8e903d752c1b5d6e +58, 0x5b34681094d7511d +59, 0x70ebad382047f5c1 +60, 0xeae5ca1448d4e9cc +61, 0x3d2d62775b631bd5 +62, 0x8cb72ebc5b4f7dc3 +63, 0x99c2939ea690a80 +64, 0xf9d3061a3006c84b +65, 0xd0872c394d734a5f +66, 0xbf768c2fb70d5c2a +67, 0x9b5a7e27e4c57259 +68, 0x8e00b050a0489404 +69, 0x72ae4545fe9d40f3 +70, 0x2bdcc8dcb50cf5a +71, 0x7b20239fe07cd664 +72, 0x37b037a8ea138f13 +73, 0xa52f51f9e9cd65b0 +74, 0x5ee0b72fd581557a +75, 0x527ebb9ac92c6fa7 +76, 0xb64f03fc892955da +77, 0x972c4feb529a9045 +78, 0xa5ee146b2461a795 +79, 0xaaef1049a5bb9b07 +80, 0xbcf5f38ab6cfe9 +81, 0x16398fd1538acdd +82, 0x8a0744fd7315cae2 +83, 0xa4bf1e39de6657a6 +84, 0x685247449d0de2ef +85, 0xa48d5c8c364fb1dd +86, 0x7fbcaafb1f2b65b5 +87, 0x96f0967f55ddec48 +88, 0x30d43cfe4a788a1a +89, 0xf7b15bed8038c711 +90, 0x8db82a6db9261a2a +91, 0x94eb6a77a00e5b2e +92, 0x3e19490dbfd221a4 +93, 0x9644e15b5d0a6b54 +94, 0xe235ca3fdaeca1a7 +95, 0x2db8e0001ea7c79e +96, 0x1d82fb1d7674fc75 +97, 0x65039b3b4805404d +98, 0xd73a9fc3e975791b +99, 0x3cb72d021fba219c +100, 0x134f43cf382ea87a +101, 0x32806c8d66cf621f +102, 0xaaddf99cd62686db +103, 0x1b3e5fe6476a54d8 +104, 0xd0a2a5e803c27068 +105, 0xacfb9437a3b64c17 +106, 0x514a55b2ce7f4982 +107, 0xe0b9ee39938c909 +108, 0x66d449a98f1052d2 +109, 0x639a3b248f7b37e8 +110, 0xf0ef1ed4a65619a5 +111, 0xf010ee5ad7e74a11 +112, 0x3fbfb63d884eca59 +113, 0xdbed473e4efad8bb +114, 0x49c9bb8f88e373e4 +115, 0x251f496458b6360c +116, 0xd91a4850fddb72cb +117, 0x610f58fad3c217c1 +118, 0xbcb05e51100ad235 +119, 0xdebf8d6ccb4a94db +120, 0x297499be7e8fe7cb +121, 0xade854104ecd6600 +122, 0xe8924c68f96b97ba +123, 0xea4332df583b4cdf +124, 0x3c5950e1726a6684 +125, 0xe78baf12ad096b30 +126, 0x130e9517756e2908 +127, 0x2519a50a14a2bdaa +128, 0x548b96fa23c310bb +129, 0x689bea6fcb7a7b18 +130, 0xe500c168143be7b8 +131, 0x6615695d45714ed3 +132, 0xf58a87a6e82fcbdf +133, 0x77d9730cc4ebf311 +134, 0x9b3a449299c50530 +135, 0xfb5d93b0b60f022b +136, 0x31bb49a47b615ca7 +137, 0x5be9713f591556b +138, 0xec54b51a1185183c +139, 0x4dca5482711b4718 +140, 0x4cbe1b130e66cc8d +141, 0xe5ab874359671f11 +142, 0xadb342dee0eaaae5 +143, 0x7a9f5af1a3e89a24 +144, 0x83656d5ed37512b6 +145, 0xced3c2b8c231d286 +146, 0x575139132aafc520 +147, 0x2fc986b84ae150d0 +148, 0xf1e782d83e9bc699 +149, 0x1855c5fab454eb48 +150, 0x8c397cc4dfbdac0 +151, 0xca53a1df39daca62 +152, 0x8df17bc285c6c2d4 +153, 0xcc409e9c492ef29e +154, 0xc6609bf8eaeaf753 +155, 0x4f0e6d330e6647cc +156, 0x32a255fd34f2b58f +157, 0x26352ca3cc29b31d +158, 0x695c88b11a7e549c +159, 0xd91ec977523e201a +160, 0xd8e5a42958325ba0 +161, 0x481223fcbeec1f35 +162, 0x601cfbb9aad67313 +163, 0xfdcac7d3cb1091ef +164, 0x7fdc76c0a076d6fd +165, 0x394266448a75927c +166, 0x63243918d6fc4774 +167, 0x6ccfae907e52cc2e +168, 0xd4ce6176046ae4a2 +169, 0xa9818d710c31aa3 +170, 0xb8e803b82ca561b9 +171, 0x620b905a8425a1cd +172, 0x2443dea6bd2bd617 +173, 0x447fd94cd80faf23 +174, 0xd4f30e2a5c7767f2 +175, 0x11298de19077eccf +176, 0x35154fb0148fa69a +177, 0xed42b9c24ebc4d19 +178, 0x422724f98f4c3a1b +179, 0xd81cc933854afa52 +180, 0x54e2a03657411d03 +181, 0x8f12d5fcccdafb4a +182, 0xd91ebb398426414b +183, 0xb5555a96d9221341 +184, 0x6073189316d5f1f +185, 0x8a488d8d9c40366a +186, 0x109f57d19c71381a +187, 0x4e043cb3d78b4fdb +188, 0xa541464ecc30b27d +189, 0x15c2bf30d64900 +190, 0xa65cd77083ee4f66 +191, 0x1b98efd8729f2197 +192, 0xe954f9556e7cd0db +193, 0xb775e8ed94ede03b +194, 0xc3ef1f33db52eb8a +195, 0x21eec6afc3a045bc +196, 0x3d09338405d07ee1 +197, 0x501d08ca80daedff +198, 0x855f69bea1e262cc +199, 0xc88e6c97b5071d6c +200, 0xad42750a0f79e135 +201, 0x19171caa21061657 +202, 0xa337869a65c8d18f +203, 0xfb0cfae4b3cd24a3 +204, 0x43140ea8817faf71 +205, 0x895807fdf0d19712 +206, 0xb0c14c560e178c2d +207, 0xc47b4af3c3bb4789 +208, 0x60cafedf6696b7a2 +209, 0xf658b394f9697989 +210, 0x45d29b40a0ca3f86 +211, 0xb881cbe06cf6c2e3 +212, 0x2f045611c5d42ecf +213, 0xf011ca853c07b2a6 +214, 0xe078befb5dffff49 +215, 0xc2d1b7728fbc0ef7 +216, 0xb3ee6d8225161ee6 +217, 0x82e51268e2c152e0 +218, 0x6d79b320e5c33a15 +219, 0x1be56b3144ecab7c +220, 0x8e341dd781b3dffc +221, 0x50310327c0b03198 +222, 0x22ab06d620970b0e +223, 0x6b542de2f5625eb +224, 0xaacc9d5de070b881 +225, 0x21581365a4307e9c +226, 0x1a09b3443a155c66 +227, 0x2941d8614648c4cc +228, 0xbc4175b682a7f884 +229, 0x9cc92ed166c9cf23 +230, 0xc765ebe7eb3911b2 +231, 0x2d169ff7cc4369ee +232, 0xa3070da6835f0a0c +233, 0x827d253009c5d376 +234, 0xf23489deaf0450f2 +235, 0xc5e5b1ba6d4550ec +236, 0xa42ce77e33e206a3 +237, 0xc096f2576edc6a17 +238, 0xc4fa32113d4200d +239, 0x9bf6baf90bdf4ac +240, 0x47dc4d9bb5714a26 +241, 0xd58f0327551e948e +242, 0x9b1926b404a93ae9 +243, 0x6034442c56b4a50f +244, 0xe29e9c6881a89f9b +245, 0x79e49c426f3d4f3f +246, 0x75ba2077148ff864 +247, 0xf5dec8c46426e9c3 +248, 0x6affed5e72eacc9e +249, 0x1e4dcd0029679920 +250, 0x6470439685e44054 +251, 0xb156aa42e8413254 +252, 0xf6529f57a03df828 +253, 0xd706ceb3bd1c5f22 +254, 0xf8a3b615eaf44c9f +255, 0xfb33215a60fc88a +256, 0x53b93d040f72e76f +257, 0x4f67360a5c6ed447 +258, 0x600e87c4cbe6910f +259, 0x729ea44a3706a389 +260, 0x924cbabe379237ec +261, 0x618aeada6735f6cf +262, 0x12b4a8b32ecefaef +263, 0x7b129ddb43b182c +264, 0xd5466dc1e1de15cb +265, 0xc2e35a196a6e1efc +266, 0x8cdbacc1fc81c786 +267, 0x28b96b91b1ca9672 +268, 0x10e2a0174fc6f81c +269, 0x35ae5c9a74f2e2d8 +270, 0xc18f6c052b7f28e4 +271, 0x4f0abb08fa0bc2d1 +272, 0x84ab0e1b7c7cd062 +273, 0x29dca86fd5f5927d +274, 0x50fb63fccba90590 +275, 0xb7a60466af0de98c +276, 0x47baf40463bbd343 +277, 0xc72942184061bb8a +278, 0x2d55077237a2ce6e +279, 0x2f6b743bc35768e7 +280, 0x96975e80bfd6f74e +281, 0x77f334f2537aba60 +282, 0x8364264d2947b429 +283, 0x7e62c258f591189f +284, 0xe1a0962ad2d4f7ea +285, 0xf7a81d56b651d434 +286, 0xcbb9abcb6ec96876 +287, 0x7028c3ceffdccec1 +288, 0xa0049e182130928a +289, 0x79dab180c238f06a +290, 0x1eb3c704ecfa28db +291, 0xf9db38cf45524135 +292, 0xbf8f3bccec0609a3 +293, 0x5f0f2a25bb3ed38e +294, 0xe365cff62ec9287f +295, 0x9f5481118acd2a76 +296, 0x99296bb12e697f0a +297, 0x76aaf656bbbf9067 +298, 0x7d81ce20bb4461cb +299, 0xefb436add3cace0f +300, 0xf3ba4a29ed722849 +301, 0xc4cde39ff82317d +302, 0xad2bc44d417453af +303, 0xb36a704f170f7edd +304, 0xcdf268d6b5e2b5fb +305, 0x91aed4730adf51f2 +306, 0xeb2a37825e8a3de +307, 0xe79d586186766a28 +308, 0xc8bc6d8a5660356c +309, 0xafeeee51b23f4a5e +310, 0xfea1ecb5f9b17114 +311, 0xf0882ad449c3a225 +312, 0x8c0d387e9b4bbd68 +313, 0x39f2c8fdbdd00e8f +314, 0x830705f2260c2ef2 +315, 0x9bff6be123cc50bf +316, 0x99e33829b97434e4 +317, 0x6059a38e8957661f +318, 0xa77e6d06957108cf +319, 0x1e719fd3e756823 +320, 0x4564dd6be166e176 +321, 0x6f6a8c540e054563 +322, 0xc800237b21dc0e2c +323, 0xc6c3f2586f8d3062 +324, 0x85c469664e405a28 +325, 0xf5771300e8da6169 +326, 0x5f79c23a5e6807e2 +327, 0x593bbb0ce26b72b1 +328, 0x7e2e976e8309dff5 +329, 0xa543c50aecd30c5e +330, 0x7b71758289d403bc +331, 0x4a01dbff8cf37014 +332, 0xf1dee5472a53176f +333, 0xd82c78d69f2bef7a +334, 0xb63903647ded6604 +335, 0xe695634a32b0d1fe +336, 0xf89cec17a9792c77 +337, 0xcbb131921e8fad4d +338, 0x9425521c6c62076d +339, 0x18fa2dc92d99a3bc +340, 0x5d84f4a98055086f +341, 0xcaa5980ecaba579 +342, 0x2fd8a209612e2b2 +343, 0x1be8b333fae80866 +344, 0x99cd4808ba7c60f1 +345, 0x107242d94ac9d491 +346, 0x873838793d69cb0d +347, 0xce87b21b6eeea0a5 +348, 0x6831420da8fb877c +349, 0x1f51fe6670631366 +350, 0x9c093d89ef323dda +351, 0x3384d45cc9aec1b9 +352, 0x144970e9a0e6f741 +353, 0x3d8deffd6db78721 +354, 0x272f876c2821800a +355, 0x66eede1f8eb0bba9 +356, 0x6b85a48c6fd8dfac +357, 0xdeed765c9682da9 +358, 0x5956688ac942fe9c +359, 0x408147c1fe103dba +360, 0x8a5545b07bd7d483 +361, 0x2c8379adb00ea5c2 +362, 0xb9f96c9acd18c563 +363, 0x18e6e515e8c11ad3 +364, 0xf4c78395a36665f3 +365, 0x9319b999d50f42f6 +366, 0x1d9e89e8d5e22c8e +367, 0x7df15c14581535d2 +368, 0x214e3cf405b8b36f +369, 0xe11a168e3a824980 +370, 0x74998ef104966497 +371, 0xd6fc353bdca37cef +372, 0x48a55220b4fa6e1a +373, 0xbe2c7cfc7c08dc03 +374, 0x26c837223b6cfd46 +375, 0x22163b501aed055d +376, 0x946537d01e261110 +377, 0x39b4c0b78a79402c +378, 0xa68b2d66140ef79e +379, 0x8dc84a722b56fd9d +380, 0x6f32f10229bd5c83 +381, 0x722074979bca28dc +382, 0xd942d9911e43d52 +383, 0xf720ad0e5adada4a +384, 0x69fe38d6baa562de +385, 0x29a7488cb00fbc49 +386, 0x4d40dbe4a23b6c94 +387, 0x6bb39808bbae9d62 +388, 0x8b80231a7369e915 +389, 0x14bf8e755f80b050 +390, 0xf19bb00604d00336 +391, 0x552db8387eea31a7 +392, 0xe9ec067b59dd95e4 +393, 0x3d71f663886c520 +394, 0x97bb54095cd331e4 +395, 0xea3e829f0695cfc7 +396, 0xa93188e41583162f +397, 0xeeaabd3e3df2f07c +398, 0x291f70992ab1c5b5 +399, 0x55183a8b5857a080 +400, 0x7df148caba2c4978 +401, 0x84f178764bffc05e +402, 0x5acea77fb3139b5e +403, 0xcf57693ff3aa5f39 +404, 0xa0867abf8c89ce6 +405, 0x597f8192569e2971 +406, 0xf90a8e47c1271e18 +407, 0xbe5346e3fd0c12a4 +408, 0x524aeaa307d4b03b +409, 0xef3d68937d8270c8 +410, 0x3e73d03007156d55 +411, 0x94cc96dfeb586897 +412, 0x14e7a22da35e8923 +413, 0xca6ecc61d3cea9bd +414, 0x6044eca5a760cfb6 +415, 0xf4ed4f4f21933f13 +416, 0x99b923d7f9925de3 +417, 0x394b054ab147ae41 +418, 0x9afb74bbca1dcec6 +419, 0x830b9ee9e52b9234 +420, 0x83712e27c87cc4c6 +421, 0x7f025017de598df8 +422, 0xb3ea4ab92495a788 +423, 0x602a7c66750a2047 +424, 0xa15ca212f5002047 +425, 0x8aa5d8a19b1b7efb +426, 0x2852eaeb46dd9d21 +427, 0x605f261b8b77d3ee +428, 0xeb27c54d4359e1fc +429, 0x77e4aa530fbb27c8 +430, 0xaf06ddf2d74745bc +431, 0xe88964e4b8d79ede +432, 0x2192553c0ce6a4d4 +433, 0x90997c5c0cf3b6ae +434, 0x1153fc6436d48bb2 +435, 0x1703c60eb24cf506 +436, 0x116d8f4e35d51cbc +437, 0x5045a10f0131f6d0 +438, 0x1fbb76ef3c622e03 +439, 0x7d33bb57dcf79365 +440, 0x1ef362b02c379673 +441, 0xdf7a4a6801ca903a +442, 0xc784df93dcbb07f1 +443, 0xbc566896f2d86db9 +444, 0x72a169884d76aa42 +445, 0xcb65ab4ad4c8a6ba +446, 0xd810c9a3ee62ed3d +447, 0x7652322c4f6520d6 +448, 0x3ad4dc2bd6e4c8dd +449, 0xb2269d6e73a22c6c +450, 0xcbfdf90c34925001 +451, 0x2bb66613fbf8044 +452, 0xae9c53e815bc69d1 +453, 0x452d886b5a7407ae +454, 0xa7f3f05dfb111951 +455, 0xbe05cb088f4dc330 +456, 0x9b740a460b6ed662 +457, 0xd77a324b60f8c74 +458, 0x60ae94f69dce3f29 +459, 0xd04859db7833712a +460, 0xb90030c4a70c588a +461, 0x25dd21f6ac7df8d7 +462, 0x162154fcf4832a15 +463, 0x15947a2bbf844bae +464, 0xa20559f3a662a753 +465, 0x6dce918dd48cad0b +466, 0x32c5a086331216f4 +467, 0x3a683208ae4f86c4 +468, 0x1ecc2982d1720167 +469, 0x2b3017d572f5c7e7 +470, 0xd7861e549dc1fdcf +471, 0xcead2c572db0b00d +472, 0xbbb4afca7e873a92 +473, 0xada92286d14a0d26 +474, 0x7af00766c03cfd0d +475, 0x2353443fbef8f013 +476, 0x35291d9ea26217d9 +477, 0x9d907261f3f7ea54 +478, 0x6f11649f6c3b69fd +479, 0x36d9e3bf31b6b209 +480, 0x5f420540094e6bb9 +481, 0x980dc001315d9d33 +482, 0x1e6023baca982809 +483, 0x28441f8357769aa6 +484, 0x4acebf5fd0e84d43 +485, 0x9991e19a0f1ffddb +486, 0xea4f7c944b325d2a +487, 0x9e44a24cb37572c8 +488, 0x2949063600779260 +489, 0x313e58e1433ffa40 +490, 0x6eea07e56604152e +491, 0x47dee53a41fe61c7 +492, 0x21e6dc482e5df531 +493, 0x4c43131087191e79 +494, 0xb378e632ee28fb31 +495, 0xc1b106afa1c14816 +496, 0xba150956e0c630bb +497, 0xc5b64d8037dbaab6 +498, 0x47325510456ecc3 +499, 0x61a6f425ff2b555 +500, 0xabb9fcb3865a8ce0 +501, 0x7eaf52f3aa10b66f +502, 0xd91cf6b8600c7115 +503, 0x18eb54dcfb1b20fe +504, 0xc8911ada29a3162e +505, 0x6cb29138cb1ac68a +506, 0x4d0e9884ade85482 +507, 0x4cad40d37b3ec8f7 +508, 0x9467d7a7b34753a6 +509, 0x45f84f5e5a26175a +510, 0xd8753f7613d5ce77 +511, 0x86d400a246e8d128 +512, 0xcb8946c9f2c10785 +513, 0x89cb7c5c5ab35ff3 +514, 0x7bb60eaebc69a3ad +515, 0x534f554712b34d6a +516, 0x5667fa5c9b731343 +517, 0xeadb76ebcdeb49b +518, 0x3485b0afe8caa42e +519, 0xc78c543b4603f643 +520, 0xa8f3fc1217b9b77c +521, 0x44ff6333a229924d +522, 0x426e31b858cfcbd1 +523, 0xed5964b45b66718c +524, 0xac18d6cbcbca89ee +525, 0xc78a8bf4beffcb0e +526, 0xbd0d95b77da79de9 +527, 0xac7b69c368ad88ff +528, 0xbb729daeb9f32b7d +529, 0x6d5dcb59284675b +530, 0x4aa9af065367853c +531, 0x40de557a4730f8dc +532, 0x6b35765ddcb83237 +533, 0x7c4cdacf0801f9aa +534, 0xcd723c55ccc75d2f +535, 0x86c67f52807c3f64 +536, 0xc597a5d9141cf5eb +537, 0x6c50d3307da89da9 +538, 0xb2e259cf10ef27ff +539, 0xcf6862f7235a11e3 +540, 0xb60e07d1d6190673 +541, 0x69de7facea0c2233 +542, 0x19e548a3950a2d1b +543, 0x6028bcf0501a1d75 +544, 0xbe060ad84380878a +545, 0x425f528fa11f5584 +546, 0xeb64fdc71b8a0369 +547, 0xdb1d4fd9af7fc48 +548, 0xc32ea3df9267e071 +549, 0x9f0b4d409a6b7db6 +550, 0xe8e1ccce740c6369 +551, 0x8d0939433ef9c005 +552, 0x7b1a1969142d70f7 +553, 0xbe055803167b4dd9 +554, 0x3d525b7f29e2a20f +555, 0x2b58ca2bf659dfcc +556, 0x1884346d743d5753 +557, 0x3e5e6a992abcc639 +558, 0x334bed0210a5a1b9 +559, 0x545bd4a1c6a6ea3a +560, 0xdc1d84e28f8b4ff0 +561, 0xf3608d9fea1e61d +562, 0x639fadfda3d29b81 +563, 0x1a4195ffb607cd4d +564, 0x823bdad2efff1975 +565, 0x5fe15698d33ad156 +566, 0x961e7fcba86b8dfa +567, 0x9b7536cd3c368430 +568, 0xf9b9c01121a82eaf +569, 0xa3f39bdf6f8668f4 +570, 0x100ae93ca508d02e +571, 0x88de050245f0f9b2 +572, 0x4ca1e3a7fce0a942 +573, 0xce0366d47e60adce +574, 0x3f00fa3b552ef6c4 +575, 0x718ca18c97de55ec +576, 0x2705ca3caa5f047b +577, 0x8e9a4530bbabc87e +578, 0x57f73f76c2365c1f +579, 0x5783c7e50c89e813 +580, 0xeb0899277d5a0925 +581, 0xdc28a57fafb04818 +582, 0x7cc97832d2b3509e +583, 0xe937c3407bc84cdb +584, 0xaa2714014f14802f +585, 0xaa0b844baf434250 +586, 0x98f6097049cb2931 +587, 0x65d93055db2280e2 +588, 0x401e59aa74e005c4 +589, 0x8540018c086c5678 +590, 0x1ebd2b7c3093183a +591, 0xb015ff173910186c +592, 0x628d0a7cdcb5ee78 +593, 0xe6bcce512cb94fba +594, 0xf2112d66f4ad825e +595, 0x143ca3c833cc6119 +596, 0x141f17377db25eda +597, 0x2b5abd96ffa1cbff +598, 0xffbc3baec2fce0ae +599, 0xfb7ef6be757ecaf +600, 0xdec0e0b34488795e +601, 0x4b0cb9bfd1759241 +602, 0xc1ec90140a15b4e +603, 0xfc16386442e70156 +604, 0xe3f12f2adf688d91 +605, 0xd53b2d7bea9c8380 +606, 0x81cc446202a2ed5c +607, 0xe70e3ad34c0b8ea7 +608, 0x5f33526009e7fab2 +609, 0x6e33d20305b8c75c +610, 0xd6d534dd9461ac91 +611, 0x40cf8974d7c931ef +612, 0xb051886f44a85f34 +613, 0xbee99cf63e9e4ec6 +614, 0x80d5c210e7e8f3b5 +615, 0x182817a277213ba5 +616, 0xb57e1fcc3fa01e29 +617, 0x21ef9e484821c685 +618, 0x40e0bdb94b52f6b8 +619, 0x3993c9973c999499 +620, 0x324fe4cdacd0c7f8 +621, 0x2f276173f8434ce3 +622, 0x16f1f99b426e931 +623, 0xed2148eb554f6965 +624, 0x2f164f3156c8ab9a +625, 0x8fa66f8b7bdd6fbb +626, 0xa7facbbc6906343e +627, 0x4903fc405e661d8f +628, 0xd5e01a117658e004 +629, 0x327b0a3517b49e0d +630, 0xaa7f3a3a33033899 +631, 0x8e978760d337249e +632, 0xe4706aca37516d8b +633, 0xd3cb6f75b94f094f +634, 0xd2b9ab9715999627 +635, 0x807694f77b219f34 +636, 0x33b79cb95dc4bc0c +637, 0xc50b1dd63a993db +638, 0xfee37af82faaec9b +639, 0x9fdacc70effcef2a +640, 0x1bf998ee028c7d6 +641, 0xfbdff299a6531fef +642, 0xa108675116536b22 +643, 0x1527b4dc58905dce +644, 0xa7707694303577ce +645, 0x9b13fbc46e340e5e +646, 0xd020c010ec0baa5b +647, 0x384c228b30f40579 +648, 0xdc323bc7fdd5453b +649, 0x4011efb021d86d0e +650, 0x73540e72fd3d5c1a +651, 0x9584873c3d070ab8 +652, 0x5b49b14248e8bf2a +653, 0x9ac40d57d39d5919 +654, 0xe0c05768df113539 +655, 0x139cd4f88a7574b7 +656, 0xb9b32474195fd2cc +657, 0x77da8950d9fb2c98 +658, 0xdff0beffbdaa4b7 +659, 0x7d7c9554dc45fa9c +660, 0x105c2efbf8116c04 +661, 0xe62b22435244a315 +662, 0x59a1e2fe06fd3544 +663, 0x328af98625a31053 +664, 0x7e03a7ec81d1a078 +665, 0x94fe2cf6653e116c +666, 0x333fc9ecf8a43b6c +667, 0xb3828218cd24f83a +668, 0x9c3fd7d848f20cb1 +669, 0x92ce295ca15436f4 +670, 0x6f088c41b55b1c1 +671, 0x57392e60bd643a69 +672, 0x6e02f429d6a11733 +673, 0x2ebecbf5bd43e0ca +674, 0x8dd7afdc5552894 +675, 0x2114803fc6503fcd +676, 0x38b1873ed0ca3e65 +677, 0xf32c628f60a36bf5 +678, 0x8552202e20fb7342 +679, 0x4741fe855aa0336 +680, 0xca4d638854de9454 +681, 0x183078fda5d360cd +682, 0x6ae60d39e68650d8 +683, 0xfd0a1e80aa46b9f0 +684, 0xdc14a1d6b0901901 +685, 0xe54df01d09b44bb8 +686, 0x309de938e8d717bb +687, 0xa5a2a2e49b9c36fb +688, 0xb38be8c575c56063 +689, 0x770e5929cffdf3e2 +690, 0xcee13e2c47cf9f56 +691, 0xdfc2db4af23da4a8 +692, 0xe1c7dcefa31d46ba +693, 0x350e999c00e252cc +694, 0xaaffdb6ca58b7dfc +695, 0x313d23d88402948e +696, 0xc3ac1498a730309 +697, 0x69350ea02740c143 +698, 0xec0d5c624376e45b +699, 0x9b49e00d551bea96 +700, 0xe6427840614e80e2 +701, 0xea27953175e05f6d +702, 0xa2861b02743e8d50 +703, 0x35b2fbf59ddfe5ca +704, 0xf25726ec3bdfbdd9 +705, 0x71aa4383b0aa4630 +706, 0x4cf3f7708d98f205 +707, 0xa6e0108f77f1318 +708, 0xcaf0b81e3222bd69 +709, 0x6b18e84e511d1b43 +710, 0x2a53e20b2f706858 +711, 0xe14599cf85db7644 +712, 0xb7a31525aecbbf69 +713, 0xfce7e9b5211df2e9 +714, 0x3f71617fc291625a +715, 0x6164e5c8ede33272 +716, 0x43a0878da9fba4f3 +717, 0x491992fb5ce344d3 +718, 0x204b93918277c357 +719, 0x31189377f32f958c +720, 0xa8522eef63ec4e04 +721, 0x52cb2d449d63dae1 +722, 0xd3ab20f38e44122f +723, 0x9738796a2cf5f72e +724, 0x61335538636be0f2 +725, 0x4dbd8fd3e18d9368 +726, 0xc4d395b525170e36 +727, 0x363d2b24bcb72ea3 +728, 0xfcedc59fa0ac0b2f +729, 0xa00cfc5984f4c62b +730, 0xaf0ca1028edd76ba +731, 0x4fdf988297f27aec +732, 0x891a876ecfe4a5d +733, 0xb638f6971c14c255 +734, 0xff63c7ca4d499307 +735, 0x1ea43f18f530449 +736, 0xdbed5a3109ff48e6 +737, 0x2b01c0495e6edab7 +738, 0x87c1b49da18fb9b8 +739, 0x79356a301557c23e +740, 0x3d83db604937cb9 +741, 0xda4471e873ed75ae +742, 0x7a9bff590c3ea65a +743, 0x63ed127445a08bec +744, 0xaa232e05b3fda15f +745, 0x643873aa525504f4 +746, 0xfa708f34ec5c9692 +747, 0x4817b5bfefae32b7 +748, 0x5c7c79edec1297bf +749, 0xf06513dfd2d4a290 +750, 0x7f0cd3ca9c36631d +751, 0xdebf1b00e7838d3a +752, 0xe46004c03a6468 +753, 0x6b1ee341cf3319c5 +754, 0x765793cd734155d8 +755, 0xddc037ee2976777b +756, 0x7d30119e994c6d06 +757, 0x372937236b1f1f03 +758, 0xbb2aa1c9ed2b0dc0 +759, 0xd0962de2eab2b6d7 +760, 0x7f80047fbd8ee81 +761, 0xab546293b8136f47 +762, 0x71b74ffd91794bc +763, 0x3fc7c2e20a88d11b +764, 0xedbbba9528be628c +765, 0x4c29f32b97788b8 +766, 0xe721ed4b5dfb4aac +767, 0xf1877d8e4eb87386 +768, 0xf399f60aa3ffdcab +769, 0x73c7f48a0571873d +770, 0x89a1c8b247a63fc1 +771, 0xb3f3a37f25f0eb9f +772, 0x24dc12bfb6030b32 +773, 0xd070cbfd0e221c15 +774, 0x47dd6c8f9e3ec6c5 +775, 0x18b5e8a79e8c2717 +776, 0x46762bb85de44be0 +777, 0x4aed493495d044dd +778, 0xc70422a4f09c5594 +779, 0x128787d3470d0a3a +780, 0xf6a925f9e15a22a5 +781, 0x86e93253485db4a4 +782, 0x5023f2e2dd23e974 +783, 0xbdb6aa877c3fdde +784, 0xa0e3237b79a5b74c +785, 0x1eb41a88cfb42b8a +786, 0x49a511f7a0a022a8 +787, 0x85596ed41f1986ac +788, 0x5e572dac0265d4c4 +789, 0xf573b46d65cac12c +790, 0x33427b16cca1ac0f +791, 0x8d4d024f8bde011c +792, 0x91dddd48b91c52da +793, 0xbc5b67a1104d4c2e +794, 0x104e90822e17122a +795, 0x8be8c4e394ce3a1f +796, 0x581426b9c905f36b +797, 0x2666efb9cac21f5d +798, 0xbf8d3e5f295060d1 +799, 0xa04598c9d6e237dc +800, 0xa9fbf5516c7b8911 +801, 0x4c6ec7e0401140f6 +802, 0xb50cc45e1895ff0b +803, 0x453c3801b4bbf75d +804, 0xde80964dde83a7ad +805, 0x1e17250043629e63 +806, 0x84d3aac71f95b6e2 +807, 0x38176666a55a3fd3 +808, 0x6433ac841c48a95e +809, 0x5ba64539f33f48a +810, 0x48e5e074f832729 +811, 0x3d1fb01607adc32e +812, 0x63b22681ceb343af +813, 0x868b07d09e57b86b +814, 0xf98212b744a71fca +815, 0x797843f3fd5e0ef5 +816, 0x6355bb33b59c84e3 +817, 0x6a6a1203c7944f31 +818, 0x177a4be397cbf761 +819, 0xea8fb29d82135b94 +820, 0x689c505eed27c67f +821, 0x50cf765dcfd4e619 +822, 0x948e20aaaeb69e93 +823, 0x660761db84df481c +824, 0xac2c2e1ebaa60049 +825, 0x81f9a054209afa66 +826, 0x66ba9ec387a82b65 +827, 0xfd602aca17e4932b +828, 0xa4aac8d6b22f5705 +829, 0x994f7b582d826f84 +830, 0x9312d16bbe890581 +831, 0x3079b18f5f44e9bc +832, 0x8ef5489a07ee6327 +833, 0x6c9f0fc8ecd29e94 +834, 0x7c603b09eafe66a3 +835, 0xc084c72299ff49c9 +836, 0x10459931d6387460 +837, 0x97908e3a98efa125 +838, 0xd7c84c45ecc2531f +839, 0x90c7eb8b1c222f5f +840, 0x74781389c601e45c +841, 0x176e7351d5f5489a +842, 0xa8d555a9197d890d +843, 0xdf3035da9ec119a7 +844, 0xf2cfdd14cc4b7db6 +845, 0x70aed924a5a1fdc0 +846, 0x4b993be0711bc5f2 +847, 0xb712037cce51b6fd +848, 0x97ca679baabf594f +849, 0xde014850ea7b8e93 +850, 0x39be8272136c2a28 +851, 0xdd6ce923c7574ba2 +852, 0xb999537b19fc106e +853, 0x3e421eaf2d0ae00c +854, 0x3ee73eab1c009f68 +855, 0xb6c3187e644c0ec6 +856, 0x32375e8c4fd12e29 +857, 0xacc6dde27d3ab697 +858, 0xd0c6da152a9d13dc +859, 0x2d93991d56d475b1 +860, 0x91f676a136ea942e +861, 0xdba3c630477ef627 +862, 0x9832442c2743f71d +863, 0x327f4b8d08f42ad6 +864, 0xb11d32b9aa369c95 +865, 0x8f3b53aa390b4e05 +866, 0xdd2b5c796526856 +867, 0x5f4a6d26e7266e74 +868, 0x92fc04aa4519deb5 +869, 0xaf5d104350902604 +870, 0xe92ee9d9eb83d48e +871, 0x92e49c24b74d10c1 +872, 0xbbcb775e1df3dd9f +873, 0xa778bc4153b74d87 +874, 0x2c5cb1cb460778d +875, 0x204b96da5ca032a3 +876, 0xf8ed00512b2c8054 +877, 0xecea085421d30bd5 +878, 0x9b9b2f6891954ee0 +879, 0x210f39a3b60388e2 +880, 0x71cf1d4f49716e96 +881, 0x831f11200be69b03 +882, 0x47cf8470f8e9f115 +883, 0xb0b9621c996452dd +884, 0xf5511dede5b32628 +885, 0xd48b9e4296cd4180 +886, 0x6ab70c3334f11aa1 +887, 0x4ebd26c8decac629 +888, 0x71aefa349216bbb9 +889, 0x37a5967b8b366498 +890, 0xc825ba8bb37e04d0 +891, 0x3411fa5b43243230 +892, 0x32ce54ba8dd0106e +893, 0xa8a0446814fa43f4 +894, 0x9905b5e6d05924df +895, 0xb226af8b15ce9a5b +896, 0x594bed79eed4e4d4 +897, 0xeb6c283c67b0eb18 +898, 0xde5cb33d3dc1d629 +899, 0x1b57482ededa779e +900, 0x1d07de9f3796453e +901, 0x3d1b093a3b2f673f +902, 0x7138dfb52b1e19f9 +903, 0xefd791255568c006 +904, 0x5e9f6ea3fd02d382 +905, 0xada1ec576dedd60c +906, 0x894f3cd4d0463181 +907, 0xf8e46d0e8c179157 +908, 0x53234c91c74681f +909, 0x458491d26dc655b6 +910, 0x2dce3244020c6219 +911, 0x6815f50060ce3a58 +912, 0x13ec2d1c70067d9d +913, 0xe252832edd6cf225 +914, 0xd6656ac22edd7a1e +915, 0x818d3bb5d04315a8 +916, 0x36c302529a73033f +917, 0x1a9c6b44ccefb355 +918, 0x99e5dac400256022 +919, 0xdcf849ba5115f17c +920, 0xdf9c1238c38b6ad8 +921, 0xf7d9422477cc5cf8 +922, 0x6e3ccc5e484db3f0 +923, 0xf9f5dc3936d5ce41 +924, 0x4e42a060e0fc7c13 +925, 0x9789adf2f7e0b250 +926, 0xd12a569e95979840 +927, 0x14b652c51eadd0c8 +928, 0x2d8d9baea2c7a8ab +929, 0x9589291913c9345e +930, 0xc3e994adc95fa2ed +931, 0x30ef4019e04f22c2 +932, 0xae4d6ac24e6a42fa +933, 0x14bf6dd1873be03f +934, 0x48e3731b4088a6df +935, 0x66b6f14a28de0cb6 +936, 0x825b0e7560fd526d +937, 0x334b0c5989386158 +938, 0x5a4a0353e701405a +939, 0x11844bcfdda17e36 +940, 0x737420216b683159 +941, 0xcdfda9150023d465 +942, 0x3ccb1da83154f7d1 +943, 0xca0ed9ba34067fd7 +944, 0x5ca93550b1ccb1ef +945, 0xd52bf628b920563 +946, 0x239147f7b5d9e31 +947, 0x70457bc990dade04 +948, 0xec5a8e4749adada3 +949, 0xd1aed177de970226 +950, 0x537d06d8885531c1 +951, 0x4f83c7fc8e711e0f +952, 0x412b2d578e62a0ab +953, 0xcce8d0bc4f4d4e57 +954, 0xabd3b7802f2d051d +955, 0x76721bb6d8b97e0 +956, 0x217c77ff302ff9f1 +957, 0x19ea31efebc3350f +958, 0xf4a3f147857e5cb9 +959, 0xe802bf7f519cd61a +960, 0x1c8d02dba97d6e3d +961, 0x78bfb57b9bb0518e +962, 0x8a48af98c6df1ca5 +963, 0xdfac5ac680503f7 +964, 0x4a9e3e96d9ea260 +965, 0x5f1931c9a7dff2a2 +966, 0xc1968e6cbed5f888 +967, 0x8eb493f97aad3ec4 +968, 0x90f2abe998c8ef87 +969, 0xc6aba12513cfbb3e +970, 0x2c0ed550f9c796f +971, 0x444fa35f7d9fe383 +972, 0xb5f04f695ecab10 +973, 0x3385d267df3349fe +974, 0x4c70e55fa2bbbeca +975, 0xd10dec43a2c0bf05 +976, 0x1ca77c39862fc552 +977, 0x9cbd688dfab24fc4 +978, 0xb7fd22171296a3d1 +979, 0x1183b02b50271be2 +980, 0x883a7e16e7e0a424 +981, 0x10d83194ac141f1a +982, 0xebe3d57aed64b429 +983, 0x50b227d667b4cab7 +984, 0x5ea269feb856345d +985, 0xb7b31144fa8d0f75 +986, 0xb2a4ee8f1fe24113 +987, 0xe630bafdf1401749 +988, 0x2a5fa38d1f97c355 +989, 0x26ce612a57a75fc8 +990, 0x657f3a8955ebe69f +991, 0x6ce0b006f4ee7ad5 +992, 0xb2394f5046b31e22 +993, 0xe778365c658b2739 +994, 0x98fd9744990f5bc7 +995, 0x46218fb884bca27 +996, 0xe1b5e671a5fa3f4a +997, 0xcde973df241f948d +998, 0xa797c49a69f2eaee +999, 0x7aac8c483a2edd2f diff --git a/_randomgen/randomgen/tests/data/xoshiro512starstar-testset-1.csv b/_randomgen/randomgen/tests/data/xoshiro512starstar-testset-1.csv new file mode 100644 index 000000000000..78fb903ee274 --- /dev/null +++ b/_randomgen/randomgen/tests/data/xoshiro512starstar-testset-1.csv @@ -0,0 +1,1001 @@ +seed, 0xdeadbeaf +0, 0x876912846bc23b4b +1, 0xc392a0d7b1e2ce1d +2, 0xd280aa92dbaf6c20 +3, 0x9a545c48769bcb4 +4, 0xba901708334ed1da +5, 0x5d5c05bee6575bba +6, 0xdd35b1a2950ba097 +7, 0xa683f4f912b2de7b +8, 0x9bc8ba4aaf061f16 +9, 0x592c9c1eb898e661 +10, 0xd4c45a31e8d0ea2e +11, 0xd0f486ff8d15aa20 +12, 0x9f476a2094cf2e20 +13, 0x5dfeca30beb341f2 +14, 0xd148d9f7909fce1b +15, 0x77dee98756ef7ccb +16, 0xadc9df01bd7ca503 +17, 0x3d3395384db35e21 +18, 0xedb29f73f3497e33 +19, 0xe8064a9d95ad523 +20, 0xf371e0481aaac707 +21, 0x20ceb788ef6cc7b0 +22, 0x322843da066393d1 +23, 0xff5b70b598091031 +24, 0xbf92dd18de3e50b0 +25, 0x34c53c75dfb462e9 +26, 0x862b38ba34e2074c +27, 0x71d7fccd15ff2980 +28, 0x57659fb10e0a2e70 +29, 0x504aff6ae76bca79 +30, 0x241e0010547d002a +31, 0x6887bf03dd4578e +32, 0x3b74f448c5b5503e +33, 0x893c36f91ae88b29 +34, 0xc997f52382a03491 +35, 0x64d70ecd46d0d3d4 +36, 0x7391b3e2b46ab3b +37, 0xad0cb7eb249d1562 +38, 0xad8c488df7a6abd8 +39, 0x821201a7bfd18bfb +40, 0x13281b52ed3db7ca +41, 0x5fb74a1925cdbbad +42, 0xa0a82244150ebae7 +43, 0x33a699202c3e9777 +44, 0xaffd2aad50ab609a +45, 0xd0b2cf8e469a6ca1 +46, 0x9642269993d293a4 +47, 0x4726480893b8003d +48, 0x43927da186b7c458 +49, 0x48bea40a5f99f533 +50, 0xe378848ac37e2376 +51, 0xf9b1f0de5818b090 +52, 0x963368da3e372d75 +53, 0x94d760894d8d59fe +54, 0xed6a9730e9f9d10a +55, 0x78c870cc88e05f99 +56, 0xe4b4445bb8ec2548 +57, 0xf2d2c9524d47c49d +58, 0x3e326b4eb1e18a59 +59, 0xc9ed2185d3b07552 +60, 0x37312e94b1a19e86 +61, 0xe2e44446e72437ae +62, 0x3e5541807ba68504 +63, 0x64fc4a8e251ba4a0 +64, 0x95cae7337b2cef03 +65, 0x4ffc22e6cee5a43a +66, 0xd1220fcfcd2b91c3 +67, 0x951e666e2b35250f +68, 0x49a6bf7293bfeb76 +69, 0x2f572a06be223951 +70, 0xa6ef2f83e4ab699c +71, 0x3c779b06245bef11 +72, 0x7ca2068971303e22 +73, 0x99181930c623a0b +74, 0x23870cb8e351237b +75, 0x4b3b096b31c0970 +76, 0x34567d210e095de +77, 0xad2d302293c080b6 +78, 0x2b9912fc65270b03 +79, 0x9d83c41c4a03c97d +80, 0xe595f5a6818c6843 +81, 0xf4de1eaa641abd16 +82, 0x2fd5d26fa4e8fda +83, 0x20228869fa37cafe +84, 0x2f5aaadbc5ed7917 +85, 0xc5a5411d976295d1 +86, 0x50860eb0a32883e2 +87, 0x9671e47f29c3fde5 +88, 0xb405167f98de3d42 +89, 0xeb9e4ab5b6277a34 +90, 0x30cb8055425283f5 +91, 0xd16fd04051825def +92, 0x9dad7dc043f76efd +93, 0x4efb0d073fa86b85 +94, 0x41f9a8f57a4c5441 +95, 0x261b340edbdfc85d +96, 0xe1770e8f6417f4b8 +97, 0xcda740ac5492b7cb +98, 0x421852a55f5fbd17 +99, 0x6b5e600ff816480e +100, 0x6f810e2bc14ef783 +101, 0x3ac30d12dbe74179 +102, 0x6e6f55e8da77d1c +103, 0xb3c1b3198ba1edd +104, 0xd42a70884e0b4885 +105, 0xe5b8554e1a265456 +106, 0x984728fa61cde5e8 +107, 0x22a8631dea8491ab +108, 0x7dde04d2623c5280 +109, 0x56ca5fa13744f021 +110, 0xa07c4dccd62318c0 +111, 0x7643fbf3cb825b82 +112, 0xb514293ac755d9ab +113, 0x976a42d4d7d5603f +114, 0xc89c841ed969a429 +115, 0xd3b58bd283d84deb +116, 0x48b0cb54ef4045de +117, 0x2aac0bed41855b31 +118, 0x84f602d6f7e8f8bb +119, 0xffb8359b5c955803 +120, 0x50a030999c6b5a41 +121, 0xf5affea03223e801 +122, 0x480fca3d8b71f253 +123, 0x78f46d086436f38d +124, 0xe55f321bb366b5c5 +125, 0x6a62bdcf97975049 +126, 0x4ba1b23acb2b30a4 +127, 0xaa8fab62162096ff +128, 0x9df7f50611bbbe05 +129, 0x8c41f29908880a54 +130, 0x5ca1036a33aef749 +131, 0x749341c5a1836f3e +132, 0x20d782c11d500c36 +133, 0x2aa089b1c26c888d +134, 0xb20781d123d61f05 +135, 0x786a566307a0e29e +136, 0xd7098641e929f68b +137, 0x8ef02287eec14ac5 +138, 0x9e3aba8329a8901f +139, 0x60f1e7d84742be3f +140, 0xc5292e6425256ab7 +141, 0xdcbf5736a8f911fe +142, 0x52ad9d372e4bd44b +143, 0xffebb934b4bfe199 +144, 0x7b5914f9b9052873 +145, 0xab29298e00ae9e7b +146, 0x3f02c3b7c59d121f +147, 0xdfa607db43e83fd5 +148, 0x1d8b966bd15e43cd +149, 0x25505363d4cf3ea6 +150, 0xc7f96d3a547efd4f +151, 0xa76458b01561c500 +152, 0x88760cde8e7f1522 +153, 0x67fe6b33586a089a +154, 0x5f0cc55ccd9dcbad +155, 0xaf32ec846865364f +156, 0x8f475ab26161ac5f +157, 0x92f00c5e55d0f3fd +158, 0x70488866e54bd9fc +159, 0xa2579ad851925266 +160, 0x1f2d66d6ab9a6467 +161, 0x18f0e12487296a55 +162, 0xca46bd4045b88b1e +163, 0xa48926a8c9ae6ddb +164, 0x70cf4b02a878020 +165, 0x3c827fe43ccf6e84 +166, 0x7b90b8b99390d7fe +167, 0x239e42fba10e8dfa +168, 0xdd950d180b5554c9 +169, 0xc219887acba392dc +170, 0xfb0cea050c6b5cfc +171, 0xa0235db93ab17388 +172, 0xce4e9a6697f39fa4 +173, 0xa77bc206c26b62aa +174, 0x6c4c0d77659b8d3a +175, 0xccf68dae535cdfce +176, 0xb774203a9c3697ec +177, 0x8f9603ede62970e0 +178, 0x73466a6c08f5c621 +179, 0xe4acd501298142da +180, 0xc1dc6d50d19ce4d0 +181, 0xf4d7157f3385da90 +182, 0xb03a1668d58ccc1e +183, 0x6c1ec730cdc15ff2 +184, 0x22b33428cf6f7b6e +185, 0x86771ba36131beb7 +186, 0x5c6f1dfb5df9a773 +187, 0x83d0e480faf79e2f +188, 0xb574e4f020a5c2f2 +189, 0x1037336e206cdac5 +190, 0xd358d3bd2f84dc07 +191, 0xe4ab7d65f5359d88 +192, 0x575e10beab6ed90d +193, 0x92b392d9011fec7a +194, 0x3743566cd03a5632 +195, 0xd84d08e20ab24432 +196, 0x264edbb98ea18981 +197, 0xb02ec336d3439df8 +198, 0x98dca28ef3481cd0 +199, 0x4c7b36c3d5a92ee8 +200, 0xea3a5d8c0656562a +201, 0x84df1e0b04e16ffb +202, 0x4033a0901c5b99b2 +203, 0xd655e52a52f95806 +204, 0x877a6c6e491f65c2 +205, 0xc7c0476aa3b57914 +206, 0xdaeb947a7ea2bffd +207, 0x9f353a9a44bb3542 +208, 0x4c6149547cb86c21 +209, 0x476f38042f81f574 +210, 0x73ae5842de15b837 +211, 0x56d08498c32a3ca1 +212, 0x3a29bd1e56c4a455 +213, 0xd4a039af15c94e2a +214, 0xd7e99d87726f6b7d +215, 0x11c8799497348055 +216, 0xf301a2a414f75291 +217, 0x61ef21e4369a33b5 +218, 0xbfebae360aed836f +219, 0x77b268e02299116e +220, 0x1d97ecb5b5ff1390 +221, 0x8931baa8bbac229 +222, 0x3e0a9cd01623e25e +223, 0x241849e522393124 +224, 0x4cac9db644404e9f +225, 0xf1b301aaaf6ee36f +226, 0xc6f3b0e23ed765f +227, 0xa721a93561fdb2fb +228, 0xec5d2fe7bdd570b6 +229, 0xaac87fcd59a92a17 +230, 0x21f96034df83ca3e +231, 0x39168b96c29637b2 +232, 0x2285e7b1962b20c4 +233, 0xe05877c5e64e80a0 +234, 0xa6e5e068434197b8 +235, 0x9953d6ba338c81ce +236, 0xc44dc6a3db952698 +237, 0xfa5494d4815d3152 +238, 0x467f7c752a541c4b +239, 0xb1a4872d1fbb6953 +240, 0x53fd30ae98ca00d7 +241, 0xc70a548b87054598 +242, 0x9d8a20c63463d5ea +243, 0x4cecb6becf778a54 +244, 0x887087ebdaca7461 +245, 0x6d518861d1cbc12 +246, 0xb8e717a809a31912 +247, 0x2d36ba962e509fe4 +248, 0x9bf46721bb113d5f +249, 0x2269b9c4c443667a +250, 0x979d9b4e6a4036c4 +251, 0x97543e06d384fa7e +252, 0x75ad7d2c23b6b570 +253, 0x43de810a5ea78624 +254, 0x80927c6293498a84 +255, 0x45a8ad9bb8f0dc2b +256, 0xabc320ec65a09cd5 +257, 0xcad9c0647042cd93 +258, 0xe84acb1bd3f3c9a0 +259, 0x76879458f63a57b9 +260, 0x49832792c9e03bc2 +261, 0x363459686faf7f24 +262, 0x1953702db3bc481e +263, 0x7fe6ba3b5a71fc59 +264, 0x1b17d2f961567f8b +265, 0x4ad033e1a4976f6e +266, 0xfcc0a6a6ba63fe49 +267, 0x841ac723afca1b63 +268, 0x6c1e91e669a97e7b +269, 0x5bd742d77c4ffc4d +270, 0x2a4ee5d86d2c240 +271, 0xe6d74f8546c38065 +272, 0x8bf207da18d16f8a +273, 0x9d1c2a99dce927c +274, 0xcba190db5ac2bc23 +275, 0xbabffcd557568ce9 +276, 0xa299e5d76f753e2f +277, 0x1d9b7854688000dc +278, 0xb77578a80be855c5 +279, 0xed5ca1b150fe57ee +280, 0x45ee175cab6988fc +281, 0x909e1e69be99cc5a +282, 0xeb19bad3b280f6eb +283, 0x183e05016ba8278b +284, 0x353ac3c6b09909cd +285, 0x52acc5f973291d01 +286, 0xf34bf118d4119a02 +287, 0x9374f1c812dd0b4d +288, 0x3cde5e29ca458381 +289, 0xa273cf101a664a2c +290, 0x3853d177648e274 +291, 0xd56392bd92a668f7 +292, 0x1a1668b6f658e0df +293, 0xcf91598b7f111669 +294, 0x9de820277a8591ab +295, 0x13e814a02eae1592 +296, 0xc6327921c4c8e137 +297, 0x4552a0478447893e +298, 0x90599b2c47bd6a68 +299, 0x6c6e379db4c5bd45 +300, 0xaddd155f6abe63fb +301, 0x16db9bcfefb79d09 +302, 0xadca159b2d4590c +303, 0xea280435e2e8ce04 +304, 0x267dde359f765411 +305, 0xc864e3d28e62e7f4 +306, 0xe1fb3b84699cb288 +307, 0x736e511cbe0a901b +308, 0x8ab9371873aa48d0 +309, 0xee14f5d0455642dc +310, 0xf46227f274aa445e +311, 0xf2ffe9298c22aaa8 +312, 0xb252d7080d3d64e5 +313, 0xf028d588f8bf09a3 +314, 0x51cf0c448bceb8a1 +315, 0x78d514cb6eb97a24 +316, 0xd35f14eeb72a2a52 +317, 0x2517e47da9fc019b +318, 0xa489556e41ab02a4 +319, 0x656545c76c5c5ad4 +320, 0x492cb4aead67db01 +321, 0xe67564b20bcd1500 +322, 0x52902e9ddd3736ff +323, 0x5fce2d6101c2d2f4 +324, 0xd6f3518a5c17b71f +325, 0xcea602751388c642 +326, 0x7c457e009571d1cb +327, 0x227cfe2d67db803d +328, 0xe6ba583bae3ce6ed +329, 0xbfede024874e2353 +330, 0x9d3f741ad2fb1c3a +331, 0xc92d955fdc49e35b +332, 0xe69f6bd427cb55c9 +333, 0x25154cf96eca70f2 +334, 0x8ada45f19fb5f353 +335, 0xc53b729eceb66699 +336, 0xad1ffe3b331399d2 +337, 0x26fa10d0ebb11981 +338, 0x4421bf4042ab1aff +339, 0xa33e3522a639e3f9 +340, 0xb27e6a340f2ae673 +341, 0xfbc848389681b76e +342, 0x87c9b594466133f1 +343, 0x5599811888d255be +344, 0xd125be5eadf51857 +345, 0xcfeddf66c3515e41 +346, 0x4e0e7d52bf2d41e7 +347, 0x7350bd89ecaa448b +348, 0x757b947295bb2315 +349, 0x9f75502e97420690 +350, 0xe507886c40a0d5d4 +351, 0xffb51fce9b6dc784 +352, 0x99c25bc884a07f13 +353, 0xae344dc6a0b5166d +354, 0x6e40f70fd2ae8839 +355, 0x549899226f83a618 +356, 0x183534a08628f76d +357, 0x13dbc72806e9cd8a +358, 0xc451b9a7f19a7148 +359, 0xf3ddd00aa2b77694 +360, 0xbbbf6a41f2637562 +361, 0x915549fda9129f5f +362, 0x6fb5452e819db506 +363, 0xc5122da2374c0ca6 +364, 0x9f418bff6eca6a59 +365, 0xad3988d59c836956 +366, 0xea3a5d086c5fe4d3 +367, 0x11a982723a4fa262 +368, 0x7f8bc4b1e17c14b2 +369, 0x4ce7986a6f72da2d +370, 0x41a50493a56271df +371, 0x477f24559f89ebfd +372, 0xc572ffc3e23521cb +373, 0xa9f628071811e1be +374, 0xcff02944927dc1bc +375, 0xd9f3bc4c212e939a +376, 0x21ffd91aafaf2c40 +377, 0x787f6ed5a2bab7b4 +378, 0x4609e004f9f4b1dc +379, 0x35ab1b27ca8c420e +380, 0xcca7c9a1b9c3b92b +381, 0xca101f017408e01a +382, 0x839abfc61cd0e8ef +383, 0x4c9cbb325badd3b7 +384, 0x5461826c9f315581 +385, 0xad20102aca3d9965 +386, 0xb649a32f64ab0793 +387, 0x725876dd5ff27c65 +388, 0xf2b14bbba3426942 +389, 0x5435afdbc2d685ae +390, 0x9c82ffffcdaabf8f +391, 0x20cdae1036653261 +392, 0x750c8fc5e91ea522 +393, 0x2360b1ebcd9d5b1c +394, 0x565e847ea6e9cacf +395, 0x8cfbc0c6bb12629b +396, 0xb26a10d6f12d2655 +397, 0xef86d9c5378690bb +398, 0xe23f3de5c1b799f6 +399, 0x31414ecd6ad5c5ef +400, 0x2921e71b83de7f45 +401, 0xebb98f34ab50544d +402, 0x6a412a4e053db405 +403, 0xddbfe7ee3e59a7d6 +404, 0xf05a0b36f67b9d5d +405, 0x849702c7806eb90 +406, 0x2203171eecce2095 +407, 0xb35c4db941a0ad7b +408, 0x9935496450296948 +409, 0x25f6a856fb1eb5d6 +410, 0x1dbb88d4fec8e2aa +411, 0xc60d3d3e39a26b96 +412, 0xf056684ba3a744d5 +413, 0x9572bd538afc7a32 +414, 0x254a093ab05dc0fa +415, 0xba6097f07c855fa9 +416, 0xf8b4dccfdb80e63e +417, 0xd2847b228bac28b +418, 0x8a8fab7c6031ab8c +419, 0xec08987d742c44bd +420, 0x133e3fff1c3c3412 +421, 0x6530ebd39d7b0f3 +422, 0xdeabc74a2373434f +423, 0x7815e18e47103e3d +424, 0xf9055ff370764f53 +425, 0x5a0d1345d2a9cc8f +426, 0x4de989802f34160a +427, 0x28a18124bdac81e5 +428, 0xeb45ab441afbb912 +429, 0x8f5a312fe7a0aadd +430, 0x7314071d14857900 +431, 0x6409cb66fa1e53ef +432, 0xfaf96ce7d2ac6c00 +433, 0x76e7a4baea8c663b +434, 0xb6e304f2a50a0321 +435, 0xa9ea300fd24f020 +436, 0xf35c396e30b7101 +437, 0x81c58595f98f6fbe +438, 0xc0a7e9607a117181 +439, 0xed09111f23a46ac4 +440, 0xb54c0bb2f0c1a3ae +441, 0x43467aba9df3e0a5 +442, 0xe8339c39a322db8c +443, 0x51c577fe5ec19d36 +444, 0x4f3b14d68f848502 +445, 0x686cd92e19b79dd4 +446, 0xdc741863e36fae80 +447, 0xd43d6b68d8b201e9 +448, 0x2c50554b76cef087 +449, 0x56c381d91bf8b46d +450, 0xd127daceb8ff95be +451, 0xd0ea2f226b20d165 +452, 0xdd905744fa9202c5 +453, 0xfe1a9600438aff20 +454, 0x5d1abb8492e2e820 +455, 0x8e39cb8cc6fa2c06 +456, 0x9f1dd3396c6629c9 +457, 0x9d03c31afb79a214 +458, 0x22010d4e60bdda86 +459, 0x80ed07d705582e63 +460, 0x4f62b3e2e44b8571 +461, 0x101943c84597f33c +462, 0x4b4345de91b98294 +463, 0xc2ac56211ca6ee2c +464, 0x3cb95b436ece64d3 +465, 0x7a44a3c791671dcc +466, 0xc8bf29ce122b9d18 +467, 0x7943b142841bea04 +468, 0xfa2cc19a05924ff4 +469, 0xf9ad7238096bedb9 +470, 0xe63a166ab147220a +471, 0x6290dc36e53827e3 +472, 0xb21625ceb1014816 +473, 0xc4e932b9872d1e1f +474, 0xb1acf7e2a966bbb5 +475, 0xb9acdda48ec54590 +476, 0x336d528109c184a7 +477, 0x11316b2094f4d127 +478, 0x9e336afa73ba2faa +479, 0xd01fbf09ceeb6b24 +480, 0xcf97f3d08a634c2 +481, 0x72366953156c6a32 +482, 0x6db4bfd8113532e5 +483, 0x420d662640c9c82d +484, 0xef483fc8418f98b8 +485, 0x8f94c007d9e7d764 +486, 0xa920478806e51718 +487, 0xd4ff1f37c4402973 +488, 0xddbc1ff65d2e4944 +489, 0x1e358eaa42485b6a +490, 0x56cb2d0f9bab7e7 +491, 0x78965a1fc3ca2f1e +492, 0xb674cef0c1fd959e +493, 0xabba2d9a65e8a159 +494, 0x2c831ed46e02e9e6 +495, 0x96813fe5b0baca53 +496, 0x344cad935e02fc84 +497, 0xfb6e6b235ddf773c +498, 0x29947186532b0ac +499, 0x39446d366a46f449 +500, 0x270064563611ed55 +501, 0x9134963540c148bf +502, 0x46e72242d92ace70 +503, 0xbb588070df8c323 +504, 0x7656b60e47229e4b +505, 0xa1515367c8182e88 +506, 0x67194c7e83f0be6a +507, 0x8019b59794f3ec41 +508, 0x9346f2071da5e890 +509, 0xbf2968158965aa88 +510, 0x23234e9079cc8067 +511, 0x52480f9037e18c77 +512, 0x28849338ded11a2c +513, 0xdee551c607d5934a +514, 0x7378da20ad9165f4 +515, 0x8c913ef9e355a530 +516, 0xe2fe80181a74edd +517, 0xf1c99e6c3b0ca5b9 +518, 0x9ed9759b0ec64466 +519, 0x651dfcfc1fefa43a +520, 0x36d83fe0802969c1 +521, 0x288a70061165d01d +522, 0x5b9ff38ba4551eb8 +523, 0xb14b82c0d9052f6 +524, 0xa4af53cf1da019e8 +525, 0x562782be5655f97d +526, 0x87f92290b4f40131 +527, 0xe18168d9d140e801 +528, 0xbdacd598ad865c11 +529, 0xc0f4fe27f0884385 +530, 0xc034cd89bb7f0f42 +531, 0x3591756fece4a5fe +532, 0x1a73abbcbdbbc237 +533, 0x9af0782b54c0527b +534, 0xee5e13f65e7b76d5 +535, 0x16b7de36f37d2dc2 +536, 0xda6e3700f7987cf7 +537, 0x88b1a7a50bb8d03c +538, 0x73e0f21f7e240cec +539, 0xaf3de5598cd8ae24 +540, 0xb48ac453d9a452b8 +541, 0x67c7769e42377756 +542, 0x29d1c81c990639c4 +543, 0x5315f99dcc1926aa +544, 0x25e2df9a59623d48 +545, 0x17088168b2d6335d +546, 0x48929f9995cf0b8d +547, 0x9c80ce435ecb9b7d +548, 0xa6dbed42aca888a0 +549, 0x95d7ce284511406 +550, 0xc98a600e73fdf6b +551, 0x144dacadb5dcae70 +552, 0xf1c57aef0ced3fd0 +553, 0x4d7e9370bf5326e1 +554, 0x60eaec9ceddb9bbc +555, 0x40b99b3647bdec5d +556, 0x23451cd70ba654dd +557, 0x9e1e45a64320a108 +558, 0x572b629749dd059c +559, 0x370b84536cf92fbf +560, 0xa53c15e1b8e6930a +561, 0xff01f2d42f396a5 +562, 0xe4ce127c2371d1f4 +563, 0x964b007fd911f9d8 +564, 0xe8ad752ca4201d78 +565, 0xec150ec1bcea7899 +566, 0x3a98196d39a146e0 +567, 0xa13a6d24b065154d +568, 0x208f8f86fce0ffb7 +569, 0x48f3f5a286b8e61 +570, 0x231fc95324da4f0 +571, 0x4a912cc8c1145073 +572, 0xf55643f746f7c8 +573, 0x981b50355641f3aa +574, 0xf5cd5ca76785adf5 +575, 0x26809313bad9613e +576, 0x8b3bc2cbe2257a8a +577, 0xe7190ca66630f33d +578, 0xd678cb7a88ceea26 +579, 0xa82e3b2a968f54a1 +580, 0x9f495544f523a642 +581, 0x542ea223014d5724 +582, 0x976e7bc0aec4f3db +583, 0x6a4936ec50a7744f +584, 0x30ee4d2e234675bf +585, 0x7668a3489b46baab +586, 0x69b5bfddb0c219ce +587, 0x6cdf31a1621b4ee5 +588, 0xd47c5fa7524889e8 +589, 0x5ea77c458ed6b908 +590, 0x9f46aeb5373d4f5a +591, 0x2436d30afa02fb0f +592, 0xf75b5b183a82b399 +593, 0x2a0d4f653d5fb2b +594, 0xbaa369f3cee66a53 +595, 0x3b86f73fe2f8a1e3 +596, 0x6d7bb0961e1fd2c7 +597, 0xe0ea2803b75bb089 +598, 0xdad50e588726a5ed +599, 0xaad4c6349ef8c9bd +600, 0xac89692a9d19027f +601, 0x9128ccf4627bc207 +602, 0x84d06846beb2e304 +603, 0x7e8f78333abbc3d3 +604, 0x3f60914f5bd7e556 +605, 0x1d1304a8114ca709 +606, 0x140e3ae0d71cd49 +607, 0xd11427f5452fd9b4 +608, 0xf5ab3e8a0298f3be +609, 0x6b9e13c2d33aac45 +610, 0x855e2a9d17dca5af +611, 0x1578bc2441980cb9 +612, 0xb6d79ee20056c9a2 +613, 0x8becbe9a399154b5 +614, 0x7dcbfacd30d88c84 +615, 0xd9d2e48917b7010c +616, 0xfc72160892a21efd +617, 0xc7034a2a63410f42 +618, 0xbfdfa5eaeac7f80d +619, 0x89ced96a0e78f3c0 +620, 0x8afc51dfec588d2f +621, 0x6cd965499ebd9c86 +622, 0x86ca64414acae86b +623, 0x235defd7163050fa +624, 0x8350429671c8a0c5 +625, 0x86242291e8c4ad95 +626, 0x479275615cc7ab91 +627, 0xa6f410c0e2a26b2e +628, 0x3855e7ac300d255a +629, 0x46db9d9dc4109474 +630, 0x4ea0b44c4fe5b658 +631, 0x5433d83c0590d49e +632, 0x326ad33d53e5cb0 +633, 0x2ad4e88d8b8f4865 +634, 0xc0b971ea67fc2c1b +635, 0xd4db06ac68087267 +636, 0x35375c34999616ca +637, 0x7f313fa01760e4fc +638, 0x1f8b7ae8938e7d90 +639, 0x68aedc55512291e3 +640, 0x71e13848edee765a +641, 0x83feb5bccb136a0 +642, 0xec115ea084398beb +643, 0xdecd12d25159994a +644, 0x6ef3f928b79e1d15 +645, 0xc910824824961e9b +646, 0x6e56798f305fba9d +647, 0x9f2a78709ae8321a +648, 0x83673dba510e8329 +649, 0x38ee325de51bee33 +650, 0x6dde848944ff5c19 +651, 0xe990435690783cd8 +652, 0x4ef2b8fdf3a31076 +653, 0xb35c280054e321d1 +654, 0x2d66f077be780ce5 +655, 0xf003d07f5e8d24f1 +656, 0x63286f306d80f9e7 +657, 0x749e66588e9d5bdb +658, 0xf296e9d13eb97fdc +659, 0x8cc6e45328cecc17 +660, 0x4b35bc27b7d27225 +661, 0xea1f0b0e7cb3f20b +662, 0xccddb348221b89a8 +663, 0x8a2b674dbe8732 +664, 0x90a2fe18fc860a2b +665, 0xee92bfccb4c6986 +666, 0x55bfc65eef023c41 +667, 0x61e082760147dced +668, 0x2cf7af28fb253ab7 +669, 0x58dec379fe82b794 +670, 0xfe6d8ec391ba7af0 +671, 0x3f96cf458d50cc0f +672, 0xb97a170ccb8094d7 +673, 0xca876f8a8ee27019 +674, 0xa03a1b9f8c2c3595 +675, 0x8ce5c48735932234 +676, 0x5bcbfeda6a7099dd +677, 0x32ffcf8fc39ebdda +678, 0x945d734289b83a9a +679, 0x8824610f5d088bdf +680, 0x9259056e8d773859 +681, 0xf4b40ae4f8ec9d59 +682, 0x78be6102d44b8198 +683, 0x7dce883504ae3027 +684, 0x3bcbac86d37993e +685, 0x334af10e3ce0cb50 +686, 0x12b3fe24d1df167c +687, 0xfa17184c24036cb +688, 0x200d27e144d9f60c +689, 0xcb1fd05755672423 +690, 0xd5ad76956dced3a5 +691, 0x7e54849c6a87880d +692, 0x359af4d5828b1f79 +693, 0x26453ccc43829d09 +694, 0x871808b8e5cb05b9 +695, 0x955a1ebf98da9d59 +696, 0xf5893da12ea014e8 +697, 0xae43111b363eaf7b +698, 0xc6dddd603e4b5cca +699, 0xe1cc643e404fe108 +700, 0xfcbe2e95831db0bd +701, 0xdc01ec9e93e54c55 +702, 0x380c88bd4fa28495 +703, 0x8bd7bfd49c7d768 +704, 0x6489b7ae98113f23 +705, 0xce19f0dd365e3544 +706, 0xf5a58147d87d3083 +707, 0x81efbadc3c88a2f0 +708, 0xad91664c2e7da0b8 +709, 0x8b78dda657eb421b +710, 0x6e552452af7e258f +711, 0xb260660b01d6650d +712, 0x27a45a1cfbd98603 +713, 0xa8f620c73f0ffb4 +714, 0x7e43f2dd4c476ebc +715, 0x7d4e51c6a3614d8c +716, 0x3d5300002b65077d +717, 0xc24e7491fa70d4db +718, 0xf2bcd733a1d21f0c +719, 0x8d5bb04c5273eab8 +720, 0xf9cd01ba63f92da1 +721, 0x64d29462217baa90 +722, 0xcaa1fc3b19b00a05 +723, 0xc9fae87d7026e4ce +724, 0x40120cb2e2680cb6 +725, 0xcc83d069bdfa6caf +726, 0x6a11b1724a9404cf +727, 0x8c24bc538308e19b +728, 0x2be028ae22c66d3d +729, 0xae2a94a920547418 +730, 0xd0c9c729c0d0fdf9 +731, 0x79855e445226f087 +732, 0xa467118788c6ae21 +733, 0x18a67b3f737ac66c +734, 0x9f0422fbf1704575 +735, 0x3cb380445380b25f +736, 0xe16d37c484cd8232 +737, 0x39403a33ed4f833d +738, 0xfea5df032f093e41 +739, 0x47b5d65b30a245a2 +740, 0x5711e2c4cd1bbc2e +741, 0x4b17a868719ff611 +742, 0x12d79e4df14b55e1 +743, 0xb759adb60f0a5110 +744, 0xc495633b8df72a7a +745, 0xc0053b2671187190 +746, 0x8d3924968e71608f +747, 0x1523ade2927ac191 +748, 0x1cfcaf3b0bc57fa +749, 0xb91a7984235eaad3 +750, 0xfc5c6cb849eb3a5e +751, 0xe5d427fef5d314bb +752, 0xb714878d2c853b41 +753, 0xbaf47a81594ca957 +754, 0x3de6e218723fcbab +755, 0x30ee829bf38ab024 +756, 0xb374a5ca939b2a77 +757, 0x689ca34206e9d827 +758, 0x5b639ed104818c6e +759, 0xd4e8fb1ae2cba92a +760, 0x1e74a4554b198ff0 +761, 0x8554e6fe30612ac5 +762, 0xf8078efbafaf7941 +763, 0xb60b6cde7161bfbc +764, 0xe81e0e93e0dea073 +765, 0xac02d3f3b697c994 +766, 0xd10bab917e4348e4 +767, 0xe6fa834ca7e7aa0b +768, 0x6eba49968d0d5254 +769, 0x4a94152838ad62fa +770, 0xe8789cecbaad60cb +771, 0xa970ebd7a89905df +772, 0xe49e4d76fac277ef +773, 0xb8adb96bd78e0d22 +774, 0x3691be969b56ec80 +775, 0x566a22004cdf18be +776, 0xd4da2618b9171235 +777, 0x8dd6f2f32503d141 +778, 0xfe199681d91e5178 +779, 0xed5891007cf409eb +780, 0xd5d999f9d416f32c +781, 0xa5f9a414434cd178 +782, 0x3cd8de680cb84094 +783, 0x2c70c158a5f08368 +784, 0xfd4c6d304ad80f14 +785, 0x1b3555f90f0fa209 +786, 0xbfc5397a69a4335d +787, 0xe51459f0861790fc +788, 0x173d12cdb0c70d44 +789, 0x6c88b6cb9a439159 +790, 0x9e3d527583959951 +791, 0x8974610167fb3d0e +792, 0x8ddec067f7d91a2 +793, 0xda0a0394d476a41 +794, 0xb4bc6f905125bb13 +795, 0x26647355ce93705 +796, 0x6e77d00e7d59f697 +797, 0x8a52c90d219277f8 +798, 0x9a9d112119a2ca00 +799, 0x78a4507edbc0c338 +800, 0xc1a70ab377af5b48 +801, 0x36a1278bed1d15a4 +802, 0xf0f6fe034ce240bd +803, 0x3774f55f64722926 +804, 0x63e4e477803ed6bf +805, 0x2b631b9e6e3dff6d +806, 0xc4c2268f2eb0bf1a +807, 0xb0b910cedfb4eec2 +808, 0x491781f6e8f5078d +809, 0x2db574eaecd44693 +810, 0x397d8904141cb1b4 +811, 0x2848d2ad2a224e0f +812, 0x41f9fae31cf93d56 +813, 0x68bca8f51877387a +814, 0xb43114eb511ba30 +815, 0x6811c33595351f9b +816, 0xf7c9b154b26a6501 +817, 0xa35317f4e4369356 +818, 0x2bbb3809e211de1b +819, 0xbf95e8ce2588f5c5 +820, 0x951b4fc9a159b558 +821, 0xbedaf5970dad8ce2 +822, 0xd79d52c7fc92c15d +823, 0x2b1440cba83e0a6f +824, 0x968f7f07b4a36640 +825, 0xddb5d48949a8258e +826, 0xc679b204042b05f1 +827, 0x9d00c9fbd7edbeb4 +828, 0xafb601b2be4c9a97 +829, 0xc35a1adfe92039b1 +830, 0x4392c71aff19cdfb +831, 0x1ab34fdb1e3f94fa +832, 0xe8e3bad693ee9d2b +833, 0x78ae4836d1711383 +834, 0xcb764bcf9104bd66 +835, 0xcb80c3c2286af3b0 +836, 0x5c1d4bb3d36d0deb +837, 0xa2071886b21e6c32 +838, 0x137909746a058350 +839, 0xa2a196ae5a9845b6 +840, 0xc0776cc50ba681ee +841, 0x8101ae19ebcdf8cb +842, 0x253846a45a1bea0a +843, 0x945829fdcac6cc2a +844, 0x28dcc868b896b986 +845, 0x336d9114936baa1d +846, 0x4bdf4ed2bfd5d8ef +847, 0x7f43f8324a743507 +848, 0xb721732c35266109 +849, 0x5654184a7879a5a +850, 0x932e5c33053debc8 +851, 0x6c8a42cb4bb07c7e +852, 0x3e2853cb7367a326 +853, 0xf670fcefeaf352e0 +854, 0x2f0ed63118ecfeee +855, 0x22b32d6a6fcaaabc +856, 0xa8df4f57af993b14 +857, 0xc4fbcdfec94e25fc +858, 0x7855b5802cd2d6e6 +859, 0xd31ec992392792cf +860, 0x499b4022955ae602 +861, 0xb1d9df2a56d1d9b5 +862, 0x2be020670c2ba9ad +863, 0x4f51c9ac114691f6 +864, 0x43db97ee34cb6585 +865, 0xf7889fa1c3372662 +866, 0x7428ebb0889ce59a +867, 0xf69778b6c2a803b1 +868, 0x68c7f79994d68355 +869, 0x49b31b833c1fe002 +870, 0x14823830b7aa93f1 +871, 0xfa3fe89a5d2be21e +872, 0xd75217b26deb1860 +873, 0x5e49f031d805df72 +874, 0x9d3c204122e892db +875, 0xe4f71314f6bce3c +876, 0x2ac5f8fa64ab428f +877, 0x71a8ee18efa4b447 +878, 0x38170f177f7babce +879, 0x77cbc1adc5a7104e +880, 0x45b756a5c674ed37 +881, 0x3da29002dd3a1dfe +882, 0xcb645f42a1a2df5f +883, 0xb733e9942b4c7ed0 +884, 0xbe1c3292f348b4bf +885, 0x78d11d13c10c2099 +886, 0xf73fa04c2283e128 +887, 0x87e719305bc8ed51 +888, 0x6566b3860eed926 +889, 0xea271a89df9f7896 +890, 0xcace2b0b23f6e8f3 +891, 0x53e2280362cfc833 +892, 0x33ee7d314d33fa14 +893, 0xc033d8359b0de79e +894, 0xec1687b4cf771683 +895, 0x7e9971fdb5f45106 +896, 0xc9e3c5777bb561be +897, 0x17d1a55af8659714 +898, 0x312ba0a1f36f469b +899, 0x74c8f6caac97449 +900, 0x951c3d8e2f973859 +901, 0xff5de9a5079d8908 +902, 0x839fe3f7bc5dc4d9 +903, 0x5a21de4667516721 +904, 0x38ec459dc4da82f9 +905, 0x7a72aa7877678423 +906, 0x9839c4f3ff159ed2 +907, 0x338c7af893a226e4 +908, 0xe057270bd63d90e1 +909, 0x74382261608dab72 +910, 0xc62804f051b15437 +911, 0xd761a1ef0c5db73a +912, 0x496ab0869f08c505 +913, 0xc8b021a098da8e32 +914, 0x6dfe12239acc8048 +915, 0x2e7a263485f52b8f +916, 0xd5e9ddf81a37d37d +917, 0x5de50454fb933d95 +918, 0x431900d5526e3d9 +919, 0x77476c947d99e745 +920, 0x31827e1ae78d0df6 +921, 0xedd8155bcff2a247 +922, 0x1e850adc3c67d0fb +923, 0x661108b21735dd75 +924, 0x352812aa0035019 +925, 0xb927385f13660903 +926, 0x9a516de262c20354 +927, 0xef7bc11900eaff94 +928, 0xf57add7357601ba5 +929, 0x80e7a452cf0b3215 +930, 0xcf6f3fdfdd010a89 +931, 0xb06e98efb8c4cf8d +932, 0xdaa9088d73c8469a +933, 0x2932275de82cf904 +934, 0xae4fe81ef1f2ea6d +935, 0x8f55ad1c108ecd7b +936, 0x4d36deb616fe60d5 +937, 0x129d84b87e28cbfd +938, 0x3d9b18404e0d716c +939, 0x5576067b39672db7 +940, 0x7e57c5806e5bd926 +941, 0xdb86a738b0df1c15 +942, 0xc4263370c4ff9fdd +943, 0x57d5bba42942542 +944, 0x2b2be3e9fa816534 +945, 0x54c1ba10ca97f953 +946, 0xd89c1f14d9805c3b +947, 0xcdad0af12830e5d +948, 0xef8a4e05bb7939a0 +949, 0x10a02cfa077c64cd +950, 0x37dd082b003ba023 +951, 0xbd52decb5ba0259d +952, 0xf07939e0ac9edc13 +953, 0xf14dce84156215f9 +954, 0x4ff635c6efd4c0d1 +955, 0x8273d381b00d1da2 +956, 0x2fe4aee0a7dab542 +957, 0x79a485b897698801 +958, 0x8d3f9726bfdec8ce +959, 0x6daea7b39c0baf5a +960, 0x8508a8b168841669 +961, 0x4dec7955aa28c99c +962, 0x6bd02c3a6e4496aa +963, 0x2c13959a34e93763 +964, 0x1ccace54fdfeb05e +965, 0x34cad73846788c6f +966, 0xabb7d3e684c062bd +967, 0x69c236a70240069c +968, 0xa53398808da493b2 +969, 0x2b4cfa32cf2603f0 +970, 0x903cde2693c3b0f9 +971, 0x5d556925830a020b +972, 0x90a63eab0db9352f +973, 0x351c2d2838792525 +974, 0xe85ceb3486eefb16 +975, 0xfa275cecec8d524d +976, 0x9f1b20f0dd3ce0d7 +977, 0xceb1490022a7a9cd +978, 0x1e7b51c976ea3265 +979, 0x5fa85864c857568e +980, 0x1e7b06ae95db5660 +981, 0xfee282a9657ed8d6 +982, 0x1f2a6fde4761b6b5 +983, 0x1568cbeaba398cdf +984, 0xe185d2c2cef2cc9c +985, 0x2933556aa7be334d +986, 0xec1d06dc69a8a107 +987, 0xa9683634651f5552 +988, 0x8f448642e633fc86 +989, 0xa39ca103aaae4c10 +990, 0x11ca0212139029ff +991, 0xdea595418a51693d +992, 0x1b96d86565401fa7 +993, 0x9876432af1ab5f2a +994, 0xc9630e117c574a52 +995, 0xdc6b6eaa00873b8d +996, 0xd4456b90b2690f82 +997, 0x38374bbd586d9905 +998, 0x47c96bd123a5f3b4 +999, 0x72ef78391219eb11 diff --git a/_randomgen/randomgen/tests/data/xoshiro512starstar-testset-2.csv b/_randomgen/randomgen/tests/data/xoshiro512starstar-testset-2.csv new file mode 100644 index 000000000000..264308f1af4f --- /dev/null +++ b/_randomgen/randomgen/tests/data/xoshiro512starstar-testset-2.csv @@ -0,0 +1,1001 @@ +seed, 0x0 +0, 0x99ec5f36cb75f2b4 +1, 0xbf6e1f784956452a +2, 0x3832e5e4541959a2 +3, 0x25715bafdf7a6b43 +4, 0x8b67fc19f1c8e17f +5, 0xe950e894acc448c1 +6, 0x940554d2c9b256b2 +7, 0xf9eadc87da09ac92 +8, 0x4bfa499f878ac962 +9, 0x383336b0082c3c49 +10, 0x2863cf13af79512e +11, 0x498c25ccc5953380 +12, 0xacde7669d72ac701 +13, 0xd8582a2fdda30a73 +14, 0xddae8a5a57c3302 +15, 0x39b75e8fb865dff5 +16, 0x6946963b565b2ba9 +17, 0xa67ec91e011a1aa3 +18, 0xf88116863cba9c94 +19, 0xc3a3c692211c54f8 +20, 0x62e1a84548f3272d +21, 0x48bfac565faea7dc +22, 0xe8ec2b5f2ee41403 +23, 0x9f4081dab8c56846 +24, 0x7cf256729df79a61 +25, 0xeede53016acd39f2 +26, 0xb37e90df69310b9c +27, 0x2975a99504c56251 +28, 0xdb9416723df2752b +29, 0xc189e2089a8ee16c +30, 0x39fb60f3d17db683 +31, 0x2b60dda991df7c61 +32, 0x5749b739403062bc +33, 0xbe7379e4398257e7 +34, 0x21adce8625781175 +35, 0xf9ca19cb6ff09a4a +36, 0x27689fd07f617a32 +37, 0x656290d3433d9077 +38, 0xc6fba3291a5d6372 +39, 0x8794d1a1bb955db7 +40, 0xc8b037815aab3077 +41, 0x23a02093b144d169 +42, 0x267ad8c80f9caad3 +43, 0x5970a90562008761 +44, 0x7419aa839b2828b6 +45, 0x52dc309a0dfe0f33 +46, 0x10564d319fe055b8 +47, 0xad925ebe373170b0 +48, 0xc38f00ef7258c162 +49, 0x19e6805cbf134b02 +50, 0xa3368cb52e0919a +51, 0xa543ded14e49d4b6 +52, 0x2cebe96c5f0a953 +53, 0xfd2f810919931d8d +54, 0x8181b29c373ad4cc +55, 0x5a03097378f059d6 +56, 0x8e9be6b21fec37b7 +57, 0x37bd0c6e705b5df2 +58, 0x8f1e22e2eb0a869e +59, 0x1abded820c714cf8 +60, 0xdfc917d8b2bed11 +61, 0xc8d119482cead771 +62, 0xee4b670743624ba5 +63, 0x55fbc8a194bf56e6 +64, 0xb21bc8ce5c709989 +65, 0x77abbb291a079826 +66, 0xabb7e9f7bd35d5be +67, 0x479866e6b1a66f15 +68, 0xec82d785eae5a82c +69, 0x2e5d3b0aa0158dc4 +70, 0x2fec4f8b5a8efbfe +71, 0x885293aa43f8645b +72, 0x816c016dc41f2dd7 +73, 0x832f06eae4dd19ed +74, 0xaabacaf4c7840bb7 +75, 0x84e0fd247b0b2412 +76, 0x4ecf02bbf93c2647 +77, 0x1ecf4e8fbab848f8 +78, 0xa7618244187427a +79, 0xc51c7d4d76a4b4e0 +80, 0x44b7b83127f6cb2 +81, 0x13e717ce99868f93 +82, 0x571466622b4e94e4 +83, 0x6086c22ca249714e +84, 0x15d182d77b18a109 +85, 0x2b5cbbf2e8092148 +86, 0x33b31ee2e36f9cdd +87, 0x5ba30dc0c04b381f +88, 0xf855a989b1146877 +89, 0x8f85aef1e22fcae8 +90, 0x7bb6f96d4b652fb7 +91, 0xf3a2e2b45a2619c9 +92, 0x49bcf25f4d6260a +93, 0x26640d4f8e246f16 +94, 0x3b3ca907ab2abb1a +95, 0x2f7a9a3d75f59615 +96, 0xdb63eb1c6172e7fb +97, 0x1569afee9f7a840d +98, 0x4fd1b0162e59bc8a +99, 0x4649428b04932d2b +100, 0xc504f1aa5e5dea73 +101, 0xc2ccb667a4325d31 +102, 0x9afbfdd5ad3a5204 +103, 0xcc07392e231e5553 +104, 0x6f4d6d195fd22ebb +105, 0xeb292b5127fb6e18 +106, 0xfe1f960a70442ded +107, 0x4447c330b74b5933 +108, 0xd21d4046f002efae +109, 0x8bc90cc78187c57e +110, 0x4f67494bf7cecee2 +111, 0xbc33ce353c1ddcfd +112, 0xb891c0a04b0e88f4 +113, 0x8f689f4d0ed5342c +114, 0xda219cd14be3d102 +115, 0x7c1ddbb38629b680 +116, 0x6c70aa3b93c4f52a +117, 0x29ec9e21b1dd5d9e +118, 0xcaeedac16be11bbf +119, 0x35b5110345859bbf +120, 0x439d41ea67b37ebb +121, 0xc6d8d0b7b4f1486a +122, 0xc52385db44d09080 +123, 0x5f99c2e9ca57b52a +124, 0xe3254276e855d800 +125, 0xefbd9049da09502c +126, 0xe6ff8ac6ad006271 +127, 0x2c930e30cb747267 +128, 0x4830da263ba45758 +129, 0x8c60b7ab98006775 +130, 0x7a57c0ea2b570c5a +131, 0xf70f75d3119e0efd +132, 0x3e522394beeed598 +133, 0xb7df8f82912f9695 +134, 0x2abb69f78de3c4f1 +135, 0xd51a5b2c0a7bb5cb +136, 0x89920a17d1de9528 +137, 0xa9d3b9cc614ce21a +138, 0xddd991172b564698 +139, 0xb4a4642875502ea0 +140, 0x8ddcf309cbfe223e +141, 0xb08ba3624d1c66b1 +142, 0x54f027d2804b5a93 +143, 0xb07c3b2d04832f27 +144, 0x848ac9c736770aba +145, 0xc341815ec6b12bf8 +146, 0x3983885191aac395 +147, 0x2c50047012e39883 +148, 0x35762e00ddd30f52 +149, 0x7592ad5f45512761 +150, 0x171247b019c3b822 +151, 0xdf2f59197f67bf2 +152, 0x3d32b07deb6ea68d +153, 0x333e4f44e437159b +154, 0x41a72372d89d3e17 +155, 0x8540ef3654d90ba2 +156, 0x87bd219a8adf77f0 +157, 0x81f0bc1fca841bb3 +158, 0xd3200d827a384d0f +159, 0xd8a9825fadc0be67 +160, 0xe05a6530036bea30 +161, 0xf142901dd1444861 +162, 0xda7d20911dad993d +163, 0x872847376d5e1231 +164, 0x3907389fdf521b33 +165, 0x90fcc779c427a50a +166, 0xb49366477e2b48c8 +167, 0xa04ebd5074accf86 +168, 0x3c92343f5469f7c +169, 0x2b84435bd09b4cb3 +170, 0xb8d4734885fece80 +171, 0xe2fca98eb7e3dc90 +172, 0x5a7f0f454e525193 +173, 0xcc0b1333129c5d2 +174, 0x6433a5896a07730a +175, 0x892937b8a1f1c314 +176, 0xe4a5b385d69dfb7d +177, 0xd8cb9ca239d53aef +178, 0x2cd7af2df788e262 +179, 0x177745f129e94f6c +180, 0x6a6db6c1ebf163e8 +181, 0x58f2f2e255caafeb +182, 0x227c81b75d181eb +183, 0x516d0226e079dbf9 +184, 0x6f66bc3efe0970ed +185, 0xb295db10d97abd08 +186, 0x99d30a4e4ace9fad +187, 0xd9d6a16104bd47d0 +188, 0xdc4c2ea12903a427 +189, 0x6334e1f5f5e03adc +190, 0x9a0cff45fc1bcee8 +191, 0x10874d542fbeec4e +192, 0x3819c7e7fba3b9bf +193, 0x1ee786f49b45924b +194, 0x54723c4712cfb62 +195, 0x3bcca5b2905fb708 +196, 0xf393a7f6ff6a667 +197, 0xaa06af9ce17f62b +198, 0x48c8f05f3e9d463c +199, 0x3479d0238b587b2b +200, 0xa8d8c6670104be96 +201, 0x55814d99b9dfe921 +202, 0xe1ce0f01000d20bd +203, 0x1014d96a94bf3326 +204, 0x582949045ca618f0 +205, 0x223bae0c2e7f5bc0 +206, 0x4bb41f7d1d9fb622 +207, 0xe1f3e2fd4021d8fd +208, 0x5ebccfc61d09c4c9 +209, 0xcfdef40545198b7 +210, 0x4ba8ccc2f8c60a64 +211, 0xba1b4fd748b5061 +212, 0x66e32eba41e0939a +213, 0xa18eed1669d9d315 +214, 0x87c02cfa0ee04b88 +215, 0xfb7c0dfe47ff10b4 +216, 0x865e22c3cbf93ed9 +217, 0xf61e66796f8889b1 +218, 0x3ce89e1af1f9c49c +219, 0x5df6d8fd03e50c56 +220, 0xe2d84d5a77047da7 +221, 0xf1e4983c4900285f +222, 0x1c4fdae662cf9ccf +223, 0x21e8d690e68e9a1a +224, 0x8bc4a83d32b939b9 +225, 0xca02b1f22175c5ff +226, 0x38c7e9f4818bb02d +227, 0x1a0849515278434f +228, 0x9b5ba0111c7e913c +229, 0x7f262e2236221eec +230, 0xbb50a7892f4f3289 +231, 0x61bf32a67a8a37ba +232, 0x8857a179391d0935 +233, 0xe6e89e905c2c838d +234, 0x42a4ac61146bc5a3 +235, 0x709439ac10ef9068 +236, 0x101b793f07cebbdb +237, 0xa15d15f938b270f5 +238, 0xb82363d829a5c246 +239, 0xf472088457296606 +240, 0xa637655483f6a118 +241, 0x8413c67139637302 +242, 0x84e91307377687b7 +243, 0x519f2fdc21adca74 +244, 0x2a57efb29d83c66b +245, 0x5061e889dbf1432f +246, 0xffb74ef07814a287 +247, 0xd82936d72d9838e7 +248, 0xfded7b21dc383d9f +249, 0xc28e1e820fa2d7f3 +250, 0xdad0ba8ae4409211 +251, 0xd7d5ed00366f754 +252, 0xc8f007b6d6161d36 +253, 0x1c4187a9c90e7d87 +254, 0x49fa2c16e3c78424 +255, 0xf3d899da10e89521 +256, 0x89aeb0ade569e3e1 +257, 0x56d3219edcc04b14 +258, 0x5853167abe7fa125 +259, 0x239b40146df96622 +260, 0xa2a70ed13e55aa13 +261, 0x452c6fd65a31f946 +262, 0x771cdf487bb8ea39 +263, 0x458020e1e0355a3 +264, 0x86b71c8ac351f40f +265, 0x4518b905912e4b44 +266, 0xe59809fb72b59f51 +267, 0xf52f08fabdb424ab +268, 0x98729bc24ae9b930 +269, 0xd18bea8f222ae2fd +270, 0xaa5bff6ddbe6cd39 +271, 0x5e6564bdf9d27a0 +272, 0xc1c4658d6d27e065 +273, 0x31d66edddd8655ed +274, 0x6af3bc60e2b4af07 +275, 0x399c4af6041796ab +276, 0x17bb479a69a6ed73 +277, 0x2784fe93a28ecaa3 +278, 0xf21f2428f04f3562 +279, 0x8400c729e4bbcaaa +280, 0xc7b9912613e2277b +281, 0x4100a49d29d132d8 +282, 0xe83d287fada879af +283, 0x20512ca7b1735a2e +284, 0x16d172b52cee39f4 +285, 0x932f40c6356b0681 +286, 0x73b173d7394ebe2f +287, 0x621f4add757fccb6 +288, 0x7724a21d6908f4b +289, 0x82723dadae7a25f +290, 0x917c3b165505d87f +291, 0x317789982769846d +292, 0x9118ac495eb78d26 +293, 0xf52b2e19d3ef473 +294, 0xa846c997a4f8604e +295, 0xf316fca50e1bf909 +296, 0x5fd613d38169c705 +297, 0xfa2c8ac49a16f4d +298, 0x19382f84f73cc4c5 +299, 0xbbbdf4d883438e9e +300, 0xd0c0b36f4d4ef8fc +301, 0x5b57967a9e761eaf +302, 0x8003a747f3cdc264 +303, 0x67245a0a751da7ad +304, 0xc8ddd03ef82a0a33 +305, 0xa7c93a1bfd6c820c +306, 0xf8c05bc5f6fdd20e +307, 0xd9879192f8295663 +308, 0x180c2ff3e2771469 +309, 0xb17b2159870533e6 +310, 0x34d6c12c9be34bc9 +311, 0x664eb6de3c27d98d +312, 0xdbb5b1ba134b9d90 +313, 0x68ce417ee1e96b76 +314, 0x2fb7a10f525e5e08 +315, 0xf4d92c47b9a37cad +316, 0x3fd6bf82bb631c2d +317, 0x269eb1cd345e8a31 +318, 0xbe940cb0cffd51ee +319, 0x17f4afb78aad2719 +320, 0xe6418d546742ed86 +321, 0xbbddf550be83c008 +322, 0x21f5abc27624453d +323, 0xa9c23d6d0fc4cc4a +324, 0x51dd98db43adfa45 +325, 0x768debf45d278d3a +326, 0x3c66726469c6d78a +327, 0x19720ca3ec5c95fe +328, 0x647128339a9de240 +329, 0x2283bfd5ff7fca46 +330, 0x491c02359844cc18 +331, 0x759e770b8b4ab91e +332, 0xca1335607f9cb5c8 +333, 0x57622ba5e6ab8e31 +334, 0xe2631640efa27ee1 +335, 0x9a374481132fdcc3 +336, 0xead08fc06ebe7d6e +337, 0x51f6e040be74899f +338, 0xef020a2644eea66b +339, 0xd08de860251ea1af +340, 0xbbd4224fef793ab5 +341, 0xe32c1f5a20c14b49 +342, 0x41a9c20ee9ab12ff +343, 0xa4f28d0065e07695 +344, 0x29f6a06ee894dde4 +345, 0xf892525b2a6eacd5 +346, 0xf014392e71ac28e +347, 0x95fc7879ae3930da +348, 0x4f6d3fbc928edb34 +349, 0x827c5e01824069df +350, 0xcc71b97aaf28952b +351, 0x34ea77a8fee21c5a +352, 0x1060da2bf2eb6e5d +353, 0xb5c810ce92166853 +354, 0xe4a3a54ee402b549 +355, 0xfccad41d569a68ba +356, 0xef7cdfbe1a1dc930 +357, 0xa4fc3447ec16869c +358, 0x38fd0381051d225d +359, 0x4588436100fb4666 +360, 0x315ee0679f95d75d +361, 0xdb3ebac7a80ce68a +362, 0x711776d978e4144f +363, 0x76335f1760bf6c69 +364, 0xa0e43f3a570985d8 +365, 0x4acd44aa515c8a2a +366, 0xeae99aa23e380173 +367, 0x64db0d85601f3581 +368, 0xb251dc038cc5c88d +369, 0x416acb242805830 +370, 0xc58c8a6f0c958ee5 +371, 0xfca9023592ef2492 +372, 0xe0b53c925afac1d +373, 0x59ab2f382172a153 +374, 0x5b32526cf9ffddf7 +375, 0xe8f7da4d2ee7d446 +376, 0x54ebb0fad0b278a6 +377, 0xdb347dac25d9f210 +378, 0xe439a5295e5218a7 +379, 0xee108ec20ca6d955 +380, 0xcaeb3ae75ca6a426 +381, 0xd626b91bed8e3cfe +382, 0xf594cc47bb420358 +383, 0xcb8c06c63f602631 +384, 0xea1bbf343755e2a6 +385, 0x769f8ad9e3e9dd82 +386, 0x5d0004d1952f258b +387, 0xf696d68c507351d1 +388, 0xcdfd3bef68eeb52f +389, 0x3d400e8af4240cca +390, 0x8662dfc98da8bbba +391, 0x5127c718b4533d93 +392, 0x1628510427094b54 +393, 0xb6d294f5979c4b17 +394, 0x6d03a41585865ea1 +395, 0x96728b5b88e3b111 +396, 0xea45bc46ab6d1e06 +397, 0x53ce57a324130f26 +398, 0x59e439b690174051 +399, 0x7c143c4e625949df +400, 0xc764c808c3e166a3 +401, 0x6263f53fa2405763 +402, 0x71952cf69bb08e58 +403, 0xfec4e83b29280505 +404, 0xce28f5ba58ef8f6e +405, 0xebd9e7ab671427a6 +406, 0x4a91ba373ed1de6e +407, 0xb22b200125627341 +408, 0x8c111548e4a162e5 +409, 0xf4345a7b421b34aa +410, 0x40ba35f569a690a4 +411, 0xf1031a09b5e1d223 +412, 0xbe1c1a131386bbc +413, 0x216f8598d1be1586 +414, 0xef45f48c338d8db0 +415, 0xf57e9f4e168b19c8 +416, 0x56e06748363954b6 +417, 0xccd0b383991896f9 +418, 0x4b40d308361e4d23 +419, 0x1ee49bb107ccb9b9 +420, 0xcdfd1ccf20e46b0b +421, 0x55089ad213e2c33e +422, 0x2852c242329b05a8 +423, 0xa46180d6534b97ef +424, 0xbfb5bbe8b1bd13cd +425, 0xb0bcb564e00214a0 +426, 0x6e9d330e742cf634 +427, 0x7b5b292cfa1b9430 +428, 0x5441cad8cf303e85 +429, 0x1762008ea3eefc9e +430, 0xa9ade7d73cb4296 +431, 0x98a6316562c0ea4f +432, 0xc51574eccad0e9fb +433, 0x677ec01be6893139 +434, 0xb0c7982fbaaee4a2 +435, 0xe07ed42cbb34d46c +436, 0xafc4634fa786c32d +437, 0xdaf8b97e6ad7e018 +438, 0x6267f0706ae3a607 +439, 0xca07bd40f70c2e9e +440, 0x4b25e8c7869abc8e +441, 0xabbb474aa737636e +442, 0x410f530d20a6769f +443, 0xee7d10dba29880d5 +444, 0x61f91eb2ebc3c39e +445, 0xc02d21d44c280731 +446, 0x7ca6f8eb9d6d3abe +447, 0x5e3fc57fc5b3ab03 +448, 0xc4b0f5d5d2655632 +449, 0x9b57a16a81ad63b9 +450, 0xc4732d2261781084 +451, 0xbd26679e27f54c19 +452, 0x8eef61d7a56c9d2d +453, 0x950e4be078a1d146 +454, 0x672e35b94cfafe9 +455, 0x79076d70ef347878 +456, 0x8d0158c3b7af319a +457, 0x9f9f475701b78fbd +458, 0x15768b3aabdb75e1 +459, 0x9f00af1f73d4209c +460, 0x680f425ca7814aa5 +461, 0x4501ef424a132af8 +462, 0xc57a90ca7cec1f2f +463, 0x708bfd7448c14dd1 +464, 0x3bfcbe7c8840456 +465, 0x6f97402f07bde0a0 +466, 0x8027440e4b178a21 +467, 0x94e947eb94a1c33f +468, 0xa99d1ab0d9e32c23 +469, 0x3240cb605f629e2a +470, 0x414086506367a711 +471, 0xb9186fe6279d4965 +472, 0x3f21caccdeb1c91a +473, 0x13554b8865e173ec +474, 0x867beb29cf375a21 +475, 0x1f27821ee23885b7 +476, 0xc64f09efbf1b5c69 +477, 0xc8f96ad307b1eaee +478, 0xea9040a44f9765f2 +479, 0xdf9c784d488953c8 +480, 0xa010bdbdce78972f +481, 0xbb8ab6017fcb7e5c +482, 0x8584f4844ad95ef6 +483, 0xc319e59b7efd9aad +484, 0x7ab487076c4a148f +485, 0xe5d8c47faa0488a0 +486, 0x4077092e33a0457a +487, 0x1bf7e7c4f615d7c4 +488, 0xea03b4fb0f4c3902 +489, 0xee72742384d93cc +490, 0x5bdae630f24c703b +491, 0x4d47db7fd176b322 +492, 0x4457f591923d3714 +493, 0x4a5cb51e0ce52280 +494, 0x16021446e36cf9ab +495, 0x87c563540c39d952 +496, 0x18c0cbfa66b443eb +497, 0xa3edd3ce7632c1f2 +498, 0x2921b28c42e77852 +499, 0xc72e3be0072541bf +500, 0x988c2deed5403283 +501, 0x510b8765988cd3ad +502, 0xa86ee406bfa09364 +503, 0xae5e6c62df70a308 +504, 0x28d4790520331444 +505, 0xbb1a0474b2f407d4 +506, 0x6bcfae4cf73c59cd +507, 0x36695e04107a9f5f +508, 0x5b1e9ad38395f724 +509, 0xd3157c290d299f2 +510, 0xd084175fa8220b7b +511, 0x76b0399bdfb66af2 +512, 0x29c3425c62e361ca +513, 0xe4bf2b3494a19bd8 +514, 0xc9d57df374baba6b +515, 0xdcee5e50619bf223 +516, 0xa3ba78fa885e6a72 +517, 0xbf34ea44695a8f30 +518, 0x5ddde2254aff3d06 +519, 0x6d1f3041e9879f3 +520, 0xaccd25b0875c2d89 +521, 0xefa539c60700018d +522, 0x7d3764e10c6d733b +523, 0x367d61076fe9c3c0 +524, 0x4657ab485775ed78 +525, 0x1ba7888d4f32d223 +526, 0x24ee78667fd08a50 +527, 0xfad3ba97460fae93 +528, 0x4dd200f3b026d7dc +529, 0x9d4e33c5fef7953f +530, 0x2ca6fd68615253c9 +531, 0xe3d16805a894838e +532, 0x10db3a0c972ecdc8 +533, 0x4090524fc5355e3c +534, 0x27385eae6f429d47 +535, 0x50af78ddc8681d35 +536, 0x1ebe6ea924bcd104 +537, 0x75423f64f5df83e7 +538, 0x876c4860427c720f +539, 0x8dc8f9407e27a179 +540, 0xedcd4c67c2676676 +541, 0x3341e48a470ebdb8 +542, 0xd4f63685f508ba66 +543, 0x3f6e375d68e34845 +544, 0x11b33ca59e6c3241 +545, 0x40189f7217f8137a +546, 0x916b0c45129e9a53 +547, 0xc1e91440f5b713bb +548, 0x414652f46a900767 +549, 0x33310db43b11e46f +550, 0xff1503c244b4b868 +551, 0x669e43bc981f4223 +552, 0xe27d487e222dc483 +553, 0xb2ae0efe4fef9eae +554, 0xd8dd8b215c1cfe79 +555, 0x16a80138d4ddcedd +556, 0xbc6a70ac7a4bcda5 +557, 0x18d80787abf2acfc +558, 0xecd0532537c2d3cc +559, 0x993800a80d4446f4 +560, 0x4ea5aeea9f43526 +561, 0x5a8031685b0c1463 +562, 0x31f108fa80921689 +563, 0xb9709186be75599f +564, 0x3adff9562a928b69 +565, 0x190d15108d41eb7 +566, 0xea7591506a38e4c7 +567, 0x4c91ea0a6340a8c3 +568, 0x919c67ef7a244bbf +569, 0xe6a76f184ad3d2b +570, 0x3a9640c5bed1edbc +571, 0x506ebd2fe9ef89e8 +572, 0x4d0796896388d9c4 +573, 0x2de4c110f7d7d112 +574, 0xe46c7b927d9f79a9 +575, 0xbf0ae3712f8eeae1 +576, 0x3b2984ee35da6a32 +577, 0xc59345b1697baef0 +578, 0xa3473fb9f81cc2df +579, 0x4454c552a21d642f +580, 0xca1636a3e911c77f +581, 0x2d9b63fde30e80fc +582, 0xaef85088f4d559f1 +583, 0x46544642eecad016 +584, 0x4da4f3f6afd9956 +585, 0xe6e375ac0867fc0a +586, 0x37d32889b072031e +587, 0x83fc712194bb9b4f +588, 0x9fa04dcc1f546c93 +589, 0x11c7883dc79aa96f +590, 0x1a71d76e8ea10b7c +591, 0x718279514561c06a +592, 0xc664454f1de48c18 +593, 0x945794f5dbc5b9b9 +594, 0x3cb32ee274775b53 +595, 0x571676c238e946b6 +596, 0x903cb8f8a39a1994 +597, 0xe63cdce42313cb65 +598, 0xddf3163b47ec269d +599, 0xb2c5a360383dd417 +600, 0x7bbf55331e3acb3e +601, 0x5c03cfbcc662c4b3 +602, 0x8cee8a1ce27b0fd0 +603, 0xb3e4f5dcce5e41de +604, 0xa3c560c653f8d148 +605, 0x9b0803f47ddbbd92 +606, 0x73598c03ae44f0c5 +607, 0xeda1ffa390632e00 +608, 0x1110571306d5e9c0 +609, 0x41ed218f2f65a1b5 +610, 0xe07441e90b230c6e +611, 0xcde6847873992446 +612, 0xb7d9b5ee4e941a3f +613, 0x5c9e0ac35e79e606 +614, 0x168d3790aca61ccc +615, 0x1846981baa478e7c +616, 0xc1689be15fa49372 +617, 0xddcb4e9701381927 +618, 0xa01ea97bce8344ff +619, 0xbaf44781cab34255 +620, 0xec241fa1a79901d1 +621, 0xea98acc2951f15ac +622, 0x1494afaba64e4697 +623, 0xda5136456a210ac1 +624, 0x5fa20a363997390d +625, 0xb53bbf197e19ce07 +626, 0xde0f31128a00cca2 +627, 0xc605fd5f98698e2a +628, 0x6796d5719b95d97c +629, 0xee44914e65e92f5a +630, 0xb0054098c1bddbe2 +631, 0xad7700d59df9004b +632, 0xcdf1288400a36d30 +633, 0x8b0f55466049fde1 +634, 0xab9410d6a2a28f3e +635, 0x4b5adce26df9bbee +636, 0xb16dcc4180dc7bb7 +637, 0x7657f9213f0dc5e2 +638, 0xc1eb5760b0852f85 +639, 0x8fb3fe1d0faec1d9 +640, 0x2dbbb8a4882f96dd +641, 0xf4ecd3eaf395f8fa +642, 0xb258df3c504f12e0 +643, 0x7ac9b40c8f945ed6 +644, 0x8f134be6970b05d9 +645, 0x6ecc9666da7fa595 +646, 0x133361dfb73314dd +647, 0xb8721ed39e997436 +648, 0x656883492dc738b9 +649, 0x174a3c8f99bf9b85 +650, 0xc09ef0f2df044a07 +651, 0x28c7a240745dff8c +652, 0x176441c5299c7c50 +653, 0x8f42c91c5e888ade +654, 0x1512801d9d3d0953 +655, 0x443640b3f1c700f +656, 0xd83f359def440e5f +657, 0x9fe61cf5cc1c3aa2 +658, 0xff32bae693ac2f8c +659, 0xb4c4595dd221d70a +660, 0xd3437b597e7286c8 +661, 0x2510f2ff588244d8 +662, 0x886154af6e3c0192 +663, 0xd6725d1af0c4a779 +664, 0x4874ef6b5ef6f9e3 +665, 0xbb987030fc6d4ede +666, 0xa0143e44289ccb48 +667, 0xca3de9e602373a89 +668, 0x78a50b8eed52c7c +669, 0x7bc6b4f801904167 +670, 0x9d14d691cb0acee5 +671, 0x53d9784fdefd3fa7 +672, 0x2b5457b8912e9095 +673, 0x41f3614d5840ec5 +674, 0xdb1d447cd66f3375 +675, 0x80f3770ee7d84b3f +676, 0xab9863f7e5a52eae +677, 0xfc078f48c4b21252 +678, 0xd360cf3d61a05da2 +679, 0xb31a15784218b1b6 +680, 0xdc0a6e5e7a89bf5a +681, 0xea18995b334e9d69 +682, 0x3e07c668b1f71a31 +683, 0x4ecf7c96be3b06e7 +684, 0xeb3f4dbab3912a0c +685, 0xf3adfd6a616308c5 +686, 0x7478bc40793ad794 +687, 0xeedca7d9bc381ea9 +688, 0x7b5a77d7b42cc04e +689, 0xd66ffb33bd6e5616 +690, 0x48d8ef97ac2d0ff7 +691, 0xb1c85985725cab07 +692, 0x669a9762479ad88f +693, 0x22e49f0ceddf433c +694, 0xb78bf3ac7e020fc9 +695, 0x3c4939f7654e38d7 +696, 0x6ba6b31e431bf01 +697, 0xe55d5f4848c9e979 +698, 0x5e943e51c4223664 +699, 0x7385c2084ba55b84 +700, 0xedae6a69b96c4181 +701, 0x5498b7fd55f464b4 +702, 0xd889c1a2eb452455 +703, 0x189fd7411f0f9003 +704, 0xd26ce80a290a614a +705, 0xe17114fdc506bf73 +706, 0xe9e4b0ef791be2f7 +707, 0xcf9fa23043d230e5 +708, 0x3a8dac60f4791a0b +709, 0xbefc5e64f0603b04 +710, 0x41e622805a016bb2 +711, 0x8a57df661b57fa6f +712, 0x13a30bb387257625 +713, 0x52a45137bdc9d9d7 +714, 0x6385fcd7f91189f0 +715, 0xb18c44ec584e6de7 +716, 0x6335807f6d6b86fd +717, 0xd573fb71853ef93a +718, 0xf6171462c9f74a61 +719, 0x10089f2cad628d2f +720, 0x96b8d5937d722b85 +721, 0x7376821fe68a497f +722, 0xb752bcac1c64da57 +723, 0x2a043c4fd7c56683 +724, 0xb9acd886078b8ca8 +725, 0xa137bfd64a2aabfa +726, 0x7b616af852cfb604 +727, 0x851d36fd60a7a376 +728, 0x1f6612c681686473 +729, 0xeb70d6175c3f21a3 +730, 0x38df2476423bb985 +731, 0x1c8946a1d708676a +732, 0xe3857fbe776fbcf0 +733, 0x4bccfabc6a7aa9f6 +734, 0xaa79d49af3fb0ad9 +735, 0x8a90ac2c9062949 +736, 0x1bef9e17f6abd7ac +737, 0x5f834c276df092ed +738, 0x57451b8f37c655de +739, 0x9b37a62f91df1c6b +740, 0xfea0e5e928521dd1 +741, 0x30ae26af2d3d3066 +742, 0x90c7f4fe041cc96f +743, 0xae3d8a1af5e89491 +744, 0x8654f2cadce2dce3 +745, 0x45b460f2bd49bf46 +746, 0xbb29582042d003d3 +747, 0x29cd1be694c5c95f +748, 0xbc0ae7374b735c03 +749, 0x4db1a0bc64758878 +750, 0x122c278b74b518c4 +751, 0x4a94e6b50bf51213 +752, 0xf408489bdda60454 +753, 0x791c5da3bf67cb99 +754, 0x83b85caa737261f3 +755, 0x619fe26f59c92f28 +756, 0x6f24d7563749d335 +757, 0x4d5224b378f4356d +758, 0xa80dece2650eccfe +759, 0xc537fb63fd483efd +760, 0x28c5c3cdb5ae2df7 +761, 0xcd66fbab1368c7aa +762, 0xf2abd0adff7069ca +763, 0x152fee808d76d3ab +764, 0x2f21b3a82acb2d08 +765, 0x7eafb15d34cfad1e +766, 0xa7f1608a241eab5e +767, 0xe030095ce12c4c10 +768, 0xa0d6ae018a94f4fb +769, 0x908e2ddca49b6b27 +770, 0x160e2f0b13791c01 +771, 0xc94bcaab64d37b36 +772, 0x9b6d2771f3cab823 +773, 0x877e720beca0fa5e +774, 0xeab6a692db2c4bb2 +775, 0xbe7c0b35f9c454dd +776, 0xafd9faefc3c2e26f +777, 0xc0b313e172484781 +778, 0x802ab792f708ee16 +779, 0x9bb8a1c513145652 +780, 0xb3bb6fbd9ac8b1f5 +781, 0xfd1222d31160e2ac +782, 0x9e8def9378eb0567 +783, 0x4cb5047d3e7613e9 +784, 0xe870feca80e56b98 +785, 0xa6b53c45c84d5b1b +786, 0x2cccb2ab07159ff1 +787, 0xbc1532a0b621d08c +788, 0xc17f60e6e631228c +789, 0xe231bf2fa4ed9790 +790, 0x9650d2546468aea4 +791, 0x78ed0341e62b1f36 +792, 0x564786e0f06f2136 +793, 0xad67f8e36f21e2a6 +794, 0x14aca551dc2007f4 +795, 0xdaaf21ba99a85718 +796, 0x801993a2b9ccd054 +797, 0xc081b520e3351ae4 +798, 0xb4c2c3a575d98933 +799, 0xee0febb05021f5d9 +800, 0xa8e9bf042c8524c2 +801, 0x62a4e29d5e5b0e32 +802, 0xca47dc23b3267d2d +803, 0x7dcda2032acfb297 +804, 0x707edefabc363d8c +805, 0x66ae33b39d40cc26 +806, 0x29af2f7a0dbe3c6c +807, 0x45bd35e7e7fe3fc8 +808, 0xe2be9934a9386886 +809, 0x1369a648c1f66d4 +810, 0x36771ede37f6912d +811, 0x29f125e90e92f06a +812, 0xdf2517a841fe4c35 +813, 0xa07e77e5ac2fa24d +814, 0xaafc1ab2e8914f7e +815, 0x64d602ea8eab3138 +816, 0x7dcc67358db459b7 +817, 0x18b3c0f3e2ddc176 +818, 0x3186ebc761499532 +819, 0x26eae2da284bf1fc +820, 0x2fce764273c3afe8 +821, 0x8d14d487425c3e78 +822, 0x515162b0ca58a70e +823, 0xc9a51fd0466b0019 +824, 0x6928f5af5674a4a2 +825, 0x23aec98e1759caa1 +826, 0x438f9a8f033d4511 +827, 0x8a6314a76994c55e +828, 0xa3bef565e65855a2 +829, 0x251c36d1deb6face +830, 0x221f06d4847ef177 +831, 0x29741abb3ab9b4e4 +832, 0x93c9827eacaa262f +833, 0x9d91f19aace9c4c9 +834, 0x30038d3da09b76e +835, 0xcddf978db05ec6cb +836, 0x798aa80467245bdf +837, 0x9c26179d57a6263b +838, 0x2cbdb745276e1c2b +839, 0xee549998a174e7c5 +840, 0x707933d84e48e90 +841, 0xc1925775d969b667 +842, 0xbac030db93b43a38 +843, 0xa478f204b04d5963 +844, 0xecfc1e66fa00531b +845, 0x4771b36479d16c0c +846, 0xfa28373c9c035622 +847, 0xc89c89a3ee2b5365 +848, 0x88a4066f98fa60a2 +849, 0x3d3395c78b0a0111 +850, 0xed59a448861220b6 +851, 0x97574be1b4fbf7cc +852, 0xe63d52a637907a6b +853, 0x5ba45d5ae3d14fcd +854, 0xecfff9b9ce46e911 +855, 0x1aff395024e1670f +856, 0x80735f71f452b8d0 +857, 0xb35665e1a7090637 +858, 0xb6fc2f8eafbdb100 +859, 0x1f72a04d1ac1ec24 +860, 0xdc6a743a6dfc9a65 +861, 0xc1f2e21f56bf953b +862, 0x3861b9573b9b211f +863, 0x1b0b5ebe315c8de6 +864, 0x4a2474209eefeb20 +865, 0x8bf700bea8771d57 +866, 0x5c826e1b9d96e021 +867, 0x3c550882c3e60dd3 +868, 0xbcfc1b474082e0b +869, 0x36328eb420971300 +870, 0x31f955615998d5c0 +871, 0xefc881172a488a7a +872, 0x8ae7f46c694723a3 +873, 0x71642de55998b04a +874, 0x43af19c9ce33d752 +875, 0xb489c13374abc234 +876, 0x3691de307b663328 +877, 0xeef765a5e6839de2 +878, 0xdceb9040010939ee +879, 0xc402cd11b98f0ab7 +880, 0x714e9a2cb8f045e +881, 0xf0cabb6fe1a41f30 +882, 0xcf41bc2a41ecfb57 +883, 0x62c24ff5eeb1048b +884, 0x74a62a4266a09c41 +885, 0xa6ddcbcf7c7af5f4 +886, 0x8534a3d967991eb1 +887, 0xe43dbafd0a4c9311 +888, 0xc0d713b3b8d9dd68 +889, 0x174a9b2d277e1f +890, 0x8573edcbab177db6 +891, 0x1bcff4d3595158e6 +892, 0x84e938887e7c6066 +893, 0x354130c60d728871 +894, 0xb8dd477ccc07d2a0 +895, 0xc1e30214f9d75b60 +896, 0xce4977c3d243d7fb +897, 0xf93ba43fa22155b7 +898, 0x1cd39a9065bed6c4 +899, 0x1677daec8a3647cc +900, 0xce08f421c19266ae +901, 0xca3ca9ebd2a2669d +902, 0x7eb68405132fca15 +903, 0x18168b0f0ce8d315 +904, 0xdf241f3d574a968e +905, 0xe2fa2207e0dbc86a +906, 0xb8bfb68c1ee88be6 +907, 0xc386a425a0e8ec8b +908, 0xf60e7ea66674e122 +909, 0xd6b7820405c40e8 +910, 0x84bd5fac533797e7 +911, 0x5acfd875363dcfdb +912, 0xd0cab73b1d04d65d +913, 0x8d5cd9a81de7cc92 +914, 0x816b262b71097355 +915, 0x2d28470f662f3ef7 +916, 0xc7ef80c95a450030 +917, 0x18be275d375e8d38 +918, 0x4ebbb686e2fe3832 +919, 0xa15f1c5068711bf +920, 0x6e3e14f47aab4b11 +921, 0x51d2f11208103b72 +922, 0x4083a7d5788b72f5 +923, 0x5037780b542dc8ce +924, 0x1df9802ce8610192 +925, 0xba270a3bcbb59d80 +926, 0xce0459574f8a37c +927, 0x543aaf1a28480574 +928, 0xea92b1cf98896d16 +929, 0x6bfd3baae08a2060 +930, 0x5d9a2b2b76d4ed11 +931, 0x8de7686a95d09d5 +932, 0x392e959b78286928 +933, 0x98fc7a7d1a82e0b5 +934, 0x23f25d04738d1d6d +935, 0x507922d324dd1207 +936, 0xef809cf741419ad7 +937, 0x3a3ffc65ef3365f3 +938, 0x3eb258435905713f +939, 0x242386e52078bd9c +940, 0xa3941556020beac4 +941, 0xbbb020f8e5f4aee2 +942, 0x3373440701bbd45e +943, 0xa6a36308592401f3 +944, 0x20e5642bed30990a +945, 0x6c3cce6f512f0c30 +946, 0x61b470467a590ea3 +947, 0xff15bf7dc3ffccb2 +948, 0x23a3c0663725715f +949, 0x197ea4c617f88f31 +950, 0x6412abc6b559972e +951, 0x5e963b8491f05790 +952, 0x7b837bd7e43c7b83 +953, 0xccde4023d6b2ba81 +954, 0xa39f9c1d210fdfed +955, 0xa413f619bdd49c28 +956, 0xd2096d2202caee6c +957, 0xbbdbb1f4178b9ec4 +958, 0x77d3deb9828dc7ec +959, 0xdb311ba28eb9b8bf +960, 0x781905616be8bc25 +961, 0xf7b401fdce0928ac +962, 0xa29286d380c51201 +963, 0x4f6790854c5fcf9e +964, 0x95b7e3793eceab8f +965, 0x77097d01be05b8fd +966, 0xea6645235d898393 +967, 0xc260212650bb4196 +968, 0xab028439386af2a1 +969, 0xb9c99c6cb6bac542 +970, 0x44597a7ac513a707 +971, 0x7c3503863d73196a +972, 0x5310606fb739afa0 +973, 0x2b9a1a30b2b82283 +974, 0x442c9600d98d3fd4 +975, 0x56dbbb72bd2fb227 +976, 0x9e137b63c9dfbd47 +977, 0x8c432826c8059484 +978, 0x2a581bd76096803 +979, 0x9bced11dd3da15d4 +980, 0x448d0782fa0e2d56 +981, 0x6fe223ed7981de88 +982, 0xa11abc8ebee400d0 +983, 0x70cfca3c8008b197 +984, 0x6de64d935456ab83 +985, 0x726bdd86810c0d6a +986, 0x1077e0584ccc4150 +987, 0x64fa38092b2316f9 +988, 0xe3ef337ecdc3b8c5 +989, 0xebc0452bc41c192a +990, 0x2a81ecd193ab45f9 +991, 0xeb6038f45a865c3a +992, 0xe7f1e1b3600ec5d2 +993, 0x16897e3406fe264c +994, 0x2768a1d17fb81ddb +995, 0x9965317d69c47896 +996, 0x949e16bd19a6c53b +997, 0x81cc74cdf8fe59ea +998, 0x180ade029d93ddc6 +999, 0xcfe8717315f3ca1f diff --git a/_randomgen/randomgen/tests/test_direct.py b/_randomgen/randomgen/tests/test_direct.py index be4f533eadc5..ee69d54163b1 100644 --- a/_randomgen/randomgen/tests/test_direct.py +++ b/_randomgen/randomgen/tests/test_direct.py @@ -8,7 +8,8 @@ import pytest from randomgen import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ - PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024 + PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024, Xoshiro256StarStar, \ + Xoshiro512StarStar if (sys.version_info > (3, 0)): long = int @@ -227,6 +228,32 @@ def setup_class(cls): cls.seed_error_type = TypeError +class TestXoshiro256StarStar(Base): + @classmethod + def setup_class(cls): + cls.brng = Xoshiro256StarStar + cls.bits = 64 + cls.dtype = np.uint64 + cls.data1 = cls._read_csv( + join(pwd, './data/xoshiro256starstar-testset-1.csv')) + cls.data2 = cls._read_csv( + join(pwd, './data/xoshiro256starstar-testset-2.csv')) + cls.seed_error_type = TypeError + + +class TestXoshiro512StarStar(Base): + @classmethod + def setup_class(cls): + cls.brng = Xoshiro512StarStar + cls.bits = 64 + cls.dtype = np.uint64 + cls.data1 = cls._read_csv( + join(pwd, './data/xoshiro512starstar-testset-1.csv')) + cls.data2 = cls._read_csv( + join(pwd, './data/xoshiro512starstar-testset-2.csv')) + cls.seed_error_type = TypeError + + class TestXorshift1024(Base): @classmethod def setup_class(cls): diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 2ab6bd2d326f..6e5e7cf87a15 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -572,7 +572,8 @@ def test_choice_return_shape(self): assert_equal(mt19937.randint(10, 10, size=0).shape, (0,)) assert_equal(mt19937.choice(0, size=0).shape, (0,)) assert_equal(mt19937.choice([], size=(0,)).shape, (0,)) - assert_equal(mt19937.choice(['a', 'b'], size=(3, 0, 4)).shape, (3, 0, 4)) + assert_equal(mt19937.choice(['a', 'b'], size=(3, 0, 4)).shape, + (3, 0, 4)) assert_raises(ValueError, mt19937.choice, [], 10) def test_bytes(self): diff --git a/_randomgen/randomgen/tests/test_smoke.py b/_randomgen/randomgen/tests/test_smoke.py index 99f218181d89..5a9882a16aed 100644 --- a/_randomgen/randomgen/tests/test_smoke.py +++ b/_randomgen/randomgen/tests/test_smoke.py @@ -10,7 +10,8 @@ from randomgen._testing import suppress_warnings from randomgen import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ - PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024 + PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024, Xoshiro256StarStar, \ + Xoshiro512StarStar from randomgen import entropy @@ -100,6 +101,17 @@ def warmup(rg, n=None): class RNG(object): + @classmethod + def setup_class(cls): + # Overridden in test classes. Place holder to silence IDE noise + cls.brng = Xoshiro256StarStar + cls.advance = None + cls.seed = [12345] + cls.rg = RandomGenerator(cls.brng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = 64 + cls._extra_setup() + @classmethod def _extra_setup(cls): cls.vec_1d = np.arange(2.0, 102.0) @@ -121,25 +133,27 @@ def test_init(self): def test_advance(self): state = self.rg.state - if hasattr(self.rg, 'advance'): - self.rg.advance(self.advance) + if hasattr(self.rg._basicrng, 'advance'): + self.rg._basicrng.advance(self.advance) assert_(not comp_state(state, self.rg.state)) else: - pytest.skip() + brng_name = self.rg._basicrng.__class__.__name__ + pytest.skip('Advance is not supported by {0}'.format(brng_name)) def test_jump(self): state = self.rg.state - if hasattr(self.rg, 'jump'): - self.rg.jump() + if hasattr(self.rg._basicrng, 'jump'): + self.rg._basicrng.jump() jumped_state = self.rg.state assert_(not comp_state(state, jumped_state)) self.rg.random_sample(2 * 3 * 5 * 7 * 11 * 13 * 17) self.rg.state = state - self.rg.jump() + self.rg._basicrng.jump() rejumped_state = self.rg.state assert_(comp_state(jumped_state, rejumped_state)) else: - pytest.skip() + brng_name = self.rg._basicrng.__class__.__name__ + pytest.skip('Jump is not supported by {0}'.format(brng_name)) def test_random_uintegers(self): assert_(len(self.rg.random_uintegers(10)) == 10) @@ -546,7 +560,9 @@ def test_pickle(self): def test_seed_array(self): if self.seed_vector_bits is None: - pytest.skip() + brng_name = self.brng.__name__ + pytest.skip('Vector seeding is not supported by ' + '{0}'.format(brng_name)) if self.seed_vector_bits == 32: dtype = np.uint32 @@ -896,7 +912,7 @@ class TestPhilox(RNG): @classmethod def setup_class(cls): cls.brng = Philox - cls.advance = None + cls.advance = 2**63 + 2**31 + 2**15 + 1 cls.seed = [12345] cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state @@ -908,7 +924,7 @@ class TestThreeFry(RNG): @classmethod def setup_class(cls): cls.brng = ThreeFry - cls.advance = None + cls.advance = 2 ** 63 + 2 ** 31 + 2 ** 15 + 1 cls.seed = [12345] cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state @@ -928,6 +944,30 @@ def setup_class(cls): cls._extra_setup() +class TestXoshiro256StarStar(RNG): + @classmethod + def setup_class(cls): + cls.brng = Xoshiro256StarStar + cls.advance = None + cls.seed = [12345] + cls.rg = RandomGenerator(cls.brng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = 64 + cls._extra_setup() + + +class TestXoshiro512StarStar(RNG): + @classmethod + def setup_class(cls): + cls.brng = Xoshiro512StarStar + cls.advance = None + cls.seed = [12345] + cls.rg = RandomGenerator(cls.brng(*cls.seed)) + cls.initial_state = cls.rg.state + cls.seed_vector_bits = 64 + cls._extra_setup() + + class TestXorshift1024(RNG): @classmethod def setup_class(cls): @@ -956,7 +996,7 @@ class TestThreeFry32(RNG): @classmethod def setup_class(cls): cls.brng = ThreeFry32 - cls.advance = [2 ** 96 + 2 ** 16 + 2 ** 5 + 1] + cls.advance = 2**63 + 2**31 + 2**15 + 1 cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.initial_state = cls.rg.state diff --git a/_randomgen/randomgen/threefry.pyx b/_randomgen/randomgen/threefry.pyx index e8971ff42161..cb3c78f5bfbf 100644 --- a/_randomgen/randomgen/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -319,7 +319,7 @@ cdef class ThreeFry: self.rng_state.uinteger = value['uinteger'] self.rng_state.buffer_pos = value['buffer_pos'] - def jump(self, np.npy_intp iter): + def jump(self, np.npy_intp iter=1): """ jump(iter=1) diff --git a/_randomgen/randomgen/threefry32.pyx b/_randomgen/randomgen/threefry32.pyx index 512ce9d00d3b..62c0e9cd8c92 100644 --- a/_randomgen/randomgen/threefry32.pyx +++ b/_randomgen/randomgen/threefry32.pyx @@ -314,7 +314,7 @@ cdef class ThreeFry32: self.rng_state.buffer[i] = value['buffer'][i] self.rng_state.buffer_pos = value['buffer_pos'] - def jump(self, np.npy_intp iter): + def jump(self, np.npy_intp iter=1): """ jump(iter=1) diff --git a/_randomgen/randomgen/xoshiro256starstar.pyx b/_randomgen/randomgen/xoshiro256starstar.pyx new file mode 100644 index 000000000000..33ecb50f1a88 --- /dev/null +++ b/_randomgen/randomgen/xoshiro256starstar.pyx @@ -0,0 +1,362 @@ +from __future__ import absolute_import + +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + +import numpy as np +cimport numpy as np + +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t +from randomgen.entropy import random_entropy, seed_by_array +import randomgen.pickle + +np.import_array() + +cdef extern from "src/xoshiro256starstar/xoshiro256starstar.h": + + struct s_xoshiro256starstar_state: + uint64_t s[4] + int has_uint32 + uint32_t uinteger + + ctypedef s_xoshiro256starstar_state xoshiro256starstar_state + + uint64_t xoshiro256starstar_next64(xoshiro256starstar_state *state) nogil + uint32_t xoshiro256starstar_next32(xoshiro256starstar_state *state) nogil + void xoshiro256starstar_jump(xoshiro256starstar_state *state) + +cdef uint64_t xoshiro256starstar_uint64(void* st) nogil: + return xoshiro256starstar_next64(st) + +cdef uint32_t xoshiro256starstar_uint32(void *st) nogil: + return xoshiro256starstar_next32( st) + +cdef double xoshiro256starstar_double(void* st) nogil: + return uint64_to_double(xoshiro256starstar_next64(st)) + +cdef class Xoshiro256StarStar: + """ + Xoshiro256StarStar(seed=None) + + Container for the xoshiro256** pseudo-random number generator. + + Parameters + ---------- + seed : {None, int, array_like}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**64-1], array of integers in + [0, 2**64-1] or ``None`` (the default). If `seed` is ``None``, + then ``Xoshiro256StarStar`` will try to read data from + ``/dev/urandom`` (or the Windows analog) if available. If + unavailable, a 64-bit hash of the time and process ID is used. + + Notes + ----- + xoshiro256** is written by David Blackman and Sebastiano Vigna. + It is a 64-bit PRNG that uses a carefully linear transformation. + This produces a fast PRNG with excellent statistical quality + [1]_. xoshiro256** has a period of :math:`2^{256} - 1` + and supports jumping the sequence in increments of :math:`2^{128}`, + which allows multiple non-overlapping sequences to be generated. + + ``Xoshiro256StarStar`` exposes no user-facing API except ``generator``, + ``state``, ``cffi`` and ``ctypes``. Designed for use in a + ``RandomGenerator`` object. + + **Compatibility Guarantee** + + ``Xoshiro256StarStar`` guarantees that a fixed seed will always produce the + same results. + + See ``Xorshift1024`` for a related PRNG with different periods + (:math:`2^{1024} - 1`) and jump size (:math:`2^{512} - 1`). + + **Parallel Features** + + ``Xoshiro256StarStar`` can be used in parallel applications by + calling the method ``jump`` which advances the state as-if + :math:`2^{128}` random numbers have been generated. This + allow the original sequence to be split so that distinct segments can be used + in each worker process. All generators should be initialized with the same + seed to ensure that the segments come from the same sequence. + + >>> from randomgen import RandomGenerator, Xoshiro256StarStar + >>> rg = [RandomGenerator(Xoshiro256StarStar(1234)) for _ in range(10)] + # Advance rs[i] by i jumps + >>> for i in range(10): + ... rg[i].jump(i) + + **State and Seeding** + + The ``Xoshiro256StarStar`` state vector consists of a 4 element array + of 64-bit unsigned integers. + + ``Xoshiro256StarStar`` is seeded using either a single 64-bit unsigned + integer or a vector of 64-bit unsigned integers. In either case, the + input seed is used as an input (or inputs) for another simple random + number generator, Splitmix64, and the output of this PRNG function is + used as the initial state. Using a single 64-bit value for the seed can + only initialize a small range of the possible initial state values. When + using an array, the SplitMix64 state for producing the ith component of + the initial state is XORd with the ith value of the seed array until the + seed array is exhausted. When using an array the initial state for the + SplitMix64 state is 0 so that using a single element array and using the + same value as a scalar will produce the same initial state. + + Examples + -------- + >>> from randomgen import RandomGenerator, Xoshiro256StarStar + >>> rg = RandomGenerator(Xoshiro256StarStar(1234)) + >>> rg.standard_normal() + + Identical method using only Xoshiro256StarStar + + >>> rg = Xoshiro256StarStar(1234).generator + >>> rg.standard_normal() + + References + ---------- + .. [1] "xoroshiro+ / xorshift* / xorshift+ generators and the PRNG shootout", + http://xorshift.di.unimi.it/ + """ + cdef xoshiro256starstar_state *rng_state + cdef brng_t *_brng + cdef public object capsule + cdef object _ctypes + cdef object _cffi + cdef object _generator + + def __init__(self, seed=None): + self.rng_state = malloc(sizeof(xoshiro256starstar_state)) + self._brng = malloc(sizeof(brng_t)) + self.seed(seed) + + self._brng.state = self.rng_state + self._brng.next_uint64 = &xoshiro256starstar_uint64 + self._brng.next_uint32 = &xoshiro256starstar_uint32 + self._brng.next_double = &xoshiro256starstar_double + self._brng.next_raw = &xoshiro256starstar_uint64 + + self._ctypes = None + self._cffi = None + self._generator = None + + cdef const char *name = "BasicRNG" + self.capsule = PyCapsule_New(self._brng, name, NULL) + + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), + self.state) + + def __dealloc__(self): + free(self.rng_state) + free(self._brng) + + cdef _reset_state_variables(self): + self.rng_state.has_uint32 = 0 + self.rng_state.uinteger = 0 + + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): + """Private benchmark command""" + cdef Py_ssize_t i + if method==u'uint64': + for i in range(cnt): + self._brng.next_uint64(self._brng.state) + elif method==u'double': + for i in range(cnt): + self._brng.next_double(self._brng.state) + else: + raise ValueError('Unknown method') + + def seed(self, seed=None): + """ + seed(seed=None) + + Seed the generator. + + This method is called at initialized. It can be called again to + re-seed the generator. + + Parameters + ---------- + seed : {int, ndarray}, optional + Seed for PRNG. Can be a single 64 bit unsigned integer or an array + of 64 bit unsigned integers. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + """ + ub = 2 ** 64 + if seed is None: + try: + state = random_entropy(8) + except RuntimeError: + state = random_entropy(8, 'fallback') + state = state.view(np.uint64) + else: + state = seed_by_array(seed, 4) + self.rng_state.s[0] = int(state[0]) + self.rng_state.s[1] = int(state[1]) + self.rng_state.s[2] = int(state[2]) + self.rng_state.s[3] = int(state[3]) + self._reset_state_variables() + + def jump(self, np.npy_intp iter=1): + """ + jump(iter=1) + + Jumps the state as-if 2**128 random numbers have been generated. + + Parameters + ---------- + iter : integer, positive + Number of times to jump the state of the rng. + + Returns + ------- + self : Xoshiro256StarStar + PRNG jumped iter times + + Notes + ----- + Jumping the rng state resets any pre-computed random numbers. This is required + to ensure exact reproducibility. + """ + cdef np.npy_intp i + for i in range(iter): + xoshiro256starstar_jump(self.rng_state) + self._reset_state_variables() + return self + + @property + def state(self): + """ + Get or set the PRNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the PRNG + """ + state = np.empty(4, dtype=np.uint64) + state[0] = self.rng_state.s[0] + state[1] = self.rng_state.s[1] + state[2] = self.rng_state.s[2] + state[3] = self.rng_state.s[3] + return {'brng': self.__class__.__name__, + 's': state, + 'has_uint32': self.rng_state.has_uint32, + 'uinteger': self.rng_state.uinteger} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + brng = value.get('brng', '') + if brng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + self.rng_state.s[0] = value['s'][0] + self.rng_state.s[1] = value['s'][1] + self.rng_state.s[2] = value['s'][2] + self.rng_state.s[3] = value['s'][3] + self.rng_state.has_uint32 = value['has_uint32'] + self.rng_state.uinteger = value['uinteger'] + + @property + def ctypes(self): + """ + Ctypes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + + if self._ctypes is not None: + return self._ctypes + + import ctypes + + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&xoshiro256starstar_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&xoshiro256starstar_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&xoshiro256starstar_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p(self._brng)) + return self.ctypes + + @property + def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + if self._cffi is not None: + return self._cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') + + ffi = cffi.FFI() + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) + return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : randomgen.generator.RandomGenerator + Random generator used this instance as the basic RNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator \ No newline at end of file diff --git a/_randomgen/randomgen/xoshiro512starstar.pyx b/_randomgen/randomgen/xoshiro512starstar.pyx new file mode 100644 index 000000000000..b4ab76158929 --- /dev/null +++ b/_randomgen/randomgen/xoshiro512starstar.pyx @@ -0,0 +1,356 @@ +from __future__ import absolute_import + +from libc.stdlib cimport malloc, free +from cpython.pycapsule cimport PyCapsule_New + +import numpy as np +cimport numpy as np + +from randomgen.common import interface +from randomgen.common cimport * +from randomgen.distributions cimport brng_t +from randomgen.entropy import random_entropy, seed_by_array +import randomgen.pickle + +np.import_array() + +cdef extern from "src/xoshiro512starstar/xoshiro512starstar.h": + + struct s_xoshiro512starstar_state: + uint64_t s[8] + int has_uint32 + uint32_t uinteger + + ctypedef s_xoshiro512starstar_state xoshiro512starstar_state + + uint64_t xoshiro512starstar_next64(xoshiro512starstar_state *state) nogil + uint32_t xoshiro512starstar_next32(xoshiro512starstar_state *state) nogil + void xoshiro512starstar_jump(xoshiro512starstar_state *state) + +cdef uint64_t xoshiro512starstar_uint64(void* st) nogil: + return xoshiro512starstar_next64(st) + +cdef uint32_t xoshiro512starstar_uint32(void *st) nogil: + return xoshiro512starstar_next32( st) + +cdef double xoshiro512starstar_double(void* st) nogil: + return uint64_to_double(xoshiro512starstar_next64(st)) + +cdef class Xoshiro512StarStar: + """ + Xoshiro512StarStar(seed=None) + + Container for the xoshiro512** pseudo-random number generator. + + Parameters + ---------- + seed : {None, int, array_like}, optional + Random seed initializing the pseudo-random number generator. + Can be an integer in [0, 2**64-1], array of integers in + [0, 2**64-1] or ``None`` (the default). If `seed` is ``None``, + then ``Xoshiro512StarStar`` will try to read data from + ``/dev/urandom`` (or the Windows analog) if available. If + unavailable, a 64-bit hash of the time and process ID is used. + + Notes + ----- + xoshiro512** is written by David Blackman and Sebastiano Vigna. + It is a 64-bit PRNG that uses a carefully linear transformation. + This produces a fast PRNG with excellent statistical quality + [1]_. xoshiro512** has a period of :math:`2^{512} - 1` + and supports jumping the sequence in increments of :math:`2^{256}`, + which allows multiple non-overlapping sequences to be generated. + + ``Xoshiro512StarStar`` exposes no user-facing API except ``generator``, + ``state``, ``cffi`` and ``ctypes``. Designed for use in a + ``RandomGenerator`` object. + + **Compatibility Guarantee** + + ``Xoshiro512StarStar`` guarantees that a fixed seed will always produce the + same results. + + See ``Xorshift1024`` for a related PRNG with different periods + (:math:`2^{1024} - 1`) and jump size (:math:`2^{512} - 1`). + + **Parallel Features** + + ``Xoshiro512StarStar`` can be used in parallel applications by + calling the method ``jump`` which advances the state as-if + :math:`2^{128}` random numbers have been generated. This + allow the original sequence to be split so that distinct segments can be used + in each worker process. All generators should be initialized with the same + seed to ensure that the segments come from the same sequence. + + >>> from randomgen import RandomGenerator, Xoshiro512StarStar + >>> rg = [RandomGenerator(Xoshiro512StarStar(1234)) for _ in range(10)] + # Advance rs[i] by i jumps + >>> for i in range(10): + ... rg[i].jump(i) + + **State and Seeding** + + The ``Xoshiro512StarStar`` state vector consists of a 4 element array + of 64-bit unsigned integers. + + ``Xoshiro512StarStar`` is seeded using either a single 64-bit unsigned + integer or a vector of 64-bit unsigned integers. In either case, the + input seed is used as an input (or inputs) for another simple random + number generator, Splitmix64, and the output of this PRNG function is + used as the initial state. Using a single 64-bit value for the seed can + only initialize a small range of the possible initial state values. When + using an array, the SplitMix64 state for producing the ith component of + the initial state is XORd with the ith value of the seed array until the + seed array is exhausted. When using an array the initial state for the + SplitMix64 state is 0 so that using a single element array and using the + same value as a scalar will produce the same initial state. + + Examples + -------- + >>> from randomgen import RandomGenerator, Xoshiro512StarStar + >>> rg = RandomGenerator(Xoshiro512StarStar(1234)) + >>> rg.standard_normal() + + Identical method using only Xoshiro512StarStar + + >>> rg = Xoshiro512StarStar(1234).generator + >>> rg.standard_normal() + + References + ---------- + .. [1] "xoroshiro+ / xorshift* / xorshift+ generators and the PRNG shootout", + http://xorshift.di.unimi.it/ + """ + cdef xoshiro512starstar_state *rng_state + cdef brng_t *_brng + cdef public object capsule + cdef object _ctypes + cdef object _cffi + cdef object _generator + + def __init__(self, seed=None): + self.rng_state = malloc(sizeof(xoshiro512starstar_state)) + self._brng = malloc(sizeof(brng_t)) + self.seed(seed) + + self._brng.state = self.rng_state + self._brng.next_uint64 = &xoshiro512starstar_uint64 + self._brng.next_uint32 = &xoshiro512starstar_uint32 + self._brng.next_double = &xoshiro512starstar_double + self._brng.next_raw = &xoshiro512starstar_uint64 + + self._ctypes = None + self._cffi = None + self._generator = None + + cdef const char *name = "BasicRNG" + self.capsule = PyCapsule_New(self._brng, name, NULL) + + # Pickling support: + def __getstate__(self): + return self.state + + def __setstate__(self, state): + self.state = state + + def __reduce__(self): + return (randomgen.pickle.__brng_ctor, + (self.state['brng'],), + self.state) + + def __dealloc__(self): + free(self.rng_state) + free(self._brng) + + cdef _reset_state_variables(self): + self.rng_state.has_uint32 = 0 + self.rng_state.uinteger = 0 + + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): + """Private benchmark command""" + cdef Py_ssize_t i + if method==u'uint64': + for i in range(cnt): + self._brng.next_uint64(self._brng.state) + elif method==u'double': + for i in range(cnt): + self._brng.next_double(self._brng.state) + else: + raise ValueError('Unknown method') + + def seed(self, seed=None): + """ + seed(seed=None) + + Seed the generator. + + This method is called at initialized. It can be called again to + re-seed the generator. + + Parameters + ---------- + seed : {int, ndarray}, optional + Seed for PRNG. Can be a single 64 bit unsigned integer or an array + of 64 bit unsigned integers. + + Raises + ------ + ValueError + If seed values are out of range for the PRNG. + """ + ub = 2 ** 64 + if seed is None: + try: + state = random_entropy(2 * 8) + except RuntimeError: + state = random_entropy(8, 'fallback') + state = state.view(np.uint64) + else: + state = seed_by_array(seed, 8) + for i in range(8): + self.rng_state.s[i] = int(state[i]) + self._reset_state_variables() + + def jump(self, np.npy_intp iter=1): + """ + jump(iter=1) + + Jumps the state as-if 2**256 random numbers have been generated. + + Parameters + ---------- + iter : integer, positive + Number of times to jump the state of the rng. + + Returns + ------- + self : Xoshiro512StarStar + PRNG jumped iter times + + Notes + ----- + Jumping the rng state resets any pre-computed random numbers. This is required + to ensure exact reproducibility. + """ + cdef np.npy_intp i + for i in range(iter): + xoshiro512starstar_jump(self.rng_state) + self._reset_state_variables() + return self + + @property + def state(self): + """ + Get or set the PRNG state + + Returns + ------- + state : dict + Dictionary containing the information required to describe the + state of the PRNG + """ + state = np.empty(8, dtype=np.uint64) + for i in range(8): + state[i] = self.rng_state.s[i] + return {'brng': self.__class__.__name__, + 's': state, + 'has_uint32': self.rng_state.has_uint32, + 'uinteger': self.rng_state.uinteger} + + @state.setter + def state(self, value): + if not isinstance(value, dict): + raise TypeError('state must be a dict') + brng = value.get('brng', '') + if brng != self.__class__.__name__: + raise ValueError('state must be for a {0} ' + 'PRNG'.format(self.__class__.__name__)) + for i in range(8): + self.rng_state.s[i] = value['s'][i] + self.rng_state.has_uint32 = value['has_uint32'] + self.rng_state.uinteger = value['uinteger'] + + @property + def ctypes(self): + """ + Ctypes interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + + if self._ctypes is not None: + return self._ctypes + + import ctypes + + self._ctypes = interface(self.rng_state, + ctypes.c_void_p(self.rng_state), + ctypes.cast(&xoshiro512starstar_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(&xoshiro512starstar_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(&xoshiro512starstar_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p(self._brng)) + return self.ctypes + + @property + def cffi(self): + """ + CFFI interface + + Returns + ------- + interface : namedtuple + Named tuple containing CFFI wrapper + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + if self._cffi is not None: + return self._cffi + try: + import cffi + except ImportError: + raise ImportError('cffi is cannot be imported.') + + ffi = cffi.FFI() + self._cffi = interface(self.rng_state, + ffi.cast('void *',self.rng_state), + ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), + ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), + ffi.cast('double (*)(void *)',self._brng.next_double), + ffi.cast('void *',self._brng)) + return self.cffi + + @property + def generator(self): + """ + Return a RandomGenerator object + + Returns + ------- + gen : randomgen.generator.RandomGenerator + Random generator used this instance as the basic RNG + """ + if self._generator is None: + from .generator import RandomGenerator + self._generator = RandomGenerator(self) + return self._generator \ No newline at end of file diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 75533ddc4a2a..3697166c13db 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -204,6 +204,30 @@ extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS ), + Extension("randomgen.xoshiro256starstar", + ["randomgen/xoshiro256starstar.pyx", + join(MOD_DIR, 'src', 'xoshiro256starstar', + 'xoshiro256starstar.c')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join( + MOD_DIR, 'src', + 'xoshiro256starstar')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), + Extension("randomgen.xoshiro512starstar", + ["randomgen/xoshiro512starstar.pyx", + join(MOD_DIR, 'src', 'xoshiro512starstar', + 'xoshiro512starstar.c')], + include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), + join( + MOD_DIR, 'src', + 'xoshiro512starstar')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS + ), Extension("randomgen.generator", ["randomgen/generator.pyx", join(MOD_DIR, 'src', 'distributions', @@ -278,8 +302,9 @@ def is_pure(self): version=versioneer.get_version(), classifiers=classifiers, cmdclass=versioneer.get_cmdclass(), - ext_modules=cythonize(extensions, compile_time_env={ - "PCG_EMULATED_MATH": PCG_EMULATED_MATH}), + ext_modules=cythonize(extensions, + compile_time_env={"PCG_EMULATED_MATH": PCG_EMULATED_MATH}, + compiler_directives={'language_level': '3'}), packages=find_packages(), package_dir={'randomgen': './randomgen'}, package_data={'': ['*.h', '*.pxi', '*.pyx', '*.pxd', '*.in'], From c41cbef3f05ca430dbaf65b7a1e3b54a1ae2e4b5 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 23 Oct 2018 18:34:31 +0100 Subject: [PATCH 163/279] DOC: Update docs with Xoshiro additions Add new BRNG to docs Update change log --- _randomgen/README.md | 6 ++- _randomgen/README.rst | 6 ++- _randomgen/doc/source/brng/index.rst | 2 + .../doc/source/brng/xoshiro256starstar.rst | 41 +++++++++++++++++++ .../doc/source/brng/xoshiro512starstar.rst | 41 +++++++++++++++++++ _randomgen/doc/source/change-log.rst | 7 ++++ _randomgen/doc/source/index.rst | 14 +++++-- .../src/xoshiro512starstar/LICENSE.md | 9 ++++ 8 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 _randomgen/doc/source/brng/xoshiro256starstar.rst create mode 100644 _randomgen/doc/source/brng/xoshiro512starstar.rst create mode 100644 _randomgen/randomgen/src/xoshiro512starstar/LICENSE.md diff --git a/_randomgen/README.md b/_randomgen/README.md index eec9bdc753e5..d3bb765579f1 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -79,8 +79,10 @@ The RNGs include: * [dSFMT](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/) a SSE2-aware version of the MT19937 generator that is especially fast at generating doubles -* [xoroshiro128+](http://xoroshiro.di.unimi.it/) and - [xorshift1024*φ](http://xorshift.di.unimi.it/) +* [xoroshiro128+](http://xoroshiro.di.unimi.it/), + [xorshift1024*φ](http://xorshift.di.unimi.it/), + [xoshiro256**](http://xorshift.di.unimi.it/), + and [xoshiro512**](http://xorshift.di.unimi.it/) * [PCG64](http://www.pcg-random.org/) * ThreeFry and Philox from [Random123](https://www.deshawresearch.com/resources_random123.html) diff --git a/_randomgen/README.rst b/_randomgen/README.rst index a0e35d584bc2..c24437372fd1 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -82,8 +82,10 @@ addition to the MT19937 that is included in NumPy. The RNGs include: - `dSFMT `__ a SSE2-aware version of the MT19937 generator that is especially fast at generating doubles -- `xoroshiro128+ `__ and - `xorshift1024*φ `__ +- `xoroshiro128+ `__, + `xorshift1024*φ `__, + `xoshiro256*\* `__, and + `xoshiro512*\* `__ - `PCG64 `__ - ThreeFry and Philox from `Random123 `__ diff --git a/_randomgen/doc/source/brng/index.rst b/_randomgen/doc/source/brng/index.rst index 709151696272..aceecc792a6c 100644 --- a/_randomgen/doc/source/brng/index.rst +++ b/_randomgen/doc/source/brng/index.rst @@ -23,6 +23,8 @@ These RNGs will be included in future releases. ThreeFry XoroShiro128+ Xorshift1024*φ + Xoshiro256** + Xoshiro512** Experimental RNGs diff --git a/_randomgen/doc/source/brng/xoshiro256starstar.rst b/_randomgen/doc/source/brng/xoshiro256starstar.rst new file mode 100644 index 000000000000..903e76bbbd20 --- /dev/null +++ b/_randomgen/doc/source/brng/xoshiro256starstar.rst @@ -0,0 +1,41 @@ +Xoshiro256** +------------ + +.. module:: randomgen.xoshiro256starstar + +.. currentmodule:: randomgen.xoshiro256starstar + +.. autoclass:: Xoshiro256StarStar + +Seeding and State +================= + +.. autosummary:: + :toctree: generated/ + + ~Xoshiro256StarStar.seed + ~Xoshiro256StarStar.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~Xoshiro256StarStar.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~Xoshiro256StarStar.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~Xoshiro256StarStar.cffi + ~Xoshiro256StarStar.ctypes + + diff --git a/_randomgen/doc/source/brng/xoshiro512starstar.rst b/_randomgen/doc/source/brng/xoshiro512starstar.rst new file mode 100644 index 000000000000..3501b2c9c85e --- /dev/null +++ b/_randomgen/doc/source/brng/xoshiro512starstar.rst @@ -0,0 +1,41 @@ +Xoshiro512** +------------ + +.. module:: randomgen.xoshiro512starstar + +.. currentmodule:: randomgen.xoshiro512starstar + +.. autoclass:: Xoshiro512StarStar + +Seeding and State +================= + +.. autosummary:: + :toctree: generated/ + + ~Xoshiro512StarStar.seed + ~Xoshiro512StarStar.state + +Parallel generation +=================== +.. autosummary:: + :toctree: generated/ + + ~Xoshiro512StarStar.jump + +Random Generator +================ +.. autosummary:: + :toctree: generated/ + + ~Xoshiro512StarStar.generator + +Extending +========= +.. autosummary:: + :toctree: generated/ + + ~Xoshiro512StarStar.cffi + ~Xoshiro512StarStar.ctypes + + diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst index 9cb5f0128081..29876a4b99b7 100644 --- a/_randomgen/doc/source/change-log.rst +++ b/_randomgen/doc/source/change-log.rst @@ -1,6 +1,13 @@ Change Log ---------- +After v1.15 +=========== +- Added Xoshiro256** and Xoshiro512**, the preferred generators of this class +- Fixed bug in `jump` method of Random123 generators which did nto specify a default value + + + v1.15 ===== - Synced empty choice changes diff --git a/_randomgen/doc/source/index.rst b/_randomgen/doc/source/index.rst index 0885666c8826..7db6cbd5b428 100644 --- a/_randomgen/doc/source/index.rst +++ b/_randomgen/doc/source/index.rst @@ -150,13 +150,19 @@ generators, 'in addition' to the standard PRNG in NumPy. The included PRNGs are to produce multiple streams in parallel applications. See :meth:`~randomgen.xoroshiro128.Xoroshiro128.jump` for details. More information about this PRNG is available at the - `xorshift and xoroshiro authors' page`_. -* XorShift1024*φ - Vast fast generator based on the XSadd + `xorshift, xoroshiro and xoshiro authors' page`_. +* XorShift1024*φ - Fast fast generator based on the XSadd generator. Supports ``jump`` and so can be used in parallel applications. See the documentation for :meth:`~randomgen.xorshift1024.Xorshift1024.jump` for details. More information about these PRNGs is available at the - `xorshift and xoroshiro authors' page`_. + `xorshift, xoroshiro and xoshiro authors' page`_. +* Xorshiro256** and Xorshiro512** - The most recently introduced XOR, + shift, and rotate generator. Supports ``jump`` and so can be used in + parallel applications. See the documentation for + :meth:`~randomgen.xoshiro256starstar.Xoshirt256StarStar.jump` for details. More + information about these PRNGs is available at the + `xorshift, xoroshiro and xoshiro authors' page`_. * PCG-64 - Fast generator that support many parallel streams and can be advanced by an arbitrary amount. See the documentation for :meth:`~randomgen.pcg64.PCG64.advance`. PCG-64 has a period of @@ -168,7 +174,7 @@ generators, 'in addition' to the standard PRNG in NumPy. The included PRNGs are .. _`NumPy's documentation`: https://docs.scipy.org/doc/numpy/reference/routines.random.html .. _`dSFMT authors' page`: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/ -.. _`xorshift and xoroshiro authors' page`: http://xoroshiro.di.unimi.it/ +.. _`xorshift, xoroshiro and xoshiro authors' page`: http://xoroshiro.di.unimi.it/ .. _`PCG author's page`: http://www.pcg-random.org/ .. _`Random123`: https://www.deshawresearch.com/resources_random123.html diff --git a/_randomgen/randomgen/src/xoshiro512starstar/LICENSE.md b/_randomgen/randomgen/src/xoshiro512starstar/LICENSE.md new file mode 100644 index 000000000000..aa34c1966a40 --- /dev/null +++ b/_randomgen/randomgen/src/xoshiro512starstar/LICENSE.md @@ -0,0 +1,9 @@ +# XOSHIRO512STARSTAR + +Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . From 37bea4b47fe4e2b1e218ae50c243c8ae0567066f Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 24 Oct 2018 07:32:21 +0100 Subject: [PATCH 164/279] DOC: Update readme Update timings --- _randomgen/README.md | 60 ++++++++++++++++++++++++------------------- _randomgen/README.rst | 60 ++++++++++++++++++++++++------------------- 2 files changed, 66 insertions(+), 54 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index d3bb765579f1..de392c52801e 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -234,36 +234,42 @@ NumPy's mt19937. Speed-up relative to NumPy (Uniform Doubles) ************************************************************ - DSFMT 137.1% - MT19937 21.0% - PCG32 101.2% - PCG64 110.7% - Philox -2.7% - ThreeFry -11.4% - ThreeFry32 -62.3% - Xoroshiro128 181.4% - Xorshift1024 141.8% + DSFMT 184.9% + MT19937 17.3% + PCG32 83.3% + PCG64 108.3% + Philox -4.9% + ThreeFry -12.0% + ThreeFry32 -63.9% + Xoroshiro128 159.5% + Xorshift1024 150.4% + Xoshiro256StarStar 145.7% + Xoshiro512StarStar 113.1% Speed-up relative to NumPy (64-bit unsigned integers) ************************************************************ - DSFMT 24.8% - MT19937 15.0% - PCG32 92.6% - PCG64 99.0% - Philox -20.4% - ThreeFry -21.7% - ThreeFry32 -64.4% - Xoroshiro128 164.2% - Xorshift1024 120.8% + DSFMT 17.4% + MT19937 7.8% + PCG32 60.3% + PCG64 73.5% + Philox -25.5% + ThreeFry -30.5% + ThreeFry32 -67.8% + Xoroshiro128 124.0% + Xorshift1024 109.4% + Xoshiro256StarStar 100.3% + Xoshiro512StarStar 63.5% Speed-up relative to NumPy (Standard normals) ************************************************************ - DSFMT 299.4% - MT19937 271.2% - PCG32 364.5% - PCG64 364.2% - Philox 256.9% - ThreeFry 236.0% - ThreeFry32 97.0% - Xoroshiro128 477.4% - Xorshift1024 360.7% + DSFMT 183.0% + MT19937 169.0% + PCG32 240.7% + PCG64 231.6% + Philox 131.3% + ThreeFry 118.3% + ThreeFry32 21.6% + Xoroshiro128 332.1% + Xorshift1024 232.4% + Xoshiro256StarStar 306.6% + Xoshiro512StarStar 274.6% diff --git a/_randomgen/README.rst b/_randomgen/README.rst index c24437372fd1..814b1272b817 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -258,39 +258,45 @@ NumPy’s mt19937. Speed-up relative to NumPy (Uniform Doubles) ************************************************************ - DSFMT 137.1% - MT19937 21.0% - PCG32 101.2% - PCG64 110.7% - Philox -2.7% - ThreeFry -11.4% - ThreeFry32 -62.3% - Xoroshiro128 181.4% - Xorshift1024 141.8% + DSFMT 184.9% + MT19937 17.3% + PCG32 83.3% + PCG64 108.3% + Philox -4.9% + ThreeFry -12.0% + ThreeFry32 -63.9% + Xoroshiro128 159.5% + Xorshift1024 150.4% + Xoshiro256StarStar 145.7% + Xoshiro512StarStar 113.1% Speed-up relative to NumPy (64-bit unsigned integers) ************************************************************ - DSFMT 24.8% - MT19937 15.0% - PCG32 92.6% - PCG64 99.0% - Philox -20.4% - ThreeFry -21.7% - ThreeFry32 -64.4% - Xoroshiro128 164.2% - Xorshift1024 120.8% + DSFMT 17.4% + MT19937 7.8% + PCG32 60.3% + PCG64 73.5% + Philox -25.5% + ThreeFry -30.5% + ThreeFry32 -67.8% + Xoroshiro128 124.0% + Xorshift1024 109.4% + Xoshiro256StarStar 100.3% + Xoshiro512StarStar 63.5% Speed-up relative to NumPy (Standard normals) ************************************************************ - DSFMT 299.4% - MT19937 271.2% - PCG32 364.5% - PCG64 364.2% - Philox 256.9% - ThreeFry 236.0% - ThreeFry32 97.0% - Xoroshiro128 477.4% - Xorshift1024 360.7% + DSFMT 183.0% + MT19937 169.0% + PCG32 240.7% + PCG64 231.6% + Philox 131.3% + ThreeFry 118.3% + ThreeFry32 21.6% + Xoroshiro128 332.1% + Xorshift1024 232.4% + Xoshiro256StarStar 306.6% + Xoshiro512StarStar 274.6% .. |Travis Build Status| image:: https://travis-ci.org/bashtage/randomgen.svg?branch=master :target: https://travis-ci.org/bashtage/randomgen From 2f8ecf6860a443407fa848d5e163428ff08a61dc Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 5 Nov 2018 23:32:22 +0000 Subject: [PATCH 165/279] UPD: Sync with upstream changes Sync upstream changes in numpy/numpy#11613, numpy/numpy#11771, and numpy/numpy#12089 --- _randomgen/randomgen/common.pxd | 1 + _randomgen/randomgen/common.pyx | 5 ++++- _randomgen/randomgen/generator.pyx | 11 +++++----- .../randomgen/tests/test_numpy_mt19937.py | 4 ++++ .../tests/test_numpy_mt19937_regressions.py | 22 +++++++++++++++++++ 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/_randomgen/randomgen/common.pxd b/_randomgen/randomgen/common.pxd index f6017c0d7504..62163ad62a0d 100644 --- a/_randomgen/randomgen/common.pxd +++ b/_randomgen/randomgen/common.pxd @@ -18,6 +18,7 @@ cdef enum ConstraintType: CONS_POSITIVE CONS_BOUNDED_0_1 CONS_BOUNDED_0_1_NOTNAN + CONS_BOUNDED_GT_0_1 CONS_GT_1 CONS_GTE_1 CONS_POISSON diff --git a/_randomgen/randomgen/common.pyx b/_randomgen/randomgen/common.pyx index b152099eb0cb..eb872d02f15b 100644 --- a/_randomgen/randomgen/common.pyx +++ b/_randomgen/randomgen/common.pyx @@ -155,10 +155,13 @@ cdef int check_array_constraint(np.ndarray val, object name, constraint_type con raise ValueError(name + " <= 0") elif cons == CONS_BOUNDED_0_1 or cons == CONS_BOUNDED_0_1_NOTNAN: if np.any(np.less(val, 0)) or np.any(np.greater(val, 1)): - raise ValueError(name + " <= 0 or " + name + " >= 1") + raise ValueError(name + " < 0 or " + name + " > 1") if cons == CONS_BOUNDED_0_1_NOTNAN: if np.any(np.isnan(val)): raise ValueError(name + ' contains NaNs') + elif cons == CONS_BOUNDED_GT_0_1: + if np.any(np.less_equal(val, 0)) or np.any(np.greater(val, 1)): + raise ValueError(name + " <= 0 or " + name + " > 1") elif cons == CONS_GT_1: if np.any(np.less_equal(val, 1)): raise ValueError(name + " <= 1") diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index a016e7262deb..4f60663ee10b 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -3561,7 +3561,7 @@ cdef class RandomGenerator: """ return disc(&random_geometric, self._brng, size, self.lock, 1, 0, - p, 'p', CONS_BOUNDED_0_1, + p, 'p', CONS_BOUNDED_GT_0_1, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE) @@ -4234,9 +4234,8 @@ cdef class RandomGenerator: self._shuffle_raw(n, sizeof(np.npy_intp), stride, x_ptr, buf_ptr) else: self._shuffle_raw(n, itemsize, stride, x_ptr, buf_ptr) - elif isinstance(x, np.ndarray) and x.ndim > 1 and x.size: - # Multidimensional ndarrays require a bounce buffer. - buf = np.empty_like(x[0]) + elif isinstance(x, np.ndarray) and x.ndim and x.size: + buf = np.empty_like(x[0,...]) with self.lock: for i in reversed(range(1, n)): j = random_interval(self._brng, i) @@ -4305,8 +4304,8 @@ cdef class RandomGenerator: # shuffle has fast-path for 1-d if arr.ndim == 1: - # must return a copy - if arr is x: + # Return a copy if same memory + if np.may_share_memory(arr, x): arr = np.array(arr) self.shuffle(arr) return arr diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 6e5e7cf87a15..b1081b2b2ba6 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -594,6 +594,10 @@ def test_shuffle(self): lambda x: [(i, i) for i in x], lambda x: np.asarray([[i, i] for i in x]), lambda x: np.vstack([x, x]).T, + # gh-11442 + lambda x: (np.asarray([(i, i) for i in x], + [("a", int), ("b", int)]) + .view(np.recarray)), # gh-4270 lambda x: np.asarray([(i, i) for i in x], [("a", object, 1), diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py b/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py index 1f082925e589..4e51327aa160 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py @@ -136,3 +136,25 @@ def test_shuffle_of_array_of_objects(self): # Force Garbage Collection - should not segfault. import gc gc.collect() + + def test_permutation_subclass(self): + class N(np.ndarray): + pass + + mt19937.seed(1) + orig = np.arange(3).view(N) + perm = mt19937.permutation(orig) + assert_array_equal(perm, np.array([0, 2, 1])) + assert_array_equal(orig, np.arange(3).view(N)) + + class M(object): + a = np.arange(5) + + def __array__(self): + return self.a + + mt19937.seed(1) + m = M() + perm = mt19937.permutation(m) + assert_array_equal(perm, np.array([2, 1, 4, 0, 3])) + assert_array_equal(m.__array__(), np.arange(5)) From 5ed4d6dcb21618e2de9d438f64eb2e8ce5d64f2c Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 6 Nov 2018 00:07:25 +0000 Subject: [PATCH 166/279] BLD: Update dependency minimums Update to NumPy 1.12 as the minimum version --- _randomgen/.travis.yml | 10 +++++----- _randomgen/README.md | 4 ++-- _randomgen/README.rst | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 052681727ab9..3c8f35c2ca4c 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -20,15 +20,15 @@ matrix: fast_finish: true include: - os: linux - env: [PYTHON=2.7, NUMPY=1.10, CYTHON=0.26] + env: [PYTHON=2.7, NUMPY=1.13, CYTHON=0.26] - os: linux - env: [PYTHON=3.5, NUMPY=1.11] + env: [PYTHON=3.5, NUMPY=1.13] - os: linux - env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.27] + env: [PYTHON=3.6, NUMPY=1.14, CYTHON=0.27] - os: linux - env: [PYTHON=3.6, NUMPY=1.13, CYTHON=0.26] + env: [PYTHON=3.6, NUMPY=1.15, CYTHON=0.28] - os: linux - env: [PYTHON=3.6, DOCBUILD=true] + env: [PYTHON=3.7, DOCBUILD=true] - os: osx language: generic env: [PYTHON=3.6] diff --git a/_randomgen/README.md b/_randomgen/README.md index de392c52801e..2d95361ab4cb 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -150,8 +150,8 @@ need to be smoothed. ## Requirements Building requires: -* Python (2.7, 3.4, 3.5, 3.6) -* NumPy (1.11, 1.12, 1.13, 1.14, 1.15) +* Python (2.7, 3.5, 3.6, 3.7) +* NumPy (1.13, 1.14, 1.15) * Cython (0.26+) * tempita (0.5+), if not provided by Cython diff --git a/_randomgen/README.rst b/_randomgen/README.rst index 814b1272b817..e36f9999749b 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -166,8 +166,8 @@ Requirements Building requires: -- Python (2.7, 3.4, 3.5, 3.6) -- NumPy (1.11, 1.12, 1.13, 1.14, 1.15) +- Python (2.7, 3.5, 3.6, 3.7) +- NumPy (1.13, 1.14, 1.15) - Cython (0.26+) - tempita (0.5+), if not provided by Cython From f80e160eab1730858cfa711aee5596ddeb7070ee Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sat, 10 Nov 2018 16:17:41 +0000 Subject: [PATCH 167/279] RLS: Small clean-up prior to 1.15.1 release Fix documentation Add information about Lemire generator Update change log Fix docstring for randint --- _randomgen/README.md | 7 +++++++ _randomgen/README.rst | 7 +++++++ _randomgen/doc/source/change-log.rst | 12 ++++++------ _randomgen/doc/source/index.rst | 5 +++++ _randomgen/doc/source/new-or-different.rst | 9 +++++++++ _randomgen/doc/source/references.rst | 5 +++++ _randomgen/randomgen/generator.pyx | 7 ++++++- 7 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 _randomgen/doc/source/references.rst diff --git a/_randomgen/README.md b/_randomgen/README.md index 2d95361ab4cb..34986ebdb45d 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -68,6 +68,9 @@ which can fully reproduce the sequence produced by NumPy. * Normals (`standard_normal`) * Standard Gammas (via `standard_gamma`) +* Support for Lemire's method of generating uniform integers on an + arbitrary interval by setting `use_masked=True`. + ## Included Pseudo Random Number Generators This module includes a number of alternative random @@ -103,6 +106,10 @@ The RNGs include: * Core random number generators can fill existing arrays using the `out` keyword argument * Standardizes integer-values random values as int64 for all platforms. +* `randint` supports generating using rejection sampling on masked + values (the default) or Lemire's method. Lemire's method can be much + faster when the required interval length is much smaller than the + closes power of 2. ### New Functions diff --git a/_randomgen/README.rst b/_randomgen/README.rst index e36f9999749b..69de75ab3811 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -71,6 +71,9 @@ Features - Normals (``standard_normal``) - Standard Gammas (via ``standard_gamma``) +- Support for Lemire’s method of generating uniform integers on an + arbitrary interval by setting ``use_masked=True``. + Included Pseudo Random Number Generators ---------------------------------------- @@ -111,6 +114,10 @@ New Features - Core random number generators can fill existing arrays using the ``out`` keyword argument - Standardizes integer-values random values as int64 for all platforms. +- ``randint`` supports generating using rejection sampling on masked + values (the default) or Lemire’s method. Lemire’s method can be much + faster when the required interval length is much smaller than the + closes power of 2. New Functions ~~~~~~~~~~~~~ diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst index 29876a4b99b7..629dd000281d 100644 --- a/_randomgen/doc/source/change-log.rst +++ b/_randomgen/doc/source/change-log.rst @@ -1,12 +1,12 @@ Change Log ---------- -After v1.15 -=========== -- Added Xoshiro256** and Xoshiro512**, the preferred generators of this class -- Fixed bug in `jump` method of Random123 generators which did nto specify a default value - - +v1.15.1 +======= +- Added Xoshiro256** and Xoshiro512**, the preferred generators of this class. +- Fixed bug in `jump` method of Random123 generators which did nto specify a default value. +- Added support for generating bounded uniform integers using Lemire's method. +- Synchronized with upstream changes, which requires moving the minimum supported NumPy to 1.13. v1.15 ===== diff --git a/_randomgen/doc/source/index.rst b/_randomgen/doc/source/index.rst index 7db6cbd5b428..eac8c1ef12e8 100644 --- a/_randomgen/doc/source/index.rst +++ b/_randomgen/doc/source/index.rst @@ -119,6 +119,10 @@ What's New or Different these basic RNGs to be used in numba. * The basic random number generators can be used in downstream projects via Cython. +* Support for Lemire’s method [Lemire]_ of generating uniform integers on an + arbitrary interval by setting ``use_masked=True`` in + (:meth:`~randomgen.generator.RandomGenerator.randint`). + See :ref:`new-or-different` for a complete list of improvements and differences. @@ -205,6 +209,7 @@ New Features Comparing Performance extending Reading System Entropy + references Changes ~~~~~~~ diff --git a/_randomgen/doc/source/new-or-different.rst b/_randomgen/doc/source/new-or-different.rst index c94d95c7c094..6598c13feb36 100644 --- a/_randomgen/doc/source/new-or-different.rst +++ b/_randomgen/doc/source/new-or-different.rst @@ -87,3 +87,12 @@ What's New or Different print(existing) .. * For changes since the previous release, see the :ref:`change-log` + +* Support for Lemire’s method of generating uniform integers on an + arbitrary interval by setting ``use_masked=True`` in + (:meth:`~randomgen.generator.RandomGenerator.randint`). + +.. ipython:: python + + %timeit rg.randint(0, 1535, use_masked=False) + %timeit numpy.random.randint(0, 1535) diff --git a/_randomgen/doc/source/references.rst b/_randomgen/doc/source/references.rst new file mode 100644 index 000000000000..0dc99868f1e5 --- /dev/null +++ b/_randomgen/doc/source/references.rst @@ -0,0 +1,5 @@ +References +---------- + +.. [Lemire] Daniel Lemire., "Fast Random Integer Generation in an Interval", + CoRR, Aug. 13, 2018, http://arxiv.org/abs/1805.10941. diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 1e92d408b7ec..5d239c725f76 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -574,7 +574,7 @@ cdef class RandomGenerator: def randint(self, low, high=None, size=None, dtype=int, use_masked=True): """ - randint(low, high=None, size=None, dtype='l') + randint(low, high=None, size=None, dtype='l', use_masked=True) Return random integers from `low` (inclusive) to `high` (exclusive). @@ -652,6 +652,11 @@ cdef class RandomGenerator: >>> randomgen.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) array([[ 8, 6, 9, 7], [ 1, 16, 9, 12]], dtype=uint8) + + References + ---------- + .. [1] Daniel Lemire., "Fast Random Integer Generation in an Interval", + CoRR, Aug. 13, 2018, http://arxiv.org/abs/1805.10941. """ if high is None: high = low From 6701896a6215a63c53b4682632119d4f33943e85 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 11 Nov 2018 15:48:36 +0000 Subject: [PATCH 168/279] REF: Refactor benchmark Refactor benchmark with more options Clean code for PEP8 violations --- _randomgen/benchmark.py | 173 +++++++----------- _randomgen/doc/source/conf.py | 2 - _randomgen/doc/source/performance.py | 16 +- .../randomgen/tests/test_numpy_mt19937.py | 16 +- 4 files changed, 83 insertions(+), 124 deletions(-) diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py index 860134de1289..c4c4ab93d8f6 100644 --- a/_randomgen/benchmark.py +++ b/_randomgen/benchmark.py @@ -84,122 +84,67 @@ def timer_uniform(): run_timer(dist, command, None, SETUP, 'Uniforms') -def timer_8bit_bounded(max=95, use_masked=True): - min = 0 +def timer_bounded(bits=8, max=95, use_masked=True): + """ + Timer for 8-bit bounded values. + + Parameters + ---------- + bits : {8, 16, 32, 64} + Bit width of unsigned output type + max : int + Upper bound for range. Lower is always 0. Must be <= 2**bits. + use_masked: bool + If True, masking and rejection sampling is used to generate a random + number in an interval. If False, Lemire's algorithm is used if + available to generate a random number in an interval. + + Notes + ----- + Lemire's algorithm has improved performance when {max}+1 is not a + power of two. + """ + if bits not in (8, 16, 32, 64): + raise ValueError('bits must be one of 8, 16, 32, 64.') + minimum = 0 dist = 'random_uintegers' - # Note on performance of generating random numbers in an interval: - # use_masked=True : masking and rejection sampling is used to generate a random number in an interval. - # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. - # Lemire's algorithm has improved performance when {max}+1 is not a power of two. + if use_masked: # Use masking & rejection. + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint{bits}, use_masked=True)' + else: # Use Lemire's algo. + command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint{bits}, use_masked=False)' - if use_masked: - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint8, use_masked=True)' # Use masking & rejection. - else: - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint8, use_masked=False)' # Use Lemire's algo. + command = command.format(min=minimum, max=max, bits=bits) - command = command.format(min=min, max=max) - - command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint8)' - command_numpy = command_numpy.format(min=min, max=max) + command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint{bits})' + command_numpy = command_numpy.format(min=minimum, max=max, bits=bits) run_timer(dist, command, command_numpy, SETUP, - '8-bit bounded unsigned integers (max={max}, use_masked={use_masked})'.format(max=max, use_masked=use_masked)) - - -def timer_16bit_bounded(max=1535, use_masked=True): - min = 0 - - dist = 'random_uintegers' - - # Note on performance of generating random numbers in an interval: - # use_masked=True : masking and rejection sampling is used to generate a random number in an interval. - # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. - # Lemire's algorithm has improved performance when {max}+1 is not a power of two. - - if use_masked: - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint16, use_masked=True)' # Use masking & rejection. - else: - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint16, use_masked=False)' # Use Lemire's algo. - - command = command.format(min=min, max=max) - - command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint16)' - command_numpy = command_numpy.format(min=min, max=max) - - run_timer(dist, command, command_numpy, SETUP, - '16-bit bounded unsigned integers (max={max}, use_masked={use_masked})'.format(max=max, use_masked=use_masked)) + '{bits}-bit bounded unsigned integers (max={max}, ' + 'use_masked={use_masked})'.format(max=max, use_masked=use_masked, bits=bits)) def timer_32bit(): info = np.iinfo(np.uint32) - min, max = info.min, info.max + minimum, maximum = info.min, info.max dist = 'random_uintegers' command = 'rg.random_uintegers(1000000, 32)' command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32)' - command_numpy = command_numpy.format(min=min, max=max) + command_numpy = command_numpy.format(min=minimum, max=maximum) run_timer(dist, command, command_numpy, SETUP, '32-bit unsigned integers') -def timer_32bit_bounded(max=1535, use_masked=True): - min = 0 - - dist = 'random_uintegers' - - # Note on performance of generating random numbers in an interval: - # use_masked=True : masking and rejection sampling is used to generate a random number in an interval. - # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. - # Lemire's algorithm has improved performance when {max}+1 is not a power of two. - - if use_masked: - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=True)' # Use masking & rejection. - else: - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32, use_masked=False)' # Use Lemire's algo. - - command = command.format(min=min, max=max) - - command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32)' - command_numpy = command_numpy.format(min=min, max=max) - - run_timer(dist, command, command_numpy, SETUP, - '32-bit bounded unsigned integers (max={max}, use_masked={use_masked})'.format(max=max, use_masked=use_masked)) - - def timer_64bit(): info = np.iinfo(np.uint64) - min, max = info.min, info.max + minimum, maximum = info.min, info.max dist = 'random_uintegers' command = 'rg.random_uintegers(1000000)' command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64)' - command_numpy = command_numpy.format(min=min, max=max) + command_numpy = command_numpy.format(min=minimum, max=maximum) run_timer(dist, command, command_numpy, SETUP, '64-bit unsigned integers') -def timer_64bit_bounded(max=1535, use_masked=True): - min = 0 - - dist = 'random_uintegers' - - # Note on performance of generating random numbers in an interval: - # use_masked=True : masking and rejection sampling is used to generate a random number in an interval. - # use_masked=False : Lemire's algorithm is used if available to generate a random number in an interval. - # Lemire's algorithm has improved performance when {max}+1 is not a power of two. - - if use_masked: - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64, use_masked=True)' # Use masking & rejection. - else: - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64, use_masked=False)' # Use Lemire's algo. - - command = command.format(min=min, max=max) - - command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64)' - command_numpy = command_numpy.format(min=min, max=max) - - run_timer(dist, command, command_numpy, SETUP, - '64-bit bounded unsigned integers (max={max}, use_masked={use_masked})'.format(max=max, use_masked=use_masked)) - - def timer_normal_zig(): dist = 'standard_normal' command = 'rg.standard_normal(1000000)' @@ -210,35 +155,47 @@ def timer_normal_zig(): if __name__ == '__main__': import argparse + parser = argparse.ArgumentParser() - parser.add_argument('--full', dest='full', action='store_true') + parser.add_argument('-f', '--full', + help='Run benchmarks for a wide range of distributions.' + ' If not provided, only tests the production of ' + 'uniform values.', + dest='full', action='store_true') + parser.add_argument('-bi', '--bounded-ints', + help='Included benchmark coverage of the bounded ' + 'integer generators in a full run.', + dest='bounded_ints', action='store_true') args = parser.parse_args() timer_uniform() if args.full: timer_raw() - timer_8bit_bounded(use_masked=True) - timer_8bit_bounded(max=64, use_masked=False) # Worst case for Numpy. - timer_8bit_bounded(max=95, use_masked=False) # Typ. avrg. case for Numpy. - timer_8bit_bounded(max=127, use_masked=False) # Best case for Numpy. + if args.bounded_ints: + timer_bounded(use_masked=True) + timer_bounded(max=64, use_masked=False) # Worst case for Numpy. + timer_bounded(max=95, use_masked=False) # Typ. avrg. case for Numpy. + timer_bounded(max=127, use_masked=False) # Best case for Numpy. - timer_16bit_bounded(use_masked=True) - timer_16bit_bounded(max=1024, use_masked=False) # Worst case for Numpy. - timer_16bit_bounded(max=1535, use_masked=False) # Typ. avrg. case for Numpy. - timer_16bit_bounded(max=2047, use_masked=False) # Best case for Numpy. + timer_bounded(16, use_masked=True) + timer_bounded(16, max=1024, use_masked=False) # Worst case for Numpy. + timer_bounded(16, max=1535, use_masked=False) # Typ. avrg. case for Numpy. + timer_bounded(16, max=2047, use_masked=False) # Best case for Numpy. timer_32bit() - timer_32bit_bounded(use_masked=True) - timer_32bit_bounded(max=1024, use_masked=False) # Worst case for Numpy. - timer_32bit_bounded(max=1535, use_masked=False) # Typ. avrg. case for Numpy. - timer_32bit_bounded(max=2047, use_masked=False) # Best case for Numpy. + if args.bounded_ints: + timer_bounded(32, use_masked=True) + timer_bounded(32, max=1024, use_masked=False) # Worst case for Numpy. + timer_bounded(32, max=1535, use_masked=False) # Typ. avrg. case for Numpy. + timer_bounded(32, max=2047, use_masked=False) # Best case for Numpy. timer_64bit() - timer_64bit_bounded(use_masked=True) - timer_64bit_bounded(max=1024, use_masked=False) # Worst case for Numpy. - timer_64bit_bounded(max=1535, use_masked=False) # Typ. avrg. case for Numpy. - timer_64bit_bounded(max=2047, use_masked=False) # Best case for Numpy. + if args.bounded_ints: + timer_bounded(64, use_masked=True) + timer_bounded(64, max=1024, use_masked=False) # Worst case for Numpy. + timer_bounded(64, max=1535, use_masked=False) # Typ. avrg. case for Numpy. + timer_bounded(64, max=2047, use_masked=False) # Best case for Numpy. timer_normal_zig() diff --git a/_randomgen/doc/source/conf.py b/_randomgen/doc/source/conf.py index c89900b5579f..4b38c42d5370 100644 --- a/_randomgen/doc/source/conf.py +++ b/_randomgen/doc/source/conf.py @@ -15,9 +15,7 @@ # import os # import sys # sys.path.insert(0, os.path.abspath('.')) -from distutils.version import LooseVersion import guzzle_sphinx_theme -# import sphinx_rtd_theme import randomgen # -- Project information ----------------------------------------------------- diff --git a/_randomgen/doc/source/performance.py b/_randomgen/doc/source/performance.py index d84c3147e398..6733b960205d 100644 --- a/_randomgen/doc/source/performance.py +++ b/_randomgen/doc/source/performance.py @@ -1,11 +1,13 @@ +from timeit import repeat + import numpy as np -from timeit import timeit, repeat import pandas as pd from randomgen import MT19937, DSFMT, ThreeFry, PCG64, Xoroshiro128, \ - Xorshift1024, Philox + Xorshift1024, Philox, Xoshiro256StarStar, Xoshiro512StarStar -PRNGS = [DSFMT, MT19937, Philox, PCG64, ThreeFry, Xoroshiro128, Xorshift1024] +PRNGS = [DSFMT, MT19937, Philox, PCG64, ThreeFry, Xoroshiro128, Xorshift1024, + Xoshiro256StarStar, Xoshiro512StarStar] funcs = {'32-bit Unsigned Ints': 'random_uintegers(size=1000000,bits=32)', '64-bit Unsigned Ints': 'random_uintegers(size=1000000,bits=32)', @@ -32,11 +34,10 @@ t = repeat(test.format(func=funcs[key]), setup.format(prng=prng().__class__.__name__), number=1, repeat=3) - col[key]= 1000 * min(t) + col[key] = 1000 * min(t) col = pd.Series(col) table[prng().__class__.__name__] = col - npfuncs = {} npfuncs.update(funcs) npfuncs['32-bit Unsigned Ints'] = 'randint(2**32,dtype="uint32",size=1000000)' @@ -54,7 +55,6 @@ col[key] = 1000 * min(t) table['NumPy'] = pd.Series(col) - table = pd.DataFrame(table) table = table.reindex(table.mean(1).sort_values().index) order = np.log(table).mean().sort_values().index @@ -63,11 +63,11 @@ table = table.T print(table.to_csv(float_format='%0.1f')) -rel = table / (table.iloc[:,[0]].values @ np.ones((1,8))) +rel = table / (table.iloc[:, [0]].values @ np.ones((1, 8))) rel.pop(rel.columns[0]) rel = rel.T rel['Overall'] = np.exp(np.log(rel).mean(1)) rel *= 100 rel = np.round(rel) rel = rel.T -print(rel.to_csv(float_format='%0d')) \ No newline at end of file +print(rel.to_csv(float_format='%0d')) diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 56adf51e8290..888baf92f296 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -437,27 +437,31 @@ def test_randint(self): assert_array_equal(actual, desired) def test_randint_masked(self): - """ Test masked rejection sampling algorithm to generate array of uint32 in an interval. """ + # Test masked rejection sampling algorithm to generate array of + # uint32 in an interval. mt19937.seed(self.seed) - actual = mt19937.randint(0, 99, size=(3, 2), dtype=np.uint32, use_masked=True) + actual = mt19937.randint(0, 99, size=(3, 2), dtype=np.uint32, + use_masked=True) desired = np.array([[2, 47], [12, 51], [33, 43]], dtype=np.uint32) assert_array_equal(actual, desired) def test_randint_lemire_32(self): - """ Test lemire algorithm to generate array of uint32 in an interval. """ + # Test lemire algorithm to generate array of uint32 in an interval. mt19937.seed(self.seed) - actual = mt19937.randint(0, 99, size=(3, 2), dtype=np.uint32, use_masked=False) + actual = mt19937.randint(0, 99, size=(3, 2), dtype=np.uint32, + use_masked=False) desired = np.array([[61, 33], [58, 14], [87, 23]], dtype=np.uint32) assert_array_equal(actual, desired) def test_randint_lemire_64(self): - """ Test lemire algorithm to generate array of uint64 in an interval. """ + # Test lemire algorithm to generate array of uint64 in an interval. mt19937.seed(self.seed) - actual = mt19937.randint(0, 99 + 0xFFFFFFFFF, size=(3, 2), dtype=np.uint64, use_masked=False) + actual = mt19937.randint(0, 99 + 0xFFFFFFFFF, size=(3, 2), + dtype=np.uint64, use_masked=False) desired = np.array([[42523252834, 40656066204], [61069871386, 61274051182], [31443797706, 53476677934]], dtype=np.uint64) From 6173d8f1684fdae243f32533ab822487d557e28a Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 11 Nov 2018 16:14:51 +0000 Subject: [PATCH 169/279] REF: Improve performance testing Improve performance testing --- _randomgen/doc/source/performance.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/_randomgen/doc/source/performance.py b/_randomgen/doc/source/performance.py index 6733b960205d..12cbbc5d38f0 100644 --- a/_randomgen/doc/source/performance.py +++ b/_randomgen/doc/source/performance.py @@ -1,3 +1,4 @@ +from collections import OrderedDict from timeit import repeat import numpy as np @@ -26,10 +27,10 @@ """ test = "rg.{func}" -table = {} +table = OrderedDict() for prng in PRNGS: print(prng) - col = {} + col = OrderedDict() for key in funcs: t = repeat(test.format(func=funcs[key]), setup.format(prng=prng().__class__.__name__), @@ -38,7 +39,7 @@ col = pd.Series(col) table[prng().__class__.__name__] = col -npfuncs = {} +npfuncs = OrderedDict() npfuncs.update(funcs) npfuncs['32-bit Unsigned Ints'] = 'randint(2**32,dtype="uint32",size=1000000)' npfuncs['64-bit Unsigned Ints'] = 'tomaxint(size=1000000)' @@ -63,7 +64,7 @@ table = table.T print(table.to_csv(float_format='%0.1f')) -rel = table / (table.iloc[:, [0]].values @ np.ones((1, 8))) +rel = table.loc[:, ['NumPy']].values @ np.ones((1, table.shape[1])) / table rel.pop(rel.columns[0]) rel = rel.T rel['Overall'] = np.exp(np.log(rel).mean(1)) From f879e4fafd5dec5a68d9ff060c250db0a9aa0c5c Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 14 Dec 2018 15:47:25 +0000 Subject: [PATCH 170/279] ENH: Cast covariance to double in random mvnormal Cast the covariance in the multivariate normal to double so that the interpretation of tol is cleaner. closes #10839 --- numpy/random/mtrand/mtrand.pyx | 3 +++ numpy/random/tests/test_random.py | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx index 059a39e55905..f49d03c425fd 100644 --- a/numpy/random/mtrand/mtrand.pyx +++ b/numpy/random/mtrand/mtrand.pyx @@ -4408,6 +4408,7 @@ cdef class RandomState: Behavior when the covariance matrix is not positive semidefinite. tol : float, optional Tolerance when checking the singular values in covariance matrix. + cov is cast to double before the check. Returns ------- @@ -4519,6 +4520,8 @@ cdef class RandomState: # not zero. We continue to use the SVD rather than Cholesky in # order to preserve current outputs. + # GH10839, ensure double to make tol meaningful + cov = cov.astype(np.double) (u, s, v) = svd(cov) if check_valid != 'ignore': diff --git a/numpy/random/tests/test_random.py b/numpy/random/tests/test_random.py index d0bb92a73895..d35d32886c56 100644 --- a/numpy/random/tests/test_random.py +++ b/numpy/random/tests/test_random.py @@ -712,6 +712,12 @@ def test_multivariate_normal(self): assert_raises(ValueError, np.random.multivariate_normal, mean, cov, check_valid='raise') + cov = np.array([[1, 0.1],[0.1, 1]], dtype=np.float32) + with suppress_warnings() as sup: + np.random.multivariate_normal(mean, cov) + w = sup.record(RuntimeWarning) + assert len(w) == 0 + def test_negative_binomial(self): np.random.seed(self.seed) actual = np.random.negative_binomial(n=100, p=.12345, size=(3, 2)) From 7695f19f2f70729c93b79ede4032b3a9095c1688 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 4 Feb 2019 15:41:04 +0000 Subject: [PATCH 171/279] BUG: Ensure buffer_loc is reset in DSFMT Ensure buffer location is reset after reseed or jump to ensure that values are produced from the new state and not reused from the old. Ensure that the fallback path uses the correct number of bytes in Xor* Small doc fixes. --- _randomgen/doc/source/change-log.rst | 11 +++++++++++ _randomgen/randomgen/dsfmt.pyx | 18 +++++++++++++----- _randomgen/randomgen/mt19937.pyx | 4 ++-- _randomgen/randomgen/tests/test_direct.py | 6 ++++++ _randomgen/randomgen/xorshift1024.pyx | 2 +- _randomgen/randomgen/xoshiro512starstar.pyx | 4 ++-- 6 files changed, 35 insertions(+), 10 deletions(-) diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst index 629dd000281d..eb884c7f3fd7 100644 --- a/_randomgen/doc/source/change-log.rst +++ b/_randomgen/doc/source/change-log.rst @@ -1,5 +1,16 @@ Change Log ---------- +v1.15.2 +======= +- Fixed a bug that affected :class:`~randomgen.dsfmt.DSFMT` when calling + :func:`~randomgen.dsfmt.DSFMT.jump` or :func:`~randomgen.dsfmt.DSFMT.seed` + that failed to reset the buffer. This resulted in upto 381 values from the + previous state being used before the buffer was refilled at the new state. +- Fixed bugs in :class:`~randomgen.xoshiro512starstar.Xoshiro512StarStar` + and :class:`~randomgen.xorshift1024.Xorshift1024` where the fallback + entropy initialization used too few bytes. This bug is unlikely to be + encountered since this path is only encountered if the system random + number generator fails. v1.15.1 ======= diff --git a/_randomgen/randomgen/dsfmt.pyx b/_randomgen/randomgen/dsfmt.pyx index c83ade5cdf2f..ee8ef270d000 100644 --- a/_randomgen/randomgen/dsfmt.pyx +++ b/_randomgen/randomgen/dsfmt.pyx @@ -79,8 +79,8 @@ cdef class DSFMT: Can be an integer in [0, 2**32-1], array of integers in [0, 2**32-1] or ``None`` (the default). If `seed` is ``None``, then ``DSFMT`` will try to read entropy from ``/dev/urandom`` - (or the Windows analog) if available to produce a 64-bit - seed. If unavailable, a 64-bit hash of the time and process + (or the Windows analog) if available to produce a 32-bit + seed. If unavailable, a 32-bit hash of the time and process ID is used. Notes @@ -114,7 +114,7 @@ cdef class DSFMT: The ``DSFMT`` state vector consists of a 384 element array of 64-bit unsigned integers plus a single integer value between 0 and 382 indicating the current position within the main array. The implementation - used here augments this with a 384 element array of doubles which are used + used here augments this with a 382 element array of doubles which are used to efficiently access the random numbers produced by the dSFMT generator. ``DSFMT`` is seeded using either a single 32-bit unsigned integer @@ -182,6 +182,10 @@ cdef class DSFMT: free(self.rng_state) free(self._brng) + cdef _reset_state_variables(self): + self.rng_state.buffer_loc = DSFMT_N64 + + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): cdef Py_ssize_t i if method==u'uint64': @@ -206,8 +210,8 @@ cdef class DSFMT: Can be an integer in [0, 2**32-1], array of integers in [0, 2**32-1] or ``None`` (the default). If `seed` is ``None``, then ``DSFMT`` will try to read entropy from ``/dev/urandom`` - (or the Windows analog) if available to produce a 64-bit - seed. If unavailable, a 64-bit hash of the time and process + (or the Windows analog) if available to produce a 32-bit + seed. If unavailable, a 32-bit hash of the time and process ID is used. Raises @@ -238,6 +242,8 @@ cdef class DSFMT: dsfmt_init_by_array(self.rng_state.state, obj.data, np.PyArray_DIM(obj, 0)) + # Clear the buffer + self._reset_state_variables() def jump(self, np.npy_intp iter=1): """ @@ -258,6 +264,8 @@ cdef class DSFMT: cdef np.npy_intp i for i in range(iter): dsfmt_jump(self.rng_state) + # Clear the buffer + self._reset_state_variables() return self @property diff --git a/_randomgen/randomgen/mt19937.pyx b/_randomgen/randomgen/mt19937.pyx index 14ab24f39878..207ebc4bd578 100644 --- a/_randomgen/randomgen/mt19937.pyx +++ b/_randomgen/randomgen/mt19937.pyx @@ -206,8 +206,8 @@ cdef class MT19937: Can be an integer in [0, 2**32-1], array of integers in [0, 2**32-1] or ``None`` (the default). If `seed` is ``None``, then ``MT19937`` will try to read entropy from ``/dev/urandom`` - (or the Windows analog) if available to produce a 64-bit - seed. If unavailable, a 64-bit hash of the time and process + (or the Windows analog) if available to produce a 32-bit + seed. If unavailable, a 32-bit hash of the time and process ID is used. Raises diff --git a/_randomgen/randomgen/tests/test_direct.py b/_randomgen/randomgen/tests/test_direct.py index ee69d54163b1..5d251a3b71e3 100644 --- a/_randomgen/randomgen/tests/test_direct.py +++ b/_randomgen/randomgen/tests/test_direct.py @@ -428,6 +428,12 @@ def test_uniform_float(self): assert_allclose(uniforms, vals) assert_equal(uniforms.dtype, np.float32) + def test_buffer_reset(self): + rs = RandomGenerator(self.brng(*self.data1['seed'])) + u = rs.random_sample(1) + rs.seed(*self.data1['seed']) + assert rs.state['buffer_loc'] == 382 + class TestThreeFry32(Base): @classmethod diff --git a/_randomgen/randomgen/xorshift1024.pyx b/_randomgen/randomgen/xorshift1024.pyx index bf8f32e90de4..8341985b4c58 100644 --- a/_randomgen/randomgen/xorshift1024.pyx +++ b/_randomgen/randomgen/xorshift1024.pyx @@ -234,7 +234,7 @@ cdef class Xorshift1024: try: state = random_entropy(32) except RuntimeError: - state = random_entropy(4, 'fallback') + state = random_entropy(32, 'fallback') state = state.view(np.uint64) else: state = seed_by_array(seed, 16) diff --git a/_randomgen/randomgen/xoshiro512starstar.pyx b/_randomgen/randomgen/xoshiro512starstar.pyx index b4ab76158929..17fe3c420192 100644 --- a/_randomgen/randomgen/xoshiro512starstar.pyx +++ b/_randomgen/randomgen/xoshiro512starstar.pyx @@ -201,9 +201,9 @@ cdef class Xoshiro512StarStar: ub = 2 ** 64 if seed is None: try: - state = random_entropy(2 * 8) + state = random_entropy(16) except RuntimeError: - state = random_entropy(8, 'fallback') + state = random_entropy(16, 'fallback') state = state.view(np.uint64) else: state = seed_by_array(seed, 8) From a449164315d43b8e6bbdc5c8da533197e676e5bc Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 4 Feb 2019 16:30:37 +0000 Subject: [PATCH 172/279] DOC: Update dirichlet documentation Sync upstream changes --- _randomgen/randomgen/generator.pyx | 32 ++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 5d239c725f76..edc9ffd444a5 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -4068,8 +4068,9 @@ cdef class RandomGenerator: Draw `size` samples of dimension k from a Dirichlet distribution. A Dirichlet-distributed random variable can be seen as a multivariate - generalization of a Beta distribution. Dirichlet pdf is the conjugate - prior of a multinomial in Bayesian inference. + generalization of a Beta distribution. The Dirichlet distribution + is a conjugate prior of a multinomial distribution in Bayesian + inference. Parameters ---------- @@ -4086,15 +4087,30 @@ cdef class RandomGenerator: samples : ndarray, The drawn samples, of shape (size, alpha.ndim). + Raises + ------- + ValueError + If any value in alpha is less than or equal to zero + Notes ----- - .. math:: X \\approx \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i} + The Dirichlet distribution is a distribution over vectors + :math:`x` that fulfil the conditions :math:`x_i>0` and + :math:`\\sum_{i=1}^k x_i = 1`. + + The probability density function :math:`p` of a + Dirichlet-distributed random vector :math:`X` is + proportional to + + .. math:: p(x) \\propto \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i}, + + where :math:`\\alpha` is a vector containing the positive + concentration parameters. - Uses the following property for computation: for each dimension, - draw a random sample y_i from a standard gamma generator of shape - `alpha_i`, then - :math:`X = \\frac{1}{\\sum_{i=1}^k{y_i}} (y_1, \\ldots, y_n)` is - Dirichlet distributed. + The method uses the following property for computation: let :math:`Y` + be a random vector which has components that follow a standard gamma + distribution, then :math:`X = \\frac{1}{\\sum_{i=1}^k{Y_i}} Y` + is Dirichlet-distributed References ---------- From ec81a8ee2edf7cfe73188816316b56cc0857413b Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 4 Feb 2019 16:31:38 +0000 Subject: [PATCH 173/279] DOC: Update beta docstring Sync upstream changes --- _randomgen/randomgen/generator.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index edc9ffd444a5..2ff3dd1139a9 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -385,9 +385,9 @@ cdef class RandomGenerator: Parameters ---------- a : float or array_like of floats - Alpha, non-negative. + Alpha, positive (>0). b : float or array_like of floats - Beta, non-negative. + Beta, positive (>0). size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), From ea65884e7b097716b9b95254750b6c9acde6e1ba Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 4 Feb 2019 16:34:15 +0000 Subject: [PATCH 174/279] BUG: Fix weibull for a=0 Sync upstream change --- _randomgen/randomgen/generator.pyx | 2 +- _randomgen/randomgen/src/distributions/distributions.c | 3 +++ _randomgen/randomgen/tests/test_numpy_mt19937.py | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 2ff3dd1139a9..01fa7f1be1b7 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -2355,7 +2355,7 @@ cdef class RandomGenerator: Parameters ---------- a : float or array_like of floats - Shape of the distribution. Should be greater than zero. + Shape parameter of the distribution. Must be nonnegative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index e04259136e93..4e7493afaac0 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -573,6 +573,9 @@ double random_pareto(brng_t *brng_state, double a) { } double random_weibull(brng_t *brng_state, double a) { + if (a == 0.0) { + return 0.0; + } return pow(standard_exponential_zig(brng_state), 1. / a); } diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 888baf92f296..df458f2eee83 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -1104,7 +1104,8 @@ def test_weibull(self): assert_array_almost_equal(actual, desired, decimal=15) def test_weibull_0(self): - assert_equal(mt19937.weibull(a=0), 0) + mt19937.seed(self.seed) + assert_equal(mt19937.weibull(a=0, size=12), np.zeros(12)) assert_raises(ValueError, mt19937.weibull, a=-0.) def test_zipf(self): From 977b8a3324ebac0fe58bb7070a31e72a19ac4556 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 4 Feb 2019 16:44:06 +0000 Subject: [PATCH 175/279] CLN: Add language_level Sync upstream changes --- _randomgen/randomgen/common.pxd | 2 ++ _randomgen/randomgen/distributions.pxd | 2 ++ _randomgen/randomgen/legacy/legacy_distributions.pxd | 2 ++ 3 files changed, 6 insertions(+) diff --git a/_randomgen/randomgen/common.pxd b/_randomgen/randomgen/common.pxd index 62163ad62a0d..63a1b3f7d09f 100644 --- a/_randomgen/randomgen/common.pxd +++ b/_randomgen/randomgen/common.pxd @@ -1,3 +1,5 @@ +#cython: language_level=3 + from __future__ import absolute_import from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, diff --git a/_randomgen/randomgen/distributions.pxd b/_randomgen/randomgen/distributions.pxd index a50d5d821173..35d92db51bbb 100644 --- a/_randomgen/randomgen/distributions.pxd +++ b/_randomgen/randomgen/distributions.pxd @@ -1,3 +1,5 @@ +#cython: language_level=3 + from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t) import numpy as np diff --git a/_randomgen/randomgen/legacy/legacy_distributions.pxd b/_randomgen/randomgen/legacy/legacy_distributions.pxd index d22d6a73aacf..e2157f70605f 100644 --- a/_randomgen/randomgen/legacy/legacy_distributions.pxd +++ b/_randomgen/randomgen/legacy/legacy_distributions.pxd @@ -1,3 +1,5 @@ +#cython: language_level=3 + from libc.stdint cimport uint64_t import numpy as np From b42a1b1d1bf10fd1ce248b957bd69ae41430ed9a Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 4 Feb 2019 16:47:07 +0000 Subject: [PATCH 176/279] BUG: Raise on nan probabilities Sync upstream changes --- _randomgen/randomgen/generator.pyx | 9 ++++++--- _randomgen/randomgen/tests/test_numpy_mt19937.py | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 01fa7f1be1b7..5a3db7795706 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -824,12 +824,15 @@ cdef class RandomGenerator: pix = np.PyArray_DATA(p) if p.ndim != 1: - raise ValueError("p must be 1-dimensional") + raise ValueError("'p' must be 1-dimensional") if p.size != pop_size: - raise ValueError("a and p must have same size") + raise ValueError("'a' and 'p' must have same size") + p_sum = kahan_sum(pix, d) + if np.isnan(p_sum): + raise ValueError("probabilities contain NaN") if np.logical_or.reduce(p < 0): raise ValueError("probabilities are not non-negative") - if abs(kahan_sum(pix, d) - 1.) > atol: + if abs(p_sum - 1.) > atol: raise ValueError("probabilities do not sum to 1") shape = size diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index df458f2eee83..a43d7d601f46 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -607,6 +607,11 @@ def test_choice_return_shape(self): (3, 0, 4)) assert_raises(ValueError, mt19937.choice, [], 10) + def test_choice_nan_probabilities(self): + a = np.array([42, 1, 2]) + p = [None, None, None] + assert_raises(ValueError, mt19937.choice, a, p=p) + def test_bytes(self): mt19937.seed(self.seed) actual = mt19937.bytes(10) From 67ddb4c50b3b2605b6843762fb029836e4c3491d Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 4 Feb 2019 16:54:58 +0000 Subject: [PATCH 177/279] CLN: Remove trailing whitespace Sync upstream --- _randomgen/randomgen/entropy.pyx | 4 +-- .../randomgen/examples/cython/extending.pyx | 2 +- _randomgen/randomgen/generator.pyx | 34 +++++++++---------- _randomgen/randomgen/legacy/_legacy.pyx | 30 ++++++++-------- _randomgen/randomgen/mt19937.pyx | 18 +++++----- _randomgen/randomgen/pcg64.pyx | 4 +-- _randomgen/randomgen/threefry.pyx | 2 +- _randomgen/randomgen/xoroshiro128.pyx | 18 +++++----- _randomgen/randomgen/xorshift1024.pyx | 16 ++++----- 9 files changed, 64 insertions(+), 64 deletions(-) diff --git a/_randomgen/randomgen/entropy.pyx b/_randomgen/randomgen/entropy.pyx index 2c85066c1d9d..d7822bfdf412 100644 --- a/_randomgen/randomgen/entropy.pyx +++ b/_randomgen/randomgen/entropy.pyx @@ -28,14 +28,14 @@ cdef Py_ssize_t compute_numel(size): def seed_by_array(object seed, Py_ssize_t n): """ Transforms a seed array into an initial state - + Parameters ---------- seed: array, 1d, uint64 Array to use. If seed is a scalar, promote to array. n : int Number of 64-bit unsigned integers required - + Notes ----- Uses splitmix64 to perform the transformation diff --git a/_randomgen/randomgen/examples/cython/extending.pyx b/_randomgen/randomgen/examples/cython/extending.pyx index 420bb17eaa37..c387a13af4f3 100644 --- a/_randomgen/randomgen/examples/cython/extending.pyx +++ b/_randomgen/randomgen/examples/cython/extending.pyx @@ -52,7 +52,7 @@ def bounded_uints(uint32_t lb, uint32_t ub, Py_ssize_t n): x = Xoroshiro128() out = np.empty(n, dtype=np.uint32) capsule = x.capsule - + if not PyCapsule_IsValid(capsule, capsule_name): raise ValueError("Invalid pointer to anon_func_state") rng = PyCapsule_GetPointer(capsule, capsule_name) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 5a3db7795706..abde2f4946ed 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -2,11 +2,11 @@ #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3 from __future__ import absolute_import -import operator +import operator import warnings from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer -from cpython cimport (Py_INCREF, PyComplex_RealAsDouble, +from cpython cimport (Py_INCREF, PyComplex_RealAsDouble, PyComplex_ImagAsDouble, PyComplex_FromDoubles, PyFloat_AsDouble) from libc cimport string from libc.stdlib cimport malloc, free @@ -141,7 +141,7 @@ cdef class RandomGenerator: Notes ----- Arguments are directly passed to the basic RNG. This is a convenience - function. + function. The best method to access seed is to directly use a basic RNG instance. This example demonstrates this best practice. @@ -156,8 +156,8 @@ cdef class RandomGenerator: >>> brng = PCG64(1234567891011) >>> rg = RandomGenerator(brng) >>> brng.seed(1110987654321) - - These best practice examples are equivalent to + + These best practice examples are equivalent to >>> rg = RandomGenerator(PCG64(1234567891011)) >>> rg.seed(1110987654321) @@ -176,10 +176,10 @@ cdef class RandomGenerator: state : dict Dictionary containing the information required to describe the state of the Basic RNG - + Notes ----- - This is a trivial pass-through function. RandomGenerator does not + This is a trivial pass-through function. RandomGenerator does not directly contain or manipulate the basic RNG's state. """ return self._basicrng.state @@ -260,7 +260,7 @@ cdef class RandomGenerator: ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. output : bool, optional - Output values. Used for performance testing since the generated + Output values. Used for performance testing since the generated values are not returned. Returns @@ -290,7 +290,7 @@ cdef class RandomGenerator: for i in range(n): self._brng.next_raw(self._brng.state) return None - + if size is None: with self.lock: return self._brng.next_raw(self._brng.state) @@ -684,7 +684,7 @@ cdef class RandomGenerator: ret = _rand_uint8(low, high, size, use_masked, self._brng, self.lock) elif key == 'bool': ret = _rand_bool(low, high, size, use_masked, self._brng, self.lock) - + if size is None and dtype in (np.bool, np.int, np.long): if np.array(ret).shape == (): return dtype(ret) @@ -1128,7 +1128,7 @@ cdef class RandomGenerator: Return random integers of type np.int64 from the "discrete uniform" distribution in the closed interval [`low`, `high`]. If `high` is - None (the default), then results are from [1, `low`]. + None (the default), then results are from [1, `low`]. This function has been deprecated. Use randint instead. @@ -1392,7 +1392,7 @@ cdef class RandomGenerator: ----- **EXPERIMENTAL** Not part of official NumPy RandomState, may change until formal release on PyPi. - + Complex normals are generated from a bivariate normal where the variance of the real component is 0.5 Re(gamma + relation), the variance of the imaginary component is 0.5 Re(gamma - relation), and @@ -4293,7 +4293,7 @@ cdef class RandomGenerator: def permutation(self, object x): """ permutation(x) - + Randomly permute a sequence, or return a permuted range. If `x` is a multi-dimensional array, it is only shuffled along its @@ -4305,20 +4305,20 @@ cdef class RandomGenerator: If `x` is an integer, randomly permute ``np.arange(x)``. If `x` is an array, make a copy and shuffle the elements randomly. - + Returns ------- out : ndarray Permuted sequence or array range. - + Examples -------- >>> np.random.permutation(10) array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) - + >>> np.random.permutation([1, 4, 9, 12, 15]) array([15, 1, 9, 4, 12]) - + >>> arr = np.arange(9).reshape((3, 3)) >>> np.random.permutation(arr) array([[6, 7, 8], diff --git a/_randomgen/randomgen/legacy/_legacy.pyx b/_randomgen/randomgen/legacy/_legacy.pyx index 030c057de657..1c206ec914e2 100644 --- a/_randomgen/randomgen/legacy/_legacy.pyx +++ b/_randomgen/randomgen/legacy/_legacy.pyx @@ -33,11 +33,11 @@ cdef class _LegacyGenerator: ``_LegacyGenerator`` exposes a number of methods for generating random numbers for a set of distributions where the method used to produce random samples has changed. Three core generators have changed: normal, exponential - and gamma. These have been replaced by faster Ziggurat-based methods in + and gamma. These have been replaced by faster Ziggurat-based methods in ``RandomGenerator``. ``_LegacyGenerator`` retains the slower methods to produce samples from these distributions as well as from distributions that depend on these such as the Chi-square, power or Weibull. - + **No Compatibility Guarantee** ``_LegacyGenerator`` is evolving and so it isn't possible to provide a @@ -55,9 +55,9 @@ cdef class _LegacyGenerator: Examples -------- Exactly reproducing a NumPy stream requires both a ``RandomGenerator`` - and a ``_LegacyGenerator``. These must share a common ``MT19937`` basic - RNG. Functions that are available in LegacyGenerator must be called - from ``_LegacyGenerator``, and other functions must be called from + and a ``_LegacyGenerator``. These must share a common ``MT19937`` basic + RNG. Functions that are available in LegacyGenerator must be called + from ``_LegacyGenerator``, and other functions must be called from ``RandomGenerator``. >>> from randomgen import RandomGenerator, MT19937 @@ -71,7 +71,7 @@ cdef class _LegacyGenerator: 0.09290787674371767 >>> lg.standard_exponential() 1.6465621229906502 - + The equivalent commands from NumPy produce identical output. >>> from numpy.random import RandomState @@ -98,7 +98,7 @@ cdef class _LegacyGenerator: if not PyCapsule_IsValid(capsule, name): raise ValueError("Invalid brng. The brng must be instantized.") self._brng = PyCapsule_GetPointer(capsule, name) - self._aug_state = malloc(sizeof(aug_brng_t)) + self._aug_state = malloc(sizeof(aug_brng_t)) self._aug_state.basicrng = self._brng self._reset_gauss() self.lock = Lock() @@ -137,7 +137,7 @@ cdef class _LegacyGenerator: Notes ----- Arguments are directly passed to the basic RNG. This is a convenience - function. + function. The best method to access seed is to directly use a basic RNG instance. This example demonstrates this best practice. @@ -153,8 +153,8 @@ cdef class _LegacyGenerator: >>> brng = MT19937(123456789) >>> lg = LegacyGenerator(brng) >>> brng.seed(987654321) - - These best practice examples are equivalent to + + These best practice examples are equivalent to >>> lg = LegacyGenerator(MT19937(123456789)) >>> lg.seed(987654321) @@ -191,7 +191,7 @@ cdef class _LegacyGenerator: if isinstance(value, tuple): if value[0] != 'MT19937': raise ValueError('tuple only supported for MT19937') - st = {'brng': value[0], + st = {'brng': value[0], 'state': {'key': value[1], 'pos': value[2]}} if len(value) > 3: st['has_gauss'] = value[3] @@ -236,7 +236,7 @@ cdef class _LegacyGenerator: return cont(&legacy_gauss, self._aug_state, size, self.lock, 0, None, None, CONS_NONE, None, None, CONS_NONE, - None, None, CONS_NONE, + None, None, CONS_NONE, None) def standard_t(self, df, size=None): @@ -1623,7 +1623,7 @@ cdef class _LegacyGenerator: while i < totsize: acc = 0.0 for j in range(k): - val_data[i+j] = legacy_standard_gamma(self._aug_state, + val_data[i+j] = legacy_standard_gamma(self._aug_state, alpha_data[j]) acc = acc + val_data[i + j] invacc = 1/acc @@ -1773,7 +1773,7 @@ cdef class _LegacyGenerator: # matrices should be equal up to roundoff error if cov is # symmetric and the singular value of the corresponding row is # not zero. We continue to use the SVD rather than Cholesky in - # order to preserve current outputs. + # order to preserve current outputs. (u, s, v) = svd(cov) @@ -1828,7 +1828,7 @@ cdef class _LegacyGenerator: return cont(&legacy_standard_exponential, self._aug_state, size, self.lock, 0, None, None, CONS_NONE, None, None, CONS_NONE, - None, None, CONS_NONE, + None, None, CONS_NONE, None) def exponential(self, scale=1.0, size=None): diff --git a/_randomgen/randomgen/mt19937.pyx b/_randomgen/randomgen/mt19937.pyx index 207ebc4bd578..c88dd02b9686 100644 --- a/_randomgen/randomgen/mt19937.pyx +++ b/_randomgen/randomgen/mt19937.pyx @@ -55,7 +55,7 @@ cdef class MT19937: Random seed used to initialize the pseudo-random number generator. Can be any integer between 0 and 2**32 - 1 inclusive, an array (or other sequence) of such integers, or ``None`` (the default). If `seed` is - ``None``, then will attempt to read data from ``/dev/urandom`` + ``None``, then will attempt to read data from ``/dev/urandom`` (or the Windows analog) if available or seed from the clock otherwise. Notes @@ -82,10 +82,10 @@ cdef class MT19937: **Compatibility Guarantee** - ``MT19937`` make a compatibility guarantee. A fixed seed and a fixed - series of calls to ``MT19937`` methods will always produce the same - results up to roundoff error except when the values were incorrect. - Incorrect values will be fixed and the version in which the fix was + ``MT19937`` make a compatibility guarantee. A fixed seed and a fixed + series of calls to ``MT19937`` methods will always produce the same + results up to roundoff error except when the values were incorrect. + Incorrect values will be fixed and the version in which the fix was made will be noted in the relevant docstring. **Parallel Features** @@ -109,10 +109,10 @@ cdef class MT19937: ---------- .. [1] Hiroshi Haramoto, Makoto Matsumoto, and Pierre L\'Ecuyer, "A Fast Jump Ahead Algorithm for Linear Recurrences in a Polynomial Space", - Sequences and Their Applications - SETA, 290--298, 2008. - .. [2] Hiroshi Haramoto, Makoto Matsumoto, Takuji Nishimura, François + Sequences and Their Applications - SETA, 290--298, 2008. + .. [2] Hiroshi Haramoto, Makoto Matsumoto, Takuji Nishimura, François Panneton, Pierre L\'Ecuyer, "Efficient Jump Ahead for F2-Linear - Random Number Generators", INFORMS JOURNAL ON COMPUTING, Vol. 20, + Random Number Generators", INFORMS JOURNAL ON COMPUTING, Vol. 20, No. 3, Summer 2008, pp. 385-390. """ @@ -253,7 +253,7 @@ cdef class MT19937: self : DSFMT PRNG jumped iter times """ - cdef np.npy_intp i + cdef np.npy_intp i for i in range(iter): mt19937_jump(self.rng_state) return self diff --git a/_randomgen/randomgen/pcg64.pyx b/_randomgen/randomgen/pcg64.pyx index e7939314e626..44e123d4ca24 100644 --- a/_randomgen/randomgen/pcg64.pyx +++ b/_randomgen/randomgen/pcg64.pyx @@ -254,7 +254,7 @@ cdef class PCG64: _seed = np.empty(2, np.uint64) _seed[0] = int(seed) // 2**64 _seed[1] = int(seed) % 2**64 - + if not np.isscalar(inc): raise TypeError('inc must be a scalar integer between 0 and {ub}'.format(ub=ub)) if inc < 0 or inc > ub or int(inc) != inc: @@ -262,7 +262,7 @@ cdef class PCG64: _inc = np.empty(2, np.uint64) _inc[0] = int(inc) // 2**64 _inc[1] = int(inc) % 2**64 - + pcg64_set_seed(self.rng_state, _seed.data, _inc.data) self._reset_state_variables() diff --git a/_randomgen/randomgen/threefry.pyx b/_randomgen/randomgen/threefry.pyx index cb3c78f5bfbf..96e65f62529e 100644 --- a/_randomgen/randomgen/threefry.pyx +++ b/_randomgen/randomgen/threefry.pyx @@ -99,7 +99,7 @@ cdef class ThreeFry: ``ThreeFry`` can be used in parallel applications by calling the method ``jump`` which advances the state as-if :math:`2^{128}` random numbers have been generated. Alternatively, - ``advance`` can be used to advance the counter for an any + ``advance`` can be used to advance the counter for an any positive step in [0, 2**256). When using ``jump``, all generators should be initialized with the same seed to ensure that the segments come from the same sequence. Alternatively, ``ThreeFry`` can be used diff --git a/_randomgen/randomgen/xoroshiro128.pyx b/_randomgen/randomgen/xoroshiro128.pyx index d9891e590334..57760c53a7a1 100644 --- a/_randomgen/randomgen/xoroshiro128.pyx +++ b/_randomgen/randomgen/xoroshiro128.pyx @@ -142,7 +142,7 @@ cdef class Xoroshiro128: self._ctypes = None self._cffi = None self._generator = None - + cdef const char *name = "BasicRNG" self.capsule = PyCapsule_New(self._brng, name, NULL) @@ -292,17 +292,17 @@ cdef class Xoroshiro128: return self._ctypes import ctypes - + self._ctypes = interface(self.rng_state, ctypes.c_void_p(self.rng_state), - ctypes.cast(&xoroshiro128_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.cast(&xoroshiro128_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&xoroshiro128_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.cast(&xoroshiro128_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&xoroshiro128_double, - ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.cast(&xoroshiro128_double, + ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), ctypes.c_void_p(self._brng)) return self.ctypes @@ -327,7 +327,7 @@ cdef class Xoroshiro128: if self._cffi is not None: return self._cffi try: - import cffi + import cffi except ImportError: raise ImportError('cffi is cannot be imported.') diff --git a/_randomgen/randomgen/xorshift1024.pyx b/_randomgen/randomgen/xorshift1024.pyx index 8341985b4c58..e7ad546e0ea6 100644 --- a/_randomgen/randomgen/xorshift1024.pyx +++ b/_randomgen/randomgen/xorshift1024.pyx @@ -325,17 +325,17 @@ cdef class Xorshift1024: return self._ctypes import ctypes - + self._ctypes = interface(self.rng_state, ctypes.c_void_p(self.rng_state), - ctypes.cast(&xorshift1024_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.cast(&xorshift1024_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.c_void_p)), - ctypes.cast(&xorshift1024_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.cast(&xorshift1024_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_void_p)), - ctypes.cast(&xorshift1024_double, - ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.cast(&xorshift1024_double, + ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_void_p)), ctypes.c_void_p(self._brng)) return self.ctypes @@ -360,7 +360,7 @@ cdef class Xorshift1024: if self._cffi is not None: return self._cffi try: - import cffi + import cffi except ImportError: raise ImportError('cffi is cannot be imported.') From 197da5e846e01c77d88fbe34619f22862da630c8 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 4 Feb 2019 18:20:03 +0000 Subject: [PATCH 178/279] DOC: Fix doc strings Sync with upstream --- _randomgen/doc/source/conf.py | 13 ++ _randomgen/randomgen/__init__.py | 3 +- _randomgen/randomgen/generator.pyx | 237 +++++++++++----------- _randomgen/randomgen/legacy/_legacy.pyx | 73 +++---- _randomgen/randomgen/tests/test_direct.py | 3 +- 5 files changed, 177 insertions(+), 152 deletions(-) diff --git a/_randomgen/doc/source/conf.py b/_randomgen/doc/source/conf.py index 4b38c42d5370..d4290d173d9c 100644 --- a/_randomgen/doc/source/conf.py +++ b/_randomgen/doc/source/conf.py @@ -206,3 +206,16 @@ } autosummary_generate = True + +doctest_global_setup = """ +import numpy as np + +import randomgen + +import matplotlib.pyplot + +def show(*args, **kwargs): + return + +matplotlib.pyplot.show = show +""" diff --git a/_randomgen/randomgen/__init__.py b/_randomgen/randomgen/__init__.py index 7529922195b0..b4c942c8fa8d 100644 --- a/_randomgen/randomgen/__init__.py +++ b/_randomgen/randomgen/__init__.py @@ -13,7 +13,8 @@ __all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'PCG32', 'Philox', 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024', - 'Xoshiro256StarStar', 'Xoshiro512StarStar'] + 'Xoshiro256StarStar', 'Xoshiro512StarStar', + 'hypergeometric', 'multinomial', 'random_sample'] from ._version import get_versions diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index abde2f4946ed..2d45f8aca2f0 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -339,17 +339,17 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.random_sample() - 0.47108547995356098 - >>> type(randomgen.random_sample()) - - >>> randomgen.random_sample((5,)) - array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) + >>> randomgen.generator.random_sample() + 0.47108547995356098 # random + >>> type(randomgen.generator.random_sample()) + + >>> randomgen.generator.random_sample((5,)) + array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) # random Three-by-two array of random numbers from [-5, 0): >>> 5 * randomgen.random_sample((3, 2)) - 5 - array([[-3.99149989, -0.52338984], + array([[-3.99149989, -0.52338984], # random [-2.99091858, -0.79479508], [-1.23204345, -1.75224494]]) """ @@ -493,7 +493,7 @@ cdef class RandomGenerator: -------- Output a 3x8000 array: - >>> n = randomgen.standard_exponential((3, 8000)) + >>> n = randomgen.generator.standard_exponential((3, 8000)) """ key = np.dtype(dtype).name if key == 'float64': @@ -541,7 +541,7 @@ cdef class RandomGenerator: -------- >>> rg = randomgen.RandomGenerator() # need a RandomGenerator object >>> rg.tomaxint((2,2,2)) - array([[[1170048599, 1600360186], + array([[[1170048599, 1600360186], # random [ 739731006, 1947757578]], [[1871712945, 752307660], [1601631370, 1479324245]]]) @@ -626,30 +626,30 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.randint(2, size=10) - array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) - >>> randomgen.randint(1, size=10) + >>> randomgen.generator.randint(2, size=10) + array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) # random + >>> randomgen.generator.randint(1, size=10) array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) Generate a 2 x 4 array of ints between 0 and 4, inclusive: - >>> randomgen.randint(5, size=(2, 4)) - array([[4, 0, 2, 1], + >>> randomgen.generator.randint(5, size=(2, 4)) + array([[4, 0, 2, 1], # random [3, 2, 2, 0]]) Generate a 1 x 3 array with 3 different upper bounds - >>> randomgen.randint(1, [3, 5, 10]) + >>> randomgen.generator.randint(1, [3, 5, 10]) array([2, 2, 9]) Generate a 1 by 3 array with 3 different lower bounds - >>> randomgen.randint([1, 5, 7], 10) + >>> randomgen.generator.randint([1, 5, 7], 10) array([9, 8, 7]) Generate a 2 by 4 array using broadcasting with dtype of uint8 - >>> randomgen.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) + >>> randomgen.generator.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) array([[ 8, 6, 9, 7], [ 1, 16, 9, 12]], dtype=uint8) @@ -708,7 +708,7 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.bytes(10) + >>> randomgen.generator.bytes(10) ' eh\\x85\\x022SZ\\xbf\\xa4' #random """ @@ -763,35 +763,35 @@ cdef class RandomGenerator: -------- Generate a uniform random sample from np.arange(5) of size 3: - >>> randomgen.choice(5, 3) - array([0, 3, 4]) + >>> randomgen.generator.choice(5, 3) + array([0, 3, 4]) # random >>> #This is equivalent to randomgen.randint(0,5,3) Generate a non-uniform random sample from np.arange(5) of size 3: - >>> randomgen.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) - array([3, 3, 0]) + >>> randomgen.generator.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) + array([3, 3, 0]) # random Generate a uniform random sample from np.arange(5) of size 3 without replacement: - >>> randomgen.choice(5, 3, replace=False) - array([3,1,0]) + >>> randomgen.generator.choice(5, 3, replace=False) + array([3,1,0]) # random >>> #This is equivalent to randomgen.permutation(np.arange(5))[:3] Generate a non-uniform random sample from np.arange(5) of size 3 without replacement: - >>> randomgen.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) - array([2, 3, 0]) + >>> randomgen.generator.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) + array([2, 3, 0]) # random Any of the above can be repeated with an arbitrary array-like instead of just integers. For instance: >>> aa_milne_arr = ['pooh', 'rabbit', 'piglet', 'Christopher'] - >>> randomgen.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) - array(['pooh', 'pooh', 'pooh', 'Christopher', 'piglet'], - dtype='|S11') + >>> randomgen.generator.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) + array(['pooh', 'pooh', 'pooh', 'Christopher', 'piglet'], # random + dtype='>> s = randomgen.uniform(-1,0,1000) + >>> s = randomgen.generator.uniform(-1,0,1000) All values are within the given interval: @@ -1049,7 +1049,7 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.rand(3,2) + >>> randomgen.generator.rand(3,2) array([[ 0.14022471, 0.96360618], #random [ 0.37601032, 0.25528411], #random [ 0.49313049, 0.94909878]]) #random @@ -1105,12 +1105,12 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.randn() + >>> randomgen.generator.randn() 2.1923875335537315 #random Two-by-four array of samples from N(3, 6.25): - >>> 2.5 * randomgen.randn(2, 4) + 3 + >>> 2.5 * randomgen.generator.randn(2, 4) + 3 array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random @@ -1169,12 +1169,12 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.random_integers(5) - 4 - >>> type(randomgen.random_integers(5)) - - >>> randomgen.random_integers(5, size=(3.,2.)) - array([[5, 4], + >>> randomgen.generator.random_integers(5) + 4 # random + >>> type(randomgen.generator.random_integers(5)) + + >>> randomgen.generator.random_integers(5, size=(3, 2)) + array([[5, 4], # random [3, 3], [4, 5]]) @@ -1182,13 +1182,13 @@ cdef class RandomGenerator: numbers between 0 and 2.5, inclusive (*i.e.*, from the set :math:`{0, 5/8, 10/8, 15/8, 20/8}`): - >>> 2.5 * (randomgen.random_integers(5, size=(5,)) - 1) / 4. - array([ 0.625, 1.25 , 0.625, 0.625, 2.5 ]) + >>> 2.5 * (randomgen.generator.random_integers(5, size=(5,)) - 1) / 4. + array([ 0.625, 1.25 , 0.625, 0.625, 2.5 ]) # random Roll two six sided dice 1000 times and sum the results: - >>> d1 = randomgen.random_integers(1, 6, 1000) - >>> d2 = randomgen.random_integers(1, 6, 1000) + >>> d1 = randomgen.generator.random_integers(1, 6, 1000) + >>> d2 = randomgen.generator.random_integers(1, 6, 1000) >>> dsums = d1 + d2 Display results as a histogram: @@ -1241,13 +1241,13 @@ cdef class RandomGenerator: Examples -------- - >>> s = randomgen.standard_normal(8000) + >>> s = randomgen.generator.standard_normal(8000) >>> s array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random -0.38672696, -0.4685006 ]) #random >>> s.shape (8000,) - >>> s = randomgen.standard_normal(size=(3, 4, 2)) + >>> s = randomgen.generator.standard_normal(size=(3, 4, 2)) >>> s.shape (3, 4, 2) @@ -1330,7 +1330,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, sigma = 0, 0.1 # mean and standard deviation - >>> s = randomgen.normal(mu, sigma, 1000) + >>> s = randomgen.generator.normal(mu, sigma, 1000) Verify the mean and the variance: @@ -1412,7 +1412,7 @@ cdef class RandomGenerator: -------- Draw samples from the distribution: - >>> s = randomgen.complex_normal(size=1000) + >>> s = randomgen.generator.complex_normal(size=1000) """ cdef np.ndarray ogamma, orelation, oloc, randoms, v_real, v_imag, rho cdef double *randoms_data @@ -1581,7 +1581,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> shape, scale = 2., 1. # mean and width - >>> s = randomgen.standard_gamma(shape, 1000000) + >>> s = randomgen.generator.standard_gamma(shape, 1000000) Display the histogram of the samples, along with the probability density function: @@ -1668,7 +1668,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> shape, scale = 2., 2. # mean and dispersion - >>> s = randomgen.gamma(shape, scale, 1000) + >>> s = randomgen.generator.gamma(shape, scale, 1000) Display the histogram of the samples, along with the probability density function: @@ -1758,12 +1758,12 @@ cdef class RandomGenerator: >>> dfnum = 1. # between group degrees of freedom >>> dfden = 48. # within groups degrees of freedom - >>> s = randomgen.f(dfnum, dfden, 1000) + >>> s = randomgen.generator.f(dfnum, dfden, 1000) The lower bound for the top 1% of the samples is : - >>> sort(s)[-10] - 7.61988120985 + >>> np.sort(s)[-10] + 7.61988120985 # random So there is about a 1% chance that the F statistic will exceed 7.62, the measured value is 36, so the null hypothesis is rejected at the 1% @@ -1833,10 +1833,11 @@ cdef class RandomGenerator: >>> dfnum = 3 # between group deg of freedom >>> dfden = 20 # within groups degrees of freedom >>> nonc = 3.0 - >>> nc_vals = randomgen.noncentral_f(dfnum, dfden, nonc, 1000000) + >>> nc_vals = randomgen.generator.noncentral_f(dfnum, dfden, nonc, 1000000) >>> NF = np.histogram(nc_vals, bins=50, density=True) - >>> c_vals = randomgen.f(dfnum, dfden, 1000000) + >>> c_vals = randomgen.generator.f(dfnum, dfden, 1000000) >>> F = np.histogram(c_vals, bins=50, density=True) + >>> import matplotlib.pyplot as plt >>> plt.plot(F[1][1:], F[0]) >>> plt.plot(NF[1][1:], NF[0]) >>> plt.show() @@ -1906,8 +1907,8 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.chisquare(2,4) - array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) + >>> randomgen.generator.chisquare(2,4) + array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) # random """ return cont(&random_chisquare, self._brng, size, self.lock, 1, @@ -1971,7 +1972,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram >>> import matplotlib.pyplot as plt - >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, 20, 100000), ... bins=200, density=True) >>> plt.show() @@ -1979,9 +1980,9 @@ cdef class RandomGenerator: and compare to a chisquare. >>> plt.figure() - >>> values = plt.hist(randomgen.noncentral_chisquare(3, .0000001, 100000), + >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, .0000001, 100000), ... bins=np.arange(0., 25, .1), density=True) - >>> values2 = plt.hist(randomgen.chisquare(3, 100000), + >>> values2 = plt.hist(randomgen.generator.chisquare(3, 100000), ... bins=np.arange(0., 25, .1), density=True) >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') >>> plt.show() @@ -1990,7 +1991,7 @@ cdef class RandomGenerator: distribution. >>> plt.figure() - >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, 20, 100000), ... bins=200, density=True) >>> plt.show() @@ -2055,8 +2056,9 @@ cdef class RandomGenerator: -------- Draw samples and plot the distribution: - >>> s = randomgen.standard_cauchy(1000000) + >>> s = randomgen.generator.standard_cauchy(1000000) >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well + >>> import matplotlib.pyplot as plt >>> plt.hist(s, bins=100) >>> plt.show() @@ -2128,7 +2130,7 @@ cdef class RandomGenerator: We have 10 degrees of freedom, so is the sample mean within 95% of the recommended value? - >>> s = randomgen.standard_t(10, size=100000) + >>> s = randomgen.generator.standard_t(10, size=100000) >>> np.mean(intake) 6753.636363636364 >>> intake.std(ddof=1) @@ -2222,7 +2224,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, kappa = 0.0, 4.0 # mean and dispersion - >>> s = randomgen.vonmises(mu, kappa, 1000) + >>> s = randomgen.generator.vonmises(mu, kappa, 1000) Display the histogram of the samples, along with the probability density function: @@ -2322,7 +2324,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a, m = 3., 2. # shape and mode - >>> s = (randomgen.pareto(a, 1000) + 1) * m + >>> s = (randomgen.generator.pareto(a, 1000) + 1) * m Display the histogram of the samples, along with the probability density function: @@ -2415,7 +2417,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a = 5. # shape - >>> s = randomgen.weibull(a, 1000) + >>> s = randomgen.generator.weibull(a, 1000) Display the histogram of the samples, along with the probability density function: @@ -2425,7 +2427,7 @@ cdef class RandomGenerator: >>> def weib(x,n,a): ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) - >>> count, bins, ignored = plt.hist(randomgen.weibull(5.,1000)) + >>> count, bins, ignored = plt.hist(randomgen.generator.weibull(5.,1000)) >>> x = np.arange(1,100.)/50. >>> scale = count.max()/weib(x, 1., 5.).max() >>> plt.plot(x, weib(x, 1., 5.)*scale) @@ -2495,7 +2497,7 @@ cdef class RandomGenerator: >>> a = 5. # shape >>> samples = 1000 - >>> s = randomgen.power(a, samples) + >>> s = randomgen.generator.power(a, samples) Display the histogram of the samples, along with the probability density function: @@ -2511,8 +2513,8 @@ cdef class RandomGenerator: Compare the power function distribution to the inverse of the Pareto. >>> from scipy import stats - >>> rvs = randomgen.power(5, 1000000) - >>> rvsp = randomgen.pareto(5, 1000000) + >>> rvs = randomgen.generator.power(5, 1000000) + >>> rvsp = randomgen.generator.pareto(5, 1000000) >>> xx = np.linspace(0,1,100) >>> powpdf = stats.powerlaw.pdf(xx,5) @@ -2598,7 +2600,7 @@ cdef class RandomGenerator: Draw samples from the distribution >>> loc, scale = 0., 1. - >>> s = randomgen.laplace(loc, scale, 1000) + >>> s = randomgen.generator.laplace(loc, scale, 1000) Display the histogram of the samples, along with the probability density function: @@ -2700,7 +2702,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, beta = 0, 0.1 # location and scale - >>> s = randomgen.gumbel(mu, beta, 1000) + >>> s = randomgen.generator.gumbel(mu, beta, 1000) Display the histogram of the samples, along with the probability density function: @@ -2718,7 +2720,7 @@ cdef class RandomGenerator: >>> means = [] >>> maxima = [] >>> for i in range(0,1000) : - ... a = randomgen.normal(mu, beta, 1000) + ... a = randomgen.generator.normal(mu, beta, 1000) ... means.append(a.mean()) ... maxima.append(a.max()) >>> count, bins, ignored = plt.hist(maxima, 30, density=True) @@ -2800,15 +2802,16 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> loc, scale = 10, 1 - >>> s = randomgen.logistic(loc, scale, 10000) + >>> s = randomgen.generator.logistic(loc, scale, 10000) + >>> import matplotlib.pyplot as plt >>> count, bins, ignored = plt.hist(s, bins=50) # plot against distribution >>> def logist(x, loc, scale): - ... return exp((loc-x)/scale)/(scale*(1+exp((loc-x)/scale))**2) - >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\\ - ... logist(bins, loc, scale).max()) + ... return np.exp((loc-x)/scale)/(scale*(1+np.exp((loc-x)/scale))**2) + >>> scale = logist(bins, loc, scale).max() + >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/scale) >>> plt.show() """ @@ -2882,7 +2885,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, sigma = 3., 1. # mean and standard deviation - >>> s = randomgen.lognormal(mu, sigma, 1000) + >>> s = randomgen.generator.lognormal(mu, sigma, 1000) Display the histogram of the samples, along with the probability density function: @@ -2906,7 +2909,7 @@ cdef class RandomGenerator: >>> # values, drawn from a normal distribution. >>> b = [] >>> for i in range(1000): - ... a = 10. + randomgen.random(100) + ... a = 10. + randomgen.generator.randn(100) ... b.append(np.product(a)) >>> b = np.array(b) / np.min(b) # scale values to be positive @@ -2973,7 +2976,8 @@ cdef class RandomGenerator: -------- Draw values from the distribution and plot the histogram - >>> values = hist(randomgen.rayleigh(3, 100000), bins=200, density=True) + >>> from matplotlib.pyplot import hist + >>> values = hist(randomgen.generator.rayleigh(3, 100000), bins=200, density=True) Wave heights tend to follow a Rayleigh distribution. If the mean wave height is 1 meter, what fraction of waves are likely to be larger than 3 @@ -2981,12 +2985,12 @@ cdef class RandomGenerator: >>> meanvalue = 1 >>> modevalue = np.sqrt(2 / np.pi) * meanvalue - >>> s = randomgen.rayleigh(modevalue, 1000000) + >>> s = randomgen.generator.rayleigh(modevalue, 1000000) The percentage of waves larger than 3 meters is: >>> 100.*sum(s>3)/1000000. - 0.087300000000000003 + 0.087300000000000003 # random """ return cont(&random_rayleigh, self._brng, size, self.lock, 1, @@ -3053,7 +3057,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(randomgen.wald(3, 2, 100000), bins=200, density=True) + >>> h = plt.hist(randomgen.generator.wald(3, 2, 100000), bins=200, density=True) >>> plt.show() """ @@ -3120,7 +3124,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(randomgen.triangular(-3, 0, 8, 100000), bins=200, + >>> h = plt.hist(randomgen.generator.triangular(-3, 0, 8, 100000), bins=200, ... density=True) >>> plt.show() @@ -3233,7 +3237,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> n, p = 10, .5 # number of trials, probability of each trial - >>> s = randomgen.binomial(n, p, 1000) + >>> s = randomgen.generator.binomial(n, p, 1000) # result of flipping a coin 10 times, tested 1000 times. A real world example. A company drills 9 wild-cat oil exploration @@ -3243,7 +3247,7 @@ cdef class RandomGenerator: Let's do 20,000 trials of the model, and count the number that generate zero positive results. - >>> sum(randomgen.binomial(9, 0.1, 20000) == 0)/20000. + >>> sum(randomgen.generator.binomial(9, 0.1, 20000) == 0)/20000. # answer = 0.38885, or 38%. """ @@ -3368,10 +3372,10 @@ cdef class RandomGenerator: for each successive well, that is what is the probability of a single success after drilling 5 wells, after 6 wells, etc.? - >>> s = np.random.negative_binomial(1, 0.9, 100000) - >>> for i in range(1, 11): + >>> s = randomgen.generator.negative_binomial(1, 0.9, 100000) + >>> for i in range(1, 11): # doctest: +SKIP ... probability = sum(s>> import numpy as np - >>> s = randomgen.poisson(5, 10000) + >>> s = randomgen.generator.poisson(5, 10000) Display histogram of the sample: @@ -3442,7 +3446,7 @@ cdef class RandomGenerator: Draw each 100 values for lambda 100 and 500: - >>> s = randomgen.poisson(lam=(100., 500.), size=(100, 2)) + >>> s = randomgen.generator.poisson(lam=(100., 500.), size=(100, 2)) """ return disc(&random_poisson, self._brng, size, self.lock, 1, 0, @@ -3507,7 +3511,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a = 2. # parameter - >>> s = randomgen.zipf(a, 1000) + >>> s = randomgen.generator.zipf(a, 1000) Display the histogram of the samples, along with the probability density function: @@ -3567,7 +3571,7 @@ cdef class RandomGenerator: Draw ten thousand values from the geometric distribution, with the probability of an individual success equal to 0.35: - >>> z = randomgen.geometric(p=0.35, size=10000) + >>> z = randomgen.generator.geometric(p=0.35, size=10000) How many trials succeeded after a single run? @@ -3655,7 +3659,8 @@ cdef class RandomGenerator: >>> ngood, nbad, nsamp = 100, 2, 10 # number of good, number of bad, and number of samples - >>> s = randomgen.hypergeometric(ngood, nbad, nsamp, 1000) + >>> s = randomgen.generator.hypergeometric(ngood, nbad, nsamp, 1000) + >>> from matplotlib.pyplot import hist >>> hist(s) # note that it is very unlikely to grab both bad items @@ -3663,7 +3668,7 @@ cdef class RandomGenerator: If you pull 15 marbles at random, how likely is it that 12 or more of them are one color? - >>> s = randomgen.hypergeometric(15, 15, 15, 100000) + >>> s = randomgen.generator.hypergeometric(15, 15, 15, 100000) >>> sum(s>=12)/100000. + sum(s<=3)/100000. # answer = 0.003 ... pretty unlikely! @@ -3764,13 +3769,14 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a = .6 - >>> s = randomgen.logseries(a, 10000) + >>> s = randomgen.generator.logseries(a, 10000) + >>> import matplotlib.pyplot as plt >>> count, bins, ignored = plt.hist(s) # plot against distribution >>> def logseries(k, p): - ... return -p**k/(k*log(1-p)) + ... return -p**k/(k*np.log(1-p)) >>> plt.plot(bins, logseries(bins, a)*count.max()/ logseries(bins, a).max(), 'r') >>> plt.show() @@ -3852,7 +3858,7 @@ cdef class RandomGenerator: Diagonal covariance means that points are oriented along x or y-axis: >>> import matplotlib.pyplot as plt - >>> x, y = randomgen.multivariate_normal(mean, cov, 5000).T + >>> x, y = randomgen.generator.multivariate_normal(mean, cov, 5000).T >>> plt.plot(x, y, 'x') >>> plt.axis('equal') >>> plt.show() @@ -3872,7 +3878,7 @@ cdef class RandomGenerator: -------- >>> mean = (1, 2) >>> cov = [[1, 0], [0, 1]] - >>> x = randomgen.multivariate_normal(mean, cov, (3, 3)) + >>> x = randomgen.generator.multivariate_normal(mean, cov, (3, 3)) >>> x.shape (3, 3, 2) @@ -3984,14 +3990,14 @@ cdef class RandomGenerator: -------- Throw a dice 20 times: - >>> randomgen.multinomial(20, [1/6.]*6, size=1) + >>> randomgen.generator.multinomial(20, [1/6.]*6, size=1) array([[4, 1, 7, 5, 2, 1]]) It landed 4 times on 1, once on 2, etc. Now, throw the dice 20 times, and 20 times again: - >>> randomgen.multinomial(20, [1/6.]*6, size=2) + >>> randomgen.generator.multinomial(20, [1/6.]*6, size=2) array([[3, 4, 3, 3, 4, 3], [2, 4, 3, 4, 0, 7]]) @@ -4000,8 +4006,8 @@ cdef class RandomGenerator: A loaded die is more likely to land on number 6: - >>> randomgen.multinomial(100, [1/7.]*5 + [2/7.]) - array([11, 16, 14, 17, 16, 26]) + >>> randomgen.generator.multinomial(100, [1/7.]*5 + [2/7.]) + array([11, 16, 14, 17, 16, 26]) # random The probability inputs should be normalized. As an implementation detail, the value of the last entry is ignored and assumed to take @@ -4009,12 +4015,12 @@ cdef class RandomGenerator: A biased coin which has twice as much weight on one side as on the other should be sampled like so: - >>> randomgen.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT - array([38, 62]) + >>> randomgen.generator.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT + array([38, 62]) # random not like: - >>> randomgen.multinomial(100, [1.0, 2.0]) # WRONG + >>> randomgen.generator.multinomial(100, [1.0, 2.0]) # WRONG array([100, 0]) """ @@ -4131,8 +4137,9 @@ cdef class RandomGenerator: average length, but allowing some variation in the relative sizes of the pieces. - >>> s = randomgen.dirichlet((10, 5, 3), 20).transpose() + >>> s = randomgen.generator.dirichlet((10, 5, 3), 20).transpose() + >>> import matplotlib.pyplot as plt >>> plt.barh(range(20), s[0]) >>> plt.barh(range(20), s[1], left=s[0], color='g') >>> plt.barh(range(20), s[2], left=s[0]+s[1], color='r') @@ -4227,14 +4234,14 @@ cdef class RandomGenerator: >>> arr = np.arange(10) >>> randomgen.shuffle(arr) >>> arr - [1 7 5 2 9 4 3 6 0 8] + [1 7 5 2 9 4 3 6 0 8] # random Multi-dimensional arrays are only shuffled along the first axis: >>> arr = np.arange(9).reshape((3, 3)) - >>> randomgen.shuffle(arr) + >>> randomgen.generator.shuffle(arr) >>> arr - array([[3, 4, 5], + array([[3, 4, 5], # random [6, 7, 8], [0, 1, 2]]) @@ -4313,15 +4320,15 @@ cdef class RandomGenerator: Examples -------- - >>> np.random.permutation(10) - array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) + >>> randomgen.generator.permutation(10) + array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) # random - >>> np.random.permutation([1, 4, 9, 12, 15]) - array([15, 1, 9, 4, 12]) + >>> randomgen.generator.permutation([1, 4, 9, 12, 15]) + array([15, 1, 9, 4, 12]) # random >>> arr = np.arange(9).reshape((3, 3)) - >>> np.random.permutation(arr) - array([[6, 7, 8], + >>> randomgen.generator.permutation(arr) + array([[6, 7, 8], # random [0, 1, 2], [3, 4, 5]]) diff --git a/_randomgen/randomgen/legacy/_legacy.pyx b/_randomgen/randomgen/legacy/_legacy.pyx index 1c206ec914e2..f27e32fe65ec 100644 --- a/_randomgen/randomgen/legacy/_legacy.pyx +++ b/_randomgen/randomgen/legacy/_legacy.pyx @@ -222,13 +222,13 @@ cdef class _LegacyGenerator: Examples -------- - >>> s = randomgen.standard_normal(8000) + >>> s = randomgen.generator.standard_normal(8000) >>> s array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random -0.38672696, -0.4685006 ]) #random >>> s.shape (8000,) - >>> s = randomgen.standard_normal(size=(3, 4, 2)) + >>> s = randomgen.generator.standard_normal(size=(3, 4, 2)) >>> s.shape (3, 4, 2) @@ -303,7 +303,7 @@ cdef class _LegacyGenerator: We have 10 degrees of freedom, so is the sample mean within 95% of the recommended value? - >>> s = randomgen.standard_t(10, size=100000) + >>> s = randomgen.generator.standard_t(10, size=100000) >>> np.mean(intake) 6753.636363636364 >>> intake.std(ddof=1) @@ -398,7 +398,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> mu, sigma = 3., 1. # mean and standard deviation - >>> s = randomgen.lognormal(mu, sigma, 1000) + >>> s = randomgen.generator.lognormal(mu, sigma, 1000) Display the histogram of the samples, along with the probability density function: @@ -422,7 +422,7 @@ cdef class _LegacyGenerator: >>> # values, drawn from a normal distribution. >>> b = [] >>> for i in range(1000): - ... a = 10. + randomgen.random(100) + ... a = 10. + randomgen.generator.randn(100) ... b.append(np.product(a)) >>> b = np.array(b) / np.min(b) # scale values to be positive @@ -502,7 +502,7 @@ cdef class _LegacyGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(randomgen.wald(3, 2, 100000), bins=200, density=True) + >>> h = plt.hist(randomgen.generator.wald(3, 2, 100000), bins=200, density=True) >>> plt.show() """ @@ -592,7 +592,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> a, m = 3., 2. # shape and mode - >>> s = (randomgen.pareto(a, 1000) + 1) * m + >>> s = (randomgen.generator.pareto(a, 1000) + 1) * m Display the histogram of the samples, along with the probability density function: @@ -685,7 +685,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> a = 5. # shape - >>> s = randomgen.weibull(a, 1000) + >>> s = randomgen.generator.weibull(a, 1000) Display the histogram of the samples, along with the probability density function: @@ -695,7 +695,7 @@ cdef class _LegacyGenerator: >>> def weib(x,n,a): ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) - >>> count, bins, ignored = plt.hist(randomgen.weibull(5.,1000)) + >>> count, bins, ignored = plt.hist(randomgen.generator.weibull(5.,1000)) >>> x = np.arange(1,100.)/50. >>> scale = count.max()/weib(x, 1., 5.).max() >>> plt.plot(x, weib(x, 1., 5.)*scale) @@ -765,10 +765,11 @@ cdef class _LegacyGenerator: >>> dfnum = 3 # between group deg of freedom >>> dfden = 20 # within groups degrees of freedom >>> nonc = 3.0 - >>> nc_vals = randomgen.noncentral_f(dfnum, dfden, nonc, 1000000) + >>> nc_vals = randomgen.generator.noncentral_f(dfnum, dfden, nonc, 1000000) >>> NF = np.histogram(nc_vals, bins=50, density=True) - >>> c_vals = randomgen.f(dfnum, dfden, 1000000) + >>> c_vals = randomgen.generator.f(dfnum, dfden, 1000000) >>> F = np.histogram(c_vals, bins=50, density=True) + >>> import matplotlib.pyplot as plt >>> plt.plot(F[1][1:], F[0]) >>> plt.plot(NF[1][1:], NF[0]) >>> plt.show() @@ -838,7 +839,7 @@ cdef class _LegacyGenerator: Examples -------- - >>> randomgen.chisquare(2,4) + >>> randomgen.generator.chisquare(2,4) array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) """ @@ -903,7 +904,7 @@ cdef class _LegacyGenerator: Draw values from the distribution and plot the histogram >>> import matplotlib.pyplot as plt - >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, 20, 100000), ... bins=200, density=True) >>> plt.show() @@ -911,9 +912,9 @@ cdef class _LegacyGenerator: and compare to a chisquare. >>> plt.figure() - >>> values = plt.hist(randomgen.noncentral_chisquare(3, .0000001, 100000), + >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, .0000001, 100000), ... bins=np.arange(0., 25, .1), density=True) - >>> values2 = plt.hist(randomgen.chisquare(3, 100000), + >>> values2 = plt.hist(randomgen.generator.chisquare(3, 100000), ... bins=np.arange(0., 25, .1), density=True) >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') >>> plt.show() @@ -922,7 +923,7 @@ cdef class _LegacyGenerator: distribution. >>> plt.figure() - >>> values = plt.hist(randomgen.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, 20, 100000), ... bins=200, density=True) >>> plt.show() @@ -987,8 +988,9 @@ cdef class _LegacyGenerator: -------- Draw samples and plot the distribution: - >>> s = randomgen.standard_cauchy(1000000) + >>> s = randomgen.generator.standard_cauchy(1000000) >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well + >>> import matplotlib.pyplot as plt >>> plt.hist(s, bins=100) >>> plt.show() @@ -1052,7 +1054,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> shape, scale = 2., 1. # mean and width - >>> s = randomgen.standard_gamma(shape, 1000000) + >>> s = randomgen.generator.standard_gamma(shape, 1000000) Display the histogram of the samples, along with the probability density function: @@ -1130,7 +1132,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> shape, scale = 2., 2. # mean and dispersion - >>> s = randomgen.gamma(shape, scale, 1000) + >>> s = randomgen.generator.gamma(shape, scale, 1000) Display the histogram of the samples, along with the probability density function: @@ -1263,11 +1265,11 @@ cdef class _LegacyGenerator: >>> dfnum = 1. # between group degrees of freedom >>> dfden = 48. # within groups degrees of freedom - >>> s = randomgen.f(dfnum, dfden, 1000) + >>> s = randomgen.generator.f(dfnum, dfden, 1000) The lower bound for the top 1% of the samples is : - >>> sort(s)[-10] + >>> np.sort(s)[-10] 7.61988120985 So there is about a 1% chance that the F statistic will exceed 7.62, @@ -1349,7 +1351,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> mu, sigma = 0, 0.1 # mean and standard deviation - >>> s = randomgen.normal(mu, sigma, 1000) + >>> s = randomgen.generator.normal(mu, sigma, 1000) Verify the mean and the variance: @@ -1414,16 +1416,16 @@ cdef class _LegacyGenerator: ----- For random samples from :math:`N(\\mu, \\sigma^2)`, use: - ``sigma * randomgen.randn(...) + mu`` + ``sigma * randomgen.generator.randn(...) + mu`` Examples -------- - >>> randomgen.randn() + >>> randomgen.generator.randn() 2.1923875335537315 #random Two-by-four array of samples from N(3, 6.25): - >>> 2.5 * randomgen.randn(2, 4) + 3 + >>> 2.5 * randomgen.generator.randn(2, 4) + 3 array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random @@ -1498,7 +1500,7 @@ cdef class _LegacyGenerator: for each successive well, that is what is the probability of a single success after drilling 5 wells, after 6 wells, etc.? - >>> s = randomgen.negative_binomial(1, 0.1, 100000) + >>> s = randomgen.generator.negative_binomial(1, 0.1, 100000) >>> for i in range(1, 11): ... probability = sum(s>> a = 5. # shape >>> samples = 1000 - >>> s = randomgen.power(a, samples) + >>> s = randomgen.generator.power(a, samples) Display the histogram of the samples, along with the probability density function: @@ -1956,20 +1959,20 @@ cdef class _LegacyGenerator: Compare the power function distribution to the inverse of the Pareto. >>> from scipy import stats - >>> rvs = randomgen.power(5, 1000000) - >>> rvsp = randomgen.pareto(5, 1000000) + >>> rvs = randomgen.generator.power(5, 1000000) + >>> rvsp = randomgen.generator.pareto(5, 1000000) >>> xx = np.linspace(0,1,100) >>> powpdf = stats.powerlaw.pdf(xx,5) >>> plt.figure() >>> plt.hist(rvs, bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('randomgen.power(5)') + >>> plt.title('randomgen.generator.power(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('inverse of 1 + randomgen.pareto(5)') + >>> plt.title('inverse of 1 + randomgen.generator.pareto(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, density=True) diff --git a/_randomgen/randomgen/tests/test_direct.py b/_randomgen/randomgen/tests/test_direct.py index 5d251a3b71e3..3f84c4cb69da 100644 --- a/_randomgen/randomgen/tests/test_direct.py +++ b/_randomgen/randomgen/tests/test_direct.py @@ -430,7 +430,8 @@ def test_uniform_float(self): def test_buffer_reset(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) - u = rs.random_sample(1) + rs.random_sample(1) + assert rs.state['buffer_loc'] != 382 rs.seed(*self.data1['seed']) assert rs.state['buffer_loc'] == 382 From 6887a9606dd248b4838d08ce7b4c80c25c9a2728 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 5 Feb 2019 08:31:23 +0000 Subject: [PATCH 179/279] RLS: Release 1.16.0 Release 1.16.0 --- _randomgen/.travis.yml | 30 +++++++++------------------- _randomgen/README.md | 6 ++++++ _randomgen/README.rst | 8 ++++++++ _randomgen/ci/conda-install.sh | 20 +++++++++++++++++++ _randomgen/ci/pypi-install.sh | 3 +++ _randomgen/doc/source/change-log.rst | 3 ++- _randomgen/requirements.txt | 2 +- 7 files changed, 49 insertions(+), 23 deletions(-) create mode 100644 _randomgen/ci/conda-install.sh create mode 100644 _randomgen/ci/pypi-install.sh diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml index 10eba96d243b..89c5be3fad84 100644 --- a/_randomgen/.travis.yml +++ b/_randomgen/.travis.yml @@ -1,7 +1,3 @@ -# Travis script that uses miniconda in place of the system installed python -# versions. Allows substantial flexability for choosing versions of -# required packages and is simpler to use to test up-to-date scientific Python -# stack group: edge dist: trusty sudo: required @@ -11,6 +7,7 @@ env: global: # Doctr deploy key for bashtage/randomgen - secure: "czwFlflS1lcfbSQ9ktv+pLAPV9/6+wmwiMTyIYyv5xgQVWRL5NRebWH+ZhQ6s2T5x17wFMtlafcAvkdV0CHQZLru34V2UNldCapuEtQ8b32EDHBXHKbs45b7SSkLx4TFXdjiJurleY4ZIKle0gX6BW21zYBwaHJqbN6I8nRv9Rp47XEU1UV1Mdf/PhfTnxY31rFrPYL77xeWJzoFfT8zao39V4gQds+1Ag7FjdNVdSDVKwDduF4kS7tIbKqb4M+jsbc3PIKyP9nyQpEQF5ebJuG7mqXJhVJGEL83rBx8MLFPA/1X3cUzKacgKyp2+Wmlt0EVhwCa1aRf9cSK6I7TbMC7/eGtDnC2ToiRlFJurVRblaEmhzVQS1yQ4Dkooqsj9hNVl6nhu7JfR52GLogns33Ec/yYuRcWcULKSlR5Cerfef/5YijBEhlr9X76SJiOpjvS4lwWFYX+h8xzuVhRLGwIVB9oQNllxYItzcDSGmRx+EOMXWASHmoUDnBOZg4GMVukqOcF5l0ynoepiA1YHLdZlMy6SB3P7BZKF/aNCOn9nXw+N9X4U/yUpkM3Pb7HoGdNrC8RO4SwrNjGrarkdEB6e1lBReK/dqcylaF/mpK9VLpfQszDI8xnR4VCmlEM+le0xOsyHfeGciabdI4KH0i0SfYl4ls5XrN+CaqFWdo=" + - PYPI=false cache: directories: @@ -22,11 +19,14 @@ matrix: - os: linux env: [PYTHON=2.7, NUMPY=1.13, CYTHON=0.26] - os: linux - env: [PYTHON=3.5, NUMPY=1.13] + env: [PYTHON=2.7] - os: linux - env: [PYTHON=3.6, NUMPY=1.14, CYTHON=0.27] + env: [PYTHON=3.5, NUMPY=1.14] - os: linux - env: [PYTHON=3.6, NUMPY=1.15, CYTHON=0.28] + env: [PYTHON=3.6, NUMPY=1.15, CYTHON=0.27] + - os: linux + python: 3.6 + env: [PYPI=true] - os: linux env: [PYTHON=3.7, DOCBUILD=true] - os: osx @@ -36,23 +36,11 @@ matrix: before_install: - git fetch --tags - - if [[ ${TRAVIS_OS_NAME} == "osx" ]]; then wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda3.sh; fi - - if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh; fi - - chmod +x miniconda3.sh - - ./miniconda3.sh -b - - export PATH=${HOME}/miniconda3/bin:$PATH - - conda config --set always_yes true - - conda update --all --quiet - - PKGS="python=${PYTHON}" - - PKGS="${PKGS} numpy"; if [ ${NUMPY} ]; then PKGS="${PKGS}=${NUMPY}"; fi - - PKGS="${PKGS} Cython"; if [ ${CYTHON} ]; then PKGS="${PKGS}=${CYTHON}"; fi - - PKGS="${PKGS} pandas"; if [ ${PANDAS} ]; then PKGS="${PKGS}=${PANDAS}"; fi - - conda create -n randomgen-test ${PKGS} pytest setuptools nose --quiet - - source activate randomgen-test + - if [[ $PYPI = true ]]; then source ci/pypi-install.sh; else source ci/conda-install.sh; fi - pip install tempita coverage coveralls pytest-cov codecov -q + - pip list - export BUILD_DIR=${PWD} - if [[ ${DOCBUILD} == true ]]; then pip install sphinx sphinx_rtd_theme guzzle_sphinx_theme ipython doctr -q; fi - - if [[ ${DOCBUILD} == true ]]; then conda install numba pandas matplotlib --quiet; fi - gcc --version || true - clang --version || true diff --git a/_randomgen/README.md b/_randomgen/README.md index 34986ebdb45d..53b58b5b2fd5 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -10,6 +10,12 @@ NumPy RandomState evolution. This is a library and generic interface for alternative random generators in Python and NumPy. +## Python 2.7 Support + +Release 1.16.0 is the final version that supports Python 2.7. Any bugs +in v1.16.0 will be patched until the end of 2019. All future releases +are Python 3, with an initial minimum version of 3.5. + ## Compatibility Warning `RandomGenerator` does not support Box-Muller normal variates and so it not diff --git a/_randomgen/README.rst b/_randomgen/README.rst index 69de75ab3811..be3e9c4279a1 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -9,6 +9,14 @@ NumPy RandomState evolution. This is a library and generic interface for alternative random generators in Python and NumPy. +.. rubric:: Python 2.7 Support + :name: Python 2.7 Support + +Release 1.16.0 is the final version that supports Python 2.7. Any bugs +in v1.16.0 will be patched until the end of 2019. All future releases +are Python 3, with an initial minimum version of 3.5. + + Compatibility Warning --------------------- diff --git a/_randomgen/ci/conda-install.sh b/_randomgen/ci/conda-install.sh new file mode 100644 index 000000000000..cccb8227dcf0 --- /dev/null +++ b/_randomgen/ci/conda-install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +if [[ ${TRAVIS_OS_NAME} == "osx" ]]; then wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda3.sh; fi +if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh; fi +chmod +x miniconda3.sh +./miniconda3.sh -b +export PATH=${HOME}/miniconda3/bin:$PATH +conda config --set always_yes true +conda update --all --quiet +conda create -n randomgen-test ${PKGS} pip --quiet +source activate randomgen-test + +PKGS="python=${PYTHON} matplotlib numpy" +if [[ -n ${NUMPY} ]]; then PKGS="${PKGS}=${NUMPY}"; fi +PKGS="${PKGS} Cython"; +if [[ -n ${CYTHON} ]]; then PKGS="${PKGS}=${CYTHON}"; fi +PKGS="${PKGS} pandas"; +if [[ -n ${PANDAS} ]]; then PKGS="${PKGS}=${PANDAS}"; fi +echo conda create -n randomgen-test ${PKGS} pytest setuptools nose --quiet +conda create -n randomgen-test ${PKGS} pytest setuptools nose --quiet diff --git a/_randomgen/ci/pypi-install.sh b/_randomgen/ci/pypi-install.sh new file mode 100644 index 000000000000..ded8dd9212d2 --- /dev/null +++ b/_randomgen/ci/pypi-install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +pip install numpy cython pandas pytest setuptools nose matplotlib --quiet diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst index eb884c7f3fd7..5be2ea8dd60f 100644 --- a/_randomgen/doc/source/change-log.rst +++ b/_randomgen/doc/source/change-log.rst @@ -1,6 +1,6 @@ Change Log ---------- -v1.15.2 +v1.16.0 ======= - Fixed a bug that affected :class:`~randomgen.dsfmt.DSFMT` when calling :func:`~randomgen.dsfmt.DSFMT.jump` or :func:`~randomgen.dsfmt.DSFMT.seed` @@ -11,6 +11,7 @@ v1.15.2 entropy initialization used too few bytes. This bug is unlikely to be encountered since this path is only encountered if the system random number generator fails. +- Synchronized with upstream changes. v1.15.1 ======= diff --git a/_randomgen/requirements.txt b/_randomgen/requirements.txt index 6c3af8ca3a6b..0d7fe1ba89e7 100644 --- a/_randomgen/requirements.txt +++ b/_randomgen/requirements.txt @@ -1,4 +1,4 @@ -numpy>=1.10 +numpy>=1.13 cython>=0.26 setuptools wheel \ No newline at end of file From 89293adf908f3659975695bb2f532710f27efcc9 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 5 Feb 2019 09:56:00 +0000 Subject: [PATCH 180/279] DOC: Fix issue in README.rst Update README.rst to match README.md --- _randomgen/README.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/_randomgen/README.rst b/_randomgen/README.rst index be3e9c4279a1..cfd447f387bb 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -9,14 +9,13 @@ NumPy RandomState evolution. This is a library and generic interface for alternative random generators in Python and NumPy. -.. rubric:: Python 2.7 Support - :name: Python 2.7 Support +Python 2.7 Support +------------------ Release 1.16.0 is the final version that supports Python 2.7. Any bugs in v1.16.0 will be patched until the end of 2019. All future releases are Python 3, with an initial minimum version of 3.5. - Compatibility Warning --------------------- From 3233d698527a42e0c56ab0d6be0924d5b92297d9 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 5 Feb 2019 16:51:26 +0000 Subject: [PATCH 181/279] DOC: Update versions supported Update to reflect no support fo 3.3, 3.4 and added support for 3.7 --- _randomgen/setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/_randomgen/setup.py b/_randomgen/setup.py index 3697166c13db..f8eb8f81147a 100644 --- a/_randomgen/setup.py +++ b/_randomgen/setup.py @@ -281,10 +281,9 @@ 'Programming Language :: C', 'Programming Language :: Cython', 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: Adaptive Technologies', 'Topic :: Artistic Software', 'Topic :: Office/Business :: Financial', From e454334a814975c5f014ea6ce493f40320782b7a Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 18 Feb 2019 12:49:17 +0000 Subject: [PATCH 182/279] BUG: Protect gamma generation from 0 input Add protection for 0 input for gamma random variables Add protection in legacy for gamma random variables Add protection for 0 input in Weibull Add test of 0 protection --- _randomgen/randomgen/src/distributions/distributions.c | 2 ++ _randomgen/randomgen/src/legacy/distributions-boxmuller.c | 6 ++++++ _randomgen/randomgen/tests/test_legacy.py | 5 +++++ .../randomgen/tests/test_numpy_mt19937_regressions.py | 4 ++++ 4 files changed, 17 insertions(+) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 4e7493afaac0..31e573b35fc7 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -346,6 +346,8 @@ static NPY_INLINE double standard_gamma_zig(brng_t *brng_state, double shape) { if (shape == 1.0) { return random_standard_exponential_zig(brng_state); + } else if (shape == 0.0) { + return 0.0; } else if (shape < 1.0) { for (;;) { U = next_double(brng_state); diff --git a/_randomgen/randomgen/src/legacy/distributions-boxmuller.c b/_randomgen/randomgen/src/legacy/distributions-boxmuller.c index 7ad1742cc585..768de066ced2 100644 --- a/_randomgen/randomgen/src/legacy/distributions-boxmuller.c +++ b/_randomgen/randomgen/src/legacy/distributions-boxmuller.c @@ -39,6 +39,9 @@ double legacy_standard_gamma(aug_brng_t *aug_state, double shape) { if (shape == 1.0) { return legacy_standard_exponential(aug_state); + } + else if (shape == 0.0) { + return 0.0; } else if (shape < 1.0) { for (;;) { U = legacy_double(aug_state); @@ -84,6 +87,9 @@ double legacy_pareto(aug_brng_t *aug_state, double a) { } double legacy_weibull(aug_brng_t *aug_state, double a) { + if (a == 0.0) { + return 0.0; + } return pow(legacy_standard_exponential(aug_state), 1. / a); } diff --git a/_randomgen/randomgen/tests/test_legacy.py b/_randomgen/randomgen/tests/test_legacy.py index e45ba3619796..21c56946f6b8 100644 --- a/_randomgen/randomgen/tests/test_legacy.py +++ b/_randomgen/randomgen/tests/test_legacy.py @@ -10,3 +10,8 @@ def test_pickle(): lg2 = pickle.loads(pickle.dumps(lg)) assert lg.standard_normal() == lg2.standard_normal() assert lg.random_sample() == lg2.random_sample() + + +def test_weibull(): + lg = LegacyGenerator() + assert lg.weibull(0.0) == 0.0 diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py b/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py index 4e51327aa160..4b81b77a98ef 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py @@ -158,3 +158,7 @@ def __array__(self): perm = mt19937.permutation(m) assert_array_equal(perm, np.array([2, 1, 4, 0, 3])) assert_array_equal(m.__array__(), np.arange(5)) + + def test_gamma_0(self): + assert mt19937.standard_gamma(0.0) == 0.0 + assert_array_equal(mt19937.standard_gamma([0.0]), 0.0) From cf72d3006bece84cfbc32d0c7fdf29a847acf4e9 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 18 Feb 2019 13:27:46 +0000 Subject: [PATCH 183/279] TST: Ensure bad value tests are run on new generators Ensure tests run on legacy generators for bad values are also run on the current set of generators --- .../randomgen/tests/test_numpy_mt19937.py | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index a43d7d601f46..df13820ca7c6 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -1161,11 +1161,13 @@ def test_normal(self): actual = normal(loc * 3, scale) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc * 3, bad_scale) + assert_raises(ValueError, mt19937.normal, loc * 3, bad_scale) self.set_seed() actual = normal(loc, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc, bad_scale * 3) + assert_raises(ValueError, mt19937.normal, loc, bad_scale * 3) def test_beta(self): a = [1] @@ -1182,12 +1184,14 @@ def test_beta(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, beta, bad_a * 3, b) assert_raises(ValueError, beta, a * 3, bad_b) + assert_raises(ValueError, mt19937.beta, bad_a * 3, b) + assert_raises(ValueError, mt19937.beta, a * 3, bad_b) self.set_seed() actual = beta(a, b * 3) assert_array_almost_equal(actual, desired, decimal=14) - assert_raises(ValueError, beta, bad_a, b * 3) - assert_raises(ValueError, beta, a, bad_b * 3) + assert_raises(ValueError, mt19937.beta, bad_a, b * 3) + assert_raises(ValueError, mt19937.beta, a, bad_b * 3) def test_exponential(self): scale = [1] @@ -1201,6 +1205,7 @@ def test_exponential(self): actual = exponential(scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, exponential, bad_scale * 3) + assert_raises(ValueError, mt19937.exponential, bad_scale * 3) def test_standard_gamma(self): shape = [1] @@ -1214,6 +1219,7 @@ def test_standard_gamma(self): actual = std_gamma(shape * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, std_gamma, bad_shape * 3) + assert_raises(ValueError, mt19937.standard_gamma, bad_shape * 3) def test_gamma(self): shape = [1] @@ -1230,12 +1236,16 @@ def test_gamma(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, gamma, bad_shape * 3, scale) assert_raises(ValueError, gamma, shape * 3, bad_scale) + assert_raises(ValueError, mt19937.gamma, bad_shape * 3, scale) + assert_raises(ValueError, mt19937.gamma, shape * 3, bad_scale) self.set_seed() actual = gamma(shape, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, gamma, bad_shape, scale * 3) assert_raises(ValueError, gamma, shape, bad_scale * 3) + assert_raises(ValueError, mt19937.gamma, bad_shape, scale * 3) + assert_raises(ValueError, mt19937.gamma, shape, bad_scale * 3) def test_f(self): dfnum = [1] @@ -1252,12 +1262,16 @@ def test_f(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, f, bad_dfnum * 3, dfden) assert_raises(ValueError, f, dfnum * 3, bad_dfden) + assert_raises(ValueError, mt19937.f, bad_dfnum * 3, dfden) + assert_raises(ValueError, mt19937.f, dfnum * 3, bad_dfden) self.set_seed() actual = f(dfnum, dfden * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, f, bad_dfnum, dfden * 3) assert_raises(ValueError, f, dfnum, bad_dfden * 3) + assert_raises(ValueError, mt19937.f, bad_dfnum, dfden * 3) + assert_raises(ValueError, mt19937.f, dfnum, bad_dfden * 3) def test_noncentral_f(self): dfnum = [2] @@ -1277,6 +1291,9 @@ def test_noncentral_f(self): assert_raises(ValueError, nonc_f, bad_dfnum * 3, dfden, nonc) assert_raises(ValueError, nonc_f, dfnum * 3, bad_dfden, nonc) assert_raises(ValueError, nonc_f, dfnum * 3, dfden, bad_nonc) + assert_raises(ValueError, mt19937.noncentral_f, bad_dfnum * 3, dfden, nonc) + assert_raises(ValueError, mt19937.noncentral_f, dfnum * 3, bad_dfden, nonc) + assert_raises(ValueError, mt19937.noncentral_f, dfnum * 3, dfden, bad_nonc) self.set_seed() actual = nonc_f(dfnum, dfden * 3, nonc) @@ -1284,6 +1301,9 @@ def test_noncentral_f(self): assert_raises(ValueError, nonc_f, bad_dfnum, dfden * 3, nonc) assert_raises(ValueError, nonc_f, dfnum, bad_dfden * 3, nonc) assert_raises(ValueError, nonc_f, dfnum, dfden * 3, bad_nonc) + assert_raises(ValueError, mt19937.noncentral_f, bad_dfnum, dfden * 3, nonc) + assert_raises(ValueError, mt19937.noncentral_f, dfnum, bad_dfden * 3, nonc) + assert_raises(ValueError, mt19937.noncentral_f, dfnum, dfden * 3, bad_nonc) self.set_seed() actual = nonc_f(dfnum, dfden, nonc * 3) @@ -1291,6 +1311,9 @@ def test_noncentral_f(self): assert_raises(ValueError, nonc_f, bad_dfnum, dfden, nonc * 3) assert_raises(ValueError, nonc_f, dfnum, bad_dfden, nonc * 3) assert_raises(ValueError, nonc_f, dfnum, dfden, bad_nonc * 3) + assert_raises(ValueError, mt19937.noncentral_f, bad_dfnum, dfden, nonc * 3) + assert_raises(ValueError, mt19937.noncentral_f, dfnum, bad_dfden, nonc * 3) + assert_raises(ValueError, mt19937.noncentral_f, dfnum, dfden, bad_nonc * 3) def test_chisquare(self): df = [1] @@ -1320,12 +1343,16 @@ def test_noncentral_chisquare(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, nonc_chi, bad_df * 3, nonc) assert_raises(ValueError, nonc_chi, df * 3, bad_nonc) + assert_raises(ValueError, mt19937.noncentral_chisquare, bad_df * 3, nonc) + assert_raises(ValueError, mt19937.noncentral_chisquare, df * 3, bad_nonc) self.set_seed() actual = nonc_chi(df, nonc * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, nonc_chi, bad_df, nonc * 3) assert_raises(ValueError, nonc_chi, df, bad_nonc * 3) + assert_raises(ValueError, mt19937.noncentral_chisquare, bad_df, nonc * 3) + assert_raises(ValueError, mt19937.noncentral_chisquare, df, bad_nonc * 3) def test_standard_t(self): df = [1] @@ -1339,6 +1366,7 @@ def test_standard_t(self): actual = t(df * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, t, bad_df * 3) + assert_raises(ValueError, mt19937.standard_t, bad_df * 3) def test_vonmises(self): mu = [2] @@ -1371,6 +1399,7 @@ def test_pareto(self): actual = pareto(a * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, pareto, bad_a * 3) + assert_raises(ValueError, mt19937.pareto, bad_a * 3) def test_weibull(self): a = [1] @@ -1384,6 +1413,7 @@ def test_weibull(self): actual = weibull(a * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, weibull, bad_a * 3) + assert_raises(ValueError, mt19937.weibull, bad_a * 3) def test_power(self): a = [1] @@ -1397,6 +1427,7 @@ def test_power(self): actual = power(a * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, power, bad_a * 3) + assert_raises(ValueError, mt19937.power, bad_a * 3) def test_laplace(self): loc = [0] @@ -1468,11 +1499,13 @@ def test_lognormal(self): actual = lognormal(mean * 3, sigma) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, lognormal, mean * 3, bad_sigma) + assert_raises(ValueError, mt19937.lognormal, mean * 3, bad_sigma) self.set_seed() actual = lognormal(mean, sigma * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, lognormal, mean, bad_sigma * 3) + assert_raises(ValueError, mt19937.lognormal, mean, bad_sigma * 3) def test_rayleigh(self): scale = [1] @@ -1502,12 +1535,16 @@ def test_wald(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, wald, bad_mean * 3, scale) assert_raises(ValueError, wald, mean * 3, bad_scale) + assert_raises(ValueError, mt19937.wald, bad_mean * 3, scale) + assert_raises(ValueError, mt19937.wald, mean * 3, bad_scale) self.set_seed() actual = wald(mean, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, wald, bad_mean, scale * 3) assert_raises(ValueError, wald, mean, bad_scale * 3) + assert_raises(ValueError, mt19937.wald, bad_mean, scale * 3) + assert_raises(ValueError, mt19937.wald, mean, bad_scale * 3) def test_triangular(self): left = [1] @@ -1583,6 +1620,9 @@ def test_negative_binomial(self): assert_raises(ValueError, neg_binom, bad_n * 3, p) assert_raises(ValueError, neg_binom, n * 3, bad_p_one) assert_raises(ValueError, neg_binom, n * 3, bad_p_two) + assert_raises(ValueError, mt19937.negative_binomial, bad_n * 3, p) + assert_raises(ValueError, mt19937.negative_binomial, n * 3, bad_p_one) + assert_raises(ValueError, mt19937.negative_binomial, n * 3, bad_p_two) self.set_seed() actual = neg_binom(n, p * 3) @@ -1590,6 +1630,9 @@ def test_negative_binomial(self): assert_raises(ValueError, neg_binom, bad_n, p * 3) assert_raises(ValueError, neg_binom, n, bad_p_one * 3) assert_raises(ValueError, neg_binom, n, bad_p_two * 3) + assert_raises(ValueError, mt19937.negative_binomial, bad_n, p * 3) + assert_raises(ValueError, mt19937.negative_binomial, n, bad_p_one * 3) + assert_raises(ValueError, mt19937.negative_binomial, n, bad_p_two * 3) def test_poisson(self): max_lam = random.poisson_lam_max From bc0abffab262e311b24212795b1c815b72cb3827 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 18 Feb 2019 15:23:41 +0000 Subject: [PATCH 184/279] CLN: Match declaration and function Use same variable definition in declaration and function --- _randomgen/randomgen/src/distributions/distributions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/_randomgen/randomgen/src/distributions/distributions.h index e618052c1a00..5cf9c72b25bc 100644 --- a/_randomgen/randomgen/src/distributions/distributions.h +++ b/_randomgen/randomgen/src/distributions/distributions.h @@ -210,7 +210,7 @@ DECLDIR void random_bounded_uint32_fill(brng_t *brng_state, uint32_t off, DECLDIR void random_bounded_uint16_fill(brng_t *brng_state, uint16_t off, uint16_t rng, npy_intp cnt, bool use_masked, uint16_t *out); -DECLDIR void random_bounded_uint8_fill(brng_t *brng_state, npy_bool off, +DECLDIR void random_bounded_uint8_fill(brng_t *brng_state, uint8_t off, uint8_t rng, npy_intp cnt, bool use_masked, uint8_t *out); DECLDIR void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, From e5be493e2480089aa9273df0a641037ac6fdb8ce Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 18 Feb 2019 18:01:55 +0000 Subject: [PATCH 185/279] DOC: Sync upstream doc changes Syn doc changes to Wald and Noncentral Chi2 --- _randomgen/randomgen/generator.pyx | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 2d45f8aca2f0..a4e3dd3a19e8 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -1954,17 +1954,9 @@ cdef class RandomGenerator: where :math:`Y_{q}` is the Chi-square with q degrees of freedom. - In Delhi (2007), it is noted that the noncentral chi-square is - useful in bombing and coverage problems, the probability of - killing the point target given by the noncentral chi-squared - distribution. - References ---------- - .. [1] Delhi, M.S. Holla, "On a noncentral chi-square distribution in - the analysis of weapon systems effectiveness", Metrika, - Volume 15, Number 1 / December, 1970. - .. [2] Wikipedia, "Noncentral chi-square distribution" + .. [1] Wikipedia, "Noncentral chi-square distribution" https://en.wikipedia.org/wiki/Noncentral_chi-square_distribution Examples @@ -3016,9 +3008,9 @@ cdef class RandomGenerator: Parameters ---------- mean : float or array_like of floats - Distribution mean, should be > 0. + Distribution mean, must be > 0. scale : float or array_like of floats - Scale parameter, should be >= 0. + Scale parameter, must be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), From 382eba3a13242b5a7026021d4c7cc75a99accd54 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 18 Feb 2019 18:02:22 +0000 Subject: [PATCH 186/279] BUG: Catch 0.0 shape parameter in float gamme Ensure 0.0 is correctly handled when generating floats --- _randomgen/randomgen/src/distributions/distributions.c | 2 ++ _randomgen/randomgen/tests/test_numpy_mt19937_regressions.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/_randomgen/randomgen/src/distributions/distributions.c index 31e573b35fc7..a9d8a308d98f 100644 --- a/_randomgen/randomgen/src/distributions/distributions.c +++ b/_randomgen/randomgen/src/distributions/distributions.c @@ -390,6 +390,8 @@ static NPY_INLINE float standard_gamma_zig_f(brng_t *brng_state, float shape) { if (shape == 1.0f) { return random_standard_exponential_zig_f(brng_state); + } else if (shape == 0.0) { + return 0.0; } else if (shape < 1.0f) { for (;;) { U = next_float(brng_state); diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py b/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py index 4b81b77a98ef..bc644e122439 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py @@ -162,3 +162,7 @@ def __array__(self): def test_gamma_0(self): assert mt19937.standard_gamma(0.0) == 0.0 assert_array_equal(mt19937.standard_gamma([0.0]), 0.0) + + actual = mt19937.standard_gamma([0.0], dtype='float') + expected = np.array([0.], dtype=np.float32) + assert_array_equal(actual, expected) From 5708029c628269580bd9a9bbda567ee88029a389 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 19 Feb 2019 18:37:41 +0000 Subject: [PATCH 187/279] DOC/ENH: Update docstring and enhance logistic Update docstring in _legacy.pyx for match generator.pyx Fix docstring in the constaint checker which had ineq rather than eq. Enhance logistic to accept 0 scale --- _randomgen/randomgen/common.pyx | 2 +- _randomgen/randomgen/generator.pyx | 8 +- _randomgen/randomgen/legacy/_legacy.pyx | 110 +++++++++--------- .../randomgen/tests/test_numpy_mt19937.py | 1 + 4 files changed, 64 insertions(+), 57 deletions(-) diff --git a/_randomgen/randomgen/common.pyx b/_randomgen/randomgen/common.pyx index eb872d02f15b..41d3074f352f 100644 --- a/_randomgen/randomgen/common.pyx +++ b/_randomgen/randomgen/common.pyx @@ -187,7 +187,7 @@ cdef int check_constraint(double val, object name, constraint_type cons) except raise ValueError(name + " <= 0") elif cons == CONS_BOUNDED_0_1 or cons == CONS_BOUNDED_0_1_NOTNAN: if val < 0 or val > 1: - raise ValueError(name + " <= 0 or " + name + " >= 1") + raise ValueError(name + " < 0 or " + name + " > 1") if cons == CONS_BOUNDED_0_1_NOTNAN: if np.isnan(val): raise ValueError(name + ' contains NaNs') diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index a4e3dd3a19e8..5b711dd933f3 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -2513,12 +2513,12 @@ cdef class RandomGenerator: >>> plt.figure() >>> plt.hist(rvs, bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('randomgen.power(5)') + >>> plt.title('randomgen.generator.power(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('inverse of 1 + randomgen.pareto(5)') + >>> plt.title('inverse of 1 + randomgen.generator.pareto(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, density=True) @@ -2746,7 +2746,7 @@ cdef class RandomGenerator: loc : float or array_like of floats, optional Parameter of the distribution. Default is 0. scale : float or array_like of floats, optional - Parameter of the distribution. Should be greater than zero. + Parameter of the distribution. Must be >= 0. Default is 1. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then @@ -2809,7 +2809,7 @@ cdef class RandomGenerator: """ return cont(&random_logistic, self._brng, size, self.lock, 2, loc, 'loc', CONS_NONE, - scale, 'scale', CONS_POSITIVE, + scale, 'scale', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, None) def lognormal(self, mean=0.0, sigma=1.0, size=None): diff --git a/_randomgen/randomgen/legacy/_legacy.pyx b/_randomgen/randomgen/legacy/_legacy.pyx index f27e32fe65ec..fa96f7757a81 100644 --- a/_randomgen/randomgen/legacy/_legacy.pyx +++ b/_randomgen/randomgen/legacy/_legacy.pyx @@ -287,12 +287,12 @@ cdef class _LegacyGenerator: .. [1] Dalgaard, Peter, "Introductory Statistics With R", Springer, 2002. .. [2] Wikipedia, "Student's t-distribution" - http://en.wikipedia.org/wiki/Student's_t-distribution + https://en.wikipedia.org/wiki/Student's_t-distribution Examples -------- From Dalgaard page 83 [1]_, suppose the daily energy intake for 11 - women in Kj is: + women in kilojoules (kJ) is: >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\ ... 7515, 8230, 8770]) @@ -461,9 +461,9 @@ cdef class _LegacyGenerator: Parameters ---------- mean : float or array_like of floats - Distribution mean, should be > 0. + Distribution mean, must be > 0. scale : float or array_like of floats - Scale parameter, should be >= 0. + Scale parameter, must be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -495,7 +495,7 @@ cdef class _LegacyGenerator: Distribution: Theory : Methodology, and Applications", CRC Press, 1988. .. [3] Wikipedia, "Wald distribution" - http://en.wikipedia.org/wiki/Wald_distribution + https://en.wikipedia.org/wiki/Wald_distribution Examples -------- @@ -585,7 +585,7 @@ cdef class _LegacyGenerator: .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme Values, Birkhauser Verlag, Basel, pp 23-30. .. [4] Wikipedia, "Pareto distribution", - http://en.wikipedia.org/wiki/Pareto_distribution + https://en.wikipedia.org/wiki/Pareto_distribution Examples -------- @@ -678,7 +678,7 @@ cdef class _LegacyGenerator: Wide Applicability", Journal Of Applied Mechanics ASME Paper 1951. .. [3] Wikipedia, "Weibull distribution", - http://en.wikipedia.org/wiki/Weibull_distribution + https://en.wikipedia.org/wiki/Weibull_distribution Examples -------- @@ -752,7 +752,7 @@ cdef class _LegacyGenerator: From MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/NoncentralF-Distribution.html .. [2] Wikipedia, "Noncentral F-distribution", - http://en.wikipedia.org/wiki/Noncentral_F-distribution + https://en.wikipedia.org/wiki/Noncentral_F-distribution Examples -------- @@ -886,18 +886,10 @@ cdef class _LegacyGenerator: where :math:`Y_{q}` is the Chi-square with q degrees of freedom. - In Delhi (2007), it is noted that the noncentral chi-square is - useful in bombing and coverage problems, the probability of - killing the point target given by the noncentral chi-squared - distribution. - References ---------- - .. [1] Delhi, M.S. Holla, "On a noncentral chi-square distribution in - the analysis of weapon systems effectiveness", Metrika, - Volume 15, Number 1 / December, 1970. - .. [2] Wikipedia, "Noncentral chi-square distribution" - http://en.wikipedia.org/wiki/Noncentral_chi-square_distribution + .. [1] Wikipedia, "Noncentral chi-square distribution" + https://en.wikipedia.org/wiki/Noncentral_chi-square_distribution Examples -------- @@ -982,7 +974,7 @@ cdef class _LegacyGenerator: Wolfram Web Resource. http://mathworld.wolfram.com/CauchyDistribution.html .. [3] Wikipedia, "Cauchy distribution" - http://en.wikipedia.org/wiki/Cauchy_distribution + https://en.wikipedia.org/wiki/Cauchy_distribution Examples -------- @@ -1047,7 +1039,7 @@ cdef class _LegacyGenerator: Wolfram Web Resource. http://mathworld.wolfram.com/GammaDistribution.html .. [2] Wikipedia, "Gamma distribution", - http://en.wikipedia.org/wiki/Gamma_distribution + https://en.wikipedia.org/wiki/Gamma_distribution Examples -------- @@ -1125,7 +1117,7 @@ cdef class _LegacyGenerator: Wolfram Web Resource. http://mathworld.wolfram.com/GammaDistribution.html .. [2] Wikipedia, "Gamma distribution", - http://en.wikipedia.org/wiki/Gamma_distribution + https://en.wikipedia.org/wiki/Gamma_distribution Examples -------- @@ -1247,7 +1239,7 @@ cdef class _LegacyGenerator: .. [1] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, Fifth Edition, 2002. .. [2] Wikipedia, "F-distribution", - http://en.wikipedia.org/wiki/F-distribution + https://en.wikipedia.org/wiki/F-distribution Examples -------- @@ -1341,7 +1333,7 @@ cdef class _LegacyGenerator: References ---------- .. [1] Wikipedia, "Normal distribution", - http://en.wikipedia.org/wiki/Normal_distribution + https://en.wikipedia.org/wiki/Normal_distribution .. [2] P. R. Peebles Jr., "Central Limit Theorem" in "Probability, Random Variables and Random Signal Principles", 4th ed., 2001, pp. 51, 51, 125. @@ -1442,7 +1434,7 @@ cdef class _LegacyGenerator: Draw samples from a negative binomial distribution. Samples are drawn from a negative binomial distribution with specified - parameters, `n` trials and `p` probability of success where `n` is an + parameters, `n` successes and `p` probability of success where `n` is an integer > 0 and `p` is in the interval [0, 1]. Parameters @@ -1462,21 +1454,19 @@ cdef class _LegacyGenerator: ------- out : ndarray or scalar Drawn samples from the parameterized negative binomial distribution, - where each sample is equal to N, the number of trials it took to - achieve n - 1 successes, N - (n - 1) failures, and a success on the, - (N + n)th trial. + where each sample is equal to N, the number of failures that + occurred before a total of n successes was reached. Notes ----- The probability density for the negative binomial distribution is - .. math:: P(N;n,p) = \\binom{N+n-1}{n-1}p^{n}(1-p)^{N}, + .. math:: P(N;n,p) = \\binom{N+n-1}{N}p^{n}(1-p)^{N}, - where :math:`n-1` is the number of successes, :math:`p` is the - probability of success, and :math:`N+n-1` is the number of trials. - The negative binomial distribution gives the probability of n-1 - successes and N failures in N+n-1 trials, and success on the (N+n)th - trial. + where :math:`n` is the number of successes, :math:`p` is the + probability of success, and :math:`N+n` is the number of trials. + The negative binomial distribution gives the probability of N + failures given n successes, with a success on the last trial. If one throws a die repeatedly until the third time a "1" appears, then the probability distribution of the number of non-"1"s that @@ -1488,7 +1478,7 @@ cdef class _LegacyGenerator: MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/NegativeBinomialDistribution.html .. [2] Wikipedia, "Negative binomial distribution", - http://en.wikipedia.org/wiki/Negative_binomial_distribution + https://en.wikipedia.org/wiki/Negative_binomial_distribution Examples -------- @@ -1500,10 +1490,10 @@ cdef class _LegacyGenerator: for each successive well, that is what is the probability of a single success after drilling 5 wells, after 6 wells, etc.? - >>> s = randomgen.generator.negative_binomial(1, 0.1, 100000) - >>> for i in range(1, 11): + >>> s = randomgen.generator.negative_binomial(1, 0.9, 100000) + >>> for i in range(1, 11): # doctest: +SKIP ... probability = sum(s0` and + :math:`\\sum_{i=1}^k x_i = 1`. + + The probability density function :math:`p` of a + Dirichlet-distributed random vector :math:`X` is + proportional to + + .. math:: p(x) \\propto \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i}, + + where :math:`\\alpha` is a vector containing the positive + concentration parameters. - Uses the following property for computation: for each dimension, - draw a random sample y_i from a standard gamma generator of shape - `alpha_i`, then - :math:`X = \\frac{1}{\\sum_{i=1}^k{y_i}} (y_1, \\ldots, y_n)` is - Dirichlet distributed. + The method uses the following property for computation: let :math:`Y` + be a random vector which has components that follow a standard gamma + distribution, then :math:`X = \\frac{1}{\\sum_{i=1}^k{Y_i}} Y` + is Dirichlet-distributed References ---------- .. [1] David McKay, "Information Theory, Inference and Learning Algorithms," chapter 23, - http://www.inference.phy.cam.ac.uk/mackay/ + http://www.inference.org.uk/mackay/itila/ .. [2] Wikipedia, "Dirichlet distribution", - http://en.wikipedia.org/wiki/Dirichlet_distribution + https://en.wikipedia.org/wiki/Dirichlet_distribution Examples -------- @@ -1776,7 +1782,8 @@ cdef class _LegacyGenerator: # matrices should be equal up to roundoff error if cov is # symmetric and the singular value of the corresponding row is # not zero. We continue to use the SVD rather than Cholesky in - # order to preserve current outputs. + # order to preserve current outputs. Note that symmetry has not + # been checked. (u, s, v) = svd(cov) @@ -1788,8 +1795,7 @@ cdef class _LegacyGenerator: psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) if not psd: if check_valid == 'warn': - warnings.warn( - "covariance is not positive-semidefinite.", + warnings.warn("covariance is not positive-semidefinite.", RuntimeWarning) else: raise ValueError( @@ -1874,9 +1880,9 @@ cdef class _LegacyGenerator: .. [1] Peyton Z. Peebles Jr., "Probability, Random Variables and Random Signal Principles", 4th ed, 2001, p. 57. .. [2] Wikipedia, "Poisson process", - http://en.wikipedia.org/wiki/Poisson_process + https://en.wikipedia.org/wiki/Poisson_process .. [3] Wikipedia, "Exponential distribution", - http://en.wikipedia.org/wiki/Exponential_distribution + https://en.wikipedia.org/wiki/Exponential_distribution """ return cont(&legacy_exponential, self._aug_state, size, self.lock, 1, diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index df13820ca7c6..0a6548c7cbe2 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -1485,6 +1485,7 @@ def test_logistic(self): actual = logistic(loc, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, logistic, loc, bad_scale * 3) + assert_equal(mt19937.logistic(1.0, 0.0), 1.0) def test_lognormal(self): mean = [0] From 7c90d567316cd3915046d4d509e566495027f1e0 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 19 Feb 2019 22:27:20 +0000 Subject: [PATCH 188/279] CLN/REF: Reorder _legacy to match generator Reorder functions in _legacy to match generator to simplify keeping doc strings synchronized. Synchronize the docstring in _legacy --- _randomgen/randomgen/legacy/_legacy.pyx | 1750 +++++++++++------------ 1 file changed, 873 insertions(+), 877 deletions(-) diff --git a/_randomgen/randomgen/legacy/_legacy.pyx b/_randomgen/randomgen/legacy/_legacy.pyx index fa96f7757a81..9db3867781ae 100644 --- a/_randomgen/randomgen/legacy/_legacy.pyx +++ b/_randomgen/randomgen/legacy/_legacy.pyx @@ -51,7 +51,6 @@ cdef class _LegacyGenerator: Basic RNG to use as the core generator. If none is provided, uses Xoroshiro128. - Examples -------- Exactly reproducing a NumPy stream requires both a ``RandomGenerator`` @@ -201,6 +200,190 @@ cdef class _LegacyGenerator: self._aug_state.has_gauss = value.get('has_gauss', 0) self._basicrng.state = value + def beta(self, a, b, size=None): + """ + beta(a, b, size=None) + + Draw samples from a Beta distribution. + + The Beta distribution is a special case of the Dirichlet distribution, + and is related to the Gamma distribution. It has the probability + distribution function + + .. math:: f(x; a,b) = \\frac{1}{B(\\alpha, \\beta)} x^{\\alpha - 1} + (1 - x)^{\\beta - 1}, + + where the normalization, B, is the beta function, + + .. math:: B(\\alpha, \\beta) = \\int_0^1 t^{\\alpha - 1} + (1 - t)^{\\beta - 1} dt. + + It is often seen in Bayesian inference and order statistics. + + Parameters + ---------- + a : float or array_like of floats + Alpha, positive (>0). + b : float or array_like of floats + Beta, positive (>0). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` and ``b`` are both scalars. + Otherwise, ``np.broadcast(a, b).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized beta distribution. + + """ + return cont(&legacy_beta, self._aug_state, size, self.lock, 2, + a, 'a', CONS_POSITIVE, + b, 'b', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + def exponential(self, scale=1.0, size=None): + """ + exponential(scale=1.0, size=None) + + Draw samples from an exponential distribution. + + Its probability density function is + + .. math:: f(x; \\frac{1}{\\beta}) = \\frac{1}{\\beta} \\exp(-\\frac{x}{\\beta}), + + for ``x > 0`` and 0 elsewhere. :math:`\\beta` is the scale parameter, + which is the inverse of the rate parameter :math:`\\lambda = 1/\\beta`. + The rate parameter is an alternative, widely used parameterization + of the exponential distribution [3]_. + + The exponential distribution is a continuous analogue of the + geometric distribution. It describes many common situations, such as + the size of raindrops measured over many rainstorms [1]_, or the time + between page requests to Wikipedia [2]_. + + Parameters + ---------- + scale : float or array_like of floats + The scale parameter, :math:`\\beta = 1/\\lambda`. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``scale`` is a scalar. Otherwise, + ``np.array(scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized exponential distribution. + + References + ---------- + .. [1] Peyton Z. Peebles Jr., "Probability, Random Variables and + Random Signal Principles", 4th ed, 2001, p. 57. + .. [2] Wikipedia, "Poisson process", + https://en.wikipedia.org/wiki/Poisson_process + .. [3] Wikipedia, "Exponential distribution", + https://en.wikipedia.org/wiki/Exponential_distribution + + """ + return cont(&legacy_exponential, self._aug_state, size, self.lock, 1, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) + + def standard_exponential(self, size=None): + """ + standard_exponential(size=None) + + Draw samples from the standard exponential distribution. + + `standard_exponential` is identical to the exponential distribution + with a scale parameter of 1. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : float or ndarray + Drawn samples. + + Examples + -------- + Output a 3x8000 array: + + >>> n = randomgen.generator.standard_exponential((3, 8000)) + """ + return cont(&legacy_standard_exponential, self._aug_state, size, self.lock, 0, + None, None, CONS_NONE, + None, None, CONS_NONE, + None, None, CONS_NONE, + None) + + def randn(self, *args): + """ + randn(d0, d1, ..., dn) + + Return a sample (or samples) from the "standard normal" distribution. + + If positive, int_like or int-convertible arguments are provided, + `randn` generates an array of shape ``(d0, d1, ..., dn)``, filled + with random floats sampled from a univariate "normal" (Gaussian) + distribution of mean 0 and variance 1 (if any of the :math:`d_i` are + floats, they are first converted to integers by truncation). A single + float randomly sampled from the distribution is returned if no + argument is provided. + + This is a convenience function. If you want an interface that takes a + tuple as the first argument, use `standard_normal` instead. + + Parameters + ---------- + d0, d1, ..., dn : int, optional + The dimensions of the returned array, should be all positive. + If no argument is given a single Python float is returned. + + Returns + ------- + Z : ndarray or float + A ``(d0, d1, ..., dn)``-shaped array of floating-point samples from + the standard normal distribution, or a single such float if + no parameters were supplied. + + See Also + -------- + standard_normal : Similar, but takes a tuple as its argument. + + Notes + ----- + For random samples from :math:`N(\\mu, \\sigma^2)`, use: + + ``sigma * randomgen.generator.randn(...) + mu`` + + Examples + -------- + >>> randomgen.generator.randn() + 2.1923875335537315 #random + + Two-by-four array of samples from N(3, 6.25): + + >>> 2.5 * randomgen.generator.randn(2, 4) + 3 + array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random + [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random + + """ + if len(args) == 0: + return self.standard_normal() + else: + return self.standard_normal(size=args) + # Complicated, continuous distributions: def standard_normal(self, size=None): """ @@ -239,472 +422,339 @@ cdef class _LegacyGenerator: None, None, CONS_NONE, None) - def standard_t(self, df, size=None): + def normal(self, loc=0.0, scale=1.0, size=None): """ - standard_t(df, size=None) + normal(loc=0.0, scale=1.0, size=None) - Draw samples from a standard Student's t distribution with `df` degrees - of freedom. + Draw random samples from a normal (Gaussian) distribution. - A special case of the hyperbolic distribution. As `df` gets - large, the result resembles that of the standard normal - distribution (`standard_normal`). + The probability density function of the normal distribution, first + derived by De Moivre and 200 years later by both Gauss and Laplace + independently [2]_, is often called the bell curve because of + its characteristic shape (see the example below). + + The normal distributions occurs often in nature. For example, it + describes the commonly occurring distribution of samples influenced + by a large number of tiny, random disturbances, each with its own + unique distribution [2]_. Parameters ---------- - df : int or array_like of ints - Degrees of freedom, should be > 0. + loc : float or array_like of floats + Mean ("centre") of the distribution. + scale : float or array_like of floats + Standard deviation (spread or "width") of the distribution. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``df`` is a scalar. Otherwise, - ``np.array(df).size`` samples are drawn. + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. Returns ------- out : ndarray or scalar - Drawn samples from the parameterized standard Student's t distribution. + Drawn samples from the parameterized normal distribution. + + See Also + -------- + scipy.stats.norm : probability density function, distribution or + cumulative density function, etc. Notes ----- - The probability density function for the t distribution is + The probability density for the Gaussian distribution is - .. math:: P(x, df) = \\frac{\\Gamma(\\frac{df+1}{2})}{\\sqrt{\\pi df} - \\Gamma(\\frac{df}{2})}\\Bigl( 1+\\frac{x^2}{df} \\Bigr)^{-(df+1)/2} + .. math:: p(x) = \\frac{1}{\\sqrt{ 2 \\pi \\sigma^2 }} + e^{ - \\frac{ (x - \\mu)^2 } {2 \\sigma^2} }, - The t test is based on an assumption that the data come from a - Normal distribution. The t test provides a way to test whether - the sample mean (that is the mean calculated from the data) is - a good estimate of the true mean. + where :math:`\\mu` is the mean and :math:`\\sigma` the standard + deviation. The square of the standard deviation, :math:`\\sigma^2`, + is called the variance. - The derivation of the t-distribution was first published in - 1908 by William Gosset while working for the Guinness Brewery - in Dublin. Due to proprietary issues, he had to publish under - a pseudonym, and so he used the name Student. + The function has its peak at the mean, and its "spread" increases with + the standard deviation (the function reaches 0.607 times its maximum at + :math:`x + \\sigma` and :math:`x - \\sigma` [2]_). This implies that + `numpy.random.normal` is more likely to return samples lying close to + the mean, rather than those far away. References ---------- - .. [1] Dalgaard, Peter, "Introductory Statistics With R", - Springer, 2002. - .. [2] Wikipedia, "Student's t-distribution" - https://en.wikipedia.org/wiki/Student's_t-distribution + .. [1] Wikipedia, "Normal distribution", + https://en.wikipedia.org/wiki/Normal_distribution + .. [2] P. R. Peebles Jr., "Central Limit Theorem" in "Probability, + Random Variables and Random Signal Principles", 4th ed., 2001, + pp. 51, 51, 125. Examples -------- - From Dalgaard page 83 [1]_, suppose the daily energy intake for 11 - women in kilojoules (kJ) is: + Draw samples from the distribution: - >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\ - ... 7515, 8230, 8770]) + >>> mu, sigma = 0, 0.1 # mean and standard deviation + >>> s = randomgen.generator.normal(mu, sigma, 1000) - Does their energy intake deviate systematically from the recommended - value of 7725 kJ? + Verify the mean and the variance: - We have 10 degrees of freedom, so is the sample mean within 95% of the - recommended value? + >>> abs(mu - np.mean(s)) < 0.01 + True - >>> s = randomgen.generator.standard_t(10, size=100000) - >>> np.mean(intake) - 6753.636363636364 - >>> intake.std(ddof=1) - 1142.1232221373727 + >>> abs(sigma - np.std(s, ddof=1)) < 0.01 + True - Calculate the t statistic, setting the ddof parameter to the unbiased - value so the divisor in the standard deviation will be degrees of - freedom, N-1. + Display the histogram of the samples, along with + the probability density function: - >>> t = (np.mean(intake)-7725)/(intake.std(ddof=1)/np.sqrt(len(intake))) >>> import matplotlib.pyplot as plt - >>> h = plt.hist(s, bins=100, density=True) - - For a one-sided t-test, how far out in the distribution does the t - statistic appear? - - >>> np.sum(s>> count, bins, ignored = plt.hist(s, 30, density=True) + >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * + ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ), + ... linewidth=2, color='r') + >>> plt.show() """ - return cont(&legacy_standard_t, self._aug_state, size, self.lock, 1, - df, 'df', CONS_POSITIVE, - 0, '', CONS_NONE, - 0, '', CONS_NONE, + return cont(&legacy_normal, self._aug_state, size, self.lock, 2, + loc, '', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) - def lognormal(self, mean=0.0, sigma=1.0, size=None): + def standard_gamma(self, shape, size=None): """ - lognormal(mean=0.0, sigma=1.0, size=None) + standard_gamma(shape, size=None) - Draw samples from a log-normal distribution. + Draw samples from a standard Gamma distribution. - Draw samples from a log-normal distribution with specified mean, - standard deviation, and array shape. Note that the mean and standard - deviation are not the values for the distribution itself, but of the - underlying normal distribution it is derived from. + Samples are drawn from a Gamma distribution with specified parameters, + shape (sometimes designated "k") and scale=1. Parameters ---------- - mean : float or array_like of floats, optional - Mean value of the underlying normal distribution. Default is 0. - sigma : float or array_like of floats, optional - Standard deviation of the underlying normal distribution. Should - be greater than zero. Default is 1. + shape : float or array_like of floats + Parameter, should be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``mean`` and ``sigma`` are both scalars. - Otherwise, ``np.broadcast(mean, sigma).size`` samples are drawn. + a single value is returned if ``shape`` is a scalar. Otherwise, + ``np.array(shape).size`` samples are drawn. Returns ------- out : ndarray or scalar - Drawn samples from the parameterized log-normal distribution. + Drawn samples from the parameterized standard gamma distribution. See Also -------- - scipy.stats.lognorm : probability density function, distribution, + scipy.stats.gamma : probability density function, distribution or cumulative density function, etc. Notes ----- - A variable `x` has a log-normal distribution if `log(x)` is normally - distributed. The probability density function for the log-normal - distribution is: + The probability density for the Gamma distribution is - .. math:: p(x) = \\frac{1}{\\sigma x \\sqrt{2\\pi}} - e^{(-\\frac{(ln(x)-\\mu)^2}{2\\sigma^2})} + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, - where :math:`\\mu` is the mean and :math:`\\sigma` is the standard - deviation of the normally distributed logarithm of the variable. - A log-normal distribution results if a random variable is the *product* - of a large number of independent, identically-distributed variables in - the same way that a normal distribution results if the variable is the - *sum* of a large number of independent, identically-distributed - variables. + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. References ---------- - .. [1] Limpert, E., Stahel, W. A., and Abbt, M., "Log-normal - Distributions across the Sciences: Keys and Clues," - BioScience, Vol. 51, No. 5, May, 2001. - http://stat.ethz.ch/~stahel/lognormal/bioscience.pdf - .. [2] Reiss, R.D. and Thomas, M., "Statistical Analysis of Extreme - Values," Basel: Birkhauser Verlag, 2001, pp. 31-32. + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + https://en.wikipedia.org/wiki/Gamma_distribution Examples -------- Draw samples from the distribution: - >>> mu, sigma = 3., 1. # mean and standard deviation - >>> s = randomgen.generator.lognormal(mu, sigma, 1000) + >>> shape, scale = 2., 1. # mean and width + >>> s = randomgen.generator.standard_gamma(shape, 1000000) Display the histogram of the samples, along with the probability density function: >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, 100, density=True, align='mid') - - >>> x = np.linspace(min(bins), max(bins), 10000) - >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) - ... / (x * sigma * np.sqrt(2 * np.pi))) - - >>> plt.plot(x, pdf, linewidth=2, color='r') - >>> plt.axis('tight') - >>> plt.show() - - Demonstrate that taking the products of random samples from a uniform - distribution can be fit well by a log-normal probability density - function. - - >>> # Generate a thousand samples: each is the product of 100 random - >>> # values, drawn from a normal distribution. - >>> b = [] - >>> for i in range(1000): - ... a = 10. + randomgen.generator.randn(100) - ... b.append(np.product(a)) - - >>> b = np.array(b) / np.min(b) # scale values to be positive - >>> count, bins, ignored = plt.hist(b, 100, density=True, align='mid') - >>> sigma = np.std(np.log(b)) - >>> mu = np.mean(np.log(b)) - - >>> x = np.linspace(min(bins), max(bins), 10000) - >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) - ... / (x * sigma * np.sqrt(2 * np.pi))) - - >>> plt.plot(x, pdf, color='r', linewidth=2) + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, density=True) + >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ + ... (sps.gamma(shape) * scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') >>> plt.show() - """ - return cont(&legacy_lognormal, self._aug_state, size, self.lock, 2, - mean, 'mean', CONS_NONE, - sigma, 'sigma', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, None) + return cont(&legacy_standard_gamma, self._aug_state, size, self.lock, 1, + shape, 'shape', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) - def wald(self, mean, scale, size=None): + def gamma(self, shape, scale=1.0, size=None): """ - wald(mean, scale, size=None) - - Draw samples from a Wald, or inverse Gaussian, distribution. + gamma(shape, scale=1.0, size=None) - As the scale approaches infinity, the distribution becomes more like a - Gaussian. Some references claim that the Wald is an inverse Gaussian - with mean equal to 1, but this is by no means universal. + Draw samples from a Gamma distribution. - The inverse Gaussian distribution was first studied in relationship to - Brownian motion. In 1956 M.C.K. Tweedie used the name inverse Gaussian - because there is an inverse relationship between the time to cover a - unit distance and distance covered in unit time. + Samples are drawn from a Gamma distribution with specified parameters, + `shape` (sometimes designated "k") and `scale` (sometimes designated + "theta"), where both parameters are > 0. Parameters ---------- - mean : float or array_like of floats - Distribution mean, must be > 0. - scale : float or array_like of floats - Scale parameter, must be > 0. + shape : float or array_like of floats + The shape of the gamma distribution. Should be greater than zero. + scale : float or array_like of floats, optional + The scale of the gamma distribution. Should be greater than zero. + Default is equal to 1. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``mean`` and ``scale`` are both scalars. - Otherwise, ``np.broadcast(mean, scale).size`` samples are drawn. + a single value is returned if ``shape`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(shape, scale).size`` samples are drawn. Returns ------- out : ndarray or scalar - Drawn samples from the parameterized Wald distribution. + Drawn samples from the parameterized gamma distribution. + + See Also + -------- + scipy.stats.gamma : probability density function, distribution or + cumulative density function, etc. Notes ----- - The probability density function for the Wald distribution is + The probability density for the Gamma distribution is - .. math:: P(x;mean,scale) = \\sqrt{\\frac{scale}{2\\pi x^3}}e^ - \\frac{-scale(x-mean)^2}{2\\cdotp mean^2x} + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, - As noted above the inverse Gaussian distribution first arise - from attempts to model Brownian motion. It is also a - competitor to the Weibull for use in reliability modeling and - modeling stock returns and interest rate processes. + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. References ---------- - .. [1] Brighton Webs Ltd., Wald Distribution, - http://www.brighton-webs.co.uk/distributions/wald.asp - .. [2] Chhikara, Raj S., and Folks, J. Leroy, "The Inverse Gaussian - Distribution: Theory : Methodology, and Applications", CRC Press, - 1988. - .. [3] Wikipedia, "Wald distribution" - https://en.wikipedia.org/wiki/Wald_distribution + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + https://en.wikipedia.org/wiki/Gamma_distribution Examples -------- - Draw values from the distribution and plot the histogram: + Draw samples from the distribution: + + >>> shape, scale = 2., 2. # mean and dispersion + >>> s = randomgen.generator.gamma(shape, scale, 1000) + + Display the histogram of the samples, along with + the probability density function: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(randomgen.generator.wald(3, 2, 100000), bins=200, density=True) + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, density=True) + >>> y = bins**(shape-1)*(np.exp(-bins/scale) / + ... (sps.gamma(shape)*scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') >>> plt.show() """ - return cont(&legacy_wald, self._aug_state, size, self.lock, 2, - mean, 'mean', CONS_POSITIVE, - scale, 'scale', CONS_POSITIVE, + return cont(&legacy_gamma, self._aug_state, size, self.lock, 2, + shape, 'shape', CONS_NON_NEGATIVE, + scale, 'scale', CONS_NON_NEGATIVE, 0.0, '', CONS_NONE, None) - def pareto(self, a, size=None): + def f(self, dfnum, dfden, size=None): """ - pareto(a, size=None) + f(dfnum, dfden, size=None) - Draw samples from a Pareto II or Lomax distribution with - specified shape. + Draw samples from an F distribution. - The Lomax or Pareto II distribution is a shifted Pareto - distribution. The classical Pareto distribution can be - obtained from the Lomax distribution by adding 1 and - multiplying by the scale parameter ``m`` (see Notes). The - smallest value of the Lomax distribution is zero while for the - classical Pareto distribution it is ``mu``, where the standard - Pareto distribution has location ``mu = 1``. Lomax can also - be considered as a simplified version of the Generalized - Pareto distribution (available in SciPy), with the scale set - to one and the location set to zero. + Samples are drawn from an F distribution with specified parameters, + `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of + freedom in denominator), where both parameters should be greater than + zero. - The Pareto distribution must be greater than zero, and is - unbounded above. It is also known as the "80-20 rule". In - this distribution, 80 percent of the weights are in the lowest - 20 percent of the range, while the other 20 percent fill the - remaining 80 percent of the range. + The random variate of the F distribution (also known as the + Fisher distribution) is a continuous probability distribution + that arises in ANOVA tests, and is the ratio of two chi-square + variates. Parameters ---------- - a : float or array_like of floats - Shape of the distribution. Should be greater than zero. + dfnum : int or array_like of ints + Degrees of freedom in numerator. Should be greater than zero. + dfden : int or array_like of ints + Degrees of freedom in denominator. Should be greater than zero. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``a`` is a scalar. Otherwise, - ``np.array(a).size`` samples are drawn. + a single value is returned if ``dfnum`` and ``dfden`` are both scalars. + Otherwise, ``np.broadcast(dfnum, dfden).size`` samples are drawn. Returns ------- out : ndarray or scalar - Drawn samples from the parameterized Pareto distribution. + Drawn samples from the parameterized Fisher distribution. See Also -------- - scipy.stats.lomax : probability density function, distribution or - cumulative density function, etc. - scipy.stats.genpareto : probability density function, distribution or + scipy.stats.f : probability density function, distribution or cumulative density function, etc. Notes ----- - The probability density for the Pareto distribution is - - .. math:: p(x) = \\frac{am^a}{x^{a+1}} - - where :math:`a` is the shape and :math:`m` the scale. - - The Pareto distribution, named after the Italian economist - Vilfredo Pareto, is a power law probability distribution - useful in many real world problems. Outside the field of - economics it is generally referred to as the Bradford - distribution. Pareto developed the distribution to describe - the distribution of wealth in an economy. It has also found - use in insurance, web page access statistics, oil field sizes, - and many other problems, including the download frequency for - projects in Sourceforge [1]_. It is one of the so-called - "fat-tailed" distributions. - + The F statistic is used to compare in-group variances to between-group + variances. Calculating the distribution depends on the sampling, and + so it is a function of the respective degrees of freedom in the + problem. The variable `dfnum` is the number of samples minus one, the + between-groups degrees of freedom, while `dfden` is the within-groups + degrees of freedom, the sum of the number of samples in each group + minus the number of groups. References ---------- - .. [1] Francis Hunt and Paul Johnson, On the Pareto Distribution of - Sourceforge projects. - .. [2] Pareto, V. (1896). Course of Political Economy. Lausanne. - .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme - Values, Birkhauser Verlag, Basel, pp 23-30. - .. [4] Wikipedia, "Pareto distribution", - https://en.wikipedia.org/wiki/Pareto_distribution + .. [1] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, + Fifth Edition, 2002. + .. [2] Wikipedia, "F-distribution", + https://en.wikipedia.org/wiki/F-distribution Examples -------- - Draw samples from the distribution: - - >>> a, m = 3., 2. # shape and mode - >>> s = (randomgen.generator.pareto(a, 1000) + 1) * m - - Display the histogram of the samples, along with the probability - density function: - - >>> import matplotlib.pyplot as plt - >>> count, bins, _ = plt.hist(s, 100, density=True) - >>> fit = a*m**a / bins**(a+1) - >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r') - >>> plt.show() - - """ - return cont(&legacy_pareto, self._aug_state, size, self.lock, 1, - a, 'a', CONS_POSITIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, None) - - def weibull(self, a, size=None): - """ - weibull(a, size=None) - - Draw samples from a Weibull distribution. - - Draw samples from a 1-parameter Weibull distribution with the given - shape parameter `a`. - - .. math:: X = (-ln(U))^{1/a} - - Here, U is drawn from the uniform distribution over (0,1]. - - The more common 2-parameter Weibull, including a scale parameter - :math:`\\lambda` is just :math:`X = \\lambda(-ln(U))^{1/a}`. - - Parameters - ---------- - a : float or array_like of floats - Shape of the distribution. Should be greater than zero. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``a`` is a scalar. Otherwise, - ``np.array(a).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized Weibull distribution. - - See Also - -------- - scipy.stats.weibull_max - scipy.stats.weibull_min - scipy.stats.genextreme - gumbel - - Notes - ----- - The Weibull (or Type III asymptotic extreme value distribution - for smallest values, SEV Type III, or Rosin-Rammler - distribution) is one of a class of Generalized Extreme Value - (GEV) distributions used in modeling extreme value problems. - This class includes the Gumbel and Frechet distributions. - - The probability density for the Weibull distribution is - - .. math:: p(x) = \\frac{a} - {\\lambda}(\\frac{x}{\\lambda})^{a-1}e^{-(x/\\lambda)^a}, - - where :math:`a` is the shape and :math:`\\lambda` the scale. - - The function has its peak (the mode) at - :math:`\\lambda(\\frac{a-1}{a})^{1/a}`. - - When ``a = 1``, the Weibull distribution reduces to the exponential - distribution. + An example from Glantz[1], pp 47-40: - References - ---------- - .. [1] Waloddi Weibull, Royal Technical University, Stockholm, - 1939 "A Statistical Theory Of The Strength Of Materials", - Ingeniorsvetenskapsakademiens Handlingar Nr 151, 1939, - Generalstabens Litografiska Anstalts Forlag, Stockholm. - .. [2] Waloddi Weibull, "A Statistical Distribution Function of - Wide Applicability", Journal Of Applied Mechanics ASME Paper - 1951. - .. [3] Wikipedia, "Weibull distribution", - https://en.wikipedia.org/wiki/Weibull_distribution + Two groups, children of diabetics (25 people) and children from people + without diabetes (25 controls). Fasting blood glucose was measured, + case group had a mean value of 86.1, controls had a mean value of + 82.2. Standard deviations were 2.09 and 2.49 respectively. Are these + data consistent with the null hypothesis that the parents diabetic + status does not affect their children's blood glucose levels? + Calculating the F statistic from the data gives a value of 36.01. - Examples - -------- Draw samples from the distribution: - >>> a = 5. # shape - >>> s = randomgen.generator.weibull(a, 1000) + >>> dfnum = 1. # between group degrees of freedom + >>> dfden = 48. # within groups degrees of freedom + >>> s = randomgen.generator.f(dfnum, dfden, 1000) - Display the histogram of the samples, along with - the probability density function: + The lower bound for the top 1% of the samples is : - >>> import matplotlib.pyplot as plt - >>> x = np.arange(1,100.)/50. - >>> def weib(x,n,a): - ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) + >>> np.sort(s)[-10] + 7.61988120985 # random - >>> count, bins, ignored = plt.hist(randomgen.generator.weibull(5.,1000)) - >>> x = np.arange(1,100.)/50. - >>> scale = count.max()/weib(x, 1., 5.).max() - >>> plt.plot(x, weib(x, 1., 5.)*scale) - >>> plt.show() + So there is about a 1% chance that the F statistic will exceed 7.62, + the measured value is 36, so the null hypothesis is rejected at the 1% + level. """ - return cont(&legacy_weibull, self._aug_state, size, self.lock, 1, - a, 'a', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, + return cont(&legacy_f, self._aug_state, size, self.lock, 2, + dfnum, 'dfnum', CONS_POSITIVE, + dfden, 'dfden', CONS_POSITIVE, 0.0, '', CONS_NONE, None) def noncentral_f(self, dfnum, dfden, nonc, size=None): @@ -835,12 +885,12 @@ cdef class _LegacyGenerator: References ---------- .. [1] NIST "Engineering Statistics Handbook" - http://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm + https://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm Examples -------- >>> randomgen.generator.chisquare(2,4) - array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) + array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) # random """ return cont(&legacy_chisquare, self._aug_state, size, self.lock, 1, @@ -990,442 +1040,575 @@ cdef class _LegacyGenerator: return cont(&legacy_standard_cauchy, self._aug_state, size, self.lock, 0, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) - - def standard_gamma(self, shape, size=None): + def standard_t(self, df, size=None): """ - standard_gamma(shape, size=None) + standard_t(df, size=None) - Draw samples from a standard Gamma distribution. + Draw samples from a standard Student's t distribution with `df` degrees + of freedom. - Samples are drawn from a Gamma distribution with specified parameters, - shape (sometimes designated "k") and scale=1. + A special case of the hyperbolic distribution. As `df` gets + large, the result resembles that of the standard normal + distribution (`standard_normal`). Parameters ---------- - shape : float or array_like of floats - Parameter, should be > 0. + df : int or array_like of ints + Degrees of freedom, should be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``shape`` is a scalar. Otherwise, - ``np.array(shape).size`` samples are drawn. + a single value is returned if ``df`` is a scalar. Otherwise, + ``np.array(df).size`` samples are drawn. Returns ------- out : ndarray or scalar - Drawn samples from the parameterized standard gamma distribution. - - See Also - -------- - scipy.stats.gamma : probability density function, distribution or - cumulative density function, etc. + Drawn samples from the parameterized standard Student's t distribution. Notes ----- - The probability density for the Gamma distribution is + The probability density function for the t distribution is - .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + .. math:: P(x, df) = \\frac{\\Gamma(\\frac{df+1}{2})}{\\sqrt{\\pi df} + \\Gamma(\\frac{df}{2})}\\Bigl( 1+\\frac{x^2}{df} \\Bigr)^{-(df+1)/2} - where :math:`k` is the shape and :math:`\\theta` the scale, - and :math:`\\Gamma` is the Gamma function. + The t test is based on an assumption that the data come from a + Normal distribution. The t test provides a way to test whether + the sample mean (that is the mean calculated from the data) is + a good estimate of the true mean. - The Gamma distribution is often used to model the times to failure of - electronic components, and arises naturally in processes for which the - waiting times between Poisson distributed events are relevant. + The derivation of the t-distribution was first published in + 1908 by William Gosset while working for the Guinness Brewery + in Dublin. Due to proprietary issues, he had to publish under + a pseudonym, and so he used the name Student. References ---------- - .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A - Wolfram Web Resource. - http://mathworld.wolfram.com/GammaDistribution.html - .. [2] Wikipedia, "Gamma distribution", - https://en.wikipedia.org/wiki/Gamma_distribution + .. [1] Dalgaard, Peter, "Introductory Statistics With R", + Springer, 2002. + .. [2] Wikipedia, "Student's t-distribution" + https://en.wikipedia.org/wiki/Student's_t-distribution Examples -------- - Draw samples from the distribution: + From Dalgaard page 83 [1]_, suppose the daily energy intake for 11 + women in kilojoules (kJ) is: - >>> shape, scale = 2., 1. # mean and width - >>> s = randomgen.generator.standard_gamma(shape, 1000000) + >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\ + ... 7515, 8230, 8770]) - Display the histogram of the samples, along with - the probability density function: + Does their energy intake deviate systematically from the recommended + value of 7725 kJ? + + We have 10 degrees of freedom, so is the sample mean within 95% of the + recommended value? + + >>> s = randomgen.generator.standard_t(10, size=100000) + >>> np.mean(intake) + 6753.636363636364 + >>> intake.std(ddof=1) + 1142.1232221373727 + + Calculate the t statistic, setting the ddof parameter to the unbiased + value so the divisor in the standard deviation will be degrees of + freedom, N-1. + + >>> t = (np.mean(intake)-7725)/(intake.std(ddof=1)/np.sqrt(len(intake))) + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(s, bins=100, density=True) + + For a one-sided t-test, how far out in the distribution does the t + statistic appear? + + >>> np.sum(s>> import matplotlib.pyplot as plt - >>> import scipy.special as sps - >>> count, bins, ignored = plt.hist(s, 50, density=True) - >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ - ... (sps.gamma(shape) * scale**shape)) - >>> plt.plot(bins, y, linewidth=2, color='r') - >>> plt.show() """ - return cont(&legacy_standard_gamma, self._aug_state, size, self.lock, 1, - shape, 'shape', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, + return cont(&legacy_standard_t, self._aug_state, size, self.lock, 1, + df, 'df', CONS_POSITIVE, + 0, '', CONS_NONE, + 0, '', CONS_NONE, None) - def gamma(self, shape, scale=1.0, size=None): + def pareto(self, a, size=None): """ - gamma(shape, scale=1.0, size=None) + pareto(a, size=None) - Draw samples from a Gamma distribution. + Draw samples from a Pareto II or Lomax distribution with + specified shape. - Samples are drawn from a Gamma distribution with specified parameters, - `shape` (sometimes designated "k") and `scale` (sometimes designated - "theta"), where both parameters are > 0. + The Lomax or Pareto II distribution is a shifted Pareto + distribution. The classical Pareto distribution can be + obtained from the Lomax distribution by adding 1 and + multiplying by the scale parameter ``m`` (see Notes). The + smallest value of the Lomax distribution is zero while for the + classical Pareto distribution it is ``mu``, where the standard + Pareto distribution has location ``mu = 1``. Lomax can also + be considered as a simplified version of the Generalized + Pareto distribution (available in SciPy), with the scale set + to one and the location set to zero. + + The Pareto distribution must be greater than zero, and is + unbounded above. It is also known as the "80-20 rule". In + this distribution, 80 percent of the weights are in the lowest + 20 percent of the range, while the other 20 percent fill the + remaining 80 percent of the range. Parameters ---------- - shape : float or array_like of floats - The shape of the gamma distribution. Should be greater than zero. - scale : float or array_like of floats, optional - The scale of the gamma distribution. Should be greater than zero. - Default is equal to 1. + a : float or array_like of floats + Shape of the distribution. Should be greater than zero. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``shape`` and ``scale`` are both scalars. - Otherwise, ``np.broadcast(shape, scale).size`` samples are drawn. + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. Returns ------- out : ndarray or scalar - Drawn samples from the parameterized gamma distribution. + Drawn samples from the parameterized Pareto distribution. See Also -------- - scipy.stats.gamma : probability density function, distribution or + scipy.stats.lomax : probability density function, distribution or + cumulative density function, etc. + scipy.stats.genpareto : probability density function, distribution or cumulative density function, etc. Notes ----- - The probability density for the Gamma distribution is + The probability density for the Pareto distribution is - .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + .. math:: p(x) = \\frac{am^a}{x^{a+1}} - where :math:`k` is the shape and :math:`\\theta` the scale, - and :math:`\\Gamma` is the Gamma function. + where :math:`a` is the shape and :math:`m` the scale. + + The Pareto distribution, named after the Italian economist + Vilfredo Pareto, is a power law probability distribution + useful in many real world problems. Outside the field of + economics it is generally referred to as the Bradford + distribution. Pareto developed the distribution to describe + the distribution of wealth in an economy. It has also found + use in insurance, web page access statistics, oil field sizes, + and many other problems, including the download frequency for + projects in Sourceforge [1]_. It is one of the so-called + "fat-tailed" distributions. - The Gamma distribution is often used to model the times to failure of - electronic components, and arises naturally in processes for which the - waiting times between Poisson distributed events are relevant. References ---------- - .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A - Wolfram Web Resource. - http://mathworld.wolfram.com/GammaDistribution.html - .. [2] Wikipedia, "Gamma distribution", - https://en.wikipedia.org/wiki/Gamma_distribution + .. [1] Francis Hunt and Paul Johnson, On the Pareto Distribution of + Sourceforge projects. + .. [2] Pareto, V. (1896). Course of Political Economy. Lausanne. + .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme + Values, Birkhauser Verlag, Basel, pp 23-30. + .. [4] Wikipedia, "Pareto distribution", + https://en.wikipedia.org/wiki/Pareto_distribution Examples -------- Draw samples from the distribution: - >>> shape, scale = 2., 2. # mean and dispersion - >>> s = randomgen.generator.gamma(shape, scale, 1000) + >>> a, m = 3., 2. # shape and mode + >>> s = (randomgen.generator.pareto(a, 1000) + 1) * m - Display the histogram of the samples, along with - the probability density function: + Display the histogram of the samples, along with the probability + density function: >>> import matplotlib.pyplot as plt - >>> import scipy.special as sps - >>> count, bins, ignored = plt.hist(s, 50, density=True) - >>> y = bins**(shape-1)*(np.exp(-bins/scale) / - ... (sps.gamma(shape)*scale**shape)) - >>> plt.plot(bins, y, linewidth=2, color='r') + >>> count, bins, _ = plt.hist(s, 100, density=True) + >>> fit = a*m**a / bins**(a+1) + >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r') >>> plt.show() """ - return cont(&legacy_gamma, self._aug_state, size, self.lock, 2, - shape, 'shape', CONS_NON_NEGATIVE, - scale, 'scale', CONS_NON_NEGATIVE, + return cont(&legacy_pareto, self._aug_state, size, self.lock, 1, + a, 'a', CONS_POSITIVE, + 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) - def beta(self, a, b, size=None): + def weibull(self, a, size=None): """ - beta(a, b, size=None) - - Draw samples from a Beta distribution. + weibull(a, size=None) - The Beta distribution is a special case of the Dirichlet distribution, - and is related to the Gamma distribution. It has the probability - distribution function + Draw samples from a Weibull distribution. - .. math:: f(x; a,b) = \\frac{1}{B(\\alpha, \\beta)} x^{\\alpha - 1} - (1 - x)^{\\beta - 1}, + Draw samples from a 1-parameter Weibull distribution with the given + shape parameter `a`. - where the normalisation, B, is the beta function, + .. math:: X = (-ln(U))^{1/a} - .. math:: B(\\alpha, \\beta) = \\int_0^1 t^{\\alpha - 1} - (1 - t)^{\\beta - 1} dt. + Here, U is drawn from the uniform distribution over (0,1]. - It is often seen in Bayesian inference and order statistics. + The more common 2-parameter Weibull, including a scale parameter + :math:`\\lambda` is just :math:`X = \\lambda(-ln(U))^{1/a}`. Parameters ---------- a : float or array_like of floats - Alpha, non-negative. - b : float or array_like of floats - Beta, non-negative. + Shape parameter of the distribution. Must be nonnegative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``a`` and ``b`` are both scalars. - Otherwise, ``np.broadcast(a, b).size`` samples are drawn. + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. Returns ------- out : ndarray or scalar - Drawn samples from the parameterized beta distribution. + Drawn samples from the parameterized Weibull distribution. + + See Also + -------- + scipy.stats.weibull_max + scipy.stats.weibull_min + scipy.stats.genextreme + gumbel + + Notes + ----- + The Weibull (or Type III asymptotic extreme value distribution + for smallest values, SEV Type III, or Rosin-Rammler + distribution) is one of a class of Generalized Extreme Value + (GEV) distributions used in modeling extreme value problems. + This class includes the Gumbel and Frechet distributions. + + The probability density for the Weibull distribution is + + .. math:: p(x) = \\frac{a} + {\\lambda}(\\frac{x}{\\lambda})^{a-1}e^{-(x/\\lambda)^a}, + + where :math:`a` is the shape and :math:`\\lambda` the scale. + + The function has its peak (the mode) at + :math:`\\lambda(\\frac{a-1}{a})^{1/a}`. + + When ``a = 1``, the Weibull distribution reduces to the exponential + distribution. + + References + ---------- + .. [1] Waloddi Weibull, Royal Technical University, Stockholm, + 1939 "A Statistical Theory Of The Strength Of Materials", + Ingeniorsvetenskapsakademiens Handlingar Nr 151, 1939, + Generalstabens Litografiska Anstalts Forlag, Stockholm. + .. [2] Waloddi Weibull, "A Statistical Distribution Function of + Wide Applicability", Journal Of Applied Mechanics ASME Paper + 1951. + .. [3] Wikipedia, "Weibull distribution", + https://en.wikipedia.org/wiki/Weibull_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a = 5. # shape + >>> s = randomgen.generator.weibull(a, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> x = np.arange(1,100.)/50. + >>> def weib(x,n,a): + ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) + + >>> count, bins, ignored = plt.hist(randomgen.generator.weibull(5.,1000)) + >>> x = np.arange(1,100.)/50. + >>> scale = count.max()/weib(x, 1., 5.).max() + >>> plt.plot(x, weib(x, 1., 5.)*scale) + >>> plt.show() """ - return cont(&legacy_beta, self._aug_state, size, self.lock, 2, - a, 'a', CONS_POSITIVE, - b, 'b', CONS_POSITIVE, + return cont(&legacy_weibull, self._aug_state, size, self.lock, 1, + a, 'a', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) - def f(self, dfnum, dfden, size=None): + def power(self, a, size=None): """ - f(dfnum, dfden, size=None) - - Draw samples from an F distribution. + power(a, size=None) - Samples are drawn from an F distribution with specified parameters, - `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of - freedom in denominator), where both parameters should be greater than - zero. + Draws samples in [0, 1] from a power distribution with positive + exponent a - 1. - The random variate of the F distribution (also known as the - Fisher distribution) is a continuous probability distribution - that arises in ANOVA tests, and is the ratio of two chi-square - variates. + Also known as the power function distribution. Parameters ---------- - dfnum : int or array_like of ints - Degrees of freedom in numerator. Should be greater than zero. - dfden : int or array_like of ints - Degrees of freedom in denominator. Should be greater than zero. + a : float or array_like of floats + Parameter of the distribution. Should be greater than zero. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``dfnum`` and ``dfden`` are both scalars. - Otherwise, ``np.broadcast(dfnum, dfden).size`` samples are drawn. + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. Returns ------- out : ndarray or scalar - Drawn samples from the parameterized Fisher distribution. + Drawn samples from the parameterized power distribution. - See Also - -------- - scipy.stats.f : probability density function, distribution or - cumulative density function, etc. + Raises + ------ + ValueError + If a < 1. Notes ----- - The F statistic is used to compare in-group variances to between-group - variances. Calculating the distribution depends on the sampling, and - so it is a function of the respective degrees of freedom in the - problem. The variable `dfnum` is the number of samples minus one, the - between-groups degrees of freedom, while `dfden` is the within-groups - degrees of freedom, the sum of the number of samples in each group - minus the number of groups. + The probability density function is + + .. math:: P(x; a) = ax^{a-1}, 0 \\le x \\le 1, a>0. + + The power function distribution is just the inverse of the Pareto + distribution. It may also be seen as a special case of the Beta + distribution. + + It is used, for example, in modeling the over-reporting of insurance + claims. References ---------- - .. [1] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, - Fifth Edition, 2002. - .. [2] Wikipedia, "F-distribution", - https://en.wikipedia.org/wiki/F-distribution + .. [1] Christian Kleiber, Samuel Kotz, "Statistical size distributions + in economics and actuarial sciences", Wiley, 2003. + .. [2] Heckert, N. A. and Filliben, James J. "NIST Handbook 148: + Dataplot Reference Manual, Volume 2: Let Subcommands and Library + Functions", National Institute of Standards and Technology + Handbook Series, June 2003. + http://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf Examples -------- - An example from Glantz[1], pp 47-40: + Draw samples from the distribution: - Two groups, children of diabetics (25 people) and children from people - without diabetes (25 controls). Fasting blood glucose was measured, - case group had a mean value of 86.1, controls had a mean value of - 82.2. Standard deviations were 2.09 and 2.49 respectively. Are these - data consistent with the null hypothesis that the parents diabetic - status does not affect their children's blood glucose levels? - Calculating the F statistic from the data gives a value of 36.01. + >>> a = 5. # shape + >>> samples = 1000 + >>> s = randomgen.generator.power(a, samples) - Draw samples from the distribution: + Display the histogram of the samples, along with + the probability density function: - >>> dfnum = 1. # between group degrees of freedom - >>> dfden = 48. # within groups degrees of freedom - >>> s = randomgen.generator.f(dfnum, dfden, 1000) + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, bins=30) + >>> x = np.linspace(0, 1, 100) + >>> y = a*x**(a-1.) + >>> normed_y = samples*np.diff(bins)[0]*y + >>> plt.plot(x, normed_y) + >>> plt.show() - The lower bound for the top 1% of the samples is : + Compare the power function distribution to the inverse of the Pareto. - >>> np.sort(s)[-10] - 7.61988120985 + >>> from scipy import stats + >>> rvs = randomgen.generator.power(5, 1000000) + >>> rvsp = randomgen.generator.pareto(5, 1000000) + >>> xx = np.linspace(0,1,100) + >>> powpdf = stats.powerlaw.pdf(xx,5) - So there is about a 1% chance that the F statistic will exceed 7.62, - the measured value is 36, so the null hypothesis is rejected at the 1% - level. + >>> plt.figure() + >>> plt.hist(rvs, bins=50, density=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('randomgen.generator.power(5)') - """ - return cont(&legacy_f, self._aug_state, size, self.lock, 2, - dfnum, 'dfnum', CONS_POSITIVE, - dfden, 'dfden', CONS_POSITIVE, - 0.0, '', CONS_NONE, None) + >>> plt.figure() + >>> plt.hist(1./(1.+rvsp), bins=50, density=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('inverse of 1 + randomgen.generator.pareto(5)') + >>> plt.figure() + >>> plt.hist(1./(1.+rvsp), bins=50, density=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('inverse of stats.pareto(5)') - def normal(self, loc=0.0, scale=1.0, size=None): """ - normal(loc=0.0, scale=1.0, size=None) + return cont(&legacy_power, self._aug_state, size, self.lock, 1, + a, 'a', CONS_POSITIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) - Draw random samples from a normal (Gaussian) distribution. + def lognormal(self, mean=0.0, sigma=1.0, size=None): + """ + lognormal(mean=0.0, sigma=1.0, size=None) - The probability density function of the normal distribution, first - derived by De Moivre and 200 years later by both Gauss and Laplace - independently [2]_, is often called the bell curve because of - its characteristic shape (see the example below). + Draw samples from a log-normal distribution. - The normal distributions occurs often in nature. For example, it - describes the commonly occurring distribution of samples influenced - by a large number of tiny, random disturbances, each with its own - unique distribution [2]_. + Draw samples from a log-normal distribution with specified mean, + standard deviation, and array shape. Note that the mean and standard + deviation are not the values for the distribution itself, but of the + underlying normal distribution it is derived from. Parameters ---------- - loc : float or array_like of floats - Mean ("centre") of the distribution. - scale : float or array_like of floats - Standard deviation (spread or "width") of the distribution. + mean : float or array_like of floats, optional + Mean value of the underlying normal distribution. Default is 0. + sigma : float or array_like of floats, optional + Standard deviation of the underlying normal distribution. Should + be greater than zero. Default is 1. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``loc`` and ``scale`` are both scalars. - Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + a single value is returned if ``mean`` and ``sigma`` are both scalars. + Otherwise, ``np.broadcast(mean, sigma).size`` samples are drawn. Returns ------- out : ndarray or scalar - Drawn samples from the parameterized normal distribution. + Drawn samples from the parameterized log-normal distribution. See Also -------- - scipy.stats.norm : probability density function, distribution or + scipy.stats.lognorm : probability density function, distribution, cumulative density function, etc. Notes ----- - The probability density for the Gaussian distribution is - - .. math:: p(x) = \\frac{1}{\\sqrt{ 2 \\pi \\sigma^2 }} - e^{ - \\frac{ (x - \\mu)^2 } {2 \\sigma^2} }, + A variable `x` has a log-normal distribution if `log(x)` is normally + distributed. The probability density function for the log-normal + distribution is: - where :math:`\\mu` is the mean and :math:`\\sigma` the standard - deviation. The square of the standard deviation, :math:`\\sigma^2`, - is called the variance. + .. math:: p(x) = \\frac{1}{\\sigma x \\sqrt{2\\pi}} + e^{(-\\frac{(ln(x)-\\mu)^2}{2\\sigma^2})} - The function has its peak at the mean, and its "spread" increases with - the standard deviation (the function reaches 0.607 times its maximum at - :math:`x + \\sigma` and :math:`x - \\sigma` [2]_). This implies that - `numpy.random.normal` is more likely to return samples lying close to - the mean, rather than those far away. + where :math:`\\mu` is the mean and :math:`\\sigma` is the standard + deviation of the normally distributed logarithm of the variable. + A log-normal distribution results if a random variable is the *product* + of a large number of independent, identically-distributed variables in + the same way that a normal distribution results if the variable is the + *sum* of a large number of independent, identically-distributed + variables. References ---------- - .. [1] Wikipedia, "Normal distribution", - https://en.wikipedia.org/wiki/Normal_distribution - .. [2] P. R. Peebles Jr., "Central Limit Theorem" in "Probability, - Random Variables and Random Signal Principles", 4th ed., 2001, - pp. 51, 51, 125. + .. [1] Limpert, E., Stahel, W. A., and Abbt, M., "Log-normal + Distributions across the Sciences: Keys and Clues," + BioScience, Vol. 51, No. 5, May, 2001. + https://stat.ethz.ch/~stahel/lognormal/bioscience.pdf + .. [2] Reiss, R.D. and Thomas, M., "Statistical Analysis of Extreme + Values," Basel: Birkhauser Verlag, 2001, pp. 31-32. Examples -------- Draw samples from the distribution: - >>> mu, sigma = 0, 0.1 # mean and standard deviation - >>> s = randomgen.generator.normal(mu, sigma, 1000) + >>> mu, sigma = 3., 1. # mean and standard deviation + >>> s = randomgen.generator.lognormal(mu, sigma, 1000) - Verify the mean and the variance: + Display the histogram of the samples, along with + the probability density function: - >>> abs(mu - np.mean(s)) < 0.01 - True + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 100, density=True, align='mid') - >>> abs(sigma - np.std(s, ddof=1)) < 0.01 - True + >>> x = np.linspace(min(bins), max(bins), 10000) + >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) + ... / (x * sigma * np.sqrt(2 * np.pi))) + + >>> plt.plot(x, pdf, linewidth=2, color='r') + >>> plt.axis('tight') + >>> plt.show() + + Demonstrate that taking the products of random samples from a uniform + distribution can be fit well by a log-normal probability density + function. + + >>> # Generate a thousand samples: each is the product of 100 random + >>> # values, drawn from a normal distribution. + >>> b = [] + >>> for i in range(1000): + ... a = 10. + randomgen.generator.randn(100) + ... b.append(np.product(a)) + + >>> b = np.array(b) / np.min(b) # scale values to be positive + >>> count, bins, ignored = plt.hist(b, 100, density=True, align='mid') + >>> sigma = np.std(np.log(b)) + >>> mu = np.mean(np.log(b)) - Display the histogram of the samples, along with - the probability density function: + >>> x = np.linspace(min(bins), max(bins), 10000) + >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) + ... / (x * sigma * np.sqrt(2 * np.pi))) - >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, 30, density=True) - >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * - ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ), - ... linewidth=2, color='r') + >>> plt.plot(x, pdf, color='r', linewidth=2) >>> plt.show() """ - return cont(&legacy_normal, self._aug_state, size, self.lock, 2, - loc, '', CONS_NONE, - scale, 'scale', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, - None) + return cont(&legacy_lognormal, self._aug_state, size, self.lock, 2, + mean, 'mean', CONS_NONE, + sigma, 'sigma', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) - def randn(self, *args): + def wald(self, mean, scale, size=None): """ - randn(d0, d1, ..., dn) + wald(mean, scale, size=None) - Return a sample (or samples) from the "standard normal" distribution. + Draw samples from a Wald, or inverse Gaussian, distribution. - If positive, int_like or int-convertible arguments are provided, - `randn` generates an array of shape ``(d0, d1, ..., dn)``, filled - with random floats sampled from a univariate "normal" (Gaussian) - distribution of mean 0 and variance 1 (if any of the :math:`d_i` are - floats, they are first converted to integers by truncation). A single - float randomly sampled from the distribution is returned if no - argument is provided. + As the scale approaches infinity, the distribution becomes more like a + Gaussian. Some references claim that the Wald is an inverse Gaussian + with mean equal to 1, but this is by no means universal. - This is a convenience function. If you want an interface that takes a - tuple as the first argument, use `standard_normal` instead. + The inverse Gaussian distribution was first studied in relationship to + Brownian motion. In 1956 M.C.K. Tweedie used the name inverse Gaussian + because there is an inverse relationship between the time to cover a + unit distance and distance covered in unit time. Parameters ---------- - d0, d1, ..., dn : int, optional - The dimensions of the returned array, should be all positive. - If no argument is given a single Python float is returned. + mean : float or array_like of floats + Distribution mean, must be > 0. + scale : float or array_like of floats + Scale parameter, must be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mean`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(mean, scale).size`` samples are drawn. Returns ------- - Z : ndarray or float - A ``(d0, d1, ..., dn)``-shaped array of floating-point samples from - the standard normal distribution, or a single such float if - no parameters were supplied. - - See Also - -------- - standard_normal : Similar, but takes a tuple as its argument. + out : ndarray or scalar + Drawn samples from the parameterized Wald distribution. Notes ----- - For random samples from :math:`N(\\mu, \\sigma^2)`, use: + The probability density function for the Wald distribution is - ``sigma * randomgen.generator.randn(...) + mu`` + .. math:: P(x;mean,scale) = \\sqrt{\\frac{scale}{2\\pi x^3}}e^ + \\frac{-scale(x-mean)^2}{2\\cdotp mean^2x} + + As noted above the inverse Gaussian distribution first arise + from attempts to model Brownian motion. It is also a + competitor to the Weibull for use in reliability modeling and + modeling stock returns and interest rate processes. + + References + ---------- + .. [1] Brighton Webs Ltd., Wald Distribution, + https://web.archive.org/web/20090423014010/http://www.brighton-webs.co.uk:80/distributions/wald.asp + .. [2] Chhikara, Raj S., and Folks, J. Leroy, "The Inverse Gaussian + Distribution: Theory : Methodology, and Applications", CRC Press, + 1988. + .. [3] Wikipedia, "Wald distribution" + https://en.wikipedia.org/wiki/Wald_distribution Examples -------- - >>> randomgen.generator.randn() - 2.1923875335537315 #random - - Two-by-four array of samples from N(3, 6.25): + Draw values from the distribution and plot the histogram: - >>> 2.5 * randomgen.generator.randn(2, 4) + 3 - array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random - [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(randomgen.generator.wald(3, 2, 100000), bins=200, density=True) + >>> plt.show() """ - if len(args) == 0: - return self.standard_normal() - else: - return self.standard_normal(size=args) + return cont(&legacy_wald, self._aug_state, size, self.lock, 2, + mean, 'mean', CONS_POSITIVE, + scale, 'scale', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + def negative_binomial(self, n, p, size=None): """ @@ -1492,156 +1675,14 @@ cdef class _LegacyGenerator: >>> s = randomgen.generator.negative_binomial(1, 0.9, 100000) >>> for i in range(1, 11): # doctest: +SKIP - ... probability = sum(s0` and - :math:`\\sum_{i=1}^k x_i = 1`. - - The probability density function :math:`p` of a - Dirichlet-distributed random vector :math:`X` is - proportional to - - .. math:: p(x) \\propto \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i}, - - where :math:`\\alpha` is a vector containing the positive - concentration parameters. - - The method uses the following property for computation: let :math:`Y` - be a random vector which has components that follow a standard gamma - distribution, then :math:`X = \\frac{1}{\\sum_{i=1}^k{Y_i}} Y` - is Dirichlet-distributed - - References - ---------- - .. [1] David McKay, "Information Theory, Inference and Learning - Algorithms," chapter 23, - http://www.inference.org.uk/mackay/itila/ - .. [2] Wikipedia, "Dirichlet distribution", - https://en.wikipedia.org/wiki/Dirichlet_distribution - - Examples - -------- - Taking an example cited in Wikipedia, this distribution can be used if - one wanted to cut strings (each of initial length 1.0) into K pieces - with different lengths, where each piece had, on average, a designated - average length, but allowing some variation in the relative sizes of - the pieces. - - >>> s = randomgen.generator.dirichlet((10, 5, 3), 20).transpose() - - >>> import matplotlib.pyplot as plt - >>> plt.barh(range(20), s[0]) - >>> plt.barh(range(20), s[1], left=s[0], color='g') - >>> plt.barh(range(20), s[2], left=s[0]+s[1], color='r') - >>> plt.title("Lengths of Strings") - - """ - - #================= - # Pure python algo - #================= - #alpha = N.atleast_1d(alpha) - #k = alpha.size - - #if n == 1: - # val = N.zeros(k) - # for i in range(k): - # val[i] = sgamma(alpha[i], n) - # val /= N.sum(val) - #else: - # val = N.zeros((k, n)) - # for i in range(k): - # val[i] = sgamma(alpha[i], n) - # val /= N.sum(val, axis = 0) - # val = val.T - - #return val - - cdef np.npy_intp k - cdef np.npy_intp totsize - cdef np.ndarray alpha_arr, val_arr - cdef double *alpha_data - cdef double *val_data - cdef np.npy_intp i, j - cdef double acc, invacc - - k = len(alpha) - alpha_arr = np.PyArray_FROM_OTF(alpha, np.NPY_DOUBLE, np.NPY_ALIGNED) - if np.any(np.less_equal(alpha_arr, 0)): - raise ValueError('alpha <= 0') - alpha_data = np.PyArray_DATA(alpha_arr) - - if size is None: - shape = (k,) - else: - try: - shape = (operator.index(size), k) - except: - shape = tuple(size) + (k,) - - diric = np.zeros(shape, np.float64) - val_arr = diric - val_data= np.PyArray_DATA(val_arr) - - i = 0 - totsize = np.PyArray_SIZE(val_arr) - with self.lock, nogil: - while i < totsize: - acc = 0.0 - for j in range(k): - val_data[i+j] = legacy_standard_gamma(self._aug_state, - alpha_data[j]) - acc = acc + val_data[i + j] - invacc = 1/acc - for j in range(k): - val_data[i + j] = val_data[i + j] * invacc - i = i + k - - return diric + ... probability = sum(s>> n = randomgen.generator.standard_exponential((3, 8000)) - """ - return cont(&legacy_standard_exponential, self._aug_state, size, self.lock, 0, - None, None, CONS_NONE, - None, None, CONS_NONE, - None, None, CONS_NONE, - None) - - def exponential(self, scale=1.0, size=None): - """ - exponential(scale=1.0, size=None) - - Draw samples from an exponential distribution. - - Its probability density function is - - .. math:: f(x; \\frac{1}{\\beta}) = \\frac{1}{\\beta} \\exp(-\\frac{x}{\\beta}), - - for ``x > 0`` and 0 elsewhere. :math:`\\beta` is the scale parameter, - which is the inverse of the rate parameter :math:`\\lambda = 1/\\beta`. - The rate parameter is an alternative, widely used parameterization - of the exponential distribution [3]_. - - The exponential distribution is a continuous analogue of the - geometric distribution. It describes many common situations, such as - the size of raindrops measured over many rainstorms [1]_, or the time - between page requests to Wikipedia [2]_. - - Parameters - ---------- - scale : float or array_like of floats - The scale parameter, :math:`\\beta = 1/\\lambda`. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``scale`` is a scalar. Otherwise, - ``np.array(scale).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized exponential distribution. - - References - ---------- - .. [1] Peyton Z. Peebles Jr., "Probability, Random Variables and - Random Signal Principles", 4th ed, 2001, p. 57. - .. [2] Wikipedia, "Poisson process", - https://en.wikipedia.org/wiki/Poisson_process - .. [3] Wikipedia, "Exponential distribution", - https://en.wikipedia.org/wiki/Exponential_distribution - - """ - return cont(&legacy_exponential, self._aug_state, size, self.lock, 1, - scale, 'scale', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, - None) - - def power(self, a, size=None): - """ - power(a, size=None) - - Draws samples in [0, 1] from a power distribution with positive - exponent a - 1. - - Also known as the power function distribution. - - Parameters - ---------- - a : float or array_like of floats - Parameter of the distribution. Should be greater than zero. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``a`` is a scalar. Otherwise, - ``np.array(a).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized power distribution. + samples : ndarray, + The drawn samples, of shape (size, alpha.ndim). Raises - ------ + ------- ValueError - If a < 1. + If any value in alpha is less than or equal to zero Notes ----- - The probability density function is + The Dirichlet distribution is a distribution over vectors + :math:`x` that fulfil the conditions :math:`x_i>0` and + :math:`\\sum_{i=1}^k x_i = 1`. - .. math:: P(x; a) = ax^{a-1}, 0 \\le x \\le 1, a>0. + The probability density function :math:`p` of a + Dirichlet-distributed random vector :math:`X` is + proportional to - The power function distribution is just the inverse of the Pareto - distribution. It may also be seen as a special case of the Beta - distribution. + .. math:: p(x) \\propto \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i}, - It is used, for example, in modeling the over-reporting of insurance - claims. + where :math:`\\alpha` is a vector containing the positive + concentration parameters. + + The method uses the following property for computation: let :math:`Y` + be a random vector which has components that follow a standard gamma + distribution, then :math:`X = \\frac{1}{\\sum_{i=1}^k{Y_i}} Y` + is Dirichlet-distributed References ---------- - .. [1] Christian Kleiber, Samuel Kotz, "Statistical size distributions - in economics and actuarial sciences", Wiley, 2003. - .. [2] Heckert, N. A. and Filliben, James J. "NIST Handbook 148: - Dataplot Reference Manual, Volume 2: Let Subcommands and Library - Functions", National Institute of Standards and Technology - Handbook Series, June 2003. - http://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf + .. [1] David McKay, "Information Theory, Inference and Learning + Algorithms," chapter 23, + http://www.inference.org.uk/mackay/itila/ + .. [2] Wikipedia, "Dirichlet distribution", + https://en.wikipedia.org/wiki/Dirichlet_distribution Examples -------- - Draw samples from the distribution: - - >>> a = 5. # shape - >>> samples = 1000 - >>> s = randomgen.generator.power(a, samples) + Taking an example cited in Wikipedia, this distribution can be used if + one wanted to cut strings (each of initial length 1.0) into K pieces + with different lengths, where each piece had, on average, a designated + average length, but allowing some variation in the relative sizes of + the pieces. - Display the histogram of the samples, along with - the probability density function: + >>> s = randomgen.generator.dirichlet((10, 5, 3), 20).transpose() >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, bins=30) - >>> x = np.linspace(0, 1, 100) - >>> y = a*x**(a-1.) - >>> normed_y = samples*np.diff(bins)[0]*y - >>> plt.plot(x, normed_y) - >>> plt.show() + >>> plt.barh(range(20), s[0]) + >>> plt.barh(range(20), s[1], left=s[0], color='g') + >>> plt.barh(range(20), s[2], left=s[0]+s[1], color='r') + >>> plt.title("Lengths of Strings") - Compare the power function distribution to the inverse of the Pareto. + """ - >>> from scipy import stats - >>> rvs = randomgen.generator.power(5, 1000000) - >>> rvsp = randomgen.generator.pareto(5, 1000000) - >>> xx = np.linspace(0,1,100) - >>> powpdf = stats.powerlaw.pdf(xx,5) + #================= + # Pure python algo + #================= + #alpha = N.atleast_1d(alpha) + #k = alpha.size - >>> plt.figure() - >>> plt.hist(rvs, bins=50, density=True) - >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('randomgen.generator.power(5)') + #if n == 1: + # val = N.zeros(k) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val) + #else: + # val = N.zeros((k, n)) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val, axis = 0) + # val = val.T - >>> plt.figure() - >>> plt.hist(1./(1.+rvsp), bins=50, density=True) - >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('inverse of 1 + randomgen.generator.pareto(5)') + #return val - >>> plt.figure() - >>> plt.hist(1./(1.+rvsp), bins=50, density=True) - >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('inverse of stats.pareto(5)') + cdef np.npy_intp k + cdef np.npy_intp totsize + cdef np.ndarray alpha_arr, val_arr + cdef double *alpha_data + cdef double *val_data + cdef np.npy_intp i, j + cdef double acc, invacc - """ - return cont(&legacy_power, self._aug_state, size, self.lock, 1, - a, 'a', CONS_POSITIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, None) + k = len(alpha) + alpha_arr = np.PyArray_FROM_OTF(alpha, np.NPY_DOUBLE, np.NPY_ALIGNED) + if np.any(np.less_equal(alpha_arr, 0)): + raise ValueError('alpha <= 0') + alpha_data = np.PyArray_DATA(alpha_arr) + + if size is None: + shape = (k,) + else: + try: + shape = (operator.index(size), k) + except: + shape = tuple(size) + (k,) + + diric = np.zeros(shape, np.float64) + val_arr = diric + val_data= np.PyArray_DATA(val_arr) + + i = 0 + totsize = np.PyArray_SIZE(val_arr) + with self.lock, nogil: + while i < totsize: + acc = 0.0 + for j in range(k): + val_data[i+j] = legacy_standard_gamma(self._aug_state, + alpha_data[j]) + acc = acc + val_data[i + j] + invacc = 1/acc + for j in range(k): + val_data[i + j] = val_data[i + j] * invacc + i = i + k + + return diric From 5785ca7bef5c0a44042f34c496bceeb79161cd8a Mon Sep 17 00:00:00 2001 From: Christopher Whelan Date: Mon, 25 Feb 2019 23:13:38 -0800 Subject: [PATCH 189/279] ENH: Create boolean and integer ufuncs for isnan, isinf, and isfinite. Previously, boolean values would be routed through the half implementations of these functions, which added considerable overhead. Creating specialized ufuncs improves performance by ~250x Additionally, enable autovectorization of new isnan, isinf, and isfinite ufuncs. --- doc/release/1.17.0-notes.rst | 6 +++++ numpy/core/code_generators/generate_umath.py | 6 ++--- numpy/core/src/umath/fast_loop_macros.h | 25 ++++++++++++++++++++ numpy/core/src/umath/loops.c.src | 25 ++++++++++++++++++++ numpy/core/src/umath/loops.h.src | 14 +++++++++++ numpy/core/tests/test_ufunc.py | 21 ++++++++++++++++ 6 files changed, 94 insertions(+), 3 deletions(-) diff --git a/doc/release/1.17.0-notes.rst b/doc/release/1.17.0-notes.rst index cd547c2b4e7e..3dcdf6660fef 100644 --- a/doc/release/1.17.0-notes.rst +++ b/doc/release/1.17.0-notes.rst @@ -163,6 +163,12 @@ thereby saving a level of indentation In some cases where ``np.interp`` would previously return ``np.nan``, it now returns an appropriate infinity. +Specialized ``np.isnan``, ``np.isinf``, and ``np.isfinite`` ufuncs for bool and int types +----------------------------------------------------------------------------------------- +The boolean and integer types are incapable of storing ``np.nan`` and ``np.inf`` values, +which allows us to provide specialized ufuncs that are up to 250x faster than the current +approach. + Changes ======= diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py index 687a8467b0d7..de0bb81fe9bb 100644 --- a/numpy/core/code_generators/generate_umath.py +++ b/numpy/core/code_generators/generate_umath.py @@ -827,7 +827,7 @@ def english_upper(s): Ufunc(1, 1, None, docstrings.get('numpy.core.umath.isnan'), None, - TD(inexact, out='?'), + TD(nodatetime_or_obj, out='?'), ), 'isnat': Ufunc(1, 1, None, @@ -839,13 +839,13 @@ def english_upper(s): Ufunc(1, 1, None, docstrings.get('numpy.core.umath.isinf'), None, - TD(inexact, out='?'), + TD(nodatetime_or_obj, out='?'), ), 'isfinite': Ufunc(1, 1, None, docstrings.get('numpy.core.umath.isfinite'), None, - TD(inexact, out='?'), + TD(nodatetime_or_obj, out='?'), ), 'signbit': Ufunc(1, 1, None, diff --git a/numpy/core/src/umath/fast_loop_macros.h b/numpy/core/src/umath/fast_loop_macros.h index 37656dcf5ab4..e3cfa1f726d0 100644 --- a/numpy/core/src/umath/fast_loop_macros.h +++ b/numpy/core/src/umath/fast_loop_macros.h @@ -64,6 +64,8 @@ #define IS_UNARY_CONT(tin, tout) (steps[0] == sizeof(tin) && \ steps[1] == sizeof(tout)) +#define IS_OUTPUT_CONT(tout) (steps[1] == sizeof(tout)) + #define IS_BINARY_REDUCE ((args[0] == args[2])\ && (steps[0] == steps[2])\ && (steps[0] == 0)) @@ -82,6 +84,29 @@ steps[2] == sizeof(tout)) +/* + * loop with contiguous specialization + * op should be the code storing the result in `tout * out` + * combine with NPY_GCC_OPT_3 to allow autovectorization + * should only be used where its worthwhile to avoid code bloat + */ +#define BASE_OUTPUT_LOOP(tout, op) \ + OUTPUT_LOOP { \ + tout * out = (tout *)op1; \ + op; \ + } +#define OUTPUT_LOOP_FAST(tout, op) \ + do { \ + /* condition allows compiler to optimize the generic macro */ \ + if (IS_OUTPUT_CONT(tout)) { \ + BASE_OUTPUT_LOOP(tout, op) \ + } \ + else { \ + BASE_OUTPUT_LOOP(tout, op) \ + } \ + } \ + while (0) + /* * loop with contiguous specialization * op should be the code working on `tin in` and diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index 04e6cbdeee3a..1e4ab350bec9 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -644,6 +644,19 @@ BOOL__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UN } +/**begin repeat + * #kind = isnan, isinf, isfinite# + * #func = npy_isnan, npy_isinf, npy_isfinite# + * #val = NPY_FALSE, NPY_FALSE, NPY_TRUE# + **/ +NPY_NO_EXPORT void +BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + OUTPUT_LOOP_FAST(npy_bool, *out = @val@); +} + +/**end repeat**/ + /* ***************************************************************************** ** INTEGER LOOPS @@ -875,6 +888,18 @@ NPY_NO_EXPORT void } } +/**begin repeat1 + * #kind = isnan, isinf, isfinite# + * #func = npy_isnan, npy_isinf, npy_isfinite# + * #val = NPY_FALSE, NPY_FALSE, NPY_TRUE# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + OUTPUT_LOOP_FAST(npy_bool, *out = @val@); +} +/**end repeat1**/ + /**end repeat**/ /**begin repeat diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src index 5264a6533ee8..f48319056c26 100644 --- a/numpy/core/src/umath/loops.h.src +++ b/numpy/core/src/umath/loops.h.src @@ -38,6 +38,13 @@ BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED NPY_NO_EXPORT void BOOL__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); +/**begin repeat + * #kind = isnan, isinf, isfinite# + **/ +NPY_NO_EXPORT void +BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat**/ + /* ***************************************************************************** ** INTEGER LOOPS @@ -146,6 +153,13 @@ NPY_NO_EXPORT void NPY_NO_EXPORT void @S@@TYPE@_lcm(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**begin repeat2 + * #kind = isnan, isinf, isfinite# + **/ +NPY_NO_EXPORT void +@S@@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat2**/ + /**end repeat1**/ /**end repeat**/ diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index 478a083974fe..b6b68d922c46 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -1915,3 +1915,24 @@ def test_invalid_args(self): exc = pytest.raises(TypeError, np.sqrt, None) # minimally check the exception text assert 'loop of ufunc does not support' in str(exc) + + @pytest.mark.parametrize('nat', [np.datetime64('nat'), np.timedelta64('nat')]) + def test_nat_is_not_finite(self, nat): + try: + assert not np.isfinite(nat) + except TypeError: + pass # ok, just not implemented + + @pytest.mark.parametrize('nat', [np.datetime64('nat'), np.timedelta64('nat')]) + def test_nat_is_nan(self, nat): + try: + assert np.isnan(nat) + except TypeError: + pass # ok, just not implemented + + @pytest.mark.parametrize('nat', [np.datetime64('nat'), np.timedelta64('nat')]) + def test_nat_is_not_inf(self, nat): + try: + assert not np.isinf(nat) + except TypeError: + pass # ok, just not implemented From 175df241cad1a04da33dde8b45077c085c415e48 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 15 Mar 2019 14:40:46 +0000 Subject: [PATCH 190/279] DOC: UPdate docs to reflect upstream changes Update doc strings and some minor parameter checks to reflect upstream changes. --- _randomgen/doc/source/change-log.rst | 5 + _randomgen/randomgen/generator.pyx | 116 ++++++++++++------ .../randomgen/tests/test_numpy_mt19937.py | 4 + 3 files changed, 90 insertions(+), 35 deletions(-) diff --git a/_randomgen/doc/source/change-log.rst b/_randomgen/doc/source/change-log.rst index 5be2ea8dd60f..f791c8f5418e 100644 --- a/_randomgen/doc/source/change-log.rst +++ b/_randomgen/doc/source/change-log.rst @@ -1,5 +1,10 @@ Change Log ---------- +v1.16.1 +======= +- Synchronized with upstream changes. +- Fixed a bug in gamma generation if the shape parameters is 0.0. + v1.16.0 ======= - Fixed a bug that affected :class:`~randomgen.dsfmt.DSFMT` when calling diff --git a/_randomgen/randomgen/generator.pyx b/_randomgen/randomgen/generator.pyx index 5b711dd933f3..6a68a1905b5c 100644 --- a/_randomgen/randomgen/generator.pyx +++ b/_randomgen/randomgen/generator.pyx @@ -429,7 +429,8 @@ cdef class RandomGenerator: Parameters ---------- scale : float or array_like of floats - The scale parameter, :math:`\\beta = 1/\\lambda`. + The scale parameter, :math:`\\beta = 1/\\lambda`. Must be + non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -855,6 +856,8 @@ cdef class RandomGenerator: if size > pop_size: raise ValueError("Cannot take a larger sample than " "population when 'replace=False'") + elif size < 0: + raise ValueError("negative dimensions are not allowed") if p is not None: if np.count_nonzero(p > 0) < size: @@ -1017,6 +1020,12 @@ cdef class RandomGenerator: Random values in a given shape. + .. note:: + This is a convenience function for users porting code from Matlab, + and wraps `numpy.random.random_sample`. That function takes a + tuple to specify the size of the output, which is consistent with + other NumPy functions like `numpy.zeros` and `numpy.ones`. + Create an array of the given shape and populate it with random samples from a uniform distribution over ``[0, 1)``. @@ -1065,16 +1074,20 @@ cdef class RandomGenerator: Return a sample (or samples) from the "standard normal" distribution. - If positive, int_like or int-convertible arguments are provided, - `randn` generates an array of shape ``(d0, d1, ..., dn)``, filled + .. note:: + This is a convenience function for users porting code from Matlab, + and wraps `numpy.random.standard_normal`. That function takes a + tuple to specify the size of the output, which is consistent with + other NumPy functions like `numpy.zeros` and `numpy.ones`. + + If positive int_like arguments are provided, `randn` generates an array + of shape ``(d0, d1, ..., dn)``, filled with random floats sampled from a univariate "normal" (Gaussian) - distribution of mean 0 and variance 1 (if any of the :math:`d_i` are - floats, they are first converted to integers by truncation). A single - float randomly sampled from the distribution is returned if no - argument is provided. + distribution of mean 0 and variance 1. A single float randomly sampled + from the distribution is returned if no argument is provided. This is a convenience function. If you want an interface that takes a - tuple as the first argument, use `standard_normal` instead. + tuple as the first argument, use `numpy.random.standard_normal` instead. Parameters ---------- @@ -1096,6 +1109,7 @@ cdef class RandomGenerator: See Also -------- standard_normal : Similar, but takes a tuple as its argument. + normal : Also accepts mu and sigma arguments Notes ----- @@ -1106,13 +1120,13 @@ cdef class RandomGenerator: Examples -------- >>> randomgen.generator.randn() - 2.1923875335537315 #random + 2.1923875335537315 # random Two-by-four array of samples from N(3, 6.25): - >>> 2.5 * randomgen.generator.randn(2, 4) + 3 - array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random - [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random + >>> 3 + 2.5 * np.random.randn(2, 4) + array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], # random + [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) # random """ if len(args) == 0: @@ -1237,20 +1251,43 @@ cdef class RandomGenerator: Returns ------- out : float or ndarray - Drawn samples. + A floating-point array of shape ``size`` of drawn samples, or a + single sample if ``size`` was not specified. + + Notes + ----- + For random samples from :math:`N(\\mu, \\sigma^2)`, use one of:: + + mu + sigma * np.random.standard_normal(size=...) + np.random.normal(mu, sigma, size=...) + + See Also + -------- + normal : + Equivalent function with additional ``loc`` and ``scale`` arguments + for setting the mean and standard deviation. Examples -------- - >>> s = randomgen.generator.standard_normal(8000) + >>> np.random.standard_normal() + 2.1923875335537315 #random + + >>> s = np.random.standard_normal(8000) >>> s - array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random - -0.38672696, -0.4685006 ]) #random + array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, # random + -0.38672696, -0.4685006 ]) # random >>> s.shape (8000,) - >>> s = randomgen.generator.standard_normal(size=(3, 4, 2)) + >>> s = np.random.standard_normal(size=(3, 4, 2)) >>> s.shape (3, 4, 2) + Two-by-four array of samples from :math:`N(3, 6.25)`: + + >>> 3 + 2.5 * np.random.standard_normal(size=(2, 4)) + array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], # random + [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) # random + """ key = np.dtype(dtype).name if key == 'float64': @@ -1283,7 +1320,8 @@ cdef class RandomGenerator: loc : float or array_like of floats Mean ("centre") of the distribution. scale : float or array_like of floats - Standard deviation (spread or "width") of the distribution. + Standard deviation (spread or "width") of the distribution. Must be + non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1334,11 +1372,11 @@ cdef class RandomGenerator: Verify the mean and the variance: - >>> abs(mu - np.mean(s)) < 0.01 - True + >>> abs(mu - np.mean(s)) + 0.0 # may vary - >>> abs(sigma - np.std(s, ddof=1)) < 0.01 - True + >>> abs(sigma - np.std(s, ddof=1)) + 0.1 # may vary Display the histogram of the samples, along with the probability density function: @@ -1350,6 +1388,12 @@ cdef class RandomGenerator: ... linewidth=2, color='r') >>> plt.show() + Two-by-four array of samples from N(3, 6.25): + + >>> np.random.normal(3, 2.5, size=(2, 4)) + array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], # random + [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) # random + """ return cont(&random_normal_zig, self._brng, size, self.lock, 2, loc, '', CONS_NONE, @@ -1530,7 +1574,7 @@ cdef class RandomGenerator: Parameters ---------- shape : float or array_like of floats - Parameter, should be > 0. + Parameter, must be non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1622,9 +1666,9 @@ cdef class RandomGenerator: Parameters ---------- shape : float or array_like of floats - The shape of the gamma distribution. Should be greater than zero. + The shape of the gamma distribution. Must be non-negative. scale : float or array_like of floats, optional - The scale of the gamma distribution. Should be greater than zero. + The scale of the gamma distribution. Must be non-negative. Default is equal to 1. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then @@ -1706,9 +1750,9 @@ cdef class RandomGenerator: Parameters ---------- dfnum : int or array_like of ints - Degrees of freedom in numerator. Should be greater than zero. + Degrees of freedom in numerator. Must be non-negative. dfden : int or array_like of ints - Degrees of freedom in denominator. Should be greater than zero. + Degrees of freedom in denominator. Must be non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2262,7 +2306,7 @@ cdef class RandomGenerator: Parameters ---------- a : float or array_like of floats - Shape of the distribution. Should be greater than zero. + Shape of the distribution. All values must be positive. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2443,7 +2487,7 @@ cdef class RandomGenerator: Parameters ---------- a : float or array_like of floats - Parameter of the distribution. Should be greater than zero. + Parameter of the distribution. Must be positive. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2548,7 +2592,8 @@ cdef class RandomGenerator: loc : float or array_like of floats, optional The position, :math:`\\mu`, of the distribution peak. Default is 0. scale : float or array_like of floats, optional - :math:`\\lambda`, the exponential decay. Default is 1. + :math:`\\lambda`, the exponential decay. Default is 1. Must be + non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2630,7 +2675,8 @@ cdef class RandomGenerator: loc : float or array_like of floats, optional The location of the mode of the distribution. Default is 0. scale : float or array_like of floats, optional - The scale parameter of the distribution. Default is 1. + The scale parameter of the distribution. Default is 1. Must be + non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2828,8 +2874,8 @@ cdef class RandomGenerator: mean : float or array_like of floats, optional Mean value of the underlying normal distribution. Default is 0. sigma : float or array_like of floats, optional - Standard deviation of the underlying normal distribution. Should - be greater than zero. Default is 1. + Standard deviation of the underlying normal distribution. Must be + non-negative. Default is 1. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2934,7 +2980,7 @@ cdef class RandomGenerator: Parameters ---------- scale : float or array_like of floats, optional - Scale, also equals the mode. Should be >= 0. Default is 1. + Scale, also equals the mode. Must be non-negative. Default is 1. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -3463,7 +3509,7 @@ cdef class RandomGenerator: Parameters ---------- a : float or array_like of floats - Distribution parameter. Should be greater than 1. + Distribution parameter. Must be greater than 1. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/_randomgen/randomgen/tests/test_numpy_mt19937.py index 0a6548c7cbe2..a19693d815c7 100644 --- a/_randomgen/randomgen/tests/test_numpy_mt19937.py +++ b/_randomgen/randomgen/tests/test_numpy_mt19937.py @@ -558,6 +558,10 @@ def test_choice_exceptions(self): assert_raises(ValueError, sample, [1, 2], 3, p=[1.1, -0.1]) assert_raises(ValueError, sample, [1, 2], 3, p=[0.4, 0.4]) assert_raises(ValueError, sample, [1, 2, 3], 4, replace=False) + # gh-13087 + assert_raises(ValueError, sample, [1, 2, 3], -2, replace=False) + assert_raises(ValueError, sample, [1, 2, 3], (-1,), replace=False) + assert_raises(ValueError, sample, [1, 2, 3], (-1, 1), replace=False) assert_raises(ValueError, sample, [1, 2, 3], 2, replace=False, p=[1, 0, 0]) From b296b2950d2d72564d24e3191244e6a47d9fe846 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 15 Mar 2019 22:11:43 +0000 Subject: [PATCH 191/279] DOC: Update README Update README with Python 2.7 information and NumPy versions supported --- _randomgen/README.md | 6 +++--- _randomgen/README.rst | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index 53b58b5b2fd5..45c33b928924 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -12,8 +12,8 @@ generators in Python and NumPy. ## Python 2.7 Support -Release 1.16.0 is the final version that supports Python 2.7. Any bugs -in v1.16.0 will be patched until the end of 2019. All future releases +v1.16 is the final major version that supports Python 2.7. Any bugs +in v1.16 will be patched until the end of 2019. All future releases are Python 3, with an initial minimum version of 3.5. ## Compatibility Warning @@ -164,7 +164,7 @@ need to be smoothed. Building requires: * Python (2.7, 3.5, 3.6, 3.7) -* NumPy (1.13, 1.14, 1.15) +* NumPy (1.13, 1.14, 1.15, 1.16) * Cython (0.26+) * tempita (0.5+), if not provided by Cython diff --git a/_randomgen/README.rst b/_randomgen/README.rst index cfd447f387bb..f4b886e5f74b 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -12,9 +12,9 @@ generators in Python and NumPy. Python 2.7 Support ------------------ -Release 1.16.0 is the final version that supports Python 2.7. Any bugs -in v1.16.0 will be patched until the end of 2019. All future releases -are Python 3, with an initial minimum version of 3.5. +v1.16 is the final major version that supports Python 2.7. Any bugs in +v1.16 will be patched until the end of 2019. All future releases are +Python 3, with an initial minimum version of 3.5. Compatibility Warning --------------------- @@ -181,7 +181,7 @@ Requirements Building requires: - Python (2.7, 3.5, 3.6, 3.7) -- NumPy (1.13, 1.14, 1.15) +- NumPy (1.13, 1.14, 1.15, 1.16) - Cython (0.26+) - tempita (0.5+), if not provided by Cython From b4256bd619847436c78c85b0ebae651fc25a37cf Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 20 Mar 2019 11:52:21 +0200 Subject: [PATCH 192/279] add README-git.md --- _randomgen/README-git.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 _randomgen/README-git.md diff --git a/_randomgen/README-git.md b/_randomgen/README-git.md new file mode 100644 index 000000000000..24d10a8e8e9f --- /dev/null +++ b/_randomgen/README-git.md @@ -0,0 +1,22 @@ +These are the bash commands used to get the bashtage/randomgen repo into numpy/numpy + +```bash +# from a directory just above a numpy git checkout +git clone https://github.com/bashtage/randomgen.git +cd randomgen +# rewrite the checkout, pushing the content into '_randomgen' +git filter-branch --index-filter ' + git ls-files -s | + sed "s-\t-\t_randomgen/-" | + GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && + mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE +' HEAD +# write this file, commit it +git add _randomgen/README-git.md +git commit -m"Add README-git.md" +git checkout -b randomgen +cd ../numpy +git remote add randomgen ../randomgen +git merge --allow-unrelated-histories randomgen/randomgen +git remote remove randomgen +``` From f31006a76d202e6bca4168547dff6efe5488f85e Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 20 Mar 2019 12:08:27 +0200 Subject: [PATCH 193/279] DOC: fixup actual commands used --- _randomgen/README-git.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/_randomgen/README-git.md b/_randomgen/README-git.md index 24d10a8e8e9f..c771693902b6 100644 --- a/_randomgen/README-git.md +++ b/_randomgen/README-git.md @@ -16,7 +16,11 @@ git add _randomgen/README-git.md git commit -m"Add README-git.md" git checkout -b randomgen cd ../numpy +git checkout -b randomgen git remote add randomgen ../randomgen +git fetch randomgen randomgen git merge --allow-unrelated-histories randomgen/randomgen git remote remove randomgen +# Now all the randomgen commits are on the randomgen branch in numpy, +# and there is a subdirectory _randomgen with the content ``` From 4437112b11998f4cf30541bdf4c8dd954557b5ed Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 20 Mar 2019 12:39:53 +0200 Subject: [PATCH 194/279] BUILD: move files out of _randomgen --- _randomgen/MANIFEST.in | 10 - _randomgen/appveyor.yml | 33 - _randomgen/ci/conda-install.sh | 20 - _randomgen/ci/pypi-install.sh | 3 - _randomgen/doc/Makefile | 20 - _randomgen/doc/make.bat | 36 - .../github_deploy_key_bashtage_randomgen.enc | 1 - _randomgen/requirements.txt | 4 - _randomgen/setup.cfg | 11 - _randomgen/versioneer.py | 1822 ----------------- ...tion in an Interval - arxiv 1805.10941.pdf | Bin .../source}/papers/random123sc11.pdf | Bin .../source/random}/brng/dsfmt.rst | 0 .../source/random}/brng/index.rst | 0 .../source/random}/brng/mt19937.rst | 0 .../source/random}/brng/pcg32.rst | 0 .../source/random}/brng/pcg64.rst | 0 .../source/random}/brng/philox.rst | 0 .../source/random}/brng/threefry.rst | 0 .../source/random}/brng/threefry32.rst | 0 .../source/random}/brng/xoroshiro128.rst | 0 .../source/random}/brng/xorshift1024.rst | 0 .../random}/brng/xoshiro256starstar.rst | 0 .../random}/brng/xoshiro512starstar.rst | 0 .../source/random}/change-log.rst | 0 .../doc/source => doc/source/random}/conf.py | 0 .../source => doc/source/random}/entropy.rst | 0 .../source/random}/extending.rst | 0 .../source/random}/generator.rst | 0 .../source => doc/source/random}/index.rst | 0 .../source => doc/source/random}/legacy.rst | 0 .../source/random}/multithreading.rst | 0 .../source/random}/new-or-different.rst | 0 .../source => doc/source/random}/parallel.rst | 0 .../source/random}/performance.py | 0 .../source/random}/performance.rst | 0 .../source/random}/references.rst | 0 .../random/randomgen}/LICENSE.md | 0 .../random}/randomgen/__init__.py | 0 .../random}/randomgen/_testing.py | 0 .../random}/randomgen/_version.py | 0 .../random}/randomgen/bounded_integers.pxd.in | 0 .../random}/randomgen/bounded_integers.pyx.in | 0 .../random}/randomgen/common.pxd | 0 .../random}/randomgen/common.pyx | 0 .../random}/randomgen/distributions.pxd | 0 .../random}/randomgen/dsfmt.pyx | 0 .../random}/randomgen/entropy.pyx | 0 .../randomgen/examples/cython/extending.pyx | 0 .../cython/extending_distributions.pyx | 0 .../randomgen/examples/cython/setup.py | 0 .../randomgen/examples/numba/extending.py | 0 .../examples/numba/extending_distributions.py | 0 .../random}/randomgen/generator.pyx | 0 .../random}/randomgen/legacy/__init__.py | 0 .../random}/randomgen/legacy/_legacy.pyx | 0 .../random}/randomgen/legacy/legacy.py | 0 .../randomgen/legacy/legacy_distributions.pxd | 0 .../random}/randomgen/mt19937.pyx | 0 .../random}/randomgen/pcg32.pyx | 0 .../random}/randomgen/pcg64.pyx | 0 .../random}/randomgen/philox.pyx | 0 .../random}/randomgen/pickle.py | 0 .../src/aligned_malloc/aligned_malloc.c | 0 .../src/aligned_malloc/aligned_malloc.h | 0 .../random}/randomgen/src/common/LICENSE.md | 0 .../random}/randomgen/src/common/inttypes.h | 0 .../random}/randomgen/src/common/stdint.h | 0 .../randomgen/src/distributions/LICENSE.md | 0 .../randomgen/src/distributions/binomial.h | 0 .../src/distributions/distributions.c | 0 .../src/distributions/distributions.h | 0 .../randomgen/src/distributions/ziggurat.h | 0 .../src/distributions/ziggurat_constants.h | 0 .../randomgen/src/dsfmt/128-bit-jump.poly.txt | 0 .../randomgen/src/dsfmt/96-bit-jump.poly.txt | 0 .../random}/randomgen/src/dsfmt/LICENSE.md | 0 .../random}/randomgen/src/dsfmt/calc-jump.cpp | 0 .../randomgen/src/dsfmt/dSFMT-benchmark.c | 0 .../randomgen/src/dsfmt/dSFMT-calc-jump.hpp | 0 .../randomgen/src/dsfmt/dSFMT-common.h | 0 .../random}/randomgen/src/dsfmt/dSFMT-jump.c | 0 .../random}/randomgen/src/dsfmt/dSFMT-jump.h | 0 .../randomgen/src/dsfmt/dSFMT-params.h | 0 .../randomgen/src/dsfmt/dSFMT-params19937.h | 0 .../random}/randomgen/src/dsfmt/dSFMT-poly.h | 0 .../randomgen/src/dsfmt/dSFMT-test-gen.c | 0 .../random}/randomgen/src/dsfmt/dSFMT.c | 0 .../random}/randomgen/src/dsfmt/dSFMT.h | 0 .../random}/randomgen/src/entropy/LICENSE.md | 0 .../random}/randomgen/src/entropy/entropy.c | 0 .../random}/randomgen/src/entropy/entropy.h | 0 .../random}/randomgen/src/legacy/LICENSE.md | 0 .../src/legacy/distributions-boxmuller.c | 0 .../src/legacy/distributions-boxmuller.h | 0 .../random}/randomgen/src/mt19937/LICENSE.md | 0 .../randomgen/src/mt19937/mt19937-benchmark.c | 0 .../randomgen/src/mt19937/mt19937-jump.c | 0 .../randomgen/src/mt19937/mt19937-jump.h | 0 .../randomgen/src/mt19937/mt19937-poly.h | 0 .../src/mt19937/mt19937-test-data-gen.c | 0 .../random}/randomgen/src/mt19937/mt19937.c | 0 .../random}/randomgen/src/mt19937/mt19937.h | 0 .../random}/randomgen/src/mt19937/randomkit.c | 0 .../random}/randomgen/src/mt19937/randomkit.h | 0 .../random}/randomgen/src/pcg32/LICENSE.md | 0 .../randomgen/src/pcg32/pcg-advance-64.c | 0 .../randomgen/src/pcg32/pcg32-test-data-gen.c | 0 .../random}/randomgen/src/pcg32/pcg32.c | 0 .../random}/randomgen/src/pcg32/pcg32.h | 0 .../randomgen/src/pcg32/pcg_variants.h | 0 .../random}/randomgen/src/pcg64/LICENSE.md | 0 .../randomgen/src/pcg64/pcg64-benchmark.c | 0 .../randomgen/src/pcg64/pcg64-test-data-gen.c | 0 .../random}/randomgen/src/pcg64/pcg64.c | 0 .../random}/randomgen/src/pcg64/pcg64.h | 0 .../random}/randomgen/src/pcg64/pcg64.orig.c | 0 .../random}/randomgen/src/pcg64/pcg64.orig.h | 0 .../random}/randomgen/src/philox/LICENSE.md | 0 .../randomgen/src/philox/philox-benchmark.c | 0 .../src/philox/philox-test-data-gen.c | 0 .../random}/randomgen/src/philox/philox.c | 0 .../random}/randomgen/src/philox/philox.h | 0 .../randomgen/src/splitmix64/LICENSE.md | 0 .../randomgen/src/splitmix64/splitmix64.c | 0 .../randomgen/src/splitmix64/splitmix64.h | 0 .../src/splitmix64/splitmix64.orig.c | 0 .../random}/randomgen/src/threefry/LICENSE.md | 0 .../src/threefry/threefry-benchmark.c | 0 .../randomgen/src/threefry/threefry-orig.c | 0 .../src/threefry/threefry-test-data-gen.c | 0 .../random}/randomgen/src/threefry/threefry.c | 0 .../random}/randomgen/src/threefry/threefry.h | 0 .../randomgen/src/threefry32/LICENSE.md | 0 .../src/threefry32/threefry32-test-data-gen.c | 0 .../randomgen/src/threefry32/threefry32.c | 0 .../randomgen/src/threefry32/threefry32.h | 0 .../randomgen/src/xoroshiro128/LICENSE.md | 0 .../src/xoroshiro128/xoroshiro128-benchmark.c | 0 .../xoroshiro128/xoroshiro128-test-data-gen.c | 0 .../randomgen/src/xoroshiro128/xoroshiro128.c | 0 .../randomgen/src/xoroshiro128/xoroshiro128.h | 0 .../src/xoroshiro128/xoroshiro128plus.orig.c | 0 .../src/xoroshiro128/xoroshiro128plus.orig.h | 0 .../randomgen/src/xorshift1024/LICENSE.md | 0 .../src/xorshift1024/xorshift1024-benchmark.c | 0 .../xorshift1024/xorshift1024-test-data-gen.c | 0 .../randomgen/src/xorshift1024/xorshift1024.c | 0 .../randomgen/src/xorshift1024/xorshift1024.h | 0 .../src/xorshift1024/xorshift1024.orig.c | 0 .../src/xorshift1024/xorshift1024.orig.h | 0 .../src/xoshiro256starstar/LICENSE.md | 0 .../xoshiro256starstar-test-data-gen.c | 0 .../xoshiro256starstar/xoshiro256starstar.c | 0 .../xoshiro256starstar/xoshiro256starstar.h | 0 .../xoshiro256starstar.orig.c | 0 .../xoshiro256starstar.orig.h | 0 .../src/xoshiro512starstar/LICENSE.md | 0 .../xoshiro512starstar-test-data-gen.c | 0 .../xoshiro512starstar/xoshiro512starstar.c | 0 .../xoshiro512starstar/xoshiro512starstar.h | 0 .../xoshiro512starstar.orig.c | 0 .../xoshiro512starstar.orig.h | 0 .../random}/randomgen/tests/__init__.py | 0 .../random}/randomgen/tests/data/__init__.py | 0 .../randomgen/tests/data/dSFMT-testset-1.csv | 0 .../randomgen/tests/data/dSFMT-testset-2.csv | 0 .../tests/data/mt19937-testset-1.csv | 0 .../tests/data/mt19937-testset-2.csv | 0 .../randomgen/tests/data/pcg32-testset-1.csv | 0 .../randomgen/tests/data/pcg32-testset-2.csv | 0 .../randomgen/tests/data/pcg64-testset-1.csv | 0 .../randomgen/tests/data/pcg64-testset-2.csv | 0 .../randomgen/tests/data/philox-testset-1.csv | 0 .../randomgen/tests/data/philox-testset-2.csv | 0 .../tests/data/threefry-testset-1.csv | 0 .../tests/data/threefry-testset-2.csv | 0 .../tests/data/threefry32-testset-1.csv | 0 .../tests/data/threefry32-testset-2.csv | 0 .../tests/data/xoroshiro128-testset-1.csv | 0 .../tests/data/xoroshiro128-testset-2.csv | 0 .../tests/data/xorshift1024-testset-1.csv | 0 .../tests/data/xorshift1024-testset-2.csv | 0 .../data/xoshiro256starstar-testset-1.csv | 0 .../data/xoshiro256starstar-testset-2.csv | 0 .../data/xoshiro512starstar-testset-1.csv | 0 .../data/xoshiro512starstar-testset-2.csv | 0 .../randomgen/tests/test_against_numpy.py | 0 .../random}/randomgen/tests/test_direct.py | 0 .../random}/randomgen/tests/test_legacy.py | 0 .../randomgen/tests/test_numpy_mt19937.py | 0 .../tests/test_numpy_mt19937_regressions.py | 0 .../random}/randomgen/tests/test_smoke.py | 0 .../random}/randomgen/threefry.pyx | 0 .../random}/randomgen/threefry32.pyx | 0 .../random}/randomgen/xoroshiro128.pyx | 0 .../random}/randomgen/xorshift1024.pyx | 0 .../random}/randomgen/xoshiro256starstar.pyx | 0 .../random}/randomgen/xoshiro512starstar.pyx | 0 199 files changed, 1960 deletions(-) delete mode 100644 _randomgen/MANIFEST.in delete mode 100644 _randomgen/appveyor.yml delete mode 100644 _randomgen/ci/conda-install.sh delete mode 100644 _randomgen/ci/pypi-install.sh delete mode 100644 _randomgen/doc/Makefile delete mode 100644 _randomgen/doc/make.bat delete mode 100644 _randomgen/github_deploy_key_bashtage_randomgen.enc delete mode 100644 _randomgen/requirements.txt delete mode 100644 _randomgen/setup.cfg delete mode 100644 _randomgen/versioneer.py rename {_randomgen => doc/source}/papers/Fast Random Integer Generation in an Interval - arxiv 1805.10941.pdf (100%) rename {_randomgen => doc/source}/papers/random123sc11.pdf (100%) rename {_randomgen/doc/source => doc/source/random}/brng/dsfmt.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/index.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/mt19937.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/pcg32.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/pcg64.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/philox.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/threefry.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/threefry32.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/xoroshiro128.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/xorshift1024.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/xoshiro256starstar.rst (100%) rename {_randomgen/doc/source => doc/source/random}/brng/xoshiro512starstar.rst (100%) rename {_randomgen/doc/source => doc/source/random}/change-log.rst (100%) rename {_randomgen/doc/source => doc/source/random}/conf.py (100%) rename {_randomgen/doc/source => doc/source/random}/entropy.rst (100%) rename {_randomgen/doc/source => doc/source/random}/extending.rst (100%) rename {_randomgen/doc/source => doc/source/random}/generator.rst (100%) rename {_randomgen/doc/source => doc/source/random}/index.rst (100%) rename {_randomgen/doc/source => doc/source/random}/legacy.rst (100%) rename {_randomgen/doc/source => doc/source/random}/multithreading.rst (100%) rename {_randomgen/doc/source => doc/source/random}/new-or-different.rst (100%) rename {_randomgen/doc/source => doc/source/random}/parallel.rst (100%) rename {_randomgen/doc/source => doc/source/random}/performance.py (100%) rename {_randomgen/doc/source => doc/source/random}/performance.rst (100%) rename {_randomgen/doc/source => doc/source/random}/references.rst (100%) rename {_randomgen => numpy/random/randomgen}/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/__init__.py (100%) rename {_randomgen => numpy/random}/randomgen/_testing.py (100%) rename {_randomgen => numpy/random}/randomgen/_version.py (100%) rename {_randomgen => numpy/random}/randomgen/bounded_integers.pxd.in (100%) rename {_randomgen => numpy/random}/randomgen/bounded_integers.pyx.in (100%) rename {_randomgen => numpy/random}/randomgen/common.pxd (100%) rename {_randomgen => numpy/random}/randomgen/common.pyx (100%) rename {_randomgen => numpy/random}/randomgen/distributions.pxd (100%) rename {_randomgen => numpy/random}/randomgen/dsfmt.pyx (100%) rename {_randomgen => numpy/random}/randomgen/entropy.pyx (100%) rename {_randomgen => numpy/random}/randomgen/examples/cython/extending.pyx (100%) rename {_randomgen => numpy/random}/randomgen/examples/cython/extending_distributions.pyx (100%) rename {_randomgen => numpy/random}/randomgen/examples/cython/setup.py (100%) rename {_randomgen => numpy/random}/randomgen/examples/numba/extending.py (100%) rename {_randomgen => numpy/random}/randomgen/examples/numba/extending_distributions.py (100%) rename {_randomgen => numpy/random}/randomgen/generator.pyx (100%) rename {_randomgen => numpy/random}/randomgen/legacy/__init__.py (100%) rename {_randomgen => numpy/random}/randomgen/legacy/_legacy.pyx (100%) rename {_randomgen => numpy/random}/randomgen/legacy/legacy.py (100%) rename {_randomgen => numpy/random}/randomgen/legacy/legacy_distributions.pxd (100%) rename {_randomgen => numpy/random}/randomgen/mt19937.pyx (100%) rename {_randomgen => numpy/random}/randomgen/pcg32.pyx (100%) rename {_randomgen => numpy/random}/randomgen/pcg64.pyx (100%) rename {_randomgen => numpy/random}/randomgen/philox.pyx (100%) rename {_randomgen => numpy/random}/randomgen/pickle.py (100%) rename {_randomgen => numpy/random}/randomgen/src/aligned_malloc/aligned_malloc.c (100%) rename {_randomgen => numpy/random}/randomgen/src/aligned_malloc/aligned_malloc.h (100%) rename {_randomgen => numpy/random}/randomgen/src/common/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/common/inttypes.h (100%) rename {_randomgen => numpy/random}/randomgen/src/common/stdint.h (100%) rename {_randomgen => numpy/random}/randomgen/src/distributions/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/distributions/binomial.h (100%) rename {_randomgen => numpy/random}/randomgen/src/distributions/distributions.c (100%) rename {_randomgen => numpy/random}/randomgen/src/distributions/distributions.h (100%) rename {_randomgen => numpy/random}/randomgen/src/distributions/ziggurat.h (100%) rename {_randomgen => numpy/random}/randomgen/src/distributions/ziggurat_constants.h (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/128-bit-jump.poly.txt (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/96-bit-jump.poly.txt (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/calc-jump.cpp (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT-benchmark.c (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT-calc-jump.hpp (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT-common.h (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT-jump.c (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT-jump.h (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT-params.h (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT-params19937.h (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT-poly.h (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT-test-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT.c (100%) rename {_randomgen => numpy/random}/randomgen/src/dsfmt/dSFMT.h (100%) rename {_randomgen => numpy/random}/randomgen/src/entropy/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/entropy/entropy.c (100%) rename {_randomgen => numpy/random}/randomgen/src/entropy/entropy.h (100%) rename {_randomgen => numpy/random}/randomgen/src/legacy/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/legacy/distributions-boxmuller.c (100%) rename {_randomgen => numpy/random}/randomgen/src/legacy/distributions-boxmuller.h (100%) rename {_randomgen => numpy/random}/randomgen/src/mt19937/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/mt19937/mt19937-benchmark.c (100%) rename {_randomgen => numpy/random}/randomgen/src/mt19937/mt19937-jump.c (100%) rename {_randomgen => numpy/random}/randomgen/src/mt19937/mt19937-jump.h (100%) rename {_randomgen => numpy/random}/randomgen/src/mt19937/mt19937-poly.h (100%) rename {_randomgen => numpy/random}/randomgen/src/mt19937/mt19937-test-data-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/mt19937/mt19937.c (100%) rename {_randomgen => numpy/random}/randomgen/src/mt19937/mt19937.h (100%) rename {_randomgen => numpy/random}/randomgen/src/mt19937/randomkit.c (100%) rename {_randomgen => numpy/random}/randomgen/src/mt19937/randomkit.h (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg32/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg32/pcg-advance-64.c (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg32/pcg32-test-data-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg32/pcg32.c (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg32/pcg32.h (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg32/pcg_variants.h (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg64/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg64/pcg64-benchmark.c (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg64/pcg64-test-data-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg64/pcg64.c (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg64/pcg64.h (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg64/pcg64.orig.c (100%) rename {_randomgen => numpy/random}/randomgen/src/pcg64/pcg64.orig.h (100%) rename {_randomgen => numpy/random}/randomgen/src/philox/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/philox/philox-benchmark.c (100%) rename {_randomgen => numpy/random}/randomgen/src/philox/philox-test-data-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/philox/philox.c (100%) rename {_randomgen => numpy/random}/randomgen/src/philox/philox.h (100%) rename {_randomgen => numpy/random}/randomgen/src/splitmix64/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/splitmix64/splitmix64.c (100%) rename {_randomgen => numpy/random}/randomgen/src/splitmix64/splitmix64.h (100%) rename {_randomgen => numpy/random}/randomgen/src/splitmix64/splitmix64.orig.c (100%) rename {_randomgen => numpy/random}/randomgen/src/threefry/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/threefry/threefry-benchmark.c (100%) rename {_randomgen => numpy/random}/randomgen/src/threefry/threefry-orig.c (100%) rename {_randomgen => numpy/random}/randomgen/src/threefry/threefry-test-data-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/threefry/threefry.c (100%) rename {_randomgen => numpy/random}/randomgen/src/threefry/threefry.h (100%) rename {_randomgen => numpy/random}/randomgen/src/threefry32/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/threefry32/threefry32-test-data-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/threefry32/threefry32.c (100%) rename {_randomgen => numpy/random}/randomgen/src/threefry32/threefry32.h (100%) rename {_randomgen => numpy/random}/randomgen/src/xoroshiro128/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xoroshiro128/xoroshiro128.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xoroshiro128/xoroshiro128.h (100%) rename {_randomgen => numpy/random}/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xoroshiro128/xoroshiro128plus.orig.h (100%) rename {_randomgen => numpy/random}/randomgen/src/xorshift1024/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/xorshift1024/xorshift1024-benchmark.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xorshift1024/xorshift1024-test-data-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xorshift1024/xorshift1024.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xorshift1024/xorshift1024.h (100%) rename {_randomgen => numpy/random}/randomgen/src/xorshift1024/xorshift1024.orig.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xorshift1024/xorshift1024.orig.h (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro256starstar/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro256starstar/xoshiro256starstar.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro256starstar/xoshiro256starstar.h (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro512starstar/LICENSE.md (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro512starstar/xoshiro512starstar.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro512starstar/xoshiro512starstar.h (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c (100%) rename {_randomgen => numpy/random}/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h (100%) rename {_randomgen => numpy/random}/randomgen/tests/__init__.py (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/__init__.py (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/dSFMT-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/dSFMT-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/mt19937-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/mt19937-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/pcg32-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/pcg32-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/pcg64-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/pcg64-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/philox-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/philox-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/threefry-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/threefry-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/threefry32-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/threefry32-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/xoroshiro128-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/xoroshiro128-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/xorshift1024-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/xorshift1024-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/xoshiro256starstar-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/xoshiro256starstar-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/xoshiro512starstar-testset-1.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/data/xoshiro512starstar-testset-2.csv (100%) rename {_randomgen => numpy/random}/randomgen/tests/test_against_numpy.py (100%) rename {_randomgen => numpy/random}/randomgen/tests/test_direct.py (100%) rename {_randomgen => numpy/random}/randomgen/tests/test_legacy.py (100%) rename {_randomgen => numpy/random}/randomgen/tests/test_numpy_mt19937.py (100%) rename {_randomgen => numpy/random}/randomgen/tests/test_numpy_mt19937_regressions.py (100%) rename {_randomgen => numpy/random}/randomgen/tests/test_smoke.py (100%) rename {_randomgen => numpy/random}/randomgen/threefry.pyx (100%) rename {_randomgen => numpy/random}/randomgen/threefry32.pyx (100%) rename {_randomgen => numpy/random}/randomgen/xoroshiro128.pyx (100%) rename {_randomgen => numpy/random}/randomgen/xorshift1024.pyx (100%) rename {_randomgen => numpy/random}/randomgen/xoshiro256starstar.pyx (100%) rename {_randomgen => numpy/random}/randomgen/xoshiro512starstar.pyx (100%) diff --git a/_randomgen/MANIFEST.in b/_randomgen/MANIFEST.in deleted file mode 100644 index 61fffb8db518..000000000000 --- a/_randomgen/MANIFEST.in +++ /dev/null @@ -1,10 +0,0 @@ -exclude randomgen/entropy.c -recursive-exclude randomgen *.c -include versioneer.py -include randomgen/_version.py -include requirements.txt -include README.md -include README.rst -include LICENSE.md -recursive-include randomgen *.py *.pyx *.px[di] *.h *.in *.csv *.md -graft randomgen/src diff --git a/_randomgen/appveyor.yml b/_randomgen/appveyor.yml deleted file mode 100644 index 88544620de73..000000000000 --- a/_randomgen/appveyor.yml +++ /dev/null @@ -1,33 +0,0 @@ -skip_tags: true -clone_depth: 50 - -os: Visual Studio 2015 - -environment: - matrix: - - PY_MAJOR_VER: 2 - PYTHON_ARCH: "x86" - - PY_MAJOR_VER: 3 - PYTHON_ARCH: "x86_64" - - PY_MAJOR_VER: 3 - PYTHON_ARCH: "x86" - -platform: - - x64 - -build_script: - - ps: Start-FileDownload "https://repo.continuum.io/miniconda/Miniconda$env:PY_MAJOR_VER-latest-Windows-$env:PYTHON_ARCH.exe" C:\Miniconda.exe; echo "Finished downloading miniconda" - - cmd: C:\Miniconda.exe /S /D=C:\Py - - SET PATH=C:\Py;C:\Py\Scripts;C:\Py\Library\bin;%PATH% - - conda config --set always_yes yes - - conda update conda --quiet - - conda install numpy cython nose pandas pytest --quiet - - python setup.py develop - - set "GIT_DIR=%cd%" - -test_script: - - pytest randomgen - -on_success: - - cd %GIT_DIR%\ - - python benchmark.py diff --git a/_randomgen/ci/conda-install.sh b/_randomgen/ci/conda-install.sh deleted file mode 100644 index cccb8227dcf0..000000000000 --- a/_randomgen/ci/conda-install.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -if [[ ${TRAVIS_OS_NAME} == "osx" ]]; then wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda3.sh; fi -if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh; fi -chmod +x miniconda3.sh -./miniconda3.sh -b -export PATH=${HOME}/miniconda3/bin:$PATH -conda config --set always_yes true -conda update --all --quiet -conda create -n randomgen-test ${PKGS} pip --quiet -source activate randomgen-test - -PKGS="python=${PYTHON} matplotlib numpy" -if [[ -n ${NUMPY} ]]; then PKGS="${PKGS}=${NUMPY}"; fi -PKGS="${PKGS} Cython"; -if [[ -n ${CYTHON} ]]; then PKGS="${PKGS}=${CYTHON}"; fi -PKGS="${PKGS} pandas"; -if [[ -n ${PANDAS} ]]; then PKGS="${PKGS}=${PANDAS}"; fi -echo conda create -n randomgen-test ${PKGS} pytest setuptools nose --quiet -conda create -n randomgen-test ${PKGS} pytest setuptools nose --quiet diff --git a/_randomgen/ci/pypi-install.sh b/_randomgen/ci/pypi-install.sh deleted file mode 100644 index ded8dd9212d2..000000000000 --- a/_randomgen/ci/pypi-install.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -pip install numpy cython pandas pytest setuptools nose matplotlib --quiet diff --git a/_randomgen/doc/Makefile b/_randomgen/doc/Makefile deleted file mode 100644 index 1ee9d3660c0d..000000000000 --- a/_randomgen/doc/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SPHINXPROJ = RandomGen -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/_randomgen/doc/make.bat b/_randomgen/doc/make.bat deleted file mode 100644 index e5a098a3426e..000000000000 --- a/_randomgen/doc/make.bat +++ /dev/null @@ -1,36 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build -set SPHINXPROJ=RandomGen - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd diff --git a/_randomgen/github_deploy_key_bashtage_randomgen.enc b/_randomgen/github_deploy_key_bashtage_randomgen.enc deleted file mode 100644 index ec025c4808eb..000000000000 --- a/_randomgen/github_deploy_key_bashtage_randomgen.enc +++ /dev/null @@ -1 +0,0 @@ -gAAAAABaqYcL3y2gmKPwdhTQvWbDmqvTV9VyGXrEJI0HFVB3ZcmhgwRY_2L9_k7wALgsaQ9-FOqKreKMagBvAiS8IYhW4dUhJ1_6MO0bb8l_fdvkiKY7NH4DXKpO6sGmOg5YPfx44agTLtnI9yuZHo_LgYTkXFS2MQISZJvpmmtgC7fv_ydaRDG3v9c4a4zi7futr6zk0jAlxw29gjyFaReWJQgH6hJTVUVvOq30RJwjpa87jf45mVTsyPdVfHRqn6rcwvGsRKCW6hFnPRsJEP6-ivdjMFbzK6uK1TrswAJ2ZZIGcH84Kaph8kQayMZRL5FUoWsonkGK_SHwiPjmmHRXVMYxSJqNAtjxDgcznzmuazUOwdWCUIkxe0FtJieW5rLwTjT2u1cgcCQ2MKkBiCjO4tORCT0JGCyhOZdsJx6_5i2s1OKaCEb6Uur07itpI2IAEreA38u7CiU150Q7D8zinpPLWuXIrsk9nKfr1YjwXBSVtOBUOuh4Sy9MjcpQuavwJPYVSpNi6_BeIclxP45wjFF5Ai2P8IgaHxSFlMJNfze9H1U-2eTyQaykuZ2WrZBPoGYFRaQExU6jnXOdPMC5FqaO5DV5tvN56fLx9UFXaCqf_UknJRvYnLi94H__nZJWhN6XfCeNaUuPZuuiOFXekK-LC5VFAWXTN84pOesek0-zESKDffFozITTjA-4cvzppUnsSZNm5cXBUdr3wszkNlrQqDVZhP_HU2B8QSilBnnfVEsbKr_-SVQ0s3ipFohPS_GTFKtn8467vvIRgCkks8J1ba5xHb6QMlt2Y2L7yunLh0vmKwqZTVtU-4L4Xm2kKvgHi1kxAaApQiEX2bM-xX7TGNnzRFLKAxpHX4EvO72K2CcQXKu0XkRNc-_c-XcxsWZ7XtvyTCBXNnPtvj26B-FW8XyJH_u0HblrB-AKRgmpRuAhDNh1l_OAcOFHpUrH5t64t6lwOYCR3lXUJJytW-UEz-Nx9j32VX4Ep1IsGjkNuM3FtW4E-iVoGPwYwT3jsGo5rsO6MzrzoEKJbFdgQHnqe3NaxpF6rEVweQTNN2E1LFFuYHnRgo2LuMdK7IDXJ66MCxqEBRMH6Gcne-b5RHEpWoCQAvgyKwU5MclS4M3zLhGnXbtO-q4OL3JV1a-wx9e4vHZJrAolMjvw7a8l5vCDj-FqT5nJIVpG5eKwB_JL24O5d4xUSbgqBm6i1h51L---brkWg9i9YXsjZj5Inf2ZuU3hasZPyXFbTZbpBXN7BMalszLadCOWWsnDJMvl-UJeX2aDDATy5M_4-9Yjt70G1ZJNxZ8K2F6UdXwVifGJGa7jHU9nteCWZVfUdkiexqkLqKebZAlPBpzisrEQw6PmokKP2UO27NBFYTlfYL1NiCahXkOUMPiTKhjQ0_JSqdlUl2igNlNUFSip-63Rk4WtgodQo9iI4icfV5TFkR0h-LPD1m9lIamruWvAQWLU-_daZcN8rdqCWsysuo1ryp80UHHvyTiwloCa2f0ZKr78RIaD_QCkHmevywprNNuMd0ErbAOD7v3dUKjnlvpf8gLpUnu4ZfR1u86OPqsyt2b5tmwB6TWdpaCBNRAjlbFOU8aHDpPDVCAKf1AcEZ1B6p36YgNf5yxmKwc1QEmzXPr1KnSWJRps_QRBX-hEuBu8Q_BUQCjlInJVLcpSgt2lTuJPwwQzdxm5CeU1xdpeWCztSxfghmfE7mzhYizIYa1WaYs32xfZQglEG_O8oXCaU524vyh6cBnIytY3cF1FlwfbKQvbKyKkq8p5YSWe8HX8XRJGVe1bBNM2RYZO5BfLLl5cENIUSbb-REs6j8E61HGgJ9cLBG4-l2QbivSEhKsa4fI0JNVGEL_kwaEOVNHa85y_4oFAQuC4eYOMdgrwGfcD-J-XkE_J6khiLCOaZRcFhFNUfTjghPYzO37D24cAQ9fGnFFehQU-08Ie8SMV2O3fmUV2RbX_h6FXYKZ5Ptp3l2wP5wcuwhPFxPPJ279pswQw9NlHBF3gdtu3_cisqwNfc_HZQ6GXYzbcE7nwTGOY03LN3RjghJgkkeaNs6e0iIxfTJjIqG6-ZWNRNOJKdotjMLVqlhfk0KNZjO5rKEfDfYW_Lbiylgu7I7O-wy-Xn60OTu7na0ObYl-Y9tXkRTZPMNasjDWpfTXKZRp8EX45W-35VKmb0ERj0ee9uXgZxiPGLd3OP8cxIiXqZdZYKwJnD09zZuXwaTa2AAp2WmLYLiF-pDIISNxVF7mCxU9G0AWl0Ml1d5pS5zadM1OYB5yfjx09hlVasaiPaGqIptNtdz8tDQ1ngH-QBPV8wNvSxHwdU4w96pJIY9jG5Z3k-PVO26NNKjZ_KMZhO-3TgQXMJI0GHSyfYFHEMGJuUbeS4ThGyAt2Z6pVKTu7WFjgceseLMmwevJQeyScvtD22t8bpSuqfgxrAGSP5O2-e1UEl_12umZZG3sSd8jc_WNBgX7nSa6LeGAmlY0z_h9SblVl63r2qZi7-Ur0Y7O4JH4rHMDkf07tMU-foCiDDppvZkPRuvPlYgzLmnyOXePN0_1aiou9qbMWmzyJwhrqnt5uZXVHpRwCKKdXRBAcBebuKU-LKqMhWWowf1OUm240628OmQL2oTOaVWBlS3x1XKHMv18_ucbgWB4KaQdidSKMwIXE_LRfhr17g-h2CTQFsfImGKU36ECJHk35K9qr3aZI5X2MLUsOJjdbQiVJsLpdCDbr_HfPDNnux0QiVRZhslKnqOlcv8_6MeKtcqcxDJTi1v1430tpiZj-A2dp3F9YXi_PvCcKD4GheUwN8TUJgEZF3m9Vc80pAWWFDN7Obof_0zCcv7HrXgXCVJHnFzJn0J4AqW6db-DvYAzdejDnLTsTZK9ctJmWxHAWWXYi35aAjj6nalFk97T7EvOr2zS6f_xSUyPeNPs2fIP1lY3togmjPRvwbIN-ZxqLzkfjmxARrLJpqAxK_AvOz2vNlEosQd3zJxk7hEQWRfkTmakvDPgkd5fNsfIGfAt8B_PWnmz41DWKeOlsSQguPAqCE40NSszmyjSBhde8uHN8tGwdQpdcjPt01kgmrdD2GHfLs8zeyNWRzE3qmLT46S1dq1kfQX2j20LXDck9Ox0nFDUXYwaz6pVDPymhPqzh4EHtg0QKePJ5qpY2RDTW3S8UK3YkE3pa_C_-BPcNLVGr_k7WaMWGx0JJ72W2MqcoXgq3bZq_CZeseeKm3rH3YiaibidLk4WqMblcWUurHW09vFCNSOyQ28jkBeMSgadJ2zEbK9M1QmsDxxSCzWtIn_y7nDLCGh0NzD2alVp4QfxwjF5ZEYSXZOYXdhRBkd3pRX9perJT_zlQf7Ag2otXUZE-J6TkDAAwhWxxUFQ0iUIKNKtO-ocM8YevCyl0EK06AzX6jmShrE5eZpej7o7DA2dCoLYksacloBbonqDjkpXR1uZcGJSnhZm29UeSSGQN7cqgR5DDCHkthvOn8gZxS8vr1fQiswazUaMCClHUD_O88IlLXnqXj4n-84TMT9iBGN3iaab4P-fb2t1Azcd8uSGl3CwNEouEekdvVWHSp3bhMkwpPuvakJheLOGfX7npwWo5iIEvdA0VhesiEV8ZVJYCt3zmOwQtI-Sk5uAVAWAieB6-up9KWtwoF89C64CLp99srzLkaPddQJKtTruYQER5l3hL1LBe5g8XPEBNMrFjp2xIN8mNYpZRt41nFxsHoA9xnsv4NXWbwqnkyImP0Wm9HmclvwTOZ9xdT5Ryj8u97XSOz4y8T5Ql5UPwRBujiBI91GQnEKz3FPmUzS70Bbrg3XIirpbPqcRp_VnnxXT8AX0zGZiuWvx94NFa5h4a11vYpeLnKzQ2RyTHB96CSpxxdXHAHfMvc9ib3XzlKRUUfDX0x0tDBj3BkV5UMgLtn2RRCgT1PydLn13wYbeNwfb5GlGutiqQY_QTuUOqSII-2vyNzA5FUPpzofXGYwAz52pGwpZ7w0s4fBpXocxWt0gGW5wxDzTEX3UdkbRsN1GXs5tYkdbcCW_jPrVcq7pUGgOyGXMEYnZUA1ack2h6nSwlxbx_Aka_VyxZCJFYJW9S165lIhm7KkDCfRpQdoA4Fx27aAXwWL70ipNCyNHFOERXD5SoVMJDcz3-cXkttEddXooygKoXojR4epBuxhSkUNxgnd70faZaIC8_L5_ZlZIBn-lH3jLT5Yuzt8-weKpAyczteZ8eLB0YlnYlqhIVFYy4QBR8iejRZBXABKiuIWz_Xf4qu6UGwHTQ-1BBfl9mr0RxULn7NGtfbQ72Xwad-HlT1MnEd_6o95MkFvHbdINlpkaeVwiAgUSFbITPh7x8JaQKlAzjROJQdhGvT4j42woumzQtuqr9UnDWtf8aECkrJP_-AEy1BLbXmUo= \ No newline at end of file diff --git a/_randomgen/requirements.txt b/_randomgen/requirements.txt deleted file mode 100644 index 0d7fe1ba89e7..000000000000 --- a/_randomgen/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -numpy>=1.13 -cython>=0.26 -setuptools -wheel \ No newline at end of file diff --git a/_randomgen/setup.cfg b/_randomgen/setup.cfg deleted file mode 100644 index b25ab5078a40..000000000000 --- a/_randomgen/setup.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[metadata] -description-file = README.md -license_file = LICENSE.md - -[versioneer] -VCS = git -style = pep440 -versionfile_source = randomgen/_version.py -versionfile_build = randomgen/_version.py -tag_prefix = v -parentdir_prefix = randomgen- diff --git a/_randomgen/versioneer.py b/_randomgen/versioneer.py deleted file mode 100644 index 64fea1c89272..000000000000 --- a/_randomgen/versioneer.py +++ /dev/null @@ -1,1822 +0,0 @@ - -# Version: 0.18 - -"""The Versioneer - like a rocketeer, but for versions. - -The Versioneer -============== - -* like a rocketeer, but for versions! -* https://github.com/warner/python-versioneer -* Brian Warner -* License: Public Domain -* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy -* [![Latest Version] -(https://pypip.in/version/versioneer/badge.svg?style=flat) -](https://pypi.python.org/pypi/versioneer/) -* [![Build Status] -(https://travis-ci.org/warner/python-versioneer.png?branch=master) -](https://travis-ci.org/warner/python-versioneer) - -This is a tool for managing a recorded version number in distutils-based -python projects. The goal is to remove the tedious and error-prone "update -the embedded version string" step from your release process. Making a new -release should be as easy as recording a new tag in your version-control -system, and maybe making new tarballs. - - -## Quick Install - -* `pip install versioneer` to somewhere to your $PATH -* add a `[versioneer]` section to your setup.cfg (see below) -* run `versioneer install` in your source tree, commit the results - -## Version Identifiers - -Source trees come from a variety of places: - -* a version-control system checkout (mostly used by developers) -* a nightly tarball, produced by build automation -* a snapshot tarball, produced by a web-based VCS browser, like github's - "tarball from tag" feature -* a release tarball, produced by "setup.py sdist", distributed through PyPI - -Within each source tree, the version identifier (either a string or a number, -this tool is format-agnostic) can come from a variety of places: - -* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows - about recent "tags" and an absolute revision-id -* the name of the directory into which the tarball was unpacked -* an expanded VCS keyword ($Id$, etc) -* a `_version.py` created by some earlier build step - -For released software, the version identifier is closely related to a VCS -tag. Some projects use tag names that include more than just the version -string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool -needs to strip the tag prefix to extract the version identifier. For -unreleased software (between tags), the version identifier should provide -enough information to help developers recreate the same tree, while also -giving them an idea of roughly how old the tree is (after version 1.2, before -version 1.3). Many VCS systems can report a description that captures this, -for example `git describe --tags --dirty --always` reports things like -"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the -0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has -uncommitted changes. - -The version identifier is used for multiple purposes: - -* to allow the module to self-identify its version: `myproject.__version__` -* to choose a name and prefix for a 'setup.py sdist' tarball - -## Theory of Operation - -Versioneer works by adding a special `_version.py` file into your source -tree, where your `__init__.py` can import it. This `_version.py` knows how to -dynamically ask the VCS tool for version information at import time. - -`_version.py` also contains `$Revision$` markers, and the installation -process marks `_version.py` to have this marker rewritten with a tag name -during the `git archive` command. As a result, generated tarballs will -contain enough information to get the proper version. - -To allow `setup.py` to compute a version too, a `versioneer.py` is added to -the top level of your source tree, next to `setup.py` and the `setup.cfg` -that configures it. This overrides several distutils/setuptools commands to -compute the version when invoked, and changes `setup.py build` and `setup.py -sdist` to replace `_version.py` with a small static file that contains just -the generated version data. - -## Installation - -See [INSTALL.md](./INSTALL.md) for detailed installation instructions. - -## Version-String Flavors - -Code which uses Versioneer can learn about its version string at runtime by -importing `_version` from your main `__init__.py` file and running the -`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can -import the top-level `versioneer.py` and run `get_versions()`. - -Both functions return a dictionary with different flavors of version -information: - -* `['version']`: A condensed version string, rendered using the selected - style. This is the most commonly used value for the project's version - string. The default "pep440" style yields strings like `0.11`, - `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section - below for alternative styles. - -* `['full-revisionid']`: detailed revision identifier. For Git, this is the - full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". - -* `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the - commit date in ISO 8601 format. This will be None if the date is not - available. - -* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that - this is only accurate if run in a VCS checkout, otherwise it is likely to - be False or None - -* `['error']`: if the version string could not be computed, this will be set - to a string describing the problem, otherwise it will be None. It may be - useful to throw an exception in setup.py if this is set, to avoid e.g. - creating tarballs with a version string of "unknown". - -Some variants are more useful than others. Including `full-revisionid` in a -bug report should allow developers to reconstruct the exact code being tested -(or indicate the presence of local changes that should be shared with the -developers). `version` is suitable for display in an "about" box or a CLI -`--version` output: it can be easily compared against release notes and lists -of bugs fixed in various releases. - -The installer adds the following text to your `__init__.py` to place a basic -version in `YOURPROJECT.__version__`: - - from ._version import get_versions - __version__ = get_versions()['version'] - del get_versions - -## Styles - -The setup.cfg `style=` configuration controls how the VCS information is -rendered into a version string. - -The default style, "pep440", produces a PEP440-compliant string, equal to the -un-prefixed tag name for actual releases, and containing an additional "local -version" section with more detail for in-between builds. For Git, this is -TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags ---dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the -tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and -that this commit is two revisions ("+2") beyond the "0.11" tag. For released -software (exactly equal to a known tag), the identifier will only contain the -stripped tag, e.g. "0.11". - -Other styles are available. See [details.md](details.md) in the Versioneer -source tree for descriptions. - -## Debugging - -Versioneer tries to avoid fatal errors: if something goes wrong, it will tend -to return a version of "0+unknown". To investigate the problem, run `setup.py -version`, which will run the version-lookup code in a verbose mode, and will -display the full contents of `get_versions()` (including the `error` string, -which may help identify what went wrong). - -## Known Limitations - -Some situations are known to cause problems for Versioneer. This details the -most significant ones. More can be found on Github -[issues page](https://github.com/warner/python-versioneer/issues). - -### Subprojects - -Versioneer has limited support for source trees in which `setup.py` is not in -the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are -two common reasons why `setup.py` might not be in the root: - -* Source trees which contain multiple subprojects, such as - [Buildbot](https://github.com/buildbot/buildbot), which contains both - "master" and "slave" subprojects, each with their own `setup.py`, - `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI - distributions (and upload multiple independently-installable tarballs). -* Source trees whose main purpose is to contain a C library, but which also - provide bindings to Python (and perhaps other langauges) in subdirectories. - -Versioneer will look for `.git` in parent directories, and most operations -should get the right version string. However `pip` and `setuptools` have bugs -and implementation details which frequently cause `pip install .` from a -subproject directory to fail to find a correct version string (so it usually -defaults to `0+unknown`). - -`pip install --editable .` should work correctly. `setup.py install` might -work too. - -Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in -some later version. - -[Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking -this issue. The discussion in -[PR #61](https://github.com/warner/python-versioneer/pull/61) describes the -issue from the Versioneer side in more detail. -[pip PR#3176](https://github.com/pypa/pip/pull/3176) and -[pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve -pip to let Versioneer work correctly. - -Versioneer-0.16 and earlier only looked for a `.git` directory next to the -`setup.cfg`, so subprojects were completely unsupported with those releases. - -### Editable installs with setuptools <= 18.5 - -`setup.py develop` and `pip install --editable .` allow you to install a -project into a virtualenv once, then continue editing the source code (and -test) without re-installing after every change. - -"Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a -convenient way to specify executable scripts that should be installed along -with the python package. - -These both work as expected when using modern setuptools. When using -setuptools-18.5 or earlier, however, certain operations will cause -`pkg_resources.DistributionNotFound` errors when running the entrypoint -script, which must be resolved by re-installing the package. This happens -when the install happens with one version, then the egg_info data is -regenerated while a different version is checked out. Many setup.py commands -cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into -a different virtualenv), so this can be surprising. - -[Bug #83](https://github.com/warner/python-versioneer/issues/83) describes -this one, but upgrading to a newer version of setuptools should probably -resolve it. - -### Unicode version strings - -While Versioneer works (and is continually tested) with both Python 2 and -Python 3, it is not entirely consistent with bytes-vs-unicode distinctions. -Newer releases probably generate unicode version strings on py2. It's not -clear that this is wrong, but it may be surprising for applications when then -write these strings to a network connection or include them in bytes-oriented -APIs like cryptographic checksums. - -[Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates -this question. - - -## Updating Versioneer - -To upgrade your project to a new release of Versioneer, do the following: - -* install the new Versioneer (`pip install -U versioneer` or equivalent) -* edit `setup.cfg`, if necessary, to include any new configuration settings - indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. -* re-run `versioneer install` in your source tree, to replace - `SRC/_version.py` -* commit any changed files - -## Future Directions - -This tool is designed to make it easily extended to other version-control -systems: all VCS-specific components are in separate directories like -src/git/ . The top-level `versioneer.py` script is assembled from these -components by running make-versioneer.py . In the future, make-versioneer.py -will take a VCS name as an argument, and will construct a version of -`versioneer.py` that is specific to the given VCS. It might also take the -configuration arguments that are currently provided manually during -installation by editing setup.py . Alternatively, it might go the other -direction and include code from all supported VCS systems, reducing the -number of intermediate scripts. - - -## License - -To make Versioneer easier to embed, all its code is dedicated to the public -domain. The `_version.py` that it creates is also in the public domain. -Specifically, both are released under the Creative Commons "Public Domain -Dedication" license (CC0-1.0), as described in -https://creativecommons.org/publicdomain/zero/1.0/ . - -""" - -from __future__ import print_function -try: - import configparser -except ImportError: - import ConfigParser as configparser -import errno -import json -import os -import re -import subprocess -import sys - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_root(): - """Get the project root directory. - - We require that all commands are run from the project root, i.e. the - directory that contains setup.py, setup.cfg, and versioneer.py . - """ - root = os.path.realpath(os.path.abspath(os.getcwd())) - setup_py = os.path.join(root, "setup.py") - versioneer_py = os.path.join(root, "versioneer.py") - if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - # allow 'python path/to/setup.py COMMAND' - root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) - setup_py = os.path.join(root, "setup.py") - versioneer_py = os.path.join(root, "versioneer.py") - if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ("Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND').") - raise VersioneerBadRootError(err) - try: - # Certain runtime workflows (setup.py install/develop in a setuptools - # tree) execute all dependencies in a single python process, so - # "versioneer" may be imported multiple times, and python's shared - # module-import table will cache the first one. So we can't use - # os.path.dirname(__file__), as that will find whichever - # versioneer.py was first imported, even in later projects. - me = os.path.realpath(os.path.abspath(__file__)) - me_dir = os.path.normcase(os.path.splitext(me)[0]) - vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) - if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py)) - except NameError: - pass - return root - - -def get_config_from_root(root): - """Read the project setup.cfg file to determine Versioneer config.""" - # This might raise EnvironmentError (if setup.cfg is missing), or - # configparser.NoSectionError (if it lacks a [versioneer] section), or - # configparser.NoOptionError (if it lacks "VCS="). See the docstring at - # the top of versioneer.py for instructions on writing your setup.cfg . - setup_cfg = os.path.join(root, "setup.cfg") - parser = configparser.SafeConfigParser() - with open(setup_cfg, "r") as f: - parser.readfp(f) - VCS = parser.get("versioneer", "VCS") # mandatory - - def get(parser, name): - if parser.has_option("versioneer", name): - return parser.get("versioneer", name) - return None - cfg = VersioneerConfig() - cfg.VCS = VCS - cfg.style = get(parser, "style") or "" - cfg.versionfile_source = get(parser, "versionfile_source") - cfg.versionfile_build = get(parser, "versionfile_build") - cfg.tag_prefix = get(parser, "tag_prefix") - if cfg.tag_prefix in ("''", '""'): - cfg.tag_prefix = "" - cfg.parentdir_prefix = get(parser, "parentdir_prefix") - cfg.verbose = get(parser, "verbose") - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -# these dictionaries contain VCS-specific tools -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, p.returncode - return stdout, p.returncode - - -LONG_VERSION_PY['git'] = ''' -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. Generated by -# versioneer-0.18 (https://github.com/warner/python-versioneer) - -"""Git implementation of _version.py.""" - -import errno -import os -import re -import subprocess -import sys - - -def get_keywords(): - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" - git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" - git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_config(): - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "%(STYLE)s" - cfg.tag_prefix = "%(TAG_PREFIX)s" - cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" - cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %%s" %% dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %%s" %% (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %%s (error)" %% dispcmd) - print("stdout was %%s" %% stdout) - return None, p.returncode - return stdout, p.returncode - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %%s but none started with prefix %%s" %% - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %%d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%%s', no digits" %% ",".join(refs - tags)) - if verbose: - print("likely tags: %%s" %% ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %%s" %% r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %%s not under git control" %% root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%%s*" %% tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%%s'" - %% describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%%s' doesn't start with prefix '%%s'" - print(fmt %% (full_tag, tag_prefix)) - pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" - %% (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%%d" %% pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%%d" %% pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%%s" %% pieces["short"] - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%%s" %% pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%%s'" %% style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -def get_versions(): - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): - root = os.path.dirname(root) - except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} -''' - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def do_vcs_install(manifest_in, versionfile_source, ipy): - """Git-specific installation logic for Versioneer. - - For Git, this means creating/changing .gitattributes to mark _version.py - for export-subst keyword substitution. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - files = [manifest_in, versionfile_source] - if ipy: - files.append(ipy) - try: - me = __file__ - if me.endswith(".pyc") or me.endswith(".pyo"): - me = os.path.splitext(me)[0] + ".py" - versioneer_file = os.path.relpath(me) - except NameError: - versioneer_file = "versioneer.py" - files.append(versioneer_file) - present = False - try: - f = open(".gitattributes", "r") - for line in f.readlines(): - if line.strip().startswith(versionfile_source): - if "export-subst" in line.strip().split()[1:]: - present = True - f.close() - except EnvironmentError: - pass - if not present: - f = open(".gitattributes", "a+") - f.write("%s export-subst\n" % versionfile_source) - f.close() - files.append(".gitattributes") - run_command(GITS, ["add", "--"] + files) - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -SHORT_VERSION_PY = """ -# This file was generated by 'versioneer.py' (0.18) from -# revision-control system data, or from the parent directory name of an -# unpacked source archive. Distribution tarballs contain a pre-generated copy -# of this file. - -import json - -version_json = ''' -%s -''' # END VERSION_JSON - - -def get_versions(): - return json.loads(version_json) -""" - - -def versions_from_file(filename): - """Try to determine the version from _version.py if present.""" - try: - with open(filename) as f: - contents = f.read() - except EnvironmentError: - raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) - if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) - if not mo: - raise NotThisMethod("no version_json in _version.py") - return json.loads(mo.group(1)) - - -def write_to_version_file(filename, versions): - """Write the given version number to the given _version.py file.""" - os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) - with open(filename, "w") as f: - f.write(SHORT_VERSION_PY % contents) - - print("set %s to '%s'" % (filename, versions["version"])) - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%d" % pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -class VersioneerBadRootError(Exception): - """The project root directory is unknown or missing key files.""" - - -def get_versions(verbose=False): - """Get the project version from whatever source is available. - - Returns dict with two keys: 'version' and 'full'. - """ - if "versioneer" in sys.modules: - # see the discussion in cmdclass.py:get_cmdclass() - del sys.modules["versioneer"] - - root = get_root() - cfg = get_config_from_root(root) - - assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" - handlers = HANDLERS.get(cfg.VCS) - assert handlers, "unrecognized VCS '%s'" % cfg.VCS - verbose = verbose or cfg.verbose - assert cfg.versionfile_source is not None, \ - "please set versioneer.versionfile_source" - assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" - - versionfile_abs = os.path.join(root, cfg.versionfile_source) - - # extract version from first of: _version.py, VCS command (e.g. 'git - # describe'), parentdir. This is meant to work for developers using a - # source checkout, for users of a tarball created by 'setup.py sdist', - # and for users of a tarball/zipball created by 'git archive' or github's - # download-from-tag feature or the equivalent in other VCSes. - - get_keywords_f = handlers.get("get_keywords") - from_keywords_f = handlers.get("keywords") - if get_keywords_f and from_keywords_f: - try: - keywords = get_keywords_f(versionfile_abs) - ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) - if verbose: - print("got version from expanded keyword %s" % ver) - return ver - except NotThisMethod: - pass - - try: - ver = versions_from_file(versionfile_abs) - if verbose: - print("got version from file %s %s" % (versionfile_abs, ver)) - return ver - except NotThisMethod: - pass - - from_vcs_f = handlers.get("pieces_from_vcs") - if from_vcs_f: - try: - pieces = from_vcs_f(cfg.tag_prefix, root, verbose) - ver = render(pieces, cfg.style) - if verbose: - print("got version from VCS %s" % ver) - return ver - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - if verbose: - print("got version from parentdir %s" % ver) - return ver - except NotThisMethod: - pass - - if verbose: - print("unable to compute version") - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} - - -def get_version(): - """Get the short version string for this project.""" - return get_versions()["version"] - - -def get_cmdclass(): - """Get the custom setuptools/distutils subclasses used by Versioneer.""" - if "versioneer" in sys.modules: - del sys.modules["versioneer"] - # this fixes the "python setup.py develop" case (also 'install' and - # 'easy_install .'), in which subdependencies of the main project are - # built (using setup.py bdist_egg) in the same python process. Assume - # a main project A and a dependency B, which use different versions - # of Versioneer. A's setup.py imports A's Versioneer, leaving it in - # sys.modules by the time B's setup.py is executed, causing B to run - # with the wrong versioneer. Setuptools wraps the sub-dep builds in a - # sandbox that restores sys.modules to it's pre-build state, so the - # parent is protected against the child's "import versioneer". By - # removing ourselves from sys.modules here, before the child build - # happens, we protect the child from the parent's versioneer too. - # Also see https://github.com/warner/python-versioneer/issues/52 - - cmds = {} - - # we add "version" to both distutils and setuptools - from distutils.core import Command - - class cmd_version(Command): - description = "report generated version string" - user_options = [] - boolean_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - vers = get_versions(verbose=True) - print("Version: %s" % vers["version"]) - print(" full-revisionid: %s" % vers.get("full-revisionid")) - print(" dirty: %s" % vers.get("dirty")) - print(" date: %s" % vers.get("date")) - if vers["error"]: - print(" error: %s" % vers["error"]) - cmds["version"] = cmd_version - - # we override "build_py" in both distutils and setuptools - # - # most invocation pathways end up running build_py: - # distutils/build -> build_py - # distutils/install -> distutils/build ->.. - # setuptools/bdist_wheel -> distutils/install ->.. - # setuptools/bdist_egg -> distutils/install_lib -> build_py - # setuptools/install -> bdist_egg ->.. - # setuptools/develop -> ? - # pip install: - # copies source tree to a tempdir before running egg_info/etc - # if .git isn't copied too, 'git describe' will fail - # then does setup.py bdist_wheel, or sometimes setup.py install - # setup.py egg_info -> ? - - # we override different "build_py" commands for both environments - if "setuptools" in sys.modules: - from setuptools.command.build_py import build_py as _build_py - else: - from distutils.command.build_py import build_py as _build_py - - class cmd_build_py(_build_py): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - _build_py.run(self) - # now locate _version.py in the new build/ directory and replace - # it with an updated value - if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - cmds["build_py"] = cmd_build_py - - if "cx_Freeze" in sys.modules: # cx_freeze enabled? - from cx_Freeze.dist import build_exe as _build_exe - # nczeczulin reports that py2exe won't like the pep440-style string - # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. - # setup(console=[{ - # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION - # "product_version": versioneer.get_version(), - # ... - - class cmd_build_exe(_build_exe): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _build_exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - cmds["build_exe"] = cmd_build_exe - del cmds["build_py"] - - if 'py2exe' in sys.modules: # py2exe enabled? - try: - from py2exe.distutils_buildexe import py2exe as _py2exe # py3 - except ImportError: - from py2exe.build_exe import py2exe as _py2exe # py2 - - class cmd_py2exe(_py2exe): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _py2exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - cmds["py2exe"] = cmd_py2exe - - # we override different "sdist" commands for both environments - if "setuptools" in sys.modules: - from setuptools.command.sdist import sdist as _sdist - else: - from distutils.command.sdist import sdist as _sdist - - class cmd_sdist(_sdist): - def run(self): - versions = get_versions() - self._versioneer_generated_versions = versions - # unless we update this, the command will keep using the old - # version - self.distribution.metadata.version = versions["version"] - return _sdist.run(self) - - def make_release_tree(self, base_dir, files): - root = get_root() - cfg = get_config_from_root(root) - _sdist.make_release_tree(self, base_dir, files) - # now locate _version.py in the new base_dir directory - # (remembering that it may be a hardlink) and replace it with an - # updated value - target_versionfile = os.path.join(base_dir, cfg.versionfile_source) - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) - cmds["sdist"] = cmd_sdist - - return cmds - - -CONFIG_ERROR = """ -setup.cfg is missing the necessary Versioneer configuration. You need -a section like: - - [versioneer] - VCS = git - style = pep440 - versionfile_source = src/myproject/_version.py - versionfile_build = myproject/_version.py - tag_prefix = - parentdir_prefix = myproject- - -You will also need to edit your setup.py to use the results: - - import versioneer - setup(version=versioneer.get_version(), - cmdclass=versioneer.get_cmdclass(), ...) - -Please read the docstring in ./versioneer.py for configuration instructions, -edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. -""" - -SAMPLE_CONFIG = """ -# See the docstring in versioneer.py for instructions. Note that you must -# re-run 'versioneer.py setup' after changing this section, and commit the -# resulting files. - -[versioneer] -#VCS = git -#style = pep440 -#versionfile_source = -#versionfile_build = -#tag_prefix = -#parentdir_prefix = - -""" - -INIT_PY_SNIPPET = """ -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions -""" - - -def do_setup(): - """Main VCS-independent setup function for installing Versioneer.""" - root = get_root() - try: - cfg = get_config_from_root(root) - except (EnvironmentError, configparser.NoSectionError, - configparser.NoOptionError) as e: - if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) - with open(os.path.join(root, "setup.cfg"), "a") as f: - f.write(SAMPLE_CONFIG) - print(CONFIG_ERROR, file=sys.stderr) - return 1 - - print(" creating %s" % cfg.versionfile_source) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") - if os.path.exists(ipy): - try: - with open(ipy, "r") as f: - old = f.read() - except EnvironmentError: - old = "" - if INIT_PY_SNIPPET not in old: - print(" appending to %s" % ipy) - with open(ipy, "a") as f: - f.write(INIT_PY_SNIPPET) - else: - print(" %s unmodified" % ipy) - else: - print(" %s doesn't exist, ok" % ipy) - ipy = None - - # Make sure both the top-level "versioneer.py" and versionfile_source - # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so - # they'll be copied into source distributions. Pip won't be able to - # install the package without this. - manifest_in = os.path.join(root, "MANIFEST.in") - simple_includes = set() - try: - with open(manifest_in, "r") as f: - for line in f: - if line.startswith("include "): - for include in line.split()[1:]: - simple_includes.add(include) - except EnvironmentError: - pass - # That doesn't cover everything MANIFEST.in can do - # (http://docs.python.org/2/distutils/sourcedist.html#commands), so - # it might give some false negatives. Appending redundant 'include' - # lines is safe, though. - if "versioneer.py" not in simple_includes: - print(" appending 'versioneer.py' to MANIFEST.in") - with open(manifest_in, "a") as f: - f.write("include versioneer.py\n") - else: - print(" 'versioneer.py' already in MANIFEST.in") - if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) - with open(manifest_in, "a") as f: - f.write("include %s\n" % cfg.versionfile_source) - else: - print(" versionfile_source already in MANIFEST.in") - - # Make VCS-specific changes. For git, this means creating/changing - # .gitattributes to mark _version.py for export-subst keyword - # substitution. - do_vcs_install(manifest_in, cfg.versionfile_source, ipy) - return 0 - - -def scan_setup_py(): - """Validate the contents of setup.py against Versioneer's expectations.""" - found = set() - setters = False - errors = 0 - with open("setup.py", "r") as f: - for line in f.readlines(): - if "import versioneer" in line: - found.add("import") - if "versioneer.get_cmdclass()" in line: - found.add("cmdclass") - if "versioneer.get_version()" in line: - found.add("get_version") - if "versioneer.VCS" in line: - setters = True - if "versioneer.versionfile_source" in line: - setters = True - if len(found) != 3: - print("") - print("Your setup.py appears to be missing some important items") - print("(but I might be wrong). Please make sure it has something") - print("roughly like the following:") - print("") - print(" import versioneer") - print(" setup( version=versioneer.get_version(),") - print(" cmdclass=versioneer.get_cmdclass(), ...)") - print("") - errors += 1 - if setters: - print("You should remove lines like 'versioneer.VCS = ' and") - print("'versioneer.versionfile_source = ' . This configuration") - print("now lives in setup.cfg, and should be removed from setup.py") - print("") - errors += 1 - return errors - - -if __name__ == "__main__": - cmd = sys.argv[1] - if cmd == "setup": - errors = do_setup() - errors += scan_setup_py() - if errors: - sys.exit(1) diff --git a/_randomgen/papers/Fast Random Integer Generation in an Interval - arxiv 1805.10941.pdf b/doc/source/papers/Fast Random Integer Generation in an Interval - arxiv 1805.10941.pdf similarity index 100% rename from _randomgen/papers/Fast Random Integer Generation in an Interval - arxiv 1805.10941.pdf rename to doc/source/papers/Fast Random Integer Generation in an Interval - arxiv 1805.10941.pdf diff --git a/_randomgen/papers/random123sc11.pdf b/doc/source/papers/random123sc11.pdf similarity index 100% rename from _randomgen/papers/random123sc11.pdf rename to doc/source/papers/random123sc11.pdf diff --git a/_randomgen/doc/source/brng/dsfmt.rst b/doc/source/random/brng/dsfmt.rst similarity index 100% rename from _randomgen/doc/source/brng/dsfmt.rst rename to doc/source/random/brng/dsfmt.rst diff --git a/_randomgen/doc/source/brng/index.rst b/doc/source/random/brng/index.rst similarity index 100% rename from _randomgen/doc/source/brng/index.rst rename to doc/source/random/brng/index.rst diff --git a/_randomgen/doc/source/brng/mt19937.rst b/doc/source/random/brng/mt19937.rst similarity index 100% rename from _randomgen/doc/source/brng/mt19937.rst rename to doc/source/random/brng/mt19937.rst diff --git a/_randomgen/doc/source/brng/pcg32.rst b/doc/source/random/brng/pcg32.rst similarity index 100% rename from _randomgen/doc/source/brng/pcg32.rst rename to doc/source/random/brng/pcg32.rst diff --git a/_randomgen/doc/source/brng/pcg64.rst b/doc/source/random/brng/pcg64.rst similarity index 100% rename from _randomgen/doc/source/brng/pcg64.rst rename to doc/source/random/brng/pcg64.rst diff --git a/_randomgen/doc/source/brng/philox.rst b/doc/source/random/brng/philox.rst similarity index 100% rename from _randomgen/doc/source/brng/philox.rst rename to doc/source/random/brng/philox.rst diff --git a/_randomgen/doc/source/brng/threefry.rst b/doc/source/random/brng/threefry.rst similarity index 100% rename from _randomgen/doc/source/brng/threefry.rst rename to doc/source/random/brng/threefry.rst diff --git a/_randomgen/doc/source/brng/threefry32.rst b/doc/source/random/brng/threefry32.rst similarity index 100% rename from _randomgen/doc/source/brng/threefry32.rst rename to doc/source/random/brng/threefry32.rst diff --git a/_randomgen/doc/source/brng/xoroshiro128.rst b/doc/source/random/brng/xoroshiro128.rst similarity index 100% rename from _randomgen/doc/source/brng/xoroshiro128.rst rename to doc/source/random/brng/xoroshiro128.rst diff --git a/_randomgen/doc/source/brng/xorshift1024.rst b/doc/source/random/brng/xorshift1024.rst similarity index 100% rename from _randomgen/doc/source/brng/xorshift1024.rst rename to doc/source/random/brng/xorshift1024.rst diff --git a/_randomgen/doc/source/brng/xoshiro256starstar.rst b/doc/source/random/brng/xoshiro256starstar.rst similarity index 100% rename from _randomgen/doc/source/brng/xoshiro256starstar.rst rename to doc/source/random/brng/xoshiro256starstar.rst diff --git a/_randomgen/doc/source/brng/xoshiro512starstar.rst b/doc/source/random/brng/xoshiro512starstar.rst similarity index 100% rename from _randomgen/doc/source/brng/xoshiro512starstar.rst rename to doc/source/random/brng/xoshiro512starstar.rst diff --git a/_randomgen/doc/source/change-log.rst b/doc/source/random/change-log.rst similarity index 100% rename from _randomgen/doc/source/change-log.rst rename to doc/source/random/change-log.rst diff --git a/_randomgen/doc/source/conf.py b/doc/source/random/conf.py similarity index 100% rename from _randomgen/doc/source/conf.py rename to doc/source/random/conf.py diff --git a/_randomgen/doc/source/entropy.rst b/doc/source/random/entropy.rst similarity index 100% rename from _randomgen/doc/source/entropy.rst rename to doc/source/random/entropy.rst diff --git a/_randomgen/doc/source/extending.rst b/doc/source/random/extending.rst similarity index 100% rename from _randomgen/doc/source/extending.rst rename to doc/source/random/extending.rst diff --git a/_randomgen/doc/source/generator.rst b/doc/source/random/generator.rst similarity index 100% rename from _randomgen/doc/source/generator.rst rename to doc/source/random/generator.rst diff --git a/_randomgen/doc/source/index.rst b/doc/source/random/index.rst similarity index 100% rename from _randomgen/doc/source/index.rst rename to doc/source/random/index.rst diff --git a/_randomgen/doc/source/legacy.rst b/doc/source/random/legacy.rst similarity index 100% rename from _randomgen/doc/source/legacy.rst rename to doc/source/random/legacy.rst diff --git a/_randomgen/doc/source/multithreading.rst b/doc/source/random/multithreading.rst similarity index 100% rename from _randomgen/doc/source/multithreading.rst rename to doc/source/random/multithreading.rst diff --git a/_randomgen/doc/source/new-or-different.rst b/doc/source/random/new-or-different.rst similarity index 100% rename from _randomgen/doc/source/new-or-different.rst rename to doc/source/random/new-or-different.rst diff --git a/_randomgen/doc/source/parallel.rst b/doc/source/random/parallel.rst similarity index 100% rename from _randomgen/doc/source/parallel.rst rename to doc/source/random/parallel.rst diff --git a/_randomgen/doc/source/performance.py b/doc/source/random/performance.py similarity index 100% rename from _randomgen/doc/source/performance.py rename to doc/source/random/performance.py diff --git a/_randomgen/doc/source/performance.rst b/doc/source/random/performance.rst similarity index 100% rename from _randomgen/doc/source/performance.rst rename to doc/source/random/performance.rst diff --git a/_randomgen/doc/source/references.rst b/doc/source/random/references.rst similarity index 100% rename from _randomgen/doc/source/references.rst rename to doc/source/random/references.rst diff --git a/_randomgen/LICENSE.md b/numpy/random/randomgen/LICENSE.md similarity index 100% rename from _randomgen/LICENSE.md rename to numpy/random/randomgen/LICENSE.md diff --git a/_randomgen/randomgen/__init__.py b/numpy/random/randomgen/__init__.py similarity index 100% rename from _randomgen/randomgen/__init__.py rename to numpy/random/randomgen/__init__.py diff --git a/_randomgen/randomgen/_testing.py b/numpy/random/randomgen/_testing.py similarity index 100% rename from _randomgen/randomgen/_testing.py rename to numpy/random/randomgen/_testing.py diff --git a/_randomgen/randomgen/_version.py b/numpy/random/randomgen/_version.py similarity index 100% rename from _randomgen/randomgen/_version.py rename to numpy/random/randomgen/_version.py diff --git a/_randomgen/randomgen/bounded_integers.pxd.in b/numpy/random/randomgen/bounded_integers.pxd.in similarity index 100% rename from _randomgen/randomgen/bounded_integers.pxd.in rename to numpy/random/randomgen/bounded_integers.pxd.in diff --git a/_randomgen/randomgen/bounded_integers.pyx.in b/numpy/random/randomgen/bounded_integers.pyx.in similarity index 100% rename from _randomgen/randomgen/bounded_integers.pyx.in rename to numpy/random/randomgen/bounded_integers.pyx.in diff --git a/_randomgen/randomgen/common.pxd b/numpy/random/randomgen/common.pxd similarity index 100% rename from _randomgen/randomgen/common.pxd rename to numpy/random/randomgen/common.pxd diff --git a/_randomgen/randomgen/common.pyx b/numpy/random/randomgen/common.pyx similarity index 100% rename from _randomgen/randomgen/common.pyx rename to numpy/random/randomgen/common.pyx diff --git a/_randomgen/randomgen/distributions.pxd b/numpy/random/randomgen/distributions.pxd similarity index 100% rename from _randomgen/randomgen/distributions.pxd rename to numpy/random/randomgen/distributions.pxd diff --git a/_randomgen/randomgen/dsfmt.pyx b/numpy/random/randomgen/dsfmt.pyx similarity index 100% rename from _randomgen/randomgen/dsfmt.pyx rename to numpy/random/randomgen/dsfmt.pyx diff --git a/_randomgen/randomgen/entropy.pyx b/numpy/random/randomgen/entropy.pyx similarity index 100% rename from _randomgen/randomgen/entropy.pyx rename to numpy/random/randomgen/entropy.pyx diff --git a/_randomgen/randomgen/examples/cython/extending.pyx b/numpy/random/randomgen/examples/cython/extending.pyx similarity index 100% rename from _randomgen/randomgen/examples/cython/extending.pyx rename to numpy/random/randomgen/examples/cython/extending.pyx diff --git a/_randomgen/randomgen/examples/cython/extending_distributions.pyx b/numpy/random/randomgen/examples/cython/extending_distributions.pyx similarity index 100% rename from _randomgen/randomgen/examples/cython/extending_distributions.pyx rename to numpy/random/randomgen/examples/cython/extending_distributions.pyx diff --git a/_randomgen/randomgen/examples/cython/setup.py b/numpy/random/randomgen/examples/cython/setup.py similarity index 100% rename from _randomgen/randomgen/examples/cython/setup.py rename to numpy/random/randomgen/examples/cython/setup.py diff --git a/_randomgen/randomgen/examples/numba/extending.py b/numpy/random/randomgen/examples/numba/extending.py similarity index 100% rename from _randomgen/randomgen/examples/numba/extending.py rename to numpy/random/randomgen/examples/numba/extending.py diff --git a/_randomgen/randomgen/examples/numba/extending_distributions.py b/numpy/random/randomgen/examples/numba/extending_distributions.py similarity index 100% rename from _randomgen/randomgen/examples/numba/extending_distributions.py rename to numpy/random/randomgen/examples/numba/extending_distributions.py diff --git a/_randomgen/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx similarity index 100% rename from _randomgen/randomgen/generator.pyx rename to numpy/random/randomgen/generator.pyx diff --git a/_randomgen/randomgen/legacy/__init__.py b/numpy/random/randomgen/legacy/__init__.py similarity index 100% rename from _randomgen/randomgen/legacy/__init__.py rename to numpy/random/randomgen/legacy/__init__.py diff --git a/_randomgen/randomgen/legacy/_legacy.pyx b/numpy/random/randomgen/legacy/_legacy.pyx similarity index 100% rename from _randomgen/randomgen/legacy/_legacy.pyx rename to numpy/random/randomgen/legacy/_legacy.pyx diff --git a/_randomgen/randomgen/legacy/legacy.py b/numpy/random/randomgen/legacy/legacy.py similarity index 100% rename from _randomgen/randomgen/legacy/legacy.py rename to numpy/random/randomgen/legacy/legacy.py diff --git a/_randomgen/randomgen/legacy/legacy_distributions.pxd b/numpy/random/randomgen/legacy/legacy_distributions.pxd similarity index 100% rename from _randomgen/randomgen/legacy/legacy_distributions.pxd rename to numpy/random/randomgen/legacy/legacy_distributions.pxd diff --git a/_randomgen/randomgen/mt19937.pyx b/numpy/random/randomgen/mt19937.pyx similarity index 100% rename from _randomgen/randomgen/mt19937.pyx rename to numpy/random/randomgen/mt19937.pyx diff --git a/_randomgen/randomgen/pcg32.pyx b/numpy/random/randomgen/pcg32.pyx similarity index 100% rename from _randomgen/randomgen/pcg32.pyx rename to numpy/random/randomgen/pcg32.pyx diff --git a/_randomgen/randomgen/pcg64.pyx b/numpy/random/randomgen/pcg64.pyx similarity index 100% rename from _randomgen/randomgen/pcg64.pyx rename to numpy/random/randomgen/pcg64.pyx diff --git a/_randomgen/randomgen/philox.pyx b/numpy/random/randomgen/philox.pyx similarity index 100% rename from _randomgen/randomgen/philox.pyx rename to numpy/random/randomgen/philox.pyx diff --git a/_randomgen/randomgen/pickle.py b/numpy/random/randomgen/pickle.py similarity index 100% rename from _randomgen/randomgen/pickle.py rename to numpy/random/randomgen/pickle.py diff --git a/_randomgen/randomgen/src/aligned_malloc/aligned_malloc.c b/numpy/random/randomgen/src/aligned_malloc/aligned_malloc.c similarity index 100% rename from _randomgen/randomgen/src/aligned_malloc/aligned_malloc.c rename to numpy/random/randomgen/src/aligned_malloc/aligned_malloc.c diff --git a/_randomgen/randomgen/src/aligned_malloc/aligned_malloc.h b/numpy/random/randomgen/src/aligned_malloc/aligned_malloc.h similarity index 100% rename from _randomgen/randomgen/src/aligned_malloc/aligned_malloc.h rename to numpy/random/randomgen/src/aligned_malloc/aligned_malloc.h diff --git a/_randomgen/randomgen/src/common/LICENSE.md b/numpy/random/randomgen/src/common/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/common/LICENSE.md rename to numpy/random/randomgen/src/common/LICENSE.md diff --git a/_randomgen/randomgen/src/common/inttypes.h b/numpy/random/randomgen/src/common/inttypes.h similarity index 100% rename from _randomgen/randomgen/src/common/inttypes.h rename to numpy/random/randomgen/src/common/inttypes.h diff --git a/_randomgen/randomgen/src/common/stdint.h b/numpy/random/randomgen/src/common/stdint.h similarity index 100% rename from _randomgen/randomgen/src/common/stdint.h rename to numpy/random/randomgen/src/common/stdint.h diff --git a/_randomgen/randomgen/src/distributions/LICENSE.md b/numpy/random/randomgen/src/distributions/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/distributions/LICENSE.md rename to numpy/random/randomgen/src/distributions/LICENSE.md diff --git a/_randomgen/randomgen/src/distributions/binomial.h b/numpy/random/randomgen/src/distributions/binomial.h similarity index 100% rename from _randomgen/randomgen/src/distributions/binomial.h rename to numpy/random/randomgen/src/distributions/binomial.h diff --git a/_randomgen/randomgen/src/distributions/distributions.c b/numpy/random/randomgen/src/distributions/distributions.c similarity index 100% rename from _randomgen/randomgen/src/distributions/distributions.c rename to numpy/random/randomgen/src/distributions/distributions.c diff --git a/_randomgen/randomgen/src/distributions/distributions.h b/numpy/random/randomgen/src/distributions/distributions.h similarity index 100% rename from _randomgen/randomgen/src/distributions/distributions.h rename to numpy/random/randomgen/src/distributions/distributions.h diff --git a/_randomgen/randomgen/src/distributions/ziggurat.h b/numpy/random/randomgen/src/distributions/ziggurat.h similarity index 100% rename from _randomgen/randomgen/src/distributions/ziggurat.h rename to numpy/random/randomgen/src/distributions/ziggurat.h diff --git a/_randomgen/randomgen/src/distributions/ziggurat_constants.h b/numpy/random/randomgen/src/distributions/ziggurat_constants.h similarity index 100% rename from _randomgen/randomgen/src/distributions/ziggurat_constants.h rename to numpy/random/randomgen/src/distributions/ziggurat_constants.h diff --git a/_randomgen/randomgen/src/dsfmt/128-bit-jump.poly.txt b/numpy/random/randomgen/src/dsfmt/128-bit-jump.poly.txt similarity index 100% rename from _randomgen/randomgen/src/dsfmt/128-bit-jump.poly.txt rename to numpy/random/randomgen/src/dsfmt/128-bit-jump.poly.txt diff --git a/_randomgen/randomgen/src/dsfmt/96-bit-jump.poly.txt b/numpy/random/randomgen/src/dsfmt/96-bit-jump.poly.txt similarity index 100% rename from _randomgen/randomgen/src/dsfmt/96-bit-jump.poly.txt rename to numpy/random/randomgen/src/dsfmt/96-bit-jump.poly.txt diff --git a/_randomgen/randomgen/src/dsfmt/LICENSE.md b/numpy/random/randomgen/src/dsfmt/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/dsfmt/LICENSE.md rename to numpy/random/randomgen/src/dsfmt/LICENSE.md diff --git a/_randomgen/randomgen/src/dsfmt/calc-jump.cpp b/numpy/random/randomgen/src/dsfmt/calc-jump.cpp similarity index 100% rename from _randomgen/randomgen/src/dsfmt/calc-jump.cpp rename to numpy/random/randomgen/src/dsfmt/calc-jump.cpp diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT-benchmark.c b/numpy/random/randomgen/src/dsfmt/dSFMT-benchmark.c similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT-benchmark.c rename to numpy/random/randomgen/src/dsfmt/dSFMT-benchmark.c diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT-calc-jump.hpp b/numpy/random/randomgen/src/dsfmt/dSFMT-calc-jump.hpp similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT-calc-jump.hpp rename to numpy/random/randomgen/src/dsfmt/dSFMT-calc-jump.hpp diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT-common.h b/numpy/random/randomgen/src/dsfmt/dSFMT-common.h similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT-common.h rename to numpy/random/randomgen/src/dsfmt/dSFMT-common.h diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT-jump.c b/numpy/random/randomgen/src/dsfmt/dSFMT-jump.c similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT-jump.c rename to numpy/random/randomgen/src/dsfmt/dSFMT-jump.c diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT-jump.h b/numpy/random/randomgen/src/dsfmt/dSFMT-jump.h similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT-jump.h rename to numpy/random/randomgen/src/dsfmt/dSFMT-jump.h diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT-params.h b/numpy/random/randomgen/src/dsfmt/dSFMT-params.h similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT-params.h rename to numpy/random/randomgen/src/dsfmt/dSFMT-params.h diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT-params19937.h b/numpy/random/randomgen/src/dsfmt/dSFMT-params19937.h similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT-params19937.h rename to numpy/random/randomgen/src/dsfmt/dSFMT-params19937.h diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT-poly.h b/numpy/random/randomgen/src/dsfmt/dSFMT-poly.h similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT-poly.h rename to numpy/random/randomgen/src/dsfmt/dSFMT-poly.h diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT-test-gen.c b/numpy/random/randomgen/src/dsfmt/dSFMT-test-gen.c similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT-test-gen.c rename to numpy/random/randomgen/src/dsfmt/dSFMT-test-gen.c diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT.c b/numpy/random/randomgen/src/dsfmt/dSFMT.c similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT.c rename to numpy/random/randomgen/src/dsfmt/dSFMT.c diff --git a/_randomgen/randomgen/src/dsfmt/dSFMT.h b/numpy/random/randomgen/src/dsfmt/dSFMT.h similarity index 100% rename from _randomgen/randomgen/src/dsfmt/dSFMT.h rename to numpy/random/randomgen/src/dsfmt/dSFMT.h diff --git a/_randomgen/randomgen/src/entropy/LICENSE.md b/numpy/random/randomgen/src/entropy/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/entropy/LICENSE.md rename to numpy/random/randomgen/src/entropy/LICENSE.md diff --git a/_randomgen/randomgen/src/entropy/entropy.c b/numpy/random/randomgen/src/entropy/entropy.c similarity index 100% rename from _randomgen/randomgen/src/entropy/entropy.c rename to numpy/random/randomgen/src/entropy/entropy.c diff --git a/_randomgen/randomgen/src/entropy/entropy.h b/numpy/random/randomgen/src/entropy/entropy.h similarity index 100% rename from _randomgen/randomgen/src/entropy/entropy.h rename to numpy/random/randomgen/src/entropy/entropy.h diff --git a/_randomgen/randomgen/src/legacy/LICENSE.md b/numpy/random/randomgen/src/legacy/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/legacy/LICENSE.md rename to numpy/random/randomgen/src/legacy/LICENSE.md diff --git a/_randomgen/randomgen/src/legacy/distributions-boxmuller.c b/numpy/random/randomgen/src/legacy/distributions-boxmuller.c similarity index 100% rename from _randomgen/randomgen/src/legacy/distributions-boxmuller.c rename to numpy/random/randomgen/src/legacy/distributions-boxmuller.c diff --git a/_randomgen/randomgen/src/legacy/distributions-boxmuller.h b/numpy/random/randomgen/src/legacy/distributions-boxmuller.h similarity index 100% rename from _randomgen/randomgen/src/legacy/distributions-boxmuller.h rename to numpy/random/randomgen/src/legacy/distributions-boxmuller.h diff --git a/_randomgen/randomgen/src/mt19937/LICENSE.md b/numpy/random/randomgen/src/mt19937/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/mt19937/LICENSE.md rename to numpy/random/randomgen/src/mt19937/LICENSE.md diff --git a/_randomgen/randomgen/src/mt19937/mt19937-benchmark.c b/numpy/random/randomgen/src/mt19937/mt19937-benchmark.c similarity index 100% rename from _randomgen/randomgen/src/mt19937/mt19937-benchmark.c rename to numpy/random/randomgen/src/mt19937/mt19937-benchmark.c diff --git a/_randomgen/randomgen/src/mt19937/mt19937-jump.c b/numpy/random/randomgen/src/mt19937/mt19937-jump.c similarity index 100% rename from _randomgen/randomgen/src/mt19937/mt19937-jump.c rename to numpy/random/randomgen/src/mt19937/mt19937-jump.c diff --git a/_randomgen/randomgen/src/mt19937/mt19937-jump.h b/numpy/random/randomgen/src/mt19937/mt19937-jump.h similarity index 100% rename from _randomgen/randomgen/src/mt19937/mt19937-jump.h rename to numpy/random/randomgen/src/mt19937/mt19937-jump.h diff --git a/_randomgen/randomgen/src/mt19937/mt19937-poly.h b/numpy/random/randomgen/src/mt19937/mt19937-poly.h similarity index 100% rename from _randomgen/randomgen/src/mt19937/mt19937-poly.h rename to numpy/random/randomgen/src/mt19937/mt19937-poly.h diff --git a/_randomgen/randomgen/src/mt19937/mt19937-test-data-gen.c b/numpy/random/randomgen/src/mt19937/mt19937-test-data-gen.c similarity index 100% rename from _randomgen/randomgen/src/mt19937/mt19937-test-data-gen.c rename to numpy/random/randomgen/src/mt19937/mt19937-test-data-gen.c diff --git a/_randomgen/randomgen/src/mt19937/mt19937.c b/numpy/random/randomgen/src/mt19937/mt19937.c similarity index 100% rename from _randomgen/randomgen/src/mt19937/mt19937.c rename to numpy/random/randomgen/src/mt19937/mt19937.c diff --git a/_randomgen/randomgen/src/mt19937/mt19937.h b/numpy/random/randomgen/src/mt19937/mt19937.h similarity index 100% rename from _randomgen/randomgen/src/mt19937/mt19937.h rename to numpy/random/randomgen/src/mt19937/mt19937.h diff --git a/_randomgen/randomgen/src/mt19937/randomkit.c b/numpy/random/randomgen/src/mt19937/randomkit.c similarity index 100% rename from _randomgen/randomgen/src/mt19937/randomkit.c rename to numpy/random/randomgen/src/mt19937/randomkit.c diff --git a/_randomgen/randomgen/src/mt19937/randomkit.h b/numpy/random/randomgen/src/mt19937/randomkit.h similarity index 100% rename from _randomgen/randomgen/src/mt19937/randomkit.h rename to numpy/random/randomgen/src/mt19937/randomkit.h diff --git a/_randomgen/randomgen/src/pcg32/LICENSE.md b/numpy/random/randomgen/src/pcg32/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/pcg32/LICENSE.md rename to numpy/random/randomgen/src/pcg32/LICENSE.md diff --git a/_randomgen/randomgen/src/pcg32/pcg-advance-64.c b/numpy/random/randomgen/src/pcg32/pcg-advance-64.c similarity index 100% rename from _randomgen/randomgen/src/pcg32/pcg-advance-64.c rename to numpy/random/randomgen/src/pcg32/pcg-advance-64.c diff --git a/_randomgen/randomgen/src/pcg32/pcg32-test-data-gen.c b/numpy/random/randomgen/src/pcg32/pcg32-test-data-gen.c similarity index 100% rename from _randomgen/randomgen/src/pcg32/pcg32-test-data-gen.c rename to numpy/random/randomgen/src/pcg32/pcg32-test-data-gen.c diff --git a/_randomgen/randomgen/src/pcg32/pcg32.c b/numpy/random/randomgen/src/pcg32/pcg32.c similarity index 100% rename from _randomgen/randomgen/src/pcg32/pcg32.c rename to numpy/random/randomgen/src/pcg32/pcg32.c diff --git a/_randomgen/randomgen/src/pcg32/pcg32.h b/numpy/random/randomgen/src/pcg32/pcg32.h similarity index 100% rename from _randomgen/randomgen/src/pcg32/pcg32.h rename to numpy/random/randomgen/src/pcg32/pcg32.h diff --git a/_randomgen/randomgen/src/pcg32/pcg_variants.h b/numpy/random/randomgen/src/pcg32/pcg_variants.h similarity index 100% rename from _randomgen/randomgen/src/pcg32/pcg_variants.h rename to numpy/random/randomgen/src/pcg32/pcg_variants.h diff --git a/_randomgen/randomgen/src/pcg64/LICENSE.md b/numpy/random/randomgen/src/pcg64/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/pcg64/LICENSE.md rename to numpy/random/randomgen/src/pcg64/LICENSE.md diff --git a/_randomgen/randomgen/src/pcg64/pcg64-benchmark.c b/numpy/random/randomgen/src/pcg64/pcg64-benchmark.c similarity index 100% rename from _randomgen/randomgen/src/pcg64/pcg64-benchmark.c rename to numpy/random/randomgen/src/pcg64/pcg64-benchmark.c diff --git a/_randomgen/randomgen/src/pcg64/pcg64-test-data-gen.c b/numpy/random/randomgen/src/pcg64/pcg64-test-data-gen.c similarity index 100% rename from _randomgen/randomgen/src/pcg64/pcg64-test-data-gen.c rename to numpy/random/randomgen/src/pcg64/pcg64-test-data-gen.c diff --git a/_randomgen/randomgen/src/pcg64/pcg64.c b/numpy/random/randomgen/src/pcg64/pcg64.c similarity index 100% rename from _randomgen/randomgen/src/pcg64/pcg64.c rename to numpy/random/randomgen/src/pcg64/pcg64.c diff --git a/_randomgen/randomgen/src/pcg64/pcg64.h b/numpy/random/randomgen/src/pcg64/pcg64.h similarity index 100% rename from _randomgen/randomgen/src/pcg64/pcg64.h rename to numpy/random/randomgen/src/pcg64/pcg64.h diff --git a/_randomgen/randomgen/src/pcg64/pcg64.orig.c b/numpy/random/randomgen/src/pcg64/pcg64.orig.c similarity index 100% rename from _randomgen/randomgen/src/pcg64/pcg64.orig.c rename to numpy/random/randomgen/src/pcg64/pcg64.orig.c diff --git a/_randomgen/randomgen/src/pcg64/pcg64.orig.h b/numpy/random/randomgen/src/pcg64/pcg64.orig.h similarity index 100% rename from _randomgen/randomgen/src/pcg64/pcg64.orig.h rename to numpy/random/randomgen/src/pcg64/pcg64.orig.h diff --git a/_randomgen/randomgen/src/philox/LICENSE.md b/numpy/random/randomgen/src/philox/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/philox/LICENSE.md rename to numpy/random/randomgen/src/philox/LICENSE.md diff --git a/_randomgen/randomgen/src/philox/philox-benchmark.c b/numpy/random/randomgen/src/philox/philox-benchmark.c similarity index 100% rename from _randomgen/randomgen/src/philox/philox-benchmark.c rename to numpy/random/randomgen/src/philox/philox-benchmark.c diff --git a/_randomgen/randomgen/src/philox/philox-test-data-gen.c b/numpy/random/randomgen/src/philox/philox-test-data-gen.c similarity index 100% rename from _randomgen/randomgen/src/philox/philox-test-data-gen.c rename to numpy/random/randomgen/src/philox/philox-test-data-gen.c diff --git a/_randomgen/randomgen/src/philox/philox.c b/numpy/random/randomgen/src/philox/philox.c similarity index 100% rename from _randomgen/randomgen/src/philox/philox.c rename to numpy/random/randomgen/src/philox/philox.c diff --git a/_randomgen/randomgen/src/philox/philox.h b/numpy/random/randomgen/src/philox/philox.h similarity index 100% rename from _randomgen/randomgen/src/philox/philox.h rename to numpy/random/randomgen/src/philox/philox.h diff --git a/_randomgen/randomgen/src/splitmix64/LICENSE.md b/numpy/random/randomgen/src/splitmix64/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/splitmix64/LICENSE.md rename to numpy/random/randomgen/src/splitmix64/LICENSE.md diff --git a/_randomgen/randomgen/src/splitmix64/splitmix64.c b/numpy/random/randomgen/src/splitmix64/splitmix64.c similarity index 100% rename from _randomgen/randomgen/src/splitmix64/splitmix64.c rename to numpy/random/randomgen/src/splitmix64/splitmix64.c diff --git a/_randomgen/randomgen/src/splitmix64/splitmix64.h b/numpy/random/randomgen/src/splitmix64/splitmix64.h similarity index 100% rename from _randomgen/randomgen/src/splitmix64/splitmix64.h rename to numpy/random/randomgen/src/splitmix64/splitmix64.h diff --git a/_randomgen/randomgen/src/splitmix64/splitmix64.orig.c b/numpy/random/randomgen/src/splitmix64/splitmix64.orig.c similarity index 100% rename from _randomgen/randomgen/src/splitmix64/splitmix64.orig.c rename to numpy/random/randomgen/src/splitmix64/splitmix64.orig.c diff --git a/_randomgen/randomgen/src/threefry/LICENSE.md b/numpy/random/randomgen/src/threefry/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/threefry/LICENSE.md rename to numpy/random/randomgen/src/threefry/LICENSE.md diff --git a/_randomgen/randomgen/src/threefry/threefry-benchmark.c b/numpy/random/randomgen/src/threefry/threefry-benchmark.c similarity index 100% rename from _randomgen/randomgen/src/threefry/threefry-benchmark.c rename to numpy/random/randomgen/src/threefry/threefry-benchmark.c diff --git a/_randomgen/randomgen/src/threefry/threefry-orig.c b/numpy/random/randomgen/src/threefry/threefry-orig.c similarity index 100% rename from _randomgen/randomgen/src/threefry/threefry-orig.c rename to numpy/random/randomgen/src/threefry/threefry-orig.c diff --git a/_randomgen/randomgen/src/threefry/threefry-test-data-gen.c b/numpy/random/randomgen/src/threefry/threefry-test-data-gen.c similarity index 100% rename from _randomgen/randomgen/src/threefry/threefry-test-data-gen.c rename to numpy/random/randomgen/src/threefry/threefry-test-data-gen.c diff --git a/_randomgen/randomgen/src/threefry/threefry.c b/numpy/random/randomgen/src/threefry/threefry.c similarity index 100% rename from _randomgen/randomgen/src/threefry/threefry.c rename to numpy/random/randomgen/src/threefry/threefry.c diff --git a/_randomgen/randomgen/src/threefry/threefry.h b/numpy/random/randomgen/src/threefry/threefry.h similarity index 100% rename from _randomgen/randomgen/src/threefry/threefry.h rename to numpy/random/randomgen/src/threefry/threefry.h diff --git a/_randomgen/randomgen/src/threefry32/LICENSE.md b/numpy/random/randomgen/src/threefry32/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/threefry32/LICENSE.md rename to numpy/random/randomgen/src/threefry32/LICENSE.md diff --git a/_randomgen/randomgen/src/threefry32/threefry32-test-data-gen.c b/numpy/random/randomgen/src/threefry32/threefry32-test-data-gen.c similarity index 100% rename from _randomgen/randomgen/src/threefry32/threefry32-test-data-gen.c rename to numpy/random/randomgen/src/threefry32/threefry32-test-data-gen.c diff --git a/_randomgen/randomgen/src/threefry32/threefry32.c b/numpy/random/randomgen/src/threefry32/threefry32.c similarity index 100% rename from _randomgen/randomgen/src/threefry32/threefry32.c rename to numpy/random/randomgen/src/threefry32/threefry32.c diff --git a/_randomgen/randomgen/src/threefry32/threefry32.h b/numpy/random/randomgen/src/threefry32/threefry32.h similarity index 100% rename from _randomgen/randomgen/src/threefry32/threefry32.h rename to numpy/random/randomgen/src/threefry32/threefry32.h diff --git a/_randomgen/randomgen/src/xoroshiro128/LICENSE.md b/numpy/random/randomgen/src/xoroshiro128/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/xoroshiro128/LICENSE.md rename to numpy/random/randomgen/src/xoroshiro128/LICENSE.md diff --git a/_randomgen/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c similarity index 100% rename from _randomgen/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c rename to numpy/random/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c diff --git a/_randomgen/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c similarity index 100% rename from _randomgen/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c rename to numpy/random/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c diff --git a/_randomgen/randomgen/src/xoroshiro128/xoroshiro128.c b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.c similarity index 100% rename from _randomgen/randomgen/src/xoroshiro128/xoroshiro128.c rename to numpy/random/randomgen/src/xoroshiro128/xoroshiro128.c diff --git a/_randomgen/randomgen/src/xoroshiro128/xoroshiro128.h b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.h similarity index 100% rename from _randomgen/randomgen/src/xoroshiro128/xoroshiro128.h rename to numpy/random/randomgen/src/xoroshiro128/xoroshiro128.h diff --git a/_randomgen/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c similarity index 100% rename from _randomgen/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c rename to numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c diff --git a/_randomgen/randomgen/src/xoroshiro128/xoroshiro128plus.orig.h b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.h similarity index 100% rename from _randomgen/randomgen/src/xoroshiro128/xoroshiro128plus.orig.h rename to numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.h diff --git a/_randomgen/randomgen/src/xorshift1024/LICENSE.md b/numpy/random/randomgen/src/xorshift1024/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/xorshift1024/LICENSE.md rename to numpy/random/randomgen/src/xorshift1024/LICENSE.md diff --git a/_randomgen/randomgen/src/xorshift1024/xorshift1024-benchmark.c b/numpy/random/randomgen/src/xorshift1024/xorshift1024-benchmark.c similarity index 100% rename from _randomgen/randomgen/src/xorshift1024/xorshift1024-benchmark.c rename to numpy/random/randomgen/src/xorshift1024/xorshift1024-benchmark.c diff --git a/_randomgen/randomgen/src/xorshift1024/xorshift1024-test-data-gen.c b/numpy/random/randomgen/src/xorshift1024/xorshift1024-test-data-gen.c similarity index 100% rename from _randomgen/randomgen/src/xorshift1024/xorshift1024-test-data-gen.c rename to numpy/random/randomgen/src/xorshift1024/xorshift1024-test-data-gen.c diff --git a/_randomgen/randomgen/src/xorshift1024/xorshift1024.c b/numpy/random/randomgen/src/xorshift1024/xorshift1024.c similarity index 100% rename from _randomgen/randomgen/src/xorshift1024/xorshift1024.c rename to numpy/random/randomgen/src/xorshift1024/xorshift1024.c diff --git a/_randomgen/randomgen/src/xorshift1024/xorshift1024.h b/numpy/random/randomgen/src/xorshift1024/xorshift1024.h similarity index 100% rename from _randomgen/randomgen/src/xorshift1024/xorshift1024.h rename to numpy/random/randomgen/src/xorshift1024/xorshift1024.h diff --git a/_randomgen/randomgen/src/xorshift1024/xorshift1024.orig.c b/numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.c similarity index 100% rename from _randomgen/randomgen/src/xorshift1024/xorshift1024.orig.c rename to numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.c diff --git a/_randomgen/randomgen/src/xorshift1024/xorshift1024.orig.h b/numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.h similarity index 100% rename from _randomgen/randomgen/src/xorshift1024/xorshift1024.orig.h rename to numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.h diff --git a/_randomgen/randomgen/src/xoshiro256starstar/LICENSE.md b/numpy/random/randomgen/src/xoshiro256starstar/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/xoshiro256starstar/LICENSE.md rename to numpy/random/randomgen/src/xoshiro256starstar/LICENSE.md diff --git a/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c b/numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c similarity index 100% rename from _randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c rename to numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c diff --git a/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.c b/numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.c similarity index 100% rename from _randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.c rename to numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.c diff --git a/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.h b/numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.h similarity index 100% rename from _randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.h rename to numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.h diff --git a/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c b/numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c similarity index 100% rename from _randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c rename to numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c diff --git a/_randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h b/numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h similarity index 100% rename from _randomgen/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h rename to numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h diff --git a/_randomgen/randomgen/src/xoshiro512starstar/LICENSE.md b/numpy/random/randomgen/src/xoshiro512starstar/LICENSE.md similarity index 100% rename from _randomgen/randomgen/src/xoshiro512starstar/LICENSE.md rename to numpy/random/randomgen/src/xoshiro512starstar/LICENSE.md diff --git a/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c b/numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c similarity index 100% rename from _randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c rename to numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c diff --git a/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.c b/numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.c similarity index 100% rename from _randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.c rename to numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.c diff --git a/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.h b/numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.h similarity index 100% rename from _randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.h rename to numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.h diff --git a/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c b/numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c similarity index 100% rename from _randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c rename to numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c diff --git a/_randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h b/numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h similarity index 100% rename from _randomgen/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h rename to numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h diff --git a/_randomgen/randomgen/tests/__init__.py b/numpy/random/randomgen/tests/__init__.py similarity index 100% rename from _randomgen/randomgen/tests/__init__.py rename to numpy/random/randomgen/tests/__init__.py diff --git a/_randomgen/randomgen/tests/data/__init__.py b/numpy/random/randomgen/tests/data/__init__.py similarity index 100% rename from _randomgen/randomgen/tests/data/__init__.py rename to numpy/random/randomgen/tests/data/__init__.py diff --git a/_randomgen/randomgen/tests/data/dSFMT-testset-1.csv b/numpy/random/randomgen/tests/data/dSFMT-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/dSFMT-testset-1.csv rename to numpy/random/randomgen/tests/data/dSFMT-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/dSFMT-testset-2.csv b/numpy/random/randomgen/tests/data/dSFMT-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/dSFMT-testset-2.csv rename to numpy/random/randomgen/tests/data/dSFMT-testset-2.csv diff --git a/_randomgen/randomgen/tests/data/mt19937-testset-1.csv b/numpy/random/randomgen/tests/data/mt19937-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/mt19937-testset-1.csv rename to numpy/random/randomgen/tests/data/mt19937-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/mt19937-testset-2.csv b/numpy/random/randomgen/tests/data/mt19937-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/mt19937-testset-2.csv rename to numpy/random/randomgen/tests/data/mt19937-testset-2.csv diff --git a/_randomgen/randomgen/tests/data/pcg32-testset-1.csv b/numpy/random/randomgen/tests/data/pcg32-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/pcg32-testset-1.csv rename to numpy/random/randomgen/tests/data/pcg32-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/pcg32-testset-2.csv b/numpy/random/randomgen/tests/data/pcg32-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/pcg32-testset-2.csv rename to numpy/random/randomgen/tests/data/pcg32-testset-2.csv diff --git a/_randomgen/randomgen/tests/data/pcg64-testset-1.csv b/numpy/random/randomgen/tests/data/pcg64-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/pcg64-testset-1.csv rename to numpy/random/randomgen/tests/data/pcg64-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/pcg64-testset-2.csv b/numpy/random/randomgen/tests/data/pcg64-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/pcg64-testset-2.csv rename to numpy/random/randomgen/tests/data/pcg64-testset-2.csv diff --git a/_randomgen/randomgen/tests/data/philox-testset-1.csv b/numpy/random/randomgen/tests/data/philox-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/philox-testset-1.csv rename to numpy/random/randomgen/tests/data/philox-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/philox-testset-2.csv b/numpy/random/randomgen/tests/data/philox-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/philox-testset-2.csv rename to numpy/random/randomgen/tests/data/philox-testset-2.csv diff --git a/_randomgen/randomgen/tests/data/threefry-testset-1.csv b/numpy/random/randomgen/tests/data/threefry-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/threefry-testset-1.csv rename to numpy/random/randomgen/tests/data/threefry-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/threefry-testset-2.csv b/numpy/random/randomgen/tests/data/threefry-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/threefry-testset-2.csv rename to numpy/random/randomgen/tests/data/threefry-testset-2.csv diff --git a/_randomgen/randomgen/tests/data/threefry32-testset-1.csv b/numpy/random/randomgen/tests/data/threefry32-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/threefry32-testset-1.csv rename to numpy/random/randomgen/tests/data/threefry32-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/threefry32-testset-2.csv b/numpy/random/randomgen/tests/data/threefry32-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/threefry32-testset-2.csv rename to numpy/random/randomgen/tests/data/threefry32-testset-2.csv diff --git a/_randomgen/randomgen/tests/data/xoroshiro128-testset-1.csv b/numpy/random/randomgen/tests/data/xoroshiro128-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/xoroshiro128-testset-1.csv rename to numpy/random/randomgen/tests/data/xoroshiro128-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/xoroshiro128-testset-2.csv b/numpy/random/randomgen/tests/data/xoroshiro128-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/xoroshiro128-testset-2.csv rename to numpy/random/randomgen/tests/data/xoroshiro128-testset-2.csv diff --git a/_randomgen/randomgen/tests/data/xorshift1024-testset-1.csv b/numpy/random/randomgen/tests/data/xorshift1024-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/xorshift1024-testset-1.csv rename to numpy/random/randomgen/tests/data/xorshift1024-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/xorshift1024-testset-2.csv b/numpy/random/randomgen/tests/data/xorshift1024-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/xorshift1024-testset-2.csv rename to numpy/random/randomgen/tests/data/xorshift1024-testset-2.csv diff --git a/_randomgen/randomgen/tests/data/xoshiro256starstar-testset-1.csv b/numpy/random/randomgen/tests/data/xoshiro256starstar-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/xoshiro256starstar-testset-1.csv rename to numpy/random/randomgen/tests/data/xoshiro256starstar-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/xoshiro256starstar-testset-2.csv b/numpy/random/randomgen/tests/data/xoshiro256starstar-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/xoshiro256starstar-testset-2.csv rename to numpy/random/randomgen/tests/data/xoshiro256starstar-testset-2.csv diff --git a/_randomgen/randomgen/tests/data/xoshiro512starstar-testset-1.csv b/numpy/random/randomgen/tests/data/xoshiro512starstar-testset-1.csv similarity index 100% rename from _randomgen/randomgen/tests/data/xoshiro512starstar-testset-1.csv rename to numpy/random/randomgen/tests/data/xoshiro512starstar-testset-1.csv diff --git a/_randomgen/randomgen/tests/data/xoshiro512starstar-testset-2.csv b/numpy/random/randomgen/tests/data/xoshiro512starstar-testset-2.csv similarity index 100% rename from _randomgen/randomgen/tests/data/xoshiro512starstar-testset-2.csv rename to numpy/random/randomgen/tests/data/xoshiro512starstar-testset-2.csv diff --git a/_randomgen/randomgen/tests/test_against_numpy.py b/numpy/random/randomgen/tests/test_against_numpy.py similarity index 100% rename from _randomgen/randomgen/tests/test_against_numpy.py rename to numpy/random/randomgen/tests/test_against_numpy.py diff --git a/_randomgen/randomgen/tests/test_direct.py b/numpy/random/randomgen/tests/test_direct.py similarity index 100% rename from _randomgen/randomgen/tests/test_direct.py rename to numpy/random/randomgen/tests/test_direct.py diff --git a/_randomgen/randomgen/tests/test_legacy.py b/numpy/random/randomgen/tests/test_legacy.py similarity index 100% rename from _randomgen/randomgen/tests/test_legacy.py rename to numpy/random/randomgen/tests/test_legacy.py diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937.py b/numpy/random/randomgen/tests/test_numpy_mt19937.py similarity index 100% rename from _randomgen/randomgen/tests/test_numpy_mt19937.py rename to numpy/random/randomgen/tests/test_numpy_mt19937.py diff --git a/_randomgen/randomgen/tests/test_numpy_mt19937_regressions.py b/numpy/random/randomgen/tests/test_numpy_mt19937_regressions.py similarity index 100% rename from _randomgen/randomgen/tests/test_numpy_mt19937_regressions.py rename to numpy/random/randomgen/tests/test_numpy_mt19937_regressions.py diff --git a/_randomgen/randomgen/tests/test_smoke.py b/numpy/random/randomgen/tests/test_smoke.py similarity index 100% rename from _randomgen/randomgen/tests/test_smoke.py rename to numpy/random/randomgen/tests/test_smoke.py diff --git a/_randomgen/randomgen/threefry.pyx b/numpy/random/randomgen/threefry.pyx similarity index 100% rename from _randomgen/randomgen/threefry.pyx rename to numpy/random/randomgen/threefry.pyx diff --git a/_randomgen/randomgen/threefry32.pyx b/numpy/random/randomgen/threefry32.pyx similarity index 100% rename from _randomgen/randomgen/threefry32.pyx rename to numpy/random/randomgen/threefry32.pyx diff --git a/_randomgen/randomgen/xoroshiro128.pyx b/numpy/random/randomgen/xoroshiro128.pyx similarity index 100% rename from _randomgen/randomgen/xoroshiro128.pyx rename to numpy/random/randomgen/xoroshiro128.pyx diff --git a/_randomgen/randomgen/xorshift1024.pyx b/numpy/random/randomgen/xorshift1024.pyx similarity index 100% rename from _randomgen/randomgen/xorshift1024.pyx rename to numpy/random/randomgen/xorshift1024.pyx diff --git a/_randomgen/randomgen/xoshiro256starstar.pyx b/numpy/random/randomgen/xoshiro256starstar.pyx similarity index 100% rename from _randomgen/randomgen/xoshiro256starstar.pyx rename to numpy/random/randomgen/xoshiro256starstar.pyx diff --git a/_randomgen/randomgen/xoshiro512starstar.pyx b/numpy/random/randomgen/xoshiro512starstar.pyx similarity index 100% rename from _randomgen/randomgen/xoshiro512starstar.pyx rename to numpy/random/randomgen/xoshiro512starstar.pyx From e927920185800cb069180e3d607dd38ebba47147 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 20 Mar 2019 15:57:11 +0200 Subject: [PATCH 195/279] BUILD: first cut at building randomgen --- .gitignore | 3 + LICENSE.txt | 5 + .../random/randomgen/bounded_integers.pxd.in | 2 +- .../random/randomgen/bounded_integers.pyx.in | 2 +- numpy/random/randomgen/common.pxd | 2 +- numpy/random/randomgen/common.pyx | 4 +- numpy/random/randomgen/dsfmt.pyx | 14 +- numpy/random/randomgen/mt19937.pyx | 14 +- numpy/random/randomgen/philox.pyx | 10 +- numpy/random/randomgen/threefry.pyx | 14 +- numpy/random/randomgen/xoshiro512starstar.pyx | 14 +- .../{randomgen => randomgen_ignore}/pcg32.pyx | 0 .../{randomgen => randomgen_ignore}/pcg64.pyx | 2 +- numpy/random/setup.py | 138 +++++++++++++++++- setup.py | 13 +- tools/cythonize.py | 2 +- 16 files changed, 192 insertions(+), 47 deletions(-) rename numpy/random/{randomgen => randomgen_ignore}/pcg32.pyx (100%) rename numpy/random/{randomgen => randomgen_ignore}/pcg64.pyx (99%) diff --git a/.gitignore b/.gitignore index a31d6ea44bd1..e1f694dc922b 100644 --- a/.gitignore +++ b/.gitignore @@ -175,4 +175,7 @@ benchmarks/numpy # cythonized files cythonize.dat numpy/random/mtrand/mtrand.c +numpy/random/randomgen/*.c numpy/random/mtrand/randint_helpers.pxi +numpy/random/randomgen/bounded_integers.pyx +numpy/random/randomgen/bounded_integers.pxd diff --git a/LICENSE.txt b/LICENSE.txt index b9731f734f58..91f0d1aabc38 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -58,3 +58,8 @@ Name: dragon4 Files: numpy/core/src/multiarray/dragon4.c License: One of a kind For license text, see numpy/core/src/multiarray/dragon4.c + +Name: randomgen +Files: numpy/random/randomgen and docs/source/random +Licence: NCSA + For license text, see numpy/random/randomgen/LICENSE.md diff --git a/numpy/random/randomgen/bounded_integers.pxd.in b/numpy/random/randomgen/bounded_integers.pxd.in index 5f723733cca6..41bf1a178923 100644 --- a/numpy/random/randomgen/bounded_integers.pxd.in +++ b/numpy/random/randomgen/bounded_integers.pxd.in @@ -6,7 +6,7 @@ import numpy as np cimport numpy as np ctypedef np.npy_bool bool_t -from randomgen.common cimport brng_t +from .common cimport brng_t _randint_types = {'bool': (0, 2), 'int8': (-2**7, 2**7), diff --git a/numpy/random/randomgen/bounded_integers.pyx.in b/numpy/random/randomgen/bounded_integers.pyx.in index eb8555b310d0..d66f09c42d4d 100644 --- a/numpy/random/randomgen/bounded_integers.pyx.in +++ b/numpy/random/randomgen/bounded_integers.pyx.in @@ -5,7 +5,7 @@ from __future__ import absolute_import import numpy as np cimport numpy as np -from randomgen.distributions cimport * +from .distributions cimport * np.import_array() diff --git a/numpy/random/randomgen/common.pxd b/numpy/random/randomgen/common.pxd index 63a1b3f7d09f..99c53a210fa9 100644 --- a/numpy/random/randomgen/common.pxd +++ b/numpy/random/randomgen/common.pxd @@ -7,7 +7,7 @@ from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t) from libc.math cimport sqrt -from randomgen.distributions cimport brng_t +from .distributions cimport brng_t import numpy as np cimport numpy as np diff --git a/numpy/random/randomgen/common.pyx b/numpy/random/randomgen/common.pyx index 41d3074f352f..28658dd51acf 100644 --- a/numpy/random/randomgen/common.pyx +++ b/numpy/random/randomgen/common.pyx @@ -8,7 +8,7 @@ import sys import numpy as np cimport numpy as np -from randomgen.common cimport * +from .common cimport * np.import_array() @@ -803,4 +803,4 @@ cdef object cont_f(void *func, brng_t *state, object size, object lock, if out is None: return randoms else: - return out \ No newline at end of file + return out diff --git a/numpy/random/randomgen/dsfmt.pyx b/numpy/random/randomgen/dsfmt.pyx index ee8ef270d000..ff488f754412 100644 --- a/numpy/random/randomgen/dsfmt.pyx +++ b/numpy/random/randomgen/dsfmt.pyx @@ -7,11 +7,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy -import randomgen.pickle +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy +from .pickle import __brng_ctor np.import_array() @@ -172,7 +172,7 @@ cdef class DSFMT: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + return (__brng_ctor, (self.state['brng'],), self.state) @@ -401,4 +401,4 @@ cdef class DSFMT: if self._generator is None: from .generator import RandomGenerator self._generator = RandomGenerator(self) - return self._generator \ No newline at end of file + return self._generator diff --git a/numpy/random/randomgen/mt19937.pyx b/numpy/random/randomgen/mt19937.pyx index c88dd02b9686..02ef133a2d44 100644 --- a/numpy/random/randomgen/mt19937.pyx +++ b/numpy/random/randomgen/mt19937.pyx @@ -8,11 +8,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy -import randomgen.pickle +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy +from .pickle import __brng_ctor np.import_array() @@ -153,7 +153,7 @@ cdef class MT19937: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + return (__brng_ctor, (self.state['brng'],), self.state) @@ -379,4 +379,4 @@ cdef class MT19937: if self._generator is None: from .generator import RandomGenerator self._generator = RandomGenerator(self) - return self._generator \ No newline at end of file + return self._generator diff --git a/numpy/random/randomgen/philox.pyx b/numpy/random/randomgen/philox.pyx index 26ece5e14b2c..3d813e5286b6 100644 --- a/numpy/random/randomgen/philox.pyx +++ b/numpy/random/randomgen/philox.pyx @@ -5,10 +5,10 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy, seed_by_array +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy, seed_by_array import randomgen.pickle np.import_array() @@ -474,4 +474,4 @@ cdef class Philox: if self._generator is None: from .generator import RandomGenerator self._generator = RandomGenerator(self) - return self._generator \ No newline at end of file + return self._generator diff --git a/numpy/random/randomgen/threefry.pyx b/numpy/random/randomgen/threefry.pyx index 96e65f62529e..36f3537dba3f 100644 --- a/numpy/random/randomgen/threefry.pyx +++ b/numpy/random/randomgen/threefry.pyx @@ -5,11 +5,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy, seed_by_array -import randomgen.pickle +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy, seed_by_array +from .pickle import __brng_ctor np.import_array() @@ -190,7 +190,7 @@ cdef class ThreeFry: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + return (__brng_ctor, (self.state['brng'],), self.state) @@ -467,4 +467,4 @@ cdef class ThreeFry: if self._generator is None: from .generator import RandomGenerator self._generator = RandomGenerator(self) - return self._generator \ No newline at end of file + return self._generator diff --git a/numpy/random/randomgen/xoshiro512starstar.pyx b/numpy/random/randomgen/xoshiro512starstar.pyx index 17fe3c420192..4fc16c5e14e8 100644 --- a/numpy/random/randomgen/xoshiro512starstar.pyx +++ b/numpy/random/randomgen/xoshiro512starstar.pyx @@ -6,11 +6,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy, seed_by_array -import randomgen.pickle +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy, seed_by_array +from .pickle import __brng_ctor np.import_array() @@ -154,7 +154,7 @@ cdef class Xoshiro512StarStar: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + return (__brng_ctor, (self.state['brng'],), self.state) @@ -353,4 +353,4 @@ cdef class Xoshiro512StarStar: if self._generator is None: from .generator import RandomGenerator self._generator = RandomGenerator(self) - return self._generator \ No newline at end of file + return self._generator diff --git a/numpy/random/randomgen/pcg32.pyx b/numpy/random/randomgen_ignore/pcg32.pyx similarity index 100% rename from numpy/random/randomgen/pcg32.pyx rename to numpy/random/randomgen_ignore/pcg32.pyx diff --git a/numpy/random/randomgen/pcg64.pyx b/numpy/random/randomgen_ignore/pcg64.pyx similarity index 99% rename from numpy/random/randomgen/pcg64.pyx rename to numpy/random/randomgen_ignore/pcg64.pyx index 44e123d4ca24..cad132f048aa 100644 --- a/numpy/random/randomgen/pcg64.pyx +++ b/numpy/random/randomgen_ignore/pcg64.pyx @@ -460,4 +460,4 @@ cdef class PCG64: if self._generator is None: from .generator import RandomGenerator self._generator = RandomGenerator(self) - return self._generator \ No newline at end of file + return self._generator diff --git a/numpy/random/setup.py b/numpy/random/setup.py index 394a70ead371..75833c5cd843 100644 --- a/numpy/random/setup.py +++ b/numpy/random/setup.py @@ -2,6 +2,8 @@ from os.path import join import sys +import os +import platform from distutils.dep_util import newer from distutils.msvccompiler import get_build_version as get_msvc_build_version @@ -16,6 +18,7 @@ def needs_mingw_ftime_workaround(): return False + def configuration(parent_package='',top_path=None): from numpy.distutils.misc_util import Configuration, get_mathlibs config = Configuration('random', parent_package, top_path) @@ -55,9 +58,142 @@ def generate_libraries(ext, build_dir): config.add_data_files(('.', join('mtrand', 'randomkit.h'))) config.add_data_dir('tests') - return config + ############################## + # randomgen + ############################## + + # Make a guess as to whether SSE2 is present for now, TODO: Improve + USE_SSE2 = False + for k in platform.uname(): + for val in ('x86', 'i686', 'i386', 'amd64'): + USE_SSE2 = USE_SSE2 or val in k.lower() + print('Building with SSE?: {0}'.format(USE_SSE2)) + if '--no-sse2' in sys.argv: + USE_SSE2 = False + sys.argv.remove('--no-sse2') + DEBUG = False + PCG_EMULATED_MATH = False + EXTRA_LINK_ARGS = [] + EXTRA_LIBRARIES = ['m'] if os.name != 'nt' else [] + EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else [ + '-std=c99', '-U__GNUC_GNU_INLINE__'] + if os.name == 'nt': + EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] + if DEBUG: + EXTRA_LINK_ARGS += ['-debug'] + EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] + if sys.version_info < (3, 0): + EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] + # + # PCG64_DEFS = [] + # if sys.maxsize < 2 ** 32 or os.name == 'nt': + # # Force emulated mode here + # PCG_EMULATED_MATH = True + # PCG64_DEFS += [('PCG_FORCE_EMULATED_128BIT_MATH', '1')] + # + # if struct.calcsize('P') < 8: + # PCG_EMULATED_MATH = True + # defs.append(('PCG_EMULATED_MATH', int(PCG_EMULATED_MATH))) + + DSFMT_DEFS = [('DSFMT_MEXP', '19937')] + if USE_SSE2: + if os.name == 'nt': + EXTRA_COMPILE_ARGS += ['/wd4146', '/GL'] + if struct.calcsize('P') < 8: + EXTRA_COMPILE_ARGS += ['/arch:SSE2'] + else: + EXTRA_COMPILE_ARGS += ['-msse2'] + DSFMT_DEFS += [('HAVE_SSE2', '1')] + + config.add_extension('randomgen.entropy', + sources=[join('randomgen', x) for x in + ['entropy.c', 'src/entropy/entropy.c']], + include_dirs=[join('randomgen', 'src', 'entropy')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('randomgen', 'src', 'splitmix64', 'splitmix.h'), + join('randomgen', 'src', 'entropy', 'entropy.h'), + join('randomgen', 'entropy.pyx'), + ], + define_macros=defs, + ) + config.add_extension('randomgen.dsfmt', + sources=[join('randomgen', x) for x in + ['dsfmt.c', 'src/dsfmt/dSFMT.c', + 'src/dsfmt/DSFMT-jump.c', + 'src/aligned_malloc/allignd_malloc.c']], + include_dirs=[join('randomgen', 'src', 'dsfmt')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('randomgen', 'src', 'dsfmt', 'dsfmt.h'), + join('randomgen', 'dsfmt.pyx'), + ], + define_macros=defs + DSFMT_DEFS, + ) + config.add_extension('randomgen.legacy._legacy', + sources=[join('randomgen', x) for x in + ['legacy/_legacy.c', + 'src/legacy/distributions-boxmuller.c', + 'src/distributions/distributions.c' ]], + include_dirs=[join('randomgen', 'legacy')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('randomgen', 'legacy', '_legacy.pyx')], + define_macros=defs + DSFMT_DEFS, + ) + for gen in ['mt19937']: + # gen.pyx, src/gen/gen.c, src/gen/gen-jump.c + config.add_extension('randomgen.%s' % gen, + sources=[join('randomgen', x) for x in + ['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen), + 'src/{0}/{0}-jump.c'.format(gen)]], + include_dirs=[join('randomgen', 'src', gen)], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('randomgen', '%s.pyx' % gen)], + ) + for gen in ['philox', 'threefry', 'threefry32', + 'xoroshiro128', 'xorshift1024', 'xoshiro256starstar', + 'xoshiro512starstar', + # 'pcg64', 'pcg32', + ]: + # gen.pyx, src/gen/gen.c + config.add_extension('randomgen.%s' % gen, + sources=[join('randomgen', x) for x in + ['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen)]], + include_dirs=[join('randomgen', 'src', gen)], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('randomgen', '%s.pyx' % gen)], + ) + for gen in ['common']: + # gen.pyx + config.add_extension('randomgen.%s' % gen, + sources=[join('randomgen', '{0}.c'.format(gen))], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('randomgen', '%s.pyx' % gen)], + ) + for gen in ['generator', 'bounded_integers']: + # gen.pyx, src/distributions/distributions.c + config.add_extension('randomgen.%s' % gen, + sources=[join('randomgen', '{0}.c'.format(gen)), + join('randomgen', 'src', 'distributions', + 'distributions.c')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('randomgen', '%s.pyx' % gen)], + ) + return config if __name__ == '__main__': from numpy.distutils.core import setup setup(configuration=configuration) diff --git a/setup.py b/setup.py index da25ddde5928..f7d6f9e0fe68 100755 --- a/setup.py +++ b/setup.py @@ -197,12 +197,13 @@ def run(self): def generate_cython(): cwd = os.path.abspath(os.path.dirname(__file__)) print("Cythonizing sources") - p = subprocess.call([sys.executable, - os.path.join(cwd, 'tools', 'cythonize.py'), - 'numpy/random'], - cwd=cwd) - if p != 0: - raise RuntimeError("Running cythonize failed!") + for d in ('mtrand', 'randomgen'): + p = subprocess.call([sys.executable, + os.path.join(cwd, 'tools', 'cythonize.py'), + 'numpy/random/{0}'.format(d)], + cwd=cwd) + if p != 0: + raise RuntimeError("Running cythonize failed!") def parse_setuppy_commands(): diff --git a/tools/cythonize.py b/tools/cythonize.py index 9e2af840dff5..5a202e0588a3 100755 --- a/tools/cythonize.py +++ b/tools/cythonize.py @@ -52,7 +52,7 @@ # Rules # def process_pyx(fromfile, tofile): - flags = ['--fast-fail'] + flags = ['-3', '--fast-fail'] if tofile.endswith('.cxx'): flags += ['--cplus'] From 0adab5552d0d9e11f855e6be6b703a5d11048236 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 21 Mar 2019 13:18:01 +0200 Subject: [PATCH 196/279] upgrade 'cythonize' and fix absolute imports to relative --- numpy/random/randomgen/generator.pyx | 14 ++--- numpy/random/randomgen/legacy/_legacy.pyx | 12 ++-- .../randomgen/legacy/legacy_distributions.pxd | 2 +- numpy/random/randomgen/threefry32.pyx | 12 ++-- numpy/random/randomgen/xoroshiro128.pyx | 14 ++--- numpy/random/randomgen/xorshift1024.pyx | 14 ++--- numpy/random/randomgen/xoshiro256starstar.pyx | 14 ++--- .../examples/cython/extending.pyx | 0 .../cython/extending_distributions.pyx | 0 .../examples/cython/setup.py | 0 .../examples/numba/extending.py | 0 .../examples/numba/extending_distributions.py | 0 numpy/random/setup.py | 7 ++- tools/cythonize.py | 63 ++++++++++++------- 14 files changed, 86 insertions(+), 66 deletions(-) rename numpy/random/{randomgen => randomgen_ignore}/examples/cython/extending.pyx (100%) rename numpy/random/{randomgen => randomgen_ignore}/examples/cython/extending_distributions.pyx (100%) rename numpy/random/{randomgen => randomgen_ignore}/examples/cython/setup.py (100%) rename numpy/random/{randomgen => randomgen_ignore}/examples/numba/extending.py (100%) rename numpy/random/{randomgen => randomgen_ignore}/examples/numba/extending_distributions.py (100%) diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index 6a68a1905b5c..41cb2a57d515 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -19,11 +19,11 @@ try: except ImportError: from dummy_threading import Lock -from randomgen.bounded_integers cimport * -from randomgen.common cimport * -from randomgen.distributions cimport * -from randomgen.xoroshiro128 import Xoroshiro128 -import randomgen.pickle +from .bounded_integers cimport * +from .common cimport * +from .distributions cimport * +from .xoroshiro128 import Xoroshiro128 +from .pickle import __generator_ctor np.import_array() @@ -128,7 +128,7 @@ cdef class RandomGenerator: self.state = state def __reduce__(self): - return (randomgen.pickle.__generator_ctor, + return (__generator_ctor, (self.state['brng'],), self.state) @@ -4440,4 +4440,4 @@ uniform = _random_generator.uniform vonmises = _random_generator.vonmises wald = _random_generator.wald weibull = _random_generator.weibull -zipf = _random_generator.zipf \ No newline at end of file +zipf = _random_generator.zipf diff --git a/numpy/random/randomgen/legacy/_legacy.pyx b/numpy/random/randomgen/legacy/_legacy.pyx index 9db3867781ae..1201fe313dea 100644 --- a/numpy/random/randomgen/legacy/_legacy.pyx +++ b/numpy/random/randomgen/legacy/_legacy.pyx @@ -16,11 +16,11 @@ try: except ImportError: from dummy_threading import Lock -from randomgen.common cimport cont, disc, CONS_NONE, CONS_POSITIVE, CONS_NON_NEGATIVE, CONS_BOUNDED_0_1 -from randomgen.distributions cimport brng_t -from randomgen.legacy.legacy_distributions cimport * -from randomgen.xoroshiro128 import Xoroshiro128 -import randomgen.pickle +from ..common cimport cont, disc, CONS_NONE, CONS_POSITIVE, CONS_NON_NEGATIVE, CONS_BOUNDED_0_1 +from ..distributions cimport brng_t +from .legacy_distributions cimport * +from ..xoroshiro128 import Xoroshiro128 +from ..pickle import __legacy_ctor np.import_array() @@ -119,7 +119,7 @@ cdef class _LegacyGenerator: self.state = state def __reduce__(self): - return (randomgen.pickle.__legacy_ctor, + return (__legacy_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/legacy/legacy_distributions.pxd b/numpy/random/randomgen/legacy/legacy_distributions.pxd index e2157f70605f..ab33d4a9da5c 100644 --- a/numpy/random/randomgen/legacy/legacy_distributions.pxd +++ b/numpy/random/randomgen/legacy/legacy_distributions.pxd @@ -5,7 +5,7 @@ from libc.stdint cimport uint64_t import numpy as np cimport numpy as np -from randomgen.distributions cimport brng_t +from ..distributions cimport brng_t cdef extern from "../src/legacy/distributions-boxmuller.h": diff --git a/numpy/random/randomgen/threefry32.pyx b/numpy/random/randomgen/threefry32.pyx index 62c0e9cd8c92..ac0d556011f6 100644 --- a/numpy/random/randomgen/threefry32.pyx +++ b/numpy/random/randomgen/threefry32.pyx @@ -4,11 +4,11 @@ import numpy as np from cpython.pycapsule cimport PyCapsule_New from libc.stdlib cimport malloc, free -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy, seed_by_array -import randomgen.pickle +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy, seed_by_array +from .pickle import __brng_ctor np.import_array() @@ -192,7 +192,7 @@ cdef class ThreeFry32: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/xoroshiro128.pyx b/numpy/random/randomgen/xoroshiro128.pyx index 57760c53a7a1..c075435ffa0e 100644 --- a/numpy/random/randomgen/xoroshiro128.pyx +++ b/numpy/random/randomgen/xoroshiro128.pyx @@ -6,11 +6,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy, seed_by_array -import randomgen.pickle +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy, seed_by_array +from .pickle import __brng_ctor np.import_array() @@ -154,7 +154,7 @@ cdef class Xoroshiro128: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + return (__brng_ctor, (self.state['brng'],), self.state) @@ -353,4 +353,4 @@ cdef class Xoroshiro128: if self._generator is None: from .generator import RandomGenerator self._generator = RandomGenerator(self) - return self._generator \ No newline at end of file + return self._generator diff --git a/numpy/random/randomgen/xorshift1024.pyx b/numpy/random/randomgen/xorshift1024.pyx index e7ad546e0ea6..029e59c4e029 100644 --- a/numpy/random/randomgen/xorshift1024.pyx +++ b/numpy/random/randomgen/xorshift1024.pyx @@ -6,11 +6,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy, seed_by_array -import randomgen.pickle +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy, seed_by_array +from .pickle import __brng_ctor np.import_array() @@ -160,7 +160,7 @@ cdef class Xorshift1024: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + return (__brng_ctor, (self.state['brng'],), self.state) @@ -386,4 +386,4 @@ cdef class Xorshift1024: if self._generator is None: from .generator import RandomGenerator self._generator = RandomGenerator(self) - return self._generator \ No newline at end of file + return self._generator diff --git a/numpy/random/randomgen/xoshiro256starstar.pyx b/numpy/random/randomgen/xoshiro256starstar.pyx index 33ecb50f1a88..e0db49dfcbaf 100644 --- a/numpy/random/randomgen/xoshiro256starstar.pyx +++ b/numpy/random/randomgen/xoshiro256starstar.pyx @@ -6,11 +6,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy, seed_by_array -import randomgen.pickle +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy, seed_by_array +from .pickle import __brng_ctor np.import_array() @@ -154,7 +154,7 @@ cdef class Xoshiro256StarStar: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + return (__brng_ctor, (self.state['brng'],), self.state) @@ -359,4 +359,4 @@ cdef class Xoshiro256StarStar: if self._generator is None: from .generator import RandomGenerator self._generator = RandomGenerator(self) - return self._generator \ No newline at end of file + return self._generator diff --git a/numpy/random/randomgen/examples/cython/extending.pyx b/numpy/random/randomgen_ignore/examples/cython/extending.pyx similarity index 100% rename from numpy/random/randomgen/examples/cython/extending.pyx rename to numpy/random/randomgen_ignore/examples/cython/extending.pyx diff --git a/numpy/random/randomgen/examples/cython/extending_distributions.pyx b/numpy/random/randomgen_ignore/examples/cython/extending_distributions.pyx similarity index 100% rename from numpy/random/randomgen/examples/cython/extending_distributions.pyx rename to numpy/random/randomgen_ignore/examples/cython/extending_distributions.pyx diff --git a/numpy/random/randomgen/examples/cython/setup.py b/numpy/random/randomgen_ignore/examples/cython/setup.py similarity index 100% rename from numpy/random/randomgen/examples/cython/setup.py rename to numpy/random/randomgen_ignore/examples/cython/setup.py diff --git a/numpy/random/randomgen/examples/numba/extending.py b/numpy/random/randomgen_ignore/examples/numba/extending.py similarity index 100% rename from numpy/random/randomgen/examples/numba/extending.py rename to numpy/random/randomgen_ignore/examples/numba/extending.py diff --git a/numpy/random/randomgen/examples/numba/extending_distributions.py b/numpy/random/randomgen_ignore/examples/numba/extending_distributions.py similarity index 100% rename from numpy/random/randomgen/examples/numba/extending_distributions.py rename to numpy/random/randomgen_ignore/examples/numba/extending_distributions.py diff --git a/numpy/random/setup.py b/numpy/random/setup.py index 75833c5cd843..ffd19f9a48cb 100644 --- a/numpy/random/setup.py +++ b/numpy/random/setup.py @@ -4,6 +4,7 @@ import sys import os import platform +import struct from distutils.dep_util import newer from distutils.msvccompiler import get_build_version as get_msvc_build_version @@ -123,8 +124,8 @@ def generate_libraries(ext, build_dir): config.add_extension('randomgen.dsfmt', sources=[join('randomgen', x) for x in ['dsfmt.c', 'src/dsfmt/dSFMT.c', - 'src/dsfmt/DSFMT-jump.c', - 'src/aligned_malloc/allignd_malloc.c']], + 'src/dsfmt/dSFMT-jump.c', + 'src/aligned_malloc/aligned_malloc.c']], include_dirs=[join('randomgen', 'src', 'dsfmt')], libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, @@ -139,7 +140,7 @@ def generate_libraries(ext, build_dir): ['legacy/_legacy.c', 'src/legacy/distributions-boxmuller.c', 'src/distributions/distributions.c' ]], - include_dirs=[join('randomgen', 'legacy')], + include_dirs=['randomgen', join('randomgen', 'legacy')], libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, diff --git a/tools/cythonize.py b/tools/cythonize.py index 5a202e0588a3..da54c549ccde 100755 --- a/tools/cythonize.py +++ b/tools/cythonize.py @@ -99,6 +99,17 @@ def process_tempita_pyx(fromfile, tofile): process_pyx(pyxfile, tofile) +def process_tempita_pyd(fromfile, tofile): + import npy_tempita as tempita + + assert fromfile.endswith('.pxd.in') + assert tofile.endswith('.pxd') + with open(fromfile, "r") as f: + tmpl = f.read() + pyxcontent = tempita.sub(tmpl) + with open(tofile, "w") as f: + f.write(pyxcontent) + def process_tempita_pxi(fromfile, tofile): import npy_tempita as tempita @@ -110,10 +121,24 @@ def process_tempita_pxi(fromfile, tofile): with open(tofile, "w") as f: f.write(pyxcontent) +def process_tempita_pxd(fromfile, tofile): + import npy_tempita as tempita + + assert fromfile.endswith('.pxd.in') + assert tofile.endswith('.pxd') + with open(fromfile, "r") as f: + tmpl = f.read() + pyxcontent = tempita.sub(tmpl) + with open(tofile, "w") as f: + f.write(pyxcontent) + rules = { - # fromext : function - '.pyx' : process_pyx, - '.pyx.in' : process_tempita_pyx + # fromext : function, toext + '.pyx' : (process_pyx, '.c'), + '.pyx.in' : (process_tempita_pyx, '.c'), + '.pxi.in' : (process_tempita_pxi, '.pxi'), + '.pxd.in' : (process_tempita_pxd, '.pxd'), + '.pyd.in' : (process_tempita_pyd, '.pyd'), } # # Hash db @@ -183,34 +208,28 @@ def find_process_files(root_dir): # .pxi or .pxi.in files are most likely dependencies for # .pyx files, so we need to process them first files.sort(key=lambda name: (name.endswith('.pxi') or - name.endswith('.pxi.in')), + name.endswith('.pxi.in') or + name.endswith('.pxd.in')), reverse=True) for filename in files: in_file = os.path.join(cur_dir, filename + ".in") - if filename.endswith('.pyx') and os.path.isfile(in_file): - continue - elif filename.endswith('.pxi.in'): - toext = '.pxi' - fromext = '.pxi.in' - fromfile = filename - function = process_tempita_pxi - tofile = filename[:-len(fromext)] + toext - process(cur_dir, fromfile, tofile, function, hash_db) - save_hashes(hash_db, HASH_FILE) - else: - for fromext, function in rules.items(): - if filename.endswith(fromext): - toext = ".c" + for fromext, value in rules.items(): + if filename.endswith(fromext): + if not value: + break + function, toext = value + if toext == '.c': with open(os.path.join(cur_dir, filename), 'rb') as f: data = f.read() m = re.search(br"^\s*#\s*distutils:\s*language\s*=\s*c\+\+\s*$", data, re.I|re.M) if m: toext = ".cxx" - fromfile = filename - tofile = filename[:-len(fromext)] + toext - process(cur_dir, fromfile, tofile, function, hash_db) - save_hashes(hash_db, HASH_FILE) + fromfile = filename + tofile = filename[:-len(fromext)] + toext + process(cur_dir, fromfile, tofile, function, hash_db) + save_hashes(hash_db, HASH_FILE) + break def main(): try: From d3017129336ba055b3c718ba16ec8333f4947eac Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 21 Mar 2019 13:58:27 +0200 Subject: [PATCH 197/279] DOC, BUILD: fail the devdoc build if there are warnings --- doc/DISTUTILS.rst.txt | 6 +----- doc/Makefile | 3 ++- doc/release/1.17.0-notes.rst | 10 +++++----- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/doc/DISTUTILS.rst.txt b/doc/DISTUTILS.rst.txt index 3cb8121769f0..42aa9561d4f3 100644 --- a/doc/DISTUTILS.rst.txt +++ b/doc/DISTUTILS.rst.txt @@ -319,11 +319,7 @@ and :c:data:`/**end repeat**/` lines, which may also be nested using consecutively numbered delimiting lines such as :c:data:`/**begin repeat1` and :c:data:`/**end repeat1**/`. String replacement specifications are started and terminated using :c:data:`#`. This may be clearer in the following -template source example: - -.. code-block:: C - :linenos: - :emphasize-lines: 3, 13, 29, 31 +template source example:: /* TIMEDELTA to non-float types */ diff --git a/doc/Makefile b/doc/Makefile index cb8f8a397fd1..c70111385bd8 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -20,7 +20,8 @@ FILES= # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +ALLSPHINXOPTS = -WT --keep-going -d build/doctrees $(PAPEROPT_$(PAPER)) \ + $(SPHINXOPTS) source .PHONY: help clean html web pickle htmlhelp latex changes linkcheck \ dist dist-build gitwash-update diff --git a/doc/release/1.17.0-notes.rst b/doc/release/1.17.0-notes.rst index b9b27da7924e..ccb44d32c75c 100644 --- a/doc/release/1.17.0-notes.rst +++ b/doc/release/1.17.0-notes.rst @@ -18,11 +18,11 @@ New functions Deprecations ============ -``np.polynomial`` functions warn when passed ``float``s in place of ``int``s ----------------------------------------------------------------------------- -Previously functions in this module would accept ``float``s provided their -values were integral. For consistency with the rest of numpy, doing so is now -deprecated, and in future will raise a ``TypeError``. +``np.polynomial`` functions warn when passed ``float`` in place of ``int`` +-------------------------------------------------------------------------- +Previously functions in this module would accept ``float`` values provided they +were integral (``1.0``, ``2.0``, etc). For consistency with the rest of numpy, +doing so is now deprecated, and in future will raise a ``TypeError``. Similarly, passing a float like ``0.5`` in place of an integer will now raise a ``TypeError`` instead of the previous ``ValueError``. From 601421b339b011b23748da62a3cad0d598f84936 Mon Sep 17 00:00:00 2001 From: Mircea Akos Bruma Date: Thu, 21 Mar 2019 16:12:25 +0100 Subject: [PATCH 198/279] DOC: Attempting to remove duplicate documentation. --- doc/source/reference/c-api.array.rst | 7 ++++++- doc/source/user/c-info.how-to-extend.rst | 20 ++++++-------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/doc/source/reference/c-api.array.rst b/doc/source/reference/c-api.array.rst index ee2be9e071df..7d6942f75490 100644 --- a/doc/source/reference/c-api.array.rst +++ b/doc/source/reference/c-api.array.rst @@ -510,6 +510,11 @@ From other objects :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_WRITEABLE` \| :c:data:`NPY_ARRAY_ALIGNED` + .. c:var:: NPY_ARRAY_OUT_ARRAY + + :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED` \| + :c:data:`NPY_ARRAY_WRITEABLE` + .. c:var:: NPY_ARRAY_OUT_FARRAY :c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_WRITEABLE` \| @@ -789,7 +794,7 @@ From other objects PyObject* obj, int typenum, int requirements) Combination of :c:func:`PyArray_FROM_OF` and :c:func:`PyArray_FROM_OT` - allowing both a *typenum* and a *flags* argument to be provided.. + allowing both a *typenum* and a *flags* argument to be provided. .. c:function:: PyObject* PyArray_FROMANY( \ PyObject* obj, int typenum, int min, int max, int requirements) diff --git a/doc/source/user/c-info.how-to-extend.rst b/doc/source/user/c-info.how-to-extend.rst index 8016cfcbda3c..b70036c894fa 100644 --- a/doc/source/user/c-info.how-to-extend.rst +++ b/doc/source/user/c-info.how-to-extend.rst @@ -447,17 +447,13 @@ writeable). The syntax is :c:data:`NPY_ARRAY_IN_ARRAY` - Equivalent to :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| - :c:data:`NPY_ARRAY_ALIGNED`. This combination of flags is useful - for arrays that must be in C-contiguous order and aligned. - These kinds of arrays are usually input arrays for some - algorithm. + This flag is useful for arrays that must be in C-contiguous + order and aligned. These kinds of arrays are usually input + arrays for some algorithm. - .. c:var:: NPY_ARRAY_OUT_ARRAY + :c:data:`NPY_ARRAY_OUT_ARRAY` - Equivalent to :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| - :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE`. This - combination of flags is useful to specify an array that is + This flag is useful to specify an array that is in C-contiguous order, is aligned, and can be written to as well. Such an array is usually returned as output (although normally such output arrays are created from @@ -465,11 +461,7 @@ writeable). The syntax is :c:data:`NPY_ARRAY_INOUT_ARRAY` - Equivalent to :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| - :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE` \| - :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` \| - :c:data:`NPY_ARRAY_UPDATEIFCOPY`. This combination of flags is - useful to specify an array that will be used for both + This flag is useful to specify an array that will be used for both input and output. :c:func:`PyArray_ResolveWritebackIfCopy` must be called before :func:`Py_DECREF` at the end of the interface routine to write back the temporary data From d07975943677a8164983326da0a1f8bad54f891e Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 21 Mar 2019 16:52:06 +0200 Subject: [PATCH 199/279] MAINT: define NPY_NO_DEPRECATED_API and fix other warnings --- .gitignore | 1 + numpy/random/mtrand/initarray.c | 1 - numpy/random/mtrand/numpy.pxd | 2 -- .../randomgen/src/distributions/distributions.c | 12 ++++++------ numpy/random/setup.py | 5 +++++ 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index e1f694dc922b..8926a73bd62c 100644 --- a/.gitignore +++ b/.gitignore @@ -176,6 +176,7 @@ benchmarks/numpy cythonize.dat numpy/random/mtrand/mtrand.c numpy/random/randomgen/*.c +numpy/random/randomgen/legacy/*.c numpy/random/mtrand/randint_helpers.pxi numpy/random/randomgen/bounded_integers.pyx numpy/random/randomgen/bounded_integers.pxd diff --git a/numpy/random/mtrand/initarray.c b/numpy/random/mtrand/initarray.c index 21f1dc05a931..beff7851002a 100644 --- a/numpy/random/mtrand/initarray.c +++ b/numpy/random/mtrand/initarray.c @@ -71,7 +71,6 @@ * http://www.math.keio.ac.jp/matumoto/emt.html * email: matumoto@math.keio.ac.jp */ -#define NPY_NO_DEPRECATED_API NPY_API_VERSION #include "initarray.h" diff --git a/numpy/random/mtrand/numpy.pxd b/numpy/random/mtrand/numpy.pxd index 1b4fe6c10491..e146054b117d 100644 --- a/numpy/random/mtrand/numpy.pxd +++ b/numpy/random/mtrand/numpy.pxd @@ -3,8 +3,6 @@ # :Author: Travis Oliphant from cpython.exc cimport PyErr_Print -cdef extern from "numpy/npy_no_deprecated_api.h": pass - cdef extern from "numpy/arrayobject.h": cdef enum NPY_TYPES: diff --git a/numpy/random/randomgen/src/distributions/distributions.c b/numpy/random/randomgen/src/distributions/distributions.c index a9d8a308d98f..10c195ae4d23 100644 --- a/numpy/random/randomgen/src/distributions/distributions.c +++ b/numpy/random/randomgen/src/distributions/distributions.c @@ -41,7 +41,7 @@ void random_double_fill(brng_t *brng_state, npy_intp cnt, double *out) { out[i] = next_double(brng_state); } } -/* +#if 0 double random_gauss(brng_t *brng_state) { if (brng_state->has_gauss) { const double temp = brng_state->gauss; @@ -57,9 +57,9 @@ double random_gauss(brng_t *brng_state) { r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); - /* Polar method, a more efficient version of the Box-Muller approach. + /* Polar method, a more efficient version of the Box-Muller approach. */ f = sqrt(-2.0 * log(r2) / r2); - /* Keep for next call + /* Keep for next call */ brng_state->gauss = f * x1; brng_state->has_gauss = true; return f * x2; @@ -81,15 +81,15 @@ float random_gauss_f(brng_t *brng_state) { r2 = x1 * x1 + x2 * x2; } while (r2 >= 1.0 || r2 == 0.0); - /* Polar method, a more efficient version of the Box-Muller approach. + /* Polar method, a more efficient version of the Box-Muller approach. */ f = sqrtf(-2.0f * logf(r2) / r2); - /* Keep for next call + /* Keep for next call */ brng_state->gauss_f = f * x1; brng_state->has_gauss_f = true; return f * x2; } } -*/ +#endif static NPY_INLINE double standard_exponential_zig(brng_t *brng_state); diff --git a/numpy/random/setup.py b/numpy/random/setup.py index ffd19f9a48cb..ac3f8611c178 100644 --- a/numpy/random/setup.py +++ b/numpy/random/setup.py @@ -44,6 +44,7 @@ def generate_libraries(ext, build_dir): defs.append(("NPY_NEEDS_MINGW_TIME_WORKAROUND", None)) libs = [] + defs.append(('NPY_NO_DEPRECATED_API', 0)) # Configure mtrand config.add_extension('mtrand', sources=[join('mtrand', x) for x in @@ -158,6 +159,7 @@ def generate_libraries(ext, build_dir): extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, depends=[join('randomgen', '%s.pyx' % gen)], + define_macros=defs, ) for gen in ['philox', 'threefry', 'threefry32', 'xoroshiro128', 'xorshift1024', 'xoshiro256starstar', @@ -173,6 +175,7 @@ def generate_libraries(ext, build_dir): extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, depends=[join('randomgen', '%s.pyx' % gen)], + define_macros=defs, ) for gen in ['common']: # gen.pyx @@ -182,6 +185,7 @@ def generate_libraries(ext, build_dir): extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, depends=[join('randomgen', '%s.pyx' % gen)], + define_macros=defs, ) for gen in ['generator', 'bounded_integers']: # gen.pyx, src/distributions/distributions.c @@ -193,6 +197,7 @@ def generate_libraries(ext, build_dir): extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, depends=[join('randomgen', '%s.pyx' % gen)], + define_macros=defs, ) return config if __name__ == '__main__': From 67dbbf726003b68eebe44fcba952b6f13048779e Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 22 Mar 2019 14:30:33 +0200 Subject: [PATCH 200/279] MAINT: enable pgc64 by always using PCG_EMULATED_MATH --- .../{randomgen_ignore => randomgen}/pcg32.pyx | 14 ++-- .../{randomgen_ignore => randomgen}/pcg64.pyx | 66 +++++++++---------- numpy/random/setup.py | 27 ++++---- 3 files changed, 55 insertions(+), 52 deletions(-) rename numpy/random/{randomgen_ignore => randomgen}/pcg32.pyx (98%) rename numpy/random/{randomgen_ignore => randomgen}/pcg64.pyx (90%) diff --git a/numpy/random/randomgen_ignore/pcg32.pyx b/numpy/random/randomgen/pcg32.pyx similarity index 98% rename from numpy/random/randomgen_ignore/pcg32.pyx rename to numpy/random/randomgen/pcg32.pyx index 5c83b1040b1d..28d6fc1205a4 100644 --- a/numpy/random/randomgen_ignore/pcg32.pyx +++ b/numpy/random/randomgen/pcg32.pyx @@ -6,11 +6,11 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy -import randomgen.pickle +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy +from .pickle import __brng_ctor np.import_array() @@ -151,7 +151,7 @@ cdef class PCG32: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + return (__brng_ctor, (self.state['brng'],), self.state) @@ -407,4 +407,4 @@ cdef class PCG32: if self._generator is None: from .generator import RandomGenerator self._generator = RandomGenerator(self) - return self._generator \ No newline at end of file + return self._generator diff --git a/numpy/random/randomgen_ignore/pcg64.pyx b/numpy/random/randomgen/pcg64.pyx similarity index 90% rename from numpy/random/randomgen_ignore/pcg64.pyx rename to numpy/random/randomgen/pcg64.pyx index cad132f048aa..04935c814625 100644 --- a/numpy/random/randomgen_ignore/pcg64.pyx +++ b/numpy/random/randomgen/pcg64.pyx @@ -6,26 +6,26 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from randomgen.common import interface -from randomgen.common cimport * -from randomgen.distributions cimport brng_t -from randomgen.entropy import random_entropy -import randomgen.pickle +from .common import interface +from .common cimport * +from .distributions cimport brng_t +from .entropy import random_entropy +from .pickle import __brng_ctor np.import_array() -IF PCG_EMULATED_MATH==1: - cdef extern from "src/pcg64/pcg64.h": - - ctypedef struct pcg128_t: - uint64_t high - uint64_t low -ELSE: - cdef extern from "inttypes.h": - ctypedef unsigned long long __uint128_t +# IF PCG_EMULATED_MATH==1: +cdef extern from "src/pcg64/pcg64.h": - cdef extern from "src/pcg64/pcg64.h": - ctypedef __uint128_t pcg128_t + ctypedef struct pcg128_t: + uint64_t high + uint64_t low +# ELSE: +# cdef extern from "inttypes.h": +# ctypedef unsigned long long __uint128_t +# +# cdef extern from "src/pcg64/pcg64.h": +# ctypedef __uint128_t pcg128_t cdef extern from "src/pcg64/pcg64.h": @@ -162,7 +162,7 @@ cdef class PCG64: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + return (__brng_ctor, (self.state['brng'],), self.state) @@ -277,14 +277,14 @@ cdef class PCG64: Dictionary containing the information required to describe the state of the RNG """ - IF PCG_EMULATED_MATH==1: - state = 2 **64 * self.rng_state.pcg_state.state.high - state += self.rng_state.pcg_state.state.low - inc = 2 **64 * self.rng_state.pcg_state.inc.high - inc += self.rng_state.pcg_state.inc.low - ELSE: - state = self.rng_state.pcg_state.state - inc = self.rng_state.pcg_state.inc + # IF PCG_EMULATED_MATH==1: + state = 2 **64 * self.rng_state.pcg_state.state.high + state += self.rng_state.pcg_state.state.low + inc = 2 **64 * self.rng_state.pcg_state.inc.high + inc += self.rng_state.pcg_state.inc.low + # ELSE: + # state = self.rng_state.pcg_state.state + # inc = self.rng_state.pcg_state.inc return {'brng': self.__class__.__name__, 'state': {'state': state, 'inc':inc}, @@ -299,14 +299,14 @@ cdef class PCG64: if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'RNG'.format(self.__class__.__name__)) - IF PCG_EMULATED_MATH==1: - self.rng_state.pcg_state.state.high = value['state']['state'] // 2 ** 64 - self.rng_state.pcg_state.state.low = value['state']['state'] % 2 ** 64 - self.rng_state.pcg_state.inc.high = value['state']['inc'] // 2 ** 64 - self.rng_state.pcg_state.inc.low = value['state']['inc'] % 2 ** 64 - ELSE: - self.rng_state.pcg_state.state = value['state']['state'] - self.rng_state.pcg_state.inc = value['state']['inc'] + # IF PCG_EMULATED_MATH==1: + self.rng_state.pcg_state.state.high = value['state']['state'] // 2 ** 64 + self.rng_state.pcg_state.state.low = value['state']['state'] % 2 ** 64 + self.rng_state.pcg_state.inc.high = value['state']['inc'] // 2 ** 64 + self.rng_state.pcg_state.inc.low = value['state']['inc'] % 2 ** 64 + # ELSE: + # self.rng_state.pcg_state.state = value['state']['state'] + # self.rng_state.pcg_state.inc = value['state']['inc'] self.rng_state.has_uint32 = value['has_uint32'] self.rng_state.uinteger = value['uinteger'] diff --git a/numpy/random/setup.py b/numpy/random/setup.py index ac3f8611c178..dd3c8fbab541 100644 --- a/numpy/random/setup.py +++ b/numpy/random/setup.py @@ -88,16 +88,15 @@ def generate_libraries(ext, build_dir): if sys.version_info < (3, 0): EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] - # - # PCG64_DEFS = [] - # if sys.maxsize < 2 ** 32 or os.name == 'nt': - # # Force emulated mode here - # PCG_EMULATED_MATH = True - # PCG64_DEFS += [('PCG_FORCE_EMULATED_128BIT_MATH', '1')] - # - # if struct.calcsize('P') < 8: - # PCG_EMULATED_MATH = True - # defs.append(('PCG_EMULATED_MATH', int(PCG_EMULATED_MATH))) + PCG64_DEFS = [] + if 1 or sys.maxsize < 2 ** 32 or os.name == 'nt': + # Force emulated mode here + PCG_EMULATED_MATH = True + PCG64_DEFS += [('PCG_FORCE_EMULATED_128BIT_MATH', '1')] + + if struct.calcsize('P') < 8: + PCG_EMULATED_MATH = True + defs.append(('PCG_EMULATED_MATH', int(PCG_EMULATED_MATH))) DSFMT_DEFS = [('DSFMT_MEXP', '19937')] if USE_SSE2: @@ -164,9 +163,13 @@ def generate_libraries(ext, build_dir): for gen in ['philox', 'threefry', 'threefry32', 'xoroshiro128', 'xorshift1024', 'xoshiro256starstar', 'xoshiro512starstar', - # 'pcg64', 'pcg32', + 'pcg64', 'pcg32', ]: # gen.pyx, src/gen/gen.c + if gen == 'pcg64': + _defs = defs + PCG64_DEFS + else: + _defs = defs config.add_extension('randomgen.%s' % gen, sources=[join('randomgen', x) for x in ['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen)]], @@ -175,7 +178,7 @@ def generate_libraries(ext, build_dir): extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, depends=[join('randomgen', '%s.pyx' % gen)], - define_macros=defs, + define_macros=_defs, ) for gen in ['common']: # gen.pyx From ca1a5090a2c99340ae44c0a590efdfddbc80bef6 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 22 Mar 2019 17:54:39 +0200 Subject: [PATCH 201/279] MAINT: refactor so import randomgen works --- numpy/random/randomgen/__init__.py | 30 +-- .../randomgen/{pickle.py => _pickle.py} | 50 ++--- numpy/random/randomgen/dsfmt.pyx | 2 +- numpy/random/randomgen/generator.pyx | 2 +- numpy/random/randomgen/mt19937.pyx | 2 +- numpy/random/randomgen/pcg32.pyx | 2 +- numpy/random/randomgen/pcg64.pyx | 2 +- numpy/random/randomgen/philox.pyx | 5 +- numpy/random/randomgen/setup.py | 190 ++++++++++++++++++ .../randomgen/tests/test_against_numpy.py | 2 +- numpy/random/randomgen/threefry.pyx | 2 +- numpy/random/randomgen/threefry32.pyx | 2 +- numpy/random/randomgen/xoroshiro128.pyx | 2 +- numpy/random/randomgen/xorshift1024.pyx | 2 +- numpy/random/randomgen/xoshiro256starstar.pyx | 2 +- numpy/random/randomgen/xoshiro512starstar.pyx | 2 +- numpy/random/setup.py | 144 +------------ 17 files changed, 247 insertions(+), 196 deletions(-) rename numpy/random/randomgen/{pickle.py => _pickle.py} (71%) create mode 100644 numpy/random/randomgen/setup.py diff --git a/numpy/random/randomgen/__init__.py b/numpy/random/randomgen/__init__.py index b4c942c8fa8d..2a4e20bbc43a 100644 --- a/numpy/random/randomgen/__init__.py +++ b/numpy/random/randomgen/__init__.py @@ -1,22 +1,22 @@ -from randomgen.dsfmt import DSFMT -from randomgen.generator import RandomGenerator -from randomgen.mt19937 import MT19937 -from randomgen.pcg32 import PCG32 -from randomgen.pcg64 import PCG64 -from randomgen.philox import Philox -from randomgen.threefry import ThreeFry -from randomgen.threefry32 import ThreeFry32 -from randomgen.xoroshiro128 import Xoroshiro128 -from randomgen.xorshift1024 import Xorshift1024 -from randomgen.xoshiro256starstar import Xoshiro256StarStar -from randomgen.xoshiro512starstar import Xoshiro512StarStar +from .dsfmt import DSFMT +from .generator import RandomGenerator +from .mt19937 import MT19937 +from .pcg32 import PCG32 +from .pcg64 import PCG64 +from .philox import Philox +from .threefry import ThreeFry +from .threefry32 import ThreeFry32 +from .xoroshiro128 import Xoroshiro128 +from .xorshift1024 import Xorshift1024 +from .xoshiro256starstar import Xoshiro256StarStar +from .xoshiro512starstar import Xoshiro512StarStar __all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'PCG32', 'Philox', 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024', 'Xoshiro256StarStar', 'Xoshiro512StarStar', 'hypergeometric', 'multinomial', 'random_sample'] -from ._version import get_versions +#from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions +#__version__ = get_versions()['version'] +#del get_versions diff --git a/numpy/random/randomgen/pickle.py b/numpy/random/randomgen/_pickle.py similarity index 71% rename from numpy/random/randomgen/pickle.py rename to numpy/random/randomgen/_pickle.py index 4dde4c2c85ec..0d7aece69546 100644 --- a/numpy/random/randomgen/pickle.py +++ b/numpy/random/randomgen/_pickle.py @@ -1,29 +1,29 @@ from .generator import RandomGenerator -from .dsfmt import DSFMT -from .mt19937 import MT19937 -from randomgen.pcg32 import PCG32 -from randomgen.pcg64 import PCG64 -from randomgen.philox import Philox -from randomgen.threefry import ThreeFry -from randomgen.threefry32 import ThreeFry32 -from randomgen.xoroshiro128 import Xoroshiro128 -from randomgen.xorshift1024 import Xorshift1024 -from randomgen.xoshiro256starstar import Xoshiro256StarStar -from randomgen.xoshiro512starstar import Xoshiro512StarStar -from randomgen.legacy import LegacyGenerator - -BasicRNGS = {'MT19937': MT19937, - 'DSFMT': DSFMT, - 'PCG32': PCG32, - 'PCG64': PCG64, - 'Philox': Philox, - 'ThreeFry': ThreeFry, - 'ThreeFry32': ThreeFry32, - 'Xorshift1024': Xorshift1024, - 'Xoroshiro128': Xoroshiro128, - 'Xoshiro256StarStar': Xoshiro256StarStar, - 'Xoshiro512StarStar': Xoshiro512StarStar, - } +# from .dsfmt import DSFMT +# from .mt19937 import MT19937 +# from .pcg32 import PCG32 +# from .pcg64 import PCG64 +# from .philox import Philox +# from .threefry import ThreeFry +# from .threefry32 import ThreeFry32 +# from .xoroshiro128 import Xoroshiro128 +# from .xorshift1024 import Xorshift1024 +# from .xoshiro256starstar import Xoshiro256StarStar +# from .xoshiro512starstar import Xoshiro512StarStar +# from .legacy import LegacyGenerator +# +# BasicRNGS = {'MT19937': MT19937, +# 'DSFMT': DSFMT, +# 'PCG32': PCG32, +# 'PCG64': PCG64, +# 'Philox': Philox, +# 'ThreeFry': ThreeFry, +# 'ThreeFry32': ThreeFry32, +# 'Xorshift1024': Xorshift1024, +# 'Xoroshiro128': Xoroshiro128, +# 'Xoshiro256StarStar': Xoshiro256StarStar, +# 'Xoshiro512StarStar': Xoshiro512StarStar, +# } def __generator_ctor(brng_name='mt19937'): diff --git a/numpy/random/randomgen/dsfmt.pyx b/numpy/random/randomgen/dsfmt.pyx index ff488f754412..2c4bfabe6937 100644 --- a/numpy/random/randomgen/dsfmt.pyx +++ b/numpy/random/randomgen/dsfmt.pyx @@ -11,7 +11,6 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy -from .pickle import __brng_ctor np.import_array() @@ -172,6 +171,7 @@ cdef class DSFMT: self.state = state def __reduce__(self): + from ._pickle import __brng_ctor return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index 41cb2a57d515..3739bdc44d3e 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -23,7 +23,6 @@ from .bounded_integers cimport * from .common cimport * from .distributions cimport * from .xoroshiro128 import Xoroshiro128 -from .pickle import __generator_ctor np.import_array() @@ -128,6 +127,7 @@ cdef class RandomGenerator: self.state = state def __reduce__(self): + from ._pickle import __generator_ctor return (__generator_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/mt19937.pyx b/numpy/random/randomgen/mt19937.pyx index 02ef133a2d44..cd69974eda7f 100644 --- a/numpy/random/randomgen/mt19937.pyx +++ b/numpy/random/randomgen/mt19937.pyx @@ -12,7 +12,6 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy -from .pickle import __brng_ctor np.import_array() @@ -153,6 +152,7 @@ cdef class MT19937: self.state = state def __reduce__(self): + from ._pickle import __brng_ctor return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/pcg32.pyx b/numpy/random/randomgen/pcg32.pyx index 28d6fc1205a4..ef2668d98384 100644 --- a/numpy/random/randomgen/pcg32.pyx +++ b/numpy/random/randomgen/pcg32.pyx @@ -10,7 +10,6 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy -from .pickle import __brng_ctor np.import_array() @@ -151,6 +150,7 @@ cdef class PCG32: self.state = state def __reduce__(self): + from ._pickle import __brng_ctor return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/pcg64.pyx b/numpy/random/randomgen/pcg64.pyx index 04935c814625..24850b583cdc 100644 --- a/numpy/random/randomgen/pcg64.pyx +++ b/numpy/random/randomgen/pcg64.pyx @@ -10,7 +10,6 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy -from .pickle import __brng_ctor np.import_array() @@ -162,6 +161,7 @@ cdef class PCG64: self.state = state def __reduce__(self): + from ._pickle import __brng_ctor return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/philox.pyx b/numpy/random/randomgen/philox.pyx index 3d813e5286b6..a40cd3e251c6 100644 --- a/numpy/random/randomgen/philox.pyx +++ b/numpy/random/randomgen/philox.pyx @@ -9,7 +9,7 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array -import randomgen.pickle + np.import_array() @@ -195,7 +195,8 @@ cdef class Philox: self.state = state def __reduce__(self): - return (randomgen.pickle.__brng_ctor, + from ._pickle import __brng_ctor + return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/setup.py b/numpy/random/randomgen/setup.py new file mode 100644 index 000000000000..3f061c931ac1 --- /dev/null +++ b/numpy/random/randomgen/setup.py @@ -0,0 +1,190 @@ +from __future__ import division, print_function + +from os.path import join +import sys +import os +import platform +import struct +from distutils.dep_util import newer +from distutils.msvccompiler import get_build_version as get_msvc_build_version + +def needs_mingw_ftime_workaround(): + # We need the mingw workaround for _ftime if the msvc runtime version is + # 7.1 or above and we build with mingw ... + # ... but we can't easily detect compiler version outside distutils command + # context, so we will need to detect in randomkit whether we build with gcc + msver = get_msvc_build_version() + if msver and msver >= 8: + return True + + return False + + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration, get_mathlibs + config = Configuration('random', parent_package, top_path) + + def generate_libraries(ext, build_dir): + config_cmd = config.get_config_cmd() + libs = get_mathlibs() + if sys.platform == 'win32': + libs.append('Advapi32') + ext.libraries.extend(libs) + return None + + # enable unix large file support on 32 bit systems + # (64 bit off_t, lseek -> lseek64 etc.) + if sys.platform[:3] == "aix": + defs = [('_LARGE_FILES', None)] + else: + defs = [('_FILE_OFFSET_BITS', '64'), + ('_LARGEFILE_SOURCE', '1'), + ('_LARGEFILE64_SOURCE', '1')] + if needs_mingw_ftime_workaround(): + defs.append(("NPY_NEEDS_MINGW_TIME_WORKAROUND", None)) + + libs = [] + defs.append(('NPY_NO_DEPRECATED_API', 0)) + config.add_data_dir('tests') + + ############################## + # randomgen + ############################## + + # Make a guess as to whether SSE2 is present for now, TODO: Improve + USE_SSE2 = False + for k in platform.uname(): + for val in ('x86', 'i686', 'i386', 'amd64'): + USE_SSE2 = USE_SSE2 or val in k.lower() + print('Building with SSE?: {0}'.format(USE_SSE2)) + if '--no-sse2' in sys.argv: + USE_SSE2 = False + sys.argv.remove('--no-sse2') + + DEBUG = False + PCG_EMULATED_MATH = False + EXTRA_LINK_ARGS = [] + EXTRA_LIBRARIES = ['m'] if os.name != 'nt' else [] + EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else [ + '-std=c99', '-U__GNUC_GNU_INLINE__'] + if os.name == 'nt': + EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] + if DEBUG: + EXTRA_LINK_ARGS += ['-debug'] + EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] + if sys.version_info < (3, 0): + EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] + + PCG64_DEFS = [] + if 1 or sys.maxsize < 2 ** 32 or os.name == 'nt': + # Force emulated mode here + PCG_EMULATED_MATH = True + PCG64_DEFS += [('PCG_FORCE_EMULATED_128BIT_MATH', '1')] + + if struct.calcsize('P') < 8: + PCG_EMULATED_MATH = True + defs.append(('PCG_EMULATED_MATH', int(PCG_EMULATED_MATH))) + + DSFMT_DEFS = [('DSFMT_MEXP', '19937')] + if USE_SSE2: + if os.name == 'nt': + EXTRA_COMPILE_ARGS += ['/wd4146', '/GL'] + if struct.calcsize('P') < 8: + EXTRA_COMPILE_ARGS += ['/arch:SSE2'] + else: + EXTRA_COMPILE_ARGS += ['-msse2'] + DSFMT_DEFS += [('HAVE_SSE2', '1')] + + config.add_extension('entropy', + sources=['entropy.c', 'src/entropy/entropy.c'], + include_dirs=[join('randomgen', 'src', 'entropy')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('src', 'splitmix64', 'splitmix.h'), + join('src', 'entropy', 'entropy.h'), + 'entropy.pyx', + ], + define_macros=defs, + ) + config.add_extension('dsfmt', + sources=['dsfmt.c', 'src/dsfmt/dSFMT.c', + 'src/dsfmt/dSFMT-jump.c', + 'src/aligned_malloc/aligned_malloc.c'], + include_dirs=[join('src', 'dsfmt')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('src', 'dsfmt', 'dsfmt.h'), + 'dsfmt.pyx', + ], + define_macros=defs + DSFMT_DEFS, + ) + config.add_extension('legacy._legacy', + sources=['legacy/_legacy.c', + 'src/legacy/distributions-boxmuller.c', + 'src/distributions/distributions.c' ], + include_dirs=['.', 'legacy'], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('legacy', '_legacy.pyx')], + define_macros=defs + DSFMT_DEFS, + ) + for gen in ['mt19937']: + # gen.pyx, src/gen/gen.c, src/gen/gen-jump.c + config.add_extension(gen, + sources=['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen), + 'src/{0}/{0}-jump.c'.format(gen)], + include_dirs=[join('src', gen)], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=['%s.pyx' % gen], + define_macros=defs, + ) + for gen in ['philox', 'threefry', 'threefry32', + 'xoroshiro128', 'xorshift1024', 'xoshiro256starstar', + 'xoshiro512starstar', + 'pcg64', 'pcg32', + ]: + # gen.pyx, src/gen/gen.c + if gen == 'pcg64': + _defs = defs + PCG64_DEFS + else: + _defs = defs + config.add_extension(gen, + sources=['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen)], + include_dirs=[join('src', gen)], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=['%s.pyx' % gen], + define_macros=_defs, + ) + for gen in ['common']: + # gen.pyx + config.add_extension(gen, + sources=['{0}.c'.format(gen)], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=['%s.pyx' % gen], + define_macros=defs, + ) + for gen in ['generator', 'bounded_integers']: + # gen.pyx, src/distributions/distributions.c + config.add_extension(gen, + sources=['{0}.c'.format(gen), + join('src', 'distributions', + 'distributions.c')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=['%s.pyx' % gen], + define_macros=defs, + ) + return config +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/random/randomgen/tests/test_against_numpy.py b/numpy/random/randomgen/tests/test_against_numpy.py index ea2656e83fdc..4f4d809b2180 100644 --- a/numpy/random/randomgen/tests/test_against_numpy.py +++ b/numpy/random/randomgen/tests/test_against_numpy.py @@ -2,7 +2,7 @@ import numpy.random from numpy.testing import assert_allclose, assert_array_equal, assert_equal -import randomgen +import numpy.random.randomgen as randomgen from randomgen import RandomGenerator, MT19937 from randomgen._testing import suppress_warnings from randomgen.legacy import LegacyGenerator diff --git a/numpy/random/randomgen/threefry.pyx b/numpy/random/randomgen/threefry.pyx index 36f3537dba3f..63364dc3de46 100644 --- a/numpy/random/randomgen/threefry.pyx +++ b/numpy/random/randomgen/threefry.pyx @@ -9,7 +9,6 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array -from .pickle import __brng_ctor np.import_array() @@ -190,6 +189,7 @@ cdef class ThreeFry: self.state = state def __reduce__(self): + from ._pickle import __brng_ctor return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/threefry32.pyx b/numpy/random/randomgen/threefry32.pyx index ac0d556011f6..c4d32a324db0 100644 --- a/numpy/random/randomgen/threefry32.pyx +++ b/numpy/random/randomgen/threefry32.pyx @@ -8,7 +8,6 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array -from .pickle import __brng_ctor np.import_array() @@ -192,6 +191,7 @@ cdef class ThreeFry32: self.state = state def __reduce__(self): + from ._pickle import __brng_ctor return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/xoroshiro128.pyx b/numpy/random/randomgen/xoroshiro128.pyx index c075435ffa0e..a85f1fde5eb4 100644 --- a/numpy/random/randomgen/xoroshiro128.pyx +++ b/numpy/random/randomgen/xoroshiro128.pyx @@ -10,7 +10,6 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array -from .pickle import __brng_ctor np.import_array() @@ -154,6 +153,7 @@ cdef class Xoroshiro128: self.state = state def __reduce__(self): + from ._pickle import __brng_ctor return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/xorshift1024.pyx b/numpy/random/randomgen/xorshift1024.pyx index 029e59c4e029..62848bb81363 100644 --- a/numpy/random/randomgen/xorshift1024.pyx +++ b/numpy/random/randomgen/xorshift1024.pyx @@ -10,7 +10,6 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array -from .pickle import __brng_ctor np.import_array() @@ -160,6 +159,7 @@ cdef class Xorshift1024: self.state = state def __reduce__(self): + from ._pickle import __brng_ctor return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/xoshiro256starstar.pyx b/numpy/random/randomgen/xoshiro256starstar.pyx index e0db49dfcbaf..2d1e1955ee36 100644 --- a/numpy/random/randomgen/xoshiro256starstar.pyx +++ b/numpy/random/randomgen/xoshiro256starstar.pyx @@ -10,7 +10,6 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array -from .pickle import __brng_ctor np.import_array() @@ -154,6 +153,7 @@ cdef class Xoshiro256StarStar: self.state = state def __reduce__(self): + from ._pickle import __brng_ctor return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/xoshiro512starstar.pyx b/numpy/random/randomgen/xoshiro512starstar.pyx index 4fc16c5e14e8..935deecfa898 100644 --- a/numpy/random/randomgen/xoshiro512starstar.pyx +++ b/numpy/random/randomgen/xoshiro512starstar.pyx @@ -10,7 +10,6 @@ from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array -from .pickle import __brng_ctor np.import_array() @@ -154,6 +153,7 @@ cdef class Xoshiro512StarStar: self.state = state def __reduce__(self): + from ._pickle import __brng_ctor return (__brng_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/setup.py b/numpy/random/setup.py index dd3c8fbab541..481c4e380a88 100644 --- a/numpy/random/setup.py +++ b/numpy/random/setup.py @@ -60,149 +60,9 @@ def generate_libraries(ext, build_dir): config.add_data_files(('.', join('mtrand', 'randomkit.h'))) config.add_data_dir('tests') - ############################## - # randomgen - ############################## - - # Make a guess as to whether SSE2 is present for now, TODO: Improve - USE_SSE2 = False - for k in platform.uname(): - for val in ('x86', 'i686', 'i386', 'amd64'): - USE_SSE2 = USE_SSE2 or val in k.lower() - print('Building with SSE?: {0}'.format(USE_SSE2)) - if '--no-sse2' in sys.argv: - USE_SSE2 = False - sys.argv.remove('--no-sse2') - - DEBUG = False - PCG_EMULATED_MATH = False - EXTRA_LINK_ARGS = [] - EXTRA_LIBRARIES = ['m'] if os.name != 'nt' else [] - EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else [ - '-std=c99', '-U__GNUC_GNU_INLINE__'] - if os.name == 'nt': - EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] - if DEBUG: - EXTRA_LINK_ARGS += ['-debug'] - EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] - if sys.version_info < (3, 0): - EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] - - PCG64_DEFS = [] - if 1 or sys.maxsize < 2 ** 32 or os.name == 'nt': - # Force emulated mode here - PCG_EMULATED_MATH = True - PCG64_DEFS += [('PCG_FORCE_EMULATED_128BIT_MATH', '1')] - - if struct.calcsize('P') < 8: - PCG_EMULATED_MATH = True - defs.append(('PCG_EMULATED_MATH', int(PCG_EMULATED_MATH))) - - DSFMT_DEFS = [('DSFMT_MEXP', '19937')] - if USE_SSE2: - if os.name == 'nt': - EXTRA_COMPILE_ARGS += ['/wd4146', '/GL'] - if struct.calcsize('P') < 8: - EXTRA_COMPILE_ARGS += ['/arch:SSE2'] - else: - EXTRA_COMPILE_ARGS += ['-msse2'] - DSFMT_DEFS += [('HAVE_SSE2', '1')] - - config.add_extension('randomgen.entropy', - sources=[join('randomgen', x) for x in - ['entropy.c', 'src/entropy/entropy.c']], - include_dirs=[join('randomgen', 'src', 'entropy')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=[join('randomgen', 'src', 'splitmix64', 'splitmix.h'), - join('randomgen', 'src', 'entropy', 'entropy.h'), - join('randomgen', 'entropy.pyx'), - ], - define_macros=defs, - ) - config.add_extension('randomgen.dsfmt', - sources=[join('randomgen', x) for x in - ['dsfmt.c', 'src/dsfmt/dSFMT.c', - 'src/dsfmt/dSFMT-jump.c', - 'src/aligned_malloc/aligned_malloc.c']], - include_dirs=[join('randomgen', 'src', 'dsfmt')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=[join('randomgen', 'src', 'dsfmt', 'dsfmt.h'), - join('randomgen', 'dsfmt.pyx'), - ], - define_macros=defs + DSFMT_DEFS, - ) - config.add_extension('randomgen.legacy._legacy', - sources=[join('randomgen', x) for x in - ['legacy/_legacy.c', - 'src/legacy/distributions-boxmuller.c', - 'src/distributions/distributions.c' ]], - include_dirs=['randomgen', join('randomgen', 'legacy')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=[join('randomgen', 'legacy', '_legacy.pyx')], - define_macros=defs + DSFMT_DEFS, - ) - for gen in ['mt19937']: - # gen.pyx, src/gen/gen.c, src/gen/gen-jump.c - config.add_extension('randomgen.%s' % gen, - sources=[join('randomgen', x) for x in - ['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen), - 'src/{0}/{0}-jump.c'.format(gen)]], - include_dirs=[join('randomgen', 'src', gen)], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=[join('randomgen', '%s.pyx' % gen)], - define_macros=defs, - ) - for gen in ['philox', 'threefry', 'threefry32', - 'xoroshiro128', 'xorshift1024', 'xoshiro256starstar', - 'xoshiro512starstar', - 'pcg64', 'pcg32', - ]: - # gen.pyx, src/gen/gen.c - if gen == 'pcg64': - _defs = defs + PCG64_DEFS - else: - _defs = defs - config.add_extension('randomgen.%s' % gen, - sources=[join('randomgen', x) for x in - ['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen)]], - include_dirs=[join('randomgen', 'src', gen)], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=[join('randomgen', '%s.pyx' % gen)], - define_macros=_defs, - ) - for gen in ['common']: - # gen.pyx - config.add_extension('randomgen.%s' % gen, - sources=[join('randomgen', '{0}.c'.format(gen))], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=[join('randomgen', '%s.pyx' % gen)], - define_macros=defs, - ) - for gen in ['generator', 'bounded_integers']: - # gen.pyx, src/distributions/distributions.c - config.add_extension('randomgen.%s' % gen, - sources=[join('randomgen', '{0}.c'.format(gen)), - join('randomgen', 'src', 'distributions', - 'distributions.c')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=[join('randomgen', '%s.pyx' % gen)], - define_macros=defs, - ) + config.add_subpackage('randomgen') return config + if __name__ == '__main__': from numpy.distutils.core import setup setup(configuration=configuration) From 161f69e224b085f1f3cf5446c70573147a0e65b6 Mon Sep 17 00:00:00 2001 From: mattip Date: Sat, 23 Mar 2019 19:18:58 +0200 Subject: [PATCH 202/279] MAINT: add TODO comments for pcg64 improvements --- numpy/random/randomgen/pcg64.pyx | 1 + numpy/random/randomgen/setup.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/numpy/random/randomgen/pcg64.pyx b/numpy/random/randomgen/pcg64.pyx index 24850b583cdc..66bf3a47148b 100644 --- a/numpy/random/randomgen/pcg64.pyx +++ b/numpy/random/randomgen/pcg64.pyx @@ -278,6 +278,7 @@ cdef class PCG64: state of the RNG """ # IF PCG_EMULATED_MATH==1: + # TODO: push this into an #ifdef in the C code state = 2 **64 * self.rng_state.pcg_state.state.high state += self.rng_state.pcg_state.state.low inc = 2 **64 * self.rng_state.pcg_state.inc.high diff --git a/numpy/random/randomgen/setup.py b/numpy/random/randomgen/setup.py index 3f061c931ac1..202c2eef8854 100644 --- a/numpy/random/randomgen/setup.py +++ b/numpy/random/randomgen/setup.py @@ -76,6 +76,8 @@ def generate_libraries(ext, build_dir): EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] PCG64_DEFS = [] + # TODO: remove the unconditional forced emulation, move code from pcg64.pyx + # to an #ifdef if 1 or sys.maxsize < 2 ** 32 or os.name == 'nt': # Force emulated mode here PCG_EMULATED_MATH = True From 289d8048dc318de9c25e9b33ab8bc94498baa9e7 Mon Sep 17 00:00:00 2001 From: Christopher Whelan Date: Sat, 23 Mar 2019 14:50:35 -0700 Subject: [PATCH 203/279] BENCH: fix Savez suite, previously was actually calling pickle.dump() --- benchmarks/benchmarks/bench_io.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benchmarks/benchmarks/bench_io.py b/benchmarks/benchmarks/bench_io.py index 879f9b69ebc8..439cd422f5fc 100644 --- a/benchmarks/benchmarks/bench_io.py +++ b/benchmarks/benchmarks/bench_io.py @@ -66,7 +66,8 @@ def setup(self): self.squares = get_squares() def time_vb_savez_squares(self): - np.savez('tmp.npz', self.squares) + np.savez('tmp.npz', **self.squares) + class LoadtxtCSVComments(Benchmark): # benchmarks for np.loadtxt comment handling From a3303a2d11362a851f396e5bf42c58122a6750f4 Mon Sep 17 00:00:00 2001 From: mattip Date: Sat, 23 Mar 2019 23:05:23 +0200 Subject: [PATCH 204/279] MAINT: fix imports, module name in setup.py; remove _testing --- numpy/random/randomgen/_pickle.py | 50 +-- numpy/random/randomgen/_testing.py | 315 ------------------ numpy/random/randomgen/legacy/__init__.py | 2 +- numpy/random/randomgen/legacy/_legacy.pyx | 2 +- numpy/random/randomgen/legacy/legacy.py | 11 +- numpy/random/randomgen/setup.py | 3 +- .../randomgen/tests/test_against_numpy.py | 11 +- numpy/random/randomgen/tests/test_direct.py | 2 +- numpy/random/randomgen/tests/test_legacy.py | 2 +- .../randomgen/tests/test_numpy_mt19937.py | 7 +- .../tests/test_numpy_mt19937_regressions.py | 2 +- numpy/random/randomgen/tests/test_smoke.py | 13 +- 12 files changed, 51 insertions(+), 369 deletions(-) delete mode 100644 numpy/random/randomgen/_testing.py diff --git a/numpy/random/randomgen/_pickle.py b/numpy/random/randomgen/_pickle.py index 0d7aece69546..b192bc8a4b1f 100644 --- a/numpy/random/randomgen/_pickle.py +++ b/numpy/random/randomgen/_pickle.py @@ -1,29 +1,29 @@ from .generator import RandomGenerator -# from .dsfmt import DSFMT -# from .mt19937 import MT19937 -# from .pcg32 import PCG32 -# from .pcg64 import PCG64 -# from .philox import Philox -# from .threefry import ThreeFry -# from .threefry32 import ThreeFry32 -# from .xoroshiro128 import Xoroshiro128 -# from .xorshift1024 import Xorshift1024 -# from .xoshiro256starstar import Xoshiro256StarStar -# from .xoshiro512starstar import Xoshiro512StarStar -# from .legacy import LegacyGenerator -# -# BasicRNGS = {'MT19937': MT19937, -# 'DSFMT': DSFMT, -# 'PCG32': PCG32, -# 'PCG64': PCG64, -# 'Philox': Philox, -# 'ThreeFry': ThreeFry, -# 'ThreeFry32': ThreeFry32, -# 'Xorshift1024': Xorshift1024, -# 'Xoroshiro128': Xoroshiro128, -# 'Xoshiro256StarStar': Xoshiro256StarStar, -# 'Xoshiro512StarStar': Xoshiro512StarStar, -# } +from .dsfmt import DSFMT +from .mt19937 import MT19937 +from .pcg32 import PCG32 +from .pcg64 import PCG64 +from .philox import Philox +from .threefry import ThreeFry +from .threefry32 import ThreeFry32 +from .xoroshiro128 import Xoroshiro128 +from .xorshift1024 import Xorshift1024 +from .xoshiro256starstar import Xoshiro256StarStar +from .xoshiro512starstar import Xoshiro512StarStar +from .legacy import LegacyGenerator + +BasicRNGS = {'MT19937': MT19937, + 'DSFMT': DSFMT, + 'PCG32': PCG32, + 'PCG64': PCG64, + 'Philox': Philox, + 'ThreeFry': ThreeFry, + 'ThreeFry32': ThreeFry32, + 'Xorshift1024': Xorshift1024, + 'Xoroshiro128': Xoroshiro128, + 'Xoshiro256StarStar': Xoshiro256StarStar, + 'Xoshiro512StarStar': Xoshiro512StarStar, + } def __generator_ctor(brng_name='mt19937'): diff --git a/numpy/random/randomgen/_testing.py b/numpy/random/randomgen/_testing.py deleted file mode 100644 index 07d41677b7c4..000000000000 --- a/numpy/random/randomgen/_testing.py +++ /dev/null @@ -1,315 +0,0 @@ -""" -Shim for NumPy's suppress_warnings -""" - - -try: - from numpy.testing import suppress_warnings -except ImportError: - - # The following two classes are copied from python 2.6 warnings module - # (context manager) - class WarningMessage(object): - - """ - Holds the result of a single showwarning() call. - Deprecated in 1.8.0 - Notes - ----- - `WarningMessage` is copied from the Python 2.6 warnings module, - so it can be used in NumPy with older Python versions. - """ - - _WARNING_DETAILS = ("message", "category", "filename", "lineno", - "file", "line") - - def __init__(self, message, category, filename, lineno, file=None, - line=None): - local_values = locals() - for attr in self._WARNING_DETAILS: - setattr(self, attr, local_values[attr]) - if category: - self._category_name = category.__name__ - else: - self._category_name = None - - def __str__(self): - return ("{message : %r, category : %r, " - "filename : %r, lineno : %s, " - "line : %r}" % (self.message, self._category_name, - self.filename, self.lineno, self.line)) - - import re - import warnings - from functools import wraps - - class suppress_warnings(object): - """ - Context manager and decorator doing much the same as - ``warnings.catch_warnings``. - However, it also provides a filter mechanism to work around - http://bugs.python.org/issue4180. - This bug causes Python before 3.4 to not reliably show warnings again - after they have been ignored once (even within catch_warnings). It - means that no "ignore" filter can be used easily, since following - tests might need to see the warning. Additionally it allows easier - specificity for testing warnings and can be nested. - Parameters - ---------- - forwarding_rule : str, optional - One of "always", "once", "module", or "location". Analogous to - the usual warnings module filter mode, it is useful to reduce - noise mostly on the outmost level. Unsuppressed and unrecorded - warnings will be forwarded based on this rule. Defaults to - "always". "location" is equivalent to the warnings "default", match - by exact location the warning warning originated from. - Notes - ----- - Filters added inside the context manager will be discarded again - when leaving it. Upon entering all filters defined outside a - context will be applied automatically. - When a recording filter is added, matching warnings are stored in the - ``log`` attribute as well as in the list returned by ``record``. - If filters are added and the ``module`` keyword is given, the - warning registry of this module will additionally be cleared when - applying it, entering the context, or exiting it. This could cause - warnings to appear a second time after leaving the context if they - were configured to be printed once (default) and were already - printed before the context was entered. - Nesting this context manager will work as expected when the - forwarding rule is "always" (default). Unfiltered and unrecorded - warnings will be passed out and be matched by the outer level. - On the outmost level they will be printed (or caught by another - warnings context). The forwarding rule argument can modify this - behaviour. - Like ``catch_warnings`` this context manager is not threadsafe. - Examples - -------- - >>> with suppress_warnings() as sup: - ... sup.filter(DeprecationWarning, "Some text") - ... sup.filter(module=np.ma.core) - ... log = sup.record(FutureWarning, "Does this occur?") - ... command_giving_warnings() - ... # The FutureWarning was given once, the filtered warnings were - ... # ignored. All other warnings abide outside settings (may be - ... # printed/error) - ... assert_(len(log) == 1) - ... assert_(len(sup.log) == 1) # also stored in log attribute - Or as a decorator: - >>> sup = suppress_warnings() - >>> sup.filter(module=np.ma.core) # module must match exact - >>> @sup - >>> def some_function(): - ... # do something which causes a warning in np.ma.core - ... pass - """ - def __init__(self, forwarding_rule="always"): - self._entered = False - - # Suppressions are instance or defined inside one with block: - self._suppressions = [] - - if forwarding_rule not in {"always", "module", "once", "location"}: - raise ValueError("unsupported forwarding rule.") - self._forwarding_rule = forwarding_rule - - def _clear_registries(self): - if hasattr(warnings, "_filters_mutated"): - # clearing the registry should not be necessary on new pythons, - # instead the filters should be mutated. - warnings._filters_mutated() - return - # Simply clear the registry, this should normally be harmless, - # note that on new pythons it would be invalidated anyway. - for module in self._tmp_modules: - if hasattr(module, "__warningregistry__"): - module.__warningregistry__.clear() - - def _filter(self, category=Warning, message="", module=None, - record=False): - if record: - record = [] # The log where to store warnings - else: - record = None - if self._entered: - if module is None: - warnings.filterwarnings( - "always", category=category, message=message) - else: - module_regex = module.__name__.replace('.', r'\.') + '$' - warnings.filterwarnings( - "always", category=category, message=message, - module=module_regex) - self._tmp_modules.add(module) - self._clear_registries() - - self._tmp_suppressions.append( - (category, message, re.compile(message, re.I), module, - record)) - else: - self._suppressions.append( - (category, message, re.compile(message, re.I), module, - record)) - - return record - - def filter(self, category=Warning, message="", module=None): - """ - Add a new suppressing filter or apply it if the state is entered. - Parameters - ---------- - category : class, optional - Warning class to filter - message : string, optional - Regular expression matching the warning message. - module : module, optional - Module to filter for. Note that the module (and its file) - must match exactly and cannot be a submodule. This may make - it unreliable for external modules. - Notes - ----- - When added within a context, filters are only added inside - the context and will be forgotten when the context is exited. - """ - self._filter(category=category, message=message, module=module, - record=False) - - def record(self, category=Warning, message="", module=None): - """ - Append a new recording filter or apply it if the state is entered. - All warnings matching will be appended to the ``log`` attribute. - Parameters - ---------- - category : class, optional - Warning class to filter - message : string, optional - Regular expression matching the warning message. - module : module, optional - Module to filter for. Note that the module (and its file) - must match exactly and cannot be a submodule. This may make - it unreliable for external modules. - Returns - ------- - log : list - A list which will be filled with all matched warnings. - Notes - ----- - When added within a context, filters are only added inside - the context and will be forgotten when the context is exited. - """ - return self._filter(category=category, message=message, - module=module, record=True) - - def __enter__(self): - if self._entered: - raise RuntimeError("cannot enter suppress_warnings twice.") - - self._orig_show = warnings.showwarning - if hasattr(warnings, "_showwarnmsg"): - self._orig_showmsg = warnings._showwarnmsg - self._filters = warnings.filters - warnings.filters = self._filters[:] - - self._entered = True - self._tmp_suppressions = [] - self._tmp_modules = set() - self._forwarded = set() - - self.log = [] # reset global log (no need to keep same list) - - for cat, mess, _, mod, log in self._suppressions: - if log is not None: - del log[:] # clear the log - if mod is None: - warnings.filterwarnings( - "always", category=cat, message=mess) - else: - module_regex = mod.__name__.replace('.', r'\.') + '$' - warnings.filterwarnings( - "always", category=cat, message=mess, - module=module_regex) - self._tmp_modules.add(mod) - warnings.showwarning = self._showwarning - if hasattr(warnings, "_showwarnmsg"): - warnings._showwarnmsg = self._showwarnmsg - self._clear_registries() - - return self - - def __exit__(self, *exc_info): - warnings.showwarning = self._orig_show - if hasattr(warnings, "_showwarnmsg"): - warnings._showwarnmsg = self._orig_showmsg - warnings.filters = self._filters - self._clear_registries() - self._entered = False - del self._orig_show - del self._filters - - def _showwarnmsg(self, msg): - self._showwarning(msg.message, msg.category, msg.filename, - msg.lineno, msg.file, msg.line, use_warnmsg=msg) - - def _showwarning(self, message, category, filename, lineno, - *args, **kwargs): - use_warnmsg = kwargs.pop("use_warnmsg", None) - for cat, _, pattern, mod, rec in ( - self._suppressions + self._tmp_suppressions)[::-1]: - if (issubclass(category, cat) and - pattern.match(message.args[0]) is not None): - if mod is None: - # Message and category match, recorded or ignored - if rec is not None: - msg = WarningMessage(message, category, filename, - lineno, **kwargs) - self.log.append(msg) - rec.append(msg) - return - # Use startswith, because warnings strips the c or o from - # .pyc/.pyo files. - elif mod.__file__.startswith(filename): - # The message and module (filename) match - if rec is not None: - msg = WarningMessage(message, category, filename, - lineno, **kwargs) - self.log.append(msg) - rec.append(msg) - return - - # There is no filter in place, so pass to the outside handler - # unless we should only pass it once - if self._forwarding_rule == "always": - if use_warnmsg is None: - self._orig_show(message, category, filename, lineno, - *args, **kwargs) - else: - self._orig_showmsg(use_warnmsg) - return - - if self._forwarding_rule == "once": - signature = (message.args, category) - elif self._forwarding_rule == "module": - signature = (message.args, category, filename) - elif self._forwarding_rule == "location": - signature = (message.args, category, filename, lineno) - - if signature in self._forwarded: - return - self._forwarded.add(signature) - if use_warnmsg is None: - self._orig_show(message, category, filename, lineno, *args, - **kwargs) - else: - self._orig_showmsg(use_warnmsg) - - def __call__(self, func): - """ - Function decorator to apply certain suppressions to a whole - function. - """ - @wraps(func) - def new_func(*args, **kwargs): - with self: - return func(*args, **kwargs) - - return new_func diff --git a/numpy/random/randomgen/legacy/__init__.py b/numpy/random/randomgen/legacy/__init__.py index b59b221b49bc..01f0c13121e6 100644 --- a/numpy/random/randomgen/legacy/__init__.py +++ b/numpy/random/randomgen/legacy/__init__.py @@ -1,3 +1,3 @@ -from randomgen.legacy.legacy import LegacyGenerator +from .legacy import LegacyGenerator __all__ = ['LegacyGenerator'] diff --git a/numpy/random/randomgen/legacy/_legacy.pyx b/numpy/random/randomgen/legacy/_legacy.pyx index 1201fe313dea..cd8f7b53214e 100644 --- a/numpy/random/randomgen/legacy/_legacy.pyx +++ b/numpy/random/randomgen/legacy/_legacy.pyx @@ -20,7 +20,6 @@ from ..common cimport cont, disc, CONS_NONE, CONS_POSITIVE, CONS_NON_NEGATIVE, C from ..distributions cimport brng_t from .legacy_distributions cimport * from ..xoroshiro128 import Xoroshiro128 -from ..pickle import __legacy_ctor np.import_array() @@ -119,6 +118,7 @@ cdef class _LegacyGenerator: self.state = state def __reduce__(self): + from .._pickle import __legacy_ctor return (__legacy_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/legacy/legacy.py b/numpy/random/randomgen/legacy/legacy.py index f23464e6069a..72b72a7f40bd 100644 --- a/numpy/random/randomgen/legacy/legacy.py +++ b/numpy/random/randomgen/legacy/legacy.py @@ -1,8 +1,6 @@ -from randomgen.generator import RandomGenerator -from randomgen.mt19937 import MT19937 -from randomgen.legacy._legacy import _LegacyGenerator -import randomgen.pickle - +from ..generator import RandomGenerator +from ..mt19937 import MT19937 +from ._legacy import _LegacyGenerator _LEGACY_ATTRIBUTES = tuple(a for a in dir( _LegacyGenerator) if not a.startswith('_')) @@ -109,6 +107,7 @@ def __setstate__(self, state): self.state = state def __reduce__(self): - return (randomgen.pickle._experiment_ctor, + from .._pickle import _experiment_ctor + return (_experiment_ctor, (self.state['brng'],), self.state) diff --git a/numpy/random/randomgen/setup.py b/numpy/random/randomgen/setup.py index 202c2eef8854..ccea6e78c370 100644 --- a/numpy/random/randomgen/setup.py +++ b/numpy/random/randomgen/setup.py @@ -22,7 +22,7 @@ def needs_mingw_ftime_workaround(): def configuration(parent_package='',top_path=None): from numpy.distutils.misc_util import Configuration, get_mathlibs - config = Configuration('random', parent_package, top_path) + config = Configuration('randomgen', parent_package, top_path) def generate_libraries(ext, build_dir): config_cmd = config.get_config_cmd() @@ -186,6 +186,7 @@ def generate_libraries(ext, build_dir): depends=['%s.pyx' % gen], define_macros=defs, ) + config.add_subpackage('legacy') return config if __name__ == '__main__': from numpy.distutils.core import setup diff --git a/numpy/random/randomgen/tests/test_against_numpy.py b/numpy/random/randomgen/tests/test_against_numpy.py index 4f4d809b2180..d0f0eefea17f 100644 --- a/numpy/random/randomgen/tests/test_against_numpy.py +++ b/numpy/random/randomgen/tests/test_against_numpy.py @@ -1,11 +1,11 @@ import numpy as np import numpy.random -from numpy.testing import assert_allclose, assert_array_equal, assert_equal +from numpy.testing import (assert_allclose, assert_array_equal, assert_equal, + suppress_warnings) import numpy.random.randomgen as randomgen -from randomgen import RandomGenerator, MT19937 -from randomgen._testing import suppress_warnings -from randomgen.legacy import LegacyGenerator +from ...randomgen import RandomGenerator, MT19937 +from ...randomgen.legacy import LegacyGenerator def compare_0_input(f1, f2): @@ -413,7 +413,8 @@ def test_dir(self): 'test', '__warningregistry__', '_numpy_tester', 'division', 'get_state', 'set_state', 'seed', 'ranf', 'random', 'sample', 'absolute_import', - 'print_function', 'RandomState'] + 'print_function', 'RandomState', 'randomgen', + 'tests'] mod += known_exlcuded diff = set(npmod).difference(mod) assert_equal(len(diff), 0) diff --git a/numpy/random/randomgen/tests/test_direct.py b/numpy/random/randomgen/tests/test_direct.py index 3f84c4cb69da..cbe2717a7233 100644 --- a/numpy/random/randomgen/tests/test_direct.py +++ b/numpy/random/randomgen/tests/test_direct.py @@ -7,7 +7,7 @@ assert_raises import pytest -from randomgen import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ +from ...randomgen import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024, Xoshiro256StarStar, \ Xoshiro512StarStar diff --git a/numpy/random/randomgen/tests/test_legacy.py b/numpy/random/randomgen/tests/test_legacy.py index 21c56946f6b8..6f8f9aee77d0 100644 --- a/numpy/random/randomgen/tests/test_legacy.py +++ b/numpy/random/randomgen/tests/test_legacy.py @@ -1,6 +1,6 @@ import pickle -from randomgen.legacy import LegacyGenerator +from ...randomgen.legacy import LegacyGenerator def test_pickle(): diff --git a/numpy/random/randomgen/tests/test_numpy_mt19937.py b/numpy/random/randomgen/tests/test_numpy_mt19937.py index a19693d815c7..663cdb272c73 100644 --- a/numpy/random/randomgen/tests/test_numpy_mt19937.py +++ b/numpy/random/randomgen/tests/test_numpy_mt19937.py @@ -7,11 +7,10 @@ from numpy.testing import ( assert_, assert_raises, assert_equal, assert_warns, assert_no_warnings, assert_array_equal, - assert_array_almost_equal) + assert_array_almost_equal, suppress_warnings) -from randomgen._testing import suppress_warnings -from randomgen import RandomGenerator, MT19937 -from randomgen.legacy import LegacyGenerator +from ...randomgen import RandomGenerator, MT19937 +from ...randomgen.legacy import LegacyGenerator random = mt19937 = RandomGenerator(MT19937()) legacy = LegacyGenerator(MT19937()) diff --git a/numpy/random/randomgen/tests/test_numpy_mt19937_regressions.py b/numpy/random/randomgen/tests/test_numpy_mt19937_regressions.py index bc644e122439..13569e950606 100644 --- a/numpy/random/randomgen/tests/test_numpy_mt19937_regressions.py +++ b/numpy/random/randomgen/tests/test_numpy_mt19937_regressions.py @@ -5,7 +5,7 @@ from numpy.compat import long import numpy as np import pytest -from randomgen import RandomGenerator, MT19937 +from ...randomgen import RandomGenerator, MT19937 mt19937 = RandomGenerator(MT19937()) diff --git a/numpy/random/randomgen/tests/test_smoke.py b/numpy/random/randomgen/tests/test_smoke.py index 5a9882a16aed..ab6f50e330ca 100644 --- a/numpy/random/randomgen/tests/test_smoke.py +++ b/numpy/random/randomgen/tests/test_smoke.py @@ -5,14 +5,11 @@ import numpy as np import pytest -from numpy.testing import assert_almost_equal, assert_equal, assert_, \ - assert_array_equal - -from randomgen._testing import suppress_warnings -from randomgen import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ - PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024, Xoshiro256StarStar, \ - Xoshiro512StarStar -from randomgen import entropy +from numpy.testing import (assert_almost_equal, assert_equal, assert_, + assert_array_equal, suppress_warnings) +from ...randomgen import (RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, + PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024, Xoshiro256StarStar, + Xoshiro512StarStar, entropy) @pytest.fixture(scope='module', From 81f0ddac64919e503beeea2c1812b36a607de55d Mon Sep 17 00:00:00 2001 From: Lars Grueter Date: Mon, 25 Mar 2019 10:23:46 +0100 Subject: [PATCH 205/279] MAINT: Rewrite numpy.pad without concatenate (gh-11358) * ENH: Add support for constant, edge, linear_ramp to new numpy.pad Passes unit tests: - TestConstant - TestEdge - TestZeroPadWidth - TestLegacyVectorFunction - TestNdarrayPadWidth - TestUnicodeInput - TestLinearRamp * MAINT: Simplify diff / change order of functions * MAINT: Revert to old handling of keyword-only arguments * ENH: Add support for stat modes * ENH: Add support for "reflect" mode * MAINT: Remove _slice_column * ENH: Add support for "symmetric" mode * MAINT: Simplify mode "linear_ramp" Creating the linear ramp as an array with 1-sized dimensions except for the one given by `axis` allows implicit broadcasting to the needed shape. This seems to be even a little bit faster that doing this by hand and allows the simplicifaction of the algorithm. Note: Profiling and optimization will be done again at a later stage. * MAINT: Reorder arguments of a sum and fix typo Addresses feedback raised in PR. * ENH: Add support for "wrap" mode This completes the first draft of the complete rewrite meaning all unit tests should pass from this commit onwards. * MAINT: Merge functions for "reflect" and "symmetric" mode The set functions were nearly the same, apart from some index offsets. Merging them reduces code duplication. * TST: Add regression test for gh-11216 The rewrite in past commits fixed this bug. * BUG: Fix edge case for _set_wrap_both when pad_amt contains 0. And include test to protect against regression. * MAINT: Simplify and optimize pad modes Major changes & goals: Don't deal with pad area in the front and back separately. This modularity isn't needed and makes handling of the right edge more awkward. All modes now deal with the left and right side at the same time. Move the creation of the linear ramps fully to its own function which behaves like a vectorized version of linspace. Separate calculation and application of the pad area where possible. This means that _get_edges can be reused for _get_linear_ramps. Combine _normalize_shape and _validate_lengths in a single function which should handles common cases faster. Add new mode "empty" which leaves the padded areas undefined. Add documentation where it was missing. * TST: Don't use np.empty in unit tests * MAINT: Reorder workflow in numpy.pad and deal with empty dimensions Only modes "constant" and "empty" can extend dimensions of size 0. Deal with this edge case gracefully for all other modes either fail or return empty array with padded non-zero dimensions. Handle default values closer to their actual usage. And validate keyword arguments that must be numbers. * MAINT: Add small tweaks to control flow and documentation * BUG: Ensure wrap mode works if right_pad is 0 * ENH: Use reduced region of interest for iterative padding When padding multiple dimensions iteratively corner values are unnecessarily overwritten multiple times. This function reduces the working area for the first dimensions so that corners are excluded. * MAINT: Restore original argument order in _slice_at_axis * MAINT: Keep original error message of broadcast_to * MAINT: Restore old behavior for non-number end_values. * BENCH: Make the pad benchmark pagefault in setup * ENH/TST: Preserve memory layout (order) of the input array and add appropriate unit test. * STY: Revert cosmetical changes to reduce diff * MAINT: Pin dtype to float64 for np.pad's benchmarks * MAINT: Remove redundant code path in _view_roi * MAINT/TST: Provide proper error message for unsupported modes and add appropriate unit test. * STY: Keep docstrings consistent and fix typo. * MAINT: Simplify logical workflow in pad * MAINT: Remove dtype argument from _linear_ramp The responsibility of rounding (but without type conversion) is not really need in _linear_ramp and only makes it a little bit harder to reason about. * DOC: Add version tag to new argument "empty" * MAINT: Default to C-order for padded arrays unless the input is F-contiguous. * MAINT: Name slice of original area consistently for all arguments describing the same thing. * STY: Reduce vertical space * MAINT: Remove shape argument from _slice_at_axis Simplifies calls to this function and the function itself. Using `(...,)` instead should keep this unambiguous. This change is not compatible with Python 2.7 which doesn't support this syntax outside sequence slicing. If that is wanted one could use `(Ellipsis,)` instead. * TST: Test if end_values of linear_ramp are exact which was not given in the old implementation `_arange_ndarray`. * DOC: Improve comments and wrap long line * MAINT: Refactor index_pair to width_pair Calling the right value an index is just plain wrong as it can't be used as such. * MAINT: Make _linear_ramp compatible with size=0 * MAINT: Don't rely on negative indices for slicing Calculating the proper positive index of the start of the right pad area makes it possible to omit the extra code paths for a width of 0. This should make the code easier to reason about. * MAINT: Skip calculation of right_stat if identical If the input area for both sides is the same we don't need to calculate it twice. * TST: Adapt tests from gh-12789 to rewrite of pad * TST: Add tests for mode "empty" * TST: Test dtype persistence for all modes * TST: Test exception for unsupported modes * TST: Test repeated wrapping for each side individually. Reaches some only partially covered if-statments in _set_wrap_both. * TST: Test padding of empty dimension with constant * TST: Test if end_values of linear_ramp are exact which was not given in the old implementation `_arange_ndarray`. (Was accidentally overwritten during the last merge). * TST: Test persistence of memory layout Adapted from an older commit 3ac4d2a1b9b258d65f8d2b5f8f25f88e3a0e8f58 which was accidentally overwritten during the last merge. * MAINT: Simplify branching in _set_reflect_both Reduce branching and try to make the calculation of the various indices easier to understand. * TST: Parametrize TestConditionalShortcuts class * TST: Test empty dimension padding for all modes * TST: Keep test parametrization ordered Keep parametrization ordered, otherwise pytest-xdist might believe that different tests were collected during parallelization causing test failures. * DOC: Describe performance improvement of np.pad as well as the new mode "empty" in release notes (see gh-11358). * DOC: Remove outdated / misleading notes These notes are badly worded or actually misleading. For a better explanation on how these functions work have a look at the context and comments just above the lines calling these functions. --- doc/release/1.17.0-notes.rst | 10 + numpy/lib/arraypad.py | 1394 ++++++++++-------------------- numpy/lib/tests/test_arraypad.py | 156 +++- 3 files changed, 595 insertions(+), 965 deletions(-) diff --git a/doc/release/1.17.0-notes.rst b/doc/release/1.17.0-notes.rst index ccb44d32c75c..4c7978f10f50 100644 --- a/doc/release/1.17.0-notes.rst +++ b/doc/release/1.17.0-notes.rst @@ -119,6 +119,10 @@ divmod operation is now supported for two ``timedelta64`` operands The divmod operator now handles two ``np.timedelta64`` operands, with type signature mm->qm. +New mode "empty" for ``np.pad`` +------------------------------- +This mode pads an array to a desired shape without initializing the new +entries. Improvements ============ @@ -171,6 +175,12 @@ but with this change, you can do:: thereby saving a level of indentation +Improve performance of ``np.pad`` +--------------------------------- +The performance of the function has been improved for most cases by filling in +a preallocated array with the desired padded shape instead of using +concatenation. + ``np.interp`` handles infinities more robustly ---------------------------------------------- In some cases where ``np.interp`` would previously return ``np.nan``, it now diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py index 66f21bfca403..570f86969725 100644 --- a/numpy/lib/arraypad.py +++ b/numpy/lib/arraypad.py @@ -16,50 +16,67 @@ # Private utility functions. -def _arange_ndarray(arr, shape, axis, reverse=False): +def _linear_ramp(ndim, axis, start, stop, size, reverse=False): """ - Create an ndarray of `shape` with increments along specified `axis` + Create a linear ramp of `size` in `axis` with `ndim`. + + This algorithm behaves like a vectorized version of `numpy.linspace`. + The resulting linear ramp is broadcastable to any array that matches the + ramp in `shape[axis]` and `ndim`. Parameters ---------- - arr : ndarray - Input array of arbitrary shape. - shape : tuple of ints - Shape of desired array. Should be equivalent to `arr.shape` except - `shape[axis]` which may have any positive value. + ndim : int + Number of dimensions of the resulting array. All dimensions except + the one specified by `axis` will have the size 1. axis : int - Axis to increment along. + The dimension that contains the linear ramp of `size`. + start : int or ndarray + The starting value(s) of the linear ramp. If given as an array, its + size must match `size`. + stop : int or ndarray + The stop value(s) (not included!) of the linear ramp. If given as an + array, its size must match `size`. + size : int + The number of elements in the linear ramp. If this argument is 0 the + dimensions of `ramp` will all be of length 1 except for the one given + by `axis` which will be 0. reverse : bool - If False, increment in a positive fashion from 1 to `shape[axis]`, - inclusive. If True, the bounds are the same but the order reversed. + If False, increment in a positive fashion, otherwise decrement. Returns ------- - padarr : ndarray - Output array sized to pad `arr` along `axis`, with linear range from - 1 to `shape[axis]` along specified `axis`. - - Notes - ----- - The range is deliberately 1-indexed for this specific use case. Think of - this algorithm as broadcasting `np.arange` to a single `axis` of an - arbitrarily shaped ndarray. + ramp : ndarray + Output array of dtype np.float64 that in- or decrements along the given + `axis`. + Examples + -------- + >>> _linear_ramp(ndim=2, axis=0, start=np.arange(3), stop=10, size=2) + array([[0. , 1. , 2. ], + [5. , 5.5, 6. ]]) + >>> _linear_ramp(ndim=3, axis=0, start=2, stop=0, size=0) + array([], shape=(0, 1, 1), dtype=float64) """ - initshape = tuple(1 if i != axis else shape[axis] - for (i, x) in enumerate(arr.shape)) - if not reverse: - padarr = np.arange(1, shape[axis] + 1) - else: - padarr = np.arange(shape[axis], 0, -1) - padarr = padarr.reshape(initshape) - for i, dim in enumerate(shape): - if padarr.shape[i] != dim: - padarr = padarr.repeat(dim, axis=i) - return padarr + # Create initial ramp + ramp = np.arange(size, dtype=np.float64) + if reverse: + ramp = ramp[::-1] + + # Make sure, that ramp is broadcastable + init_shape = (1,) * axis + (size,) + (1,) * (ndim - axis - 1) + ramp = ramp.reshape(init_shape) + + if size != 0: + # And scale to given start and stop values + gain = (stop - start) / float(size) + ramp = ramp * gain + ramp += start + return ramp -def _round_ifneeded(arr, dtype): + +def _round_if_needed(arr, dtype): """ Rounds arr inplace if destination dtype is integer. @@ -69,821 +86,418 @@ def _round_ifneeded(arr, dtype): Input array. dtype : dtype The dtype of the destination array. - """ if np.issubdtype(dtype, np.integer): arr.round(out=arr) -def _slice_at_axis(shape, sl, axis): - """ - Construct a slice tuple the length of shape, with sl at the specified axis - """ - slice_tup = (slice(None),) - return slice_tup * axis + (sl,) + slice_tup * (len(shape) - axis - 1) - - -def _slice_first(shape, n, axis): - """ Construct a slice tuple to take the first n elements along axis """ - return _slice_at_axis(shape, slice(0, n), axis=axis) - - -def _slice_last(shape, n, axis): - """ Construct a slice tuple to take the last n elements along axis """ - dim = shape[axis] # doing this explicitly makes n=0 work - return _slice_at_axis(shape, slice(dim - n, dim), axis=axis) - - -def _do_prepend(arr, pad_chunk, axis): - return np.concatenate( - (pad_chunk.astype(arr.dtype, copy=False), arr), axis=axis) - - -def _do_append(arr, pad_chunk, axis): - return np.concatenate( - (arr, pad_chunk.astype(arr.dtype, copy=False)), axis=axis) - - -def _prepend_const(arr, pad_amt, val, axis=-1): +def _slice_at_axis(sl, axis): """ - Prepend constant `val` along `axis` of `arr`. + Construct tuple of slices to slice an array in the given dimension. Parameters ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to prepend. - val : scalar - Constant value to use. For best results should be of type `arr.dtype`; - if not `arr.dtype` will be cast to `arr.dtype`. + sl : slice + The slice for the given dimension. axis : int - Axis along which to pad `arr`. + The axis to which `sl` is applied. All other dimensions are left + "unsliced". Returns ------- - padarr : ndarray - Output array, with `pad_amt` constant `val` prepended along `axis`. + sl : tuple of slices + A tuple with slices matching `shape` in length. + Examples + -------- + >>> _slice_at_axis(slice(None, 3, -1), 1) + (slice(None, None, None), slice(None, 3, -1), (...,)) """ - if pad_amt == 0: - return arr - padshape = tuple(x if i != axis else pad_amt - for (i, x) in enumerate(arr.shape)) - return _do_prepend(arr, np.full(padshape, val, dtype=arr.dtype), axis) + return (slice(None),) * axis + (sl,) + (...,) -def _append_const(arr, pad_amt, val, axis=-1): +def _view_roi(array, original_area_slice, axis): """ - Append constant `val` along `axis` of `arr`. + Get a view of the current region of interest during iterative padding. - Parameters - ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to append. - val : scalar - Constant value to use. For best results should be of type `arr.dtype`; - if not `arr.dtype` will be cast to `arr.dtype`. - axis : int - Axis along which to pad `arr`. - - Returns - ------- - padarr : ndarray - Output array, with `pad_amt` constant `val` appended along `axis`. - - """ - if pad_amt == 0: - return arr - padshape = tuple(x if i != axis else pad_amt - for (i, x) in enumerate(arr.shape)) - return _do_append(arr, np.full(padshape, val, dtype=arr.dtype), axis) - - - -def _prepend_edge(arr, pad_amt, axis=-1): - """ - Prepend `pad_amt` to `arr` along `axis` by extending edge values. + When padding multiple dimensions iteratively corner values are + unnecessarily overwritten multiple times. This function reduces the + working area for the first dimensions so that corners are excluded. Parameters ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to prepend. + array : ndarray + The array with the region of interest. + original_area_slice : tuple of slices + Denotes the area with original values of the unpadded array. axis : int - Axis along which to pad `arr`. + The currently padded dimension assuming that `axis` is padded before + `axis` + 1. Returns ------- - padarr : ndarray - Output array, extended by `pad_amt` edge values appended along `axis`. - + roi : ndarray + The region of interest of the original `array`. """ - if pad_amt == 0: - return arr + axis += 1 + sl = (slice(None),) * axis + original_area_slice[axis:] + return array[sl] - edge_slice = _slice_first(arr.shape, 1, axis=axis) - edge_arr = arr[edge_slice] - return _do_prepend(arr, edge_arr.repeat(pad_amt, axis=axis), axis) - -def _append_edge(arr, pad_amt, axis=-1): +def _pad_simple(array, pad_width, fill_value=None): """ - Append `pad_amt` to `arr` along `axis` by extending edge values. + Pad array on all sides with either a single value or undefined values. Parameters ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to append. - axis : int - Axis along which to pad `arr`. + array : ndarray + Array to grow. + pad_width : sequence of tuple[int, int] + Pad width on both sides for each dimension in `arr`. + fill_value : scalar, optional + If provided the padded area is filled with this value, otherwise + the pad area left undefined. Returns ------- - padarr : ndarray - Output array, extended by `pad_amt` edge values prepended along - `axis`. - + padded : ndarray + The padded array with the same dtype as`array`. Its order will default + to C-style if `array` is not F-contiguous. + original_area_slice : tuple + A tuple of slices pointing to the area of the original array. """ - if pad_amt == 0: - return arr - - edge_slice = _slice_last(arr.shape, 1, axis=axis) - edge_arr = arr[edge_slice] - return _do_append(arr, edge_arr.repeat(pad_amt, axis=axis), axis) + # Allocate grown array + new_shape = tuple( + left + size + right + for size, (left, right) in zip(array.shape, pad_width) + ) + order = 'F' if array.flags.fnc else 'C' # Fortran and not also C-order + padded = np.empty(new_shape, dtype=array.dtype, order=order) + if fill_value is not None: + padded.fill(fill_value) -def _prepend_ramp(arr, pad_amt, end, axis=-1): - """ - Prepend linear ramp along `axis`. + # Copy old array into correct space + original_area_slice = tuple( + slice(left, left + size) + for size, (left, right) in zip(array.shape, pad_width) + ) + padded[original_area_slice] = array - Parameters - ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to prepend. - end : scalar - Constal value to use. For best results should be of type `arr.dtype`; - if not `arr.dtype` will be cast to `arr.dtype`. - axis : int - Axis along which to pad `arr`. + return padded, original_area_slice - Returns - ------- - padarr : ndarray - Output array, with `pad_amt` values prepended along `axis`. The - prepended region ramps linearly from the edge value to `end`. +def _set_pad_area(padded, axis, width_pair, value_pair): """ - if pad_amt == 0: - return arr - - # Generate shape for final concatenated array - padshape = tuple(x if i != axis else pad_amt - for (i, x) in enumerate(arr.shape)) - - # Generate an n-dimensional array incrementing along `axis` - ramp_arr = _arange_ndarray(arr, padshape, axis, - reverse=True).astype(np.float64) - - # Appropriate slicing to extract n-dimensional edge along `axis` - edge_slice = _slice_first(arr.shape, 1, axis=axis) - - # Extract edge, and extend along `axis` - edge_pad = arr[edge_slice].repeat(pad_amt, axis) - - # Linear ramp - slope = (end - edge_pad) / float(pad_amt) - ramp_arr = ramp_arr * slope - ramp_arr += edge_pad - _round_ifneeded(ramp_arr, arr.dtype) - - # Ramp values will most likely be float, cast them to the same type as arr - return _do_prepend(arr, ramp_arr, axis) - - -def _append_ramp(arr, pad_amt, end, axis=-1): - """ - Append linear ramp along `axis`. + Set empty-padded area in given dimension. Parameters ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to append. - end : scalar - Constal value to use. For best results should be of type `arr.dtype`; - if not `arr.dtype` will be cast to `arr.dtype`. + padded : ndarray + Array with the pad area which is modified inplace. axis : int - Axis along which to pad `arr`. - - Returns - ------- - padarr : ndarray - Output array, with `pad_amt` values appended along `axis`. The - appended region ramps linearly from the edge value to `end`. - + Dimension with the pad area to set. + width_pair : (int, int) + Pair of widths that mark the pad area on both sides in the given + dimension. + value_pair : tuple of scalars or ndarrays + Values inserted into the pad area on each side. It must match or be + broadcastable to the shape of `arr`. """ - if pad_amt == 0: - return arr - - # Generate shape for final concatenated array - padshape = tuple(x if i != axis else pad_amt - for (i, x) in enumerate(arr.shape)) + left_slice = _slice_at_axis(slice(None, width_pair[0]), axis) + padded[left_slice] = value_pair[0] - # Generate an n-dimensional array incrementing along `axis` - ramp_arr = _arange_ndarray(arr, padshape, axis, - reverse=False).astype(np.float64) + right_slice = _slice_at_axis( + slice(padded.shape[axis] - width_pair[1], None), axis) + padded[right_slice] = value_pair[1] - # Slice a chunk from the edge to calculate stats on - edge_slice = _slice_last(arr.shape, 1, axis=axis) - # Extract edge, and extend along `axis` - edge_pad = arr[edge_slice].repeat(pad_amt, axis) - - # Linear ramp - slope = (end - edge_pad) / float(pad_amt) - ramp_arr = ramp_arr * slope - ramp_arr += edge_pad - _round_ifneeded(ramp_arr, arr.dtype) - - # Ramp values will most likely be float, cast them to the same type as arr - return _do_append(arr, ramp_arr, axis) - - -def _prepend_max(arr, pad_amt, num, axis=-1): +def _get_edges(padded, axis, width_pair): """ - Prepend `pad_amt` maximum values along `axis`. + Retrieve edge values from empty-padded array in given dimension. Parameters ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to prepend. - num : int - Depth into `arr` along `axis` to calculate maximum. - Range: [1, `arr.shape[axis]`] or None (entire axis) - axis : int - Axis along which to pad `arr`. - - Returns - ------- - padarr : ndarray - Output array, with `pad_amt` values appended along `axis`. The - prepended region is the maximum of the first `num` values along - `axis`. - - """ - if pad_amt == 0: - return arr - - # Equivalent to edge padding for single value, so do that instead - if num == 1: - return _prepend_edge(arr, pad_amt, axis) - - # Use entire array if `num` is too large - if num is not None: - if num >= arr.shape[axis]: - num = None - - # Slice a chunk from the edge to calculate stats on - max_slice = _slice_first(arr.shape, num, axis=axis) - - # Extract slice, calculate max - max_chunk = arr[max_slice].max(axis=axis, keepdims=True) - - # Concatenate `arr` with `max_chunk`, extended along `axis` by `pad_amt` - return _do_prepend(arr, max_chunk.repeat(pad_amt, axis=axis), axis) - - -def _append_max(arr, pad_amt, num, axis=-1): - """ - Pad one `axis` of `arr` with the maximum of the last `num` elements. - - Parameters - ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to append. - num : int - Depth into `arr` along `axis` to calculate maximum. - Range: [1, `arr.shape[axis]`] or None (entire axis) + padded : ndarray + Empty-padded array. axis : int - Axis along which to pad `arr`. + Dimension in which the edges are considered. + width_pair : (int, int) + Pair of widths that mark the pad area on both sides in the given + dimension. Returns ------- - padarr : ndarray - Output array, with `pad_amt` values appended along `axis`. The - appended region is the maximum of the final `num` values along `axis`. - + left_edge, right_edge : ndarray + Edge values of the valid area in `padded` in the given dimension. Its + shape will always match `padded` except for the dimension given by + `axis` which will have a length of 1. """ - if pad_amt == 0: - return arr - - # Equivalent to edge padding for single value, so do that instead - if num == 1: - return _append_edge(arr, pad_amt, axis) - - # Use entire array if `num` is too large - if num is not None: - if num >= arr.shape[axis]: - num = None - - # Slice a chunk from the edge to calculate stats on - if num is not None: - max_slice = _slice_last(arr.shape, num, axis=axis) - else: - max_slice = tuple(slice(None) for x in arr.shape) + left_index = width_pair[0] + left_slice = _slice_at_axis(slice(left_index, left_index + 1), axis) + left_edge = padded[left_slice] - # Extract slice, calculate max - max_chunk = arr[max_slice].max(axis=axis, keepdims=True) + right_index = padded.shape[axis] - width_pair[1] + right_slice = _slice_at_axis(slice(right_index - 1, right_index), axis) + right_edge = padded[right_slice] - # Concatenate `arr` with `max_chunk`, extended along `axis` by `pad_amt` - return _do_append(arr, max_chunk.repeat(pad_amt, axis=axis), axis) + return left_edge, right_edge -def _prepend_mean(arr, pad_amt, num, axis=-1): +def _get_linear_ramps(padded, axis, width_pair, end_value_pair): """ - Prepend `pad_amt` mean values along `axis`. + Construct linear ramps for empty-padded array in given dimension. Parameters ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to prepend. - num : int - Depth into `arr` along `axis` to calculate mean. - Range: [1, `arr.shape[axis]`] or None (entire axis) + padded : ndarray + Empty-padded array. axis : int - Axis along which to pad `arr`. + Dimension in which the ramps are constructed. + width_pair : (int, int) + Pair of widths that mark the pad area on both sides in the given + dimension. + end_value_pair : (scalar, scalar) + End values for the linear ramps which form the edge of the fully padded + array. These values are included in the linear ramps. Returns ------- - padarr : ndarray - Output array, with `pad_amt` values prepended along `axis`. The - prepended region is the mean of the first `num` values along `axis`. - + left_ramp, right_ramp : ndarray + Linear ramps to set on both sides of `padded`. """ - if pad_amt == 0: - return arr + edge_pair = _get_edges(padded, axis, width_pair) - # Equivalent to edge padding for single value, so do that instead - if num == 1: - return _prepend_edge(arr, pad_amt, axis) + left_ramp = _linear_ramp( + padded.ndim, axis, start=end_value_pair[0], stop=edge_pair[0], + size=width_pair[0], reverse=False + ) + _round_if_needed(left_ramp, padded.dtype) - # Use entire array if `num` is too large - if num is not None: - if num >= arr.shape[axis]: - num = None + right_ramp = _linear_ramp( + padded.ndim, axis, start=end_value_pair[1], stop=edge_pair[1], + size=width_pair[1], reverse=True + ) + _round_if_needed(right_ramp, padded.dtype) - # Slice a chunk from the edge to calculate stats on - mean_slice = _slice_first(arr.shape, num, axis=axis) + return left_ramp, right_ramp - # Extract slice, calculate mean - mean_chunk = arr[mean_slice].mean(axis, keepdims=True) - _round_ifneeded(mean_chunk, arr.dtype) - # Concatenate `arr` with `mean_chunk`, extended along `axis` by `pad_amt` - return _do_prepend(arr, mean_chunk.repeat(pad_amt, axis), axis=axis) - - -def _append_mean(arr, pad_amt, num, axis=-1): +def _get_stats(padded, axis, width_pair, length_pair, stat_func): """ - Append `pad_amt` mean values along `axis`. + Calculate statistic for the empty-padded array in given dimnsion. Parameters ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to append. - num : int - Depth into `arr` along `axis` to calculate mean. - Range: [1, `arr.shape[axis]`] or None (entire axis) + padded : ndarray + Empty-padded array. axis : int - Axis along which to pad `arr`. + Dimension in which the statistic is calculated. + width_pair : (int, int) + Pair of widths that mark the pad area on both sides in the given + dimension. + length_pair : 2-element sequence of None or int + Gives the number of values in valid area from each side that is + taken into account when calculating the statistic. If None the entire + valid area in `padded` is considered. + stat_func : function + Function to compute statistic. The expected signature is + ``stat_func(x: ndarray, axis: int, keepdims: bool) -> ndarray``. Returns ------- - padarr : ndarray - Output array, with `pad_amt` values appended along `axis`. The - appended region is the maximum of the final `num` values along `axis`. - - """ - if pad_amt == 0: - return arr - - # Equivalent to edge padding for single value, so do that instead - if num == 1: - return _append_edge(arr, pad_amt, axis) - - # Use entire array if `num` is too large - if num is not None: - if num >= arr.shape[axis]: - num = None - - # Slice a chunk from the edge to calculate stats on - if num is not None: - mean_slice = _slice_last(arr.shape, num, axis=axis) - else: - mean_slice = tuple(slice(None) for x in arr.shape) - - # Extract slice, calculate mean - mean_chunk = arr[mean_slice].mean(axis=axis, keepdims=True) - _round_ifneeded(mean_chunk, arr.dtype) - - # Concatenate `arr` with `mean_chunk`, extended along `axis` by `pad_amt` - return _do_append(arr, mean_chunk.repeat(pad_amt, axis), axis=axis) - - -def _prepend_med(arr, pad_amt, num, axis=-1): - """ - Prepend `pad_amt` median values along `axis`. + left_stat, right_stat : ndarray + Calculated statistic for both sides of `padded`. + """ + # Calculate indices of the edges of the area with original values + left_index = width_pair[0] + right_index = padded.shape[axis] - width_pair[1] + # as well as its length + max_length = right_index - left_index + + # Limit stat_lengths to max_length + left_length, right_length = length_pair + if left_length is None or max_length < left_length: + left_length = max_length + if right_length is None or max_length < right_length: + right_length = max_length + + # Calculate statistic for the left side + left_slice = _slice_at_axis( + slice(left_index, left_index + left_length), axis) + left_chunk = padded[left_slice] + left_stat = stat_func(left_chunk, axis=axis, keepdims=True) + _round_if_needed(left_stat, padded.dtype) + + if left_length == right_length == max_length: + # return early as right_stat must be identical to left_stat + return left_stat, left_stat + + # Calculate statistic for the right side + right_slice = _slice_at_axis( + slice(right_index - right_length, right_index), axis) + right_chunk = padded[right_slice] + right_stat = stat_func(right_chunk, axis=axis, keepdims=True) + _round_if_needed(right_stat, padded.dtype) + return left_stat, right_stat + + +def _set_reflect_both(padded, axis, width_pair, method, include_edge=False): + """ + Pad `axis` of `arr` with reflection. Parameters ---------- - arr : ndarray + padded : ndarray Input array of arbitrary shape. - pad_amt : int - Amount of padding to prepend. - num : int - Depth into `arr` along `axis` to calculate median. - Range: [1, `arr.shape[axis]`] or None (entire axis) axis : int Axis along which to pad `arr`. - - Returns - ------- - padarr : ndarray - Output array, with `pad_amt` values prepended along `axis`. The - prepended region is the median of the first `num` values along `axis`. - - """ - if pad_amt == 0: - return arr - - # Equivalent to edge padding for single value, so do that instead - if num == 1: - return _prepend_edge(arr, pad_amt, axis) - - # Use entire array if `num` is too large - if num is not None: - if num >= arr.shape[axis]: - num = None - - # Slice a chunk from the edge to calculate stats on - med_slice = _slice_first(arr.shape, num, axis=axis) - - # Extract slice, calculate median - med_chunk = np.median(arr[med_slice], axis=axis, keepdims=True) - _round_ifneeded(med_chunk, arr.dtype) - - # Concatenate `arr` with `med_chunk`, extended along `axis` by `pad_amt` - return _do_prepend(arr, med_chunk.repeat(pad_amt, axis), axis=axis) - - -def _append_med(arr, pad_amt, num, axis=-1): - """ - Append `pad_amt` median values along `axis`. - - Parameters - ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to append. - num : int - Depth into `arr` along `axis` to calculate median. - Range: [1, `arr.shape[axis]`] or None (entire axis) - axis : int - Axis along which to pad `arr`. - - Returns - ------- - padarr : ndarray - Output array, with `pad_amt` values appended along `axis`. The - appended region is the median of the final `num` values along `axis`. - - """ - if pad_amt == 0: - return arr - - # Equivalent to edge padding for single value, so do that instead - if num == 1: - return _append_edge(arr, pad_amt, axis) - - # Use entire array if `num` is too large - if num is not None: - if num >= arr.shape[axis]: - num = None - - # Slice a chunk from the edge to calculate stats on - if num is not None: - med_slice = _slice_last(arr.shape, num, axis=axis) - else: - med_slice = tuple(slice(None) for x in arr.shape) - - # Extract slice, calculate median - med_chunk = np.median(arr[med_slice], axis=axis, keepdims=True) - _round_ifneeded(med_chunk, arr.dtype) - - # Concatenate `arr` with `med_chunk`, extended along `axis` by `pad_amt` - return _do_append(arr, med_chunk.repeat(pad_amt, axis), axis=axis) - - -def _prepend_min(arr, pad_amt, num, axis=-1): - """ - Prepend `pad_amt` minimum values along `axis`. - - Parameters - ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to prepend. - num : int - Depth into `arr` along `axis` to calculate minimum. - Range: [1, `arr.shape[axis]`] or None (entire axis) - axis : int - Axis along which to pad `arr`. - - Returns - ------- - padarr : ndarray - Output array, with `pad_amt` values prepended along `axis`. The - prepended region is the minimum of the first `num` values along - `axis`. - - """ - if pad_amt == 0: - return arr - - # Equivalent to edge padding for single value, so do that instead - if num == 1: - return _prepend_edge(arr, pad_amt, axis) - - # Use entire array if `num` is too large - if num is not None: - if num >= arr.shape[axis]: - num = None - - # Slice a chunk from the edge to calculate stats on - min_slice = _slice_first(arr.shape, num, axis=axis) - - # Extract slice, calculate min - min_chunk = arr[min_slice].min(axis=axis, keepdims=True) - - # Concatenate `arr` with `min_chunk`, extended along `axis` by `pad_amt` - return _do_prepend(arr, min_chunk.repeat(pad_amt, axis), axis=axis) - - -def _append_min(arr, pad_amt, num, axis=-1): - """ - Append `pad_amt` median values along `axis`. - - Parameters - ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : int - Amount of padding to append. - num : int - Depth into `arr` along `axis` to calculate minimum. - Range: [1, `arr.shape[axis]`] or None (entire axis) - axis : int - Axis along which to pad `arr`. - - Returns - ------- - padarr : ndarray - Output array, with `pad_amt` values appended along `axis`. The - appended region is the minimum of the final `num` values along `axis`. - - """ - if pad_amt == 0: - return arr - - # Equivalent to edge padding for single value, so do that instead - if num == 1: - return _append_edge(arr, pad_amt, axis) - - # Use entire array if `num` is too large - if num is not None: - if num >= arr.shape[axis]: - num = None - - # Slice a chunk from the edge to calculate stats on - if num is not None: - min_slice = _slice_last(arr.shape, num, axis=axis) - else: - min_slice = tuple(slice(None) for x in arr.shape) - - # Extract slice, calculate min - min_chunk = arr[min_slice].min(axis=axis, keepdims=True) - - # Concatenate `arr` with `min_chunk`, extended along `axis` by `pad_amt` - return _do_append(arr, min_chunk.repeat(pad_amt, axis), axis=axis) - - -def _pad_ref(arr, pad_amt, method, axis=-1): - """ - Pad `axis` of `arr` by reflection. - - Parameters - ---------- - arr : ndarray - Input array of arbitrary shape. - pad_amt : tuple of ints, length 2 - Padding to (prepend, append) along `axis`. + width_pair : (int, int) + Pair of widths that mark the pad area on both sides in the given + dimension. method : str Controls method of reflection; options are 'even' or 'odd'. - axis : int - Axis along which to pad `arr`. + include_edge : bool + If true, edge value is included in reflection, otherwise the edge + value forms the symmetric axis to the reflection. Returns ------- - padarr : ndarray - Output array, with `pad_amt[0]` values prepended and `pad_amt[1]` - values appended along `axis`. Both regions are padded with reflected - values from the original array. - - Notes - ----- - This algorithm does not pad with repetition, i.e. the edges are not - repeated in the reflection. For that behavior, use `mode='symmetric'`. - - The modes 'reflect', 'symmetric', and 'wrap' must be padded with a - single function, lest the indexing tricks in non-integer multiples of the - original shape would violate repetition in the final iteration. - - """ - # Implicit booleanness to test for zero (or None) in any scalar type - if pad_amt[0] == 0 and pad_amt[1] == 0: - return arr - - ########################################################################## - # Prepended region - - # Slice off a reverse indexed chunk from near edge to pad `arr` before - ref_slice = _slice_at_axis(arr.shape, slice(pad_amt[0], 0, -1), axis=axis) - - ref_chunk1 = arr[ref_slice] - - # Memory/computationally more expensive, only do this if `method='odd'` - if 'odd' in method and pad_amt[0] > 0: - edge_slice1 = _slice_first(arr.shape, 1, axis=axis) - edge_chunk = arr[edge_slice1] - ref_chunk1 = 2 * edge_chunk - ref_chunk1 - del edge_chunk - - ########################################################################## - # Appended region - - # Slice off a reverse indexed chunk from far edge to pad `arr` after - start = arr.shape[axis] - pad_amt[1] - 1 - end = arr.shape[axis] - 1 - ref_slice = _slice_at_axis(arr.shape, slice(start, end), axis=axis) - rev_idx = _slice_at_axis(arr.shape, slice(None, None, -1), axis=axis) - ref_chunk2 = arr[ref_slice][rev_idx] - - if 'odd' in method: - edge_slice2 = _slice_last(arr.shape, 1, axis=axis) - edge_chunk = arr[edge_slice2] - ref_chunk2 = 2 * edge_chunk - ref_chunk2 - del edge_chunk - - # Concatenate `arr` with both chunks, extending along `axis` - return np.concatenate((ref_chunk1, arr, ref_chunk2), axis=axis) - - -def _pad_sym(arr, pad_amt, method, axis=-1): - """ - Pad `axis` of `arr` by symmetry. - - Parameters - ---------- - arr : ndarray - Input array of arbitrary shape. pad_amt : tuple of ints, length 2 - Padding to (prepend, append) along `axis`. - method : str - Controls method of symmetry; options are 'even' or 'odd'. - axis : int - Axis along which to pad `arr`. - - Returns - ------- - padarr : ndarray - Output array, with `pad_amt[0]` values prepended and `pad_amt[1]` - values appended along `axis`. Both regions are padded with symmetric - values from the original array. - - Notes - ----- - This algorithm DOES pad with repetition, i.e. the edges are repeated. - For padding without repeated edges, use `mode='reflect'`. - - The modes 'reflect', 'symmetric', and 'wrap' must be padded with a - single function, lest the indexing tricks in non-integer multiples of the - original shape would violate repetition in the final iteration. - + New index positions of padding to do along the `axis`. If these are + both 0, padding is done in this dimension. """ - # Implicit booleanness to test for zero (or None) in any scalar type - if pad_amt[0] == 0 and pad_amt[1] == 0: - return arr - - ########################################################################## - # Prepended region - - # Slice off a reverse indexed chunk from near edge to pad `arr` before - sym_slice = _slice_first(arr.shape, pad_amt[0], axis=axis) - rev_idx = _slice_at_axis(arr.shape, slice(None, None, -1), axis=axis) - sym_chunk1 = arr[sym_slice][rev_idx] - - # Memory/computationally more expensive, only do this if `method='odd'` - if 'odd' in method and pad_amt[0] > 0: - edge_slice1 = _slice_first(arr.shape, 1, axis=axis) - edge_chunk = arr[edge_slice1] - sym_chunk1 = 2 * edge_chunk - sym_chunk1 - del edge_chunk - - ########################################################################## - # Appended region + left_pad, right_pad = width_pair + old_length = padded.shape[axis] - right_pad - left_pad - # Slice off a reverse indexed chunk from far edge to pad `arr` after - sym_slice = _slice_last(arr.shape, pad_amt[1], axis=axis) - sym_chunk2 = arr[sym_slice][rev_idx] - - if 'odd' in method: - edge_slice2 = _slice_last(arr.shape, 1, axis=axis) - edge_chunk = arr[edge_slice2] - sym_chunk2 = 2 * edge_chunk - sym_chunk2 - del edge_chunk - - # Concatenate `arr` with both chunks, extending along `axis` - return np.concatenate((sym_chunk1, arr, sym_chunk2), axis=axis) - - -def _pad_wrap(arr, pad_amt, axis=-1): - """ - Pad `axis` of `arr` via wrapping. + if include_edge: + # Edge is included, we need to offset the pad amount by 1 + edge_offset = 1 + else: + edge_offset = 0 # Edge is not included, no need to offset pad amount + old_length -= 1 # but must be omitted from the chunk + + if left_pad > 0: + # Pad with reflected values on left side: + # First limit chunk size which can't be larger than pad area + chunk_length = min(old_length, left_pad) + # Slice right to left, stop on or next to edge, start relative to stop + stop = left_pad - edge_offset + start = stop + chunk_length + left_slice = _slice_at_axis(slice(start, stop, -1), axis) + left_chunk = padded[left_slice] + + if method == "odd": + # Negate chunk and align with edge + edge_slice = _slice_at_axis(slice(left_pad, left_pad + 1), axis) + left_chunk = 2 * padded[edge_slice] - left_chunk + + # Insert chunk into padded area + start = left_pad - chunk_length + stop = left_pad + pad_area = _slice_at_axis(slice(start, stop), axis) + padded[pad_area] = left_chunk + # Adjust pointer to left edge for next iteration + left_pad -= chunk_length + + if right_pad > 0: + # Pad with reflected values on right side: + # First limit chunk size which can't be larger than pad area + chunk_length = min(old_length, right_pad) + # Slice right to left, start on or next to edge, stop relative to start + start = -right_pad + edge_offset - 2 + stop = start - chunk_length + right_slice = _slice_at_axis(slice(start, stop, -1), axis) + right_chunk = padded[right_slice] + + if method == "odd": + # Negate chunk and align with edge + edge_slice = _slice_at_axis( + slice(-right_pad - 1, -right_pad), axis) + right_chunk = 2 * padded[edge_slice] - right_chunk + + # Insert chunk into padded area + start = padded.shape[axis] - right_pad + stop = start + chunk_length + pad_area = _slice_at_axis(slice(start, stop), axis) + padded[pad_area] = right_chunk + # Adjust pointer to right edge for next iteration + right_pad -= chunk_length + + return left_pad, right_pad + + +def _set_wrap_both(padded, axis, width_pair): + """ + Pad `axis` of `arr` with wrapped values. Parameters ---------- - arr : ndarray + padded : ndarray Input array of arbitrary shape. - pad_amt : tuple of ints, length 2 - Padding to (prepend, append) along `axis`. axis : int Axis along which to pad `arr`. + width_pair : (int, int) + Pair of widths that mark the pad area on both sides in the given + dimension. Returns ------- - padarr : ndarray - Output array, with `pad_amt[0]` values prepended and `pad_amt[1]` - values appended along `axis`. Both regions are padded wrapped values - from the opposite end of `axis`. - - Notes - ----- - This method of padding is also known as 'tile' or 'tiling'. - - The modes 'reflect', 'symmetric', and 'wrap' must be padded with a - single function, lest the indexing tricks in non-integer multiples of the - original shape would violate repetition in the final iteration. - - """ - # Implicit booleanness to test for zero (or None) in any scalar type - if pad_amt[0] == 0 and pad_amt[1] == 0: - return arr - - ########################################################################## - # Prepended region - - # Slice off a reverse indexed chunk from near edge to pad `arr` before - wrap_slice = _slice_last(arr.shape, pad_amt[0], axis=axis) - wrap_chunk1 = arr[wrap_slice] - - ########################################################################## - # Appended region - - # Slice off a reverse indexed chunk from far edge to pad `arr` after - wrap_slice = _slice_first(arr.shape, pad_amt[1], axis=axis) - wrap_chunk2 = arr[wrap_slice] - - # Concatenate `arr` with both chunks, extending along `axis` - return np.concatenate((wrap_chunk1, arr, wrap_chunk2), axis=axis) + pad_amt : tuple of ints, length 2 + New index positions of padding to do along the `axis`. If these are + both 0, padding is done in this dimension. + """ + left_pad, right_pad = width_pair + period = padded.shape[axis] - right_pad - left_pad + + # If the current dimension of `arr` doesn't contain enough valid values + # (not part of the undefined pad area) we need to pad multiple times. + # Each time the pad area shrinks on both sides which is communicated with + # these variables. + new_left_pad = 0 + new_right_pad = 0 + + if left_pad > 0: + # Pad with wrapped values on left side + # First slice chunk from right side of the non-pad area. + # Use min(period, left_pad) to ensure that chunk is not larger than + # pad area + right_slice = _slice_at_axis( + slice(-right_pad - min(period, left_pad), + -right_pad if right_pad != 0 else None), + axis + ) + right_chunk = padded[right_slice] + + if left_pad > period: + # Chunk is smaller than pad area + pad_area = _slice_at_axis(slice(left_pad - period, left_pad), axis) + new_left_pad = left_pad - period + else: + # Chunk matches pad area + pad_area = _slice_at_axis(slice(None, left_pad), axis) + padded[pad_area] = right_chunk + + if right_pad > 0: + # Pad with wrapped values on right side + # First slice chunk from left side of the non-pad area. + # Use min(period, right_pad) to ensure that chunk is not larger than + # pad area + left_slice = _slice_at_axis( + slice(left_pad, left_pad + min(period, right_pad),), axis) + left_chunk = padded[left_slice] + + if right_pad > period: + # Chunk is smaller than pad area + pad_area = _slice_at_axis( + slice(-right_pad, -right_pad + period), axis) + new_right_pad = right_pad - period + else: + # Chunk matches pad area + pad_area = _slice_at_axis(slice(-right_pad, None), axis) + padded[pad_area] = left_chunk + + return new_left_pad, new_right_pad def _as_pairs(x, ndim, as_index=False): @@ -953,23 +567,23 @@ def _as_pairs(x, ndim, as_index=False): return np.broadcast_to(x, (ndim, 2)).tolist() -############################################################################### -# Public functions - - def _pad_dispatcher(array, pad_width, mode=None, **kwargs): return (array,) +############################################################################### +# Public functions + + @array_function_dispatch(_pad_dispatcher, module='numpy') def pad(array, pad_width, mode='constant', **kwargs): """ - Pads an array. + Pad an array. Parameters ---------- array : array_like of rank N - Input array + The array to pad. pad_width : {sequence, array_like, int} Number of values padded to the edges of each axis. ((before_1, after_1), ... (before_N, after_N)) unique pad widths @@ -1010,6 +624,11 @@ def pad(array, pad_width, mode='constant', **kwargs): Pads with the wrap of the vector along the axis. The first values are used to pad the end and the end values are used to pad the beginning. + 'empty' + Pads with undefined values. + + .. versionadded:: 1.17 + Padding function, see Notes. stat_length : sequence or int, optional @@ -1099,7 +718,7 @@ def pad(array, pad_width, mode='constant', **kwargs): Examples -------- >>> a = [1, 2, 3, 4, 5] - >>> np.pad(a, (2,3), 'constant', constant_values=(4, 6)) + >>> np.pad(a, (2, 3), 'constant', constant_values=(4, 6)) array([4, 4, 1, ..., 6, 6, 6]) >>> np.pad(a, (2, 3), 'edge') @@ -1165,15 +784,30 @@ def pad(array, pad_width, mode='constant', **kwargs): [100, 100, 100, 100, 100, 100, 100], [100, 100, 100, 100, 100, 100, 100]]) """ - if not np.asarray(pad_width).dtype.kind == 'i': + array = np.asarray(array) + pad_width = np.asarray(pad_width) + + if not pad_width.dtype.kind == 'i': raise TypeError('`pad_width` must be of integral type.') - narray = np.array(array) - pad_width = _as_pairs(pad_width, narray.ndim, as_index=True) + # Broadcast to shape (array.ndim, 2) + pad_width = _as_pairs(pad_width, array.ndim, as_index=True) - allowedkwargs = { + if callable(mode): + # Old behavior: Use user-supplied function with np.apply_along_axis + function = mode + # Create a new zero padded array + padded, _ = _pad_simple(array, pad_width, fill_value=0) + # And apply along each axis + for axis in range(padded.ndim): + np.apply_along_axis( + function, axis, padded, pad_width[axis], axis, kwargs) + return padded + + # Make sure that no unsupported keywords were passed for the current mode + allowed_kwargs = { + 'empty': [], 'edge': [], 'wrap': [], 'constant': ['constant_values'], - 'edge': [], 'linear_ramp': ['end_values'], 'maximum': ['stat_length'], 'mean': ['stat_length'], @@ -1181,175 +815,101 @@ def pad(array, pad_width, mode='constant', **kwargs): 'minimum': ['stat_length'], 'reflect': ['reflect_type'], 'symmetric': ['reflect_type'], - 'wrap': [], - } - - kwdefaults = { - 'stat_length': None, - 'constant_values': 0, - 'end_values': 0, - 'reflect_type': 'even', - } - - if isinstance(mode, np.compat.basestring): - # Make sure have allowed kwargs appropriate for mode - for key in kwargs: - if key not in allowedkwargs[mode]: - raise ValueError('%s keyword not in allowed keywords %s' % - (key, allowedkwargs[mode])) - - # Set kwarg defaults - for kw in allowedkwargs[mode]: - kwargs.setdefault(kw, kwdefaults[kw]) - - # Need to only normalize particular keywords. - for i in kwargs: - if i == 'stat_length': - kwargs[i] = _as_pairs(kwargs[i], narray.ndim, as_index=True) - if i in ['end_values', 'constant_values']: - kwargs[i] = _as_pairs(kwargs[i], narray.ndim) - else: - # Drop back to old, slower np.apply_along_axis mode for user-supplied - # vector function - function = mode - - # Create a new padded array - rank = list(range(narray.ndim)) - total_dim_increase = [np.sum(pad_width[i]) for i in rank] - offset_slices = tuple( - slice(pad_width[i][0], pad_width[i][0] + narray.shape[i]) - for i in rank) - new_shape = np.array(narray.shape) + total_dim_increase - newmat = np.zeros(new_shape, narray.dtype) - - # Insert the original array into the padded array - newmat[offset_slices] = narray - - # This is the core of pad ... - for iaxis in rank: - np.apply_along_axis(function, - iaxis, - newmat, - pad_width[iaxis], - iaxis, - kwargs) - return newmat - - # If we get here, use new padding method - newmat = narray.copy() - - # API preserved, but completely new algorithm which pads by building the - # entire block to pad before/after `arr` with in one step, for each axis. - if mode == 'constant': - for axis, ((pad_before, pad_after), (before_val, after_val)) \ - in enumerate(zip(pad_width, kwargs['constant_values'])): - newmat = _prepend_const(newmat, pad_before, before_val, axis) - newmat = _append_const(newmat, pad_after, after_val, axis) - - elif mode == 'edge': - for axis, (pad_before, pad_after) in enumerate(pad_width): - newmat = _prepend_edge(newmat, pad_before, axis) - newmat = _append_edge(newmat, pad_after, axis) - - elif mode == 'linear_ramp': - for axis, ((pad_before, pad_after), (before_val, after_val)) \ - in enumerate(zip(pad_width, kwargs['end_values'])): - newmat = _prepend_ramp(newmat, pad_before, before_val, axis) - newmat = _append_ramp(newmat, pad_after, after_val, axis) - - elif mode == 'maximum': - for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ - in enumerate(zip(pad_width, kwargs['stat_length'])): - newmat = _prepend_max(newmat, pad_before, chunk_before, axis) - newmat = _append_max(newmat, pad_after, chunk_after, axis) - - elif mode == 'mean': - for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ - in enumerate(zip(pad_width, kwargs['stat_length'])): - newmat = _prepend_mean(newmat, pad_before, chunk_before, axis) - newmat = _append_mean(newmat, pad_after, chunk_after, axis) - - elif mode == 'median': - for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ - in enumerate(zip(pad_width, kwargs['stat_length'])): - newmat = _prepend_med(newmat, pad_before, chunk_before, axis) - newmat = _append_med(newmat, pad_after, chunk_after, axis) - - elif mode == 'minimum': - for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ - in enumerate(zip(pad_width, kwargs['stat_length'])): - newmat = _prepend_min(newmat, pad_before, chunk_before, axis) - newmat = _append_min(newmat, pad_after, chunk_after, axis) - - elif mode == 'reflect': - for axis, (pad_before, pad_after) in enumerate(pad_width): - if narray.shape[axis] == 0: - # Axes with non-zero padding cannot be empty. - if pad_before > 0 or pad_after > 0: - raise ValueError("There aren't any elements to reflect" - " in axis {} of `array`".format(axis)) - # Skip zero padding on empty axes. - continue - - # Recursive padding along any axis where `pad_amt` is too large - # for indexing tricks. We can only safely pad the original axis - # length, to keep the period of the reflections consistent. - if ((pad_before > 0) or - (pad_after > 0)) and newmat.shape[axis] == 1: + } + try: + unsupported_kwargs = set(kwargs) - set(allowed_kwargs[mode]) + except KeyError: + raise ValueError("mode '{}' is not supported".format(mode)) + if unsupported_kwargs: + raise ValueError("unsupported keyword arguments for mode '{}': {}" + .format(mode, unsupported_kwargs)) + + stat_functions = {"maximum": np.max, "minimum": np.min, + "mean": np.mean, "median": np.median} + + # Create array with final shape and original values + # (padded area is undefined) + padded, original_area_slice = _pad_simple(array, pad_width) + # And prepare iteration over all dimensions + # (zipping may be more readable than using enumerate) + axes = range(padded.ndim) + + if mode == "constant": + values = kwargs.get("constant_values", 0) + values = _as_pairs(values, padded.ndim) + for axis, width_pair, value_pair in zip(axes, pad_width, values): + roi = _view_roi(padded, original_area_slice, axis) + _set_pad_area(roi, axis, width_pair, value_pair) + + elif mode == "empty": + pass # Do nothing as _pad_simple already returned the correct result + + elif array.size == 0: + # Only modes "constant" and "empty" can extend empty axes, all other + # modes depend on `array` not being empty + # -> ensure every empty axis is only "padded with 0" + for axis, width_pair in zip(axes, pad_width): + if array.shape[axis] == 0 and any(width_pair): + raise ValueError( + "can't extend empty axis {} using modes other than " + "'constant' or 'empty'".format(axis) + ) + # passed, don't need to do anything more as _pad_simple already + # returned the correct result + + elif mode == "edge": + for axis, width_pair in zip(axes, pad_width): + roi = _view_roi(padded, original_area_slice, axis) + edge_pair = _get_edges(roi, axis, width_pair) + _set_pad_area(roi, axis, width_pair, edge_pair) + + elif mode == "linear_ramp": + end_values = kwargs.get("end_values", 0) + end_values = _as_pairs(end_values, padded.ndim) + for axis, width_pair, value_pair in zip(axes, pad_width, end_values): + roi = _view_roi(padded, original_area_slice, axis) + ramp_pair = _get_linear_ramps(roi, axis, width_pair, value_pair) + _set_pad_area(roi, axis, width_pair, ramp_pair) + + elif mode in stat_functions: + func = stat_functions[mode] + length = kwargs.get("stat_length", None) + length = _as_pairs(length, padded.ndim, as_index=True) + for axis, width_pair, length_pair in zip(axes, pad_width, length): + roi = _view_roi(padded, original_area_slice, axis) + stat_pair = _get_stats(roi, axis, width_pair, length_pair, func) + _set_pad_area(roi, axis, width_pair, stat_pair) + + elif mode in {"reflect", "symmetric"}: + method = kwargs.get("reflect_type", "even") + include_edge = True if mode == "symmetric" else False + for axis, (left_index, right_index) in zip(axes, pad_width): + if array.shape[axis] == 1 and (left_index > 0 or right_index > 0): # Extending singleton dimension for 'reflect' is legacy # behavior; it really should raise an error. - newmat = _prepend_edge(newmat, pad_before, axis) - newmat = _append_edge(newmat, pad_after, axis) + edge_pair = _get_edges(padded, axis, (left_index, right_index)) + _set_pad_area( + padded, axis, (left_index, right_index), edge_pair) continue - method = kwargs['reflect_type'] - safe_pad = newmat.shape[axis] - 1 - while ((pad_before > safe_pad) or (pad_after > safe_pad)): - pad_iter_b = min(safe_pad, - safe_pad * (pad_before // safe_pad)) - pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad)) - newmat = _pad_ref(newmat, (pad_iter_b, - pad_iter_a), method, axis) - pad_before -= pad_iter_b - pad_after -= pad_iter_a - safe_pad += pad_iter_b + pad_iter_a - newmat = _pad_ref(newmat, (pad_before, pad_after), method, axis) - - elif mode == 'symmetric': - for axis, (pad_before, pad_after) in enumerate(pad_width): - # Recursive padding along any axis where `pad_amt` is too large - # for indexing tricks. We can only safely pad the original axis - # length, to keep the period of the reflections consistent. - method = kwargs['reflect_type'] - safe_pad = newmat.shape[axis] - while ((pad_before > safe_pad) or - (pad_after > safe_pad)): - pad_iter_b = min(safe_pad, - safe_pad * (pad_before // safe_pad)) - pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad)) - newmat = _pad_sym(newmat, (pad_iter_b, - pad_iter_a), method, axis) - pad_before -= pad_iter_b - pad_after -= pad_iter_a - safe_pad += pad_iter_b + pad_iter_a - newmat = _pad_sym(newmat, (pad_before, pad_after), method, axis) - - elif mode == 'wrap': - for axis, (pad_before, pad_after) in enumerate(pad_width): - # Recursive padding along any axis where `pad_amt` is too large - # for indexing tricks. We can only safely pad the original axis - # length, to keep the period of the reflections consistent. - safe_pad = newmat.shape[axis] - while ((pad_before > safe_pad) or - (pad_after > safe_pad)): - pad_iter_b = min(safe_pad, - safe_pad * (pad_before // safe_pad)) - pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad)) - newmat = _pad_wrap(newmat, (pad_iter_b, pad_iter_a), axis) - - pad_before -= pad_iter_b - pad_after -= pad_iter_a - safe_pad += pad_iter_b + pad_iter_a - newmat = _pad_wrap(newmat, (pad_before, pad_after), axis) - - return newmat + roi = _view_roi(padded, original_area_slice, axis) + while left_index > 0 or right_index > 0: + # Iteratively pad until dimension is filled with reflected + # values. This is necessary if the pad area is larger than + # the length of the original values in the current dimension. + left_index, right_index = _set_reflect_both( + roi, axis, (left_index, right_index), + method, include_edge + ) + + elif mode == "wrap": + for axis, (left_index, right_index) in zip(axes, pad_width): + roi = _view_roi(padded, original_area_slice, axis) + while left_index > 0 or right_index > 0: + # Iteratively pad until dimension is filled with wrapped + # values. This is necessary if the pad area is larger than + # the length of the original values in the current dimension. + left_index, right_index = _set_wrap_both( + roi, axis, (left_index, right_index)) + + return padded diff --git a/numpy/lib/tests/test_arraypad.py b/numpy/lib/tests/test_arraypad.py index b7393294ae95..d43c0d32e916 100644 --- a/numpy/lib/tests/test_arraypad.py +++ b/numpy/lib/tests/test_arraypad.py @@ -2,6 +2,7 @@ """ from __future__ import division, absolute_import, print_function +from itertools import chain import pytest @@ -21,6 +22,7 @@ 'reflect': {'reflect_type': 'even'}, 'symmetric': {'reflect_type': 'even'}, 'wrap': {}, + 'empty': {} } @@ -108,46 +110,25 @@ def test_exceptions(self): class TestConditionalShortcuts(object): - def test_zero_padding_shortcuts(self): + @pytest.mark.parametrize("mode", _all_modes.keys()) + def test_zero_padding_shortcuts(self, mode): test = np.arange(120).reshape(4, 5, 6) - pad_amt = [(0, 0) for axis in test.shape] - modes = ['constant', - 'edge', - 'linear_ramp', - 'maximum', - 'mean', - 'median', - 'minimum', - 'reflect', - 'symmetric', - 'wrap', - ] - for mode in modes: - assert_array_equal(test, np.pad(test, pad_amt, mode=mode)) - - def test_shallow_statistic_range(self): + pad_amt = [(0, 0) for _ in test.shape] + assert_array_equal(test, np.pad(test, pad_amt, mode=mode)) + + @pytest.mark.parametrize("mode", ['maximum', 'mean', 'median', 'minimum',]) + def test_shallow_statistic_range(self, mode): test = np.arange(120).reshape(4, 5, 6) - pad_amt = [(1, 1) for axis in test.shape] - modes = ['maximum', - 'mean', - 'median', - 'minimum', - ] - for mode in modes: - assert_array_equal(np.pad(test, pad_amt, mode='edge'), - np.pad(test, pad_amt, mode=mode, stat_length=1)) - - def test_clip_statistic_range(self): + pad_amt = [(1, 1) for _ in test.shape] + assert_array_equal(np.pad(test, pad_amt, mode='edge'), + np.pad(test, pad_amt, mode=mode, stat_length=1)) + + @pytest.mark.parametrize("mode", ['maximum', 'mean', 'median', 'minimum',]) + def test_clip_statistic_range(self, mode): test = np.arange(30).reshape(5, 6) - pad_amt = [(3, 3) for axis in test.shape] - modes = ['maximum', - 'mean', - 'median', - 'minimum', - ] - for mode in modes: - assert_array_equal(np.pad(test, pad_amt, mode=mode), - np.pad(test, pad_amt, mode=mode, stat_length=30)) + pad_amt = [(3, 3) for _ in test.shape] + assert_array_equal(np.pad(test, pad_amt, mode=mode), + np.pad(test, pad_amt, mode=mode, stat_length=30)) class TestStatistic(object): @@ -444,7 +425,7 @@ def test_check_mean_2(self): assert_array_equal(a, b) @pytest.mark.parametrize("mode", [ - pytest.param("mean", marks=pytest.mark.xfail(reason="gh-11216")), + "mean", "median", "minimum", "maximum" @@ -662,6 +643,11 @@ def test_check_object_array(self): assert_array_equal(arr, expected) + def test_pad_empty_dimension(self): + arr = np.zeros((3, 0, 2)) + result = np.pad(arr, [(0,), (2,), (1,)], mode="constant") + assert result.shape == (3, 4, 4) + class TestLinearRamp(object): def test_check_simple(self): @@ -721,6 +707,14 @@ def test_object_array(self): ]) assert_equal(actual, expected) + def test_end_values(self): + """Ensure that end values are exact.""" + a = np.pad(np.ones(10).reshape(2, 5), (223, 123), mode="linear_ramp") + assert_equal(a[:, 0], 0.) + assert_equal(a[:, -1], 0.) + assert_equal(a[0, :], 0.) + assert_equal(a[-1, :], 0.) + class TestReflect(object): def test_check_simple(self): @@ -831,19 +825,29 @@ def test_check_03(self): b = np.array([1, 2, 3, 2, 1, 2, 3, 2, 1, 2, 3]) assert_array_equal(a, b) - def test_check_padding_an_empty_array(self): - a = np.pad(np.zeros((0, 3)), ((0,), (1,)), mode='reflect') - b = np.zeros((0, 5)) - assert_array_equal(a, b) - def test_padding_empty_dimension(self): - match = "There aren't any elements to reflect in axis 0" +class TestEmptyArray(object): + """Check how padding behaves on arrays with an empty dimension.""" + + @pytest.mark.parametrize( + # Keep parametrization ordered, otherwise pytest-xdist might believe + # that different tests were collected during parallelization + "mode", sorted(_all_modes.keys() - {"constant", "empty"}) + ) + def test_pad_empty_dimension(self, mode): + match = ("can't extend empty axis 0 using modes other than 'constant' " + "or 'empty'") with pytest.raises(ValueError, match=match): - np.pad([], 4, mode='reflect') + np.pad([], 4, mode=mode) with pytest.raises(ValueError, match=match): - np.pad(np.ndarray(0), 4, mode='reflect') + np.pad(np.ndarray(0), 4, mode=mode) with pytest.raises(ValueError, match=match): - np.pad(np.zeros((0, 3)), ((1,), (0,)), mode='reflect') + np.pad(np.zeros((0, 3)), ((1,), (0,)), mode=mode) + + @pytest.mark.parametrize("mode", _all_modes.keys()) + def test_pad_non_empty_dimension(self, mode): + result = np.pad(np.ones((2, 0, 2)), ((3,), (0,), (1,)), mode=mode) + assert result.shape == (8, 0, 4) class TestSymmetric(object): @@ -1080,6 +1084,19 @@ def test_pad_with_zero(self): b = np.pad(a, (0, 5), mode="wrap") assert_array_equal(a, b[:-5, :-5]) + def test_repeated_wrapping(self): + """ + Check wrapping on each side individually if the wrapped area is longer + than the original array. + """ + a = np.arange(5) + b = np.pad(a, (12, 0), mode="wrap") + assert_array_equal(np.r_[a, a, a, a][3:], b) + + a = np.arange(5) + b = np.pad(a, (0, 12), mode="wrap") + assert_array_equal(np.r_[a, a, a, a][:-3], b) + class TestEdge(object): def test_check_simple(self): @@ -1120,6 +1137,19 @@ def test_check_width_shape_1_2(self): assert_array_equal(padded, expected) +class TestEmpty(object): + def test_simple(self): + arr = np.arange(24).reshape(4, 6) + result = np.pad(arr, [(2, 3), (3, 1)], mode="empty") + assert result.shape == (9, 10) + assert_equal(arr, result[2:-3, 3:-1]) + + def test_pad_empty_dimension(self): + arr = np.zeros((3, 0, 2)) + result = np.pad(arr, [(0,), (2,), (1,)], mode="empty") + assert result.shape == (3, 4, 4) + + def test_legacy_vector_functionality(): def _padwithtens(vector, pad_width, iaxis, kwargs): vector[:pad_width[0]] = 10 @@ -1244,7 +1274,7 @@ def test_kwargs(mode): np.pad([1, 2, 3], 1, mode, **allowed) # Test if prohibited keyword arguments of other modes raise an error for key, value in not_allowed.items(): - match = 'keyword not in allowed keywords' + match = "unsupported keyword arguments for mode '{}'".format(mode) with pytest.raises(ValueError, match=match): np.pad([1, 2, 3], 1, mode, **{key: value}) @@ -1254,9 +1284,39 @@ def test_constant_zero_default(): assert_array_equal(np.pad(arr, 2), [0, 0, 1, 1, 0, 0]) +@pytest.mark.parametrize("mode", [1, "const", object(), None, True, False]) +def test_unsupported_mode(mode): + match= "mode '{}' is not supported".format(mode) + with pytest.raises(ValueError, match=match): + np.pad([1, 2, 3], 4, mode=mode) + + @pytest.mark.parametrize("mode", _all_modes.keys()) def test_non_contiguous_array(mode): arr = np.arange(24).reshape(4, 6)[::2, ::2] result = np.pad(arr, (2, 3), mode) assert result.shape == (7, 8) assert_equal(result[2:-3, 2:-3], arr) + + +@pytest.mark.parametrize("mode", _all_modes.keys()) +def test_memory_layout_persistence(mode): + """Test if C and F order is preserved for all pad modes.""" + x = np.ones((5, 10), order='C') + assert np.pad(x, 5, mode).flags["C_CONTIGUOUS"] + x = np.ones((5, 10), order='F') + assert np.pad(x, 5, mode).flags["F_CONTIGUOUS"] + + +@pytest.mark.parametrize("dtype", chain( + # Skip "other" dtypes as they are not supported by all modes + np.sctypes["int"], + np.sctypes["uint"], + np.sctypes["float"], + np.sctypes["complex"] +)) +@pytest.mark.parametrize("mode", _all_modes.keys()) +def test_dtype_persistence(dtype, mode): + arr = np.zeros((3, 2, 1), dtype=dtype) + result = np.pad(arr, 1, mode=mode) + assert result.dtype == dtype From 28bd9a2e1c15d25b7c48eca349e9ec69956cc706 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 25 Mar 2019 16:05:05 +0200 Subject: [PATCH 206/279] MAINT: make cythonize non-recursive, restore examples to proper place --- .../examples/cython/extending.pyx | 0 .../cython/extending_distributions.pyx | 0 .../examples/cython/setup.py | 0 .../examples/numba/extending.py | 0 .../examples/numba/extending_distributions.py | 0 setup.py | 2 +- tools/cythonize.py | 50 +++++++++---------- 7 files changed, 26 insertions(+), 26 deletions(-) rename numpy/random/{randomgen_ignore => randomgen}/examples/cython/extending.pyx (100%) rename numpy/random/{randomgen_ignore => randomgen}/examples/cython/extending_distributions.pyx (100%) rename numpy/random/{randomgen_ignore => randomgen}/examples/cython/setup.py (100%) rename numpy/random/{randomgen_ignore => randomgen}/examples/numba/extending.py (100%) rename numpy/random/{randomgen_ignore => randomgen}/examples/numba/extending_distributions.py (100%) diff --git a/numpy/random/randomgen_ignore/examples/cython/extending.pyx b/numpy/random/randomgen/examples/cython/extending.pyx similarity index 100% rename from numpy/random/randomgen_ignore/examples/cython/extending.pyx rename to numpy/random/randomgen/examples/cython/extending.pyx diff --git a/numpy/random/randomgen_ignore/examples/cython/extending_distributions.pyx b/numpy/random/randomgen/examples/cython/extending_distributions.pyx similarity index 100% rename from numpy/random/randomgen_ignore/examples/cython/extending_distributions.pyx rename to numpy/random/randomgen/examples/cython/extending_distributions.pyx diff --git a/numpy/random/randomgen_ignore/examples/cython/setup.py b/numpy/random/randomgen/examples/cython/setup.py similarity index 100% rename from numpy/random/randomgen_ignore/examples/cython/setup.py rename to numpy/random/randomgen/examples/cython/setup.py diff --git a/numpy/random/randomgen_ignore/examples/numba/extending.py b/numpy/random/randomgen/examples/numba/extending.py similarity index 100% rename from numpy/random/randomgen_ignore/examples/numba/extending.py rename to numpy/random/randomgen/examples/numba/extending.py diff --git a/numpy/random/randomgen_ignore/examples/numba/extending_distributions.py b/numpy/random/randomgen/examples/numba/extending_distributions.py similarity index 100% rename from numpy/random/randomgen_ignore/examples/numba/extending_distributions.py rename to numpy/random/randomgen/examples/numba/extending_distributions.py diff --git a/setup.py b/setup.py index f7d6f9e0fe68..e2eaaeee55e2 100755 --- a/setup.py +++ b/setup.py @@ -197,7 +197,7 @@ def run(self): def generate_cython(): cwd = os.path.abspath(os.path.dirname(__file__)) print("Cythonizing sources") - for d in ('mtrand', 'randomgen'): + for d in ('mtrand', 'randomgen', 'randomgen/legacy'): p = subprocess.call([sys.executable, os.path.join(cwd, 'tools', 'cythonize.py'), 'numpy/random/{0}'.format(d)], diff --git a/tools/cythonize.py b/tools/cythonize.py index da54c549ccde..c81b72d2506a 100755 --- a/tools/cythonize.py +++ b/tools/cythonize.py @@ -204,32 +204,32 @@ def process(path, fromfile, tofile, processor_function, hash_db): def find_process_files(root_dir): hash_db = load_hashes(HASH_FILE) - for cur_dir, dirs, files in os.walk(root_dir): - # .pxi or .pxi.in files are most likely dependencies for - # .pyx files, so we need to process them first - files.sort(key=lambda name: (name.endswith('.pxi') or - name.endswith('.pxi.in') or - name.endswith('.pxd.in')), - reverse=True) - - for filename in files: - in_file = os.path.join(cur_dir, filename + ".in") - for fromext, value in rules.items(): - if filename.endswith(fromext): - if not value: - break - function, toext = value - if toext == '.c': - with open(os.path.join(cur_dir, filename), 'rb') as f: - data = f.read() - m = re.search(br"^\s*#\s*distutils:\s*language\s*=\s*c\+\+\s*$", data, re.I|re.M) - if m: - toext = ".cxx" - fromfile = filename - tofile = filename[:-len(fromext)] + toext - process(cur_dir, fromfile, tofile, function, hash_db) - save_hashes(hash_db, HASH_FILE) + files = [x for x in os.listdir(root_dir) if not os.path.isdir(x)] + # .pxi or .pxi.in files are most likely dependencies for + # .pyx files, so we need to process them first + files.sort(key=lambda name: (name.endswith('.pxi') or + name.endswith('.pxi.in') or + name.endswith('.pxd.in')), + reverse=True) + + for filename in files: + in_file = os.path.join(root_dir, filename + ".in") + for fromext, value in rules.items(): + if filename.endswith(fromext): + if not value: break + function, toext = value + if toext == '.c': + with open(os.path.join(root_dir, filename), 'rb') as f: + data = f.read() + m = re.search(br"^\s*#\s*distutils:\s*language\s*=\s*c\+\+\s*$", data, re.I|re.M) + if m: + toext = ".cxx" + fromfile = filename + tofile = filename[:-len(fromext)] + toext + process(root_dir, fromfile, tofile, function, hash_db) + save_hashes(hash_db, HASH_FILE) + break def main(): try: From f65e2d0f586b893d2f87ad029691a461b9b5fd24 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 25 Mar 2019 19:28:17 +0200 Subject: [PATCH 207/279] MAINT: update to randomgen 7bca296c0b9 --- _randomgen/README.md | 16 ++++---- _randomgen/README.rst | 22 +++++----- numpy/random/randomgen/common.pyx | 41 ++++++++----------- numpy/random/randomgen/generator.pyx | 6 +-- .../randomgen/tests/test_against_numpy.py | 33 +++++++++++++-- 5 files changed, 69 insertions(+), 49 deletions(-) diff --git a/_randomgen/README.md b/_randomgen/README.md index 45c33b928924..2e8073645f30 100644 --- a/_randomgen/README.md +++ b/_randomgen/README.md @@ -47,9 +47,9 @@ which can fully reproduce the sequence produced by NumPy. from randomgen import RandomGenerator # Default basic PRNG is Xoroshiro128 rnd = RandomGenerator() - w = rnd.standard_normal(10000, method='zig') - x = rnd.standard_exponential(10000, method='zig') - y = rnd.standard_gamma(5.5, 10000, method='zig') + w = rnd.standard_normal(10000) + x = rnd.standard_exponential(10000) + y = rnd.standard_gamma(5.5, 10000) ``` * Support for 32-bit floating randoms for core generators. @@ -135,15 +135,15 @@ The RNGs include: ## Status * Builds and passes all tests on: - * Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 + * Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6, 3.6 * PC-BSD (FreeBSD) 64-bit, Python 2.7 - * OSX 64-bit, Python 3.6 - * Windows 32/64 bit, Python 2.7, 3.5 and 3.6 + * OSX 64-bit, Python 2.7, 3.5, 3.6, 3.7 + * Windows 32/64 bit, Python 2.7, 3.5, 3.6 and 3.7 ## Version The version matched the latest version of NumPy where -`RandomGenerator(MT19937())` passes all NumPy test. +`LegacyGenerator(MT19937())` passes all NumPy test. ## Documentation @@ -168,7 +168,7 @@ Building requires: * Cython (0.26+) * tempita (0.5+), if not provided by Cython -Testing requires pytest (3.0+). +Testing requires pytest (4.0+). **Note:** it might work with other versions but only tested with these versions. diff --git a/_randomgen/README.rst b/_randomgen/README.rst index f4b886e5f74b..7e91b898d17e 100644 --- a/_randomgen/README.rst +++ b/_randomgen/README.rst @@ -12,9 +12,9 @@ generators in Python and NumPy. Python 2.7 Support ------------------ -v1.16 is the final major version that supports Python 2.7. Any bugs in -v1.16 will be patched until the end of 2019. All future releases are -Python 3, with an initial minimum version of 3.5. +Release 1.16.0 is the final version that supports Python 2.7. Any bugs +in v1.16.0 will be patched until the end of 2019. All future releases +are Python 3, with an initial minimum version of 3.5. Compatibility Warning --------------------- @@ -51,9 +51,9 @@ Features from randomgen import RandomGenerator # Default basic PRNG is Xoroshiro128 rnd = RandomGenerator() - w = rnd.standard_normal(10000, method='zig') - x = rnd.standard_exponential(10000, method='zig') - y = rnd.standard_gamma(5.5, 10000, method='zig') + w = rnd.standard_normal(10000) + x = rnd.standard_exponential(10000) + y = rnd.standard_gamma(5.5, 10000) - Support for 32-bit floating randoms for core generators. Currently supported: @@ -147,16 +147,16 @@ Status - Builds and passes all tests on: - - Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6 + - Linux 32/64 bit, Python 2.7, 3.5, 3.6, 3.7 - PC-BSD (FreeBSD) 64-bit, Python 2.7 - - OSX 64-bit, Python 3.6 - - Windows 32/64 bit, Python 2.7, 3.5 and 3.6 + - OSX 64-bit, Python 2.7, 3.5, 3.6, 3.7 + - Windows 32/64 bit, Python 2.7, 3.5, 3.6, and 3.7 Version ------- The version matched the latest version of NumPy where -``RandomGenerator(MT19937())`` passes all NumPy test. +``LegacyGenerator(MT19937())`` passes all NumPy test. Documentation ------------- @@ -185,7 +185,7 @@ Building requires: - Cython (0.26+) - tempita (0.5+), if not provided by Cython -Testing requires pytest (3.0+). +Testing requires pytest (4.0+). **Note:** it might work with other versions but only tested with these versions. diff --git a/numpy/random/randomgen/common.pyx b/numpy/random/randomgen/common.pyx index 28658dd51acf..30f62bf9129d 100644 --- a/numpy/random/randomgen/common.pyx +++ b/numpy/random/randomgen/common.pyx @@ -148,30 +148,28 @@ cdef uint64_t MAXSIZE = sys.maxsize cdef int check_array_constraint(np.ndarray val, object name, constraint_type cons) except -1: if cons == CONS_NON_NEGATIVE: - if np.any(np.signbit(val)): + if np.any(np.signbit(val)) or np.any(np.isnan(val)): raise ValueError(name + " < 0") elif cons == CONS_POSITIVE: - if np.any(np.less_equal(val, 0)): + if not np.all(np.greater(val, 0)): raise ValueError(name + " <= 0") - elif cons == CONS_BOUNDED_0_1 or cons == CONS_BOUNDED_0_1_NOTNAN: - if np.any(np.less(val, 0)) or np.any(np.greater(val, 1)): + elif cons == CONS_BOUNDED_0_1: + if not np.all(np.greater_equal(val, 0)) or \ + not np.all(np.less_equal(val, 1)): raise ValueError(name + " < 0 or " + name + " > 1") - if cons == CONS_BOUNDED_0_1_NOTNAN: - if np.any(np.isnan(val)): - raise ValueError(name + ' contains NaNs') elif cons == CONS_BOUNDED_GT_0_1: - if np.any(np.less_equal(val, 0)) or np.any(np.greater(val, 1)): + if not np.all(np.greater(val, 0)) or not np.all(np.less_equal(val, 1)): raise ValueError(name + " <= 0 or " + name + " > 1") elif cons == CONS_GT_1: - if np.any(np.less_equal(val, 1)): + if not np.all(np.greater(val, 1)): raise ValueError(name + " <= 1") elif cons == CONS_GTE_1: - if np.any(np.less(val, 1)): + if not np.all(np.greater_equal(val, 1)): raise ValueError(name + " < 1") elif cons == CONS_POISSON: - if np.any(np.greater(val, POISSON_LAM_MAX)): + if not np.all(np.less_equal(val, POISSON_LAM_MAX)): raise ValueError(name + " value too large") - if np.any(np.less(val, 0.0)): + if not np.all(np.greater_equal(val, 0.0)): raise ValueError(name + " < 0") return 0 @@ -180,27 +178,24 @@ cdef int check_array_constraint(np.ndarray val, object name, constraint_type con cdef int check_constraint(double val, object name, constraint_type cons) except -1: if cons == CONS_NON_NEGATIVE: - if np.signbit(val): + if np.signbit(val) or np.isnan(val): raise ValueError(name + " < 0") elif cons == CONS_POSITIVE: - if val <= 0: + if not (val > 0): raise ValueError(name + " <= 0") - elif cons == CONS_BOUNDED_0_1 or cons == CONS_BOUNDED_0_1_NOTNAN: - if val < 0 or val > 1: + elif cons == CONS_BOUNDED_0_1: + if not (val >= 0) or not (val <= 1): raise ValueError(name + " < 0 or " + name + " > 1") - if cons == CONS_BOUNDED_0_1_NOTNAN: - if np.isnan(val): - raise ValueError(name + ' contains NaNs') elif cons == CONS_GT_1: - if val <= 1: + if not (val > 1): raise ValueError(name + " <= 1") elif cons == CONS_GTE_1: - if val < 1: + if not (val >= 1): raise ValueError(name + " < 1") elif cons == CONS_POISSON: - if val < 0: + if not (val >= 0): raise ValueError(name + " < 0") - elif val > POISSON_LAM_MAX: + elif not (val <= POISSON_LAM_MAX): raise ValueError(name + " value too large") return 0 diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index 3739bdc44d3e..ab980f443644 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -3304,7 +3304,7 @@ cdef class RandomGenerator: is_scalar = is_scalar and np.PyArray_NDIM(n_arr) == 0 if not is_scalar: - check_array_constraint(p_arr, 'p', CONS_BOUNDED_0_1_NOTNAN) + check_array_constraint(p_arr, 'p', CONS_BOUNDED_0_1) check_array_constraint(n_arr, 'n', CONS_NON_NEGATIVE) if size is not None: randoms = np.empty(size, np.int64) @@ -3328,7 +3328,7 @@ cdef class RandomGenerator: _dp = PyFloat_AsDouble(p) _in = n - check_constraint(_dp, 'p', CONS_BOUNDED_0_1_NOTNAN) + check_constraint(_dp, 'p', CONS_BOUNDED_0_1) check_constraint(_in, 'n', CONS_NON_NEGATIVE) if size is None: @@ -3742,7 +3742,7 @@ cdef class RandomGenerator: raise ValueError("ngood + nbad < nsample") return discrete_broadcast_iii(&random_hypergeometric, self._brng, size, self.lock, ongood, 'ngood', CONS_NON_NEGATIVE, - onbad, nbad, CONS_NON_NEGATIVE, + onbad, 'nbad', CONS_NON_NEGATIVE, onsample, 'nsample', CONS_GTE_1) def logseries(self, p, size=None): diff --git a/numpy/random/randomgen/tests/test_against_numpy.py b/numpy/random/randomgen/tests/test_against_numpy.py index d0f0eefea17f..82d84bef1041 100644 --- a/numpy/random/randomgen/tests/test_against_numpy.py +++ b/numpy/random/randomgen/tests/test_against_numpy.py @@ -3,9 +3,10 @@ from numpy.testing import (assert_allclose, assert_array_equal, assert_equal, suppress_warnings) -import numpy.random.randomgen as randomgen -from ...randomgen import RandomGenerator, MT19937 -from ...randomgen.legacy import LegacyGenerator +import pytest + +from numpy.random.randomgen import RandomGenerator, MT19937, generator +from numpy.random.randomgen.legacy import LegacyGenerator def compare_0_input(f1, f2): @@ -407,7 +408,7 @@ def test_dir(self): assert (len(nprs_d.difference(rs_d)) == 0) npmod = dir(numpy.random) - mod = dir(randomgen.generator) + mod = dir(generator) known_exlcuded = ['__all__', '__cached__', '__path__', 'Tester', 'info', 'bench', '__RandomState_ctor', 'mtrand', 'test', '__warningregistry__', '_numpy_tester', @@ -567,3 +568,27 @@ def test_multivariate_normal(self): assert_allclose(f(np.array(mu), np.array(cov), size=(7, 31)), g(np.array(mu), np.array(cov), size=(7, 31))) self._is_state_common_legacy() + + +funcs = [generator.exponential, + generator.zipf, + generator.chisquare, + generator.logseries, + generator.poisson] +ids = [f.__name__ for f in funcs] + + +@pytest.mark.filterwarnings('ignore:invalid value encountered:RuntimeWarning') +@pytest.mark.parametrize('func', funcs, ids=ids ) +def test_nan_guard(func): + with pytest.raises(ValueError): + func([np.nan]) + with pytest.raises(ValueError): + func(np.nan) + + +def test_cons_gte1_nan_guard(): + with pytest.raises(ValueError): + generator.hypergeometric(10, 10, [np.nan]) + with pytest.raises(ValueError): + generator.hypergeometric(10, 10, np.nan) From d6dcaedad22f5842e28179351238b4847e74d5a9 Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Mon, 25 Mar 2019 15:23:46 -0400 Subject: [PATCH 208/279] DOC: correction to numpy.pad docstring (#13149) * DOC: fix mistatement in numpy.pad docstring --- numpy/lib/arraypad.py | 8 +++----- numpy/lib/tests/test_arraypad.py | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py index 570f86969725..07146f404ad3 100644 --- a/numpy/lib/arraypad.py +++ b/numpy/lib/arraypad.py @@ -694,9 +694,8 @@ def pad(array, pad_width, mode='constant', **kwargs): think about with a rank 2 array where the corners of the padded array are calculated by using padded values from the first axis. - The padding function, if used, should return a rank 1 array equal in - length to the vector argument with padded values replaced. It has the - following signature:: + The padding function, if used, should modify a rank 1 array in-place. It + has the following signature:: padding_func(vector, iaxis_pad_width, iaxis, kwargs) @@ -704,7 +703,7 @@ def pad(array, pad_width, mode='constant', **kwargs): vector : ndarray A rank 1 array already padded with zeros. Padded values are - vector[:pad_tuple[0]] and vector[-pad_tuple[1]:]. + vector[:iaxis_pad_width[0]] and vector[-iaxis_pad_width[1]:]. iaxis_pad_width : tuple A 2-tuple of ints, iaxis_pad_width[0] represents the number of values padded at the beginning of vector where @@ -766,7 +765,6 @@ def pad(array, pad_width, mode='constant', **kwargs): ... pad_value = kwargs.get('padder', 10) ... vector[:pad_width[0]] = pad_value ... vector[-pad_width[1]:] = pad_value - ... return vector >>> a = np.arange(6) >>> a = a.reshape((2, 3)) >>> np.pad(a, 2, pad_with) diff --git a/numpy/lib/tests/test_arraypad.py b/numpy/lib/tests/test_arraypad.py index d43c0d32e916..b7630cdcdc47 100644 --- a/numpy/lib/tests/test_arraypad.py +++ b/numpy/lib/tests/test_arraypad.py @@ -1154,7 +1154,6 @@ def test_legacy_vector_functionality(): def _padwithtens(vector, pad_width, iaxis, kwargs): vector[:pad_width[0]] = 10 vector[-pad_width[1]:] = 10 - return vector a = np.arange(6).reshape(2, 3) a = np.pad(a, 2, _padwithtens) From 170fbbb16a25a97adf82980c6acee249eaa1d262 Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 26 Mar 2019 01:33:47 +0200 Subject: [PATCH 209/279] ENH: replace mtrand with LegacyGenerator, tweak for compatibility --- numpy/random/__init__.py | 14 +++++++++----- numpy/random/randomgen/legacy/_legacy.pyx | 12 +++++++++++- numpy/random/randomgen/legacy/legacy.py | 5 +++++ numpy/random/randomgen/mt19937.pyx | 4 ++++ numpy/random/randomgen/tests/test_against_numpy.py | 1 + 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/numpy/random/__init__.py b/numpy/random/__init__.py index 965ab5ea9b75..0cf519d5b5a7 100644 --- a/numpy/random/__init__.py +++ b/numpy/random/__init__.py @@ -86,8 +86,6 @@ """ from __future__ import division, absolute_import, print_function -import warnings - __all__ = [ 'beta', 'binomial', @@ -138,9 +136,15 @@ 'zipf' ] -with warnings.catch_warnings(): - warnings.filterwarnings("ignore", message="numpy.ndarray size changed") - from .mtrand import * +# from .mtrand import * +from .randomgen.legacy import LegacyGenerator as RandomState +mtrand = RandomState() +for _x in dir(mtrand): + if _x[0] != '_' and _x not in ('poisson_lam_max', 'state'): + locals()[_x] = getattr(mtrand, _x) +del _x +get_state = mtrand.get_state +set_state = mtrand.set_state # Some aliases: ranf = random = sample = random_sample diff --git a/numpy/random/randomgen/legacy/_legacy.pyx b/numpy/random/randomgen/legacy/_legacy.pyx index cd8f7b53214e..00504d30a6cd 100644 --- a/numpy/random/randomgen/legacy/_legacy.pyx +++ b/numpy/random/randomgen/legacy/_legacy.pyx @@ -185,9 +185,16 @@ cdef class _LegacyGenerator: st['gauss'] = self._aug_state.gauss return st + def get_state(self): + st = self._basicrng.state + if st['brng'] != 'MT19937': + raise ValueError('get_state only supported for MT19937') + return (st['brng'], st['state']['key'], st['state']['pos'], + self._aug_state.has_gauss, self._aug_state.gauss) + @state.setter def state(self, value): - if isinstance(value, tuple): + if isinstance(value, (tuple, list)): if value[0] != 'MT19937': raise ValueError('tuple only supported for MT19937') st = {'brng': value[0], @@ -200,6 +207,9 @@ cdef class _LegacyGenerator: self._aug_state.has_gauss = value.get('has_gauss', 0) self._basicrng.state = value + def set_state(self, value): + self.state = value + def beta(self, a, b, size=None): """ beta(a, b, size=None) diff --git a/numpy/random/randomgen/legacy/legacy.py b/numpy/random/randomgen/legacy/legacy.py index 72b72a7f40bd..cdd9b4c5354f 100644 --- a/numpy/random/randomgen/legacy/legacy.py +++ b/numpy/random/randomgen/legacy/legacy.py @@ -8,6 +8,7 @@ _LEGACY_ATTRIBUTES += ('__getstate__', '__setstate__', '__reduce__') + def with_metaclass(meta, *bases): """Create a base class with a metaclass.""" # This requires a bit of explanation: the basic idea is to make a dummy @@ -91,6 +92,10 @@ class LegacyGenerator(with_metaclass(LegacyGeneratorType, RandomGenerator)): def __init__(self, brng=None): if brng is None: brng = MT19937() + elif isinstance(brng, MT19937): + pass + else: + brng = MT19937(brng) super(LegacyGenerator, self).__init__(brng) self.__legacy = _LegacyGenerator(brng) diff --git a/numpy/random/randomgen/mt19937.pyx b/numpy/random/randomgen/mt19937.pyx index cd69974eda7f..0e476e53bc75 100644 --- a/numpy/random/randomgen/mt19937.pyx +++ b/numpy/random/randomgen/mt19937.pyx @@ -232,6 +232,10 @@ cdef class MT19937: mt19937_seed(self.rng_state, seed) except TypeError: obj = np.asarray(seed).astype(np.int64, casting='safe') + if obj.size == 0: + raise ValueError("Seed must be non-empty") + if obj.ndim != 1: + raise ValueError("Seed array must be 1-d") if ((obj > int(2**32 - 1)) | (obj < 0)).any(): raise ValueError("Seed must be between 0 and 2**32 - 1") obj = obj.astype(np.uint32, casting='unsafe', order='C') diff --git a/numpy/random/randomgen/tests/test_against_numpy.py b/numpy/random/randomgen/tests/test_against_numpy.py index 82d84bef1041..140c4e097b5a 100644 --- a/numpy/random/randomgen/tests/test_against_numpy.py +++ b/numpy/random/randomgen/tests/test_against_numpy.py @@ -404,6 +404,7 @@ def test_dir(self): nprs_d = set(dir(self.nprs)) rs_d = dir(self.rg) excluded = {'get_state', 'set_state'} + nprs_d.discard('_LegacyGenerator__legacy') nprs_d.difference_update(excluded) assert (len(nprs_d.difference(rs_d)) == 0) From b34ed1bd9bf2bd7e306bcefbd8c9c55569737812 Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 26 Mar 2019 13:00:55 +0200 Subject: [PATCH 210/279] BUG: port f879ef4 to fix GH10839 --- numpy/random/randomgen/generator.pyx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index ab980f443644..223f2e79db60 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -3856,6 +3856,7 @@ cdef class RandomGenerator: Behavior when the covariance matrix is not positive semidefinite. tol : float, optional Tolerance when checking the singular values in covariance matrix. + `cov` is cast to double before the check. Returns ------- @@ -3968,6 +3969,8 @@ cdef class RandomGenerator: # order to preserve current outputs. Note that symmetry has not # been checked. + # GH10839, ensure double to make tol meaningful + cov = cov.astype(np.double) (u, s, v) = svd(cov) if check_valid != 'ignore': From 4477134685502d776ea9c70a4a00c870b2d60b7c Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 26 Mar 2019 13:54:09 +0200 Subject: [PATCH 211/279] BUG: minimized difference between generator.pyx and _legacy.pyx --- numpy/random/randomgen/generator.pyx | 8 +++++--- numpy/random/randomgen/legacy/_legacy.pyx | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index 223f2e79db60..b35622a74932 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -3975,15 +3975,17 @@ cdef class RandomGenerator: if check_valid != 'ignore': if check_valid != 'warn' and check_valid != 'raise': - raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") + raise ValueError( + "check_valid must equal 'warn', 'raise', or 'ignore'") psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) if not psd: if check_valid == 'warn': warnings.warn("covariance is not positive-semidefinite.", - RuntimeWarning) + RuntimeWarning) else: - raise ValueError("covariance is not positive-semidefinite.") + raise ValueError( + "covariance is not positive-semidefinite.") x = np.dot(x, np.sqrt(s)[:, None] * v) x += mean diff --git a/numpy/random/randomgen/legacy/_legacy.pyx b/numpy/random/randomgen/legacy/_legacy.pyx index 00504d30a6cd..db8885d79d07 100644 --- a/numpy/random/randomgen/legacy/_legacy.pyx +++ b/numpy/random/randomgen/legacy/_legacy.pyx @@ -1724,6 +1724,7 @@ cdef class _LegacyGenerator: Behavior when the covariance matrix is not positive semidefinite. tol : float, optional Tolerance when checking the singular values in covariance matrix. + `cov` is cast to double before the check. Returns ------- @@ -1836,6 +1837,8 @@ cdef class _LegacyGenerator: # order to preserve current outputs. Note that symmetry has not # been checked. + # GH10839, ensure double to make tol meaningful + cov = cov.astype(np.double) (u, s, v) = svd(cov) if check_valid != 'ignore': From e000e61783ef9f4073d483031b4f482e55eb66bf Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 26 Mar 2019 15:54:01 +0200 Subject: [PATCH 212/279] DOC: fix namespace in doctests, mark results that are random --- numpy/random/randomgen/generator.pyx | 208 +++++++++++----------- numpy/random/randomgen/legacy/_legacy.pyx | 77 ++++---- 2 files changed, 142 insertions(+), 143 deletions(-) diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index b35622a74932..518d25d596af 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -75,13 +75,13 @@ cdef class RandomGenerator: Examples -------- - >>> from randomgen import RandomGenerator + >>> from np.random.randomgen import RandomGenerator >>> rg = RandomGenerator() >>> rg.standard_normal() Using a specific generator - >>> from randomgen import MT19937 + >>> from np.random.randomgen import MT19937 >>> rg = RandomGenerator(MT19937()) The generator is also directly available from basic RNGs @@ -146,7 +146,7 @@ cdef class RandomGenerator: The best method to access seed is to directly use a basic RNG instance. This example demonstrates this best practice. - >>> from randomgen import RandomGenerator, PCG64 + >>> from np.random.randomgen import RandomGenerator, PCG64 >>> brng = PCG64(1234567891011) >>> rg = brng.generator >>> brng.seed(1110987654321) @@ -339,16 +339,16 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.generator.random_sample() + >>> np.random.random_sample() 0.47108547995356098 # random - >>> type(randomgen.generator.random_sample()) + >>> type(np.random.random_sample()) - >>> randomgen.generator.random_sample((5,)) + >>> np.random.random_sample((5,)) array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) # random Three-by-two array of random numbers from [-5, 0): - >>> 5 * randomgen.random_sample((3, 2)) - 5 + >>> 5 * np.random.random_sample((3, 2)) - 5 array([[-3.99149989, -0.52338984], # random [-2.99091858, -0.79479508], [-1.23204345, -1.75224494]]) @@ -494,7 +494,7 @@ cdef class RandomGenerator: -------- Output a 3x8000 array: - >>> n = randomgen.generator.standard_exponential((3, 8000)) + >>> n = np.random.standard_exponential((3, 8000)) """ key = np.dtype(dtype).name if key == 'float64': @@ -540,7 +540,7 @@ cdef class RandomGenerator: Examples -------- - >>> rg = randomgen.RandomGenerator() # need a RandomGenerator object + >>> rg = np.random.randomgen.RandomGenerator() # need a RandomGenerator object >>> rg.tomaxint((2,2,2)) array([[[1170048599, 1600360186], # random [ 739731006, 1947757578]], @@ -627,32 +627,32 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.generator.randint(2, size=10) - array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) # random - >>> randomgen.generator.randint(1, size=10) + >>> np.random.randint(2, size=10) + array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) # random + >>> np.random.randint(1, size=10) array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) Generate a 2 x 4 array of ints between 0 and 4, inclusive: - >>> randomgen.generator.randint(5, size=(2, 4)) - array([[4, 0, 2, 1], # random - [3, 2, 2, 0]]) + >>> np.random.randint(5, size=(2, 4)) + array([[4, 0, 2, 1], + [3, 2, 2, 0]]) # random Generate a 1 x 3 array with 3 different upper bounds - >>> randomgen.generator.randint(1, [3, 5, 10]) - array([2, 2, 9]) + >>> np.random.randint(1, [3, 5, 10]) + array([2, 2, 9]) # random Generate a 1 by 3 array with 3 different lower bounds - >>> randomgen.generator.randint([1, 5, 7], 10) - array([9, 8, 7]) + >>> np.random.randint([1, 5, 7], 10) + array([9, 8, 7]) # random Generate a 2 by 4 array using broadcasting with dtype of uint8 - >>> randomgen.generator.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) + >>> np.random.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) array([[ 8, 6, 9, 7], - [ 1, 16, 9, 12]], dtype=uint8) + [ 1, 16, 9, 12]], dtype=uint8) # random References ---------- @@ -709,7 +709,7 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.generator.bytes(10) + >>> np.random.bytes(10) ' eh\\x85\\x022SZ\\xbf\\xa4' #random """ @@ -764,33 +764,33 @@ cdef class RandomGenerator: -------- Generate a uniform random sample from np.arange(5) of size 3: - >>> randomgen.generator.choice(5, 3) + >>> np.random.choice(5, 3) array([0, 3, 4]) # random - >>> #This is equivalent to randomgen.randint(0,5,3) + >>> #This is equivalent to np.random.randint(0,5,3) Generate a non-uniform random sample from np.arange(5) of size 3: - >>> randomgen.generator.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) + >>> np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) array([3, 3, 0]) # random Generate a uniform random sample from np.arange(5) of size 3 without replacement: - >>> randomgen.generator.choice(5, 3, replace=False) + >>> np.random.choice(5, 3, replace=False) array([3,1,0]) # random - >>> #This is equivalent to randomgen.permutation(np.arange(5))[:3] + >>> #This is equivalent to np.random.permutation(np.arange(5))[:3] Generate a non-uniform random sample from np.arange(5) of size 3 without replacement: - >>> randomgen.generator.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) + >>> np.random.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) array([2, 3, 0]) # random Any of the above can be repeated with an arbitrary array-like instead of just integers. For instance: >>> aa_milne_arr = ['pooh', 'rabbit', 'piglet', 'Christopher'] - >>> randomgen.generator.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) + >>> np.random.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) array(['pooh', 'pooh', 'pooh', 'Christopher', 'piglet'], # random dtype='>> s = randomgen.generator.uniform(-1,0,1000) + >>> s = np.random.uniform(-1,0,1000) All values are within the given interval: @@ -1052,13 +1052,13 @@ cdef class RandomGenerator: Notes ----- This is a convenience function. If you want an interface that takes - a shape-tuple as the first argument, refer to randomgen.random_sample. + a shape-tuple as the first argument, refer to `numpy.random.random_sample`. ``dtype`` can only be changed using a keyword argument. Examples -------- - >>> randomgen.generator.rand(3,2) + >>> np.random.rand(3,2) array([[ 0.14022471, 0.96360618], #random [ 0.37601032, 0.25528411], #random [ 0.49313049, 0.94909878]]) #random @@ -1115,11 +1115,11 @@ cdef class RandomGenerator: ----- For random samples from :math:`N(\\mu, \\sigma^2)`, use: - ``sigma * randomgen.randn(...) + mu`` + ``sigma * np.random.randn(...) + mu`` Examples -------- - >>> randomgen.generator.randn() + >>> np.random.randn() 2.1923875335537315 # random Two-by-four array of samples from N(3, 6.25): @@ -1179,15 +1179,15 @@ cdef class RandomGenerator: To sample from N evenly spaced floating-point numbers between a and b, use:: - a + (b - a) * (randomgen.random_integers(N) - 1) / (N - 1.) + a + (b - a) * (np.random.random_integers(N) - 1) / (N - 1.) Examples -------- - >>> randomgen.generator.random_integers(5) + >>> np.random.random_integers(5) 4 # random - >>> type(randomgen.generator.random_integers(5)) + >>> type(np.random.random_integers(5)) - >>> randomgen.generator.random_integers(5, size=(3, 2)) + >>> np.random.random_integers(5, size=(3, 2)) array([[5, 4], # random [3, 3], [4, 5]]) @@ -1196,13 +1196,13 @@ cdef class RandomGenerator: numbers between 0 and 2.5, inclusive (*i.e.*, from the set :math:`{0, 5/8, 10/8, 15/8, 20/8}`): - >>> 2.5 * (randomgen.generator.random_integers(5, size=(5,)) - 1) / 4. + >>> 2.5 * (np.random.random_integers(5, size=(5,)) - 1) / 4. array([ 0.625, 1.25 , 0.625, 0.625, 2.5 ]) # random Roll two six sided dice 1000 times and sum the results: - >>> d1 = randomgen.generator.random_integers(1, 6, 1000) - >>> d2 = randomgen.generator.random_integers(1, 6, 1000) + >>> d1 = np.random.random_integers(1, 6, 1000) + >>> d2 = np.random.random_integers(1, 6, 1000) >>> dsums = d1 + d2 Display results as a histogram: @@ -1368,7 +1368,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, sigma = 0, 0.1 # mean and standard deviation - >>> s = randomgen.generator.normal(mu, sigma, 1000) + >>> s = np.random.normal(mu, sigma, 1000) Verify the mean and the variance: @@ -1456,7 +1456,7 @@ cdef class RandomGenerator: -------- Draw samples from the distribution: - >>> s = randomgen.generator.complex_normal(size=1000) + >>> s = np.random.complex_normal(size=1000) """ cdef np.ndarray ogamma, orelation, oloc, randoms, v_real, v_imag, rho cdef double *randoms_data @@ -1625,7 +1625,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> shape, scale = 2., 1. # mean and width - >>> s = randomgen.generator.standard_gamma(shape, 1000000) + >>> s = np.random.standard_gamma(shape, 1000000) Display the histogram of the samples, along with the probability density function: @@ -1712,7 +1712,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> shape, scale = 2., 2. # mean and dispersion - >>> s = randomgen.generator.gamma(shape, scale, 1000) + >>> s = np.random.gamma(shape, scale, 1000) Display the histogram of the samples, along with the probability density function: @@ -1802,7 +1802,7 @@ cdef class RandomGenerator: >>> dfnum = 1. # between group degrees of freedom >>> dfden = 48. # within groups degrees of freedom - >>> s = randomgen.generator.f(dfnum, dfden, 1000) + >>> s = np.random.f(dfnum, dfden, 1000) The lower bound for the top 1% of the samples is : @@ -1877,9 +1877,9 @@ cdef class RandomGenerator: >>> dfnum = 3 # between group deg of freedom >>> dfden = 20 # within groups degrees of freedom >>> nonc = 3.0 - >>> nc_vals = randomgen.generator.noncentral_f(dfnum, dfden, nonc, 1000000) + >>> nc_vals = np.random.noncentral_f(dfnum, dfden, nonc, 1000000) >>> NF = np.histogram(nc_vals, bins=50, density=True) - >>> c_vals = randomgen.generator.f(dfnum, dfden, 1000000) + >>> c_vals = np.random.f(dfnum, dfden, 1000000) >>> F = np.histogram(c_vals, bins=50, density=True) >>> import matplotlib.pyplot as plt >>> plt.plot(F[1][1:], F[0]) @@ -1951,7 +1951,7 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.generator.chisquare(2,4) + >>> np.random.chisquare(2,4) array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) # random """ @@ -2008,7 +2008,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram >>> import matplotlib.pyplot as plt - >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), ... bins=200, density=True) >>> plt.show() @@ -2016,9 +2016,9 @@ cdef class RandomGenerator: and compare to a chisquare. >>> plt.figure() - >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, .0000001, 100000), + >>> values = plt.hist(np.random.noncentral_chisquare(3, .0000001, 100000), ... bins=np.arange(0., 25, .1), density=True) - >>> values2 = plt.hist(randomgen.generator.chisquare(3, 100000), + >>> values2 = plt.hist(np.random.chisquare(3, 100000), ... bins=np.arange(0., 25, .1), density=True) >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') >>> plt.show() @@ -2027,7 +2027,7 @@ cdef class RandomGenerator: distribution. >>> plt.figure() - >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), ... bins=200, density=True) >>> plt.show() @@ -2092,7 +2092,7 @@ cdef class RandomGenerator: -------- Draw samples and plot the distribution: - >>> s = randomgen.generator.standard_cauchy(1000000) + >>> s = np.random.standard_cauchy(1000000) >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well >>> import matplotlib.pyplot as plt >>> plt.hist(s, bins=100) @@ -2166,7 +2166,7 @@ cdef class RandomGenerator: We have 10 degrees of freedom, so is the sample mean within 95% of the recommended value? - >>> s = randomgen.generator.standard_t(10, size=100000) + >>> s = np.random.standard_t(10, size=100000) >>> np.mean(intake) 6753.636363636364 >>> intake.std(ddof=1) @@ -2260,7 +2260,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, kappa = 0.0, 4.0 # mean and dispersion - >>> s = randomgen.generator.vonmises(mu, kappa, 1000) + >>> s = np.random.vonmises(mu, kappa, 1000) Display the histogram of the samples, along with the probability density function: @@ -2360,7 +2360,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a, m = 3., 2. # shape and mode - >>> s = (randomgen.generator.pareto(a, 1000) + 1) * m + >>> s = (np.random.pareto(a, 1000) + 1) * m Display the histogram of the samples, along with the probability density function: @@ -2453,7 +2453,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a = 5. # shape - >>> s = randomgen.generator.weibull(a, 1000) + >>> s = np.random.weibull(a, 1000) Display the histogram of the samples, along with the probability density function: @@ -2463,7 +2463,7 @@ cdef class RandomGenerator: >>> def weib(x,n,a): ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) - >>> count, bins, ignored = plt.hist(randomgen.generator.weibull(5.,1000)) + >>> count, bins, ignored = plt.hist(np.random.weibull(5.,1000)) >>> x = np.arange(1,100.)/50. >>> scale = count.max()/weib(x, 1., 5.).max() >>> plt.plot(x, weib(x, 1., 5.)*scale) @@ -2533,7 +2533,7 @@ cdef class RandomGenerator: >>> a = 5. # shape >>> samples = 1000 - >>> s = randomgen.generator.power(a, samples) + >>> s = np.random.power(a, samples) Display the histogram of the samples, along with the probability density function: @@ -2549,20 +2549,20 @@ cdef class RandomGenerator: Compare the power function distribution to the inverse of the Pareto. >>> from scipy import stats - >>> rvs = randomgen.generator.power(5, 1000000) - >>> rvsp = randomgen.generator.pareto(5, 1000000) + >>> rvs = np.random.power(5, 1000000) + >>> rvsp = np.random.pareto(5, 1000000) >>> xx = np.linspace(0,1,100) >>> powpdf = stats.powerlaw.pdf(xx,5) >>> plt.figure() >>> plt.hist(rvs, bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('randomgen.generator.power(5)') + >>> plt.title('np.random.power(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('inverse of 1 + randomgen.generator.pareto(5)') + >>> plt.title('inverse of 1 + np.random.pareto(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, density=True) @@ -2637,7 +2637,7 @@ cdef class RandomGenerator: Draw samples from the distribution >>> loc, scale = 0., 1. - >>> s = randomgen.generator.laplace(loc, scale, 1000) + >>> s = np.random.laplace(loc, scale, 1000) Display the histogram of the samples, along with the probability density function: @@ -2740,7 +2740,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, beta = 0, 0.1 # location and scale - >>> s = randomgen.generator.gumbel(mu, beta, 1000) + >>> s = np.random.gumbel(mu, beta, 1000) Display the histogram of the samples, along with the probability density function: @@ -2758,7 +2758,7 @@ cdef class RandomGenerator: >>> means = [] >>> maxima = [] >>> for i in range(0,1000) : - ... a = randomgen.generator.normal(mu, beta, 1000) + ... a = np.random.normal(mu, beta, 1000) ... means.append(a.mean()) ... maxima.append(a.max()) >>> count, bins, ignored = plt.hist(maxima, 30, density=True) @@ -2840,7 +2840,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> loc, scale = 10, 1 - >>> s = randomgen.generator.logistic(loc, scale, 10000) + >>> s = np.random.logistic(loc, scale, 10000) >>> import matplotlib.pyplot as plt >>> count, bins, ignored = plt.hist(s, bins=50) @@ -2923,7 +2923,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> mu, sigma = 3., 1. # mean and standard deviation - >>> s = randomgen.generator.lognormal(mu, sigma, 1000) + >>> s = np.random.lognormal(mu, sigma, 1000) Display the histogram of the samples, along with the probability density function: @@ -2947,7 +2947,7 @@ cdef class RandomGenerator: >>> # values, drawn from a normal distribution. >>> b = [] >>> for i in range(1000): - ... a = 10. + randomgen.generator.randn(100) + ... a = 10. + np.random.randn(100) ... b.append(np.product(a)) >>> b = np.array(b) / np.min(b) # scale values to be positive @@ -3015,7 +3015,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram >>> from matplotlib.pyplot import hist - >>> values = hist(randomgen.generator.rayleigh(3, 100000), bins=200, density=True) + >>> values = hist(np.random.rayleigh(3, 100000), bins=200, density=True) Wave heights tend to follow a Rayleigh distribution. If the mean wave height is 1 meter, what fraction of waves are likely to be larger than 3 @@ -3023,7 +3023,7 @@ cdef class RandomGenerator: >>> meanvalue = 1 >>> modevalue = np.sqrt(2 / np.pi) * meanvalue - >>> s = randomgen.generator.rayleigh(modevalue, 1000000) + >>> s = np.random.rayleigh(modevalue, 1000000) The percentage of waves larger than 3 meters is: @@ -3095,7 +3095,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(randomgen.generator.wald(3, 2, 100000), bins=200, density=True) + >>> h = plt.hist(np.random.wald(3, 2, 100000), bins=200, density=True) >>> plt.show() """ @@ -3162,7 +3162,7 @@ cdef class RandomGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(randomgen.generator.triangular(-3, 0, 8, 100000), bins=200, + >>> h = plt.hist(np.random.triangular(-3, 0, 8, 100000), bins=200, ... density=True) >>> plt.show() @@ -3275,7 +3275,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> n, p = 10, .5 # number of trials, probability of each trial - >>> s = randomgen.generator.binomial(n, p, 1000) + >>> s = np.random.binomial(n, p, 1000) # result of flipping a coin 10 times, tested 1000 times. A real world example. A company drills 9 wild-cat oil exploration @@ -3285,7 +3285,7 @@ cdef class RandomGenerator: Let's do 20,000 trials of the model, and count the number that generate zero positive results. - >>> sum(randomgen.generator.binomial(9, 0.1, 20000) == 0)/20000. + >>> sum(np.random.binomial(9, 0.1, 20000) == 0)/20000. # answer = 0.38885, or 38%. """ @@ -3410,7 +3410,7 @@ cdef class RandomGenerator: for each successive well, that is what is the probability of a single success after drilling 5 wells, after 6 wells, etc.? - >>> s = randomgen.generator.negative_binomial(1, 0.9, 100000) + >>> s = np.random.negative_binomial(1, 0.9, 100000) >>> for i in range(1, 11): # doctest: +SKIP ... probability = sum(s>> a = 2. # parameter - >>> s = randomgen.generator.zipf(a, 1000) + >>> s = np.random.zipf(a, 1000) Display the histogram of the samples, along with the probability density function: @@ -3609,7 +3609,7 @@ cdef class RandomGenerator: Draw ten thousand values from the geometric distribution, with the probability of an individual success equal to 0.35: - >>> z = randomgen.generator.geometric(p=0.35, size=10000) + >>> z = np.random.geometric(p=0.35, size=10000) How many trials succeeded after a single run? @@ -3697,7 +3697,7 @@ cdef class RandomGenerator: >>> ngood, nbad, nsamp = 100, 2, 10 # number of good, number of bad, and number of samples - >>> s = randomgen.generator.hypergeometric(ngood, nbad, nsamp, 1000) + >>> s = np.random.hypergeometric(ngood, nbad, nsamp, 1000) >>> from matplotlib.pyplot import hist >>> hist(s) # note that it is very unlikely to grab both bad items @@ -3706,7 +3706,7 @@ cdef class RandomGenerator: If you pull 15 marbles at random, how likely is it that 12 or more of them are one color? - >>> s = randomgen.generator.hypergeometric(15, 15, 15, 100000) + >>> s = np.random.hypergeometric(15, 15, 15, 100000) >>> sum(s>=12)/100000. + sum(s<=3)/100000. # answer = 0.003 ... pretty unlikely! @@ -3807,7 +3807,7 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> a = .6 - >>> s = randomgen.generator.logseries(a, 10000) + >>> s = np.random.logseries(a, 10000) >>> import matplotlib.pyplot as plt >>> count, bins, ignored = plt.hist(s) @@ -3815,8 +3815,8 @@ cdef class RandomGenerator: >>> def logseries(k, p): ... return -p**k/(k*np.log(1-p)) - >>> plt.plot(bins, logseries(bins, a)*count.max()/ - logseries(bins, a).max(), 'r') + >>> plt.plot(bins, logseries(bins, a) * count.max()/ + ... logseries(bins, a).max(), 'r') >>> plt.show() """ @@ -3897,7 +3897,7 @@ cdef class RandomGenerator: Diagonal covariance means that points are oriented along x or y-axis: >>> import matplotlib.pyplot as plt - >>> x, y = randomgen.generator.multivariate_normal(mean, cov, 5000).T + >>> x, y = np.random.multivariate_normal(mean, cov, 5000).T >>> plt.plot(x, y, 'x') >>> plt.axis('equal') >>> plt.show() @@ -3917,7 +3917,7 @@ cdef class RandomGenerator: -------- >>> mean = (1, 2) >>> cov = [[1, 0], [0, 1]] - >>> x = randomgen.generator.multivariate_normal(mean, cov, (3, 3)) + >>> x = np.random.multivariate_normal(mean, cov, (3, 3)) >>> x.shape (3, 3, 2) @@ -3925,7 +3925,7 @@ cdef class RandomGenerator: standard deviation: >>> list((x[0,0,:] - mean) < 0.6) - [True, True] + [True, False] # random """ from numpy.dual import svd @@ -4033,24 +4033,24 @@ cdef class RandomGenerator: -------- Throw a dice 20 times: - >>> randomgen.generator.multinomial(20, [1/6.]*6, size=1) - array([[4, 1, 7, 5, 2, 1]]) + >>> np.random.multinomial(20, [1/6.]*6, size=1) + array([[2, 5, 3, 3, 3, 4]]) # random It landed 4 times on 1, once on 2, etc. Now, throw the dice 20 times, and 20 times again: - >>> randomgen.generator.multinomial(20, [1/6.]*6, size=2) - array([[3, 4, 3, 3, 4, 3], - [2, 4, 3, 4, 0, 7]]) + >>> np.random.multinomial(20, [1/6.]*6, size=2) + array([[5, 2, 1, 2, 5, 5], + [5, 3, 4, 4, 2, 2]]) # random For the first run, we threw 3 times 1, 4 times 2, etc. For the second, we threw 2 times 1, 4 times 2, etc. A loaded die is more likely to land on number 6: - >>> randomgen.generator.multinomial(100, [1/7.]*5 + [2/7.]) - array([11, 16, 14, 17, 16, 26]) # random + >>> np.random.multinomial(100, [1/7.]*5 + [2/7.]) + array([11, 16, 14, 17, 16, 26]) # random The probability inputs should be normalized. As an implementation detail, the value of the last entry is ignored and assumed to take @@ -4058,12 +4058,12 @@ cdef class RandomGenerator: A biased coin which has twice as much weight on one side as on the other should be sampled like so: - >>> randomgen.generator.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT + >>> np.random.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT array([38, 62]) # random not like: - >>> randomgen.generator.multinomial(100, [1.0, 2.0]) # WRONG + >>> np.random.multinomial(100, [1.0, 2.0]) # WRONG array([100, 0]) """ @@ -4180,7 +4180,7 @@ cdef class RandomGenerator: average length, but allowing some variation in the relative sizes of the pieces. - >>> s = randomgen.generator.dirichlet((10, 5, 3), 20).transpose() + >>> s = np.random.dirichlet((10, 5, 3), 20).transpose() >>> import matplotlib.pyplot as plt >>> plt.barh(range(20), s[0]) @@ -4275,14 +4275,14 @@ cdef class RandomGenerator: Examples -------- >>> arr = np.arange(10) - >>> randomgen.shuffle(arr) + >>> np.random.shuffle(arr) >>> arr [1 7 5 2 9 4 3 6 0 8] # random Multi-dimensional arrays are only shuffled along the first axis: >>> arr = np.arange(9).reshape((3, 3)) - >>> randomgen.generator.shuffle(arr) + >>> np.random.shuffle(arr) >>> arr array([[3, 4, 5], # random [6, 7, 8], @@ -4363,14 +4363,14 @@ cdef class RandomGenerator: Examples -------- - >>> randomgen.generator.permutation(10) + >>> np.random.permutation(10) array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) # random - >>> randomgen.generator.permutation([1, 4, 9, 12, 15]) + >>> np.random.permutation([1, 4, 9, 12, 15]) array([15, 1, 9, 4, 12]) # random >>> arr = np.arange(9).reshape((3, 3)) - >>> randomgen.generator.permutation(arr) + >>> np.random.permutation(arr) array([[6, 7, 8], # random [0, 1, 2], [3, 4, 5]]) diff --git a/numpy/random/randomgen/legacy/_legacy.pyx b/numpy/random/randomgen/legacy/_legacy.pyx index db8885d79d07..ecceeecfb7e2 100644 --- a/numpy/random/randomgen/legacy/_legacy.pyx +++ b/numpy/random/randomgen/legacy/_legacy.pyx @@ -58,8 +58,8 @@ cdef class _LegacyGenerator: from ``_LegacyGenerator``, and other functions must be called from ``RandomGenerator``. - >>> from randomgen import RandomGenerator, MT19937 - >>> from randomgen.legacy._legacy import _LegacyGenerator + >>> from numpy.random.randomgen import RandomGenerator, MT19937 + >>> from numpy.random.randomgen.legacy._legacy import _LegacyGenerator >>> mt = MT19937(12345) >>> lg = _LegacyGenerator(mt) >>> rg = RandomGenerator(mt) @@ -141,8 +141,8 @@ cdef class _LegacyGenerator: The best method to access seed is to directly use a basic RNG instance. This example demonstrates this best practice. - >>> from randomgen import MT19937 - >>> from randomgen.legacy import LegacyGenerator + >>> from numpy.random.randomgen import MT19937 + >>> from numpy.random.randomgen.legacy import LegacyGenerator >>> brng = MT19937(123456789) >>> lg = brng.generator >>> brng.seed(987654321) @@ -162,7 +162,6 @@ cdef class _LegacyGenerator: # TODO: Should this remain self._basicrng.seed(*args, **kwargs) self._reset_gauss() - return self @property def state(self): @@ -329,7 +328,7 @@ cdef class _LegacyGenerator: -------- Output a 3x8000 array: - >>> n = randomgen.generator.standard_exponential((3, 8000)) + >>> n = np.random.standard_exponential((3, 8000)) """ return cont(&legacy_standard_exponential, self._aug_state, size, self.lock, 0, None, None, CONS_NONE, @@ -375,16 +374,16 @@ cdef class _LegacyGenerator: ----- For random samples from :math:`N(\\mu, \\sigma^2)`, use: - ``sigma * randomgen.generator.randn(...) + mu`` + ``sigma * np.random.randn(...) + mu`` Examples -------- - >>> randomgen.generator.randn() + >>> np.random.randn() 2.1923875335537315 #random Two-by-four array of samples from N(3, 6.25): - >>> 2.5 * randomgen.generator.randn(2, 4) + 3 + >>> 2.5 * np.random.randn(2, 4) + 3 array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random @@ -415,13 +414,13 @@ cdef class _LegacyGenerator: Examples -------- - >>> s = randomgen.generator.standard_normal(8000) + >>> s = np.random.standard_normal(8000) >>> s array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random -0.38672696, -0.4685006 ]) #random >>> s.shape (8000,) - >>> s = randomgen.generator.standard_normal(size=(3, 4, 2)) + >>> s = np.random.standard_normal(size=(3, 4, 2)) >>> s.shape (3, 4, 2) @@ -500,7 +499,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> mu, sigma = 0, 0.1 # mean and standard deviation - >>> s = randomgen.generator.normal(mu, sigma, 1000) + >>> s = np.random.normal(mu, sigma, 1000) Verify the mean and the variance: @@ -582,7 +581,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> shape, scale = 2., 1. # mean and width - >>> s = randomgen.generator.standard_gamma(shape, 1000000) + >>> s = np.random.standard_gamma(shape, 1000000) Display the histogram of the samples, along with the probability density function: @@ -660,7 +659,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> shape, scale = 2., 2. # mean and dispersion - >>> s = randomgen.generator.gamma(shape, scale, 1000) + >>> s = np.random.gamma(shape, scale, 1000) Display the histogram of the samples, along with the probability density function: @@ -750,7 +749,7 @@ cdef class _LegacyGenerator: >>> dfnum = 1. # between group degrees of freedom >>> dfden = 48. # within groups degrees of freedom - >>> s = randomgen.generator.f(dfnum, dfden, 1000) + >>> s = np.random.f(dfnum, dfden, 1000) The lower bound for the top 1% of the samples is : @@ -825,9 +824,9 @@ cdef class _LegacyGenerator: >>> dfnum = 3 # between group deg of freedom >>> dfden = 20 # within groups degrees of freedom >>> nonc = 3.0 - >>> nc_vals = randomgen.generator.noncentral_f(dfnum, dfden, nonc, 1000000) + >>> nc_vals = np.random.noncentral_f(dfnum, dfden, nonc, 1000000) >>> NF = np.histogram(nc_vals, bins=50, density=True) - >>> c_vals = randomgen.generator.f(dfnum, dfden, 1000000) + >>> c_vals = np.random.f(dfnum, dfden, 1000000) >>> F = np.histogram(c_vals, bins=50, density=True) >>> import matplotlib.pyplot as plt >>> plt.plot(F[1][1:], F[0]) @@ -899,7 +898,7 @@ cdef class _LegacyGenerator: Examples -------- - >>> randomgen.generator.chisquare(2,4) + >>> np.random.chisquare(2,4) array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) # random """ @@ -956,7 +955,7 @@ cdef class _LegacyGenerator: Draw values from the distribution and plot the histogram >>> import matplotlib.pyplot as plt - >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), ... bins=200, density=True) >>> plt.show() @@ -964,9 +963,9 @@ cdef class _LegacyGenerator: and compare to a chisquare. >>> plt.figure() - >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, .0000001, 100000), + >>> values = plt.hist(np.random.noncentral_chisquare(3, .0000001, 100000), ... bins=np.arange(0., 25, .1), density=True) - >>> values2 = plt.hist(randomgen.generator.chisquare(3, 100000), + >>> values2 = plt.hist(np.random.chisquare(3, 100000), ... bins=np.arange(0., 25, .1), density=True) >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') >>> plt.show() @@ -975,7 +974,7 @@ cdef class _LegacyGenerator: distribution. >>> plt.figure() - >>> values = plt.hist(randomgen.generator.noncentral_chisquare(3, 20, 100000), + >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), ... bins=200, density=True) >>> plt.show() @@ -1040,7 +1039,7 @@ cdef class _LegacyGenerator: -------- Draw samples and plot the distribution: - >>> s = randomgen.generator.standard_cauchy(1000000) + >>> s = np.random.standard_cauchy(1000000) >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well >>> import matplotlib.pyplot as plt >>> plt.hist(s, bins=100) @@ -1114,7 +1113,7 @@ cdef class _LegacyGenerator: We have 10 degrees of freedom, so is the sample mean within 95% of the recommended value? - >>> s = randomgen.generator.standard_t(10, size=100000) + >>> s = np.random.standard_t(10, size=100000) >>> np.mean(intake) 6753.636363636364 >>> intake.std(ddof=1) @@ -1225,7 +1224,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> a, m = 3., 2. # shape and mode - >>> s = (randomgen.generator.pareto(a, 1000) + 1) * m + >>> s = (np.random.pareto(a, 1000) + 1) * m Display the histogram of the samples, along with the probability density function: @@ -1318,7 +1317,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> a = 5. # shape - >>> s = randomgen.generator.weibull(a, 1000) + >>> s = np.random.weibull(a, 1000) Display the histogram of the samples, along with the probability density function: @@ -1328,7 +1327,7 @@ cdef class _LegacyGenerator: >>> def weib(x,n,a): ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) - >>> count, bins, ignored = plt.hist(randomgen.generator.weibull(5.,1000)) + >>> count, bins, ignored = plt.hist(np.random.weibull(5.,1000)) >>> x = np.arange(1,100.)/50. >>> scale = count.max()/weib(x, 1., 5.).max() >>> plt.plot(x, weib(x, 1., 5.)*scale) @@ -1398,7 +1397,7 @@ cdef class _LegacyGenerator: >>> a = 5. # shape >>> samples = 1000 - >>> s = randomgen.generator.power(a, samples) + >>> s = np.random.power(a, samples) Display the histogram of the samples, along with the probability density function: @@ -1414,20 +1413,20 @@ cdef class _LegacyGenerator: Compare the power function distribution to the inverse of the Pareto. >>> from scipy import stats - >>> rvs = randomgen.generator.power(5, 1000000) - >>> rvsp = randomgen.generator.pareto(5, 1000000) + >>> rvs = np.random.power(5, 1000000) + >>> rvsp = np.random.pareto(5, 1000000) >>> xx = np.linspace(0,1,100) >>> powpdf = stats.powerlaw.pdf(xx,5) >>> plt.figure() >>> plt.hist(rvs, bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('randomgen.generator.power(5)') + >>> plt.title('np.random.power(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, density=True) >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('inverse of 1 + randomgen.generator.pareto(5)') + >>> plt.title('inverse of 1 + np.random.pareto(5)') >>> plt.figure() >>> plt.hist(1./(1.+rvsp), bins=50, density=True) @@ -1505,7 +1504,7 @@ cdef class _LegacyGenerator: Draw samples from the distribution: >>> mu, sigma = 3., 1. # mean and standard deviation - >>> s = randomgen.generator.lognormal(mu, sigma, 1000) + >>> s = np.random.lognormal(mu, sigma, 1000) Display the histogram of the samples, along with the probability density function: @@ -1529,7 +1528,7 @@ cdef class _LegacyGenerator: >>> # values, drawn from a normal distribution. >>> b = [] >>> for i in range(1000): - ... a = 10. + randomgen.generator.randn(100) + ... a = 10. + np.random.randn(100) ... b.append(np.product(a)) >>> b = np.array(b) / np.min(b) # scale values to be positive @@ -1609,7 +1608,7 @@ cdef class _LegacyGenerator: Draw values from the distribution and plot the histogram: >>> import matplotlib.pyplot as plt - >>> h = plt.hist(randomgen.generator.wald(3, 2, 100000), bins=200, density=True) + >>> h = plt.hist(np.random.wald(3, 2, 100000), bins=200, density=True) >>> plt.show() """ @@ -1683,7 +1682,7 @@ cdef class _LegacyGenerator: for each successive well, that is what is the probability of a single success after drilling 5 wells, after 6 wells, etc.? - >>> s = randomgen.generator.negative_binomial(1, 0.9, 100000) + >>> s = np.random.negative_binomial(1, 0.9, 100000) >>> for i in range(1, 11): # doctest: +SKIP ... probability = sum(s Date: Wed, 27 Mar 2019 09:30:04 -0400 Subject: [PATCH 214/279] MAINT: add overlap checks to choose, take, put, putmask (#13182) Fixes #9293, #6272 --- doc/release/1.17.0-notes.rst | 5 ++ numpy/core/fromnumeric.py | 9 ++- numpy/core/src/multiarray/item_selection.c | 90 +++++++++++++--------- numpy/core/tests/test_multiarray.py | 20 +++++ 4 files changed, 86 insertions(+), 38 deletions(-) diff --git a/doc/release/1.17.0-notes.rst b/doc/release/1.17.0-notes.rst index 4c7978f10f50..7ff064c0143e 100644 --- a/doc/release/1.17.0-notes.rst +++ b/doc/release/1.17.0-notes.rst @@ -72,6 +72,11 @@ Looking up ``__buffer__`` attribute in `numpy.frombuffer` was undocumented and non-functional. This code was removed. If needed, use ``frombuffer(memoryview(obj), ...)`` instead. +``out``is buffered for memory overlaps in ``np.take``, ``np.choose``, ``np.put`` +-------------------------------------------------------------------------------- +If the out argument to these functions is provided and has memory overlap with +the other arguments, it is now buffered to avoid order-dependent behavior. + C API changes ============= diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py index 760577890769..cb10c39478f1 100644 --- a/numpy/core/fromnumeric.py +++ b/numpy/core/fromnumeric.py @@ -130,7 +130,8 @@ def take(a, indices, axis=None, out=None, mode='raise'): input array is used. out : ndarray, optional (Ni..., Nj..., Nk...) If provided, the result will be placed in this array. It should - be of the appropriate shape and dtype. + be of the appropriate shape and dtype. Note that `out` is always + buffered if `mode='raise'`; use other modes for better performance. mode : {'raise', 'wrap', 'clip'}, optional Specifies how out-of-bounds indices will behave. @@ -355,7 +356,8 @@ def choose(a, choices, out=None, mode='raise'): ``choices.shape[0]``) is taken as defining the "sequence". out : array, optional If provided, the result will be inserted into this array. It should - be of the appropriate shape and dtype. + be of the appropriate shape and dtype. Note that `out` is always + buffered if `mode='raise'`; use other modes for better performance. mode : {'raise' (default), 'wrap', 'clip'}, optional Specifies how indices outside `[0, n-1]` will be treated: @@ -512,7 +514,8 @@ def put(a, ind, v, mode='raise'): 'clip' mode means that all indices that are too large are replaced by the index that addresses the last element along that axis. Note - that this disables indexing with negative numbers. + that this disables indexing with negative numbers. In 'raise' mode, + if an exception occurs the target array may still be modified. See Also -------- diff --git a/numpy/core/src/multiarray/item_selection.c b/numpy/core/src/multiarray/item_selection.c index 5a40803dbaa6..ff7c1130a9c1 100644 --- a/numpy/core/src/multiarray/item_selection.c +++ b/numpy/core/src/multiarray/item_selection.c @@ -98,6 +98,10 @@ PyArray_TakeFrom(PyArrayObject *self0, PyObject *indices0, int axis, goto fail; } + if (arrays_overlap(out, self)) { + flags |= NPY_ARRAY_ENSURECOPY; + } + if (clipmode == NPY_RAISE) { /* * we need to make sure and get a copy @@ -261,6 +265,7 @@ PyArray_PutTo(PyArrayObject *self, PyObject* values0, PyObject *indices0, npy_intp i, chunk, ni, max_item, nv, tmp; char *src, *dest; int copied = 0; + int overlap = 0; indices = NULL; values = NULL; @@ -274,24 +279,6 @@ PyArray_PutTo(PyArrayObject *self, PyObject* values0, PyObject *indices0, return NULL; } - if (!PyArray_ISCONTIGUOUS(self)) { - PyArrayObject *obj; - int flags = NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY; - - if (clipmode == NPY_RAISE) { - flags |= NPY_ARRAY_ENSURECOPY; - } - Py_INCREF(PyArray_DESCR(self)); - obj = (PyArrayObject *)PyArray_FromArray(self, - PyArray_DESCR(self), flags); - if (obj != self) { - copied = 1; - } - self = obj; - } - max_item = PyArray_SIZE(self); - dest = PyArray_DATA(self); - chunk = PyArray_DESCR(self)->elsize; indices = (PyArrayObject *)PyArray_ContiguousFromAny(indices0, NPY_INTP, 0, 0); if (indices == NULL) { @@ -308,6 +295,25 @@ PyArray_PutTo(PyArrayObject *self, PyObject* values0, PyObject *indices0, if (nv <= 0) { goto finish; } + + overlap = arrays_overlap(self, values) || arrays_overlap(self, indices); + if (overlap || !PyArray_ISCONTIGUOUS(self)) { + PyArrayObject *obj; + int flags = NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY | + NPY_ARRAY_ENSURECOPY; + + Py_INCREF(PyArray_DESCR(self)); + obj = (PyArrayObject *)PyArray_FromArray(self, + PyArray_DESCR(self), flags); + if (obj != self) { + copied = 1; + } + self = obj; + } + max_item = PyArray_SIZE(self); + dest = PyArray_DATA(self); + chunk = PyArray_DESCR(self)->elsize; + if (PyDataType_REFCHK(PyArray_DESCR(self))) { switch(clipmode) { case NPY_RAISE: @@ -434,10 +440,11 @@ PyArray_PutMask(PyArrayObject *self, PyObject* values0, PyObject* mask0) PyArray_FastPutmaskFunc *func; PyArrayObject *mask, *values; PyArray_Descr *dtype; - npy_intp i, j, chunk, ni, max_item, nv; + npy_intp i, j, chunk, ni, nv; char *src, *dest; npy_bool *mask_data; int copied = 0; + int overlap = 0; mask = NULL; values = NULL; @@ -447,29 +454,14 @@ PyArray_PutMask(PyArrayObject *self, PyObject* values0, PyObject* mask0) "be an array"); return NULL; } - if (!PyArray_ISCONTIGUOUS(self)) { - PyArrayObject *obj; - dtype = PyArray_DESCR(self); - Py_INCREF(dtype); - obj = (PyArrayObject *)PyArray_FromArray(self, dtype, - NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY); - if (obj != self) { - copied = 1; - } - self = obj; - } - - max_item = PyArray_SIZE(self); - dest = PyArray_DATA(self); - chunk = PyArray_DESCR(self)->elsize; mask = (PyArrayObject *)PyArray_FROM_OTF(mask0, NPY_BOOL, NPY_ARRAY_CARRAY | NPY_ARRAY_FORCECAST); if (mask == NULL) { goto fail; } ni = PyArray_SIZE(mask); - if (ni != max_item) { + if (ni != PyArray_SIZE(self)) { PyErr_SetString(PyExc_ValueError, "putmask: mask and data must be " "the same size"); @@ -491,6 +483,27 @@ PyArray_PutMask(PyArrayObject *self, PyObject* values0, PyObject* mask0) } src = PyArray_DATA(values); + overlap = arrays_overlap(self, values) || arrays_overlap(self, mask); + if (overlap || !PyArray_ISCONTIGUOUS(self)) { + int flags = NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY; + PyArrayObject *obj; + + if (overlap) { + flags |= NPY_ARRAY_ENSURECOPY; + } + + dtype = PyArray_DESCR(self); + Py_INCREF(dtype); + obj = (PyArrayObject *)PyArray_FromArray(self, dtype, flags); + if (obj != self) { + copied = 1; + } + self = obj; + } + + chunk = PyArray_DESCR(self)->elsize; + dest = PyArray_DATA(self); + if (PyDataType_REFCHK(PyArray_DESCR(self))) { for (i = 0, j = 0; i < ni; i++, j++) { if (j >= nv) { @@ -712,6 +725,13 @@ PyArray_Choose(PyArrayObject *ip, PyObject *op, PyArrayObject *out, "choose: invalid shape for output array."); goto fail; } + + for (i = 0; i < n; i++) { + if (arrays_overlap(out, mps[i])) { + flags |= NPY_ARRAY_ENSURECOPY; + } + } + if (clipmode == NPY_RAISE) { /* * we need to make sure and get a copy diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index b8d5dc71fd7d..ae2fd3cf42ef 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -1491,6 +1491,11 @@ def test_choose(self): # gh-12031, caused SEGFAULT assert_raises(TypeError, oned.choose,np.void(0), [oned]) + # gh-6272 check overlap on out + x = np.arange(5) + y = np.choose([0,0,0], [x[:3], x[:3], x[:3]], out=x[1:4], mode='wrap') + assert_equal(y, np.array([0, 1, 2])) + def test_prod(self): ba = [1, 2, 10, 11, 6, 5, 4] ba2 = [[1, 2, 3, 4], [5, 6, 7, 9], [10, 3, 4, 5]] @@ -4377,6 +4382,16 @@ def test_record_array(self): assert_array_equal(rec['y'], [11, 4]) assert_array_equal(rec['z'], [3, 3]) + def test_overlaps(self): + # gh-6272 check overlap + x = np.array([True, False, True, False]) + np.putmask(x[1:4], [True, True, True], x[:3]) + assert_equal(x, np.array([True, True, False, True])) + + x = np.array([True, False, True, False]) + np.putmask(x[1:4], x[:3], [True, False, True]) + assert_equal(x, np.array([True, True, True, True])) + class TestTake(object): def tst_basic(self, x): @@ -4425,6 +4440,11 @@ def test_record_array(self): rec1 = rec.take([1]) assert_(rec1['x'] == 5.0 and rec1['y'] == 4.0) + def test_out_overlap(self): + # gh-6272 check overlap on out + x = np.arange(5) + y = np.take(x, [1, 2, 3], out=x[2:5], mode='wrap') + assert_equal(y, np.array([1, 2, 3])) class TestLexsort(object): def test_basic(self): From 39f0dbff0597af181c11cb3e50d0f055591f7952 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 28 Mar 2019 14:49:51 +0000 Subject: [PATCH 215/279] DOC: Use std docstring for multivariate normal (#13203) Switch from python-style kwarg signature to style used for all other functions --- numpy/random/mtrand/mtrand.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx index 445fd4a154fd..2426dbaa475f 100644 --- a/numpy/random/mtrand/mtrand.pyx +++ b/numpy/random/mtrand/mtrand.pyx @@ -4422,7 +4422,7 @@ cdef class RandomState: def multivariate_normal(self, mean, cov, size=None, check_valid='warn', tol=1e-8): """ - multivariate_normal(mean, cov[, size, check_valid, tol]) + multivariate_normal(mean, cov, size=None, check_valid='warn', tol=1e-8) Draw random samples from a multivariate normal distribution. From 43972706d283f2ce81b0a32f32689a5f021205fe Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 28 Mar 2019 20:53:36 +0200 Subject: [PATCH 216/279] BUILD: pin sphinx to before-2.0.0 --- .circleci/config.yml | 2 +- azure-pipelines.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cc01e8851bf5..2a3d826770a3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,7 +20,7 @@ jobs: command: | python3 -m venv venv . venv/bin/activate - pip install cython sphinx>=1.8.3 matplotlib + pip install cython sphinx==1.8.5 matplotlib sudo apt-get update sudo apt-get install -y graphviz texlive-fonts-recommended texlive-latex-recommended texlive-latex-extra texlive-generic-extra latexmk texlive-xetex diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d65d1e41fb15..722823b7ff2f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -81,7 +81,7 @@ jobs: displayName: 'install pre-built openblas' - script: python -m pip install --upgrade pip setuptools wheel displayName: 'Install tools' - - script: python -m pip install cython nose pytz pytest pickle5 vulture docutils sphinx>=1.8.3 numpydoc matplotlib + - script: python -m pip install cython nose pytz pytest pickle5 vulture docutils sphinx==1.8.5 numpydoc matplotlib displayName: 'Install dependencies; some are optional to avoid test skips' - script: /bin/bash -c "! vulture . --min-confidence 100 --exclude doc/,numpy/distutils/ | grep 'unreachable'" displayName: 'Check for unreachable code paths in Python modules' From 15b14c5212e872ae2a274529dc2f93f3902a2e85 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 26 Mar 2019 00:09:09 -0700 Subject: [PATCH 217/279] MAINT: Simplify logic in convert_datetime_to_datetimestruct Most of this is just emulating the behavior of python's divmod. With a carefully crafted out parameter, we can eliminate a lot of repetition --- numpy/core/src/multiarray/datetime.c | 211 ++++++++++----------------- 1 file changed, 78 insertions(+), 133 deletions(-) diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c index a33f643f1bf3..f1e4feac2f91 100644 --- a/numpy/core/src/multiarray/datetime.c +++ b/numpy/core/src/multiarray/datetime.c @@ -408,6 +408,26 @@ PyArray_TimedeltaStructToTimedelta(NPY_DATETIMEUNIT fr, npy_timedeltastruct *d) return -1; } +/* + * Computes the python `ret, d = divmod(d, unit)`. + * + * Note that GCC is smart enough at -O2 to eliminate the `if(*d < 0)` branch + * for subsequent calls to this command - it is able to deduce that `*d >= 0`. + */ +static inline +npy_int64 extract_unit(npy_datetime *d, npy_datetime unit) { + assert(unit > 0); + npy_int64 div = *d / unit; + npy_int64 mod = *d % unit; + if (mod < 0) { + mod += unit; + div -= 1; + } + assert(mod >= 0); + *d = mod; + return div; +} + /* * Converts a datetime based on the given metadata into a datetimestruct */ @@ -451,14 +471,8 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta, break; case NPY_FR_M: - if (dt >= 0) { - out->year = 1970 + dt / 12; - out->month = dt % 12 + 1; - } - else { - out->year = 1969 + (dt + 1) / 12; - out->month = 12 + (dt + 1)% 12; - } + out->year = 1970 + extract_unit(&dt, 12); + out->month = dt + 1; break; case NPY_FR_W: @@ -473,169 +487,100 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta, case NPY_FR_h: perday = 24LL; - if (dt >= 0) { - set_datetimestruct_days(dt / perday, out); - dt = dt % perday; - } - else { - set_datetimestruct_days((dt - (perday-1)) / perday, out); - dt = (perday-1) + (dt + 1) % perday; - } + set_datetimestruct_days(extract_unit(&dt, perday), out); out->hour = (int)dt; break; case NPY_FR_m: perday = 24LL * 60; - if (dt >= 0) { - set_datetimestruct_days(dt / perday, out); - dt = dt % perday; - } - else { - set_datetimestruct_days((dt - (perday-1)) / perday, out); - dt = (perday-1) + (dt + 1) % perday; - } - out->hour = (int)(dt / 60); - out->min = (int)(dt % 60); + set_datetimestruct_days(extract_unit(&dt, perday), out); + out->hour = (int)extract_unit(&dt, 60); + out->min = (int)dt; break; case NPY_FR_s: perday = 24LL * 60 * 60; - if (dt >= 0) { - set_datetimestruct_days(dt / perday, out); - dt = dt % perday; - } - else { - set_datetimestruct_days((dt - (perday-1)) / perday, out); - dt = (perday-1) + (dt + 1) % perday; - } - out->hour = (int)(dt / (60*60)); - out->min = (int)((dt / 60) % 60); - out->sec = (int)(dt % 60); + set_datetimestruct_days(extract_unit(&dt, perday), out); + out->hour = (int)extract_unit(&dt, 60*60); + out->min = (int)extract_unit(&dt, 60); + out->sec = (int)dt; break; case NPY_FR_ms: perday = 24LL * 60 * 60 * 1000; - if (dt >= 0) { - set_datetimestruct_days(dt / perday, out); - dt = dt % perday; - } - else { - set_datetimestruct_days((dt - (perday-1)) / perday, out); - dt = (perday-1) + (dt + 1) % perday; - } - out->hour = (int)(dt / (60*60*1000LL)); - out->min = (int)((dt / (60*1000LL)) % 60); - out->sec = (int)((dt / 1000LL) % 60); - out->us = (int)((dt % 1000LL) * 1000); + set_datetimestruct_days(extract_unit(&dt, perday), out); + out->hour = (int)extract_unit(&dt, 1000LL*60*60); + out->min = (int)extract_unit(&dt, 1000LL*60); + out->sec = (int)extract_unit(&dt, 1000LL); + out->us = (int)(dt * 1000); break; case NPY_FR_us: perday = 24LL * 60LL * 60LL * 1000LL * 1000LL; - - if (dt >= 0) { - set_datetimestruct_days(dt / perday, out); - dt = dt % perday; - } - else { - set_datetimestruct_days((dt - (perday-1)) / perday, out); - dt = (perday-1) + (dt + 1) % perday; - } - out->hour = (int)(dt / (60*60*1000000LL)); - out->min = (int)((dt / (60*1000000LL)) % 60); - out->sec = (int)((dt / 1000000LL) % 60); - out->us = (int)(dt % 1000000LL); + set_datetimestruct_days(extract_unit(&dt, perday), out); + out->hour = (int)extract_unit(&dt, 1000LL*1000*60*60); + out->min = (int)extract_unit(&dt, 1000LL*1000*60); + out->sec = (int)extract_unit(&dt, 1000LL*1000); + out->us = (int)dt; break; case NPY_FR_ns: perday = 24LL * 60LL * 60LL * 1000LL * 1000LL * 1000LL; - if (dt >= 0) { - set_datetimestruct_days(dt / perday, out); - dt = dt % perday; - } - else { - set_datetimestruct_days((dt - (perday-1)) / perday, out); - dt = (perday-1) + (dt + 1) % perday; - } - out->hour = (int)(dt / (60*60*1000000000LL)); - out->min = (int)((dt / (60*1000000000LL)) % 60); - out->sec = (int)((dt / 1000000000LL) % 60); - out->us = (int)((dt / 1000LL) % 1000000LL); - out->ps = (int)((dt % 1000LL) * 1000); + set_datetimestruct_days(extract_unit(&dt, perday), out); + out->hour = (int)extract_unit(&dt, 1000LL*1000*1000*60*60); + out->min = (int)extract_unit(&dt, 1000LL*1000*1000*60); + out->sec = (int)extract_unit(&dt, 1000LL*1000*1000); + out->us = (int)extract_unit(&dt, 1000LL); + out->ps = (int)(dt * 1000); break; case NPY_FR_ps: perday = 24LL * 60 * 60 * 1000 * 1000 * 1000 * 1000; - if (dt >= 0) { - set_datetimestruct_days(dt / perday, out); - dt = dt % perday; - } - else { - set_datetimestruct_days((dt - (perday-1)) / perday, out); - dt = (perday-1) + (dt + 1) % perday; - } - out->hour = (int)(dt / (60*60*1000000000000LL)); - out->min = (int)((dt / (60*1000000000000LL)) % 60); - out->sec = (int)((dt / 1000000000000LL) % 60); - out->us = (int)((dt / 1000000LL) % 1000000LL); - out->ps = (int)(dt % 1000000LL); + set_datetimestruct_days(extract_unit(&dt, perday), out); + out->hour = (int)extract_unit(&dt, 1000LL*1000*1000*1000*60*60); + out->min = (int)extract_unit(&dt, 1000LL*1000*1000*1000*60); + out->sec = (int)extract_unit(&dt, 1000LL*1000*1000*1000); + out->us = (int)extract_unit(&dt, 1000LL*1000); + out->ps = (int)(dt); break; case NPY_FR_fs: /* entire range is only +- 2.6 hours */ - if (dt >= 0) { - out->hour = (int)(dt / (60*60*1000000000000000LL)); - out->min = (int)((dt / (60*1000000000000000LL)) % 60); - out->sec = (int)((dt / 1000000000000000LL) % 60); - out->us = (int)((dt / 1000000000LL) % 1000000LL); - out->ps = (int)((dt / 1000LL) % 1000000LL); - out->as = (int)((dt % 1000LL) * 1000); - } - else { - npy_datetime minutes; - - minutes = dt / (60*1000000000000000LL); - dt = dt % (60*1000000000000000LL); - if (dt < 0) { - dt += (60*1000000000000000LL); - --minutes; - } - /* Offset the negative minutes */ - add_minutes_to_datetimestruct(out, minutes); - out->sec = (int)((dt / 1000000000000000LL) % 60); - out->us = (int)((dt / 1000000000LL) % 1000000LL); - out->ps = (int)((dt / 1000LL) % 1000000LL); - out->as = (int)((dt % 1000LL) * 1000); - } + out->hour = (int)extract_unit(&dt, 1000LL*1000*1000*1000*1000*60*60); + if (out->hour < 0) { + out->year = 1969; + out->month = 12; + out->day = 31; + out->hour += 24; + assert(out->hour >= 0); + } + out->min = (int)extract_unit(&dt, 1000LL*1000*1000*1000*1000*60); + out->sec = (int)extract_unit(&dt, 1000LL*1000*1000*1000*1000); + out->us = (int)extract_unit(&dt, 1000LL*1000*1000); + out->ps = (int)extract_unit(&dt, 1000LL); + out->as = (int)(dt * 1000); break; case NPY_FR_as: /* entire range is only +- 9.2 seconds */ - if (dt >= 0) { - out->sec = (int)((dt / 1000000000000000000LL) % 60); - out->us = (int)((dt / 1000000000000LL) % 1000000LL); - out->ps = (int)((dt / 1000000LL) % 1000000LL); - out->as = (int)(dt % 1000000LL); - } - else { - npy_datetime seconds; - - seconds = dt / 1000000000000000000LL; - dt = dt % 1000000000000000000LL; - if (dt < 0) { - dt += 1000000000000000000LL; - --seconds; - } - /* Offset the negative seconds */ - add_seconds_to_datetimestruct(out, seconds); - out->us = (int)((dt / 1000000000000LL) % 1000000LL); - out->ps = (int)((dt / 1000000LL) % 1000000LL); - out->as = (int)(dt % 1000000LL); - } + out->sec = (int)extract_unit(&dt, 1000LL*1000*1000*1000*1000*1000); + if (out->sec < 0) { + out->year = 1969; + out->month = 12; + out->day = 31; + out->hour = 23; + out->min = 59; + out->sec += 60; + assert(out->sec >= 0); + } + out->us = (int)extract_unit(&dt, 1000LL*1000*1000*1000); + out->ps = (int)extract_unit(&dt, 1000LL*1000); + out->as = (int)dt; break; default: From 27efe4d1e2a37143c5bd7915ed49c95a344bf0e7 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 26 Mar 2019 14:19:11 -0700 Subject: [PATCH 218/279] TST: add tests for the existence and round-tripping of datetime limits --- numpy/core/tests/test_datetime.py | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py index 8d480e7a3a61..91cd2c115229 100644 --- a/numpy/core/tests/test_datetime.py +++ b/numpy/core/tests/test_datetime.py @@ -2220,6 +2220,44 @@ def test_corecursive_input(self): assert_raises(RecursionError, obj_arr.astype, 'M8') assert_raises(RecursionError, obj_arr.astype, 'm8') + @pytest.mark.parametrize("time_unit", [ + "Y", "M", "W", "D", "h", "m", "s", "ms", "us", "ns", "ps", "fs", "as", + # compound units + "10D", "2M", + ]) + def test_limit_symmetry(self, time_unit): + """ + Dates should have symmetric limits around the unix epoch at +/-np.int64 + """ + epoch = np.datetime64(0, time_unit) + latest = np.datetime64(np.iinfo(np.int64).max, time_unit) + earliest = np.datetime64(-np.iinfo(np.int64).max, time_unit) + + # above should not have overflowed + assert earliest < epoch < latest + + @pytest.mark.parametrize("time_unit", [ + "Y", "M", + pytest.param("W", marks=pytest.mark.xfail(reason="gh-13197")), + "D", "h", "m", + "s", "ms", "us", "ns", "ps", "fs", "as", + pytest.param("10D", marks=pytest.mark.xfail(reason="similar to gh-13197")), + ]) + @pytest.mark.parametrize("sign", [-1, 1]) + def test_limit_str_roundtrip(self, time_unit, sign): + """ + Limits should roundtrip when converted to strings. + + This tests the conversion to and from npy_datetimestruct. + """ + # TODO: add absolute (gold standard) time span limit strings + limit = np.datetime64(np.iinfo(np.int64).max * sign, time_unit) + + # Convert to string and back. Explicit unit needed since the day and + # week reprs are not distinguishable. + limit_via_str = np.datetime64(str(limit), time_unit) + assert limit_via_str == limit + class TestDateTimeData(object): From 303b2d5bcdac67b3131e3f1b676924a51ebd9a38 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 29 Mar 2019 17:44:04 +0300 Subject: [PATCH 219/279] MAINT: merge randomgen/fix-legacy --- numpy/random/__init__.py | 2 - numpy/random/randomgen/legacy/_legacy.pyx | 287 +++++++++++++++++++++- numpy/random/randomgen/legacy/legacy.py | 12 + 3 files changed, 287 insertions(+), 14 deletions(-) diff --git a/numpy/random/__init__.py b/numpy/random/__init__.py index 0cf519d5b5a7..818ece58aba2 100644 --- a/numpy/random/__init__.py +++ b/numpy/random/__init__.py @@ -143,8 +143,6 @@ if _x[0] != '_' and _x not in ('poisson_lam_max', 'state'): locals()[_x] = getattr(mtrand, _x) del _x -get_state = mtrand.get_state -set_state = mtrand.set_state # Some aliases: ranf = random = sample = random_sample diff --git a/numpy/random/randomgen/legacy/_legacy.pyx b/numpy/random/randomgen/legacy/_legacy.pyx index ecceeecfb7e2..b3b8af0cf5ca 100644 --- a/numpy/random/randomgen/legacy/_legacy.pyx +++ b/numpy/random/randomgen/legacy/_legacy.pyx @@ -16,13 +16,35 @@ try: except ImportError: from dummy_threading import Lock -from ..common cimport cont, disc, CONS_NONE, CONS_POSITIVE, CONS_NON_NEGATIVE, CONS_BOUNDED_0_1 -from ..distributions cimport brng_t -from .legacy_distributions cimport * +from ..bounded_integers cimport (_rand_int32, _rand_int64, _rand_int16, + _rand_uint32, _rand_uint64, _rand_uint16, + _rand_bool, _rand_int8, _rand_uint8) +from ..common cimport (cont, disc, double_fill, CONS_NONE, CONS_POSITIVE, + CONS_NON_NEGATIVE, CONS_BOUNDED_0_1) +from ..distributions cimport brng_t, random_double_fill +from .legacy_distributions cimport (aug_brng_t, legacy_beta, legacy_pareto, + legacy_exponential, legacy_f, legacy_chisquare, legacy_gamma, + legacy_gauss, legacy_standard_exponential, legacy_negative_binomial, + legacy_normal, legacy_standard_gamma, legacy_standard_cauchy, + legacy_standard_t, legacy_noncentral_f, legacy_noncentral_chisquare, + legacy_negative_binomial, legacy_power, legacy_lognormal, legacy_wald, + legacy_weibull) from ..xoroshiro128 import Xoroshiro128 np.import_array() +_randint_types = {'bool': (0, 2), + 'int8': (-2**7, 2**7), + 'int16': (-2**15, 2**15), + 'int32': (-2**31, 2**31), + 'int64': (-2**63, 2**63), + 'uint8': (0, 2**8), + 'uint16': (0, 2**16), + 'uint32': (0, 2**32), + 'uint64': (0, 2**64) + } + + cdef class _LegacyGenerator: """ _LegacyGenerator(brng=None) @@ -184,13 +206,6 @@ cdef class _LegacyGenerator: st['gauss'] = self._aug_state.gauss return st - def get_state(self): - st = self._basicrng.state - if st['brng'] != 'MT19937': - raise ValueError('get_state only supported for MT19937') - return (st['brng'], st['state']['key'], st['state']['pos'], - self._aug_state.has_gauss, self._aug_state.gauss) - @state.setter def state(self, value): if isinstance(value, (tuple, list)): @@ -206,8 +221,127 @@ cdef class _LegacyGenerator: self._aug_state.has_gauss = value.get('has_gauss', 0) self._basicrng.state = value - def set_state(self, value): - self.state = value + def get_state(self): + """ + get_state() + Return a tuple representing the internal state of the generator. + For more details, see `set_state`. + Returns + ------- + out : tuple(str, ndarray of 624 uints, int, int, float) + The returned tuple has the following items: + 1. the string 'MT19937'. + 2. a 1-D array of 624 unsigned integer keys. + 3. an integer ``pos``. + 4. an integer ``has_gauss``. + 5. a float ``cached_gaussian``. + See Also + -------- + set_state + Notes + ----- + `set_state` and `get_state` are not needed to work with any of the + random distributions in NumPy. If the internal state is manually altered, + the user should know exactly what he/she is doing. + """ + st = self._basicrng.state + if st['brng'] != 'MT19937': + raise RuntimeError('get_state can only be used with the MT19937 ' + 'basic RNG. When using other basic RNGs, ' + 'use `state`.') + st['has_gauss'] = self._aug_state.has_gauss + st['gauss'] = self._aug_state.gauss + + return (st['brng'], st['state']['key'], st['state']['pos'], + st['has_gauss'], st['gauss']) + + def set_state(self, state): + """ + set_state(state) + Set the internal state of the generator from a tuple. + For use if one has reason to manually (re-)set the internal state of the + "Mersenne Twister"[1]_ pseudo-random number generating algorithm. + Parameters + ---------- + state : tuple(str, ndarray of 624 uints, int, int, float) + The `state` tuple has the following items: + 1. the string 'MT19937', specifying the Mersenne Twister algorithm. + 2. a 1-D array of 624 unsigned integers ``keys``. + 3. an integer ``pos``. + 4. an integer ``has_gauss``. + 5. a float ``cached_gaussian``. + Returns + ------- + out : None + Returns 'None' on success. + See Also + -------- + get_state + Notes + ----- + `set_state` and `get_state` are not needed to work with any of the + random distributions in NumPy. If the internal state is manually altered, + the user should know exactly what he/she is doing. + For backwards compatibility, the form (str, array of 624 uints, int) is + also accepted although it is missing some information about the cached + Gaussian value: ``state = ('MT19937', keys, pos)``. + References + ---------- + .. [1] M. Matsumoto and T. Nishimura, "Mersenne Twister: A + 623-dimensionally equidistributed uniform pseudorandom number + generator," *ACM Trans. on Modeling and Computer Simulation*, + Vol. 8, No. 1, pp. 3-30, Jan. 1998. + """ + if not isinstance(state, (tuple, list)): + raise TypeError('state must be a tuple when using set_state. ' + 'Use `state` to set the state using a dictionary.') + if state[0] != 'MT19937': + raise ValueError('set_state can only be used with legacy MT19937' + 'state instances.') + st = {'brng': state[0], + 'state': {'key': state[1], 'pos': state[2]}} + if len(state) > 3: + st['has_gauss'] = state[3] + st['gauss'] = state[4] + self._aug_state.gauss = st.get('gauss', 0.0) + self._aug_state.has_gauss = st.get('has_gauss', 0) + self._basicrng.state = st + + def random_sample(self, size=None): + """ + random_sample(size=None) + Return random floats in the half-open interval [0.0, 1.0). + Results are from the "continuous uniform" distribution over the + stated interval. To sample :math:`Unif[a, b), b > a` multiply + the output of `random_sample` by `(b-a)` and add `a`:: + (b - a) * random_sample() + a + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + Returns + ------- + out : float or ndarray of floats + Array of random floats of shape `size` (unless ``size=None``, in which + case a single float is returned). + Examples + -------- + np.random.random_sample() + 0.47108547995356098 + type(np.random.random_sample()) + + np.random.random_sample((5,)) + array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) + Three-by-two array of random numbers from [-5, 0): + 5 * np.random.random_sample((3, 2)) - 5 + array([[-3.99149989, -0.52338984], + [-2.99091858, -0.79479508], + [-1.23204345, -1.75224494]]) + """ + cdef double temp + return double_fill(&random_double_fill, self._brng, size, self.lock, None) def beta(self, a, b, size=None): """ @@ -336,6 +470,135 @@ cdef class _LegacyGenerator: None, None, CONS_NONE, None) + def randint(self, low, high=None, size=None, dtype=int): + """ + randint(low, high=None, size=None, dtype='l') + Return random integers from `low` (inclusive) to `high` (exclusive). + Return random integers from the "discrete uniform" distribution of + the specified dtype in the "half-open" interval [`low`, `high`). If + `high` is None (the default), then results are from [0, `low`). + Parameters + ---------- + low : int or array-like of ints + Lowest (signed) integers to be drawn from the distribution (unless + ``high=None``, in which case this parameter is one above the + *highest* such integer). + high : int or array-like of ints, optional + If provided, one above the largest (signed) integer to be drawn + from the distribution (see above for behavior if ``high=None``). + If array-like, must contain integer values + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + dtype : {str, dtype}, optional + Desired dtype of the result. All dtypes are determined by their + name, i.e., 'int64', 'int', etc, so byteorder is not available + and a specific precision may have different C types depending + on the platform. The default value is 'np.int'. + .. versionadded:: 1.11.0 + Returns + ------- + out : int or ndarray of ints + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + See Also + -------- + random.random_integers : similar to `randint`, only for the closed + interval [`low`, `high`], and 1 is the lowest value if `high` is + omitted. In particular, this other one is the one to use to generate + uniformly distributed discrete non-integers. + Examples + -------- + >>> randomgen.generator.randint(2, size=10) + array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) # random + >>> randomgen.generator.randint(1, size=10) + array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) # random + Generate a 2 x 4 array of ints between 0 and 4, inclusive: + >>> randomgen.generator.randint(5, size=(2, 4)) + array([[4, 0, 2, 1], # random + [3, 2, 2, 0]]) + Generate a 1 x 3 array with 3 different upper bounds + >>> randomgen.generator.randint(1, [3, 5, 10]) + array([2, 2, 9]) # random + Generate a 1 by 3 array with 3 different lower bounds + >>> randomgen.generator.randint([1, 5, 7], 10) + array([9, 8, 7]) # random + Generate a 2 by 4 array using broadcasting with dtype of uint8 + >>> randomgen.generator.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) + array([[ 8, 6, 9, 7], # random + [ 1, 16, 9, 12]], dtype=uint8) + """ + cdef bint use_masked=1 + + if high is None: + high = low + low = 0 + + key = np.dtype(dtype).name + if not key in _randint_types: + raise TypeError('Unsupported dtype "%s" for randint' % key) + + if key == 'int32': + ret = _rand_int32(low, high, size, use_masked, self._brng, self.lock) + elif key == 'int64': + ret = _rand_int64(low, high, size, use_masked, self._brng, self.lock) + elif key == 'int16': + ret = _rand_int16(low, high, size, use_masked, self._brng, self.lock) + elif key == 'int8': + ret = _rand_int8(low, high, size, use_masked, self._brng, self.lock) + elif key == 'uint64': + ret = _rand_uint64(low, high, size, use_masked, self._brng, self.lock) + elif key == 'uint32': + ret = _rand_uint32(low, high, size, use_masked, self._brng, self.lock) + elif key == 'uint16': + ret = _rand_uint16(low, high, size, use_masked, self._brng, self.lock) + elif key == 'uint8': + ret = _rand_uint8(low, high, size, use_masked, self._brng, self.lock) + elif key == 'bool': + ret = _rand_bool(low, high, size, use_masked, self._brng, self.lock) + + if size is None and dtype in (np.bool, np.int, np.long): + if np.array(ret).shape == (): + return dtype(ret) + return ret + + def rand(self, *args): + """ + rand(d0, d1, ..., dn) + Random values in a given shape. + Create an array of the given shape and populate it with + random samples from a uniform distribution + over ``[0, 1)``. + Parameters + ---------- + d0, d1, ..., dn : int, optional + The dimensions of the returned array, should all be positive. + If no argument is given a single Python float is returned. + Returns + ------- + out : ndarray, shape ``(d0, d1, ..., dn)`` + Random values. + See Also + -------- + random + Notes + ----- + This is a convenience function. If you want an interface that + takes a shape-tuple as the first argument, refer to + np.random.random_sample . + Examples + -------- + >>> np.random.rand(3,2) + array([[ 0.14022471, 0.96360618], #random + [ 0.37601032, 0.25528411], #random + [ 0.49313049, 0.94909878]]) #random + """ + if len(args) == 0: + return self.random_sample() + else: + return self.random_sample(size=args) + def randn(self, *args): """ randn(d0, d1, ..., dn) diff --git a/numpy/random/randomgen/legacy/legacy.py b/numpy/random/randomgen/legacy/legacy.py index cdd9b4c5354f..bb0d0c721475 100644 --- a/numpy/random/randomgen/legacy/legacy.py +++ b/numpy/random/randomgen/legacy/legacy.py @@ -2,7 +2,11 @@ from ..mt19937 import MT19937 from ._legacy import _LegacyGenerator +# Attributes in RandomGenerator that should not appear in LegacyGenerator +_HIDDEN_ATTRIBUTES = ['complex_normal', 'random_raw', 'random_uintegers'] + _LEGACY_ATTRIBUTES = tuple(a for a in dir( + _LegacyGenerator) if not a.startswith('_')) _LEGACY_ATTRIBUTES += ('__getstate__', '__setstate__', '__reduce__') @@ -89,6 +93,9 @@ class LegacyGenerator(with_metaclass(LegacyGeneratorType, RandomGenerator)): 1.6465621229906502 """ + __atttributes = sorted(set(dir(_LegacyGenerator) + + dir(RandomGenerator)).difference(_HIDDEN_ATTRIBUTES)) + def __init__(self, brng=None): if brng is None: brng = MT19937() @@ -100,10 +107,15 @@ def __init__(self, brng=None): self.__legacy = _LegacyGenerator(brng) def __getattribute__(self, name): + if name in _HIDDEN_ATTRIBUTES: + raise AttributeError('No attribute {0}'.format(name)) if name in _LEGACY_ATTRIBUTES: return self.__legacy.__getattribute__(name) return object.__getattribute__(self, name) + def __dir__(self): + return self.__atttributes + # Pickling support: def __getstate__(self): return self.state From 5128c5a04c09e0f0e721a7e0515482b17650741b Mon Sep 17 00:00:00 2001 From: Vrinda Narayan Date: Fri, 29 Mar 2019 19:33:28 +0530 Subject: [PATCH 220/279] Adding an example of successful execution of numpy.test() to the Docs --- doc/source/dev/development_environment.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/source/dev/development_environment.rst b/doc/source/dev/development_environment.rst index f9b438bfd001..445ce320452d 100644 --- a/doc/source/dev/development_environment.rst +++ b/doc/source/dev/development_environment.rst @@ -127,6 +127,9 @@ the interpreter, tests can be run like this:: >>> np.test('full') # Also run tests marked as slow >>> np.test('full', verbose=2) # Additionally print test name/file + An example of a successful test : + ``4686 passed, 362 skipped, 9 xfailed, 5 warnings in 213.99 seconds`` + Or a similar way from the command line:: $ python -c "import numpy as np; np.test()" From e74cbc38bd8511075eaf7af3a7cc6127684a99b0 Mon Sep 17 00:00:00 2001 From: Tyler Reddy Date: Fri, 29 Mar 2019 13:44:16 -0700 Subject: [PATCH 221/279] TST: always publish Azure tests * add Azure configuration directives to ensure that CI test results are always published, even in the case where there are test failures --- azure-pipelines.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 722823b7ff2f..d240e587f739 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -28,9 +28,11 @@ jobs: F77=gfortran-5 F90=gfortran-5 \ CFLAGS='-UNDEBUG -std=c99' python3 runtests.py --mode=full -- -rsx --junitxml=junit/test-results.xml" displayName: 'Run 32-bit Ubuntu Docker Build / Tests' + continueOnError: true - task: PublishTestResults@2 inputs: testResultsFiles: '**/test-*.xml' + failTaskOnFailedTests: false testRunTitle: 'Publish test results for Python 3.6-32 bit full Linux' - job: macOS pool: @@ -99,9 +101,11 @@ jobs: displayName: 'Run Refuide Check' - script: python runtests.py --mode=full -- -rsx --junitxml=junit/test-results.xml displayName: 'Run Full NumPy Test Suite' + continueOnError: true - task: PublishTestResults@2 inputs: testResultsFiles: '**/test-*.xml' + failTaskOnFailedTests: false testRunTitle: 'Publish test results for Python 3.6 64-bit full Mac OS' - job: Windows pool: @@ -200,7 +204,9 @@ jobs: displayName: 'For gh-12667; Windows DLL resolution' - script: python runtests.py -n --show-build-log --mode=$(TEST_MODE) -- -rsx --junitxml=junit/test-results.xml displayName: 'Run NumPy Test Suite' + continueOnError: true - task: PublishTestResults@2 inputs: testResultsFiles: '**/test-*.xml' + failTaskOnFailedTests: false testRunTitle: 'Publish test results for Python $(PYTHON_VERSION) $(BITS)-bit $(TEST_MODE) Windows' From bea6946b607ec53d20f3cf82b0504a343285b45c Mon Sep 17 00:00:00 2001 From: Christopher Whelan Date: Thu, 28 Mar 2019 20:30:26 -0700 Subject: [PATCH 222/279] MAINT: cleanup of fast_loop_macros.h --- numpy/core/src/umath/fast_loop_macros.h | 122 +++++++++++++----------- numpy/core/src/umath/loops.c.src | 4 +- 2 files changed, 67 insertions(+), 59 deletions(-) diff --git a/numpy/core/src/umath/fast_loop_macros.h b/numpy/core/src/umath/fast_loop_macros.h index e3cfa1f726d0..bab126b45042 100644 --- a/numpy/core/src/umath/fast_loop_macros.h +++ b/numpy/core/src/umath/fast_loop_macros.h @@ -74,10 +74,12 @@ #define IS_BINARY_CONT(tin, tout) (steps[0] == sizeof(tin) && \ steps[1] == sizeof(tin) && \ steps[2] == sizeof(tout)) + /* binary loop input and output contiguous with first scalar */ #define IS_BINARY_CONT_S1(tin, tout) (steps[0] == 0 && \ steps[1] == sizeof(tin) && \ steps[2] == sizeof(tout)) + /* binary loop input and output contiguous with second scalar */ #define IS_BINARY_CONT_S2(tin, tout) (steps[0] == sizeof(tin) && \ steps[1] == 0 && \ @@ -86,61 +88,63 @@ /* * loop with contiguous specialization - * op should be the code storing the result in `tout * out` + * val should be the value to be stored in `tout *out` * combine with NPY_GCC_OPT_3 to allow autovectorization * should only be used where its worthwhile to avoid code bloat */ -#define BASE_OUTPUT_LOOP(tout, op) \ +#define BASE_OUTPUT_LOOP(tout, val) \ OUTPUT_LOOP { \ - tout * out = (tout *)op1; \ - op; \ + tout *out = (tout *)op1; \ + *out = val; \ } -#define OUTPUT_LOOP_FAST(tout, op) \ + +#define OUTPUT_LOOP_FAST(tout, val) \ do { \ - /* condition allows compiler to optimize the generic macro */ \ - if (IS_OUTPUT_CONT(tout)) { \ - BASE_OUTPUT_LOOP(tout, op) \ - } \ - else { \ - BASE_OUTPUT_LOOP(tout, op) \ - } \ + /* condition allows compiler to optimize the generic macro */ \ + if (IS_OUTPUT_CONT(tout)) { \ + BASE_OUTPUT_LOOP(tout, val) \ + } \ + else { \ + BASE_OUTPUT_LOOP(tout, val) \ + } \ } \ while (0) /* * loop with contiguous specialization * op should be the code working on `tin in` and - * storing the result in `tout * out` + * storing the result in `tout *out` * combine with NPY_GCC_OPT_3 to allow autovectorization * should only be used where its worthwhile to avoid code bloat */ #define BASE_UNARY_LOOP(tin, tout, op) \ UNARY_LOOP { \ const tin in = *(tin *)ip1; \ - tout * out = (tout *)op1; \ + tout *out = (tout *)op1; \ op; \ } -#define UNARY_LOOP_FAST(tin, tout, op) \ + +#define UNARY_LOOP_FAST(tin, tout, op) \ do { \ - /* condition allows compiler to optimize the generic macro */ \ - if (IS_UNARY_CONT(tin, tout)) { \ - if (args[0] == args[1]) { \ - BASE_UNARY_LOOP(tin, tout, op) \ + /* condition allows compiler to optimize the generic macro */ \ + if (IS_UNARY_CONT(tin, tout)) { \ + if (args[0] == args[1]) { \ + BASE_UNARY_LOOP(tin, tout, op) \ + } \ + else { \ + BASE_UNARY_LOOP(tin, tout, op) \ + } \ } \ else { \ BASE_UNARY_LOOP(tin, tout, op) \ } \ } \ - else { \ - BASE_UNARY_LOOP(tin, tout, op) \ - } \ - } \ while (0) /* * loop with contiguous specialization * op should be the code working on `tin in1`, `tin in2` and - * storing the result in `tout * out` + * storing the result in `tout *out` * combine with NPY_GCC_OPT_3 to allow autovectorization * should only be used where its worthwhile to avoid code bloat */ @@ -148,9 +152,10 @@ BINARY_LOOP { \ const tin in1 = *(tin *)ip1; \ const tin in2 = *(tin *)ip2; \ - tout * out = (tout *)op1; \ + tout *out = (tout *)op1; \ op; \ } + /* * unfortunately gcc 6/7 regressed and we need to give it additional hints to * vectorize inplace operations (PR80198) @@ -171,59 +176,62 @@ for(i = 0; i < n; i++, ip1 += is1, ip2 += is2, op1 += os1) { \ const tin in1 = *(tin *)ip1; \ const tin in2 = *(tin *)ip2; \ - tout * out = (tout *)op1; \ + tout *out = (tout *)op1; \ op; \ } + #define BASE_BINARY_LOOP_S(tin, tout, cin, cinp, vin, vinp, op) \ const tin cin = *(tin *)cinp; \ BINARY_LOOP { \ const tin vin = *(tin *)vinp; \ - tout * out = (tout *)op1; \ + tout *out = (tout *)op1; \ op; \ } + /* PR80198 again, scalar works without the pragma */ #define BASE_BINARY_LOOP_S_INP(tin, tout, cin, cinp, vin, vinp, op) \ const tin cin = *(tin *)cinp; \ BINARY_LOOP { \ const tin vin = *(tin *)vinp; \ - tout * out = (tout *)vinp; \ + tout *out = (tout *)vinp; \ op; \ } -#define BINARY_LOOP_FAST(tin, tout, op) \ + +#define BINARY_LOOP_FAST(tin, tout, op) \ do { \ - /* condition allows compiler to optimize the generic macro */ \ - if (IS_BINARY_CONT(tin, tout)) { \ - if (abs_ptrdiff(args[2], args[0]) == 0 && \ - abs_ptrdiff(args[2], args[1]) >= NPY_MAX_SIMD_SIZE) { \ - BASE_BINARY_LOOP_INP(tin, tout, op) \ + /* condition allows compiler to optimize the generic macro */ \ + if (IS_BINARY_CONT(tin, tout)) { \ + if (abs_ptrdiff(args[2], args[0]) == 0 && \ + abs_ptrdiff(args[2], args[1]) >= NPY_MAX_SIMD_SIZE) { \ + BASE_BINARY_LOOP_INP(tin, tout, op) \ + } \ + else if (abs_ptrdiff(args[2], args[1]) == 0 && \ + abs_ptrdiff(args[2], args[0]) >= NPY_MAX_SIMD_SIZE) { \ + BASE_BINARY_LOOP_INP(tin, tout, op) \ + } \ + else { \ + BASE_BINARY_LOOP(tin, tout, op) \ + } \ } \ - else if (abs_ptrdiff(args[2], args[1]) == 0 && \ - abs_ptrdiff(args[2], args[0]) >= NPY_MAX_SIMD_SIZE) { \ - BASE_BINARY_LOOP_INP(tin, tout, op) \ + else if (IS_BINARY_CONT_S1(tin, tout)) { \ + if (abs_ptrdiff(args[2], args[1]) == 0) { \ + BASE_BINARY_LOOP_S_INP(tin, tout, in1, args[0], in2, ip2, op) \ + } \ + else { \ + BASE_BINARY_LOOP_S(tin, tout, in1, args[0], in2, ip2, op) \ + } \ } \ - else { \ - BASE_BINARY_LOOP(tin, tout, op) \ - } \ - } \ - else if (IS_BINARY_CONT_S1(tin, tout)) { \ - if (abs_ptrdiff(args[2], args[1]) == 0) { \ - BASE_BINARY_LOOP_S_INP(tin, tout, in1, args[0], in2, ip2, op) \ + else if (IS_BINARY_CONT_S2(tin, tout)) { \ + if (abs_ptrdiff(args[2], args[0]) == 0) { \ + BASE_BINARY_LOOP_S_INP(tin, tout, in2, args[1], in1, ip1, op) \ + } \ + else { \ + BASE_BINARY_LOOP_S(tin, tout, in2, args[1], in1, ip1, op) \ + }\ } \ else { \ - BASE_BINARY_LOOP_S(tin, tout, in1, args[0], in2, ip2, op) \ - } \ - } \ - else if (IS_BINARY_CONT_S2(tin, tout)) { \ - if (abs_ptrdiff(args[2], args[0]) == 0) { \ - BASE_BINARY_LOOP_S_INP(tin, tout, in2, args[1], in1, ip1, op) \ + BASE_BINARY_LOOP(tin, tout, op) \ } \ - else { \ - BASE_BINARY_LOOP_S(tin, tout, in2, args[1], in1, ip1, op) \ - }\ - } \ - else { \ - BASE_BINARY_LOOP(tin, tout, op) \ - } \ } \ while (0) diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index 1e4ab350bec9..b7e28537a8aa 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -652,7 +652,7 @@ BOOL__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UN NPY_NO_EXPORT void BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { - OUTPUT_LOOP_FAST(npy_bool, *out = @val@); + OUTPUT_LOOP_FAST(npy_bool, @val@); } /**end repeat**/ @@ -896,7 +896,7 @@ NPY_NO_EXPORT void NPY_NO_EXPORT void @TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { - OUTPUT_LOOP_FAST(npy_bool, *out = @val@); + OUTPUT_LOOP_FAST(npy_bool, @val@); } /**end repeat1**/ From 838abd75b5f3109e02c1834d15e47f0bc65e2129 Mon Sep 17 00:00:00 2001 From: Christopher Whelan Date: Thu, 28 Mar 2019 22:47:32 -0700 Subject: [PATCH 223/279] MAINT: remove OUTPUT_LOOP_FAST macro and use UNARY_LOOP_FAST instead --- numpy/core/src/umath/fast_loop_macros.h | 25 ------------------------- numpy/core/src/umath/loops.c.src | 12 ++++++++++-- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/numpy/core/src/umath/fast_loop_macros.h b/numpy/core/src/umath/fast_loop_macros.h index bab126b45042..7a1ed66bc94f 100644 --- a/numpy/core/src/umath/fast_loop_macros.h +++ b/numpy/core/src/umath/fast_loop_macros.h @@ -85,31 +85,6 @@ steps[1] == 0 && \ steps[2] == sizeof(tout)) - -/* - * loop with contiguous specialization - * val should be the value to be stored in `tout *out` - * combine with NPY_GCC_OPT_3 to allow autovectorization - * should only be used where its worthwhile to avoid code bloat - */ -#define BASE_OUTPUT_LOOP(tout, val) \ - OUTPUT_LOOP { \ - tout *out = (tout *)op1; \ - *out = val; \ - } - -#define OUTPUT_LOOP_FAST(tout, val) \ - do { \ - /* condition allows compiler to optimize the generic macro */ \ - if (IS_OUTPUT_CONT(tout)) { \ - BASE_OUTPUT_LOOP(tout, val) \ - } \ - else { \ - BASE_OUTPUT_LOOP(tout, val) \ - } \ - } \ - while (0) - /* * loop with contiguous specialization * op should be the code working on `tin in` and diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index b7e28537a8aa..abfd883f7cf4 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -652,7 +652,11 @@ BOOL__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UN NPY_NO_EXPORT void BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { - OUTPUT_LOOP_FAST(npy_bool, @val@); + /* + * The (void)in; suppresses an unused variable warning raised by gcc and allows + * us to re-use this macro even though we do not depend on in + */ + UNARY_LOOP_FAST(npy_bool, npy_bool, (void)in; *out = @val@); } /**end repeat**/ @@ -896,7 +900,11 @@ NPY_NO_EXPORT void NPY_NO_EXPORT void @TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { - OUTPUT_LOOP_FAST(npy_bool, @val@); + /* + * The (void)in; suppresses an unused variable warning raised by gcc and allows + * us to re-use this macro even though we do not depend on in + */ + UNARY_LOOP_FAST(@type@, npy_bool, (void)in; *out = @val@); } /**end repeat1**/ From 4b1d5cbf24174b1ed96824e706f74c84841633bc Mon Sep 17 00:00:00 2001 From: kikocorreoso Date: Sat, 30 Mar 2019 16:47:40 +0100 Subject: [PATCH 224/279] address comments on #9355 --- numpy/lib/tests/test_type_check.py | 42 +++++++++++++++++++++++++++ numpy/lib/type_check.py | 46 ++++++++++++++++++++++++------ 2 files changed, 79 insertions(+), 9 deletions(-) diff --git a/numpy/lib/tests/test_type_check.py b/numpy/lib/tests/test_type_check.py index 2982ca31a3c2..1a6af3b6c070 100644 --- a/numpy/lib/tests/test_type_check.py +++ b/numpy/lib/tests/test_type_check.py @@ -360,6 +360,15 @@ def test_generic(self): assert_(vals[1] == 0) assert_all(vals[2] > 1e10) and assert_all(np.isfinite(vals[2])) assert_equal(type(vals), np.ndarray) + + # perform the same tests but with nan, posinf and neginf keywords + with np.errstate(divide='ignore', invalid='ignore'): + vals = nan_to_num(np.array((-1., 0, 1))/0., + nan=10, posinf=20, neginf=30) + assert_all(vals[0] == 30) and assert_all(np.isfinite(vals[0])) + assert_(vals[1] == 10) + assert_all(vals[2] == 20) and assert_all(np.isfinite(vals[2])) + assert_equal(type(vals), np.ndarray) # perform the same test but in-place with np.errstate(divide='ignore', invalid='ignore'): @@ -371,26 +380,49 @@ def test_generic(self): assert_(vals[1] == 0) assert_all(vals[2] > 1e10) and assert_all(np.isfinite(vals[2])) assert_equal(type(vals), np.ndarray) + + # perform the same test but in-place + with np.errstate(divide='ignore', invalid='ignore'): + vals = np.array((-1., 0, 1))/0. + result = nan_to_num(vals, copy=False, nan=10, posinf=20, neginf=30) + + assert_(result is vals) + assert_all(vals[0] == 30) and assert_all(np.isfinite(vals[0])) + assert_(vals[1] == 10) + assert_all(vals[2] == 20) and assert_all(np.isfinite(vals[2])) + assert_equal(type(vals), np.ndarray) def test_array(self): vals = nan_to_num([1]) assert_array_equal(vals, np.array([1], int)) assert_equal(type(vals), np.ndarray) + vals = nan_to_num([1], nan=10, posinf=20, neginf=30) + assert_array_equal(vals, np.array([1], int)) + assert_equal(type(vals), np.ndarray) def test_integer(self): vals = nan_to_num(1) assert_all(vals == 1) assert_equal(type(vals), np.int_) + vals = nan_to_num(1, nan=10, posinf=20, neginf=30) + assert_all(vals == 1) + assert_equal(type(vals), np.int_) def test_float(self): vals = nan_to_num(1.0) assert_all(vals == 1.0) assert_equal(type(vals), np.float_) + vals = nan_to_num(1.1, nan=10, posinf=20, neginf=30) + assert_all(vals == 1.1) + assert_equal(type(vals), np.float_) def test_complex_good(self): vals = nan_to_num(1+1j) assert_all(vals == 1+1j) assert_equal(type(vals), np.complex_) + vals = nan_to_num(1+1j, nan=10, posinf=20, neginf=30) + assert_all(vals == 1+1j) + assert_equal(type(vals), np.complex_) def test_complex_bad(self): with np.errstate(divide='ignore', invalid='ignore'): @@ -414,6 +446,16 @@ def test_complex_bad2(self): # !! inf. Comment out for now, and see if it # !! changes #assert_all(vals.real < -1e10) and assert_all(np.isfinite(vals)) + + def test_do_not_rewrite__previous_keyword(self): + # This is done to test that when, for instance, nan=np.inf then these + # values are not rewritten by posinf keyword to the posinf value. + with np.errstate(divide='ignore', invalid='ignore'): + vals = nan_to_num(np.array((-1., 0, 1))/0., nan=np.inf, posinf=999) + assert_all(vals[0] < -1e10) and assert_all(np.isfinite(vals[0])) + assert_(vals[1] == np.inf) + assert_all(vals[2] == 999) and assert_all(np.isfinite(vals[2])) + assert_equal(type(vals), np.ndarray) class TestRealIfClose(object): diff --git a/numpy/lib/type_check.py b/numpy/lib/type_check.py index f55517732d0a..2b254b6c084d 100644 --- a/numpy/lib/type_check.py +++ b/numpy/lib/type_check.py @@ -363,18 +363,23 @@ def _getmaxmin(t): return f.max, f.min -def _nan_to_num_dispatcher(x, copy=None): +def _nan_to_num_dispatcher(x, copy=None, nan=None, posinf=None, neginf=None): return (x,) @array_function_dispatch(_nan_to_num_dispatcher) -def nan_to_num(x, copy=True): +def nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None): """ - Replace NaN with zero and infinity with large finite numbers. + Replace NaN with zero and infinity with large finite numbers (default + behaviour) or with the numbers defined by the user using the `nan`, + `posinf` and/or `neginf` keywords. - If `x` is inexact, NaN is replaced by zero, and infinity and -infinity - replaced by the respectively largest and most negative finite floating - point values representable by ``x.dtype``. + If `x` is inexact, NaN is replaced by zero or by the user defined value in + `nan` keyword, infinity is replaced by the largest finite floating point + values representable by ``x.dtype`` or by the user defined value in + `posinf` keyword and -infinity is replaced by the most negative finite + floating point values representable by ``x.dtype`` or by the user defined + value in `neginf` keyword. For complex dtypes, the above is applied to each of the real and imaginary components of `x` separately. @@ -390,6 +395,17 @@ def nan_to_num(x, copy=True): in-place (False). The in-place operation only occurs if casting to an array does not require a copy. Default is True. + nan : int, float, optional + Value to be used to fill NaN values. If no value is passed + then NaN values will be replaced with 0.0. + posinf : int, float, optional + Value to be used to fill positive infinity values. If no value is + passed then positive infinity values will be replaced with a very + large number. + neginf : int, float, optional + Value to be used to fill negative infinity values. If no value is + passed then negative infinity values will be replaced with a very + small (or negative) number. .. versionadded:: 1.13 @@ -424,6 +440,9 @@ def nan_to_num(x, copy=True): >>> np.nan_to_num(x) array([ 1.79769313e+308, -1.79769313e+308, 0.00000000e+000, # may vary -1.28000000e+002, 1.28000000e+002]) + >>> np.nan_to_num(x, nan=-9999, posinf=33333333, neginf=33333333) + array([ 3.3333333e+07, 3.3333333e+07, -9.9990000e+03, + -1.2800000e+02, 1.2800000e+02]) >>> y = np.array([complex(np.inf, np.nan), np.nan, complex(np.nan, np.inf)]) array([ 1.79769313e+308, -1.79769313e+308, 0.00000000e+000, # may vary -1.28000000e+002, 1.28000000e+002]) @@ -431,6 +450,8 @@ def nan_to_num(x, copy=True): array([ 1.79769313e+308 +0.00000000e+000j, # may vary 0.00000000e+000 +0.00000000e+000j, 0.00000000e+000 +1.79769313e+308j]) + >>> np.nan_to_num(y, nan=111111, posinf=222222) + array([222222.+111111.j, 111111. +0.j, 111111.+222222.j]) """ x = _nx.array(x, subok=True, copy=copy) xtype = x.dtype.type @@ -444,10 +465,17 @@ def nan_to_num(x, copy=True): dest = (x.real, x.imag) if iscomplex else (x,) maxf, minf = _getmaxmin(x.real.dtype) + if posinf is not None: + maxf = posinf + if neginf is not None: + minf = neginf for d in dest: - _nx.copyto(d, 0.0, where=isnan(d)) - _nx.copyto(d, maxf, where=isposinf(d)) - _nx.copyto(d, minf, where=isneginf(d)) + idx_nan = isnan(d) + idx_posinf = isposinf(d) + idx_neginf = isneginf(d) + _nx.copyto(d, nan, where=idx_nan) + _nx.copyto(d, maxf, where=idx_posinf) + _nx.copyto(d, minf, where=idx_neginf) return x[()] if isscalar else x #----------------------------------------------------------------------------- From 46852796a13ac1ecc35b6312b73e885fb7517879 Mon Sep 17 00:00:00 2001 From: Valentin Haenel Date: Sat, 30 Mar 2019 21:40:57 +0100 Subject: [PATCH 225/279] ENH: Improve error message for np.repeat `np.repeat` can take an array of numbers as value for it's `repeat` argument. The error message if one of these is negative is `count < 0`. The first time I encountered this, I did not understand the error since this message is somewhat cryptic and uninformtiave. Replace it by something better and more explicit. --- numpy/core/src/multiarray/item_selection.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/numpy/core/src/multiarray/item_selection.c b/numpy/core/src/multiarray/item_selection.c index ff7c1130a9c1..6065c1df44d4 100644 --- a/numpy/core/src/multiarray/item_selection.c +++ b/numpy/core/src/multiarray/item_selection.c @@ -607,7 +607,8 @@ PyArray_Repeat(PyArrayObject *aop, PyObject *op, int axis) else { for (j = 0; j < n; j++) { if (counts[j] < 0) { - PyErr_SetString(PyExc_ValueError, "count < 0"); + PyErr_SetString(PyExc_ValueError, + "repeats may not contain negative values."); goto fail; } total += counts[j]; From ad885aedf8c9da9e52be08d1ab9b6b8dfa0f5667 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 31 Mar 2019 08:14:58 +0100 Subject: [PATCH 226/279] DOC: Fix small issues in mtrand doc strings Remove overly long underscore Remove trailing whitespace --- numpy/random/mtrand/mtrand.pyx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx index 2426dbaa475f..f49299f5587e 100644 --- a/numpy/random/mtrand/mtrand.pyx +++ b/numpy/random/mtrand/mtrand.pyx @@ -992,7 +992,7 @@ cdef class RandomState: raise ValueError("high is out of bounds for %s" % dtype) if ilow >= ihigh and np.prod(size) != 0: raise ValueError("Range cannot be empty (low >= high) unless no samples are taken") - + with self.lock: ret = randfunc(ilow, ihigh - 1, size, self.state_address) @@ -1040,7 +1040,7 @@ cdef class RandomState: .. versionadded:: 1.7.0 Parameters - ----------- + ---------- a : 1-D array-like or int If an ndarray, a random sample is generated from its elements. If an int, the random sample is generated as if a were np.arange(a) @@ -4706,7 +4706,7 @@ cdef class RandomState: Draw `size` samples of dimension k from a Dirichlet distribution. A Dirichlet-distributed random variable can be seen as a multivariate generalization of a Beta distribution. The Dirichlet distribution - is a conjugate prior of a multinomial distribution in Bayesian + is a conjugate prior of a multinomial distribution in Bayesian inference. Parameters @@ -4732,22 +4732,22 @@ cdef class RandomState: Notes ----- - The Dirichlet distribution is a distribution over vectors - :math:`x` that fulfil the conditions :math:`x_i>0` and + The Dirichlet distribution is a distribution over vectors + :math:`x` that fulfil the conditions :math:`x_i>0` and :math:`\\sum_{i=1}^k x_i = 1`. - The probability density function :math:`p` of a - Dirichlet-distributed random vector :math:`X` is + The probability density function :math:`p` of a + Dirichlet-distributed random vector :math:`X` is proportional to .. math:: p(x) \\propto \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i}, - where :math:`\\alpha` is a vector containing the positive + where :math:`\\alpha` is a vector containing the positive concentration parameters. The method uses the following property for computation: let :math:`Y` - be a random vector which has components that follow a standard gamma - distribution, then :math:`X = \\frac{1}{\\sum_{i=1}^k{Y_i}} Y` + be a random vector which has components that follow a standard gamma + distribution, then :math:`X = \\frac{1}{\\sum_{i=1}^k{Y_i}} Y` is Dirichlet-distributed References @@ -4962,7 +4962,7 @@ cdef class RandomState: return arr arr = np.asarray(x) - + # shuffle has fast-path for 1-d if arr.ndim == 1: # Return a copy if same memory @@ -4975,7 +4975,7 @@ cdef class RandomState: idx = np.arange(arr.shape[0], dtype=np.intp) self.shuffle(idx) return arr[idx] - + _rand = RandomState() seed = _rand.seed From ba96ca5f1f96477a20357904ffde969261233dc8 Mon Sep 17 00:00:00 2001 From: mattip Date: Sun, 31 Mar 2019 00:12:25 +0300 Subject: [PATCH 227/279] BUG: fix doctests --- numpy/random/randomgen/legacy/_legacy.pyx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/numpy/random/randomgen/legacy/_legacy.pyx b/numpy/random/randomgen/legacy/_legacy.pyx index b3b8af0cf5ca..1b2168374a10 100644 --- a/numpy/random/randomgen/legacy/_legacy.pyx +++ b/numpy/random/randomgen/legacy/_legacy.pyx @@ -510,22 +510,22 @@ cdef class _LegacyGenerator: uniformly distributed discrete non-integers. Examples -------- - >>> randomgen.generator.randint(2, size=10) + >>> np.random.randint(2, size=10) array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) # random - >>> randomgen.generator.randint(1, size=10) + >>> np.random.randint(1, size=10) array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) # random Generate a 2 x 4 array of ints between 0 and 4, inclusive: - >>> randomgen.generator.randint(5, size=(2, 4)) + >>> np.random.randint(5, size=(2, 4)) array([[4, 0, 2, 1], # random [3, 2, 2, 0]]) Generate a 1 x 3 array with 3 different upper bounds - >>> randomgen.generator.randint(1, [3, 5, 10]) + >>> np.random.randint(1, [3, 5, 10]) array([2, 2, 9]) # random Generate a 1 by 3 array with 3 different lower bounds - >>> randomgen.generator.randint([1, 5, 7], 10) + >>> np.random.randint([1, 5, 7], 10) array([9, 8, 7]) # random Generate a 2 by 4 array using broadcasting with dtype of uint8 - >>> randomgen.generator.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) + >>> np.random.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) array([[ 8, 6, 9, 7], # random [ 1, 16, 9, 12]], dtype=uint8) """ @@ -2055,7 +2055,7 @@ cdef class _LegacyGenerator: standard deviation: >>> list((x[0,0,:] - mean) < 0.6) - [True, True] + [True, True] # random """ from numpy.dual import svd From f297d317f9d2355228fb3a265e9ff3c69e37b1e2 Mon Sep 17 00:00:00 2001 From: Chirag Nighut Date: Mon, 1 Apr 2019 19:19:09 +0530 Subject: [PATCH 228/279] BUG: Fix of `var` method for complex object arrays Previously, an object array which contained complex numbers would give complex output, as it was simply multiplied with itself instead of with its conjugate. --- numpy/core/_methods.py | 7 ++++--- numpy/core/tests/test_numeric.py | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/numpy/core/_methods.py b/numpy/core/_methods.py index 51362c7614ee..953e7e1b84c2 100644 --- a/numpy/core/_methods.py +++ b/numpy/core/_methods.py @@ -115,10 +115,11 @@ def _var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False): # Note that x may not be inexact and that we need it to be an array, # not a scalar. x = asanyarray(arr - arrmean) - if issubclass(arr.dtype.type, nt.complexfloating): - x = um.multiply(x, um.conjugate(x), out=x).real - else: + if issubclass(arr.dtype.type, (nt.floating, nt.integer)): x = um.multiply(x, x, out=x) + else: + x = um.multiply(x, um.conjugate(x), out=x).real + ret = umr_sum(x, axis, dtype, out, keepdims) # Compute degrees of freedom and make sure it is not negative. diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 90ac43a56dc0..1822a7adf72b 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -216,6 +216,9 @@ def test_var(self): assert_(np.isnan(np.var([]))) assert_(w[0].category is RuntimeWarning) + B = np.array([None, 0]) + B[0] = 1j + assert_almost_equal(np.var(B), 0.25) class TestIsscalar(object): def test_isscalar(self): From a8844501f5371b9c38f6a8328a346104790a6815 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 1 Apr 2019 13:45:48 +0100 Subject: [PATCH 229/279] MAINT: Sync with randomgen changes Synchronize with changes in randomgen --- numpy/random/__init__.py | 4 +- numpy/random/randomgen/__init__.py | 5 +- numpy/random/randomgen/_pickle.py | 38 +- .../random/randomgen/bounded_integers.pxd.in | 13 +- .../random/randomgen/bounded_integers.pyx.in | 17 +- numpy/random/randomgen/common.pxd | 14 +- numpy/random/randomgen/common.pyx | 203 +- numpy/random/randomgen/distributions.pxd | 8 +- numpy/random/randomgen/dsfmt.pyx | 120 +- numpy/random/randomgen/entropy.pyx | 7 +- .../randomgen/examples/cython/extending.pyx | 10 +- .../cython/extending_distributions.pyx | 37 +- .../randomgen/examples/numba/extending.py | 2 +- numpy/random/randomgen/generator.pyx | 440 +- numpy/random/randomgen/legacy/__init__.py | 2 +- numpy/random/randomgen/legacy/_legacy.pyx | 2263 --------- numpy/random/randomgen/legacy/legacy.py | 130 - .../randomgen/legacy/legacy_distributions.pxd | 4 +- numpy/random/randomgen/mt19937.pyx | 103 +- numpy/random/randomgen/mtrand.pyx | 4172 +++++++++++++++++ numpy/random/randomgen/pcg32.pyx | 102 +- numpy/random/randomgen/pcg64.pyx | 104 +- numpy/random/randomgen/philox.pyx | 107 +- numpy/random/randomgen/setup.py | 22 +- .../src/distributions/distributions.c | 3 + numpy/random/randomgen/src/pcg32/pcg32.h | 4 + numpy/random/randomgen/src/pcg64/pcg64.h | 4 +- .../randomgen/tests/test_against_numpy.py | 55 +- numpy/random/randomgen/tests/test_direct.py | 191 +- numpy/random/randomgen/tests/test_legacy.py | 17 - .../randomgen/tests/test_numpy_mt19937.py | 499 +- .../randomgen/tests/test_randomstate.py | 1808 +++++++ .../tests/test_randomstate_regression.py | 157 + numpy/random/randomgen/tests/test_smoke.py | 38 +- numpy/random/randomgen/threefry.pyx | 104 +- numpy/random/randomgen/threefry32.pyx | 102 +- numpy/random/randomgen/xoroshiro128.pyx | 102 +- numpy/random/randomgen/xorshift1024.pyx | 105 +- numpy/random/randomgen/xoshiro256starstar.pyx | 103 +- numpy/random/randomgen/xoshiro512starstar.pyx | 101 +- 40 files changed, 7590 insertions(+), 3730 deletions(-) delete mode 100644 numpy/random/randomgen/legacy/_legacy.pyx delete mode 100644 numpy/random/randomgen/legacy/legacy.py create mode 100644 numpy/random/randomgen/mtrand.pyx delete mode 100644 numpy/random/randomgen/tests/test_legacy.py create mode 100644 numpy/random/randomgen/tests/test_randomstate.py create mode 100644 numpy/random/randomgen/tests/test_randomstate_regression.py diff --git a/numpy/random/__init__.py b/numpy/random/__init__.py index 818ece58aba2..b5ff1cfcab4b 100644 --- a/numpy/random/__init__.py +++ b/numpy/random/__init__.py @@ -137,7 +137,7 @@ ] # from .mtrand import * -from .randomgen.legacy import LegacyGenerator as RandomState +from .randomgen.mtrand import RandomState mtrand = RandomState() for _x in dir(mtrand): if _x[0] != '_' and _x not in ('poisson_lam_max', 'state'): @@ -145,7 +145,7 @@ del _x # Some aliases: -ranf = random = sample = random_sample +ranf = random = sample = mtrand.random_sample __all__.extend(['ranf', 'random', 'sample']) def __RandomState_ctor(): diff --git a/numpy/random/randomgen/__init__.py b/numpy/random/randomgen/__init__.py index 2a4e20bbc43a..1af2fc3b200c 100644 --- a/numpy/random/randomgen/__init__.py +++ b/numpy/random/randomgen/__init__.py @@ -10,11 +10,10 @@ from .xorshift1024 import Xorshift1024 from .xoshiro256starstar import Xoshiro256StarStar from .xoshiro512starstar import Xoshiro512StarStar - +from .mtrand import RandomState __all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'PCG32', 'Philox', 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024', - 'Xoshiro256StarStar', 'Xoshiro512StarStar', - 'hypergeometric', 'multinomial', 'random_sample'] + 'Xoshiro256StarStar', 'Xoshiro512StarStar', 'RandomState'] #from ._version import get_versions diff --git a/numpy/random/randomgen/_pickle.py b/numpy/random/randomgen/_pickle.py index b192bc8a4b1f..bcfc00402dee 100644 --- a/numpy/random/randomgen/_pickle.py +++ b/numpy/random/randomgen/_pickle.py @@ -10,7 +10,7 @@ from .xorshift1024 import Xorshift1024 from .xoshiro256starstar import Xoshiro256StarStar from .xoshiro512starstar import Xoshiro512StarStar -from .legacy import LegacyGenerator +from .mtrand import RandomState BasicRNGS = {'MT19937': MT19937, 'DSFMT': DSFMT, @@ -78,9 +78,9 @@ def __brng_ctor(brng_name='mt19937'): return brng() -def __legacy_ctor(brng_name='mt19937'): +def __randomstate_ctor(brng_name='mt19937'): """ - Pickling helper function that returns a LegacyGenerator object + Pickling helper function that returns a legacy RandomState-like object Parameters ---------- @@ -89,8 +89,8 @@ def __legacy_ctor(brng_name='mt19937'): Returns ------- - lg: LegacyGenerator - LegacyGenerator using the named core BasicRNG + rs: RandomState + Legacy RandomState using the named core BasicRNG """ try: brng_name = brng_name.decode('ascii') @@ -101,30 +101,4 @@ def __legacy_ctor(brng_name='mt19937'): else: raise ValueError(str(brng_name) + ' is not a known BasicRNG module.') - return LegacyGenerator(brng()) - - -def _experiment_ctor(brng_name='mt19937'): - """ - Pickling helper function that returns a LegacyGenerator object - - Parameters - ---------- - brng_name: str - String containing the name of the Basic RNG - - Returns - ------- - brng: BasicRNG - Basic RNG instance - """ - try: - brng_name = brng_name.decode('ascii') - except AttributeError: - pass - if brng_name in BasicRNGS: - brng = BasicRNGS[brng_name] - else: - raise ValueError(str(brng_name) + ' is not a known BasicRNG module.') - - return LegacyGenerator(brng()) + return RandomState(brng()) diff --git a/numpy/random/randomgen/bounded_integers.pxd.in b/numpy/random/randomgen/bounded_integers.pxd.in index 41bf1a178923..50df0c7897cf 100644 --- a/numpy/random/randomgen/bounded_integers.pxd.in +++ b/numpy/random/randomgen/bounded_integers.pxd.in @@ -3,22 +3,11 @@ from __future__ import absolute_import from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t) import numpy as np -cimport numpy as np +cimport numpy as np ctypedef np.npy_bool bool_t from .common cimport brng_t -_randint_types = {'bool': (0, 2), - 'int8': (-2**7, 2**7), - 'int16': (-2**15, 2**15), - 'int32': (-2**31, 2**31), - 'int64': (-2**63, 2**63), - 'uint8': (0, 2**8), - 'uint16': (0, 2**16), - 'uint32': (0, 2**32), - 'uint64': (0, 2**64) - } - cdef inline uint64_t _gen_mask(uint64_t max_val) nogil: """Mask generator for use in bounded random numbers""" # Smallest bit mask >= max diff --git a/numpy/random/randomgen/bounded_integers.pyx.in b/numpy/random/randomgen/bounded_integers.pyx.in index d66f09c42d4d..56d558b14175 100644 --- a/numpy/random/randomgen/bounded_integers.pyx.in +++ b/numpy/random/randomgen/bounded_integers.pyx.in @@ -9,6 +9,15 @@ from .distributions cimport * np.import_array() +_randint_types = {'bool': (0, 2), + 'int8': (-2**7, 2**7), + 'int16': (-2**15, 2**15), + 'int32': (-2**31, 2**31), + 'int64': (-2**63, 2**63), + 'uint8': (0, 2**8), + 'uint16': (0, 2**16), + 'uint32': (0, 2**32), + 'uint64': (0, 2**64)} {{ py: type_info = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000ULL'), @@ -21,7 +30,6 @@ type_info = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000U )}} {{for nptype, utype, nptype_up, npctype, remaining, bitshift, lb, ub in type_info}} {{ py: otype = nptype + '_' if nptype == 'bool' else nptype }} - cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object size, bint use_masked, brng_t *state, object lock): @@ -42,7 +50,6 @@ cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object s cdef np.broadcast it cdef int buf_rem = 0 - # Array path low_arr = low high_arr = high @@ -83,7 +90,6 @@ cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object s np.PyArray_MultiIter_NEXT(it) return out_arr {{endfor}} - {{ py: big_type_info = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFFFULL'), @@ -166,7 +172,6 @@ cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, return out_arr {{endfor}} - {{ py: type_info = (('uint64', 'uint64', '0x0ULL', '0xFFFFFFFFFFFFFFFFULL'), @@ -241,8 +246,8 @@ cdef object _rand_{{nptype}}(object low, object high, object size, high_arr = np.array(high, copy=False) low_ndim = np.PyArray_NDIM(low_arr) high_ndim = np.PyArray_NDIM(high_arr) - if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and - (high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))): + if ((low_ndim == 0 or (low_ndim == 1 and low_arr.size == 1 and size is not None)) and + (high_ndim == 0 or (high_ndim == 1 and high_arr.size == 1 and size is not None))): low = int(low_arr) high = int(high_arr) # Subtract 1 since internal generator produces on closed interval [low, high] diff --git a/numpy/random/randomgen/common.pxd b/numpy/random/randomgen/common.pxd index 99c53a210fa9..824225cebf95 100644 --- a/numpy/random/randomgen/common.pxd +++ b/numpy/random/randomgen/common.pxd @@ -27,14 +27,18 @@ cdef enum ConstraintType: ctypedef ConstraintType constraint_type +cdef object benchmark(brng_t *brng, object lock, Py_ssize_t cnt, object method) +cdef object random_raw(brng_t *brng, object lock, object size, object output) +cdef object prepare_cffi(brng_t *brng) +cdef object prepare_ctypes(brng_t *brng) cdef int check_constraint(double val, object name, constraint_type cons) except -1 cdef int check_array_constraint(np.ndarray val, object name, constraint_type cons) except -1 cdef extern from "src/aligned_malloc/aligned_malloc.h": - cdef void *PyArray_realloc_aligned(void *p, size_t n); - cdef void *PyArray_malloc_aligned(size_t n); - cdef void *PyArray_calloc_aligned(size_t n, size_t s); - cdef void PyArray_free_aligned(void *p); + cdef void *PyArray_realloc_aligned(void *p, size_t n) + cdef void *PyArray_malloc_aligned(size_t n) + cdef void *PyArray_calloc_aligned(size_t n, size_t s) + cdef void PyArray_free_aligned(void *p) ctypedef double (*random_double_fill)(brng_t *state, np.npy_intp count, double* out) nogil ctypedef double (*random_double_0)(void *state) nogil @@ -105,5 +109,5 @@ cdef inline void compute_complex(double *rv_r, double *rv_i, double loc_r, scale_r = sqrt(var_r) scale_i = sqrt(var_i) - rv_i[0] = loc_i + scale_i * (rho * rv_r[0] + scale_c * rv_i[0]) + rv_i[0] = loc_i + scale_i * (rho * rv_r[0] + scale_c * rv_i[0]) rv_r[0] = loc_r + scale_r * rv_r[0] diff --git a/numpy/random/randomgen/common.pyx b/numpy/random/randomgen/common.pyx index 30f62bf9129d..2ade3e821cc4 100644 --- a/numpy/random/randomgen/common.pyx +++ b/numpy/random/randomgen/common.pyx @@ -1,7 +1,5 @@ #!python #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3 -from __future__ import absolute_import - from collections import namedtuple from cpython cimport PyFloat_AsDouble import sys @@ -16,6 +14,150 @@ interface = namedtuple('interface', ['state_address', 'state', 'next_uint64', 'next_uint32', 'next_double', 'brng']) +cdef object benchmark(brng_t *brng, object lock, Py_ssize_t cnt, object method): + """Benchmark command used by BasicRNG""" + cdef Py_ssize_t i + if method==u'uint64': + with lock, nogil: + for i in range(cnt): + brng.next_uint64(brng.state) + elif method==u'double': + with lock, nogil: + for i in range(cnt): + brng.next_double(brng.state) + else: + raise ValueError('Unknown method') + + +cdef object random_raw(brng_t *brng, object lock, object size, object output): + """ + random_raw(self, size=None) + + Return randoms as generated by the underlying PRNG + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. + + Returns + ------- + out : uint or ndarray + Drawn samples. + + Notes + ----- + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. + """ + cdef np.ndarray randoms + cdef uint64_t *randoms_data + cdef Py_ssize_t i, n + + if not output: + if size is None: + with lock: + brng.next_raw(brng.state) + return None + n = np.asarray(size).sum() + with lock, nogil: + for i in range(n): + brng.next_raw(brng.state) + return None + + if size is None: + with lock: + return brng.next_raw(brng.state) + + randoms = np.empty(size, np.uint64) + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + with lock, nogil: + for i in range(n): + randoms_data[i] = brng.next_raw(brng.state) + return randoms + +cdef object prepare_cffi(brng_t *brng): + """ + Bundles the interfaces to interact with a Basic RNG using cffi + + Parameters + ---------- + brng : pointer + A pointer to a Basic RNG instance + + Returns + ------- + interface : namedtuple + The functions required to interface with the Basic RNG using cffi + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + try: + import cffi + except ImportError: + raise ImportError('cffi cannot be imported.') + + ffi = cffi.FFI() + _cffi = interface(brng.state, + ffi.cast('void *', brng.state), + ffi.cast('uint64_t (*)(void *)', brng.next_uint64), + ffi.cast('uint32_t (*)(void *)', brng.next_uint32), + ffi.cast('double (*)(void *)', brng.next_double), + ffi.cast('void *', brng)) + return _cffi + +cdef object prepare_ctypes(brng_t *brng): + """ + Bundles the interfaces to interact with a Basic RNG using ctypes + + Parameters + ---------- + brng : pointer + A pointer to a Basic RNG instance + + Returns + ------- + interface : namedtuple + The functions required to interface with the Basic RNG using ctypes: + + * state_address - Memory address of the state struct + * state - pointer to the state struct + * next_uint64 - function pointer to produce 64 bit integers + * next_uint32 - function pointer to produce 32 bit integers + * next_double - function pointer to produce doubles + * brng - pointer to the Basic RNG struct + """ + import ctypes + + _ctypes = interface(brng.state, + ctypes.c_void_p(brng.state), + ctypes.cast(brng.next_uint64, + ctypes.CFUNCTYPE(ctypes.c_uint64, + ctypes.c_void_p)), + ctypes.cast(brng.next_uint32, + ctypes.CFUNCTYPE(ctypes.c_uint32, + ctypes.c_void_p)), + ctypes.cast(brng.next_double, + ctypes.CFUNCTYPE(ctypes.c_double, + ctypes.c_void_p)), + ctypes.c_void_p(brng)) + return _ctypes + cdef double kahan_sum(double *darr, np.npy_intp n): cdef double c, y, t, sum cdef np.npy_intp i @@ -29,6 +171,7 @@ cdef double kahan_sum(double *darr, np.npy_intp n): return sum cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size): + """Convert a large integer to an array of unsigned integers""" len = bits // uint_size value = np.asarray(value) if uint_size == 32: @@ -67,8 +210,12 @@ cdef check_output(object out, object dtype, object size): raise TypeError('Supplied output array has the wrong type. ' 'Expected {0}, got {0}'.format(dtype, out_array.dtype)) if size is not None: - # TODO: enable this !!! if tuple(size) != out_array.shape: - raise ValueError('size and out cannot be simultaneously used') + try: + tup_size = tuple(size) + except TypeError: + tup_size = tuple([size]) + if tup_size != out.shape: + raise ValueError('size must match out.shape when used together') cdef object double_fill(void *func, brng_t *state, object size, object lock, object out): @@ -175,7 +322,6 @@ cdef int check_array_constraint(np.ndarray val, object name, constraint_type con return 0 - cdef int check_constraint(double val, object name, constraint_type cons) except -1: if cons == CONS_NON_NEGATIVE: if np.signbit(val) or np.isnan(val): @@ -257,7 +403,6 @@ cdef object cont_broadcast_2(void *func, void *state, object size, object lock, randoms = np.empty(it.shape, np.double) # randoms = np.PyArray_SimpleNew(it.nd, np.PyArray_DIMS(it), np.NPY_DOUBLE) - randoms_data = np.PyArray_DATA(randoms) n = np.PyArray_SIZE(randoms) @@ -296,7 +441,7 @@ cdef object cont_broadcast_3(void *func, void *state, object size, object lock, randoms = np.empty(size, np.double) else: it = np.PyArray_MultiIterNew3(a_arr, b_arr, c_arr) - #randoms = np.PyArray_SimpleNew(it.nd, np.PyArray_DIMS(it), np.NPY_DOUBLE) + # randoms = np.PyArray_SimpleNew(it.nd, np.PyArray_DIMS(it), np.NPY_DOUBLE) randoms = np.empty(it.shape, np.double) randoms_data = np.PyArray_DATA(randoms) @@ -381,11 +526,11 @@ cdef object cont(void *func, void *state, object size, object lock, int narg, randoms = out n = np.PyArray_SIZE(randoms) - cdef double *randoms_data = np.PyArray_DATA(randoms) - cdef random_double_0 f0; - cdef random_double_1 f1; - cdef random_double_2 f2; - cdef random_double_3 f3; + cdef double *randoms_data = np.PyArray_DATA(randoms) + cdef random_double_0 f0 + cdef random_double_1 f1 + cdef random_double_2 f2 + cdef random_double_3 f3 with lock, nogil: if narg == 0: @@ -425,7 +570,7 @@ cdef object discrete_broadcast_d(void *func, void *state, object size, object lo if size is not None: randoms = np.empty(size, np.int64) else: - #randoms = np.empty(np.shape(a_arr), np.double) + # randoms = np.empty(np.shape(a_arr), np.double) randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_INT64) randoms_data = np.PyArray_DATA(randoms) @@ -485,7 +630,6 @@ cdef object discrete_broadcast_di(void *func, void *state, object size, object l cdef random_uint_di f = (func) cdef np.npy_intp i, n - if a_constraint != CONS_NONE: check_array_constraint(a_arr, a_name, a_constraint) @@ -553,7 +697,7 @@ cdef object discrete_broadcast_iii(void *func, void *state, object size, object return randoms cdef object discrete_broadcast_i(void *func, void *state, object size, object lock, - np.ndarray a_arr, object a_name, constraint_type a_constraint): + np.ndarray a_arr, object a_name, constraint_type a_constraint): cdef np.ndarray randoms cdef int64_t *randoms_data cdef np.broadcast it @@ -589,7 +733,7 @@ cdef object disc(void *func, void *state, object size, object lock, object c, object c_name, constraint_type c_constraint): cdef double _da = 0, _db = 0 - cdef int64_t _ia = 0, _ib = 0 , _ic = 0 + cdef int64_t _ia = 0, _ib = 0, _ic = 0 cdef bint is_scalar = True if narg_double > 0: a_arr = np.PyArray_FROM_OTF(a, np.NPY_DOUBLE, np.NPY_ALIGNED) @@ -607,7 +751,7 @@ cdef object disc(void *func, void *state, object size, object lock, if narg_int64 > 1: b_arr = np.PyArray_FROM_OTF(b, np.NPY_INT64, np.NPY_ALIGNED) is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0 - if narg_int64 > 2 : + if narg_int64 > 2: c_arr = np.PyArray_FROM_OTF(c, np.NPY_INT64, np.NPY_ALIGNED) is_scalar = is_scalar and np.PyArray_NDIM(c_arr) == 0 @@ -631,7 +775,6 @@ cdef object disc(void *func, void *state, object size, object lock, else: raise NotImplementedError("No vector path available") - if narg_double > 0: _da = PyFloat_AsDouble(a) if a_constraint != CONS_NONE and is_scalar: @@ -654,7 +797,7 @@ cdef object disc(void *func, void *state, object size, object lock, _ib = b if b_constraint != CONS_NONE and is_scalar: check_constraint(_ib, b_name, b_constraint) - if narg_int64 > 2 : + if narg_int64 > 2: _ic = c if c_constraint != CONS_NONE and is_scalar: check_constraint(_ic, c_name, c_constraint) @@ -679,15 +822,15 @@ cdef object disc(void *func, void *state, object size, object lock, cdef np.npy_intp i, n cdef np.ndarray randoms = np.empty(size, np.int64) cdef np.int64_t *randoms_data - cdef random_uint_0 f0; - cdef random_uint_d fd; - cdef random_uint_dd fdd; - cdef random_uint_di fdi; - cdef random_uint_i fi; - cdef random_uint_iii fiii; + cdef random_uint_0 f0 + cdef random_uint_d fd + cdef random_uint_dd fdd + cdef random_uint_di fdi + cdef random_uint_i fi + cdef random_uint_iii fiii n = np.PyArray_SIZE(randoms) - randoms_data = np.PyArray_DATA(randoms) + randoms_data = np.PyArray_DATA(randoms) with lock, nogil: if narg_int64 == 0: @@ -721,8 +864,8 @@ cdef object disc(void *func, void *state, object size, object lock, cdef object cont_broadcast_1_f(void *func, brng_t *state, object size, object lock, - np.ndarray a_arr, object a_name, constraint_type a_constraint, - object out): + np.ndarray a_arr, object a_name, constraint_type a_constraint, + object out): cdef np.ndarray randoms cdef float a_val @@ -788,8 +931,8 @@ cdef object cont_f(void *func, brng_t *state, object size, object lock, randoms = out n = np.PyArray_SIZE(randoms) - cdef float *randoms_data = np.PyArray_DATA(randoms) - cdef random_float_1 f1 = func; + cdef float *randoms_data = np.PyArray_DATA(randoms) + cdef random_float_1 f1 = func with lock, nogil: for i in range(n): diff --git a/numpy/random/randomgen/distributions.pxd b/numpy/random/randomgen/distributions.pxd index 35d92db51bbb..ddb7a84bf190 100644 --- a/numpy/random/randomgen/distributions.pxd +++ b/numpy/random/randomgen/distributions.pxd @@ -3,7 +3,7 @@ from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t) import numpy as np -cimport numpy as np +cimport numpy as np cdef extern from "src/distributions/distributions.h": @@ -80,13 +80,13 @@ cdef extern from "src/distributions/distributions.h": double random_rayleigh(brng_t *brng_state, double mode) nogil double random_standard_t(brng_t *brng_state, double df) nogil double random_noncentral_chisquare(brng_t *brng_state, double df, - double nonc) nogil + double nonc) nogil double random_noncentral_f(brng_t *brng_state, double dfnum, - double dfden, double nonc) nogil + double dfden, double nonc) nogil double random_wald(brng_t *brng_state, double mean, double scale) nogil double random_vonmises(brng_t *brng_state, double mu, double kappa) nogil double random_triangular(brng_t *brng_state, double left, double mode, - double right) nogil + double right) nogil int64_t random_poisson(brng_t *brng_state, double lam) nogil int64_t random_negative_binomial(brng_t *brng_state, double n, double p) nogil diff --git a/numpy/random/randomgen/dsfmt.pyx b/numpy/random/randomgen/dsfmt.pyx index 2c4bfabe6937..129caafff17a 100644 --- a/numpy/random/randomgen/dsfmt.pyx +++ b/numpy/random/randomgen/dsfmt.pyx @@ -1,9 +1,12 @@ -from __future__ import absolute_import - import operator from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock + import numpy as np cimport numpy as np @@ -15,24 +18,24 @@ from .entropy import random_entropy np.import_array() DEF DSFMT_MEXP = 19937 -DEF DSFMT_N = 191 # ((DSFMT_MEXP - 128) / 104 + 1) -DEF DSFMT_N_PLUS_1 = 192 # DSFMT_N + 1 +DEF DSFMT_N = 191 # ((DSFMT_MEXP - 128) / 104 + 1) +DEF DSFMT_N_PLUS_1 = 192 # DSFMT_N + 1 DEF DSFMT_N64 = DSFMT_N * 2 cdef extern from "src/dsfmt/dSFMT.h": union W128_T: - uint64_t u[2]; - uint32_t u32[4]; - double d[2]; + uint64_t u[2] + uint32_t u32[4] + double d[2] - ctypedef W128_T w128_t; + ctypedef W128_T w128_t struct DSFMT_T: - w128_t status[DSFMT_N_PLUS_1]; - int idx; + w128_t status[DSFMT_N_PLUS_1] + int idx - ctypedef DSFMT_T dsfmt_t; + ctypedef DSFMT_T dsfmt_t struct s_dsfmt_state: dsfmt_t *state @@ -51,7 +54,7 @@ cdef extern from "src/dsfmt/dSFMT.h": void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[], int key_length) - void dsfmt_jump(dsfmt_state *state); + void dsfmt_jump(dsfmt_state *state) cdef uint64_t dsfmt_uint64(void* st) nogil: return dsfmt_next64(st) @@ -137,12 +140,13 @@ cdef class DSFMT: Jump Ahead Algorithm for Linear Recurrences in a Polynomial Space", Sequences and Their Applications - SETA, 290--298, 2008. """ - cdef dsfmt_state *rng_state + cdef dsfmt_state *rng_state cdef brng_t *_brng cdef public object capsule cdef public object _cffi cdef public object _ctypes cdef public object _generator + cdef public object lock def __init__(self, seed=None): self.rng_state = malloc(sizeof(dsfmt_state)) @@ -151,6 +155,8 @@ cdef class DSFMT: self.rng_state.buffer_loc = DSFMT_N64 self._brng = malloc(sizeof(brng_t)) self.seed(seed) + self.lock = Lock() + self._brng.state = self.rng_state self._brng.next_uint64 = &dsfmt_uint64 self._brng.next_uint32 = &dsfmt_uint32 @@ -185,17 +191,39 @@ cdef class DSFMT: cdef _reset_state_variables(self): self.rng_state.buffer_loc = DSFMT_N64 + def random_raw(self, size=None, output=True): + """ + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. + + Returns + ------- + out : uint or ndarray + Drawn samples. + + Notes + ----- + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. + """ + return random_raw(self._brng, self.lock, size, output) def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - cdef Py_ssize_t i - if method==u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method==u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None): """ @@ -289,14 +317,14 @@ cdef class DSFMT: for j in range(2): state[loc] = self.rng_state.state.status[i].u[j] loc += 1 - buffered_uniforms = np.empty(DSFMT_N64,dtype=np.double) + buffered_uniforms = np.empty(DSFMT_N64, dtype=np.double) for i in range(DSFMT_N64): buffered_uniforms[i] = self.rng_state.buffered_uniforms[i] return {'brng': self.__class__.__name__, - 'state': {'state':np.asarray(state), - 'idx':self.rng_state.state.idx}, + 'state': {'state': np.asarray(state), + 'idx': self.rng_state.state.idx}, 'buffer_loc': self.rng_state.buffer_loc, - 'buffered_uniforms':np.asarray(buffered_uniforms)} + 'buffered_uniforms': np.asarray(buffered_uniforms)} @state.setter def state(self, value): @@ -321,12 +349,12 @@ cdef class DSFMT: @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -335,25 +363,10 @@ cdef class DSFMT: * next_double - function pointer to produce doubles * brng - pointer to the Basic RNG struct """ + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&dsfmt_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&dsfmt_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&dsfmt_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) - return self.ctypes + return self._ctypes @property def cffi(self): @@ -374,19 +387,8 @@ cdef class DSFMT: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): diff --git a/numpy/random/randomgen/entropy.pyx b/numpy/random/randomgen/entropy.pyx index d7822bfdf412..0e429e9f2631 100644 --- a/numpy/random/randomgen/entropy.pyx +++ b/numpy/random/randomgen/entropy.pyx @@ -1,7 +1,3 @@ -from __future__ import absolute_import - -import operator - cimport numpy as np import numpy as np @@ -25,6 +21,7 @@ cdef Py_ssize_t compute_numel(size): n = size return n + def seed_by_array(object seed, Py_ssize_t n): """ Transforms a seed array into an initial state @@ -150,4 +147,4 @@ def random_entropy(size=None, source='system'): if n == 0: return random - return np.asarray(randoms).reshape(size) \ No newline at end of file + return np.asarray(randoms).reshape(size) diff --git a/numpy/random/randomgen/examples/cython/extending.pyx b/numpy/random/randomgen/examples/cython/extending.pyx index c387a13af4f3..a8d314bb19a3 100644 --- a/numpy/random/randomgen/examples/cython/extending.pyx +++ b/numpy/random/randomgen/examples/cython/extending.pyx @@ -1,13 +1,17 @@ +#cython: language_level=3 +from libc.stdint cimport uint32_t +from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer + import numpy as np cimport numpy as np cimport cython -from libc.stdint cimport uint32_t -from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer + from randomgen.common cimport brng_t from randomgen.xoroshiro128 import Xoroshiro128 np.import_array() + def uniform_mean(Py_ssize_t N): cdef Py_ssize_t i cdef brng_t *rng @@ -26,6 +30,7 @@ def uniform_mean(Py_ssize_t N): randoms = np.asarray(random_values) return randoms.mean() + cdef uint32_t bounded_uint(uint32_t lb, uint32_t ub, brng_t *rng): cdef uint32_t mask, delta, val mask = delta = ub - lb @@ -41,6 +46,7 @@ cdef uint32_t bounded_uint(uint32_t lb, uint32_t ub, brng_t *rng): return lb + val + @cython.boundscheck(False) @cython.wraparound(False) def bounded_uints(uint32_t lb, uint32_t ub, Py_ssize_t n): diff --git a/numpy/random/randomgen/examples/cython/extending_distributions.pyx b/numpy/random/randomgen/examples/cython/extending_distributions.pyx index 630d952bf75e..03f04af041a5 100644 --- a/numpy/random/randomgen/examples/cython/extending_distributions.pyx +++ b/numpy/random/randomgen/examples/cython/extending_distributions.pyx @@ -1,3 +1,4 @@ +#cython: language_level=3 import numpy as np cimport numpy as np cimport cython @@ -6,6 +7,7 @@ from randomgen.common cimport * from randomgen.distributions cimport random_gauss_zig from randomgen.xoroshiro128 import Xoroshiro128 + @cython.boundscheck(False) @cython.wraparound(False) def normals_zig(Py_ssize_t n): @@ -25,24 +27,25 @@ def normals_zig(Py_ssize_t n): randoms = np.asarray(random_values) return randoms + @cython.boundscheck(False) @cython.wraparound(False) def uniforms(Py_ssize_t n): - cdef Py_ssize_t i - cdef brng_t *rng - cdef const char *capsule_name = "BasicRNG" - cdef double[::1] random_values + cdef Py_ssize_t i + cdef brng_t *rng + cdef const char *capsule_name = "BasicRNG" + cdef double[::1] random_values - x = Xoroshiro128() - capsule = x.capsule - # Optional check that the capsule if from a Basic RNG - if not PyCapsule_IsValid(capsule, capsule_name): - raise ValueError("Invalid pointer to anon_func_state") - # Cast the pointer - rng = PyCapsule_GetPointer(capsule, capsule_name) - random_values = np.empty(n) - for i in range(n): - # Call the function - random_values[i] = rng.next_double(rng.state) - randoms = np.asarray(random_values) - return randoms \ No newline at end of file + x = Xoroshiro128() + capsule = x.capsule + # Optional check that the capsule if from a Basic RNG + if not PyCapsule_IsValid(capsule, capsule_name): + raise ValueError("Invalid pointer to anon_func_state") + # Cast the pointer + rng = PyCapsule_GetPointer(capsule, capsule_name) + random_values = np.empty(n) + for i in range(n): + # Call the function + random_values[i] = rng.next_double(rng.state) + randoms = np.asarray(random_values) + return randoms diff --git a/numpy/random/randomgen/examples/numba/extending.py b/numpy/random/randomgen/examples/numba/extending.py index 4dafeb5c4d12..72e903b1f19a 100644 --- a/numpy/random/randomgen/examples/numba/extending.py +++ b/numpy/random/randomgen/examples/numba/extending.py @@ -26,7 +26,7 @@ def bounded_uint(lb, ub, state): return lb + val -bounded_uint(323, 2394691, s.value) +print(bounded_uint(323, 2394691, s.value)) @nb.jit(nopython=True) diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index 23482ce7ffb2..ffd269f9820b 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -1,7 +1,5 @@ #!python #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3 -from __future__ import absolute_import - import operator import warnings @@ -14,28 +12,14 @@ cimport numpy as np import numpy as np cimport cython -try: - from threading import Lock -except ImportError: - from dummy_threading import Lock - from .bounded_integers cimport * +from .bounded_integers import _randint_types from .common cimport * from .distributions cimport * from .xoroshiro128 import Xoroshiro128 np.import_array() -_randint_types = {'bool': (0, 2), - 'int8': (-2**7, 2**7), - 'int16': (-2**15, 2**15), - 'int32': (-2**31, 2**31), - 'int64': (-2**63, 2**63), - 'uint8': (0, 2**8), - 'uint16': (0, 2**16), - 'uint32': (0, 2**32), - 'uint64': (0, 2**64) - } cdef class RandomGenerator: """ @@ -106,7 +90,7 @@ cdef class RandomGenerator: raise ValueError("Invalid brng. The brng must be instantized.") self._brng = PyCapsule_GetPointer(capsule, name) self._binomial = malloc(sizeof(binomial_t)) - self.lock = Lock() + self.lock = brng.lock def __dealloc__(self): free(self._binomial) @@ -146,7 +130,7 @@ cdef class RandomGenerator: The best method to access seed is to directly use a basic RNG instance. This example demonstrates this best practice. - >>> from np.random.randomgen import RandomGenerator, PCG64 + >>> from numpy.random.randomgen import RandomGenerator, PCG64 >>> brng = PCG64(1234567891011) >>> rg = brng.generator >>> brng.seed(1110987654321) @@ -161,6 +145,7 @@ cdef class RandomGenerator: >>> rg = RandomGenerator(PCG64(1234567891011)) >>> rg.seed(1110987654321) + """ # TODO: Should this remain self._basicrng.seed(*args, **kwargs) @@ -181,6 +166,7 @@ cdef class RandomGenerator: ----- This is a trivial pass-through function. RandomGenerator does not directly contain or manipulate the basic RNG's state. + """ return self._basicrng.state @@ -188,122 +174,6 @@ cdef class RandomGenerator: def state(self, value): self._basicrng.state = value - def random_uintegers(self, size=None, int bits=64): - """ - random_uintegers(size=None, bits=64) - - Return random unsigned integers - - Parameters - ---------- - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - bits : int {32, 64} - Size of the unsigned integer to return, either 32 bit or 64 bit. - - Returns - ------- - out : uint or ndarray - Drawn samples. - - Notes - ----- - This method effectively exposes access to the raw underlying - pseudo-random number generator since these all produce unsigned - integers. In practice these are most useful for generating other - random numbers. - - These should not be used to produce bounded random numbers by - simple truncation. - """ - cdef np.npy_intp i, n - cdef np.ndarray array - cdef uint32_t* data32 - cdef uint64_t* data64 - if bits == 64: - if size is None: - with self.lock: - return self._brng.next_uint64(self._brng.state) - array = np.empty(size, np.uint64) - n = np.PyArray_SIZE(array) - data64 = np.PyArray_DATA(array) - with self.lock, nogil: - for i in range(n): - data64[i] = self._brng.next_uint64(self._brng.state) - elif bits == 32: - if size is None: - with self.lock: - return self._brng.next_uint32(self._brng.state) - array = np.empty(size, np.uint32) - n = np.PyArray_SIZE(array) - data32 = np.PyArray_DATA(array) - with self.lock, nogil: - for i in range(n): - data32[i] = self._brng.next_uint32(self._brng.state) - else: - raise ValueError('Unknown value of bits. Must be either 32 or 64.') - - return array - - def random_raw(self, size=None, output=True): - """ - random_raw(self, size=None) - - Return randoms as generated by the underlying PRNG - - Parameters - ---------- - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - output : bool, optional - Output values. Used for performance testing since the generated - values are not returned. - - Returns - ------- - out : uint or ndarray - Drawn samples. - - Notes - ----- - This method directly exposes the the raw underlying pseudo-random - number generator. All values are returned as unsigned 64-bit - values irrespective of the number of bits produced by the PRNG. - - See the class docstring for the number of bits returned. - """ - cdef np.ndarray randoms - cdef uint64_t *randoms_data - cdef Py_ssize_t i, n - - if not output: - if size is None: - with self.lock: - self._brng.next_raw(self._brng.state) - return None - n = np.asarray(size).sum() - with self.lock, nogil: - for i in range(n): - self._brng.next_raw(self._brng.state) - return None - - if size is None: - with self.lock: - return self._brng.next_raw(self._brng.state) - - randoms = np.empty(size, np.uint64) - randoms_data = np.PyArray_DATA(randoms) - n = np.PyArray_SIZE(randoms) - - with self.lock, nogil: - for i in range(n): - randoms_data[i] = self._brng.next_raw(self._brng.state) - return randoms - def random_sample(self, size=None, dtype=np.float64, out=None): """ random_sample(size=None, dtype='d', out=None) @@ -352,6 +222,7 @@ cdef class RandomGenerator: array([[-3.99149989, -0.52338984], # random [-2.99091858, -0.79479508], [-1.23204345, -1.75224494]]) + """ cdef double temp key = np.dtype(dtype).name @@ -405,7 +276,6 @@ cdef class RandomGenerator: b, 'b', CONS_POSITIVE, 0.0, '', CONS_NONE, None) - def exponential(self, scale=1.0, size=None): """ exponential(scale=1.0, size=None) @@ -495,6 +365,7 @@ cdef class RandomGenerator: Output a 3x8000 array: >>> n = np.random.standard_exponential((3, 8000)) + """ key = np.dtype(dtype).name if key == 'float64': @@ -658,37 +529,38 @@ cdef class RandomGenerator: ---------- .. [1] Daniel Lemire., "Fast Random Integer Generation in an Interval", CoRR, Aug. 13, 2018, http://arxiv.org/abs/1805.10941. + """ if high is None: high = low low = 0 key = np.dtype(dtype).name - if not key in _randint_types: + if key not in _randint_types: raise TypeError('Unsupported dtype "%s" for randint' % key) if key == 'int32': - ret = _rand_int32(low, high, size, use_masked, self._brng, self.lock) + ret = _rand_int32(low, high, size, use_masked, self._brng, self.lock) elif key == 'int64': - ret = _rand_int64(low, high, size, use_masked, self._brng, self.lock) + ret = _rand_int64(low, high, size, use_masked, self._brng, self.lock) elif key == 'int16': - ret = _rand_int16(low, high, size, use_masked, self._brng, self.lock) + ret = _rand_int16(low, high, size, use_masked, self._brng, self.lock) elif key == 'int8': - ret = _rand_int8(low, high, size, use_masked, self._brng, self.lock) + ret = _rand_int8(low, high, size, use_masked, self._brng, self.lock) elif key == 'uint64': - ret = _rand_uint64(low, high, size, use_masked, self._brng, self.lock) + ret = _rand_uint64(low, high, size, use_masked, self._brng, self.lock) elif key == 'uint32': - ret = _rand_uint32(low, high, size, use_masked, self._brng, self.lock) + ret = _rand_uint32(low, high, size, use_masked, self._brng, self.lock) elif key == 'uint16': - ret = _rand_uint16(low, high, size, use_masked, self._brng, self.lock) + ret = _rand_uint16(low, high, size, use_masked, self._brng, self.lock) elif key == 'uint8': - ret = _rand_uint8(low, high, size, use_masked, self._brng, self.lock) + ret = _rand_uint8(low, high, size, use_masked, self._brng, self.lock) elif key == 'bool': - ret = _rand_bool(low, high, size, use_masked, self._brng, self.lock) + ret = _rand_bool(low, high, size, use_masked, self._brng, self.lock) if size is None and dtype in (np.bool, np.int, np.long): - if np.array(ret).shape == (): - return dtype(ret) + if np.array(ret).shape == (): + return dtype(ret) return ret def bytes(self, np.npy_intp length): @@ -716,7 +588,6 @@ cdef class RandomGenerator: cdef Py_ssize_t n_uint32 = ((length - 1) // 4 + 1) return self.randint(0, 4294967296, size=n_uint32, dtype=np.uint32).tobytes()[:length] - @cython.wraparound(True) def choice(self, a, size=None, replace=True, p=None): """ @@ -849,7 +720,7 @@ cdef class RandomGenerator: cdf /= cdf[-1] uniform_samples = self.random_sample(shape) idx = cdf.searchsorted(uniform_samples, side='right') - idx = np.array(idx, copy=False) # searchsorted returns a scalar + idx = np.array(idx, copy=False) # searchsorted returns a scalar else: idx = self.randint(0, pop_size, size=shape) else: @@ -888,7 +759,7 @@ cdef class RandomGenerator: # In most cases a scalar will have been made an array idx = idx.item(0) - #Use samples as indices for a if a is array-like + # Use samples as indices for a if a is array-like if a.ndim == 0: return idx @@ -904,7 +775,6 @@ cdef class RandomGenerator: return a[idx] - def uniform(self, low=0.0, high=1.0, size=None): """ uniform(low=0.0, high=1.0, size=None) @@ -980,6 +850,7 @@ cdef class RandomGenerator: >>> count, bins, ignored = plt.hist(s, 15, density=True) >>> plt.plot(bins, np.ones_like(bins), linewidth=2, color='r') >>> plt.show() + """ cdef bint is_scalar = True cdef np.ndarray alow, ahigh, arange @@ -1003,8 +874,10 @@ cdef class RandomGenerator: None) temp = np.subtract(ahigh, alow) - Py_INCREF(temp) # needed to get around Pyrex's automatic reference-counting - # rules because EnsureArray steals a reference + # needed to get around Pyrex's automatic reference-counting + # rules because EnsureArray steals a reference + Py_INCREF(temp) + arange = np.PyArray_EnsureArray(temp) if not np.all(np.isfinite(arange)): raise OverflowError('Range exceeds valid bounds') @@ -1049,19 +922,13 @@ cdef class RandomGenerator: -------- random - Notes - ----- - This is a convenience function. If you want an interface that takes - a shape-tuple as the first argument, refer to `numpy.random.random_sample`. - - ``dtype`` can only be changed using a keyword argument. - Examples -------- >>> np.random.rand(3,2) array([[ 0.14022471, 0.96360618], #random [ 0.37601032, 0.25528411], #random [ 0.49313049, 0.94909878]]) #random + """ if len(args) == 0: return self.random_sample(dtype=dtype) @@ -1086,9 +953,6 @@ cdef class RandomGenerator: distribution of mean 0 and variance 1. A single float randomly sampled from the distribution is returned if no argument is provided. - This is a convenience function. If you want an interface that takes a - tuple as the first argument, use `numpy.random.standard_normal` instead. - Parameters ---------- d0, d1, ..., dn : int, optional @@ -1109,7 +973,7 @@ cdef class RandomGenerator: See Also -------- standard_normal : Similar, but takes a tuple as its argument. - normal : Also accepts mu and sigma arguments + normal : Also accepts mu and sigma arguments. Notes ----- @@ -1138,7 +1002,7 @@ cdef class RandomGenerator: """ random_integers(low, high=None, size=None) - Random integers of type np.int64 between `low` and `high`, inclusive. + Random integers of type np.int between `low` and `high`, inclusive. Return random integers of type np.int64 from the "discrete uniform" distribution in the closed interval [`low`, `high`]. If `high` is @@ -1221,8 +1085,9 @@ cdef class RandomGenerator: else: warnings.warn(("This function is deprecated. Please call " - "randint({low}, {high} + 1) instead".format( - low=low, high=high)), DeprecationWarning) + "randint({low}, {high} + 1)" + "instead".format(low=low, high=high)), + DeprecationWarning) return self.randint(low, high + 1, size=size, dtype='l') @@ -1298,7 +1163,6 @@ cdef class RandomGenerator: else: raise TypeError('Unsupported dtype "%s" for standard_normal' % key) - def normal(self, loc=0.0, scale=1.0, size=None): """ normal(loc=0.0, scale=1.0, size=None) @@ -1457,10 +1321,11 @@ cdef class RandomGenerator: Draw samples from the distribution: >>> s = np.random.complex_normal(size=1000) + """ cdef np.ndarray ogamma, orelation, oloc, randoms, v_real, v_imag, rho cdef double *randoms_data - cdef double fgamma_r, fgamma_i, frelation_r, frelation_i, frho, fvar_r , fvar_i, \ + cdef double fgamma_r, fgamma_i, frelation_r, frelation_i, frho, fvar_r, fvar_i, \ floc_r, floc_i, f_real, f_imag, i_r_scale, r_scale, i_scale, f_rho cdef np.npy_intp i, j, n, n2 cdef np.broadcast it @@ -1530,7 +1395,7 @@ cdef class RandomGenerator: cov = 0.5 * np.imag(orelation) rho = np.zeros_like(cov) idx = (v_real.flat > 0) & (v_imag.flat > 0) - rho.flat[idx] = cov.flat[idx] / np.sqrt(v_real.flat[idx] * v_imag.flat[idx]) + rho.flat[idx] = cov.flat[idx] / np.sqrt(v_real.flat[idx] * v_imag.flat[idx]) if np.any(cov.flat[~idx] != 0) or np.any(np.abs(rho) > 1): raise ValueError('Im(relation) ** 2 > Re(gamma ** 2 - relation ** 2)') @@ -1637,6 +1502,7 @@ cdef class RandomGenerator: ... (sps.gamma(shape) * scale**shape)) >>> plt.plot(bins, y, linewidth=2, color='r') >>> plt.show() + """ cdef void *func key = np.dtype(dtype).name @@ -1711,7 +1577,7 @@ cdef class RandomGenerator: -------- Draw samples from the distribution: - >>> shape, scale = 2., 2. # mean and dispersion + >>> shape, scale = 2., 2. # mean=4, std=2*sqrt(2) >>> s = np.random.gamma(shape, scale, 1000) Display the histogram of the samples, along with @@ -1749,10 +1615,10 @@ cdef class RandomGenerator: Parameters ---------- - dfnum : int or array_like of ints - Degrees of freedom in numerator. Must be non-negative. - dfden : int or array_like of ints - Degrees of freedom in denominator. Must be non-negative. + dfnum : float or array_like of floats + Degrees of freedom in numerator, should be > 0. + dfden : float or array_like of float + Degrees of freedom in denominator, should be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1832,12 +1698,16 @@ cdef class RandomGenerator: Parameters ---------- - dfnum : int or array_like of ints - Parameter, should be > 1. - dfden : int or array_like of ints - Parameter, should be > 1. + dfnum : float or array_like of floats + Numerator degrees of freedom, should be > 0. + + .. versionchanged:: 1.14.0 + Earlier NumPy versions required dfnum > 1. + dfden : float or array_like of floats + Denominator degrees of freedom, should be > 0. nonc : float or array_like of floats - Parameter, should be >= 0. + Non-centrality parameter, the sum of the squares of the numerator + means, should be >= 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1905,8 +1775,8 @@ cdef class RandomGenerator: Parameters ---------- - df : int or array_like of ints - Number of degrees of freedom. + df : float or array_like of floats + Number of degrees of freedom, should be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1971,9 +1841,11 @@ cdef class RandomGenerator: Parameters ---------- - df : int or array_like of ints - Degrees of freedom, should be > 0 as of NumPy 1.10.0, - should be > 1 for earlier versions. + df : float or array_like of floats + Degrees of freedom, should be > 0. + + .. versionchanged:: 1.10.0 + Earlier NumPy versions required dfnum > 1. nonc : float or array_like of floats Non-centrality, should be non-negative. size : int or tuple of ints, optional @@ -1994,14 +1866,14 @@ cdef class RandomGenerator: .. math:: P(x;df,nonc) = \\sum^{\\infty}_{i=0} \\frac{e^{-nonc/2}(nonc/2)^{i}}{i!} - \\P_{Y_{df+2i}}(x), + P_{Y_{df+2i}}(x), where :math:`Y_{q}` is the Chi-square with q degrees of freedom. References ---------- - .. [1] Wikipedia, "Noncentral chi-square distribution" - https://en.wikipedia.org/wiki/Noncentral_chi-square_distribution + .. [1] Wikipedia, "Noncentral chi-squared distribution" + https://en.wikipedia.org/wiki/Noncentral_chi-squared_distribution Examples -------- @@ -2081,7 +1953,7 @@ cdef class RandomGenerator: ---------- .. [1] NIST/SEMATECH e-Handbook of Statistical Methods, "Cauchy Distribution", - http://www.itl.nist.gov/div898/handbook/eda/section3/eda3663.htm + https://www.itl.nist.gov/div898/handbook/eda/section3/eda3663.htm .. [2] Weisstein, Eric W. "Cauchy Distribution." From MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/CauchyDistribution.html @@ -2092,9 +1964,9 @@ cdef class RandomGenerator: -------- Draw samples and plot the distribution: + >>> import matplotlib.pyplot as plt >>> s = np.random.standard_cauchy(1000000) >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well - >>> import matplotlib.pyplot as plt >>> plt.hist(s, bins=100) >>> plt.show() @@ -2115,7 +1987,7 @@ cdef class RandomGenerator: Parameters ---------- - df : int or array_like of ints + df : float or array_like of floats Degrees of freedom, should be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then @@ -2306,7 +2178,7 @@ cdef class RandomGenerator: Parameters ---------- a : float or array_like of floats - Shape of the distribution. All values must be positive. + Shape of the distribution. Must all be positive. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2487,7 +2359,7 @@ cdef class RandomGenerator: Parameters ---------- a : float or array_like of floats - Parameter of the distribution. Must be positive. + Parameter of the distribution. Must be non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2525,7 +2397,7 @@ cdef class RandomGenerator: Dataplot Reference Manual, Volume 2: Let Subcommands and Library Functions", National Institute of Standards and Technology Handbook Series, June 2003. - http://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf + https://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf Examples -------- @@ -2592,8 +2464,8 @@ cdef class RandomGenerator: loc : float or array_like of floats, optional The position, :math:`\\mu`, of the distribution peak. Default is 0. scale : float or array_like of floats, optional - :math:`\\lambda`, the exponential decay. Default is 1. Must be - non-negative. + :math:`\\lambda`, the exponential decay. Default is 1. Must be non- + negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2675,8 +2547,8 @@ cdef class RandomGenerator: loc : float or array_like of floats, optional The location of the mode of the distribution. Default is 0. scale : float or array_like of floats, optional - The scale parameter of the distribution. Default is 1. Must be - non-negative. + The scale parameter of the distribution. Default is 1. Must be non- + negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2792,7 +2664,7 @@ cdef class RandomGenerator: loc : float or array_like of floats, optional Parameter of the distribution. Default is 0. scale : float or array_like of floats, optional - Parameter of the distribution. Must be >= 0. + Parameter of the distribution. Must be non-negative. Default is 1. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then @@ -2848,8 +2720,8 @@ cdef class RandomGenerator: >>> def logist(x, loc, scale): ... return np.exp((loc-x)/scale)/(scale*(1+np.exp((loc-x)/scale))**2) - >>> scale = logist(bins, loc, scale).max() - >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/scale) + >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\ + ... logist(bins, loc, scale).max()) >>> plt.show() """ @@ -3087,8 +2959,8 @@ cdef class RandomGenerator: .. [2] Chhikara, Raj S., and Folks, J. Leroy, "The Inverse Gaussian Distribution: Theory : Methodology, and Applications", CRC Press, 1988. - .. [3] Wikipedia, "Wald distribution" - https://en.wikipedia.org/wiki/Wald_distribution + .. [3] Wikipedia, "Inverse Gaussian distribution" + https://en.wikipedia.org/wiki/Inverse_Gaussian_distribution Examples -------- @@ -3337,7 +3209,7 @@ cdef class RandomGenerator: randoms = np.empty(size, np.int64) cnt = np.PyArray_SIZE(randoms) - randoms_data = np.PyArray_DATA(randoms) + randoms_data = np.PyArray_DATA(randoms) with self.lock, nogil: for i in range(cnt): @@ -3346,7 +3218,6 @@ cdef class RandomGenerator: return randoms - def negative_binomial(self, n, p, size=None): """ negative_binomial(n, p, size=None) @@ -3354,14 +3225,13 @@ cdef class RandomGenerator: Draw samples from a negative binomial distribution. Samples are drawn from a negative binomial distribution with specified - parameters, `n` successes and `p` probability of success where `n` is an - integer > 0 and `p` is in the interval [0, 1]. + parameters, `n` successes and `p` probability of success where `n` + is > 0 and `p` is in the interval [0, 1]. Parameters ---------- - n : int or array_like of ints - Parameter of the distribution, > 0. Floats are also accepted, - but they will be truncated to integers. + n : float or array_like of floats + Parameter of the distribution, > 0. p : float or array_like of floats Parameter of the distribution, >= 0 and <=1. size : int or tuple of ints, optional @@ -3379,14 +3249,17 @@ cdef class RandomGenerator: Notes ----- - The probability density for the negative binomial distribution is + The probability mass function of the negative binomial distribution is - .. math:: P(N;n,p) = \\binom{N+n-1}{N}p^{n}(1-p)^{N}, + .. math:: P(N;n,p) = \\frac{\\Gamma(N+n)}{N!\\Gamma(n)}p^{n}(1-p)^{N}, where :math:`n` is the number of successes, :math:`p` is the - probability of success, and :math:`N+n` is the number of trials. - The negative binomial distribution gives the probability of N - failures given n successes, with a success on the last trial. + probability of success, :math:`N+n` is the number of trials, and + :math:`\\Gamma` is the gamma function. When :math:`n` is an integer, + :math:`\\frac{\\Gamma(N+n)}{N!\\Gamma(n)} = \\binom{N+n-1}{N}`, which is + the more common form of this term in the the pmf. The negative + binomial distribution gives the probability of N failures given n + successes, with a success on the last trial. If one throws a die repeatedly until the third time a "1" appears, then the probability distribution of the number of non-"1"s that @@ -3417,9 +3290,9 @@ cdef class RandomGenerator: """ return disc(&random_negative_binomial, self._brng, size, self.lock, 2, 0, - n, 'n', CONS_POSITIVE, - p, 'p', CONS_BOUNDED_0_1, - 0.0, '', CONS_NONE) + n, 'n', CONS_POSITIVE, + p, 'p', CONS_BOUNDED_0_1, + 0.0, '', CONS_NONE) def poisson(self, lam=1.0, size=None): """ @@ -3488,9 +3361,9 @@ cdef class RandomGenerator: """ return disc(&random_poisson, self._brng, size, self.lock, 1, 0, - lam, 'lam', CONS_POISSON, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE) + lam, 'lam', CONS_POISSON, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) def zipf(self, a, size=None): """ @@ -3567,9 +3440,9 @@ cdef class RandomGenerator: """ return disc(&random_zipf, self._brng, size, self.lock, 1, 0, - a, 'a', CONS_GT_1, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE) + a, 'a', CONS_GT_1, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) def geometric(self, p, size=None): """ @@ -3618,9 +3491,9 @@ cdef class RandomGenerator: """ return disc(&random_geometric, self._brng, size, self.lock, 1, 0, - p, 'p', CONS_BOUNDED_GT_0_1, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE) + p, 'p', CONS_BOUNDED_GT_0_1, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) def hypergeometric(self, ngood, nbad, nsample, size=None): """ @@ -3631,7 +3504,7 @@ cdef class RandomGenerator: Samples are drawn from a hypergeometric distribution with specified parameters, `ngood` (ways to make a good selection), `nbad` (ways to make a bad selection), and `nsample` (number of items sampled, which is less - than or equal to the sum ``ngood + nbad``) + than or equal to the sum ``ngood + nbad``). Parameters ---------- @@ -3727,12 +3600,6 @@ cdef class RandomGenerator: lnbad = nbad lnsample = nsample - if lngood < 0: - raise ValueError("ngood < 0") - if lnbad < 0: - raise ValueError("nbad < 0") - if lnsample < 1: - raise ValueError("nsample < 1") if lngood + lnbad < lnsample: raise ValueError("ngood + nbad < nsample") return disc(&random_hypergeometric, self._brng, size, self.lock, 0, 3, @@ -3740,7 +3607,7 @@ cdef class RandomGenerator: lnbad, 'nbad', CONS_NON_NEGATIVE, lnsample, 'nsample', CONS_GTE_1) - if np.any(np.less(np.add(ongood, onbad),onsample)): + if np.any(np.less(np.add(ongood, onbad), onsample)): raise ValueError("ngood + nbad < nsample") return discrete_broadcast_iii(&random_hypergeometric, self._brng, size, self.lock, ongood, 'ngood', CONS_NON_NEGATIVE, @@ -3858,7 +3725,7 @@ cdef class RandomGenerator: Behavior when the covariance matrix is not positive semidefinite. tol : float, optional Tolerance when checking the singular values in covariance matrix. - `cov` is cast to double before the check. + cov is cast to double before the check. Returns ------- @@ -3927,7 +3794,7 @@ cdef class RandomGenerator: standard deviation: >>> list((x[0,0,:] - mean) < 0.6) - [True, False] # random + [True, True] # random """ from numpy.dual import svd @@ -3943,11 +3810,11 @@ cdef class RandomGenerator: shape = size if len(mean.shape) != 1: - raise ValueError("mean must be 1 dimensional") + raise ValueError("mean must be 1 dimensional") if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): - raise ValueError("cov must be 2 dimensional and square") + raise ValueError("cov must be 2 dimensional and square") if mean.shape[0] != cov.shape[0]: - raise ValueError("mean and cov must have same length") + raise ValueError("mean and cov must have same length") # Compute shape of output and create a matrix of independent # standard normally distributed random numbers. The matrix has rows @@ -3977,17 +3844,15 @@ cdef class RandomGenerator: if check_valid != 'ignore': if check_valid != 'warn' and check_valid != 'raise': - raise ValueError( - "check_valid must equal 'warn', 'raise', or 'ignore'") + raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) if not psd: if check_valid == 'warn': warnings.warn("covariance is not positive-semidefinite.", - RuntimeWarning) + RuntimeWarning) else: - raise ValueError( - "covariance is not positive-semidefinite.") + raise ValueError("covariance is not positive-semidefinite.") x = np.dot(x, np.sqrt(s)[:, None] * v) x += mean @@ -4036,15 +3901,15 @@ cdef class RandomGenerator: Throw a dice 20 times: >>> np.random.multinomial(20, [1/6.]*6, size=1) - array([[2, 5, 3, 3, 3, 4]]) # random + array([[4, 1, 7, 5, 2, 1]]) # random It landed 4 times on 1, once on 2, etc. Now, throw the dice 20 times, and 20 times again: >>> np.random.multinomial(20, [1/6.]*6, size=2) - array([[5, 2, 1, 2, 5, 5], - [5, 3, 4, 4, 2, 2]]) # random + array([[3, 4, 3, 3, 4, 3], + [2, 4, 3, 4, 0, 7]]) # random For the first run, we threw 3 times 1, 4 times 2, etc. For the second, we threw 2 times 1, 4 times 2, etc. @@ -4061,7 +3926,7 @@ cdef class RandomGenerator: other should be sampled like so: >>> np.random.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT - array([38, 62]) # random + array([38, 62]) # random not like: @@ -4192,39 +4057,36 @@ cdef class RandomGenerator: """ - #================= + # ================= # Pure python algo - #================= - #alpha = N.atleast_1d(alpha) - #k = alpha.size - - #if n == 1: - # val = N.zeros(k) - # for i in range(k): - # val[i] = sgamma(alpha[i], n) - # val /= N.sum(val) - #else: - # val = N.zeros((k, n)) - # for i in range(k): - # val[i] = sgamma(alpha[i], n) - # val /= N.sum(val, axis = 0) - # val = val.T - - #return val - - cdef np.npy_intp k - cdef np.npy_intp totsize - cdef np.ndarray alpha_arr, val_arr - cdef double *alpha_data - cdef double *val_data - cdef np.npy_intp i, j - cdef double acc, invacc - - k = len(alpha) - alpha_arr = np.PyArray_FROM_OTF(alpha, np.NPY_DOUBLE, np.NPY_ALIGNED) + # ================= + # alpha = N.atleast_1d(alpha) + # k = alpha.size + + # if n == 1: + # val = N.zeros(k) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val) + # else: + # val = N.zeros((k, n)) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val, axis = 0) + # val = val.T + # return val + + cdef np.npy_intp k, totsize, i, j + cdef np.ndarray alpha_arr, val_arr + cdef double *alpha_data + cdef double *val_data + cdef double acc, invacc + + k = len(alpha) + alpha_arr = np.PyArray_FROM_OTF(alpha, np.NPY_DOUBLE, np.NPY_ALIGNED) if np.any(np.less_equal(alpha_arr, 0)): raise ValueError('alpha <= 0') - alpha_data = np.PyArray_DATA(alpha_arr) + alpha_data = np.PyArray_DATA(alpha_arr) if size is None: shape = (k,) @@ -4234,7 +4096,7 @@ cdef class RandomGenerator: except: shape = tuple(size) + (k,) - diric = np.zeros(shape, np.float64) + diric = np.zeros(shape, np.float64) val_arr = diric val_data= np.PyArray_DATA(val_arr) @@ -4246,10 +4108,10 @@ cdef class RandomGenerator: for j in range(k): val_data[i+j] = random_standard_gamma_zig(self._brng, alpha_data[j]) - acc = acc + val_data[i + j] - invacc = 1/acc + acc = acc + val_data[i + j] + invacc = 1/acc for j in range(k): - val_data[i + j] = val_data[i + j] * invacc + val_data[i + j] = val_data[i + j] * invacc i = i + k return diric @@ -4307,7 +4169,7 @@ cdef class RandomGenerator: # of bytes for the swaps to avoid leaving one of the objects # within the buffer and erroneously decrementing it's refcount # when the function exits. - buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit + buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit buf_ptr = buf.ctypes.data with self.lock: # We trick gcc into providing a specialized implementation for @@ -4318,11 +4180,13 @@ cdef class RandomGenerator: else: self._shuffle_raw(n, itemsize, stride, x_ptr, buf_ptr) elif isinstance(x, np.ndarray) and x.ndim and x.size: - buf = np.empty_like(x[0,...]) + buf = np.empty_like(x[0, ...]) with self.lock: for i in reversed(range(1, n)): j = random_interval(self._brng, i) - if i == j : continue # i == j is not needed and memcpy is undefined. + if i == j: + # i == j is not needed and memcpy is undefined. + continue buf[...] = x[j] x[j] = x[i] x[i] = buf @@ -4431,9 +4295,7 @@ rand = _random_generator.rand randint = _random_generator.randint randn = _random_generator.randn random_integers = _random_generator.random_integers -random_raw = _random_generator.random_raw random_sample = _random_generator.random_sample -random_uintegers = _random_generator.random_uintegers rayleigh = _random_generator.rayleigh shuffle = _random_generator.shuffle standard_cauchy = _random_generator.standard_cauchy diff --git a/numpy/random/randomgen/legacy/__init__.py b/numpy/random/randomgen/legacy/__init__.py index 01f0c13121e6..9ce1f665dd15 100644 --- a/numpy/random/randomgen/legacy/__init__.py +++ b/numpy/random/randomgen/legacy/__init__.py @@ -1,3 +1,3 @@ -from .legacy import LegacyGenerator +from ..mtrand import RandomState as LegacyGenerator __all__ = ['LegacyGenerator'] diff --git a/numpy/random/randomgen/legacy/_legacy.pyx b/numpy/random/randomgen/legacy/_legacy.pyx deleted file mode 100644 index 1b2168374a10..000000000000 --- a/numpy/random/randomgen/legacy/_legacy.pyx +++ /dev/null @@ -1,2263 +0,0 @@ -#!python -#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3 -from __future__ import absolute_import - -import warnings -import operator - -from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer -from libc.stdlib cimport malloc, free -cimport numpy as np -import numpy as np -cimport cython - -try: - from threading import Lock -except ImportError: - from dummy_threading import Lock - -from ..bounded_integers cimport (_rand_int32, _rand_int64, _rand_int16, - _rand_uint32, _rand_uint64, _rand_uint16, - _rand_bool, _rand_int8, _rand_uint8) -from ..common cimport (cont, disc, double_fill, CONS_NONE, CONS_POSITIVE, - CONS_NON_NEGATIVE, CONS_BOUNDED_0_1) -from ..distributions cimport brng_t, random_double_fill -from .legacy_distributions cimport (aug_brng_t, legacy_beta, legacy_pareto, - legacy_exponential, legacy_f, legacy_chisquare, legacy_gamma, - legacy_gauss, legacy_standard_exponential, legacy_negative_binomial, - legacy_normal, legacy_standard_gamma, legacy_standard_cauchy, - legacy_standard_t, legacy_noncentral_f, legacy_noncentral_chisquare, - legacy_negative_binomial, legacy_power, legacy_lognormal, legacy_wald, - legacy_weibull) -from ..xoroshiro128 import Xoroshiro128 - -np.import_array() - -_randint_types = {'bool': (0, 2), - 'int8': (-2**7, 2**7), - 'int16': (-2**15, 2**15), - 'int32': (-2**31, 2**31), - 'int64': (-2**63, 2**63), - 'uint8': (0, 2**8), - 'uint16': (0, 2**16), - 'uint32': (0, 2**32), - 'uint64': (0, 2**64) - } - - -cdef class _LegacyGenerator: - """ - _LegacyGenerator(brng=None) - - Container providing legacy generators. - - ``_LegacyGenerator`` exposes a number of methods for generating random - numbers for a set of distributions where the method used to produce random - samples has changed. Three core generators have changed: normal, exponential - and gamma. These have been replaced by faster Ziggurat-based methods in - ``RandomGenerator``. ``_LegacyGenerator`` retains the slower methods - to produce samples from these distributions as well as from distributions - that depend on these such as the Chi-square, power or Weibull. - - **No Compatibility Guarantee** - - ``_LegacyGenerator`` is evolving and so it isn't possible to provide a - compatibility guarantee like NumPy does. In particular, better algorithms - have already been added. This will change once ``RandomGenerator`` - stabilizes. - - Parameters - ---------- - brng : Basic RNG, optional - Basic RNG to use as the core generator. If none is provided, uses - Xoroshiro128. - - Examples - -------- - Exactly reproducing a NumPy stream requires both a ``RandomGenerator`` - and a ``_LegacyGenerator``. These must share a common ``MT19937`` basic - RNG. Functions that are available in LegacyGenerator must be called - from ``_LegacyGenerator``, and other functions must be called from - ``RandomGenerator``. - - >>> from numpy.random.randomgen import RandomGenerator, MT19937 - >>> from numpy.random.randomgen.legacy._legacy import _LegacyGenerator - >>> mt = MT19937(12345) - >>> lg = _LegacyGenerator(mt) - >>> rg = RandomGenerator(mt) - >>> x = lg.standard_normal(10) - >>> rg.shuffle(x) - >>> x[0] - 0.09290787674371767 - >>> lg.standard_exponential() - 1.6465621229906502 - - The equivalent commands from NumPy produce identical output. - - >>> from numpy.random import RandomState - >>> rs = RandomState(12345) - >>> x = rs.standard_normal(10) - >>> rs.shuffle(x) - >>> x[0] - 0.09290787674371767 - >>> rs.standard_exponential() - 1.6465621229906502 - """ - cdef public object _basicrng - cdef brng_t *_brng - cdef aug_brng_t *_aug_state - cdef object lock - - def __init__(self, brng=None): - if brng is None: - brng = Xoroshiro128() - self._basicrng = brng - - capsule = brng.capsule - cdef const char *name = "BasicRNG" - if not PyCapsule_IsValid(capsule, name): - raise ValueError("Invalid brng. The brng must be instantized.") - self._brng = PyCapsule_GetPointer(capsule, name) - self._aug_state = malloc(sizeof(aug_brng_t)) - self._aug_state.basicrng = self._brng - self._reset_gauss() - self.lock = Lock() - - def __dealloc__(self): - free(self._aug_state) - - def __repr__(self): - return self.__str__() + ' at 0x{:X}'.format(id(self)) - - def __str__(self): - return self.__class__.__name__ + '(' + self._basicrng.__class__.__name__ + ')' - - # Pickling support: - def __getstate__(self): - return self.state - - def __setstate__(self, state): - self.state = state - - def __reduce__(self): - from .._pickle import __legacy_ctor - return (__legacy_ctor, - (self.state['brng'],), - self.state) - - cdef _reset_gauss(self): - self._aug_state.has_gauss = 0 - self._aug_state.gauss = 0.0 - - def seed(self, *args, **kwargs): - """ - Reseed the basic RNG. - - Parameters depend on the basic RNG used. - - Notes - ----- - Arguments are directly passed to the basic RNG. This is a convenience - function. - - The best method to access seed is to directly use a basic RNG instance. - This example demonstrates this best practice. - - >>> from numpy.random.randomgen import MT19937 - >>> from numpy.random.randomgen.legacy import LegacyGenerator - >>> brng = MT19937(123456789) - >>> lg = brng.generator - >>> brng.seed(987654321) - - The method used to create the generator is not important. - - >>> brng = MT19937(123456789) - >>> lg = LegacyGenerator(brng) - >>> brng.seed(987654321) - - These best practice examples are equivalent to - - >>> lg = LegacyGenerator(MT19937(123456789)) - >>> lg.seed(987654321) - """ - - # TODO: Should this remain - self._basicrng.seed(*args, **kwargs) - self._reset_gauss() - - @property - def state(self): - """ - Get or set the augmented state - - Returns the basic RNGs state as well as two values added to track - normal generation using the Polar (Box-Muller-like) method. - - Returns - ------- - state : dict - Dictionary containing the information required to describe the - state of the Basic RNG with two additional fields, gauss and - has_gauss, required to store generated Polar transformation - (Box-Muller-like) normals. - """ - st = self._basicrng.state - st['has_gauss'] = self._aug_state.has_gauss - st['gauss'] = self._aug_state.gauss - return st - - @state.setter - def state(self, value): - if isinstance(value, (tuple, list)): - if value[0] != 'MT19937': - raise ValueError('tuple only supported for MT19937') - st = {'brng': value[0], - 'state': {'key': value[1], 'pos': value[2]}} - if len(value) > 3: - st['has_gauss'] = value[3] - st['gauss'] = value[4] - value = st - self._aug_state.gauss = value.get('gauss', 0.0) - self._aug_state.has_gauss = value.get('has_gauss', 0) - self._basicrng.state = value - - def get_state(self): - """ - get_state() - Return a tuple representing the internal state of the generator. - For more details, see `set_state`. - Returns - ------- - out : tuple(str, ndarray of 624 uints, int, int, float) - The returned tuple has the following items: - 1. the string 'MT19937'. - 2. a 1-D array of 624 unsigned integer keys. - 3. an integer ``pos``. - 4. an integer ``has_gauss``. - 5. a float ``cached_gaussian``. - See Also - -------- - set_state - Notes - ----- - `set_state` and `get_state` are not needed to work with any of the - random distributions in NumPy. If the internal state is manually altered, - the user should know exactly what he/she is doing. - """ - st = self._basicrng.state - if st['brng'] != 'MT19937': - raise RuntimeError('get_state can only be used with the MT19937 ' - 'basic RNG. When using other basic RNGs, ' - 'use `state`.') - st['has_gauss'] = self._aug_state.has_gauss - st['gauss'] = self._aug_state.gauss - - return (st['brng'], st['state']['key'], st['state']['pos'], - st['has_gauss'], st['gauss']) - - def set_state(self, state): - """ - set_state(state) - Set the internal state of the generator from a tuple. - For use if one has reason to manually (re-)set the internal state of the - "Mersenne Twister"[1]_ pseudo-random number generating algorithm. - Parameters - ---------- - state : tuple(str, ndarray of 624 uints, int, int, float) - The `state` tuple has the following items: - 1. the string 'MT19937', specifying the Mersenne Twister algorithm. - 2. a 1-D array of 624 unsigned integers ``keys``. - 3. an integer ``pos``. - 4. an integer ``has_gauss``. - 5. a float ``cached_gaussian``. - Returns - ------- - out : None - Returns 'None' on success. - See Also - -------- - get_state - Notes - ----- - `set_state` and `get_state` are not needed to work with any of the - random distributions in NumPy. If the internal state is manually altered, - the user should know exactly what he/she is doing. - For backwards compatibility, the form (str, array of 624 uints, int) is - also accepted although it is missing some information about the cached - Gaussian value: ``state = ('MT19937', keys, pos)``. - References - ---------- - .. [1] M. Matsumoto and T. Nishimura, "Mersenne Twister: A - 623-dimensionally equidistributed uniform pseudorandom number - generator," *ACM Trans. on Modeling and Computer Simulation*, - Vol. 8, No. 1, pp. 3-30, Jan. 1998. - """ - if not isinstance(state, (tuple, list)): - raise TypeError('state must be a tuple when using set_state. ' - 'Use `state` to set the state using a dictionary.') - if state[0] != 'MT19937': - raise ValueError('set_state can only be used with legacy MT19937' - 'state instances.') - st = {'brng': state[0], - 'state': {'key': state[1], 'pos': state[2]}} - if len(state) > 3: - st['has_gauss'] = state[3] - st['gauss'] = state[4] - self._aug_state.gauss = st.get('gauss', 0.0) - self._aug_state.has_gauss = st.get('has_gauss', 0) - self._basicrng.state = st - - def random_sample(self, size=None): - """ - random_sample(size=None) - Return random floats in the half-open interval [0.0, 1.0). - Results are from the "continuous uniform" distribution over the - stated interval. To sample :math:`Unif[a, b), b > a` multiply - the output of `random_sample` by `(b-a)` and add `a`:: - (b - a) * random_sample() + a - Parameters - ---------- - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - Returns - ------- - out : float or ndarray of floats - Array of random floats of shape `size` (unless ``size=None``, in which - case a single float is returned). - Examples - -------- - np.random.random_sample() - 0.47108547995356098 - type(np.random.random_sample()) - - np.random.random_sample((5,)) - array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) - Three-by-two array of random numbers from [-5, 0): - 5 * np.random.random_sample((3, 2)) - 5 - array([[-3.99149989, -0.52338984], - [-2.99091858, -0.79479508], - [-1.23204345, -1.75224494]]) - """ - cdef double temp - return double_fill(&random_double_fill, self._brng, size, self.lock, None) - - def beta(self, a, b, size=None): - """ - beta(a, b, size=None) - - Draw samples from a Beta distribution. - - The Beta distribution is a special case of the Dirichlet distribution, - and is related to the Gamma distribution. It has the probability - distribution function - - .. math:: f(x; a,b) = \\frac{1}{B(\\alpha, \\beta)} x^{\\alpha - 1} - (1 - x)^{\\beta - 1}, - - where the normalization, B, is the beta function, - - .. math:: B(\\alpha, \\beta) = \\int_0^1 t^{\\alpha - 1} - (1 - t)^{\\beta - 1} dt. - - It is often seen in Bayesian inference and order statistics. - - Parameters - ---------- - a : float or array_like of floats - Alpha, positive (>0). - b : float or array_like of floats - Beta, positive (>0). - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``a`` and ``b`` are both scalars. - Otherwise, ``np.broadcast(a, b).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized beta distribution. - - """ - return cont(&legacy_beta, self._aug_state, size, self.lock, 2, - a, 'a', CONS_POSITIVE, - b, 'b', CONS_POSITIVE, - 0.0, '', CONS_NONE, None) - - def exponential(self, scale=1.0, size=None): - """ - exponential(scale=1.0, size=None) - - Draw samples from an exponential distribution. - - Its probability density function is - - .. math:: f(x; \\frac{1}{\\beta}) = \\frac{1}{\\beta} \\exp(-\\frac{x}{\\beta}), - - for ``x > 0`` and 0 elsewhere. :math:`\\beta` is the scale parameter, - which is the inverse of the rate parameter :math:`\\lambda = 1/\\beta`. - The rate parameter is an alternative, widely used parameterization - of the exponential distribution [3]_. - - The exponential distribution is a continuous analogue of the - geometric distribution. It describes many common situations, such as - the size of raindrops measured over many rainstorms [1]_, or the time - between page requests to Wikipedia [2]_. - - Parameters - ---------- - scale : float or array_like of floats - The scale parameter, :math:`\\beta = 1/\\lambda`. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``scale`` is a scalar. Otherwise, - ``np.array(scale).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized exponential distribution. - - References - ---------- - .. [1] Peyton Z. Peebles Jr., "Probability, Random Variables and - Random Signal Principles", 4th ed, 2001, p. 57. - .. [2] Wikipedia, "Poisson process", - https://en.wikipedia.org/wiki/Poisson_process - .. [3] Wikipedia, "Exponential distribution", - https://en.wikipedia.org/wiki/Exponential_distribution - - """ - return cont(&legacy_exponential, self._aug_state, size, self.lock, 1, - scale, 'scale', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, - None) - - def standard_exponential(self, size=None): - """ - standard_exponential(size=None) - - Draw samples from the standard exponential distribution. - - `standard_exponential` is identical to the exponential distribution - with a scale parameter of 1. - - Parameters - ---------- - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - - Returns - ------- - out : float or ndarray - Drawn samples. - - Examples - -------- - Output a 3x8000 array: - - >>> n = np.random.standard_exponential((3, 8000)) - """ - return cont(&legacy_standard_exponential, self._aug_state, size, self.lock, 0, - None, None, CONS_NONE, - None, None, CONS_NONE, - None, None, CONS_NONE, - None) - - def randint(self, low, high=None, size=None, dtype=int): - """ - randint(low, high=None, size=None, dtype='l') - Return random integers from `low` (inclusive) to `high` (exclusive). - Return random integers from the "discrete uniform" distribution of - the specified dtype in the "half-open" interval [`low`, `high`). If - `high` is None (the default), then results are from [0, `low`). - Parameters - ---------- - low : int or array-like of ints - Lowest (signed) integers to be drawn from the distribution (unless - ``high=None``, in which case this parameter is one above the - *highest* such integer). - high : int or array-like of ints, optional - If provided, one above the largest (signed) integer to be drawn - from the distribution (see above for behavior if ``high=None``). - If array-like, must contain integer values - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - dtype : {str, dtype}, optional - Desired dtype of the result. All dtypes are determined by their - name, i.e., 'int64', 'int', etc, so byteorder is not available - and a specific precision may have different C types depending - on the platform. The default value is 'np.int'. - .. versionadded:: 1.11.0 - Returns - ------- - out : int or ndarray of ints - `size`-shaped array of random integers from the appropriate - distribution, or a single such random int if `size` not provided. - See Also - -------- - random.random_integers : similar to `randint`, only for the closed - interval [`low`, `high`], and 1 is the lowest value if `high` is - omitted. In particular, this other one is the one to use to generate - uniformly distributed discrete non-integers. - Examples - -------- - >>> np.random.randint(2, size=10) - array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) # random - >>> np.random.randint(1, size=10) - array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) # random - Generate a 2 x 4 array of ints between 0 and 4, inclusive: - >>> np.random.randint(5, size=(2, 4)) - array([[4, 0, 2, 1], # random - [3, 2, 2, 0]]) - Generate a 1 x 3 array with 3 different upper bounds - >>> np.random.randint(1, [3, 5, 10]) - array([2, 2, 9]) # random - Generate a 1 by 3 array with 3 different lower bounds - >>> np.random.randint([1, 5, 7], 10) - array([9, 8, 7]) # random - Generate a 2 by 4 array using broadcasting with dtype of uint8 - >>> np.random.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) - array([[ 8, 6, 9, 7], # random - [ 1, 16, 9, 12]], dtype=uint8) - """ - cdef bint use_masked=1 - - if high is None: - high = low - low = 0 - - key = np.dtype(dtype).name - if not key in _randint_types: - raise TypeError('Unsupported dtype "%s" for randint' % key) - - if key == 'int32': - ret = _rand_int32(low, high, size, use_masked, self._brng, self.lock) - elif key == 'int64': - ret = _rand_int64(low, high, size, use_masked, self._brng, self.lock) - elif key == 'int16': - ret = _rand_int16(low, high, size, use_masked, self._brng, self.lock) - elif key == 'int8': - ret = _rand_int8(low, high, size, use_masked, self._brng, self.lock) - elif key == 'uint64': - ret = _rand_uint64(low, high, size, use_masked, self._brng, self.lock) - elif key == 'uint32': - ret = _rand_uint32(low, high, size, use_masked, self._brng, self.lock) - elif key == 'uint16': - ret = _rand_uint16(low, high, size, use_masked, self._brng, self.lock) - elif key == 'uint8': - ret = _rand_uint8(low, high, size, use_masked, self._brng, self.lock) - elif key == 'bool': - ret = _rand_bool(low, high, size, use_masked, self._brng, self.lock) - - if size is None and dtype in (np.bool, np.int, np.long): - if np.array(ret).shape == (): - return dtype(ret) - return ret - - def rand(self, *args): - """ - rand(d0, d1, ..., dn) - Random values in a given shape. - Create an array of the given shape and populate it with - random samples from a uniform distribution - over ``[0, 1)``. - Parameters - ---------- - d0, d1, ..., dn : int, optional - The dimensions of the returned array, should all be positive. - If no argument is given a single Python float is returned. - Returns - ------- - out : ndarray, shape ``(d0, d1, ..., dn)`` - Random values. - See Also - -------- - random - Notes - ----- - This is a convenience function. If you want an interface that - takes a shape-tuple as the first argument, refer to - np.random.random_sample . - Examples - -------- - >>> np.random.rand(3,2) - array([[ 0.14022471, 0.96360618], #random - [ 0.37601032, 0.25528411], #random - [ 0.49313049, 0.94909878]]) #random - """ - if len(args) == 0: - return self.random_sample() - else: - return self.random_sample(size=args) - - def randn(self, *args): - """ - randn(d0, d1, ..., dn) - - Return a sample (or samples) from the "standard normal" distribution. - - If positive, int_like or int-convertible arguments are provided, - `randn` generates an array of shape ``(d0, d1, ..., dn)``, filled - with random floats sampled from a univariate "normal" (Gaussian) - distribution of mean 0 and variance 1 (if any of the :math:`d_i` are - floats, they are first converted to integers by truncation). A single - float randomly sampled from the distribution is returned if no - argument is provided. - - This is a convenience function. If you want an interface that takes a - tuple as the first argument, use `standard_normal` instead. - - Parameters - ---------- - d0, d1, ..., dn : int, optional - The dimensions of the returned array, should be all positive. - If no argument is given a single Python float is returned. - - Returns - ------- - Z : ndarray or float - A ``(d0, d1, ..., dn)``-shaped array of floating-point samples from - the standard normal distribution, or a single such float if - no parameters were supplied. - - See Also - -------- - standard_normal : Similar, but takes a tuple as its argument. - - Notes - ----- - For random samples from :math:`N(\\mu, \\sigma^2)`, use: - - ``sigma * np.random.randn(...) + mu`` - - Examples - -------- - >>> np.random.randn() - 2.1923875335537315 #random - - Two-by-four array of samples from N(3, 6.25): - - >>> 2.5 * np.random.randn(2, 4) + 3 - array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random - [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random - - """ - if len(args) == 0: - return self.standard_normal() - else: - return self.standard_normal(size=args) - - # Complicated, continuous distributions: - def standard_normal(self, size=None): - """ - standard_normal(size=None) - - Draw samples from a standard Normal distribution (mean=0, stdev=1). - - Parameters - ---------- - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - - Returns - ------- - out : float or ndarray - Drawn samples. - - Examples - -------- - >>> s = np.random.standard_normal(8000) - >>> s - array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random - -0.38672696, -0.4685006 ]) #random - >>> s.shape - (8000,) - >>> s = np.random.standard_normal(size=(3, 4, 2)) - >>> s.shape - (3, 4, 2) - - """ - return cont(&legacy_gauss, self._aug_state, size, self.lock, 0, - None, None, CONS_NONE, - None, None, CONS_NONE, - None, None, CONS_NONE, - None) - - def normal(self, loc=0.0, scale=1.0, size=None): - """ - normal(loc=0.0, scale=1.0, size=None) - - Draw random samples from a normal (Gaussian) distribution. - - The probability density function of the normal distribution, first - derived by De Moivre and 200 years later by both Gauss and Laplace - independently [2]_, is often called the bell curve because of - its characteristic shape (see the example below). - - The normal distributions occurs often in nature. For example, it - describes the commonly occurring distribution of samples influenced - by a large number of tiny, random disturbances, each with its own - unique distribution [2]_. - - Parameters - ---------- - loc : float or array_like of floats - Mean ("centre") of the distribution. - scale : float or array_like of floats - Standard deviation (spread or "width") of the distribution. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``loc`` and ``scale`` are both scalars. - Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized normal distribution. - - See Also - -------- - scipy.stats.norm : probability density function, distribution or - cumulative density function, etc. - - Notes - ----- - The probability density for the Gaussian distribution is - - .. math:: p(x) = \\frac{1}{\\sqrt{ 2 \\pi \\sigma^2 }} - e^{ - \\frac{ (x - \\mu)^2 } {2 \\sigma^2} }, - - where :math:`\\mu` is the mean and :math:`\\sigma` the standard - deviation. The square of the standard deviation, :math:`\\sigma^2`, - is called the variance. - - The function has its peak at the mean, and its "spread" increases with - the standard deviation (the function reaches 0.607 times its maximum at - :math:`x + \\sigma` and :math:`x - \\sigma` [2]_). This implies that - `numpy.random.normal` is more likely to return samples lying close to - the mean, rather than those far away. - - References - ---------- - .. [1] Wikipedia, "Normal distribution", - https://en.wikipedia.org/wiki/Normal_distribution - .. [2] P. R. Peebles Jr., "Central Limit Theorem" in "Probability, - Random Variables and Random Signal Principles", 4th ed., 2001, - pp. 51, 51, 125. - - Examples - -------- - Draw samples from the distribution: - - >>> mu, sigma = 0, 0.1 # mean and standard deviation - >>> s = np.random.normal(mu, sigma, 1000) - - Verify the mean and the variance: - - >>> abs(mu - np.mean(s)) < 0.01 - True - - >>> abs(sigma - np.std(s, ddof=1)) < 0.01 - True - - Display the histogram of the samples, along with - the probability density function: - - >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, 30, density=True) - >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * - ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ), - ... linewidth=2, color='r') - >>> plt.show() - - """ - return cont(&legacy_normal, self._aug_state, size, self.lock, 2, - loc, '', CONS_NONE, - scale, 'scale', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, - None) - - def standard_gamma(self, shape, size=None): - """ - standard_gamma(shape, size=None) - - Draw samples from a standard Gamma distribution. - - Samples are drawn from a Gamma distribution with specified parameters, - shape (sometimes designated "k") and scale=1. - - Parameters - ---------- - shape : float or array_like of floats - Parameter, should be > 0. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``shape`` is a scalar. Otherwise, - ``np.array(shape).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized standard gamma distribution. - - See Also - -------- - scipy.stats.gamma : probability density function, distribution or - cumulative density function, etc. - - Notes - ----- - The probability density for the Gamma distribution is - - .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, - - where :math:`k` is the shape and :math:`\\theta` the scale, - and :math:`\\Gamma` is the Gamma function. - - The Gamma distribution is often used to model the times to failure of - electronic components, and arises naturally in processes for which the - waiting times between Poisson distributed events are relevant. - - References - ---------- - .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A - Wolfram Web Resource. - http://mathworld.wolfram.com/GammaDistribution.html - .. [2] Wikipedia, "Gamma distribution", - https://en.wikipedia.org/wiki/Gamma_distribution - - Examples - -------- - Draw samples from the distribution: - - >>> shape, scale = 2., 1. # mean and width - >>> s = np.random.standard_gamma(shape, 1000000) - - Display the histogram of the samples, along with - the probability density function: - - >>> import matplotlib.pyplot as plt - >>> import scipy.special as sps - >>> count, bins, ignored = plt.hist(s, 50, density=True) - >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ - ... (sps.gamma(shape) * scale**shape)) - >>> plt.plot(bins, y, linewidth=2, color='r') - >>> plt.show() - """ - return cont(&legacy_standard_gamma, self._aug_state, size, self.lock, 1, - shape, 'shape', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, - None) - - def gamma(self, shape, scale=1.0, size=None): - """ - gamma(shape, scale=1.0, size=None) - - Draw samples from a Gamma distribution. - - Samples are drawn from a Gamma distribution with specified parameters, - `shape` (sometimes designated "k") and `scale` (sometimes designated - "theta"), where both parameters are > 0. - - Parameters - ---------- - shape : float or array_like of floats - The shape of the gamma distribution. Should be greater than zero. - scale : float or array_like of floats, optional - The scale of the gamma distribution. Should be greater than zero. - Default is equal to 1. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``shape`` and ``scale`` are both scalars. - Otherwise, ``np.broadcast(shape, scale).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized gamma distribution. - - See Also - -------- - scipy.stats.gamma : probability density function, distribution or - cumulative density function, etc. - - Notes - ----- - The probability density for the Gamma distribution is - - .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, - - where :math:`k` is the shape and :math:`\\theta` the scale, - and :math:`\\Gamma` is the Gamma function. - - The Gamma distribution is often used to model the times to failure of - electronic components, and arises naturally in processes for which the - waiting times between Poisson distributed events are relevant. - - References - ---------- - .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A - Wolfram Web Resource. - http://mathworld.wolfram.com/GammaDistribution.html - .. [2] Wikipedia, "Gamma distribution", - https://en.wikipedia.org/wiki/Gamma_distribution - - Examples - -------- - Draw samples from the distribution: - - >>> shape, scale = 2., 2. # mean and dispersion - >>> s = np.random.gamma(shape, scale, 1000) - - Display the histogram of the samples, along with - the probability density function: - - >>> import matplotlib.pyplot as plt - >>> import scipy.special as sps - >>> count, bins, ignored = plt.hist(s, 50, density=True) - >>> y = bins**(shape-1)*(np.exp(-bins/scale) / - ... (sps.gamma(shape)*scale**shape)) - >>> plt.plot(bins, y, linewidth=2, color='r') - >>> plt.show() - - """ - return cont(&legacy_gamma, self._aug_state, size, self.lock, 2, - shape, 'shape', CONS_NON_NEGATIVE, - scale, 'scale', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, None) - - def f(self, dfnum, dfden, size=None): - """ - f(dfnum, dfden, size=None) - - Draw samples from an F distribution. - - Samples are drawn from an F distribution with specified parameters, - `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of - freedom in denominator), where both parameters should be greater than - zero. - - The random variate of the F distribution (also known as the - Fisher distribution) is a continuous probability distribution - that arises in ANOVA tests, and is the ratio of two chi-square - variates. - - Parameters - ---------- - dfnum : int or array_like of ints - Degrees of freedom in numerator. Should be greater than zero. - dfden : int or array_like of ints - Degrees of freedom in denominator. Should be greater than zero. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``dfnum`` and ``dfden`` are both scalars. - Otherwise, ``np.broadcast(dfnum, dfden).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized Fisher distribution. - - See Also - -------- - scipy.stats.f : probability density function, distribution or - cumulative density function, etc. - - Notes - ----- - The F statistic is used to compare in-group variances to between-group - variances. Calculating the distribution depends on the sampling, and - so it is a function of the respective degrees of freedom in the - problem. The variable `dfnum` is the number of samples minus one, the - between-groups degrees of freedom, while `dfden` is the within-groups - degrees of freedom, the sum of the number of samples in each group - minus the number of groups. - - References - ---------- - .. [1] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, - Fifth Edition, 2002. - .. [2] Wikipedia, "F-distribution", - https://en.wikipedia.org/wiki/F-distribution - - Examples - -------- - An example from Glantz[1], pp 47-40: - - Two groups, children of diabetics (25 people) and children from people - without diabetes (25 controls). Fasting blood glucose was measured, - case group had a mean value of 86.1, controls had a mean value of - 82.2. Standard deviations were 2.09 and 2.49 respectively. Are these - data consistent with the null hypothesis that the parents diabetic - status does not affect their children's blood glucose levels? - Calculating the F statistic from the data gives a value of 36.01. - - Draw samples from the distribution: - - >>> dfnum = 1. # between group degrees of freedom - >>> dfden = 48. # within groups degrees of freedom - >>> s = np.random.f(dfnum, dfden, 1000) - - The lower bound for the top 1% of the samples is : - - >>> np.sort(s)[-10] - 7.61988120985 # random - - So there is about a 1% chance that the F statistic will exceed 7.62, - the measured value is 36, so the null hypothesis is rejected at the 1% - level. - - """ - return cont(&legacy_f, self._aug_state, size, self.lock, 2, - dfnum, 'dfnum', CONS_POSITIVE, - dfden, 'dfden', CONS_POSITIVE, - 0.0, '', CONS_NONE, None) - - def noncentral_f(self, dfnum, dfden, nonc, size=None): - """ - noncentral_f(dfnum, dfden, nonc, size=None) - - Draw samples from the noncentral F distribution. - - Samples are drawn from an F distribution with specified parameters, - `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of - freedom in denominator), where both parameters > 1. - `nonc` is the non-centrality parameter. - - Parameters - ---------- - dfnum : int or array_like of ints - Parameter, should be > 1. - dfden : int or array_like of ints - Parameter, should be > 1. - nonc : float or array_like of floats - Parameter, should be >= 0. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``dfnum``, ``dfden``, and ``nonc`` - are all scalars. Otherwise, ``np.broadcast(dfnum, dfden, nonc).size`` - samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized noncentral Fisher distribution. - - Notes - ----- - When calculating the power of an experiment (power = probability of - rejecting the null hypothesis when a specific alternative is true) the - non-central F statistic becomes important. When the null hypothesis is - true, the F statistic follows a central F distribution. When the null - hypothesis is not true, then it follows a non-central F statistic. - - References - ---------- - .. [1] Weisstein, Eric W. "Noncentral F-Distribution." - From MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/NoncentralF-Distribution.html - .. [2] Wikipedia, "Noncentral F-distribution", - https://en.wikipedia.org/wiki/Noncentral_F-distribution - - Examples - -------- - In a study, testing for a specific alternative to the null hypothesis - requires use of the Noncentral F distribution. We need to calculate the - area in the tail of the distribution that exceeds the value of the F - distribution for the null hypothesis. We'll plot the two probability - distributions for comparison. - - >>> dfnum = 3 # between group deg of freedom - >>> dfden = 20 # within groups degrees of freedom - >>> nonc = 3.0 - >>> nc_vals = np.random.noncentral_f(dfnum, dfden, nonc, 1000000) - >>> NF = np.histogram(nc_vals, bins=50, density=True) - >>> c_vals = np.random.f(dfnum, dfden, 1000000) - >>> F = np.histogram(c_vals, bins=50, density=True) - >>> import matplotlib.pyplot as plt - >>> plt.plot(F[1][1:], F[0]) - >>> plt.plot(NF[1][1:], NF[0]) - >>> plt.show() - - """ - return cont(&legacy_noncentral_f, self._aug_state, size, self.lock, 3, - dfnum, 'dfnum', CONS_POSITIVE, - dfden, 'dfden', CONS_POSITIVE, - nonc, 'nonc', CONS_NON_NEGATIVE, None) - - def chisquare(self, df, size=None): - """ - chisquare(df, size=None) - - Draw samples from a chi-square distribution. - - When `df` independent random variables, each with standard normal - distributions (mean 0, variance 1), are squared and summed, the - resulting distribution is chi-square (see Notes). This distribution - is often used in hypothesis testing. - - Parameters - ---------- - df : int or array_like of ints - Number of degrees of freedom. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``df`` is a scalar. Otherwise, - ``np.array(df).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized chi-square distribution. - - Raises - ------ - ValueError - When `df` <= 0 or when an inappropriate `size` (e.g. ``size=-1``) - is given. - - Notes - ----- - The variable obtained by summing the squares of `df` independent, - standard normally distributed random variables: - - .. math:: Q = \\sum_{i=0}^{\\mathtt{df}} X^2_i - - is chi-square distributed, denoted - - .. math:: Q \\sim \\chi^2_k. - - The probability density function of the chi-squared distribution is - - .. math:: p(x) = \\frac{(1/2)^{k/2}}{\\Gamma(k/2)} - x^{k/2 - 1} e^{-x/2}, - - where :math:`\\Gamma` is the gamma function, - - .. math:: \\Gamma(x) = \\int_0^{-\\infty} t^{x - 1} e^{-t} dt. - - References - ---------- - .. [1] NIST "Engineering Statistics Handbook" - https://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm - - Examples - -------- - >>> np.random.chisquare(2,4) - array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) # random - - """ - return cont(&legacy_chisquare, self._aug_state, size, self.lock, 1, - df, 'df', CONS_POSITIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, None) - - def noncentral_chisquare(self, df, nonc, size=None): - """ - noncentral_chisquare(df, nonc, size=None) - - Draw samples from a noncentral chi-square distribution. - - The noncentral :math:`\\chi^2` distribution is a generalisation of - the :math:`\\chi^2` distribution. - - Parameters - ---------- - df : int or array_like of ints - Degrees of freedom, should be > 0 as of NumPy 1.10.0, - should be > 1 for earlier versions. - nonc : float or array_like of floats - Non-centrality, should be non-negative. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``df`` and ``nonc`` are both scalars. - Otherwise, ``np.broadcast(df, nonc).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized noncentral chi-square distribution. - - Notes - ----- - The probability density function for the noncentral Chi-square - distribution is - - .. math:: P(x;df,nonc) = \\sum^{\\infty}_{i=0} - \\frac{e^{-nonc/2}(nonc/2)^{i}}{i!} - \\P_{Y_{df+2i}}(x), - - where :math:`Y_{q}` is the Chi-square with q degrees of freedom. - - References - ---------- - .. [1] Wikipedia, "Noncentral chi-square distribution" - https://en.wikipedia.org/wiki/Noncentral_chi-square_distribution - - Examples - -------- - Draw values from the distribution and plot the histogram - - >>> import matplotlib.pyplot as plt - >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), - ... bins=200, density=True) - >>> plt.show() - - Draw values from a noncentral chisquare with very small noncentrality, - and compare to a chisquare. - - >>> plt.figure() - >>> values = plt.hist(np.random.noncentral_chisquare(3, .0000001, 100000), - ... bins=np.arange(0., 25, .1), density=True) - >>> values2 = plt.hist(np.random.chisquare(3, 100000), - ... bins=np.arange(0., 25, .1), density=True) - >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') - >>> plt.show() - - Demonstrate how large values of non-centrality lead to a more symmetric - distribution. - - >>> plt.figure() - >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), - ... bins=200, density=True) - >>> plt.show() - - """ - return cont(&legacy_noncentral_chisquare, self._aug_state, size, self.lock, 2, - df, 'df', CONS_POSITIVE, - nonc, 'nonc', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, None) - - def standard_cauchy(self, size=None): - """ - standard_cauchy(size=None) - - Draw samples from a standard Cauchy distribution with mode = 0. - - Also known as the Lorentz distribution. - - Parameters - ---------- - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - - Returns - ------- - samples : ndarray or scalar - The drawn samples. - - Notes - ----- - The probability density function for the full Cauchy distribution is - - .. math:: P(x; x_0, \\gamma) = \\frac{1}{\\pi \\gamma \\bigl[ 1+ - (\\frac{x-x_0}{\\gamma})^2 \\bigr] } - - and the Standard Cauchy distribution just sets :math:`x_0=0` and - :math:`\\gamma=1` - - The Cauchy distribution arises in the solution to the driven harmonic - oscillator problem, and also describes spectral line broadening. It - also describes the distribution of values at which a line tilted at - a random angle will cut the x axis. - - When studying hypothesis tests that assume normality, seeing how the - tests perform on data from a Cauchy distribution is a good indicator of - their sensitivity to a heavy-tailed distribution, since the Cauchy looks - very much like a Gaussian distribution, but with heavier tails. - - References - ---------- - .. [1] NIST/SEMATECH e-Handbook of Statistical Methods, "Cauchy - Distribution", - http://www.itl.nist.gov/div898/handbook/eda/section3/eda3663.htm - .. [2] Weisstein, Eric W. "Cauchy Distribution." From MathWorld--A - Wolfram Web Resource. - http://mathworld.wolfram.com/CauchyDistribution.html - .. [3] Wikipedia, "Cauchy distribution" - https://en.wikipedia.org/wiki/Cauchy_distribution - - Examples - -------- - Draw samples and plot the distribution: - - >>> s = np.random.standard_cauchy(1000000) - >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well - >>> import matplotlib.pyplot as plt - >>> plt.hist(s, bins=100) - >>> plt.show() - - """ - return cont(&legacy_standard_cauchy, self._aug_state, size, self.lock, 0, - 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) - - def standard_t(self, df, size=None): - """ - standard_t(df, size=None) - - Draw samples from a standard Student's t distribution with `df` degrees - of freedom. - - A special case of the hyperbolic distribution. As `df` gets - large, the result resembles that of the standard normal - distribution (`standard_normal`). - - Parameters - ---------- - df : int or array_like of ints - Degrees of freedom, should be > 0. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``df`` is a scalar. Otherwise, - ``np.array(df).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized standard Student's t distribution. - - Notes - ----- - The probability density function for the t distribution is - - .. math:: P(x, df) = \\frac{\\Gamma(\\frac{df+1}{2})}{\\sqrt{\\pi df} - \\Gamma(\\frac{df}{2})}\\Bigl( 1+\\frac{x^2}{df} \\Bigr)^{-(df+1)/2} - - The t test is based on an assumption that the data come from a - Normal distribution. The t test provides a way to test whether - the sample mean (that is the mean calculated from the data) is - a good estimate of the true mean. - - The derivation of the t-distribution was first published in - 1908 by William Gosset while working for the Guinness Brewery - in Dublin. Due to proprietary issues, he had to publish under - a pseudonym, and so he used the name Student. - - References - ---------- - .. [1] Dalgaard, Peter, "Introductory Statistics With R", - Springer, 2002. - .. [2] Wikipedia, "Student's t-distribution" - https://en.wikipedia.org/wiki/Student's_t-distribution - - Examples - -------- - From Dalgaard page 83 [1]_, suppose the daily energy intake for 11 - women in kilojoules (kJ) is: - - >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\ - ... 7515, 8230, 8770]) - - Does their energy intake deviate systematically from the recommended - value of 7725 kJ? - - We have 10 degrees of freedom, so is the sample mean within 95% of the - recommended value? - - >>> s = np.random.standard_t(10, size=100000) - >>> np.mean(intake) - 6753.636363636364 - >>> intake.std(ddof=1) - 1142.1232221373727 - - Calculate the t statistic, setting the ddof parameter to the unbiased - value so the divisor in the standard deviation will be degrees of - freedom, N-1. - - >>> t = (np.mean(intake)-7725)/(intake.std(ddof=1)/np.sqrt(len(intake))) - >>> import matplotlib.pyplot as plt - >>> h = plt.hist(s, bins=100, density=True) - - For a one-sided t-test, how far out in the distribution does the t - statistic appear? - - >>> np.sum(s>> a, m = 3., 2. # shape and mode - >>> s = (np.random.pareto(a, 1000) + 1) * m - - Display the histogram of the samples, along with the probability - density function: - - >>> import matplotlib.pyplot as plt - >>> count, bins, _ = plt.hist(s, 100, density=True) - >>> fit = a*m**a / bins**(a+1) - >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r') - >>> plt.show() - - """ - return cont(&legacy_pareto, self._aug_state, size, self.lock, 1, - a, 'a', CONS_POSITIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, None) - - def weibull(self, a, size=None): - """ - weibull(a, size=None) - - Draw samples from a Weibull distribution. - - Draw samples from a 1-parameter Weibull distribution with the given - shape parameter `a`. - - .. math:: X = (-ln(U))^{1/a} - - Here, U is drawn from the uniform distribution over (0,1]. - - The more common 2-parameter Weibull, including a scale parameter - :math:`\\lambda` is just :math:`X = \\lambda(-ln(U))^{1/a}`. - - Parameters - ---------- - a : float or array_like of floats - Shape parameter of the distribution. Must be nonnegative. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``a`` is a scalar. Otherwise, - ``np.array(a).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized Weibull distribution. - - See Also - -------- - scipy.stats.weibull_max - scipy.stats.weibull_min - scipy.stats.genextreme - gumbel - - Notes - ----- - The Weibull (or Type III asymptotic extreme value distribution - for smallest values, SEV Type III, or Rosin-Rammler - distribution) is one of a class of Generalized Extreme Value - (GEV) distributions used in modeling extreme value problems. - This class includes the Gumbel and Frechet distributions. - - The probability density for the Weibull distribution is - - .. math:: p(x) = \\frac{a} - {\\lambda}(\\frac{x}{\\lambda})^{a-1}e^{-(x/\\lambda)^a}, - - where :math:`a` is the shape and :math:`\\lambda` the scale. - - The function has its peak (the mode) at - :math:`\\lambda(\\frac{a-1}{a})^{1/a}`. - - When ``a = 1``, the Weibull distribution reduces to the exponential - distribution. - - References - ---------- - .. [1] Waloddi Weibull, Royal Technical University, Stockholm, - 1939 "A Statistical Theory Of The Strength Of Materials", - Ingeniorsvetenskapsakademiens Handlingar Nr 151, 1939, - Generalstabens Litografiska Anstalts Forlag, Stockholm. - .. [2] Waloddi Weibull, "A Statistical Distribution Function of - Wide Applicability", Journal Of Applied Mechanics ASME Paper - 1951. - .. [3] Wikipedia, "Weibull distribution", - https://en.wikipedia.org/wiki/Weibull_distribution - - Examples - -------- - Draw samples from the distribution: - - >>> a = 5. # shape - >>> s = np.random.weibull(a, 1000) - - Display the histogram of the samples, along with - the probability density function: - - >>> import matplotlib.pyplot as plt - >>> x = np.arange(1,100.)/50. - >>> def weib(x,n,a): - ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) - - >>> count, bins, ignored = plt.hist(np.random.weibull(5.,1000)) - >>> x = np.arange(1,100.)/50. - >>> scale = count.max()/weib(x, 1., 5.).max() - >>> plt.plot(x, weib(x, 1., 5.)*scale) - >>> plt.show() - - """ - return cont(&legacy_weibull, self._aug_state, size, self.lock, 1, - a, 'a', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, None) - - def power(self, a, size=None): - """ - power(a, size=None) - - Draws samples in [0, 1] from a power distribution with positive - exponent a - 1. - - Also known as the power function distribution. - - Parameters - ---------- - a : float or array_like of floats - Parameter of the distribution. Should be greater than zero. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``a`` is a scalar. Otherwise, - ``np.array(a).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized power distribution. - - Raises - ------ - ValueError - If a < 1. - - Notes - ----- - The probability density function is - - .. math:: P(x; a) = ax^{a-1}, 0 \\le x \\le 1, a>0. - - The power function distribution is just the inverse of the Pareto - distribution. It may also be seen as a special case of the Beta - distribution. - - It is used, for example, in modeling the over-reporting of insurance - claims. - - References - ---------- - .. [1] Christian Kleiber, Samuel Kotz, "Statistical size distributions - in economics and actuarial sciences", Wiley, 2003. - .. [2] Heckert, N. A. and Filliben, James J. "NIST Handbook 148: - Dataplot Reference Manual, Volume 2: Let Subcommands and Library - Functions", National Institute of Standards and Technology - Handbook Series, June 2003. - http://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf - - Examples - -------- - Draw samples from the distribution: - - >>> a = 5. # shape - >>> samples = 1000 - >>> s = np.random.power(a, samples) - - Display the histogram of the samples, along with - the probability density function: - - >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, bins=30) - >>> x = np.linspace(0, 1, 100) - >>> y = a*x**(a-1.) - >>> normed_y = samples*np.diff(bins)[0]*y - >>> plt.plot(x, normed_y) - >>> plt.show() - - Compare the power function distribution to the inverse of the Pareto. - - >>> from scipy import stats - >>> rvs = np.random.power(5, 1000000) - >>> rvsp = np.random.pareto(5, 1000000) - >>> xx = np.linspace(0,1,100) - >>> powpdf = stats.powerlaw.pdf(xx,5) - - >>> plt.figure() - >>> plt.hist(rvs, bins=50, density=True) - >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('np.random.power(5)') - - >>> plt.figure() - >>> plt.hist(1./(1.+rvsp), bins=50, density=True) - >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('inverse of 1 + np.random.pareto(5)') - - >>> plt.figure() - >>> plt.hist(1./(1.+rvsp), bins=50, density=True) - >>> plt.plot(xx,powpdf,'r-') - >>> plt.title('inverse of stats.pareto(5)') - - """ - return cont(&legacy_power, self._aug_state, size, self.lock, 1, - a, 'a', CONS_POSITIVE, - 0.0, '', CONS_NONE, - 0.0, '', CONS_NONE, None) - - def lognormal(self, mean=0.0, sigma=1.0, size=None): - """ - lognormal(mean=0.0, sigma=1.0, size=None) - - Draw samples from a log-normal distribution. - - Draw samples from a log-normal distribution with specified mean, - standard deviation, and array shape. Note that the mean and standard - deviation are not the values for the distribution itself, but of the - underlying normal distribution it is derived from. - - Parameters - ---------- - mean : float or array_like of floats, optional - Mean value of the underlying normal distribution. Default is 0. - sigma : float or array_like of floats, optional - Standard deviation of the underlying normal distribution. Should - be greater than zero. Default is 1. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``mean`` and ``sigma`` are both scalars. - Otherwise, ``np.broadcast(mean, sigma).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized log-normal distribution. - - See Also - -------- - scipy.stats.lognorm : probability density function, distribution, - cumulative density function, etc. - - Notes - ----- - A variable `x` has a log-normal distribution if `log(x)` is normally - distributed. The probability density function for the log-normal - distribution is: - - .. math:: p(x) = \\frac{1}{\\sigma x \\sqrt{2\\pi}} - e^{(-\\frac{(ln(x)-\\mu)^2}{2\\sigma^2})} - - where :math:`\\mu` is the mean and :math:`\\sigma` is the standard - deviation of the normally distributed logarithm of the variable. - A log-normal distribution results if a random variable is the *product* - of a large number of independent, identically-distributed variables in - the same way that a normal distribution results if the variable is the - *sum* of a large number of independent, identically-distributed - variables. - - References - ---------- - .. [1] Limpert, E., Stahel, W. A., and Abbt, M., "Log-normal - Distributions across the Sciences: Keys and Clues," - BioScience, Vol. 51, No. 5, May, 2001. - https://stat.ethz.ch/~stahel/lognormal/bioscience.pdf - .. [2] Reiss, R.D. and Thomas, M., "Statistical Analysis of Extreme - Values," Basel: Birkhauser Verlag, 2001, pp. 31-32. - - Examples - -------- - Draw samples from the distribution: - - >>> mu, sigma = 3., 1. # mean and standard deviation - >>> s = np.random.lognormal(mu, sigma, 1000) - - Display the histogram of the samples, along with - the probability density function: - - >>> import matplotlib.pyplot as plt - >>> count, bins, ignored = plt.hist(s, 100, density=True, align='mid') - - >>> x = np.linspace(min(bins), max(bins), 10000) - >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) - ... / (x * sigma * np.sqrt(2 * np.pi))) - - >>> plt.plot(x, pdf, linewidth=2, color='r') - >>> plt.axis('tight') - >>> plt.show() - - Demonstrate that taking the products of random samples from a uniform - distribution can be fit well by a log-normal probability density - function. - - >>> # Generate a thousand samples: each is the product of 100 random - >>> # values, drawn from a normal distribution. - >>> b = [] - >>> for i in range(1000): - ... a = 10. + np.random.randn(100) - ... b.append(np.product(a)) - - >>> b = np.array(b) / np.min(b) # scale values to be positive - >>> count, bins, ignored = plt.hist(b, 100, density=True, align='mid') - >>> sigma = np.std(np.log(b)) - >>> mu = np.mean(np.log(b)) - - >>> x = np.linspace(min(bins), max(bins), 10000) - >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) - ... / (x * sigma * np.sqrt(2 * np.pi))) - - >>> plt.plot(x, pdf, color='r', linewidth=2) - >>> plt.show() - - """ - return cont(&legacy_lognormal, self._aug_state, size, self.lock, 2, - mean, 'mean', CONS_NONE, - sigma, 'sigma', CONS_NON_NEGATIVE, - 0.0, '', CONS_NONE, None) - - def wald(self, mean, scale, size=None): - """ - wald(mean, scale, size=None) - - Draw samples from a Wald, or inverse Gaussian, distribution. - - As the scale approaches infinity, the distribution becomes more like a - Gaussian. Some references claim that the Wald is an inverse Gaussian - with mean equal to 1, but this is by no means universal. - - The inverse Gaussian distribution was first studied in relationship to - Brownian motion. In 1956 M.C.K. Tweedie used the name inverse Gaussian - because there is an inverse relationship between the time to cover a - unit distance and distance covered in unit time. - - Parameters - ---------- - mean : float or array_like of floats - Distribution mean, must be > 0. - scale : float or array_like of floats - Scale parameter, must be > 0. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``mean`` and ``scale`` are both scalars. - Otherwise, ``np.broadcast(mean, scale).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized Wald distribution. - - Notes - ----- - The probability density function for the Wald distribution is - - .. math:: P(x;mean,scale) = \\sqrt{\\frac{scale}{2\\pi x^3}}e^ - \\frac{-scale(x-mean)^2}{2\\cdotp mean^2x} - - As noted above the inverse Gaussian distribution first arise - from attempts to model Brownian motion. It is also a - competitor to the Weibull for use in reliability modeling and - modeling stock returns and interest rate processes. - - References - ---------- - .. [1] Brighton Webs Ltd., Wald Distribution, - https://web.archive.org/web/20090423014010/http://www.brighton-webs.co.uk:80/distributions/wald.asp - .. [2] Chhikara, Raj S., and Folks, J. Leroy, "The Inverse Gaussian - Distribution: Theory : Methodology, and Applications", CRC Press, - 1988. - .. [3] Wikipedia, "Wald distribution" - https://en.wikipedia.org/wiki/Wald_distribution - - Examples - -------- - Draw values from the distribution and plot the histogram: - - >>> import matplotlib.pyplot as plt - >>> h = plt.hist(np.random.wald(3, 2, 100000), bins=200, density=True) - >>> plt.show() - - """ - return cont(&legacy_wald, self._aug_state, size, self.lock, 2, - mean, 'mean', CONS_POSITIVE, - scale, 'scale', CONS_POSITIVE, - 0.0, '', CONS_NONE, None) - - - - def negative_binomial(self, n, p, size=None): - """ - negative_binomial(n, p, size=None) - - Draw samples from a negative binomial distribution. - - Samples are drawn from a negative binomial distribution with specified - parameters, `n` successes and `p` probability of success where `n` is an - integer > 0 and `p` is in the interval [0, 1]. - - Parameters - ---------- - n : int or array_like of ints - Parameter of the distribution, > 0. Floats are also accepted, - but they will be truncated to integers. - p : float or array_like of floats - Parameter of the distribution, >= 0 and <=1. - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``n`` and ``p`` are both scalars. - Otherwise, ``np.broadcast(n, p).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized negative binomial distribution, - where each sample is equal to N, the number of failures that - occurred before a total of n successes was reached. - - Notes - ----- - The probability density for the negative binomial distribution is - - .. math:: P(N;n,p) = \\binom{N+n-1}{N}p^{n}(1-p)^{N}, - - where :math:`n` is the number of successes, :math:`p` is the - probability of success, and :math:`N+n` is the number of trials. - The negative binomial distribution gives the probability of N - failures given n successes, with a success on the last trial. - - If one throws a die repeatedly until the third time a "1" appears, - then the probability distribution of the number of non-"1"s that - appear before the third "1" is a negative binomial distribution. - - References - ---------- - .. [1] Weisstein, Eric W. "Negative Binomial Distribution." From - MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/NegativeBinomialDistribution.html - .. [2] Wikipedia, "Negative binomial distribution", - https://en.wikipedia.org/wiki/Negative_binomial_distribution - - Examples - -------- - Draw samples from the distribution: - - A real world example. A company drills wild-cat oil - exploration wells, each with an estimated probability of - success of 0.1. What is the probability of having one success - for each successive well, that is what is the probability of a - single success after drilling 5 wells, after 6 wells, etc.? - - >>> s = np.random.negative_binomial(1, 0.9, 100000) - >>> for i in range(1, 11): # doctest: +SKIP - ... probability = sum(s>> mean = [0, 0] - >>> cov = [[1, 0], [0, 100]] # diagonal covariance - - Diagonal covariance means that points are oriented along x or y-axis: - - >>> import matplotlib.pyplot as plt - >>> x, y = np.random.multivariate_normal(mean, cov, 5000).T - >>> plt.plot(x, y, 'x') - >>> plt.axis('equal') - >>> plt.show() - - Note that the covariance matrix must be positive semidefinite (a.k.a. - nonnegative-definite). Otherwise, the behavior of this method is - undefined and backwards compatibility is not guaranteed. - - References - ---------- - .. [1] Papoulis, A., "Probability, Random Variables, and Stochastic - Processes," 3rd ed., New York: McGraw-Hill, 1991. - .. [2] Duda, R. O., Hart, P. E., and Stork, D. G., "Pattern - Classification," 2nd ed., New York: Wiley, 2001. - - Examples - -------- - >>> mean = (1, 2) - >>> cov = [[1, 0], [0, 1]] - >>> x = np.random.multivariate_normal(mean, cov, (3, 3)) - >>> x.shape - (3, 3, 2) - - The following is probably true, given that 0.6 is roughly twice the - standard deviation: - - >>> list((x[0,0,:] - mean) < 0.6) - [True, True] # random - - """ - from numpy.dual import svd - - # Check preconditions on arguments - mean = np.array(mean) - cov = np.array(cov) - if size is None: - shape = [] - elif isinstance(size, (int, long, np.integer)): - shape = [size] - else: - shape = size - - if len(mean.shape) != 1: - raise ValueError("mean must be 1 dimensional") - if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): - raise ValueError("cov must be 2 dimensional and square") - if mean.shape[0] != cov.shape[0]: - raise ValueError("mean and cov must have same length") - - # Compute shape of output and create a matrix of independent - # standard normally distributed random numbers. The matrix has rows - # with the same length as mean and as many rows are necessary to - # form a matrix of shape final_shape. - final_shape = list(shape[:]) - final_shape.append(mean.shape[0]) - x = self.standard_normal(final_shape).reshape(-1, mean.shape[0]) - - # Transform matrix of standard normals into matrix where each row - # contains multivariate normals with the desired covariance. - # Compute A such that dot(transpose(A),A) == cov. - # Then the matrix products of the rows of x and A has the desired - # covariance. Note that sqrt(s)*v where (u,s,v) is the singular value - # decomposition of cov is such an A. - # - # Also check that cov is positive-semidefinite. If so, the u.T and v - # matrices should be equal up to roundoff error if cov is - # symmetric and the singular value of the corresponding row is - # not zero. We continue to use the SVD rather than Cholesky in - # order to preserve current outputs. Note that symmetry has not - # been checked. - - # GH10839, ensure double to make tol meaningful - cov = cov.astype(np.double) - (u, s, v) = svd(cov) - - if check_valid != 'ignore': - if check_valid != 'warn' and check_valid != 'raise': - raise ValueError( - "check_valid must equal 'warn', 'raise', or 'ignore'") - - psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) - if not psd: - if check_valid == 'warn': - warnings.warn("covariance is not positive-semidefinite.", - RuntimeWarning) - else: - raise ValueError( - "covariance is not positive-semidefinite.") - - x = np.dot(x, np.sqrt(s)[:, None] * v) - x += mean - x.shape = tuple(final_shape) - return x - - def dirichlet(self, object alpha, size=None): - """ - dirichlet(alpha, size=None) - - Draw samples from the Dirichlet distribution. - - Draw `size` samples of dimension k from a Dirichlet distribution. A - Dirichlet-distributed random variable can be seen as a multivariate - generalization of a Beta distribution. The Dirichlet distribution - is a conjugate prior of a multinomial distribution in Bayesian - inference. - - Parameters - ---------- - alpha : array - Parameter of the distribution (k dimension for sample of - dimension k). - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. Default is None, in which case a - single value is returned. - - Returns - ------- - samples : ndarray, - The drawn samples, of shape (size, alpha.ndim). - - Raises - ------- - ValueError - If any value in alpha is less than or equal to zero - - Notes - ----- - The Dirichlet distribution is a distribution over vectors - :math:`x` that fulfil the conditions :math:`x_i>0` and - :math:`\\sum_{i=1}^k x_i = 1`. - - The probability density function :math:`p` of a - Dirichlet-distributed random vector :math:`X` is - proportional to - - .. math:: p(x) \\propto \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i}, - - where :math:`\\alpha` is a vector containing the positive - concentration parameters. - - The method uses the following property for computation: let :math:`Y` - be a random vector which has components that follow a standard gamma - distribution, then :math:`X = \\frac{1}{\\sum_{i=1}^k{Y_i}} Y` - is Dirichlet-distributed - - References - ---------- - .. [1] David McKay, "Information Theory, Inference and Learning - Algorithms," chapter 23, - http://www.inference.org.uk/mackay/itila/ - .. [2] Wikipedia, "Dirichlet distribution", - https://en.wikipedia.org/wiki/Dirichlet_distribution - - Examples - -------- - Taking an example cited in Wikipedia, this distribution can be used if - one wanted to cut strings (each of initial length 1.0) into K pieces - with different lengths, where each piece had, on average, a designated - average length, but allowing some variation in the relative sizes of - the pieces. - - >>> s = np.random.dirichlet((10, 5, 3), 20).transpose() - - >>> import matplotlib.pyplot as plt - >>> plt.barh(range(20), s[0]) - >>> plt.barh(range(20), s[1], left=s[0], color='g') - >>> plt.barh(range(20), s[2], left=s[0]+s[1], color='r') - >>> plt.title("Lengths of Strings") - - """ - - #================= - # Pure python algo - #================= - #alpha = N.atleast_1d(alpha) - #k = alpha.size - - #if n == 1: - # val = N.zeros(k) - # for i in range(k): - # val[i] = sgamma(alpha[i], n) - # val /= N.sum(val) - #else: - # val = N.zeros((k, n)) - # for i in range(k): - # val[i] = sgamma(alpha[i], n) - # val /= N.sum(val, axis = 0) - # val = val.T - - #return val - - cdef np.npy_intp k - cdef np.npy_intp totsize - cdef np.ndarray alpha_arr, val_arr - cdef double *alpha_data - cdef double *val_data - cdef np.npy_intp i, j - cdef double acc, invacc - - k = len(alpha) - alpha_arr = np.PyArray_FROM_OTF(alpha, np.NPY_DOUBLE, np.NPY_ALIGNED) - if np.any(np.less_equal(alpha_arr, 0)): - raise ValueError('alpha <= 0') - alpha_data = np.PyArray_DATA(alpha_arr) - - if size is None: - shape = (k,) - else: - try: - shape = (operator.index(size), k) - except: - shape = tuple(size) + (k,) - - diric = np.zeros(shape, np.float64) - val_arr = diric - val_data= np.PyArray_DATA(val_arr) - - i = 0 - totsize = np.PyArray_SIZE(val_arr) - with self.lock, nogil: - while i < totsize: - acc = 0.0 - for j in range(k): - val_data[i+j] = legacy_standard_gamma(self._aug_state, - alpha_data[j]) - acc = acc + val_data[i + j] - invacc = 1/acc - for j in range(k): - val_data[i + j] = val_data[i + j] * invacc - i = i + k - - return diric diff --git a/numpy/random/randomgen/legacy/legacy.py b/numpy/random/randomgen/legacy/legacy.py deleted file mode 100644 index bb0d0c721475..000000000000 --- a/numpy/random/randomgen/legacy/legacy.py +++ /dev/null @@ -1,130 +0,0 @@ -from ..generator import RandomGenerator -from ..mt19937 import MT19937 -from ._legacy import _LegacyGenerator - -# Attributes in RandomGenerator that should not appear in LegacyGenerator -_HIDDEN_ATTRIBUTES = ['complex_normal', 'random_raw', 'random_uintegers'] - -_LEGACY_ATTRIBUTES = tuple(a for a in dir( - - _LegacyGenerator) if not a.startswith('_')) - -_LEGACY_ATTRIBUTES += ('__getstate__', '__setstate__', '__reduce__') - - - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - - # From six, https://raw.githubusercontent.com/benjaminp/six - class metaclass(type): - - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - - @classmethod - def __prepare__(cls, name, this_bases): - return meta.__prepare__(name, bases) - return type.__new__(metaclass, 'temporary_class', (), {}) - - -class LegacyGeneratorType(type): - def __getattribute__(self, name): - if name in _LEGACY_ATTRIBUTES: - return object.__getattribute__(_LegacyGenerator, name) - return object.__getattribute__(RandomGenerator, name) - - -class LegacyGenerator(with_metaclass(LegacyGeneratorType, RandomGenerator)): - """ - LegacyGenerator(brng=None) - - Container providing legacy generators. - - ``LegacyGenerator`` exposes a number of methods for generating random - numbers for a set of distributions where the method used to produce random - samples has changed. Three core generators have changed: normal, - exponential and gamma. These have been replaced by faster Ziggurat-based - methods in ``RadnomGenerator``. ``LegacyGenerator`` retains the slower - methods to produce samples from these distributions as well as from - distributions that depend on these such as the Chi-square, power or - Weibull. - - **No Compatibility Guarantee** - - ``LegacyGenerator`` is evolving and so it isn't possible to provide a - compatibility guarantee like NumPy does. In particular, better algorithms - have already been added. This will change once ``RandomGenerator`` - stabilizes. - - Parameters - ---------- - brng : Basic RNG, optional - Basic RNG to use as the core generator. If none is provided, uses - MT19937. - - - Examples - -------- - Exactly reproducing a NumPy stream requires using ``MT19937`` as - the Basic RNG. - - >>> from randomgen import MT19937 - >>> lg = LegacyGenerator(MT19937(12345)) - >>> x = lg.standard_normal(10) - >>> lg.shuffle(x) - >>> x[0] - 0.09290787674371767 - >>> lg.standard_exponential() - 1.6465621229906502 - - The equivalent commands from NumPy produce identical output. - - >>> from numpy.random import RandomState - >>> rs = RandomState(12345) - >>> x = rs.standard_normal(10) - >>> rs.shuffle(x) - >>> x[0] - 0.09290787674371767 - >>> rs.standard_exponential() - 1.6465621229906502 - """ - - __atttributes = sorted(set(dir(_LegacyGenerator) + - dir(RandomGenerator)).difference(_HIDDEN_ATTRIBUTES)) - - def __init__(self, brng=None): - if brng is None: - brng = MT19937() - elif isinstance(brng, MT19937): - pass - else: - brng = MT19937(brng) - super(LegacyGenerator, self).__init__(brng) - self.__legacy = _LegacyGenerator(brng) - - def __getattribute__(self, name): - if name in _HIDDEN_ATTRIBUTES: - raise AttributeError('No attribute {0}'.format(name)) - if name in _LEGACY_ATTRIBUTES: - return self.__legacy.__getattribute__(name) - return object.__getattribute__(self, name) - - def __dir__(self): - return self.__atttributes - - # Pickling support: - def __getstate__(self): - return self.state - - def __setstate__(self, state): - self.state = state - - def __reduce__(self): - from .._pickle import _experiment_ctor - return (_experiment_ctor, - (self.state['brng'],), - self.state) diff --git a/numpy/random/randomgen/legacy/legacy_distributions.pxd b/numpy/random/randomgen/legacy/legacy_distributions.pxd index ab33d4a9da5c..bc00994dbacb 100644 --- a/numpy/random/randomgen/legacy/legacy_distributions.pxd +++ b/numpy/random/randomgen/legacy/legacy_distributions.pxd @@ -3,7 +3,7 @@ from libc.stdint cimport uint64_t import numpy as np -cimport numpy as np +cimport numpy as np from ..distributions cimport brng_t @@ -12,7 +12,7 @@ cdef extern from "../src/legacy/distributions-boxmuller.h": struct aug_brng: brng_t *basicrng int has_gauss - double gauss + double gauss ctypedef aug_brng aug_brng_t diff --git a/numpy/random/randomgen/mt19937.pyx b/numpy/random/randomgen/mt19937.pyx index 0e476e53bc75..f6c76e7ab1bd 100644 --- a/numpy/random/randomgen/mt19937.pyx +++ b/numpy/random/randomgen/mt19937.pyx @@ -1,10 +1,13 @@ -from __future__ import absolute_import - import operator from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock + import numpy as np cimport numpy as np @@ -121,11 +124,13 @@ cdef class MT19937: cdef object _ctypes cdef object _cffi cdef object _generator + cdef public object lock def __init__(self, seed=None): self.rng_state = malloc(sizeof(mt19937_state)) self._brng = malloc(sizeof(brng_t)) self.seed(seed) + self.lock = Lock() self._brng.state = self.rng_state self._brng.next_uint64 = &mt19937_uint64 @@ -157,41 +162,39 @@ cdef class MT19937: (self.state['brng'],), self.state) - def __random_integer(self, bits=64): + def random_raw(self, size=None, output=True): """ - 64-bit Random Integers from the PRNG + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG Parameters ---------- - bits : {32, 64} - Number of random bits to return + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. Returns ------- - rv : int - Next random value + out : uint or ndarray + Drawn samples. Notes ----- - Testing only + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. """ - if bits == 64: - return self._brng.next_uint64(self._brng.state) - elif bits == 32: - return self._brng.next_uint32(self._brng.state) - else: - raise ValueError('bits must be 32 or 64') + return random_raw(self._brng, self.lock, size, output) def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - cdef Py_ssize_t i - if method==u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method==u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None): """ @@ -231,9 +234,10 @@ cdef class MT19937: raise ValueError("Seed must be between 0 and 2**32 - 1") mt19937_seed(self.rng_state, seed) except TypeError: - obj = np.asarray(seed).astype(np.int64, casting='safe') + obj = np.asarray(seed) if obj.size == 0: raise ValueError("Seed must be non-empty") + obj = obj.astype(np.int64, casting='safe') if obj.ndim != 1: raise ValueError("Seed array must be 1-d") if ((obj > int(2**32 - 1)) | (obj < 0)).any(): @@ -278,16 +282,15 @@ cdef class MT19937: key[i] = self.rng_state.key[i] return {'brng': self.__class__.__name__, - 'state': {'key':key, 'pos': self.rng_state.pos}} + 'state': {'key': key, 'pos': self.rng_state.pos}} @state.setter def state(self, value): if isinstance(value, tuple): - if value[0] != 'MT19937' or len(value) not in (3,5): - raise ValueError('state is not a legacy MT19937 state') + if value[0] != 'MT19937' or len(value) not in (3, 5): + raise ValueError('state is not a legacy MT19937 state') value ={'brng': 'MT19937', - 'state':{'key': value[1], 'pos': value[2]}} - + 'state': {'key': value[1], 'pos': value[2]}} if not isinstance(value, dict): raise TypeError('state must be a dict') @@ -303,12 +306,12 @@ cdef class MT19937: @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -317,25 +320,10 @@ cdef class MT19937: * next_double - function pointer to produce doubles * brng - pointer to the Basic RNG struct """ + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&mt19937_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&mt19937_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&mt19937_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) - return self.ctypes + return self._ctypes @property def cffi(self): @@ -356,19 +344,8 @@ cdef class MT19937: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): diff --git a/numpy/random/randomgen/mtrand.pyx b/numpy/random/randomgen/mtrand.pyx new file mode 100644 index 000000000000..41006c56016d --- /dev/null +++ b/numpy/random/randomgen/mtrand.pyx @@ -0,0 +1,4172 @@ +#!python +#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3 +import operator +import warnings +from collections.abc import Mapping +from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer +from cpython cimport (Py_INCREF, PyFloat_AsDouble) +from libc cimport string +from libc.stdlib cimport malloc, free +cimport numpy as np +import numpy as np +cimport cython + +from .bounded_integers cimport * +from .bounded_integers import _randint_types +from .common cimport * +from .distributions cimport * +from .legacy.legacy_distributions cimport * +from .mt19937 import MT19937 as _MT19937 + +np.import_array() + +cdef class RandomState: + """ + RandomState(brng=None) + + Container for the Mersenne Twister pseudo-random number generator. + + `RandomState` exposes a number of methods for generating random numbers + drawn from a variety of probability distributions. In addition to the + distribution-specific arguments, each method takes a keyword argument + `size` that defaults to ``None``. If `size` is ``None``, then a single + value is generated and returned. If `size` is an integer, then a 1-D + array filled with generated values is returned. If `size` is a tuple, + then an array with that shape is filled and returned. + + *Compatibility Guarantee* + A fixed seed and a fixed series of calls to 'RandomState' methods using + the same parameters will always produce the same results up to roundoff + error except when the values were incorrect. Incorrect values will be + fixed and the NumPy version in which the fix was made will be noted in + the relevant docstring. Extension of existing parameter ranges and the + addition of new parameters is allowed as long the previous behavior + remains unchanged. + + Parameters + ---------- + brng : {None, int, array_like, BasicRNG}, optional + Random seed used to initialize the pseudo-random number generator or + an instantized BasicRNG. If an integer or array, used as a seed for + the MT19937 BasicRNG. Values can be any integer between 0 and + 2**32 - 1 inclusive, an array (or other sequence) of such integers, + or ``None`` (the default). If `seed` is ``None``, then the `MT19937` + BasicRNG is initialized by reading data from ``/dev/urandom`` + (or the Windows analogue) if available or seed from the clock + otherwise. + + Notes + ----- + The Python stdlib module "random" also contains a Mersenne Twister + pseudo-random number generator with a number of methods that are similar + to the ones available in `RandomState`. `RandomState`, besides being + NumPy-aware, has the advantage that it provides a much larger number + of probability distributions to choose from. + + """ + cdef public object _basicrng + cdef brng_t *_brng + cdef aug_brng_t *_aug_state + cdef binomial_t *_binomial + cdef object lock + poisson_lam_max = POISSON_LAM_MAX + + def __init__(self, brng=None): + if brng is None: + brng = _MT19937() + elif not hasattr(brng, 'capsule'): + brng = _MT19937(brng) + + self._basicrng = brng + capsule = brng.capsule + cdef const char *name = "BasicRNG" + if not PyCapsule_IsValid(capsule, name): + raise ValueError("Invalid brng. The brng must be instantized.") + self._brng = PyCapsule_GetPointer(capsule, name) + self._aug_state = malloc(sizeof(aug_brng_t)) + self._aug_state.basicrng = self._brng + self._binomial = malloc(sizeof(binomial_t)) + self._reset_gauss() + self.lock = brng.lock + + def __dealloc__(self): + free(self._binomial) + free(self._aug_state) + + def __repr__(self): + return self.__str__() + ' at 0x{:X}'.format(id(self)) + + def __str__(self): + _str = self.__class__.__name__ + _str += '(' + self._basicrng.__class__.__name__ + ')' + return _str + + # Pickling support: + def __getstate__(self): + return self.get_state(legacy=False) + + def __setstate__(self, state): + self.set_state(state) + + def __reduce__(self): + state = self.get_state(legacy=False) + from ._pickle import __randomstate_ctor + return (__randomstate_ctor, + (state['brng'],), + state) + + cdef _reset_gauss(self): + self._aug_state.has_gauss = 0 + self._aug_state.gauss = 0.0 + + def seed(self, *args, **kwargs): + """ + seed(self, *args, **kwargs) + + Reseed the basic RNG. + + Parameters depend on the basic RNG used. + + Notes + ----- + Arguments are directly passed to the basic RNG. This is a convenience + function. + + The best method to access seed is to directly use a basic RNG instance. + This example demonstrates this best practice. + + >>> from np.random.randomgen import MT19937 + >>> from np.random import RandomState + >>> brng = MT19937(123456789) + >>> rs = RandomState(brng) + >>> brng.seed(987654321) + + These best practice examples are equivalent to + + >>> rs = RandomState(MT19937()) + >>> rs.seed(987654321) + """ + self._basicrng.seed(*args, **kwargs) + self._reset_gauss() + return self + + def get_state(self, legacy=True): + """ + get_state() + + Return a tuple representing the internal state of the generator. + + For more details, see `set_state`. + + Returns + ------- + out : {tuple(str, ndarray of 624 uints, int, int, float), dict} + The returned tuple has the following items: + + 1. the string 'MT19937'. + 2. a 1-D array of 624 unsigned integer keys. + 3. an integer ``pos``. + 4. an integer ``has_gauss``. + 5. a float ``cached_gaussian``. + + If `legacy` is False, or the basic RNG is not NT19937, then + state is returned as a dictionary. + + legacy : bool + Flag indicating the return a legacy tuple state when the basic RNG + is MT19937. + + See Also + -------- + set_state + + Notes + ----- + `set_state` and `get_state` are not needed to work with any of the + random distributions in NumPy. If the internal state is manually altered, + the user should know exactly what he/she is doing. + + """ + st = self._basicrng.state + if st['brng'] != 'MT19937' and legacy: + warnings.warn('get_state and legacy can only be used with the ' + 'MT19937 basic RNG. To silence this warning, ' + 'set `legacy` to False.', RuntimeWarning) + legacy = False + st['has_gauss'] = self._aug_state.has_gauss + st['gauss'] = self._aug_state.gauss + if legacy: + return (st['brng'], st['state']['key'], st['state']['pos'], + st['has_gauss'], st['gauss']) + return st + + def set_state(self, state): + """ + set_state(state) + + Set the internal state of the generator from a tuple. + + For use if one has reason to manually (re-)set the internal state of the + "Mersenne Twister"[1]_ pseudo-random number generating algorithm. + + Parameters + ---------- + state : {tuple(str, ndarray of 624 uints, int, int, float), dict} + The `state` tuple has the following items: + + 1. the string 'MT19937', specifying the Mersenne Twister algorithm. + 2. a 1-D array of 624 unsigned integers ``keys``. + 3. an integer ``pos``. + 4. an integer ``has_gauss``. + 5. a float ``cached_gaussian``. + + If state is a dictionary, it is directly set using the BasicRNGs + `state` property. + + Returns + ------- + out : None + Returns 'None' on success. + + See Also + -------- + get_state + + Notes + ----- + `set_state` and `get_state` are not needed to work with any of the + random distributions in NumPy. If the internal state is manually altered, + the user should know exactly what he/she is doing. + + For backwards compatibility, the form (str, array of 624 uints, int) is + also accepted although it is missing some information about the cached + Gaussian value: ``state = ('MT19937', keys, pos)``. + + References + ---------- + .. [1] M. Matsumoto and T. Nishimura, "Mersenne Twister: A + 623-dimensionally equidistributed uniform pseudorandom number + generator," *ACM Trans. on Modeling and Computer Simulation*, + Vol. 8, No. 1, pp. 3-30, Jan. 1998. + + """ + if isinstance(state, Mapping): + if 'brng' not in state or 'state' not in state: + raise ValueError('state dictionary is not valid.') + st = state + else: + if not isinstance(state, (tuple, list)): + raise TypeError('state must be a dict or a tuple.') + if state[0] != 'MT19937': + raise ValueError('set_state can only be used with legacy MT19937' + 'state instances.') + st = {'brng': state[0], + 'state': {'key': state[1], 'pos': state[2]}} + if len(state) > 3: + st['has_gauss'] = state[3] + st['gauss'] = state[4] + value = st + + self._aug_state.gauss = st.get('gauss', 0.0) + self._aug_state.has_gauss = st.get('has_gauss', 0) + self._basicrng.state = st + + def random_sample(self, size=None): + """ + random_sample(size=None) + + Return random floats in the half-open interval [0.0, 1.0). + + Results are from the "continuous uniform" distribution over the + stated interval. To sample :math:`Unif[a, b), b > a` multiply + the output of `random_sample` by `(b-a)` and add `a`:: + + (b - a) * random_sample() + a + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : float or ndarray of floats + Array of random floats of shape `size` (unless ``size=None``, in which + case a single float is returned). + + Examples + -------- + >>> np.random.random_sample() + 0.47108547995356098 # random + >>> type(np.random.random_sample()) + + >>> np.random.random_sample((5,)) + array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) # random + + Three-by-two array of random numbers from [-5, 0): + + >>> 5 * np.random.random_sample((3, 2)) - 5 + array([[-3.99149989, -0.52338984], # random + [-2.99091858, -0.79479508], + [-1.23204345, -1.75224494]]) + + """ + cdef double temp + return double_fill(&random_double_fill, self._brng, size, self.lock, None) + + def beta(self, a, b, size=None): + """ + beta(a, b, size=None) + + Draw samples from a Beta distribution. + + The Beta distribution is a special case of the Dirichlet distribution, + and is related to the Gamma distribution. It has the probability + distribution function + + .. math:: f(x; a,b) = \\frac{1}{B(\\alpha, \\beta)} x^{\\alpha - 1} + (1 - x)^{\\beta - 1}, + + where the normalisation, B, is the beta function, + + .. math:: B(\\alpha, \\beta) = \\int_0^1 t^{\\alpha - 1} + (1 - t)^{\\beta - 1} dt. + + It is often seen in Bayesian inference and order statistics. + + Parameters + ---------- + a : float or array_like of floats + Alpha, positive (>0). + b : float or array_like of floats + Beta, positive (>0). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` and ``b`` are both scalars. + Otherwise, ``np.broadcast(a, b).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized beta distribution. + + """ + return cont(&legacy_beta, self._aug_state, size, self.lock, 2, + a, 'a', CONS_POSITIVE, + b, 'b', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + def exponential(self, scale=1.0, size=None): + """ + exponential(scale=1.0, size=None) + + Draw samples from an exponential distribution. + + Its probability density function is + + .. math:: f(x; \\frac{1}{\\beta}) = \\frac{1}{\\beta} \\exp(-\\frac{x}{\\beta}), + + for ``x > 0`` and 0 elsewhere. :math:`\\beta` is the scale parameter, + which is the inverse of the rate parameter :math:`\\lambda = 1/\\beta`. + The rate parameter is an alternative, widely used parameterization + of the exponential distribution [3]_. + + The exponential distribution is a continuous analogue of the + geometric distribution. It describes many common situations, such as + the size of raindrops measured over many rainstorms [1]_, or the time + between page requests to Wikipedia [2]_. + + Parameters + ---------- + scale : float or array_like of floats + The scale parameter, :math:`\\beta = 1/\\lambda`. Must be + non-negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``scale`` is a scalar. Otherwise, + ``np.array(scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized exponential distribution. + + References + ---------- + .. [1] Peyton Z. Peebles Jr., "Probability, Random Variables and + Random Signal Principles", 4th ed, 2001, p. 57. + .. [2] Wikipedia, "Poisson process", + https://en.wikipedia.org/wiki/Poisson_process + .. [3] Wikipedia, "Exponential distribution", + https://en.wikipedia.org/wiki/Exponential_distribution + + """ + return cont(&legacy_exponential, self._aug_state, size, self.lock, 1, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) + + def standard_exponential(self, size=None): + """ + standard_exponential(size=None) + + Draw samples from the standard exponential distribution. + + `standard_exponential` is identical to the exponential distribution + with a scale parameter of 1. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : float or ndarray + Drawn samples. + + Examples + -------- + Output a 3x8000 array: + + >>> n = np.random.standard_exponential((3, 8000)) + + """ + return cont(&legacy_standard_exponential, self._aug_state, size, self.lock, 0, + None, None, CONS_NONE, + None, None, CONS_NONE, + None, None, CONS_NONE, + None) + + def tomaxint(self, size=None): + """ + tomaxint(size=None) + + Random integers between 0 and ``sys.maxint``, inclusive. + + Return a sample of uniformly distributed random integers in the interval + [0, ``sys.maxint``]. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : ndarray + Drawn samples, with shape `size`. + + See Also + -------- + randint : Uniform sampling over a given half-open interval of integers. + random_integers : Uniform sampling over a given closed interval of + integers. + + Examples + -------- + >>> rs = np.random.RandomState() # need a RandomGenerator object + >>> rs.tomaxint((2,2,2)) + array([[[1170048599, 1600360186], # random + [ 739731006, 1947757578]], + [[1871712945, 752307660], + [1601631370, 1479324245]]]) + >>> import sys + >>> sys.maxint + 2147483647 + >>> rs.tomaxint((2,2,2)) < sys.maxint + array([[[ True, True], + [ True, True]], + [[ True, True], + [ True, True]]]) + + """ + cdef np.npy_intp n + cdef np.ndarray randoms + cdef int64_t *randoms_data + + if size is None: + with self.lock: + return random_positive_int(self._brng) + + randoms = np.empty(size, dtype=np.int64) + randoms_data = np.PyArray_DATA(randoms) + n = np.PyArray_SIZE(randoms) + + for i in range(n): + with self.lock, nogil: + randoms_data[i] = random_positive_int(self._brng) + return randoms + + def randint(self, low, high=None, size=None, dtype=int): + """ + randint(low, high=None, size=None, dtype='l') + + Return random integers from `low` (inclusive) to `high` (exclusive). + + Return random integers from the "discrete uniform" distribution of + the specified dtype in the "half-open" interval [`low`, `high`). If + `high` is None (the default), then results are from [0, `low`). + + Parameters + ---------- + low : int or array-like of ints + Lowest (signed) integers to be drawn from the distribution (unless + ``high=None``, in which case this parameter is one above the + *highest* such integer). + high : int or array-like of ints, optional + If provided, one above the largest (signed) integer to be drawn + from the distribution (see above for behavior if ``high=None``). + If array-like, must contain integer values + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + dtype : {str, dtype}, optional + Desired dtype of the result. All dtypes are determined by their + name, i.e., 'int64', 'int', etc, so byteorder is not available + and a specific precision may have different C types depending + on the platform. The default value is 'np.int'. + + .. versionadded:: 1.11.0 + + Returns + ------- + out : int or ndarray of ints + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + See Also + -------- + random.random_integers : similar to `randint`, only for the closed + interval [`low`, `high`], and 1 is the lowest value if `high` is + omitted. In particular, this other one is the one to use to generate + uniformly distributed discrete non-integers. + + Examples + -------- + >>> np.random.randint(2, size=10) + array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) # random + >>> np.random.randint(1, size=10) + array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) # random + + Generate a 2 x 4 array of ints between 0 and 4, inclusive: + + >>> np.random.randint(5, size=(2, 4)) + array([[4, 0, 2, 1], # random + [3, 2, 2, 0]]) + + Generate a 1 x 3 array with 3 different upper bounds + + >>> np.random.randint(1, [3, 5, 10]) + array([2, 2, 9]) # random + + Generate a 1 by 3 array with 3 different lower bounds + + >>> np.random.randint([1, 5, 7], 10) + array([9, 8, 7]) # random + + Generate a 2 by 4 array using broadcasting with dtype of uint8 + + >>> np.random.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8) + array([[ 8, 6, 9, 7], # random + [ 1, 16, 9, 12]], dtype=uint8) + """ + cdef bint use_masked=1 + + if high is None: + high = low + low = 0 + + key = np.dtype(dtype).name + if key not in _randint_types: + raise TypeError('Unsupported dtype "%s" for randint' % key) + + if key == 'int32': + ret = _rand_int32(low, high, size, use_masked, self._brng, self.lock) + elif key == 'int64': + ret = _rand_int64(low, high, size, use_masked, self._brng, self.lock) + elif key == 'int16': + ret = _rand_int16(low, high, size, use_masked, self._brng, self.lock) + elif key == 'int8': + ret = _rand_int8(low, high, size, use_masked, self._brng, self.lock) + elif key == 'uint64': + ret = _rand_uint64(low, high, size, use_masked, self._brng, self.lock) + elif key == 'uint32': + ret = _rand_uint32(low, high, size, use_masked, self._brng, self.lock) + elif key == 'uint16': + ret = _rand_uint16(low, high, size, use_masked, self._brng, self.lock) + elif key == 'uint8': + ret = _rand_uint8(low, high, size, use_masked, self._brng, self.lock) + elif key == 'bool': + ret = _rand_bool(low, high, size, use_masked, self._brng, self.lock) + + if size is None and dtype in (np.bool, np.int, np.long): + if np.array(ret).shape == (): + return dtype(ret) + return ret + + def bytes(self, np.npy_intp length): + """ + bytes(length) + + Return random bytes. + + Parameters + ---------- + length : int + Number of random bytes. + + Returns + ------- + out : str + String of length `length`. + + Examples + -------- + >>> np.random.bytes(10) + ' eh\\x85\\x022SZ\\xbf\\xa4' #random + + """ + cdef Py_ssize_t n_uint32 = ((length - 1) // 4 + 1) + return self.randint(0, 4294967296, size=n_uint32, dtype=np.uint32).tobytes()[:length] + + @cython.wraparound(True) + def choice(self, a, size=None, replace=True, p=None): + """ + choice(a, size=None, replace=True, p=None) + + Generates a random sample from a given 1-D array + + .. versionadded:: 1.7.0 + + Parameters + ---------- + a : 1-D array-like or int + If an ndarray, a random sample is generated from its elements. + If an int, the random sample is generated as if a were np.arange(a) + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + replace : boolean, optional + Whether the sample is with or without replacement + p : 1-D array-like, optional + The probabilities associated with each entry in a. + If not given the sample assumes a uniform distribution over all + entries in a. + + Returns + -------- + samples : single item or ndarray + The generated random samples + + Raises + ------- + ValueError + If a is an int and less than zero, if a or p are not 1-dimensional, + if a is an array-like of size 0, if p is not a vector of + probabilities, if a and p have different lengths, or if + replace=False and the sample size is greater than the population + size + + See Also + --------- + randint, shuffle, permutation + + Examples + --------- + Generate a uniform random sample from np.arange(5) of size 3: + + >>> np.random.choice(5, 3) + array([0, 3, 4]) # random + >>> #This is equivalent to np.random.randint(0,5,3) + + Generate a non-uniform random sample from np.arange(5) of size 3: + + >>> np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) + array([3, 3, 0]) # random + + Generate a uniform random sample from np.arange(5) of size 3 without + replacement: + + >>> np.random.choice(5, 3, replace=False) + array([3,1,0]) # random + >>> #This is equivalent to np.random.permutation(np.arange(5))[:3] + + Generate a non-uniform random sample from np.arange(5) of size + 3 without replacement: + + >>> np.random.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) + array([2, 3, 0]) # random + + Any of the above can be repeated with an arbitrary array-like + instead of just integers. For instance: + + >>> aa_milne_arr = ['pooh', 'rabbit', 'piglet', 'Christopher'] + >>> np.random.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) + array(['pooh', 'pooh', 'pooh', 'Christopher', 'piglet'], # random + dtype='np.PyArray_FROM_OTF(p, np.NPY_DOUBLE, np.NPY_ALIGNED) + pix = np.PyArray_DATA(p) + + if p.ndim != 1: + raise ValueError("'p' must be 1-dimensional") + if p.size != pop_size: + raise ValueError("'a' and 'p' must have same size") + p_sum = kahan_sum(pix, d) + if np.isnan(p_sum): + raise ValueError("probabilities contain NaN") + if np.logical_or.reduce(p < 0): + raise ValueError("probabilities are not non-negative") + if abs(p_sum - 1.) > atol: + raise ValueError("probabilities do not sum to 1") + + shape = size + if shape is not None: + size = np.prod(shape, dtype=np.intp) + else: + size = 1 + + # Actual sampling + if replace: + if p is not None: + cdf = p.cumsum() + cdf /= cdf[-1] + uniform_samples = self.random_sample(shape) + idx = cdf.searchsorted(uniform_samples, side='right') + idx = np.array(idx, copy=False) # searchsorted returns a scalar + else: + idx = self.randint(0, pop_size, size=shape) + else: + if size > pop_size: + raise ValueError("Cannot take a larger sample than " + "population when 'replace=False'") + elif size < 0: + raise ValueError("negative dimensions are not allowed") + + if p is not None: + if np.count_nonzero(p > 0) < size: + raise ValueError("Fewer non-zero entries in p than size") + n_uniq = 0 + p = p.copy() + found = np.zeros(shape, dtype=np.int64) + flat_found = found.ravel() + while n_uniq < size: + x = self.rand(size - n_uniq) + if n_uniq > 0: + p[flat_found[0:n_uniq]] = 0 + cdf = np.cumsum(p) + cdf /= cdf[-1] + new = cdf.searchsorted(x, side='right') + _, unique_indices = np.unique(new, return_index=True) + unique_indices.sort() + new = new.take(unique_indices) + flat_found[n_uniq:n_uniq + new.size] = new + n_uniq += new.size + idx = found + else: + idx = self.permutation(pop_size)[:size] + if shape is not None: + idx.shape = shape + + if shape is None and isinstance(idx, np.ndarray): + # In most cases a scalar will have been made an array + idx = idx.item(0) + + # Use samples as indices for a if a is array-like + if a.ndim == 0: + return idx + + if shape is not None and idx.ndim == 0: + # If size == () then the user requested a 0-d array as opposed to + # a scalar object when size is None. However a[idx] is always a + # scalar and not an array. So this makes sure the result is an + # array, taking into account that np.array(item) may not work + # for object arrays. + res = np.empty((), dtype=a.dtype) + res[()] = a[idx] + return res + + return a[idx] + + def uniform(self, low=0.0, high=1.0, size=None): + """ + uniform(low=0.0, high=1.0, size=None) + + Draw samples from a uniform distribution. + + Samples are uniformly distributed over the half-open interval + ``[low, high)`` (includes low, but excludes high). In other words, + any value within the given interval is equally likely to be drawn + by `uniform`. + + Parameters + ---------- + low : float or array_like of floats, optional + Lower boundary of the output interval. All values generated will be + greater than or equal to low. The default value is 0. + high : float or array_like of floats + Upper boundary of the output interval. All values generated will be + less than high. The default value is 1.0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``low`` and ``high`` are both scalars. + Otherwise, ``np.broadcast(low, high).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized uniform distribution. + + See Also + -------- + randint : Discrete uniform distribution, yielding integers. + random_integers : Discrete uniform distribution over the closed + interval ``[low, high]``. + random_sample : Floats uniformly distributed over ``[0, 1)``. + random : Alias for `random_sample`. + rand : Convenience function that accepts dimensions as input, e.g., + ``rand(2,2)`` would generate a 2-by-2 array of floats, + uniformly distributed over ``[0, 1)``. + + Notes + ----- + The probability density function of the uniform distribution is + + .. math:: p(x) = \\frac{1}{b - a} + + anywhere within the interval ``[a, b)``, and zero elsewhere. + + When ``high`` == ``low``, values of ``low`` will be returned. + If ``high`` < ``low``, the results are officially undefined + and may eventually raise an error, i.e. do not rely on this + function to behave when passed arguments satisfying that + inequality condition. + + Examples + -------- + Draw samples from the distribution: + + >>> s = np.random.uniform(-1,0,1000) + + All values are within the given interval: + + >>> np.all(s >= -1) + True + >>> np.all(s < 0) + True + + Display the histogram of the samples, along with the + probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 15, density=True) + >>> plt.plot(bins, np.ones_like(bins), linewidth=2, color='r') + >>> plt.show() + + """ + cdef bint is_scalar = True + cdef np.ndarray alow, ahigh, arange + cdef double _low, _high, range + cdef object temp + + alow = np.PyArray_FROM_OTF(low, np.NPY_DOUBLE, np.NPY_ALIGNED) + ahigh = np.PyArray_FROM_OTF(high, np.NPY_DOUBLE, np.NPY_ALIGNED) + + if np.PyArray_NDIM(alow) == np.PyArray_NDIM(ahigh) == 0: + _low = PyFloat_AsDouble(low) + _high = PyFloat_AsDouble(high) + range = _high - _low + if not np.isfinite(range): + raise OverflowError('Range exceeds valid bounds') + + return cont(&random_uniform, self._brng, size, self.lock, 2, + _low, '', CONS_NONE, + range, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) + + temp = np.subtract(ahigh, alow) + Py_INCREF(temp) + # needed to get around Pyrex's automatic reference-counting + # rules because EnsureArray steals a reference + arange = np.PyArray_EnsureArray(temp) + if not np.all(np.isfinite(arange)): + raise OverflowError('Range exceeds valid bounds') + return cont(&random_uniform, self._brng, size, self.lock, 2, + alow, '', CONS_NONE, + arange, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) + + def rand(self, *args): + """ + rand(d0, d1, ..., dn) + + Random values in a given shape. + + .. note:: + This is a convenience function for users porting code from Matlab, + and wraps `numpy.random.random_sample`. That function takes a + tuple to specify the size of the output, which is consistent with + other NumPy functions like `numpy.zeros` and `numpy.ones`. + + Create an array of the given shape and populate it with + random samples from a uniform distribution + over ``[0, 1)``. + + Parameters + ---------- + d0, d1, ..., dn : int, optional + The dimensions of the returned array, should all be positive. + If no argument is given a single Python float is returned. + + Returns + ------- + out : ndarray, shape ``(d0, d1, ..., dn)`` + Random values. + + See Also + -------- + random + + Examples + -------- + >>> np.random.rand(3,2) + array([[ 0.14022471, 0.96360618], #random + [ 0.37601032, 0.25528411], #random + [ 0.49313049, 0.94909878]]) #random + + """ + if len(args) == 0: + return self.random_sample() + else: + return self.random_sample(size=args) + + def randn(self, *args): + """ + randn(d0, d1, ..., dn) + + Return a sample (or samples) from the "standard normal" distribution. + + .. note:: + This is a convenience function for users porting code from Matlab, + and wraps `numpy.random.standard_normal`. That function takes a + tuple to specify the size of the output, which is consistent with + other NumPy functions like `numpy.zeros` and `numpy.ones`. + + If positive int_like arguments are provided, `randn` generates an array + of shape ``(d0, d1, ..., dn)``, filled + with random floats sampled from a univariate "normal" (Gaussian) + distribution of mean 0 and variance 1. A single float randomly sampled + from the distribution is returned if no argument is provided. + + Parameters + ---------- + d0, d1, ..., dn : int, optional + The dimensions of the returned array, should be all positive. + If no argument is given a single Python float is returned. + + Returns + ------- + Z : ndarray or float + A ``(d0, d1, ..., dn)``-shaped array of floating-point samples from + the standard normal distribution, or a single such float if + no parameters were supplied. + + See Also + -------- + standard_normal : Similar, but takes a tuple as its argument. + normal : Also accepts mu and sigma arguments. + + Notes + ----- + For random samples from :math:`N(\\mu, \\sigma^2)`, use: + + ``sigma * np.random.randn(...) + mu`` + + Examples + -------- + >>> np.random.randn() + 2.1923875335537315 # random + + Two-by-four array of samples from N(3, 6.25): + + >>> 3 + 2.5 * np.random.randn(2, 4) + array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], # random + [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) # random + """ + if len(args) == 0: + return self.standard_normal() + else: + return self.standard_normal(size=args) + + def random_integers(self, low, high=None, size=None): + """ + random_integers(low, high=None, size=None) + + Random integers of type np.int between `low` and `high`, inclusive. + + Return random integers of type np.int from the "discrete uniform" + distribution in the closed interval [`low`, `high`]. If `high` is + None (the default), then results are from [1, `low`]. The np.int + type translates to the C long type used by Python 2 for "short" + integers and its precision is platform dependent. + + This function has been deprecated. Use randint instead. + + .. deprecated:: 1.11.0 + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int, optional + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : int or ndarray of ints + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + See Also + -------- + randint : Similar to `random_integers`, only for the half-open + interval [`low`, `high`), and 0 is the lowest value if `high` is + omitted. + + Notes + ----- + To sample from N evenly spaced floating-point numbers between a and b, + use:: + + a + (b - a) * (np.random.random_integers(N) - 1) / (N - 1.) + + Examples + -------- + >>> np.random.random_integers(5) + 4 # random + >>> type(np.random.random_integers(5)) + + >>> np.random.random_integers(5, size=(3,2)) + array([[5, 4], # random + [3, 3], + [4, 5]]) + + Choose five random numbers from the set of five evenly-spaced + numbers between 0 and 2.5, inclusive (*i.e.*, from the set + :math:`{0, 5/8, 10/8, 15/8, 20/8}`): + + >>> 2.5 * (np.random.random_integers(5, size=(5,)) - 1) / 4. + array([ 0.625, 1.25 , 0.625, 0.625, 2.5 ]) # random + + Roll two six sided dice 1000 times and sum the results: + + >>> d1 = np.random.random_integers(1, 6, 1000) + >>> d2 = np.random.random_integers(1, 6, 1000) + >>> dsums = d1 + d2 + + Display results as a histogram: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(dsums, 11, density=True) + >>> plt.show() + + """ + if high is None: + warnings.warn(("This function is deprecated. Please call " + "randint(1, {low} + 1) instead".format(low=low)), + DeprecationWarning) + high = low + low = 1 + + else: + warnings.warn(("This function is deprecated. Please call " + "randint({low}, {high} + 1) " + "instead".format(low=low, high=high)), + DeprecationWarning) + + return self.randint(low, high + 1, size=size, dtype='l') + + # Complicated, continuous distributions: + def standard_normal(self, size=None): + """ + standard_normal(size=None) + + Draw samples from a standard Normal distribution (mean=0, stdev=1). + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : float or ndarray + A floating-point array of shape ``size`` of drawn samples, or a + single sample if ``size`` was not specified. + + Notes + ----- + For random samples from :math:`N(\\mu, \\sigma^2)`, use one of:: + + mu + sigma * np.random.standard_normal(size=...) + np.random.normal(mu, sigma, size=...) + + See Also + -------- + normal : + Equivalent function with additional ``loc`` and ``scale`` arguments + for setting the mean and standard deviation. + + Examples + -------- + >>> np.random.standard_normal() + 2.1923875335537315 #random + + >>> s = np.random.standard_normal(8000) + >>> s + array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, # random + -0.38672696, -0.4685006 ]) # random + >>> s.shape + (8000,) + >>> s = np.random.standard_normal(size=(3, 4, 2)) + >>> s.shape + (3, 4, 2) + + Two-by-four array of samples from :math:`N(3, 6.25)`: + + >>> 3 + 2.5 * np.random.standard_normal(size=(2, 4)) + array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], # random + [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) # random + + """ + return cont(&legacy_gauss, self._aug_state, size, self.lock, 0, + None, None, CONS_NONE, + None, None, CONS_NONE, + None, None, CONS_NONE, + None) + + def normal(self, loc=0.0, scale=1.0, size=None): + """ + normal(loc=0.0, scale=1.0, size=None) + + Draw random samples from a normal (Gaussian) distribution. + + The probability density function of the normal distribution, first + derived by De Moivre and 200 years later by both Gauss and Laplace + independently [2]_, is often called the bell curve because of + its characteristic shape (see the example below). + + The normal distributions occurs often in nature. For example, it + describes the commonly occurring distribution of samples influenced + by a large number of tiny, random disturbances, each with its own + unique distribution [2]_. + + Parameters + ---------- + loc : float or array_like of floats + Mean ("centre") of the distribution. + scale : float or array_like of floats + Standard deviation (spread or "width") of the distribution. Must be + non-negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized normal distribution. + + See Also + -------- + scipy.stats.norm : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gaussian distribution is + + .. math:: p(x) = \\frac{1}{\\sqrt{ 2 \\pi \\sigma^2 }} + e^{ - \\frac{ (x - \\mu)^2 } {2 \\sigma^2} }, + + where :math:`\\mu` is the mean and :math:`\\sigma` the standard + deviation. The square of the standard deviation, :math:`\\sigma^2`, + is called the variance. + + The function has its peak at the mean, and its "spread" increases with + the standard deviation (the function reaches 0.607 times its maximum at + :math:`x + \\sigma` and :math:`x - \\sigma` [2]_). This implies that + `numpy.random.normal` is more likely to return samples lying close to + the mean, rather than those far away. + + References + ---------- + .. [1] Wikipedia, "Normal distribution", + https://en.wikipedia.org/wiki/Normal_distribution + .. [2] P. R. Peebles Jr., "Central Limit Theorem" in "Probability, + Random Variables and Random Signal Principles", 4th ed., 2001, + pp. 51, 51, 125. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, sigma = 0, 0.1 # mean and standard deviation + >>> s = np.random.normal(mu, sigma, 1000) + + Verify the mean and the variance: + + >>> abs(mu - np.mean(s)) + 0.0 # may vary + + >>> abs(sigma - np.std(s, ddof=1)) + 0.1 # may vary + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 30, density=True) + >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * + ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ), + ... linewidth=2, color='r') + >>> plt.show() + + Two-by-four array of samples from N(3, 6.25): + + >>> np.random.normal(3, 2.5, size=(2, 4)) + array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], # random + [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) # random + + """ + return cont(&legacy_normal, self._aug_state, size, self.lock, 2, + loc, '', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + None) + + def standard_gamma(self, shape, size=None): + """ + standard_gamma(shape, size=None) + + Draw samples from a standard Gamma distribution. + + Samples are drawn from a Gamma distribution with specified parameters, + shape (sometimes designated "k") and scale=1. + + Parameters + ---------- + shape : float or array_like of floats + Parameter, must be non-negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``shape`` is a scalar. Otherwise, + ``np.array(shape).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized standard gamma distribution. + + See Also + -------- + scipy.stats.gamma : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gamma distribution is + + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. + + References + ---------- + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + https://en.wikipedia.org/wiki/Gamma_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> shape, scale = 2., 1. # mean and width + >>> s = np.random.standard_gamma(shape, 1000000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, density=True) + >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ + ... (sps.gamma(shape) * scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') + >>> plt.show() + + """ + return cont(&legacy_standard_gamma, self._aug_state, size, self.lock, 1, + shape, 'shape', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, + None) + + def gamma(self, shape, scale=1.0, size=None): + """ + gamma(shape, scale=1.0, size=None) + + Draw samples from a Gamma distribution. + + Samples are drawn from a Gamma distribution with specified parameters, + `shape` (sometimes designated "k") and `scale` (sometimes designated + "theta"), where both parameters are > 0. + + Parameters + ---------- + shape : float or array_like of floats + The shape of the gamma distribution. Must be non-negative. + scale : float or array_like of floats, optional + The scale of the gamma distribution. Must be non-negative. + Default is equal to 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``shape`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(shape, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized gamma distribution. + + See Also + -------- + scipy.stats.gamma : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gamma distribution is + + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. + + References + ---------- + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + https://en.wikipedia.org/wiki/Gamma_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> shape, scale = 2., 2. # mean=4, std=2*sqrt(2) + >>> s = np.random.gamma(shape, scale, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, density=True) + >>> y = bins**(shape-1)*(np.exp(-bins/scale) / + ... (sps.gamma(shape)*scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') + >>> plt.show() + + """ + return cont(&legacy_gamma, self._aug_state, size, self.lock, 2, + shape, 'shape', CONS_NON_NEGATIVE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def f(self, dfnum, dfden, size=None): + """ + f(dfnum, dfden, size=None) + + Draw samples from an F distribution. + + Samples are drawn from an F distribution with specified parameters, + `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of + freedom in denominator), where both parameters should be greater than + zero. + + The random variate of the F distribution (also known as the + Fisher distribution) is a continuous probability distribution + that arises in ANOVA tests, and is the ratio of two chi-square + variates. + + Parameters + ---------- + dfnum : float or array_like of floats + Degrees of freedom in numerator, should be > 0. + dfden : float or array_like of float + Degrees of freedom in denominator, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``dfnum`` and ``dfden`` are both scalars. + Otherwise, ``np.broadcast(dfnum, dfden).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Fisher distribution. + + See Also + -------- + scipy.stats.f : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The F statistic is used to compare in-group variances to between-group + variances. Calculating the distribution depends on the sampling, and + so it is a function of the respective degrees of freedom in the + problem. The variable `dfnum` is the number of samples minus one, the + between-groups degrees of freedom, while `dfden` is the within-groups + degrees of freedom, the sum of the number of samples in each group + minus the number of groups. + + References + ---------- + .. [1] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, + Fifth Edition, 2002. + .. [2] Wikipedia, "F-distribution", + https://en.wikipedia.org/wiki/F-distribution + + Examples + -------- + An example from Glantz[1], pp 47-40: + + Two groups, children of diabetics (25 people) and children from people + without diabetes (25 controls). Fasting blood glucose was measured, + case group had a mean value of 86.1, controls had a mean value of + 82.2. Standard deviations were 2.09 and 2.49 respectively. Are these + data consistent with the null hypothesis that the parents diabetic + status does not affect their children's blood glucose levels? + Calculating the F statistic from the data gives a value of 36.01. + + Draw samples from the distribution: + + >>> dfnum = 1. # between group degrees of freedom + >>> dfden = 48. # within groups degrees of freedom + >>> s = np.random.f(dfnum, dfden, 1000) + + The lower bound for the top 1% of the samples is : + + >>> np.sort(s)[-10] + 7.61988120985 # random + + So there is about a 1% chance that the F statistic will exceed 7.62, + the measured value is 36, so the null hypothesis is rejected at the 1% + level. + + """ + return cont(&legacy_f, self._aug_state, size, self.lock, 2, + dfnum, 'dfnum', CONS_POSITIVE, + dfden, 'dfden', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + def noncentral_f(self, dfnum, dfden, nonc, size=None): + """ + noncentral_f(dfnum, dfden, nonc, size=None) + + Draw samples from the noncentral F distribution. + + Samples are drawn from an F distribution with specified parameters, + `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of + freedom in denominator), where both parameters > 1. + `nonc` is the non-centrality parameter. + + Parameters + ---------- + dfnum : float or array_like of floats + Numerator degrees of freedom, should be > 0. + + .. versionchanged:: 1.14.0 + Earlier NumPy versions required dfnum > 1. + dfden : float or array_like of floats + Denominator degrees of freedom, should be > 0. + nonc : float or array_like of floats + Non-centrality parameter, the sum of the squares of the numerator + means, should be >= 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``dfnum``, ``dfden``, and ``nonc`` + are all scalars. Otherwise, ``np.broadcast(dfnum, dfden, nonc).size`` + samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized noncentral Fisher distribution. + + Notes + ----- + When calculating the power of an experiment (power = probability of + rejecting the null hypothesis when a specific alternative is true) the + non-central F statistic becomes important. When the null hypothesis is + true, the F statistic follows a central F distribution. When the null + hypothesis is not true, then it follows a non-central F statistic. + + References + ---------- + .. [1] Weisstein, Eric W. "Noncentral F-Distribution." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/NoncentralF-Distribution.html + .. [2] Wikipedia, "Noncentral F-distribution", + https://en.wikipedia.org/wiki/Noncentral_F-distribution + + Examples + -------- + In a study, testing for a specific alternative to the null hypothesis + requires use of the Noncentral F distribution. We need to calculate the + area in the tail of the distribution that exceeds the value of the F + distribution for the null hypothesis. We'll plot the two probability + distributions for comparison. + + >>> dfnum = 3 # between group deg of freedom + >>> dfden = 20 # within groups degrees of freedom + >>> nonc = 3.0 + >>> nc_vals = np.random.noncentral_f(dfnum, dfden, nonc, 1000000) + >>> NF = np.histogram(nc_vals, bins=50, density=True) + >>> c_vals = np.random.f(dfnum, dfden, 1000000) + >>> F = np.histogram(c_vals, bins=50, density=True) + >>> import matplotlib.pyplot as plt + >>> plt.plot(F[1][1:], F[0]) + >>> plt.plot(NF[1][1:], NF[0]) + >>> plt.show() + + """ + return cont(&legacy_noncentral_f, self._aug_state, size, self.lock, 3, + dfnum, 'dfnum', CONS_POSITIVE, + dfden, 'dfden', CONS_POSITIVE, + nonc, 'nonc', CONS_NON_NEGATIVE, None) + + def chisquare(self, df, size=None): + """ + chisquare(df, size=None) + + Draw samples from a chi-square distribution. + + When `df` independent random variables, each with standard normal + distributions (mean 0, variance 1), are squared and summed, the + resulting distribution is chi-square (see Notes). This distribution + is often used in hypothesis testing. + + Parameters + ---------- + df : float or array_like of floats + Number of degrees of freedom, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` is a scalar. Otherwise, + ``np.array(df).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized chi-square distribution. + + Raises + ------ + ValueError + When `df` <= 0 or when an inappropriate `size` (e.g. ``size=-1``) + is given. + + Notes + ----- + The variable obtained by summing the squares of `df` independent, + standard normally distributed random variables: + + .. math:: Q = \\sum_{i=0}^{\\mathtt{df}} X^2_i + + is chi-square distributed, denoted + + .. math:: Q \\sim \\chi^2_k. + + The probability density function of the chi-squared distribution is + + .. math:: p(x) = \\frac{(1/2)^{k/2}}{\\Gamma(k/2)} + x^{k/2 - 1} e^{-x/2}, + + where :math:`\\Gamma` is the gamma function, + + .. math:: \\Gamma(x) = \\int_0^{-\\infty} t^{x - 1} e^{-t} dt. + + References + ---------- + .. [1] NIST "Engineering Statistics Handbook" + https://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm + + Examples + -------- + >>> np.random.chisquare(2,4) + array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) # random + + """ + return cont(&legacy_chisquare, self._aug_state, size, self.lock, 1, + df, 'df', CONS_POSITIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def noncentral_chisquare(self, df, nonc, size=None): + """ + noncentral_chisquare(df, nonc, size=None) + + Draw samples from a noncentral chi-square distribution. + + The noncentral :math:`\\chi^2` distribution is a generalisation of + the :math:`\\chi^2` distribution. + + Parameters + ---------- + df : float or array_like of floats + Degrees of freedom, should be > 0. + + .. versionchanged:: 1.10.0 + Earlier NumPy versions required dfnum > 1. + nonc : float or array_like of floats + Non-centrality, should be non-negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` and ``nonc`` are both scalars. + Otherwise, ``np.broadcast(df, nonc).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized noncentral chi-square distribution. + + Notes + ----- + The probability density function for the noncentral Chi-square + distribution is + + .. math:: P(x;df,nonc) = \\sum^{\\infty}_{i=0} + \\frac{e^{-nonc/2}(nonc/2)^{i}}{i!} + P_{Y_{df+2i}}(x), + + where :math:`Y_{q}` is the Chi-square with q degrees of freedom. + + References + ---------- + .. [1] Wikipedia, "Noncentral chi-squared distribution" + https://en.wikipedia.org/wiki/Noncentral_chi-squared_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram + + >>> import matplotlib.pyplot as plt + >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), + ... bins=200, density=True) + >>> plt.show() + + Draw values from a noncentral chisquare with very small noncentrality, + and compare to a chisquare. + + >>> plt.figure() + >>> values = plt.hist(np.random.noncentral_chisquare(3, .0000001, 100000), + ... bins=np.arange(0., 25, .1), density=True) + >>> values2 = plt.hist(np.random.chisquare(3, 100000), + ... bins=np.arange(0., 25, .1), density=True) + >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') + >>> plt.show() + + Demonstrate how large values of non-centrality lead to a more symmetric + distribution. + + >>> plt.figure() + >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), + ... bins=200, density=True) + >>> plt.show() + """ + return cont(&legacy_noncentral_chisquare, self._aug_state, size, self.lock, 2, + df, 'df', CONS_POSITIVE, + nonc, 'nonc', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def standard_cauchy(self, size=None): + """ + standard_cauchy(size=None) + + Draw samples from a standard Cauchy distribution with mode = 0. + + Also known as the Lorentz distribution. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + samples : ndarray or scalar + The drawn samples. + + Notes + ----- + The probability density function for the full Cauchy distribution is + + .. math:: P(x; x_0, \\gamma) = \\frac{1}{\\pi \\gamma \\bigl[ 1+ + (\\frac{x-x_0}{\\gamma})^2 \\bigr] } + + and the Standard Cauchy distribution just sets :math:`x_0=0` and + :math:`\\gamma=1` + + The Cauchy distribution arises in the solution to the driven harmonic + oscillator problem, and also describes spectral line broadening. It + also describes the distribution of values at which a line tilted at + a random angle will cut the x axis. + + When studying hypothesis tests that assume normality, seeing how the + tests perform on data from a Cauchy distribution is a good indicator of + their sensitivity to a heavy-tailed distribution, since the Cauchy looks + very much like a Gaussian distribution, but with heavier tails. + + References + ---------- + .. [1] NIST/SEMATECH e-Handbook of Statistical Methods, "Cauchy + Distribution", + https://www.itl.nist.gov/div898/handbook/eda/section3/eda3663.htm + .. [2] Weisstein, Eric W. "Cauchy Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/CauchyDistribution.html + .. [3] Wikipedia, "Cauchy distribution" + https://en.wikipedia.org/wiki/Cauchy_distribution + + Examples + -------- + Draw samples and plot the distribution: + + >>> import matplotlib.pyplot as plt + >>> s = np.random.standard_cauchy(1000000) + >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well + >>> plt.hist(s, bins=100) + >>> plt.show() + + """ + return cont(&legacy_standard_cauchy, self._aug_state, size, self.lock, 0, + 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None) + + def standard_t(self, df, size=None): + """ + standard_t(df, size=None) + + Draw samples from a standard Student's t distribution with `df` degrees + of freedom. + + A special case of the hyperbolic distribution. As `df` gets + large, the result resembles that of the standard normal + distribution (`standard_normal`). + + Parameters + ---------- + df : float or array_like of floats + Degrees of freedom, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` is a scalar. Otherwise, + ``np.array(df).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized standard Student's t distribution. + + Notes + ----- + The probability density function for the t distribution is + + .. math:: P(x, df) = \\frac{\\Gamma(\\frac{df+1}{2})}{\\sqrt{\\pi df} + \\Gamma(\\frac{df}{2})}\\Bigl( 1+\\frac{x^2}{df} \\Bigr)^{-(df+1)/2} + + The t test is based on an assumption that the data come from a + Normal distribution. The t test provides a way to test whether + the sample mean (that is the mean calculated from the data) is + a good estimate of the true mean. + + The derivation of the t-distribution was first published in + 1908 by William Gosset while working for the Guinness Brewery + in Dublin. Due to proprietary issues, he had to publish under + a pseudonym, and so he used the name Student. + + References + ---------- + .. [1] Dalgaard, Peter, "Introductory Statistics With R", + Springer, 2002. + .. [2] Wikipedia, "Student's t-distribution" + https://en.wikipedia.org/wiki/Student's_t-distribution + + Examples + -------- + From Dalgaard page 83 [1]_, suppose the daily energy intake for 11 + women in kilojoules (kJ) is: + + >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\ + ... 7515, 8230, 8770]) + + Does their energy intake deviate systematically from the recommended + value of 7725 kJ? + + We have 10 degrees of freedom, so is the sample mean within 95% of the + recommended value? + + >>> s = np.random.standard_t(10, size=100000) + >>> np.mean(intake) + 6753.636363636364 + >>> intake.std(ddof=1) + 1142.1232221373727 + + Calculate the t statistic, setting the ddof parameter to the unbiased + value so the divisor in the standard deviation will be degrees of + freedom, N-1. + + >>> t = (np.mean(intake)-7725)/(intake.std(ddof=1)/np.sqrt(len(intake))) + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(s, bins=100, density=True) + + For a one-sided t-test, how far out in the distribution does the t + statistic appear? + + >>> np.sum(s=0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mu`` and ``kappa`` are both scalars. + Otherwise, ``np.broadcast(mu, kappa).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized von Mises distribution. + + See Also + -------- + scipy.stats.vonmises : probability density function, distribution, or + cumulative density function, etc. + + Notes + ----- + The probability density for the von Mises distribution is + + .. math:: p(x) = \\frac{e^{\\kappa cos(x-\\mu)}}{2\\pi I_0(\\kappa)}, + + where :math:`\\mu` is the mode and :math:`\\kappa` the dispersion, + and :math:`I_0(\\kappa)` is the modified Bessel function of order 0. + + The von Mises is named for Richard Edler von Mises, who was born in + Austria-Hungary, in what is now the Ukraine. He fled to the United + States in 1939 and became a professor at Harvard. He worked in + probability theory, aerodynamics, fluid mechanics, and philosophy of + science. + + References + ---------- + .. [1] Abramowitz, M. and Stegun, I. A. (Eds.). "Handbook of + Mathematical Functions with Formulas, Graphs, and Mathematical + Tables, 9th printing," New York: Dover, 1972. + .. [2] von Mises, R., "Mathematical Theory of Probability + and Statistics", New York: Academic Press, 1964. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, kappa = 0.0, 4.0 # mean and dispersion + >>> s = np.random.vonmises(mu, kappa, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> from scipy.special import i0 + >>> plt.hist(s, 50, density=True) + >>> x = np.linspace(-np.pi, np.pi, num=51) + >>> y = np.exp(kappa*np.cos(x-mu))/(2*np.pi*i0(kappa)) + >>> plt.plot(x, y, linewidth=2, color='r') + >>> plt.show() + + """ + return cont(&random_vonmises, self._brng, size, self.lock, 2, + mu, 'mu', CONS_NONE, + kappa, 'kappa', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def pareto(self, a, size=None): + """ + pareto(a, size=None) + + Draw samples from a Pareto II or Lomax distribution with + specified shape. + + The Lomax or Pareto II distribution is a shifted Pareto + distribution. The classical Pareto distribution can be + obtained from the Lomax distribution by adding 1 and + multiplying by the scale parameter ``m`` (see Notes). The + smallest value of the Lomax distribution is zero while for the + classical Pareto distribution it is ``mu``, where the standard + Pareto distribution has location ``mu = 1``. Lomax can also + be considered as a simplified version of the Generalized + Pareto distribution (available in SciPy), with the scale set + to one and the location set to zero. + + The Pareto distribution must be greater than zero, and is + unbounded above. It is also known as the "80-20 rule". In + this distribution, 80 percent of the weights are in the lowest + 20 percent of the range, while the other 20 percent fill the + remaining 80 percent of the range. + + Parameters + ---------- + a : float or array_like of floats + Shape of the distribution. Must all be positive. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Pareto distribution. + + See Also + -------- + scipy.stats.lomax : probability density function, distribution or + cumulative density function, etc. + scipy.stats.genpareto : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Pareto distribution is + + .. math:: p(x) = \\frac{am^a}{x^{a+1}} + + where :math:`a` is the shape and :math:`m` the scale. + + The Pareto distribution, named after the Italian economist + Vilfredo Pareto, is a power law probability distribution + useful in many real world problems. Outside the field of + economics it is generally referred to as the Bradford + distribution. Pareto developed the distribution to describe + the distribution of wealth in an economy. It has also found + use in insurance, web page access statistics, oil field sizes, + and many other problems, including the download frequency for + projects in Sourceforge [1]_. It is one of the so-called + "fat-tailed" distributions. + + + References + ---------- + .. [1] Francis Hunt and Paul Johnson, On the Pareto Distribution of + Sourceforge projects. + .. [2] Pareto, V. (1896). Course of Political Economy. Lausanne. + .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme + Values, Birkhauser Verlag, Basel, pp 23-30. + .. [4] Wikipedia, "Pareto distribution", + https://en.wikipedia.org/wiki/Pareto_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a, m = 3., 2. # shape and mode + >>> s = (np.random.pareto(a, 1000) + 1) * m + + Display the histogram of the samples, along with the probability + density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, _ = plt.hist(s, 100, density=True) + >>> fit = a*m**a / bins**(a+1) + >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r') + >>> plt.show() + + """ + return cont(&legacy_pareto, self._aug_state, size, self.lock, 1, + a, 'a', CONS_POSITIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def weibull(self, a, size=None): + """ + weibull(a, size=None) + + Draw samples from a Weibull distribution. + + Draw samples from a 1-parameter Weibull distribution with the given + shape parameter `a`. + + .. math:: X = (-ln(U))^{1/a} + + Here, U is drawn from the uniform distribution over (0,1]. + + The more common 2-parameter Weibull, including a scale parameter + :math:`\\lambda` is just :math:`X = \\lambda(-ln(U))^{1/a}`. + + Parameters + ---------- + a : float or array_like of floats + Shape parameter of the distribution. Must be nonnegative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Weibull distribution. + + See Also + -------- + scipy.stats.weibull_max + scipy.stats.weibull_min + scipy.stats.genextreme + gumbel + + Notes + ----- + The Weibull (or Type III asymptotic extreme value distribution + for smallest values, SEV Type III, or Rosin-Rammler + distribution) is one of a class of Generalized Extreme Value + (GEV) distributions used in modeling extreme value problems. + This class includes the Gumbel and Frechet distributions. + + The probability density for the Weibull distribution is + + .. math:: p(x) = \\frac{a} + {\\lambda}(\\frac{x}{\\lambda})^{a-1}e^{-(x/\\lambda)^a}, + + where :math:`a` is the shape and :math:`\\lambda` the scale. + + The function has its peak (the mode) at + :math:`\\lambda(\\frac{a-1}{a})^{1/a}`. + + When ``a = 1``, the Weibull distribution reduces to the exponential + distribution. + + References + ---------- + .. [1] Waloddi Weibull, Royal Technical University, Stockholm, + 1939 "A Statistical Theory Of The Strength Of Materials", + Ingeniorsvetenskapsakademiens Handlingar Nr 151, 1939, + Generalstabens Litografiska Anstalts Forlag, Stockholm. + .. [2] Waloddi Weibull, "A Statistical Distribution Function of + Wide Applicability", Journal Of Applied Mechanics ASME Paper + 1951. + .. [3] Wikipedia, "Weibull distribution", + https://en.wikipedia.org/wiki/Weibull_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a = 5. # shape + >>> s = np.random.weibull(a, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> x = np.arange(1,100.)/50. + >>> def weib(x,n,a): + ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) + + >>> count, bins, ignored = plt.hist(np.random.weibull(5.,1000)) + >>> x = np.arange(1,100.)/50. + >>> scale = count.max()/weib(x, 1., 5.).max() + >>> plt.plot(x, weib(x, 1., 5.)*scale) + >>> plt.show() + + """ + return cont(&legacy_weibull, self._aug_state, size, self.lock, 1, + a, 'a', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def power(self, a, size=None): + """ + power(a, size=None) + + Draws samples in [0, 1] from a power distribution with positive + exponent a - 1. + + Also known as the power function distribution. + + Parameters + ---------- + a : float or array_like of floats + Parameter of the distribution. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized power distribution. + + Raises + ------ + ValueError + If a < 1. + + Notes + ----- + The probability density function is + + .. math:: P(x; a) = ax^{a-1}, 0 \\le x \\le 1, a>0. + + The power function distribution is just the inverse of the Pareto + distribution. It may also be seen as a special case of the Beta + distribution. + + It is used, for example, in modeling the over-reporting of insurance + claims. + + References + ---------- + .. [1] Christian Kleiber, Samuel Kotz, "Statistical size distributions + in economics and actuarial sciences", Wiley, 2003. + .. [2] Heckert, N. A. and Filliben, James J. "NIST Handbook 148: + Dataplot Reference Manual, Volume 2: Let Subcommands and Library + Functions", National Institute of Standards and Technology + Handbook Series, June 2003. + https://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf + + Examples + -------- + Draw samples from the distribution: + + >>> a = 5. # shape + >>> samples = 1000 + >>> s = np.random.power(a, samples) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, bins=30) + >>> x = np.linspace(0, 1, 100) + >>> y = a*x**(a-1.) + >>> normed_y = samples*np.diff(bins)[0]*y + >>> plt.plot(x, normed_y) + >>> plt.show() + + Compare the power function distribution to the inverse of the Pareto. + + >>> from scipy import stats + >>> rvs = np.random.power(5, 1000000) + >>> rvsp = np.random.pareto(5, 1000000) + >>> xx = np.linspace(0,1,100) + >>> powpdf = stats.powerlaw.pdf(xx,5) + + >>> plt.figure() + >>> plt.hist(rvs, bins=50, density=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('np.random.power(5)') + + >>> plt.figure() + >>> plt.hist(1./(1.+rvsp), bins=50, density=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('inverse of 1 + np.random.pareto(5)') + + >>> plt.figure() + >>> plt.hist(1./(1.+rvsp), bins=50, density=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('inverse of stats.pareto(5)') + + """ + return cont(&legacy_power, self._aug_state, size, self.lock, 1, + a, 'a', CONS_POSITIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def laplace(self, loc=0.0, scale=1.0, size=None): + """ + laplace(loc=0.0, scale=1.0, size=None) + + Draw samples from the Laplace or double exponential distribution with + specified location (or mean) and scale (decay). + + The Laplace distribution is similar to the Gaussian/normal distribution, + but is sharper at the peak and has fatter tails. It represents the + difference between two independent, identically distributed exponential + random variables. + + Parameters + ---------- + loc : float or array_like of floats, optional + The position, :math:`\\mu`, of the distribution peak. Default is 0. + scale : float or array_like of floats, optional + :math:`\\lambda`, the exponential decay. Default is 1. Must be non- + negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Laplace distribution. + + Notes + ----- + It has the probability density function + + .. math:: f(x; \\mu, \\lambda) = \\frac{1}{2\\lambda} + \\exp\\left(-\\frac{|x - \\mu|}{\\lambda}\\right). + + The first law of Laplace, from 1774, states that the frequency + of an error can be expressed as an exponential function of the + absolute magnitude of the error, which leads to the Laplace + distribution. For many problems in economics and health + sciences, this distribution seems to model the data better + than the standard Gaussian distribution. + + References + ---------- + .. [1] Abramowitz, M. and Stegun, I. A. (Eds.). "Handbook of + Mathematical Functions with Formulas, Graphs, and Mathematical + Tables, 9th printing," New York: Dover, 1972. + .. [2] Kotz, Samuel, et. al. "The Laplace Distribution and + Generalizations, " Birkhauser, 2001. + .. [3] Weisstein, Eric W. "Laplace Distribution." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/LaplaceDistribution.html + .. [4] Wikipedia, "Laplace distribution", + https://en.wikipedia.org/wiki/Laplace_distribution + + Examples + -------- + Draw samples from the distribution + + >>> loc, scale = 0., 1. + >>> s = np.random.laplace(loc, scale, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 30, density=True) + >>> x = np.arange(-8., 8., .01) + >>> pdf = np.exp(-abs(x-loc)/scale)/(2.*scale) + >>> plt.plot(x, pdf) + + Plot Gaussian for comparison: + + >>> g = (1/(scale * np.sqrt(2 * np.pi)) * + ... np.exp(-(x - loc)**2 / (2 * scale**2))) + >>> plt.plot(x,g) + + """ + return cont(&random_laplace, self._brng, size, self.lock, 2, + loc, 'loc', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def gumbel(self, loc=0.0, scale=1.0, size=None): + """ + gumbel(loc=0.0, scale=1.0, size=None) + + Draw samples from a Gumbel distribution. + + Draw samples from a Gumbel distribution with specified location and + scale. For more information on the Gumbel distribution, see + Notes and References below. + + Parameters + ---------- + loc : float or array_like of floats, optional + The location of the mode of the distribution. Default is 0. + scale : float or array_like of floats, optional + The scale parameter of the distribution. Default is 1. Must be non- + negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Gumbel distribution. + + See Also + -------- + scipy.stats.gumbel_l + scipy.stats.gumbel_r + scipy.stats.genextreme + weibull + + Notes + ----- + The Gumbel (or Smallest Extreme Value (SEV) or the Smallest Extreme + Value Type I) distribution is one of a class of Generalized Extreme + Value (GEV) distributions used in modeling extreme value problems. + The Gumbel is a special case of the Extreme Value Type I distribution + for maximums from distributions with "exponential-like" tails. + + The probability density for the Gumbel distribution is + + .. math:: p(x) = \\frac{e^{-(x - \\mu)/ \\beta}}{\\beta} e^{ -e^{-(x - \\mu)/ + \\beta}}, + + where :math:`\\mu` is the mode, a location parameter, and + :math:`\\beta` is the scale parameter. + + The Gumbel (named for German mathematician Emil Julius Gumbel) was used + very early in the hydrology literature, for modeling the occurrence of + flood events. It is also used for modeling maximum wind speed and + rainfall rates. It is a "fat-tailed" distribution - the probability of + an event in the tail of the distribution is larger than if one used a + Gaussian, hence the surprisingly frequent occurrence of 100-year + floods. Floods were initially modeled as a Gaussian process, which + underestimated the frequency of extreme events. + + It is one of a class of extreme value distributions, the Generalized + Extreme Value (GEV) distributions, which also includes the Weibull and + Frechet. + + The function has a mean of :math:`\\mu + 0.57721\\beta` and a variance + of :math:`\\frac{\\pi^2}{6}\\beta^2`. + + References + ---------- + .. [1] Gumbel, E. J., "Statistics of Extremes," + New York: Columbia University Press, 1958. + .. [2] Reiss, R.-D. and Thomas, M., "Statistical Analysis of Extreme + Values from Insurance, Finance, Hydrology and Other Fields," + Basel: Birkhauser Verlag, 2001. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, beta = 0, 0.1 # location and scale + >>> s = np.random.gumbel(mu, beta, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 30, density=True) + >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta) + ... * np.exp( -np.exp( -(bins - mu) /beta) ), + ... linewidth=2, color='r') + >>> plt.show() + + Show how an extreme value distribution can arise from a Gaussian process + and compare to a Gaussian: + + >>> means = [] + >>> maxima = [] + >>> for i in range(0,1000) : + ... a = np.random.normal(mu, beta, 1000) + ... means.append(a.mean()) + ... maxima.append(a.max()) + >>> count, bins, ignored = plt.hist(maxima, 30, density=True) + >>> beta = np.std(maxima) * np.sqrt(6) / np.pi + >>> mu = np.mean(maxima) - 0.57721*beta + >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta) + ... * np.exp(-np.exp(-(bins - mu)/beta)), + ... linewidth=2, color='r') + >>> plt.plot(bins, 1/(beta * np.sqrt(2 * np.pi)) + ... * np.exp(-(bins - mu)**2 / (2 * beta**2)), + ... linewidth=2, color='g') + >>> plt.show() + + """ + return cont(&random_gumbel, self._brng, size, self.lock, 2, + loc, 'loc', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def logistic(self, loc=0.0, scale=1.0, size=None): + """ + logistic(loc=0.0, scale=1.0, size=None) + + Draw samples from a logistic distribution. + + Samples are drawn from a logistic distribution with specified + parameters, loc (location or mean, also median), and scale (>0). + + Parameters + ---------- + loc : float or array_like of floats, optional + Parameter of the distribution. Default is 0. + scale : float or array_like of floats, optional + Parameter of the distribution. Must be non-negative. + Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized logistic distribution. + + See Also + -------- + scipy.stats.logistic : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Logistic distribution is + + .. math:: P(x) = P(x) = \\frac{e^{-(x-\\mu)/s}}{s(1+e^{-(x-\\mu)/s})^2}, + + where :math:`\\mu` = location and :math:`s` = scale. + + The Logistic distribution is used in Extreme Value problems where it + can act as a mixture of Gumbel distributions, in Epidemiology, and by + the World Chess Federation (FIDE) where it is used in the Elo ranking + system, assuming the performance of each player is a logistically + distributed random variable. + + References + ---------- + .. [1] Reiss, R.-D. and Thomas M. (2001), "Statistical Analysis of + Extreme Values, from Insurance, Finance, Hydrology and Other + Fields," Birkhauser Verlag, Basel, pp 132-133. + .. [2] Weisstein, Eric W. "Logistic Distribution." From + MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/LogisticDistribution.html + .. [3] Wikipedia, "Logistic-distribution", + https://en.wikipedia.org/wiki/Logistic_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> loc, scale = 10, 1 + >>> s = np.random.logistic(loc, scale, 10000) + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, bins=50) + + # plot against distribution + + >>> def logist(x, loc, scale): + ... return np.exp((loc-x)/scale)/(scale*(1+np.exp((loc-x)/scale))**2) + >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\\ + ... logist(bins, loc, scale).max()) + >>> plt.show() + + """ + return cont(&random_logistic, self._brng, size, self.lock, 2, + loc, 'loc', CONS_NONE, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def lognormal(self, mean=0.0, sigma=1.0, size=None): + """ + lognormal(mean=0.0, sigma=1.0, size=None) + + Draw samples from a log-normal distribution. + + Draw samples from a log-normal distribution with specified mean, + standard deviation, and array shape. Note that the mean and standard + deviation are not the values for the distribution itself, but of the + underlying normal distribution it is derived from. + + Parameters + ---------- + mean : float or array_like of floats, optional + Mean value of the underlying normal distribution. Default is 0. + sigma : float or array_like of floats, optional + Standard deviation of the underlying normal distribution. Must be + non-negative. Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mean`` and ``sigma`` are both scalars. + Otherwise, ``np.broadcast(mean, sigma).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized log-normal distribution. + + See Also + -------- + scipy.stats.lognorm : probability density function, distribution, + cumulative density function, etc. + + Notes + ----- + A variable `x` has a log-normal distribution if `log(x)` is normally + distributed. The probability density function for the log-normal + distribution is: + + .. math:: p(x) = \\frac{1}{\\sigma x \\sqrt{2\\pi}} + e^{(-\\frac{(ln(x)-\\mu)^2}{2\\sigma^2})} + + where :math:`\\mu` is the mean and :math:`\\sigma` is the standard + deviation of the normally distributed logarithm of the variable. + A log-normal distribution results if a random variable is the *product* + of a large number of independent, identically-distributed variables in + the same way that a normal distribution results if the variable is the + *sum* of a large number of independent, identically-distributed + variables. + + References + ---------- + .. [1] Limpert, E., Stahel, W. A., and Abbt, M., "Log-normal + Distributions across the Sciences: Keys and Clues," + BioScience, Vol. 51, No. 5, May, 2001. + https://stat.ethz.ch/~stahel/lognormal/bioscience.pdf + .. [2] Reiss, R.D. and Thomas, M., "Statistical Analysis of Extreme + Values," Basel: Birkhauser Verlag, 2001, pp. 31-32. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, sigma = 3., 1. # mean and standard deviation + >>> s = np.random.lognormal(mu, sigma, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 100, density=True, align='mid') + + >>> x = np.linspace(min(bins), max(bins), 10000) + >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) + ... / (x * sigma * np.sqrt(2 * np.pi))) + + >>> plt.plot(x, pdf, linewidth=2, color='r') + >>> plt.axis('tight') + >>> plt.show() + + Demonstrate that taking the products of random samples from a uniform + distribution can be fit well by a log-normal probability density + function. + + >>> # Generate a thousand samples: each is the product of 100 random + >>> # values, drawn from a normal distribution. + >>> b = [] + >>> for i in range(1000): + ... a = 10. + np.random.random(100) + ... b.append(np.product(a)) + + >>> b = np.array(b) / np.min(b) # scale values to be positive + >>> count, bins, ignored = plt.hist(b, 100, density=True, align='mid') + >>> sigma = np.std(np.log(b)) + >>> mu = np.mean(np.log(b)) + + >>> x = np.linspace(min(bins), max(bins), 10000) + >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) + ... / (x * sigma * np.sqrt(2 * np.pi))) + + >>> plt.plot(x, pdf, color='r', linewidth=2) + >>> plt.show() + + """ + return cont(&legacy_lognormal, self._aug_state, size, self.lock, 2, + mean, 'mean', CONS_NONE, + sigma, 'sigma', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, None) + + def rayleigh(self, scale=1.0, size=None): + """ + rayleigh(scale=1.0, size=None) + + Draw samples from a Rayleigh distribution. + + The :math:`\\chi` and Weibull distributions are generalizations of the + Rayleigh. + + Parameters + ---------- + scale : float or array_like of floats, optional + Scale, also equals the mode. Must be non-negative. Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``scale`` is a scalar. Otherwise, + ``np.array(scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Rayleigh distribution. + + Notes + ----- + The probability density function for the Rayleigh distribution is + + .. math:: P(x;scale) = \\frac{x}{scale^2}e^{\\frac{-x^2}{2 \\cdotp scale^2}} + + The Rayleigh distribution would arise, for example, if the East + and North components of the wind velocity had identical zero-mean + Gaussian distributions. Then the wind speed would have a Rayleigh + distribution. + + References + ---------- + .. [1] Brighton Webs Ltd., "Rayleigh Distribution," + https://web.archive.org/web/20090514091424/http://brighton-webs.co.uk:80/distributions/rayleigh.asp + .. [2] Wikipedia, "Rayleigh distribution" + https://en.wikipedia.org/wiki/Rayleigh_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram + + >>> from matplotlib.pyplot import hist + >>> values = hist(np.random.rayleigh(3, 100000), bins=200, density=True) + + Wave heights tend to follow a Rayleigh distribution. If the mean wave + height is 1 meter, what fraction of waves are likely to be larger than 3 + meters? + + >>> meanvalue = 1 + >>> modevalue = np.sqrt(2 / np.pi) * meanvalue + >>> s = np.random.rayleigh(modevalue, 1000000) + + The percentage of waves larger than 3 meters is: + + >>> 100.*sum(s>3)/1000000. + 0.087300000000000003 # random + + """ + return cont(&random_rayleigh, self._brng, size, self.lock, 1, + scale, 'scale', CONS_NON_NEGATIVE, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE, None) + + def wald(self, mean, scale, size=None): + """ + wald(mean, scale, size=None) + + Draw samples from a Wald, or inverse Gaussian, distribution. + + As the scale approaches infinity, the distribution becomes more like a + Gaussian. Some references claim that the Wald is an inverse Gaussian + with mean equal to 1, but this is by no means universal. + + The inverse Gaussian distribution was first studied in relationship to + Brownian motion. In 1956 M.C.K. Tweedie used the name inverse Gaussian + because there is an inverse relationship between the time to cover a + unit distance and distance covered in unit time. + + Parameters + ---------- + mean : float or array_like of floats + Distribution mean, must be > 0. + scale : float or array_like of floats + Scale parameter, must be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mean`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(mean, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Wald distribution. + + Notes + ----- + The probability density function for the Wald distribution is + + .. math:: P(x;mean,scale) = \\sqrt{\\frac{scale}{2\\pi x^3}}e^ + \\frac{-scale(x-mean)^2}{2\\cdotp mean^2x} + + As noted above the inverse Gaussian distribution first arise + from attempts to model Brownian motion. It is also a + competitor to the Weibull for use in reliability modeling and + modeling stock returns and interest rate processes. + + References + ---------- + .. [1] Brighton Webs Ltd., Wald Distribution, + https://web.archive.org/web/20090423014010/http://www.brighton-webs.co.uk:80/distributions/wald.asp + .. [2] Chhikara, Raj S., and Folks, J. Leroy, "The Inverse Gaussian + Distribution: Theory : Methodology, and Applications", CRC Press, + 1988. + .. [3] Wikipedia, "Inverse Gaussian distribution" + https://en.wikipedia.org/wiki/Inverse_Gaussian_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram: + + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(np.random.wald(3, 2, 100000), bins=200, density=True) + >>> plt.show() + + """ + return cont(&legacy_wald, self._aug_state, size, self.lock, 2, + mean, 'mean', CONS_POSITIVE, + scale, 'scale', CONS_POSITIVE, + 0.0, '', CONS_NONE, None) + + def triangular(self, left, mode, right, size=None): + """ + triangular(left, mode, right, size=None) + + Draw samples from the triangular distribution over the + interval ``[left, right]``. + + The triangular distribution is a continuous probability + distribution with lower limit left, peak at mode, and upper + limit right. Unlike the other distributions, these parameters + directly define the shape of the pdf. + + Parameters + ---------- + left : float or array_like of floats + Lower limit. + mode : float or array_like of floats + The value where the peak of the distribution occurs. + The value should fulfill the condition ``left <= mode <= right``. + right : float or array_like of floats + Upper limit, should be larger than `left`. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``left``, ``mode``, and ``right`` + are all scalars. Otherwise, ``np.broadcast(left, mode, right).size`` + samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized triangular distribution. + + Notes + ----- + The probability density function for the triangular distribution is + + .. math:: P(x;l, m, r) = \\begin{cases} + \\frac{2(x-l)}{(r-l)(m-l)}& \\text{for $l \\leq x \\leq m$},\\\\ + \\frac{2(r-x)}{(r-l)(r-m)}& \\text{for $m \\leq x \\leq r$},\\\\ + 0& \\text{otherwise}. + \\end{cases} + + The triangular distribution is often used in ill-defined + problems where the underlying distribution is not known, but + some knowledge of the limits and mode exists. Often it is used + in simulations. + + References + ---------- + .. [1] Wikipedia, "Triangular distribution" + https://en.wikipedia.org/wiki/Triangular_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram: + + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(np.random.triangular(-3, 0, 8, 100000), bins=200, + ... density=True) + >>> plt.show() + + """ + cdef bint is_scalar = True + cdef double fleft, fmode, fright + cdef np.ndarray oleft, omode, oright + + oleft = np.PyArray_FROM_OTF(left, np.NPY_DOUBLE, np.NPY_ALIGNED) + omode = np.PyArray_FROM_OTF(mode, np.NPY_DOUBLE, np.NPY_ALIGNED) + oright = np.PyArray_FROM_OTF(right, np.NPY_DOUBLE, np.NPY_ALIGNED) + + if np.PyArray_NDIM(oleft) == np.PyArray_NDIM(omode) == np.PyArray_NDIM(oright) == 0: + fleft = PyFloat_AsDouble(left) + fright = PyFloat_AsDouble(right) + fmode = PyFloat_AsDouble(mode) + + if fleft > fmode: + raise ValueError("left > mode") + if fmode > fright: + raise ValueError("mode > right") + if fleft == fright: + raise ValueError("left == right") + return cont(&random_triangular, self._brng, size, self.lock, 3, + fleft, '', CONS_NONE, + fmode, '', CONS_NONE, + fright, '', CONS_NONE, None) + + if np.any(np.greater(oleft, omode)): + raise ValueError("left > mode") + if np.any(np.greater(omode, oright)): + raise ValueError("mode > right") + if np.any(np.equal(oleft, oright)): + raise ValueError("left == right") + + return cont_broadcast_3(&random_triangular, self._brng, size, self.lock, + oleft, '', CONS_NONE, + omode, '', CONS_NONE, + oright, '', CONS_NONE) + + # Complicated, discrete distributions: + def binomial(self, n, p, size=None): + """ + binomial(n, p, size=None) + + Draw samples from a binomial distribution. + + Samples are drawn from a binomial distribution with specified + parameters, n trials and p probability of success where + n an integer >= 0 and p is in the interval [0,1]. (n may be + input as a float, but it is truncated to an integer in use) + + Parameters + ---------- + n : int or array_like of ints + Parameter of the distribution, >= 0. Floats are also accepted, + but they will be truncated to integers. + p : float or array_like of floats + Parameter of the distribution, >= 0 and <=1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``n`` and ``p`` are both scalars. + Otherwise, ``np.broadcast(n, p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized binomial distribution, where + each sample is equal to the number of successes over the n trials. + + See Also + -------- + scipy.stats.binom : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the binomial distribution is + + .. math:: P(N) = \\binom{n}{N}p^N(1-p)^{n-N}, + + where :math:`n` is the number of trials, :math:`p` is the probability + of success, and :math:`N` is the number of successes. + + When estimating the standard error of a proportion in a population by + using a random sample, the normal distribution works well unless the + product p*n <=5, where p = population proportion estimate, and n = + number of samples, in which case the binomial distribution is used + instead. For example, a sample of 15 people shows 4 who are left + handed, and 11 who are right handed. Then p = 4/15 = 27%. 0.27*15 = 4, + so the binomial distribution should be used in this case. + + References + ---------- + .. [1] Dalgaard, Peter, "Introductory Statistics with R", + Springer-Verlag, 2002. + .. [2] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, + Fifth Edition, 2002. + .. [3] Lentner, Marvin, "Elementary Applied Statistics", Bogden + and Quigley, 1972. + .. [4] Weisstein, Eric W. "Binomial Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/BinomialDistribution.html + .. [5] Wikipedia, "Binomial distribution", + https://en.wikipedia.org/wiki/Binomial_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> n, p = 10, .5 # number of trials, probability of each trial + >>> s = np.random.binomial(n, p, 1000) + # result of flipping a coin 10 times, tested 1000 times. + + A real world example. A company drills 9 wild-cat oil exploration + wells, each with an estimated probability of success of 0.1. All nine + wells fail. What is the probability of that happening? + + Let's do 20,000 trials of the model, and count the number that + generate zero positive results. + + >>> sum(np.random.binomial(9, 0.1, 20000) == 0)/20000. + # answer = 0.38885, or 38%. + + """ + + # Uses a custom implementation since self._binomial is required + cdef double _dp = 0 + cdef int64_t _in = 0 + cdef bint is_scalar = True + cdef np.npy_intp i, cnt + cdef np.ndarray randoms + cdef np.int64_t *randoms_data + cdef np.broadcast it + + p_arr = np.PyArray_FROM_OTF(p, np.NPY_DOUBLE, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(p_arr) == 0 + n_arr = np.PyArray_FROM_OTF(n, np.NPY_INT64, np.NPY_ALIGNED) + is_scalar = is_scalar and np.PyArray_NDIM(n_arr) == 0 + + if not is_scalar: + check_array_constraint(p_arr, 'p', CONS_BOUNDED_0_1) + check_array_constraint(n_arr, 'n', CONS_NON_NEGATIVE) + if size is not None: + randoms = np.empty(size, np.int64) + else: + it = np.PyArray_MultiIterNew2(p_arr, n_arr) + randoms = np.empty(it.shape, np.int64) + + randoms_data = np.PyArray_DATA(randoms) + cnt = np.PyArray_SIZE(randoms) + + it = np.PyArray_MultiIterNew3(randoms, p_arr, n_arr) + with self.lock, nogil: + for i in range(cnt): + _dp = (np.PyArray_MultiIter_DATA(it, 1))[0] + _in = (np.PyArray_MultiIter_DATA(it, 2))[0] + (np.PyArray_MultiIter_DATA(it, 0))[0] = random_binomial(self._brng, _dp, _in, self._binomial) + + np.PyArray_MultiIter_NEXT(it) + + return randoms + + _dp = PyFloat_AsDouble(p) + _in = n + check_constraint(_dp, 'p', CONS_BOUNDED_0_1) + check_constraint(_in, 'n', CONS_NON_NEGATIVE) + + if size is None: + with self.lock: + return random_binomial(self._brng, _dp, _in, self._binomial) + + randoms = np.empty(size, np.int64) + cnt = np.PyArray_SIZE(randoms) + randoms_data = np.PyArray_DATA(randoms) + + with self.lock, nogil: + for i in range(cnt): + randoms_data[i] = random_binomial(self._brng, _dp, _in, + self._binomial) + + return randoms + + def negative_binomial(self, n, p, size=None): + """ + negative_binomial(n, p, size=None) + + Draw samples from a negative binomial distribution. + + Samples are drawn from a negative binomial distribution with specified + parameters, `n` successes and `p` probability of success where `n` + is > 0 and `p` is in the interval [0, 1]. + + Parameters + ---------- + n : float or array_like of floats + Parameter of the distribution, > 0. + p : float or array_like of floats + Parameter of the distribution, >= 0 and <=1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``n`` and ``p`` are both scalars. + Otherwise, ``np.broadcast(n, p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized negative binomial distribution, + where each sample is equal to N, the number of failures that + occurred before a total of n successes was reached. + + Notes + ----- + The probability mass function of the negative binomial distribution is + + .. math:: P(N;n,p) = \\frac{\\Gamma(N+n)}{N!\\Gamma(n)}p^{n}(1-p)^{N}, + + where :math:`n` is the number of successes, :math:`p` is the + probability of success, :math:`N+n` is the number of trials, and + :math:`\\Gamma` is the gamma function. When :math:`n` is an integer, + :math:`\\frac{\\Gamma(N+n)}{N!\\Gamma(n)} = \\binom{N+n-1}{N}`, which is + the more common form of this term in the the pmf. The negative + binomial distribution gives the probability of N failures given n + successes, with a success on the last trial. + + If one throws a die repeatedly until the third time a "1" appears, + then the probability distribution of the number of non-"1"s that + appear before the third "1" is a negative binomial distribution. + + References + ---------- + .. [1] Weisstein, Eric W. "Negative Binomial Distribution." From + MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/NegativeBinomialDistribution.html + .. [2] Wikipedia, "Negative binomial distribution", + https://en.wikipedia.org/wiki/Negative_binomial_distribution + + Examples + -------- + Draw samples from the distribution: + + A real world example. A company drills wild-cat oil + exploration wells, each with an estimated probability of + success of 0.1. What is the probability of having one success + for each successive well, that is what is the probability of a + single success after drilling 5 wells, after 6 wells, etc.? + + >>> s = np.random.negative_binomial(1, 0.1, 100000) + >>> for i in range(1, 11): # doctest: +SKIP + ... probability = sum(s= 0. A sequence of expectation + intervals must be broadcastable over the requested size. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``lam`` is a scalar. Otherwise, + ``np.array(lam).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Poisson distribution. + + Notes + ----- + The Poisson distribution + + .. math:: f(k; \\lambda)=\\frac{\\lambda^k e^{-\\lambda}}{k!} + + For events with an expected separation :math:`\\lambda` the Poisson + distribution :math:`f(k; \\lambda)` describes the probability of + :math:`k` events occurring within the observed + interval :math:`\\lambda`. + + Because the output is limited to the range of the C int64 type, a + ValueError is raised when `lam` is within 10 sigma of the maximum + representable value. + + References + ---------- + .. [1] Weisstein, Eric W. "Poisson Distribution." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/PoissonDistribution.html + .. [2] Wikipedia, "Poisson distribution", + https://en.wikipedia.org/wiki/Poisson_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> import numpy as np + >>> s = np.random.poisson(5, 10000) + + Display histogram of the sample: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 14, density=True) + >>> plt.show() + + Draw each 100 values for lambda 100 and 500: + + >>> s = np.random.poisson(lam=(100., 500.), size=(100, 2)) + + """ + return disc(&random_poisson, self._brng, size, self.lock, 1, 0, + lam, 'lam', CONS_POISSON, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) + + def zipf(self, a, size=None): + """ + zipf(a, size=None) + + Draw samples from a Zipf distribution. + + Samples are drawn from a Zipf distribution with specified parameter + `a` > 1. + + The Zipf distribution (also known as the zeta distribution) is a + continuous probability distribution that satisfies Zipf's law: the + frequency of an item is inversely proportional to its rank in a + frequency table. + + Parameters + ---------- + a : float or array_like of floats + Distribution parameter. Should be greater than 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Zipf distribution. + + See Also + -------- + scipy.stats.zipf : probability density function, distribution, or + cumulative density function, etc. + + Notes + ----- + The probability density for the Zipf distribution is + + .. math:: p(x) = \\frac{x^{-a}}{\\zeta(a)}, + + where :math:`\\zeta` is the Riemann Zeta function. + + It is named for the American linguist George Kingsley Zipf, who noted + that the frequency of any word in a sample of a language is inversely + proportional to its rank in the frequency table. + + References + ---------- + .. [1] Zipf, G. K., "Selected Studies of the Principle of Relative + Frequency in Language," Cambridge, MA: Harvard Univ. Press, + 1932. + + Examples + -------- + Draw samples from the distribution: + + >>> a = 2. # parameter + >>> s = np.random.zipf(a, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> from scipy import special + + Truncate s values at 50 so plot is interesting: + + >>> count, bins, ignored = plt.hist(s[s<50], 50, density=True) + >>> x = np.arange(1., 50.) + >>> y = x**(-a) / special.zetac(a) + >>> plt.plot(x, y/max(y), linewidth=2, color='r') + >>> plt.show() + + """ + return disc(&random_zipf, self._brng, size, self.lock, 1, 0, + a, 'a', CONS_GT_1, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) + + def geometric(self, p, size=None): + """ + geometric(p, size=None) + + Draw samples from the geometric distribution. + + Bernoulli trials are experiments with one of two outcomes: + success or failure (an example of such an experiment is flipping + a coin). The geometric distribution models the number of trials + that must be run in order to achieve success. It is therefore + supported on the positive integers, ``k = 1, 2, ...``. + + The probability mass function of the geometric distribution is + + .. math:: f(k) = (1 - p)^{k - 1} p + + where `p` is the probability of success of an individual trial. + + Parameters + ---------- + p : float or array_like of floats + The probability of success of an individual trial. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``p`` is a scalar. Otherwise, + ``np.array(p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized geometric distribution. + + Examples + -------- + Draw ten thousand values from the geometric distribution, + with the probability of an individual success equal to 0.35: + + >>> z = np.random.geometric(p=0.35, size=10000) + + How many trials succeeded after a single run? + + >>> (z == 1).sum() / 10000. + 0.34889999999999999 #random + + """ + return disc(&random_geometric, self._brng, size, self.lock, 1, 0, + p, 'p', CONS_BOUNDED_GT_0_1, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) + + def hypergeometric(self, ngood, nbad, nsample, size=None): + """ + hypergeometric(ngood, nbad, nsample, size=None) + + Draw samples from a Hypergeometric distribution. + + Samples are drawn from a hypergeometric distribution with specified + parameters, `ngood` (ways to make a good selection), `nbad` (ways to make + a bad selection), and `nsample` (number of items sampled, which is less + than or equal to the sum ``ngood + nbad``). + + Parameters + ---------- + ngood : int or array_like of ints + Number of ways to make a good selection. Must be nonnegative. + nbad : int or array_like of ints + Number of ways to make a bad selection. Must be nonnegative. + nsample : int or array_like of ints + Number of items sampled. Must be at least 1 and at most + ``ngood + nbad``. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if `ngood`, `nbad`, and `nsample` + are all scalars. Otherwise, ``np.broadcast(ngood, nbad, nsample).size`` + samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized hypergeometric distribution. Each + sample is the number of good items within a randomly selected subset of + size `nsample` taken from a set of `ngood` good items and `nbad` bad items. + + See Also + -------- + scipy.stats.hypergeom : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Hypergeometric distribution is + + .. math:: P(x) = \\frac{\\binom{g}{x}\\binom{b}{n-x}}{\\binom{g+b}{n}}, + + where :math:`0 \\le x \\le n` and :math:`n-b \\le x \\le g` + + for P(x) the probability of ``x`` good results in the drawn sample, + g = `ngood`, b = `nbad`, and n = `nsample`. + + Consider an urn with black and white marbles in it, `ngood` of them + are black and `nbad` are white. If you draw `nsample` balls without + replacement, then the hypergeometric distribution describes the + distribution of black balls in the drawn sample. + + Note that this distribution is very similar to the binomial + distribution, except that in this case, samples are drawn without + replacement, whereas in the Binomial case samples are drawn with + replacement (or the sample space is infinite). As the sample space + becomes large, this distribution approaches the binomial. + + References + ---------- + .. [1] Lentner, Marvin, "Elementary Applied Statistics", Bogden + and Quigley, 1972. + .. [2] Weisstein, Eric W. "Hypergeometric Distribution." From + MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/HypergeometricDistribution.html + .. [3] Wikipedia, "Hypergeometric distribution", + https://en.wikipedia.org/wiki/Hypergeometric_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> ngood, nbad, nsamp = 100, 2, 10 + # number of good, number of bad, and number of samples + >>> s = np.random.hypergeometric(ngood, nbad, nsamp, 1000) + >>> from matplotlib.pyplot import hist + >>> hist(s) + # note that it is very unlikely to grab both bad items + + Suppose you have an urn with 15 white and 15 black marbles. + If you pull 15 marbles at random, how likely is it that + 12 or more of them are one color? + + >>> s = np.random.hypergeometric(15, 15, 15, 100000) + >>> sum(s>=12)/100000. + sum(s<=3)/100000. + # answer = 0.003 ... pretty unlikely! + + """ + cdef bint is_scalar = True + cdef np.ndarray ongood, onbad, onsample + cdef int64_t lngood, lnbad, lnsample + + ongood = np.PyArray_FROM_OTF(ngood, np.NPY_INT64, np.NPY_ALIGNED) + onbad = np.PyArray_FROM_OTF(nbad, np.NPY_INT64, np.NPY_ALIGNED) + onsample = np.PyArray_FROM_OTF(nsample, np.NPY_INT64, np.NPY_ALIGNED) + + if np.PyArray_NDIM(ongood) == np.PyArray_NDIM(onbad) == np.PyArray_NDIM(onsample) == 0: + + lngood = ngood + lnbad = nbad + lnsample = nsample + + if lngood + lnbad < lnsample: + raise ValueError("ngood + nbad < nsample") + return disc(&random_hypergeometric, self._brng, size, self.lock, 0, 3, + lngood, 'ngood', CONS_NON_NEGATIVE, + lnbad, 'nbad', CONS_NON_NEGATIVE, + lnsample, 'nsample', CONS_GTE_1) + + if np.any(np.less(np.add(ongood, onbad), onsample)): + raise ValueError("ngood + nbad < nsample") + return discrete_broadcast_iii(&random_hypergeometric, self._brng, size, self.lock, + ongood, 'ngood', CONS_NON_NEGATIVE, + onbad, 'nbad', CONS_NON_NEGATIVE, + onsample, 'nsample', CONS_GTE_1) + + def logseries(self, p, size=None): + """ + logseries(p, size=None) + + Draw samples from a logarithmic series distribution. + + Samples are drawn from a log series distribution with specified + shape parameter, 0 < ``p`` < 1. + + Parameters + ---------- + p : float or array_like of floats + Shape parameter for the distribution. Must be in the range (0, 1). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``p`` is a scalar. Otherwise, + ``np.array(p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized logarithmic series distribution. + + See Also + -------- + scipy.stats.logser : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Log Series distribution is + + .. math:: P(k) = \\frac{-p^k}{k \\ln(1-p)}, + + where p = probability. + + The log series distribution is frequently used to represent species + richness and occurrence, first proposed by Fisher, Corbet, and + Williams in 1943 [2]. It may also be used to model the numbers of + occupants seen in cars [3]. + + References + ---------- + .. [1] Buzas, Martin A.; Culver, Stephen J., Understanding regional + species diversity through the log series distribution of + occurrences: BIODIVERSITY RESEARCH Diversity & Distributions, + Volume 5, Number 5, September 1999 , pp. 187-195(9). + .. [2] Fisher, R.A,, A.S. Corbet, and C.B. Williams. 1943. The + relation between the number of species and the number of + individuals in a random sample of an animal population. + Journal of Animal Ecology, 12:42-58. + .. [3] D. J. Hand, F. Daly, D. Lunn, E. Ostrowski, A Handbook of Small + Data Sets, CRC Press, 1994. + .. [4] Wikipedia, "Logarithmic distribution", + https://en.wikipedia.org/wiki/Logarithmic_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a = .6 + >>> s = np.random.logseries(a, 10000) + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s) + + # plot against distribution + + >>> def logseries(k, p): + ... return -p**k/(k*np.log(1-p)) + >>> plt.plot(bins, logseries(bins, a)*count.max()/ + ... logseries(bins, a).max(), 'r') + >>> plt.show() + + """ + return disc(&random_logseries, self._brng, size, self.lock, 1, 0, + p, 'p', CONS_BOUNDED_0_1, + 0.0, '', CONS_NONE, + 0.0, '', CONS_NONE) + + # Multivariate distributions: + def multivariate_normal(self, mean, cov, size=None, check_valid='warn', + tol=1e-8): + """ + multivariate_normal(mean, cov, size=None, check_valid='warn', tol=1e-8) + + Draw random samples from a multivariate normal distribution. + + The multivariate normal, multinormal or Gaussian distribution is a + generalization of the one-dimensional normal distribution to higher + dimensions. Such a distribution is specified by its mean and + covariance matrix. These parameters are analogous to the mean + (average or "center") and variance (standard deviation, or "width," + squared) of the one-dimensional normal distribution. + + Parameters + ---------- + mean : 1-D array_like, of length N + Mean of the N-dimensional distribution. + cov : 2-D array_like, of shape (N, N) + Covariance matrix of the distribution. It must be symmetric and + positive-semidefinite for proper sampling. + size : int or tuple of ints, optional + Given a shape of, for example, ``(m,n,k)``, ``m*n*k`` samples are + generated, and packed in an `m`-by-`n`-by-`k` arrangement. Because + each sample is `N`-dimensional, the output shape is ``(m,n,k,N)``. + If no shape is specified, a single (`N`-D) sample is returned. + check_valid : { 'warn', 'raise', 'ignore' }, optional + Behavior when the covariance matrix is not positive semidefinite. + tol : float, optional + Tolerance when checking the singular values in covariance matrix. + cov is cast to double before the check. + + Returns + ------- + out : ndarray + The drawn samples, of shape *size*, if that was provided. If not, + the shape is ``(N,)``. + + In other words, each entry ``out[i,j,...,:]`` is an N-dimensional + value drawn from the distribution. + + Notes + ----- + The mean is a coordinate in N-dimensional space, which represents the + location where samples are most likely to be generated. This is + analogous to the peak of the bell curve for the one-dimensional or + univariate normal distribution. + + Covariance indicates the level to which two variables vary together. + From the multivariate normal distribution, we draw N-dimensional + samples, :math:`X = [x_1, x_2, ... x_N]`. The covariance matrix + element :math:`C_{ij}` is the covariance of :math:`x_i` and :math:`x_j`. + The element :math:`C_{ii}` is the variance of :math:`x_i` (i.e. its + "spread"). + + Instead of specifying the full covariance matrix, popular + approximations include: + + - Spherical covariance (`cov` is a multiple of the identity matrix) + - Diagonal covariance (`cov` has non-negative elements, and only on + the diagonal) + + This geometrical property can be seen in two dimensions by plotting + generated data-points: + + >>> mean = [0, 0] + >>> cov = [[1, 0], [0, 100]] # diagonal covariance + + Diagonal covariance means that points are oriented along x or y-axis: + + >>> import matplotlib.pyplot as plt + >>> x, y = np.random.multivariate_normal(mean, cov, 5000).T + >>> plt.plot(x, y, 'x') + >>> plt.axis('equal') + >>> plt.show() + + Note that the covariance matrix must be positive semidefinite (a.k.a. + nonnegative-definite). Otherwise, the behavior of this method is + undefined and backwards compatibility is not guaranteed. + + References + ---------- + .. [1] Papoulis, A., "Probability, Random Variables, and Stochastic + Processes," 3rd ed., New York: McGraw-Hill, 1991. + .. [2] Duda, R. O., Hart, P. E., and Stork, D. G., "Pattern + Classification," 2nd ed., New York: Wiley, 2001. + + Examples + -------- + >>> mean = (1, 2) + >>> cov = [[1, 0], [0, 1]] + >>> x = np.random.multivariate_normal(mean, cov, (3, 3)) + >>> x.shape + (3, 3, 2) + + The following is probably true, given that 0.6 is roughly twice the + standard deviation: + + >>> list((x[0,0,:] - mean) < 0.6) + [True, True] # random + + """ + from numpy.dual import svd + + # Check preconditions on arguments + mean = np.array(mean) + cov = np.array(cov) + if size is None: + shape = [] + elif isinstance(size, (int, long, np.integer)): + shape = [size] + else: + shape = size + + if len(mean.shape) != 1: + raise ValueError("mean must be 1 dimensional") + if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + raise ValueError("cov must be 2 dimensional and square") + if mean.shape[0] != cov.shape[0]: + raise ValueError("mean and cov must have same length") + + # Compute shape of output and create a matrix of independent + # standard normally distributed random numbers. The matrix has rows + # with the same length as mean and as many rows are necessary to + # form a matrix of shape final_shape. + final_shape = list(shape[:]) + final_shape.append(mean.shape[0]) + x = self.standard_normal(final_shape).reshape(-1, mean.shape[0]) + + # Transform matrix of standard normals into matrix where each row + # contains multivariate normals with the desired covariance. + # Compute A such that dot(transpose(A),A) == cov. + # Then the matrix products of the rows of x and A has the desired + # covariance. Note that sqrt(s)*v where (u,s,v) is the singular value + # decomposition of cov is such an A. + # + # Also check that cov is positive-semidefinite. If so, the u.T and v + # matrices should be equal up to roundoff error if cov is + # symmetric and the singular value of the corresponding row is + # not zero. We continue to use the SVD rather than Cholesky in + # order to preserve current outputs. Note that symmetry has not + # been checked. + + # GH10839, ensure double to make tol meaningful + cov = cov.astype(np.double) + (u, s, v) = svd(cov) + + if check_valid != 'ignore': + if check_valid != 'warn' and check_valid != 'raise': + raise ValueError( + "check_valid must equal 'warn', 'raise', or 'ignore'") + + psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) + if not psd: + if check_valid == 'warn': + warnings.warn("covariance is not positive-semidefinite.", + RuntimeWarning) + else: + raise ValueError( + "covariance is not positive-semidefinite.") + + x = np.dot(x, np.sqrt(s)[:, None] * v) + x += mean + x.shape = tuple(final_shape) + return x + + def multinomial(self, np.npy_intp n, object pvals, size=None): + """ + multinomial(n, pvals, size=None) + + Draw samples from a multinomial distribution. + + The multinomial distribution is a multivariate generalisation of the + binomial distribution. Take an experiment with one of ``p`` + possible outcomes. An example of such an experiment is throwing a dice, + where the outcome can be 1 through 6. Each sample drawn from the + distribution represents `n` such experiments. Its values, + ``X_i = [X_0, X_1, ..., X_p]``, represent the number of times the + outcome was ``i``. + + Parameters + ---------- + n : int + Number of experiments. + pvals : sequence of floats, length p + Probabilities of each of the ``p`` different outcomes. These + should sum to 1 (however, the last element is always assumed to + account for the remaining probability, as long as + ``sum(pvals[:-1]) <= 1)``. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : ndarray + The drawn samples, of shape *size*, if that was provided. If not, + the shape is ``(N,)``. + + In other words, each entry ``out[i,j,...,:]`` is an N-dimensional + value drawn from the distribution. + + Examples + -------- + Throw a dice 20 times: + + >>> np.random.multinomial(20, [1/6.]*6, size=1) + array([[4, 1, 7, 5, 2, 1]]) # random + + It landed 4 times on 1, once on 2, etc. + + Now, throw the dice 20 times, and 20 times again: + + >>> np.random.multinomial(20, [1/6.]*6, size=2) + array([[3, 4, 3, 3, 4, 3], # random + [2, 4, 3, 4, 0, 7]]) + + For the first run, we threw 3 times 1, 4 times 2, etc. For the second, + we threw 2 times 1, 4 times 2, etc. + + A loaded die is more likely to land on number 6: + + >>> np.random.multinomial(100, [1/7.]*5 + [2/7.]) + array([11, 16, 14, 17, 16, 26]) # random + + The probability inputs should be normalized. As an implementation + detail, the value of the last entry is ignored and assumed to take + up any leftover probability mass, but this should not be relied on. + A biased coin which has twice as much weight on one side as on the + other should be sampled like so: + + >>> np.random.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT + array([38, 62]) # random + + not like: + + >>> np.random.multinomial(100, [1.0, 2.0]) # WRONG + array([100, 0]) + + """ + cdef np.npy_intp d, i, j, dn, sz + cdef np.ndarray parr "arrayObject_parr", mnarr "arrayObject_mnarr" + cdef double *pix + cdef int64_t *mnix + cdef double Sum + + d = len(pvals) + parr = np.PyArray_FROM_OTF(pvals, np.NPY_DOUBLE, np.NPY_ALIGNED) + pix = np.PyArray_DATA(parr) + + if kahan_sum(pix, d-1) > (1.0 + 1e-12): + raise ValueError("sum(pvals[:-1]) > 1.0") + + if size is None: + shape = (d,) + else: + try: + shape = (operator.index(size), d) + except: + shape = tuple(size) + (d,) + + multin = np.zeros(shape, dtype=np.int64) + mnarr = multin + mnix = np.PyArray_DATA(mnarr) + sz = np.PyArray_SIZE(mnarr) + + with self.lock, nogil: + i = 0 + while i < sz: + Sum = 1.0 + dn = n + for j in range(d-1): + mnix[i+j] = random_binomial(self._brng, pix[j]/Sum, dn, + self._binomial) + dn = dn - mnix[i+j] + if dn <= 0: + break + Sum = Sum - pix[j] + if dn > 0: + mnix[i+d-1] = dn + + i = i + d + + return multin + + def dirichlet(self, object alpha, size=None): + """ + dirichlet(alpha, size=None) + + Draw samples from the Dirichlet distribution. + + Draw `size` samples of dimension k from a Dirichlet distribution. A + Dirichlet-distributed random variable can be seen as a multivariate + generalization of a Beta distribution. The Dirichlet distribution + is a conjugate prior of a multinomial distribution in Bayesian + inference. + + Parameters + ---------- + alpha : array + Parameter of the distribution (k dimension for sample of + dimension k). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + samples : ndarray, + The drawn samples, of shape (size, alpha.ndim). + + Raises + ------- + ValueError + If any value in alpha is less than or equal to zero + + Notes + ----- + + The Dirichlet distribution is a distribution over vectors + :math:`x` that fulfil the conditions :math:`x_i>0` and + :math:`\\sum_{i=1}^k x_i = 1`. + + The probability density function :math:`p` of a + Dirichlet-distributed random vector :math:`X` is + proportional to + + .. math:: p(x) \\propto \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i}, + + where :math:`\\alpha` is a vector containing the positive + concentration parameters. + + The method uses the following property for computation: let :math:`Y` + be a random vector which has components that follow a standard gamma + distribution, then :math:`X = \\frac{1}{\\sum_{i=1}^k{Y_i}} Y` + is Dirichlet-distributed + + References + ---------- + .. [1] David McKay, "Information Theory, Inference and Learning + Algorithms," chapter 23, + http://www.inference.org.uk/mackay/itila/ + .. [2] Wikipedia, "Dirichlet distribution", + https://en.wikipedia.org/wiki/Dirichlet_distribution + + Examples + -------- + Taking an example cited in Wikipedia, this distribution can be used if + one wanted to cut strings (each of initial length 1.0) into K pieces + with different lengths, where each piece had, on average, a designated + average length, but allowing some variation in the relative sizes of + the pieces. + + >>> s = np.random.dirichlet((10, 5, 3), 20).transpose() + + >>> import matplotlib.pyplot as plt + >>> plt.barh(range(20), s[0]) + >>> plt.barh(range(20), s[1], left=s[0], color='g') + >>> plt.barh(range(20), s[2], left=s[0]+s[1], color='r') + >>> plt.title("Lengths of Strings") + + """ + + # ================= + # Pure python algo + # ================= + # alpha = N.atleast_1d(alpha) + # k = alpha.size + + # if n == 1: + # val = N.zeros(k) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val) + # else: + # val = N.zeros((k, n)) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val, axis = 0) + # val = val.T + # return val + + cdef np.npy_intp k, totsize, i, j + cdef np.ndarray alpha_arr, val_arr + cdef double *alpha_data + cdef double *val_data + cdef double acc, invacc + + k = len(alpha) + alpha_arr = np.PyArray_FROM_OTF(alpha, np.NPY_DOUBLE, np.NPY_ALIGNED) + if np.any(np.less_equal(alpha_arr, 0)): + raise ValueError('alpha <= 0') + alpha_data = np.PyArray_DATA(alpha_arr) + + if size is None: + shape = (k,) + else: + try: + shape = (operator.index(size), k) + except: + shape = tuple(size) + (k,) + + diric = np.zeros(shape, np.float64) + val_arr = diric + val_data = np.PyArray_DATA(val_arr) + + i = 0 + totsize = np.PyArray_SIZE(val_arr) + with self.lock, nogil: + while i < totsize: + acc = 0.0 + for j in range(k): + val_data[i+j] = legacy_standard_gamma(self._aug_state, + alpha_data[j]) + acc = acc + val_data[i + j] + invacc = 1/acc + for j in range(k): + val_data[i + j] = val_data[i + j] * invacc + i = i + k + + return diric + + # Shuffling and permutations: + def shuffle(self, object x): + """ + shuffle(x) + + Modify a sequence in-place by shuffling its contents. + + This function only shuffles the array along the first axis of a + multi-dimensional array. The order of sub-arrays is changed but + their contents remains the same. + + Parameters + ---------- + x : array_like + The array or list to be shuffled. + + Returns + ------- + None + + Examples + -------- + >>> arr = np.arange(10) + >>> np.random.shuffle(arr) + >>> arr + [1 7 5 2 9 4 3 6 0 8] # random + + Multi-dimensional arrays are only shuffled along the first axis: + + >>> arr = np.arange(9).reshape((3, 3)) + >>> np.random.shuffle(arr) + >>> arr + array([[3, 4, 5], # random + [6, 7, 8], + [0, 1, 2]]) + + """ + cdef: + np.npy_intp i, j, n = len(x), stride, itemsize + char* x_ptr + char* buf_ptr + + if type(x) is np.ndarray and x.ndim == 1 and x.size: + # Fast, statically typed path: shuffle the underlying buffer. + # Only for non-empty, 1d objects of class ndarray (subclasses such + # as MaskedArrays may not support this approach). + x_ptr = x.ctypes.data + stride = x.strides[0] + itemsize = x.dtype.itemsize + # As the array x could contain python objects we use a buffer + # of bytes for the swaps to avoid leaving one of the objects + # within the buffer and erroneously decrementing it's refcount + # when the function exits. + buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit + buf_ptr = buf.ctypes.data + with self.lock: + # We trick gcc into providing a specialized implementation for + # the most common case, yielding a ~33% performance improvement. + # Note that apparently, only one branch can ever be specialized. + if itemsize == sizeof(np.npy_intp): + self._shuffle_raw(n, sizeof(np.npy_intp), stride, x_ptr, buf_ptr) + else: + self._shuffle_raw(n, itemsize, stride, x_ptr, buf_ptr) + elif isinstance(x, np.ndarray) and x.ndim and x.size: + buf = np.empty_like(x[0, ...]) + with self.lock: + for i in reversed(range(1, n)): + j = random_interval(self._brng, i) + if i == j: + continue # i == j is not needed and memcpy is undefined. + buf[...] = x[j] + x[j] = x[i] + x[i] = buf + else: + # Untyped path. + with self.lock: + for i in reversed(range(1, n)): + j = random_interval(self._brng, i) + x[i], x[j] = x[j], x[i] + + cdef inline _shuffle_raw(self, np.npy_intp n, np.npy_intp itemsize, + np.npy_intp stride, char* data, char* buf): + cdef np.npy_intp i, j + for i in reversed(range(1, n)): + j = random_interval(self._brng, i) + string.memcpy(buf, data + j * stride, itemsize) + string.memcpy(data + j * stride, data + i * stride, itemsize) + string.memcpy(data + i * stride, buf, itemsize) + + def permutation(self, object x): + """ + permutation(x) + + Randomly permute a sequence, or return a permuted range. + + If `x` is a multi-dimensional array, it is only shuffled along its + first index. + + Parameters + ---------- + x : int or array_like + If `x` is an integer, randomly permute ``np.arange(x)``. + If `x` is an array, make a copy and shuffle the elements + randomly. + + Returns + ------- + out : ndarray + Permuted sequence or array range. + + Examples + -------- + >>> np.random.permutation(10) + array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) # random + + >>> np.random.permutation([1, 4, 9, 12, 15]) + array([15, 1, 9, 4, 12]) # random + + >>> arr = np.arange(9).reshape((3, 3)) + >>> np.random.permutation(arr) + array([[6, 7, 8], # random + [0, 1, 2], + [3, 4, 5]]) + + """ + if isinstance(x, (int, long, np.integer)): + arr = np.arange(x) + self.shuffle(arr) + return arr + + arr = np.asarray(x) + + # shuffle has fast-path for 1-d + if arr.ndim == 1: + # Return a copy if same memory + if np.may_share_memory(arr, x): + arr = np.array(arr) + self.shuffle(arr) + return arr + + # Shuffle index array, dtype to ensure fast path + idx = np.arange(arr.shape[0], dtype=np.intp) + self.shuffle(idx) + return arr[idx] + +_mtrand = RandomState() + +beta = _mtrand.beta +binomial = _mtrand.binomial +bytes = _mtrand.bytes +chisquare = _mtrand.chisquare +choice = _mtrand.choice +dirichlet = _mtrand.dirichlet +exponential = _mtrand.exponential +f = _mtrand.f +gamma = _mtrand.gamma +get_state = _mtrand.get_state +geometric = _mtrand.geometric +gumbel = _mtrand.gumbel +hypergeometric = _mtrand.hypergeometric +laplace = _mtrand.laplace +logistic = _mtrand.logistic +lognormal = _mtrand.lognormal +logseries = _mtrand.logseries +multinomial = _mtrand.multinomial +multivariate_normal = _mtrand.multivariate_normal +negative_binomial = _mtrand.negative_binomial +noncentral_chisquare = _mtrand.noncentral_chisquare +noncentral_f = _mtrand.noncentral_f +normal = _mtrand.normal +pareto = _mtrand.pareto +permutation = _mtrand.permutation +poisson = _mtrand.poisson +power = _mtrand.power +rand = _mtrand.rand +randint = _mtrand.randint +randn = _mtrand.randn +random = _mtrand.random_sample +random_integers = _mtrand.random_integers +random_sample = _mtrand.random_sample +ranf = _mtrand.random_sample +rayleigh = _mtrand.rayleigh +sample = _mtrand.random_sample +seed = _mtrand.seed +set_state = _mtrand.set_state +shuffle = _mtrand.shuffle +standard_cauchy = _mtrand.standard_cauchy +standard_exponential = _mtrand.standard_exponential +standard_gamma = _mtrand.standard_gamma +standard_normal = _mtrand.standard_normal +standard_t = _mtrand.standard_t +triangular = _mtrand.triangular +uniform = _mtrand.uniform +vonmises = _mtrand.vonmises +wald = _mtrand.wald +weibull = _mtrand.weibull +zipf = _mtrand.zipf diff --git a/numpy/random/randomgen/pcg32.pyx b/numpy/random/randomgen/pcg32.pyx index ef2668d98384..b163f3f950cd 100644 --- a/numpy/random/randomgen/pcg32.pyx +++ b/numpy/random/randomgen/pcg32.pyx @@ -1,8 +1,11 @@ -from __future__ import absolute_import - from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock + import numpy as np cimport numpy as np @@ -23,14 +26,14 @@ cdef extern from "src/pcg32/pcg32.h": ctypedef pcg_state_setseq_64 pcg32_random_t struct s_pcg32_state: - pcg32_random_t *pcg_state + pcg32_random_t *pcg_state ctypedef s_pcg32_state pcg32_state uint64_t pcg32_next64(pcg32_state *state) nogil uint32_t pcg32_next32(pcg32_state *state) nogil double pcg32_next_double(pcg32_state *state) nogil - void pcg32_jump(pcg32_state *state) + void pcg32_jump(pcg32_state *state) void pcg32_advance_state(pcg32_state *state, uint64_t step) void pcg32_set_seed(pcg32_state *state, uint64_t seed, uint64_t inc) @@ -122,12 +125,14 @@ cdef class PCG32: cdef object _ctypes cdef object _cffi cdef object _generator + cdef public object lock def __init__(self, seed=None, inc=0): self.rng_state = malloc(sizeof(pcg32_state)) self.rng_state.pcg_state = malloc(sizeof(pcg32_random_t)) self._brng = malloc(sizeof(brng_t)) self.seed(seed, inc) + self.lock = Lock() self._brng.state = self.rng_state self._brng.next_uint64 = &pcg32_uint64 @@ -159,42 +164,39 @@ cdef class PCG32: free(self.rng_state) free(self._brng) - def __random_integer(self, bits=64): + def random_raw(self, size=None, output=True): """ - 64-bit Random Integers from the PRNG + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG Parameters ---------- - bits : {32, 64} - Number of random bits to return + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. Returns ------- - rv : int - Next random value + out : uint or ndarray + Drawn samples. Notes ----- - Testing only + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. """ - if bits == 64: - return self._brng.next_uint64(self._brng.state) - elif bits == 32: - return self._brng.next_uint32(self._brng.state) - else: - raise ValueError('bits must be 32 or 64') + return random_raw(self._brng, self.lock, size, output) def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - cdef Py_ssize_t i - if method==u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method==u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') - + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None, inc=0): """ @@ -218,7 +220,7 @@ cdef class PCG32: ValueError If seed values are out of range for the PRNG. """ - ub = 2 ** 64 + ub = 2 ** 64 if seed is None: try: seed = random_entropy(2) @@ -257,7 +259,7 @@ cdef class PCG32: """ return {'brng': self.__class__.__name__, 'state': {'state': self.rng_state.pcg_state.state, - 'inc':self.rng_state.pcg_state.inc}} + 'inc': self.rng_state.pcg_state.inc}} @state.setter def state(self, value): @@ -267,7 +269,7 @@ cdef class PCG32: if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'PRNG'.format(self.__class__.__name__)) - self.rng_state.pcg_state.state = value['state']['state'] + self.rng_state.pcg_state.state = value['state']['state'] self.rng_state.pcg_state.inc = value['state']['inc'] def advance(self, delta): @@ -327,12 +329,12 @@ cdef class PCG32: @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -341,25 +343,10 @@ cdef class PCG32: * next_double - function pointer to produce doubles * brng - pointer to the Basic RNG struct """ + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&pcg32_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&pcg32_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&pcg32_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) - return self.ctypes + return self._ctypes @property def cffi(self): @@ -380,19 +367,8 @@ cdef class PCG32: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): diff --git a/numpy/random/randomgen/pcg64.pyx b/numpy/random/randomgen/pcg64.pyx index 66bf3a47148b..d69535111b27 100644 --- a/numpy/random/randomgen/pcg64.pyx +++ b/numpy/random/randomgen/pcg64.pyx @@ -1,8 +1,11 @@ -from __future__ import absolute_import - from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock + import numpy as np cimport numpy as np @@ -35,15 +38,15 @@ cdef extern from "src/pcg64/pcg64.h": ctypedef pcg_state_setseq_128 pcg64_random_t struct s_pcg64_state: - pcg64_random_t *pcg_state - int has_uint32 - uint32_t uinteger + pcg64_random_t *pcg_state + int has_uint32 + uint32_t uinteger ctypedef s_pcg64_state pcg64_state uint64_t pcg64_next64(pcg64_state *state) nogil uint32_t pcg64_next32(pcg64_state *state) nogil - void pcg64_jump(pcg64_state *state) + void pcg64_jump(pcg64_state *state) void pcg64_advance(pcg64_state *state, uint64_t *step) void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc) @@ -133,12 +136,14 @@ cdef class PCG64: cdef object _ctypes cdef object _cffi cdef object _generator + cdef public object lock def __init__(self, seed=None, inc=0): self.rng_state = malloc(sizeof(pcg64_state)) self.rng_state.pcg_state = malloc(sizeof(pcg64_random_t)) self._brng = malloc(sizeof(brng_t)) self.seed(seed, inc) + self.lock = Lock() self._brng.state = self.rng_state self._brng.next_uint64 = &pcg64_uint64 @@ -174,42 +179,39 @@ cdef class PCG64: self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - def __random_integer(self, bits=64): + def random_raw(self, size=None, output=True): """ - 64-bit Random Integers from the RNG + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG Parameters ---------- - bits : {32, 64} - Number of random bits to return + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. Returns ------- - rv : int - Next random value + out : uint or ndarray + Drawn samples. Notes ----- - Testing only + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. """ - if bits == 64: - return self._brng.next_uint64(self._brng.state) - elif bits == 32: - return self._brng.next_uint32(self._brng.state) - else: - raise ValueError('bits must be 32 or 64') + return random_raw(self._brng, self.lock, size, output) def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - cdef Py_ssize_t i - if method==u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method==u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') - + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None, inc=0): """ @@ -235,7 +237,7 @@ cdef class PCG64: """ cdef np.ndarray _seed, _inc - ub = 2 ** 128 + ub = 2 ** 128 if seed is None: try: _seed = random_entropy(4) @@ -288,7 +290,7 @@ cdef class PCG64: # inc = self.rng_state.pcg_state.inc return {'brng': self.__class__.__name__, - 'state': {'state': state, 'inc':inc}, + 'state': {'state': state, 'inc': inc}, 'has_uint32': self.rng_state.has_uint32, 'uinteger': self.rng_state.uinteger} @@ -381,12 +383,12 @@ cdef class PCG64: @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -395,25 +397,10 @@ cdef class PCG64: * next_double - function pointer to produce doubles * brng - pointer to the Basic RNG struct """ + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&pcg64_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&pcg64_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&pcg64_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) - return self.ctypes + return self._ctypes @property def cffi(self): @@ -434,19 +421,8 @@ cdef class PCG64: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): diff --git a/numpy/random/randomgen/philox.pyx b/numpy/random/randomgen/philox.pyx index a40cd3e251c6..05f3b17b4c51 100644 --- a/numpy/random/randomgen/philox.pyx +++ b/numpy/random/randomgen/philox.pyx @@ -1,8 +1,11 @@ -from __future__ import absolute_import - from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock + import numpy as np from .common import interface @@ -25,14 +28,14 @@ cdef extern from 'src/philox/philox.h': ctypedef s_r123array4x64 r123array4x64 ctypedef s_r123array2x64 r123array2x64 - ctypedef r123array4x64 philox4x64_ctr_t; - ctypedef r123array2x64 philox4x64_key_t; + ctypedef r123array4x64 philox4x64_ctr_t + ctypedef r123array2x64 philox4x64_key_t struct s_philox_state: - philox4x64_ctr_t *ctr; - philox4x64_key_t *key; - int buffer_pos; - uint64_t buffer[PHILOX_BUFFER_SIZE]; + philox4x64_ctr_t *ctr + philox4x64_key_t *key + int buffer_pos + uint64_t buffer[PHILOX_BUFFER_SIZE] int has_uint32 uint32_t uinteger @@ -158,12 +161,13 @@ cdef class Philox: the International Conference for High Performance Computing, Networking, Storage and Analysis (SC11), New York, NY: ACM, 2011. """ - cdef philox_state *rng_state + cdef philox_state *rng_state cdef brng_t *_brng cdef public object capsule cdef object _ctypes cdef object _cffi cdef object _generator + cdef public object lock def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(philox_state)) @@ -173,6 +177,7 @@ cdef class Philox: sizeof(philox4x64_key_t)) self._brng = malloc(sizeof(brng_t)) self.seed(seed, counter, key) + self.lock = Lock() self._brng.state = self.rng_state self._brng.next_uint64 = &philox_uint64 @@ -213,16 +218,39 @@ cdef class Philox: for i in range(PHILOX_BUFFER_SIZE): self.rng_state.buffer[i] = 0 + def random_raw(self, size=None, output=True): + """ + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. + + Returns + ------- + out : uint or ndarray + Drawn samples. + + Notes + ----- + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. + """ + return random_raw(self._brng, self.lock, size, output) + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - cdef Py_ssize_t i - if method==u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method==u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None, counter=None, key=None): """ @@ -257,7 +285,7 @@ cdef class Philox: """ if seed is not None and key is not None: raise ValueError('seed and key cannot be both used') - ub = 2 ** 64 + ub = 2 ** 64 if key is None: if seed is None: try: @@ -393,14 +421,15 @@ cdef class Philox: self._reset_state_variables() return self + @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -409,25 +438,10 @@ cdef class Philox: * next_double - function pointer to produce doubles * brng - pointer to the Basic RNG struct """ + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&philox_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&philox_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&philox_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) - return self.ctypes + return self._ctypes @property def cffi(self): @@ -448,19 +462,8 @@ cdef class Philox: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): diff --git a/numpy/random/randomgen/setup.py b/numpy/random/randomgen/setup.py index ccea6e78c370..94680e73e617 100644 --- a/numpy/random/randomgen/setup.py +++ b/numpy/random/randomgen/setup.py @@ -122,17 +122,6 @@ def generate_libraries(ext, build_dir): ], define_macros=defs + DSFMT_DEFS, ) - config.add_extension('legacy._legacy', - sources=['legacy/_legacy.c', - 'src/legacy/distributions-boxmuller.c', - 'src/distributions/distributions.c' ], - include_dirs=['.', 'legacy'], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=[join('legacy', '_legacy.pyx')], - define_macros=defs + DSFMT_DEFS, - ) for gen in ['mt19937']: # gen.pyx, src/gen/gen.c, src/gen/gen-jump.c config.add_extension(gen, @@ -186,6 +175,17 @@ def generate_libraries(ext, build_dir): depends=['%s.pyx' % gen], define_macros=defs, ) + config.add_extension('mtrand', + sources=['mtrand.c', + 'src/legacy/distributions-boxmuller.c', + 'src/distributions/distributions.c' ], + include_dirs=['.', 'legacy'], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=['mtrand.pyx'], + define_macros=defs + DSFMT_DEFS, + ) config.add_subpackage('legacy') return config if __name__ == '__main__': diff --git a/numpy/random/randomgen/src/distributions/distributions.c b/numpy/random/randomgen/src/distributions/distributions.c index 10c195ae4d23..20cdbe8632bf 100644 --- a/numpy/random/randomgen/src/distributions/distributions.c +++ b/numpy/random/randomgen/src/distributions/distributions.c @@ -879,6 +879,9 @@ int64_t random_binomial(brng_t *brng_state, double p, int64_t n, binomial_t *binomial) { double q; + if ((n == 0LL) || (p == 0.0f)) + return 0; + if (p <= 0.5) { if (p * n <= 30.0) { return random_binomial_inversion(brng_state, n, p, binomial); diff --git a/numpy/random/randomgen/src/pcg32/pcg32.h b/numpy/random/randomgen/src/pcg32/pcg32.h index 15410bd821c7..557113d8f6af 100644 --- a/numpy/random/randomgen/src/pcg32/pcg32.h +++ b/numpy/random/randomgen/src/pcg32/pcg32.h @@ -1,3 +1,5 @@ +#ifndef _RANDOMDGEN__PCG32_H_ +#define _RANDOMDGEN__PCG32_H_ #ifdef _WIN32 #ifndef _INTTYPES @@ -83,3 +85,5 @@ static inline double pcg32_next_double(pcg32_state *state) { void pcg32_advance_state(pcg32_state *state, uint64_t step); void pcg32_set_seed(pcg32_state *state, uint64_t seed, uint64_t inc); + +#endif diff --git a/numpy/random/randomgen/src/pcg64/pcg64.h b/numpy/random/randomgen/src/pcg64/pcg64.h index 854930176f09..156c73a36988 100644 --- a/numpy/random/randomgen/src/pcg64/pcg64.h +++ b/numpy/random/randomgen/src/pcg64/pcg64.h @@ -212,8 +212,6 @@ typedef pcg_state_setseq_128 pcg64_random_t; } #endif -#endif /* PCG64_H_INCLUDED */ - typedef struct s_pcg64_state { pcg64_random_t *pcg_state; int has_uint32; @@ -239,3 +237,5 @@ static inline uint32_t pcg64_next32(pcg64_state *state) { void pcg64_advance(pcg64_state *state, uint64_t *step); void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc); + +#endif /* PCG64_H_INCLUDED */ diff --git a/numpy/random/randomgen/tests/test_against_numpy.py b/numpy/random/randomgen/tests/test_against_numpy.py index c31113b511e7..14f21aad3a2d 100644 --- a/numpy/random/randomgen/tests/test_against_numpy.py +++ b/numpy/random/randomgen/tests/test_against_numpy.py @@ -6,7 +6,7 @@ import pytest from numpy.random.randomgen import RandomGenerator, MT19937, generator -from numpy.random.randomgen.legacy import LegacyGenerator +from numpy.random.randomgen.mtrand import RandomState def compare_0_input(f1, f2): @@ -96,7 +96,7 @@ def setup_class(cls): cls.brng = MT19937 cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.lg = LegacyGenerator(cls.brng(*cls.seed)) + cls.rs = RandomState(cls.brng(*cls.seed)) cls.nprs = cls.np.RandomState(*cls.seed) cls.initial_state = cls.rg.state cls._set_common_state() @@ -114,7 +114,7 @@ def _set_common_state(cls): @classmethod def _set_common_state_legacy(cls): - state = cls.lg.state + state = cls.rs.get_state(legacy=False) st = [[]] * 5 st[0] = 'MT19937' st[1] = state['state']['key'] @@ -131,7 +131,7 @@ def _is_state_common(self): def _is_state_common_legacy(self): state = self.nprs.get_state() - state2 = self.lg.state + state2 = self.rs.get_state(legacy=False) assert (state[1] == state2['state']['key']).all() assert (state[2] == state2['state']['pos']) assert (state[3] == state2['has_gauss']) @@ -166,21 +166,21 @@ def test_standard_normal(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_0_input(self.nprs.standard_normal, - self.lg.standard_normal) + self.rs.standard_normal) self._is_state_common_legacy() def test_standard_cauchy(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_0_input(self.nprs.standard_cauchy, - self.lg.standard_cauchy) + self.rs.standard_cauchy) self._is_state_common_legacy() def test_standard_exponential(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_0_input(self.nprs.standard_exponential, - self.lg.standard_exponential) + self.rs.standard_exponential) self._is_state_common_legacy() def test_tomaxint(self): @@ -404,7 +404,6 @@ def test_dir(self): nprs_d = set(dir(self.nprs)) rs_d = dir(self.rg) excluded = {'get_state', 'set_state'} - nprs_d.discard('_LegacyGenerator__legacy') nprs_d.difference_update(excluded) assert (len(nprs_d.difference(rs_d)) == 0) @@ -416,7 +415,7 @@ def test_dir(self): 'division', 'get_state', 'set_state', 'seed', 'ranf', 'random', 'sample', 'absolute_import', 'print_function', 'RandomState', 'randomgen', - 'tests'] + 'tests', 'Lock'] mod += known_exlcuded diff = set(npmod).difference(mod) assert_equal(len(diff), 0) @@ -426,112 +425,112 @@ def test_chisquare(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_1_input(self.nprs.chisquare, - self.lg.chisquare) + self.rs.chisquare) self._is_state_common_legacy() def test_standard_gamma(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_1_input(self.nprs.standard_gamma, - self.lg.standard_gamma) + self.rs.standard_gamma) self._is_state_common_legacy() def test_standard_t(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_1_input(self.nprs.standard_t, - self.lg.standard_t) + self.rs.standard_t) self._is_state_common_legacy() def test_pareto(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_1_input(self.nprs.pareto, - self.lg.pareto) + self.rs.pareto) self._is_state_common_legacy() def test_power(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_1_input(self.nprs.power, - self.lg.power) + self.rs.power) self._is_state_common_legacy() def test_weibull(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_1_input(self.nprs.weibull, - self.lg.weibull) + self.rs.weibull) self._is_state_common_legacy() def test_beta(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_2_input(self.nprs.beta, - self.lg.beta) + self.rs.beta) self._is_state_common_legacy() def test_exponential(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_1_input(self.nprs.exponential, - self.lg.exponential) + self.rs.exponential) self._is_state_common_legacy() def test_f(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_2_input(self.nprs.f, - self.lg.f) + self.rs.f) self._is_state_common_legacy() def test_gamma(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_2_input(self.nprs.gamma, - self.lg.gamma) + self.rs.gamma) self._is_state_common_legacy() def test_lognormal(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_2_input(self.nprs.lognormal, - self.lg.lognormal) + self.rs.lognormal) self._is_state_common_legacy() def test_noncentral_chisquare(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_2_input(self.nprs.noncentral_chisquare, - self.lg.noncentral_chisquare) + self.rs.noncentral_chisquare) self._is_state_common_legacy() def test_normal(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_2_input(self.nprs.normal, - self.lg.normal) + self.rs.normal) self._is_state_common_legacy() def test_wald(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_2_input(self.nprs.wald, - self.lg.wald) + self.rs.wald) self._is_state_common_legacy() def test_negative_binomial(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_2_input(self.nprs.negative_binomial, - self.lg.negative_binomial, + self.rs.negative_binomial, is_np=True) self._is_state_common_legacy() def test_randn(self): self._set_common_state_legacy() self._is_state_common_legacy() - f = self.lg.randn + f = self.rs.randn g = self.nprs.randn assert_allclose(f(10), g(10)) assert_allclose(f(3, 4, 5), g(3, 4, 5)) @@ -540,7 +539,7 @@ def test_randn(self): def test_dirichlet(self): self._set_common_state_legacy() self._is_state_common_legacy() - f = self.lg.dirichlet + f = self.rs.dirichlet g = self.nprs.dirichlet a = [3, 4, 5, 6, 7, 10] assert_allclose(f(a), g(a)) @@ -552,7 +551,7 @@ def test_noncentral_f(self): self._set_common_state_legacy() self._is_state_common_legacy() compare_3_input(self.nprs.noncentral_f, - self.lg.noncentral_f) + self.rs.noncentral_f) self._is_state_common_legacy() def test_multivariate_normal(self): @@ -560,7 +559,7 @@ def test_multivariate_normal(self): self._is_state_common_legacy() mu = [1, 2, 3] cov = [[1, .2, .3], [.2, 4, 1], [.3, 1, 10]] - f = self.lg.multivariate_normal + f = self.rs.multivariate_normal g = self.nprs.multivariate_normal assert_allclose(f(mu, cov), g(mu, cov)) assert_allclose(f(np.array(mu), cov), g(np.array(mu), cov)) diff --git a/numpy/random/randomgen/tests/test_direct.py b/numpy/random/randomgen/tests/test_direct.py index cbe2717a7233..5bfc872cb188 100644 --- a/numpy/random/randomgen/tests/test_direct.py +++ b/numpy/random/randomgen/tests/test_direct.py @@ -10,6 +10,21 @@ from ...randomgen import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024, Xoshiro256StarStar, \ Xoshiro512StarStar +from ...randomgen.common import interface + +try: + import cffi # noqa: F401 + + MISSING_CFFI = False +except ImportError: + MISSING_CFFI = True + +try: + import ctypes # noqa: F401 + + MISSING_CTYPES = False +except ImportError: + MISSING_CTYPES = False if (sys.version_info > (3, 0)): long = int @@ -17,6 +32,16 @@ pwd = os.path.dirname(os.path.abspath(__file__)) +def assert_state_equal(actual, target): + for key in actual: + if isinstance(actual[key], dict): + assert_state_equal(actual[key], target[key]) + elif isinstance(actual[key], np.ndarray): + assert_array_equal(actual[key], target[key]) + else: + assert actual[key] == target[key] + + def uniform32_from_uint64(x): x = np.uint64(x) upper = np.array(x >> np.uint64(32), dtype=np.uint32) @@ -126,6 +151,8 @@ def setup_class(cls): cls.bits = 64 cls.dtype = np.uint64 cls.seed_error_type = TypeError + cls.invalid_seed_types = [] + cls.invalid_seed_values = [] @classmethod def _read_csv(cls, filename): @@ -139,14 +166,25 @@ def _read_csv(cls, filename): return {'seed': seed, 'data': np.array(data, dtype=cls.dtype)} def test_raw(self): - rs = RandomGenerator(self.brng(*self.data1['seed'])) - uints = rs.random_raw(1000) + brng = self.brng(*self.data1['seed']) + uints = brng.random_raw(1000) assert_equal(uints, self.data1['data']) - rs = RandomGenerator(self.brng(*self.data2['seed'])) - uints = rs.random_raw(1000) + brng = self.brng(*self.data1['seed']) + uints = brng.random_raw() + assert_equal(uints, self.data1['data'][0]) + + brng = self.brng(*self.data2['seed']) + uints = brng.random_raw(1000) assert_equal(uints, self.data2['data']) + def test_random_raw(self): + brng = self.brng(*self.data1['seed']) + uints = brng.random_raw(output=False) + assert uints is None + uints = brng.random_raw(1000, output=False) + assert uints is None + @pytest.mark.skip(reason='Polar transform no longer supported') def test_gauss_inv(self): n = 25 @@ -214,6 +252,87 @@ def test_seed_out_of_range_array(self): assert_raises(ValueError, rs.seed, [2 ** (2 * self.bits + 1)]) assert_raises(ValueError, rs.seed, [-1]) + def test_repr(self): + rs = RandomGenerator(self.brng(*self.data1['seed'])) + assert 'RandomGenerator' in rs.__repr__() + assert str(hex(id(rs)))[2:].upper() in rs.__repr__() + + def test_str(self): + rs = RandomGenerator(self.brng(*self.data1['seed'])) + assert 'RandomGenerator' in str(rs) + assert str(self.brng.__name__) in str(rs) + assert str(hex(id(rs)))[2:].upper() not in str(rs) + + def test_generator(self): + brng = self.brng(*self.data1['seed']) + assert isinstance(brng.generator, RandomGenerator) + + def test_pickle(self): + import pickle + + brng = self.brng(*self.data1['seed']) + state = brng.state + brng_pkl = pickle.dumps(brng) + reloaded = pickle.loads(brng_pkl) + reloaded_state = reloaded.state + assert_array_equal(brng.generator.standard_normal(1000), + reloaded.generator.standard_normal(1000)) + assert brng is not reloaded + assert_state_equal(reloaded_state, state) + + def test_invalid_state_type(self): + brng = self.brng(*self.data1['seed']) + with pytest.raises(TypeError): + brng.state = {'1'} + + def test_invalid_state_value(self): + brng = self.brng(*self.data1['seed']) + state = brng.state + state['brng'] = 'otherBRNG' + with pytest.raises(ValueError): + brng.state = state + + def test_invalid_seed_type(self): + brng = self.brng(*self.data1['seed']) + for st in self.invalid_seed_types: + with pytest.raises(TypeError): + brng.seed(*st) + + def test_invalid_seed_values(self): + brng = self.brng(*self.data1['seed']) + for st in self.invalid_seed_values: + with pytest.raises(ValueError): + brng.seed(*st) + + def test_benchmark(self): + brng = self.brng(*self.data1['seed']) + brng._benchmark(1) + brng._benchmark(1, 'double') + with pytest.raises(ValueError): + brng._benchmark(1, 'int32') + + @pytest.mark.skipif(MISSING_CFFI, reason='cffi not available') + def test_cffi(self): + brng = self.brng(*self.data1['seed']) + cffi_interface = brng.cffi + assert isinstance(cffi_interface, interface) + other_cffi_interface = brng.cffi + assert other_cffi_interface is cffi_interface + + @pytest.mark.skipif(MISSING_CTYPES, reason='ctypes not available') + def test_ctypes(self): + brng = self.brng(*self.data1['seed']) + ctypes_interface = brng.ctypes + assert isinstance(ctypes_interface, interface) + other_ctypes_interface = brng.ctypes + assert other_ctypes_interface is ctypes_interface + + def test_getstate(self): + brng = self.brng(*self.data1['seed']) + state = brng.state + alt_state = brng.__getstate__() + assert_state_equal(state, alt_state) + class TestXoroshiro128(Base): @classmethod @@ -226,6 +345,8 @@ def setup_class(cls): cls.data2 = cls._read_csv( join(pwd, './data/xoroshiro128-testset-2.csv')) cls.seed_error_type = TypeError + cls.invalid_seed_types = [('apple',), (2 + 3j,), (3.1,)] + cls.invalid_seed_values = [(-2,), (np.empty((2, 2), dtype=np.int64),)] class TestXoshiro256StarStar(Base): @@ -239,6 +360,8 @@ def setup_class(cls): cls.data2 = cls._read_csv( join(pwd, './data/xoshiro256starstar-testset-2.csv')) cls.seed_error_type = TypeError + cls.invalid_seed_types = [('apple',), (2 + 3j,), (3.1,)] + cls.invalid_seed_values = [(-2,), (np.empty((2, 2), dtype=np.int64),)] class TestXoshiro512StarStar(Base): @@ -252,6 +375,8 @@ def setup_class(cls): cls.data2 = cls._read_csv( join(pwd, './data/xoshiro512starstar-testset-2.csv')) cls.seed_error_type = TypeError + cls.invalid_seed_types = [('apple',), (2 + 3j,), (3.1,)] + cls.invalid_seed_values = [(-2,), (np.empty((2, 2), dtype=np.int64),)] class TestXorshift1024(Base): @@ -265,6 +390,8 @@ def setup_class(cls): cls.data2 = cls._read_csv( join(pwd, './data/xorshift1024-testset-2.csv')) cls.seed_error_type = TypeError + cls.invalid_seed_types = [('apple',), (2 + 3j,), (3.1,)] + cls.invalid_seed_values = [(-2,), (np.empty((2, 2), dtype=np.int64),)] class TestThreeFry(Base): @@ -278,6 +405,16 @@ def setup_class(cls): cls.data2 = cls._read_csv( join(pwd, './data/threefry-testset-2.csv')) cls.seed_error_type = TypeError + cls.invalid_seed_types = [] + cls.invalid_seed_values = [(1, None, 1), (-1,), (2 ** 257 + 1,), + (None, None, 2 ** 257 + 1)] + + def test_set_key(self): + brng = self.brng(*self.data1['seed']) + state = brng.state + keyed = self.brng(counter=state['state']['counter'], + key=state['state']['key']) + assert_state_equal(brng.state, keyed.state) class TestPCG64(Base): @@ -289,6 +426,10 @@ def setup_class(cls): cls.data1 = cls._read_csv(join(pwd, './data/pcg64-testset-1.csv')) cls.data2 = cls._read_csv(join(pwd, './data/pcg64-testset-2.csv')) cls.seed_error_type = TypeError + cls.invalid_seed_types = [(np.array([1, 2]),), (3.2,), + (None, np.zeros(1))] + cls.invalid_seed_values = [(-1,), (2 ** 129 + 1,), (None, -1), + (None, 2 ** 129 + 1)] def test_seed_float_array(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) @@ -317,6 +458,16 @@ def setup_class(cls): cls.data2 = cls._read_csv( join(pwd, './data/philox-testset-2.csv')) cls.seed_error_type = TypeError + cls.invalid_seed_types = [] + cls.invalid_seed_values = [(1, None, 1), (-1,), (2 ** 257 + 1,), + (None, None, 2 ** 257 + 1)] + + def test_set_key(self): + brng = self.brng(*self.data1['seed']) + state = brng.state + keyed = self.brng(counter=state['state']['counter'], + key=state['state']['key']) + assert_state_equal(brng.state, keyed.state) class TestMT19937(Base): @@ -328,6 +479,8 @@ def setup_class(cls): cls.data1 = cls._read_csv(join(pwd, './data/mt19937-testset-1.csv')) cls.data2 = cls._read_csv(join(pwd, './data/mt19937-testset-2.csv')) cls.seed_error_type = ValueError + cls.invalid_seed_types = [] + cls.invalid_seed_values = [(-1,), np.array([2 ** 33])] def test_seed_out_of_range(self): # GH #82 @@ -359,6 +512,19 @@ def test_seed_float_array(self): assert_raises(TypeError, rs.seed, [np.pi]) assert_raises(TypeError, rs.seed, [0, np.pi]) + def test_state_tuple(self): + rs = RandomGenerator(self.brng(*self.data1['seed'])) + state = rs.state + desired = rs.randint(2 ** 16) + tup = (state['brng'], state['state']['key'], state['state']['pos']) + rs.state = tup + actual = rs.randint(2 ** 16) + assert_equal(actual, desired) + tup = tup + (0, 0.0) + rs.state = tup + actual = rs.randint(2 ** 16) + assert_equal(actual, desired) + class TestDSFMT(Base): @classmethod @@ -369,6 +535,9 @@ def setup_class(cls): cls.data1 = cls._read_csv(join(pwd, './data/dSFMT-testset-1.csv')) cls.data2 = cls._read_csv(join(pwd, './data/dSFMT-testset-2.csv')) cls.seed_error_type = TypeError + cls.invalid_seed_types = [] + cls.invalid_seed_values = [(-1,), np.array([2 ** 33]), + (np.array([2 ** 33, 2 ** 33]),)] def test_uniform_double(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) @@ -445,6 +614,16 @@ def setup_class(cls): cls.data1 = cls._read_csv(join(pwd, './data/threefry32-testset-1.csv')) cls.data2 = cls._read_csv(join(pwd, './data/threefry32-testset-2.csv')) cls.seed_error_type = TypeError + cls.invalid_seed_types = [] + cls.invalid_seed_values = [(1, None, 1), (-1,), (2 ** 257 + 1,), + (None, None, 2 ** 129 + 1)] + + def test_set_key(self): + brng = self.brng(*self.data1['seed']) + state = brng.state + keyed = self.brng(counter=state['state']['counter'], + key=state['state']['key']) + assert_state_equal(brng.state, keyed.state) class TestPCG32(TestPCG64): @@ -456,3 +635,7 @@ def setup_class(cls): cls.data1 = cls._read_csv(join(pwd, './data/pcg32-testset-1.csv')) cls.data2 = cls._read_csv(join(pwd, './data/pcg32-testset-2.csv')) cls.seed_error_type = TypeError + cls.invalid_seed_types = [(np.array([1, 2]),), (3.2,), + (None, np.zeros(1))] + cls.invalid_seed_values = [(-1,), (2 ** 129 + 1,), (None, -1), + (None, 2 ** 129 + 1)] diff --git a/numpy/random/randomgen/tests/test_legacy.py b/numpy/random/randomgen/tests/test_legacy.py deleted file mode 100644 index 6f8f9aee77d0..000000000000 --- a/numpy/random/randomgen/tests/test_legacy.py +++ /dev/null @@ -1,17 +0,0 @@ -import pickle - -from ...randomgen.legacy import LegacyGenerator - - -def test_pickle(): - lg = LegacyGenerator() - lg.random_sample(100) - lg.standard_normal() - lg2 = pickle.loads(pickle.dumps(lg)) - assert lg.standard_normal() == lg2.standard_normal() - assert lg.random_sample() == lg2.random_sample() - - -def test_weibull(): - lg = LegacyGenerator() - assert lg.weibull(0.0) == 0.0 diff --git a/numpy/random/randomgen/tests/test_numpy_mt19937.py b/numpy/random/randomgen/tests/test_numpy_mt19937.py index 5a08eca02476..b2249b684f67 100644 --- a/numpy/random/randomgen/tests/test_numpy_mt19937.py +++ b/numpy/random/randomgen/tests/test_numpy_mt19937.py @@ -10,10 +10,8 @@ assert_array_almost_equal, suppress_warnings) from ...randomgen import RandomGenerator, MT19937 -from ...randomgen.legacy import LegacyGenerator random = mt19937 = RandomGenerator(MT19937()) -legacy = LegacyGenerator(MT19937()) class TestSeed(object): @@ -90,6 +88,9 @@ def test_size(self): assert_raises(TypeError, mt19937.multinomial, 1, p, float(1)) + def test_invalid_prob(self): + assert_raises(ValueError, random.multinomial, 100, [1.1, 0.2]) + class TestSetState(object): def setup(self): @@ -124,19 +125,6 @@ def test_gaussian_reset_in_media_res(self): new = self.brng.standard_normal(size=3) assert_(np.all(old == new)) - def test_backwards_compatibility(self): - # Make sure we can accept old state tuples that do not have the - # cached Gaussian value. - old_state = self.legacy_state - legacy.state = old_state - x1 = legacy.standard_normal(size=16) - legacy.state = old_state - x2 = legacy.standard_normal(size=16) - legacy.state = old_state + (0, 0.0) - x3 = legacy.standard_normal(size=16) - assert_(np.all(x1 == x2)) - assert_(np.all(x1 == x3)) - def test_negative_binomial(self): # Ensure that the negative binomial results take floating point # arguments without truncation. @@ -419,14 +407,24 @@ def test_rand(self): [0.4575674820298663, 0.7781880808593471]]) assert_array_almost_equal(actual, desired, decimal=15) + def test_rand_singleton(self): + mt19937.seed(self.seed) + actual = mt19937.rand() + desired = 0.61879477158567997 + assert_array_almost_equal(actual, desired, decimal=15) + def test_randn(self): - legacy.seed(self.seed) - actual = legacy.randn(3, 2) - desired = np.array([[1.34016345771863121, 1.73759122771936081], - [1.498988344300628, -0.2286433324536169], - [2.031033998682787, 2.17032494605655257]]) + mt19937.seed(self.seed) + actual = mt19937.randn(3, 2) + desired = np.array([[-3.472754000610961, -0.108938564229143], + [-0.245965753396411, -0.704101550261701], + [0.360102487116356, 0.127832101772367]]) assert_array_almost_equal(actual, desired, decimal=15) + mt19937.seed(self.seed) + actual = mt19937.randn() + assert_array_almost_equal(actual, desired[0, 0], decimal=15) + def test_randint(self): mt19937.seed(self.seed) actual = mt19937.randint(-99, 99, size=(3, 2)) @@ -514,6 +512,21 @@ def test_random_sample(self): [0.4575674820298663, 0.7781880808593471]]) assert_array_almost_equal(actual, desired, decimal=15) + mt19937.seed(self.seed) + actual = mt19937.random_sample() + assert_array_almost_equal(actual, desired[0, 0], decimal=15) + + def test_random_sample_float(self): + mt19937.seed(self.seed) + actual = mt19937.random_sample((3, 2)) + desired = np.array([[0.6187948, 0.5916236], + [0.8886836, 0.8916548], + [0.4575675, 0.7781881]]) + assert_array_almost_equal(actual, desired, decimal=7) + + def test_random_sample_unsupported_type(self): + assert_raises(TypeError, mt19937.random_sample, dtype='int32') + def test_choice_uniform_replace(self): mt19937.seed(self.seed) actual = mt19937.choice(4, 4) @@ -662,6 +675,18 @@ def test_shuffle_masked(self): assert_equal( sorted(b.data[~b.mask]), sorted(b_orig.data[~b_orig.mask])) + def test_permutation(self): + mt19937.seed(self.seed) + alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] + actual = mt19937.permutation(alist) + desired = [0, 1, 9, 6, 2, 4, 5, 8, 7, 3] + assert_array_equal(actual, desired) + + mt19937.seed(self.seed) + arr_2d = np.atleast_2d([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]).T + actual = mt19937.permutation(arr_2d) + assert_array_equal(actual, np.atleast_2d(desired).T) + def test_beta(self): mt19937.seed(self.seed) actual = mt19937.beta(.1, .9, size=(3, 2)) @@ -680,23 +705,23 @@ def test_binomial(self): assert_array_equal(actual, desired) def test_chisquare(self): - legacy.seed(self.seed) - actual = legacy.chisquare(50, size=(3, 2)) - desired = np.array([[63.87858175501090585, 68.68407748911370447], - [65.77116116901505904, 47.09686762438974483], - [72.3828403199695174, 74.18408615260374006]]) + mt19937.seed(self.seed) + actual = mt19937.chisquare(50, size=(3, 2)) + desired = np.array([[22.2534560369812, 46.9302393710074], + [52.9974164611614, 85.3559029505718], + [46.1580841240719, 36.1933148548090]]) assert_array_almost_equal(actual, desired, decimal=13) def test_dirichlet(self): - legacy.seed(self.seed) + mt19937.seed(self.seed) alpha = np.array([51.72840233779265162, 39.74494232180943953]) - actual = legacy.dirichlet(alpha, size=(3, 2)) - desired = np.array([[[0.54539444573611562, 0.45460555426388438], - [0.62345816822039413, 0.37654183177960598]], - [[0.55206000085785778, 0.44793999914214233], - [0.58964023305154301, 0.41035976694845688]], - [[0.59266909280647828, 0.40733090719352177], - [0.56974431743975207, 0.43025568256024799]]]) + actual = mt19937.dirichlet(alpha, size=(3, 2)) + desired = np.array([[[0.444382290764855, 0.555617709235145], + [0.468440809291970, 0.531559190708030]], + [[0.613461427360549, 0.386538572639451], + [0.529103072088183, 0.470896927911817]], + [[0.513490650101800, 0.486509349898200], + [0.558550925712797, 0.441449074287203]]]) assert_array_almost_equal(actual, desired, decimal=15) bad_alpha = np.array([5.4e-01, -1.0e-16]) assert_raises(ValueError, mt19937.dirichlet, bad_alpha) @@ -719,11 +744,11 @@ def test_dirichlet_bad_alpha(self): assert_raises(ValueError, mt19937.dirichlet, alpha) def test_exponential(self): - legacy.seed(self.seed) - actual = legacy.exponential(1.1234, size=(3, 2)) - desired = np.array([[1.08342649775011624, 1.00607889924557314], - [2.46628830085216721, 2.49668106809923884], - [0.68717433461363442, 1.69175666993575979]]) + random.seed(self.seed) + actual = random.exponential(1.1234, size=(3, 2)) + desired = np.array([[5.350682337747634, 1.152307441755771], + [3.867015473358779, 1.538765912839396], + [0.347846818048527, 2.715656549872026]]) assert_array_almost_equal(actual, desired, decimal=15) def test_exponential_0(self): @@ -731,19 +756,19 @@ def test_exponential_0(self): assert_raises(ValueError, mt19937.exponential, scale=-0.) def test_f(self): - legacy.seed(self.seed) - actual = legacy.f(12, 77, size=(3, 2)) - desired = np.array([[1.21975394418575878, 1.75135759791559775], - [1.44803115017146489, 1.22108959480396262], - [1.02176975757740629, 1.34431827623300415]]) + random.seed(self.seed) + actual = random.f(12, 77, size=(3, 2)) + desired = np.array([[0.809498839488467, 2.867222762455471], + [0.588036831639353, 1.012185639664636], + [1.147554281917365, 1.150886518432105]]) assert_array_almost_equal(actual, desired, decimal=15) def test_gamma(self): - legacy.seed(self.seed) - actual = legacy.gamma(5, 3, size=(3, 2)) - desired = np.array([[24.60509188649287182, 28.54993563207210627], - [26.13476110204064184, 12.56988482927716078], - [31.71863275789960568, 33.30143302795922011]]) + random.seed(self.seed) + actual = random.gamma(5, 3, size=(3, 2)) + desired = np.array([[12.46569350177219, 16.46580642087044], + [43.65744473309084, 11.98722785682592], + [6.50371499559955, 7.48465689751638]]) assert_array_almost_equal(actual, desired, decimal=14) def test_gamma_0(self): @@ -817,11 +842,11 @@ def test_logistic(self): assert_array_almost_equal(actual, desired, decimal=15) def test_lognormal(self): - legacy.seed(self.seed) - actual = legacy.lognormal(mean=.123456789, sigma=2.0, size=(3, 2)) - desired = np.array([[16.50698631688883822, 36.54846706092654784], - [22.67886599981281748, 0.71617561058995771], - [65.72798501792723869, 86.84341601437161273]]) + random.seed(self.seed) + actual = random.lognormal(mean=.123456789, sigma=2.0, size=(3, 2)) + desired = np.array([[1.0894838661036e-03, 9.0990021488311e-01], + [6.9178869932225e-01, 2.7672077560016e-01], + [2.3248645126975e+00, 1.4609997951330e+00]]) assert_array_almost_equal(actual, desired, decimal=13) def test_lognormal_0(self): @@ -848,23 +873,25 @@ def test_multinomial(self): assert_array_equal(actual, desired) def test_multivariate_normal(self): - legacy.seed(self.seed) + random.seed(self.seed) mean = (.123456789, 10) cov = [[1, 0], [0, 1]] size = (3, 2) - actual = legacy.multivariate_normal(mean, cov, size) - desired = np.array([[[1.463620246718631, 11.73759122771936], - [1.622445133300628, 9.771356667546383]], - [[2.154490787682787, 12.170324946056553], - [1.719909438201865, 9.230548443648306]], - [[0.689515026297799, 9.880729819607714], - [-0.023054015651998, 9.201096623542879]]]) + actual = random.multivariate_normal(mean, cov, size) + np.set_printoptions(precision=20) + print(actual) + desired = np.array([[[-3.34929721161096100, 9.891061435770858], + [-0.12250896439641100, 9.295898449738300]], + [[0.48355927611635563, 10.127832101772366], + [3.11093021424924300, 10.283109168794352]], + [[-0.20332082341774727, 9.868532121697195], + [-1.33806889550667330, 9.813657233804179]]]) assert_array_almost_equal(actual, desired, decimal=15) # Check for default size, was raising deprecation warning - actual = legacy.multivariate_normal(mean, cov) - desired = np.array([0.895289569463708, 9.17180864067987]) + actual = random.multivariate_normal(mean, cov) + desired = np.array([-1.097443117192574, 10.535787051184261]) assert_array_almost_equal(actual, desired, decimal=15) # Check that non positive-semidefinite covariance warns with @@ -883,54 +910,65 @@ def test_multivariate_normal(self): cov = np.array([[1, 0.1], [0.1, 1]], dtype=np.float32) with suppress_warnings() as sup: - w = sup.record(RuntimeWarning) mt19937.multivariate_normal(mean, cov) + w = sup.record(RuntimeWarning) assert len(w) == 0 + mu = np.zeros(2) + cov = np.eye(2) + assert_raises(ValueError, mt19937.multivariate_normal, mean, cov, + check_valid='other') + assert_raises(ValueError, mt19937.multivariate_normal, + np.zeros((2, 1, 1)), cov) + assert_raises(ValueError, mt19937.multivariate_normal, + mu, np.empty((3, 2))) + assert_raises(ValueError, mt19937.multivariate_normal, + mu, np.eye(3)) + def test_negative_binomial(self): - legacy.seed(self.seed) - actual = legacy.negative_binomial(n=100, p=.12345, size=(3, 2)) - desired = np.array([[848, 841], - [892, 611], - [779, 647]]) + random.seed(self.seed) + actual = random.negative_binomial(n=100, p=.12345, size=(3, 2)) + desired = np.array([[521, 736], + [665, 690], + [723, 751]]) assert_array_equal(actual, desired) def test_noncentral_chisquare(self): - legacy.seed(self.seed) - actual = legacy.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) - desired = np.array([[23.91905354498517511, 13.35324692733826346], - [31.22452661329736401, 16.60047399466177254], - [5.03461598262724586, 17.94973089023519464]]) + random.seed(self.seed) + actual = random.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) + desired = np.array([[9.47783251920357, 10.02066178260461], + [3.15869984192364, 10.5581565031544], + [5.01652540543548, 13.7689551218441]]) assert_array_almost_equal(actual, desired, decimal=14) - actual = legacy.noncentral_chisquare(df=.5, nonc=.2, size=(3, 2)) - desired = np.array([[1.47145377828516666, 0.15052899268012659], - [0.00943803056963588, 1.02647251615666169], - [0.332334982684171, 0.15451287602753125]]) + actual = random.noncentral_chisquare(df=.5, nonc=.2, size=(3, 2)) + desired = np.array([[0.00145153051285, 0.22432468724778], + [0.02956713468556, 0.00207192946898], + [1.41985055641800, 0.15451287602753]]) assert_array_almost_equal(actual, desired, decimal=14) - legacy.seed(self.seed) - actual = legacy.noncentral_chisquare(df=5, nonc=0, size=(3, 2)) - desired = np.array([[9.597154162763948, 11.725484450296079], - [10.413711048138335, 3.694475922923986], - [13.484222138963087, 14.377255424602957]]) + random.seed(self.seed) + actual = random.noncentral_chisquare(df=5, nonc=0, size=(3, 2)) + desired = np.array([[3.64881368071039, 5.48224544747803], + [20.41999842025404, 3.44075915187367], + [1.29765160605552, 1.64125033268606]]) assert_array_almost_equal(actual, desired, decimal=14) def test_noncentral_f(self): - legacy.seed(self.seed) - actual = legacy.noncentral_f(dfnum=5, dfden=2, nonc=1, + random.seed(self.seed) + actual = random.noncentral_f(dfnum=5, dfden=2, nonc=1, size=(3, 2)) - desired = np.array([[1.40598099674926669, 0.34207973179285761], - [3.57715069265772545, 7.92632662577829805], - [0.43741599463544162, 1.1774208752428319]]) + desired = np.array([[1.22680230963236, 2.56457837623956], + [2.7653304499494, 7.4336268865443], + [1.16362730891403, 2.54104276581491]]) assert_array_almost_equal(actual, desired, decimal=14) def test_normal(self): - legacy.seed(self.seed) - actual = legacy.normal(loc=.123456789, scale=2.0, size=(3, 2)) - desired = np.array([[2.80378370443726244, 3.59863924443872163], - [3.121433477601256, -0.33382987590723379], - [4.18552478636557357, 4.46410668111310471]]) + random.seed(self.seed) + actual = random.normal(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[-6.822051212221923, -0.094420339458285], + [-0.368474717792823, -1.284746311523402], + [0.843661763232711, 0.379120992544734]]) assert_array_almost_equal(actual, desired, decimal=15) def test_normal_0(self): @@ -938,12 +976,13 @@ def test_normal_0(self): assert_raises(ValueError, mt19937.normal, scale=-0.) def test_pareto(self): - legacy.seed(self.seed) - actual = legacy.pareto(a=.123456789, size=(3, 2)) - desired = np.array( - [[2.46852460439034849e+03, 1.41286880810518346e+03], - [5.28287797029485181e+07, 6.57720981047328785e+07], - [1.40840323350391515e+02, 1.98390255135251704e+05]]) + random.seed(self.seed) + actual = random.pareto(a=.123456789, size=(3, 2)) + np.set_printoptions(precision=20) + print(actual) + desired = np.array([[5.6883528121891552e+16, 4.0569373841667057e+03], + [1.2854967019379475e+12, 6.5833156486851483e+04], + [1.1281132447159091e+01, 3.1895968171107006e+08]]) # For some reason on 32-bit x86 Ubuntu 12.10 the [1, 0] entry in this # matrix differs by 24 nulps. Discussion: # http://mail.scipy.org/pipermail/numpy-discussion/2012-September/063801.html @@ -969,11 +1008,11 @@ def test_poisson_exceptions(self): assert_raises(ValueError, mt19937.poisson, [lambig] * 10) def test_power(self): - legacy.seed(self.seed) - actual = legacy.power(a=.123456789, size=(3, 2)) - desired = np.array([[0.02048932883240791, 0.01424192241128213], - [0.38446073748535298, 0.39499689943484395], - [0.00177699707563439, 0.13115505880863756]]) + random.seed(self.seed) + actual = random.power(a=.123456789, size=(3, 2)) + desired = np.array([[9.328833342693975e-01, 2.742250409261003e-02], + [7.684513237993961e-01, 9.297548209160028e-02], + [2.214811188828573e-05, 4.693448360603472e-01]]) assert_array_almost_equal(actual, desired, decimal=15) def test_rayleigh(self): @@ -989,11 +1028,11 @@ def test_rayleigh_0(self): assert_raises(ValueError, mt19937.rayleigh, scale=-0.) def test_standard_cauchy(self): - legacy.seed(self.seed) - actual = legacy.standard_cauchy(size=(3, 2)) - desired = np.array([[0.77127660196445336, -6.55601161955910605], - [0.93582023391158309, -2.07479293013759447], - [-4.74601644297011926, 0.18338989290760804]]) + random.seed(self.seed) + actual = random.standard_cauchy(size=(3, 2)) + desired = np.array([[31.87809592667601, 0.349332782046838], + [2.816995747731641, 10.552372563459114], + [2.485608017991235, 7.843211273201831]]) assert_array_almost_equal(actual, desired, decimal=15) def test_standard_exponential(self): @@ -1005,31 +1044,43 @@ def test_standard_exponential(self): assert_array_almost_equal(actual, desired, decimal=15) def test_standard_gamma(self): - legacy.seed(self.seed) - actual = legacy.standard_gamma(shape=3, size=(3, 2)) - desired = np.array([[5.50841531318455058, 6.62953470301903103], - [5.93988484943779227, 2.31044849402133989], - [7.54838614231317084, 8.012756093271868]]) + random.seed(self.seed) + actual = random.standard_gamma(shape=3, size=(3, 2)) + desired = np.array([[2.28483515569645, 3.29899524967824], + [11.12492298902645, 2.16784417297277], + [0.92121813690910, 1.12853552328470]]) assert_array_almost_equal(actual, desired, decimal=14) + def test_standard_gamma_float(self): + random.seed(self.seed) + actual = random.standard_gamma(shape=3, size=(3, 2)) + desired = np.array([[2.2848352, 3.2989952], + [11.124923, 2.1678442], + [0.9212181, 1.1285355]]) + assert_array_almost_equal(actual, desired, decimal=7) + + def test_standard_gamma_unknown_type(self): + assert_raises(TypeError, random.standard_gamma, 1., + dtype='int32') + def test_standard_gamma_0(self): assert_equal(mt19937.standard_gamma(shape=0), 0) assert_raises(ValueError, mt19937.standard_gamma, shape=-0.) def test_standard_normal(self): - legacy.seed(self.seed) - actual = legacy.standard_normal(size=(3, 2)) - desired = np.array([[1.34016345771863121, 1.73759122771936081], - [1.498988344300628, -0.2286433324536169], - [2.031033998682787, 2.17032494605655257]]) + random.seed(self.seed) + actual = random.standard_normal(size=(3, 2)) + desired = np.array([[-3.472754000610961, -0.108938564229143], + [-0.245965753396411, -0.704101550261701], + [0.360102487116356, 0.127832101772367]]) assert_array_almost_equal(actual, desired, decimal=15) def test_standard_t(self): - legacy.seed(self.seed) - actual = legacy.standard_t(df=10, size=(3, 2)) - desired = np.array([[0.97140611862659965, -0.08830486548450577], - [1.36311143689505321, -0.55317463909867071], - [-0.18473749069684214, 0.61181537341755321]]) + random.seed(self.seed) + actual = random.standard_t(df=10, size=(3, 2)) + desired = np.array([[-3.68722108185508, -0.672031186266171], + [2.900224996448669, -0.199656996187739], + [-1.12179956985969, 1.85668262342106]]) assert_array_almost_equal(actual, desired, decimal=15) def test_triangular(self): @@ -1102,19 +1153,19 @@ def test_vonmises_small(self): assert_(np.isfinite(r).all()) def test_wald(self): - legacy.seed(self.seed) - actual = legacy.wald(mean=1.23, scale=1.54, size=(3, 2)) - desired = np.array([[3.82935265715889983, 5.13125249184285526], - [0.35045403618358717, 1.50832396872003538], - [0.24124319895843183, 0.22031101461955038]]) + random.seed(self.seed) + actual = random.wald(mean=1.23, scale=1.54, size=(3, 2)) + desired = np.array([[0.10653278160339, 0.98771068102461], + [0.89276055317879, 0.13640126419923], + [0.9194319091599, 0.36037816317472]]) assert_array_almost_equal(actual, desired, decimal=14) def test_weibull(self): - legacy.seed(self.seed) - actual = legacy.weibull(a=1.23, size=(3, 2)) - desired = np.array([[0.97097342648766727, 0.91422896443565516], - [1.89517770034962929, 1.91414357960479564], - [0.67057783752390987, 1.39494046635066793]]) + random.seed(self.seed) + actual = random.weibull(a=1.23, size=(3, 2)) + desired = np.array([[3.557276979846361, 1.020870580998542], + [2.731847777612348, 1.29148068905082], + [0.385531483942839, 2.049551716717254]]) assert_array_almost_equal(actual, desired, decimal=15) def test_weibull_0(self): @@ -1139,7 +1190,6 @@ def setup(self): def set_seed(self): random.seed(self.seed) - legacy.seed(self.seed) def test_uniform(self): low = [0] @@ -1161,10 +1211,10 @@ def test_normal(self): loc = [0] scale = [1] bad_scale = [-1] - normal = legacy.normal - desired = np.array([2.2129019979039612, - 2.1283977976520019, - 1.8417114045748335]) + normal = random.normal + desired = np.array([0.454879818179180, + -0.62749179463661, + -0.06063266769872]) self.set_seed() actual = normal(loc * 3, scale) @@ -1183,104 +1233,90 @@ def test_beta(self): b = [2] bad_a = [-1] bad_b = [-2] - beta = legacy.beta - desired = np.array([0.19843558305989056, - 0.075230336409423643, - 0.24976865978980844]) + beta = mt19937.beta + desired = np.array([0.63222080311226, + 0.33310522220774, + 0.64494078460190]) self.set_seed() actual = beta(a * 3, b) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, beta, bad_a * 3, b) assert_raises(ValueError, beta, a * 3, bad_b) - assert_raises(ValueError, mt19937.beta, bad_a * 3, b) - assert_raises(ValueError, mt19937.beta, a * 3, bad_b) self.set_seed() actual = beta(a, b * 3) assert_array_almost_equal(actual, desired, decimal=14) - assert_raises(ValueError, mt19937.beta, bad_a, b * 3) - assert_raises(ValueError, mt19937.beta, a, bad_b * 3) def test_exponential(self): scale = [1] bad_scale = [-1] - exponential = legacy.exponential - desired = np.array([0.76106853658845242, - 0.76386282278691653, - 0.71243813125891797]) + exponential = mt19937.exponential + desired = np.array([1.68591211640990, + 3.14186859487914, + 0.67717375919228]) self.set_seed() actual = exponential(scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, exponential, bad_scale * 3) - assert_raises(ValueError, mt19937.exponential, bad_scale * 3) def test_standard_gamma(self): shape = [1] bad_shape = [-1] - std_gamma = legacy.standard_gamma - desired = np.array([0.76106853658845242, - 0.76386282278691653, - 0.71243813125891797]) + std_gamma = mt19937.standard_gamma + desired = np.array([1.68591211640990, + 3.14186859487914, + 0.67717375919228]) self.set_seed() actual = std_gamma(shape * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, std_gamma, bad_shape * 3) - assert_raises(ValueError, mt19937.standard_gamma, bad_shape * 3) def test_gamma(self): shape = [1] scale = [2] bad_shape = [-1] bad_scale = [-2] - gamma = legacy.gamma - desired = np.array([1.5221370731769048, - 1.5277256455738331, - 1.4248762625178359]) + gamma = mt19937.gamma + desired = np.array([3.37182423281980, + 6.28373718975827, + 1.35434751838456]) self.set_seed() actual = gamma(shape * 3, scale) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, gamma, bad_shape * 3, scale) assert_raises(ValueError, gamma, shape * 3, bad_scale) - assert_raises(ValueError, mt19937.gamma, bad_shape * 3, scale) - assert_raises(ValueError, mt19937.gamma, shape * 3, bad_scale) self.set_seed() actual = gamma(shape, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, gamma, bad_shape, scale * 3) assert_raises(ValueError, gamma, shape, bad_scale * 3) - assert_raises(ValueError, mt19937.gamma, bad_shape, scale * 3) - assert_raises(ValueError, mt19937.gamma, shape, bad_scale * 3) def test_f(self): dfnum = [1] dfden = [2] bad_dfnum = [-1] bad_dfden = [-2] - f = legacy.f - desired = np.array([0.80038951638264799, - 0.86768719635363512, - 2.7251095168386801]) + f = mt19937.f + desired = np.array([0.84207044881810, + 3.08607209903483, + 3.12823105933169]) self.set_seed() actual = f(dfnum * 3, dfden) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, f, bad_dfnum * 3, dfden) assert_raises(ValueError, f, dfnum * 3, bad_dfden) - assert_raises(ValueError, mt19937.f, bad_dfnum * 3, dfden) - assert_raises(ValueError, mt19937.f, dfnum * 3, bad_dfden) self.set_seed() actual = f(dfnum, dfden * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, f, bad_dfnum, dfden * 3) assert_raises(ValueError, f, dfnum, bad_dfden * 3) - assert_raises(ValueError, mt19937.f, bad_dfnum, dfden * 3) - assert_raises(ValueError, mt19937.f, dfnum, bad_dfden * 3) def test_noncentral_f(self): dfnum = [2] @@ -1289,10 +1325,10 @@ def test_noncentral_f(self): bad_dfnum = [0] bad_dfden = [-1] bad_nonc = [-2] - nonc_f = legacy.noncentral_f - desired = np.array([9.1393943263705211, - 13.025456344595602, - 8.8018098359100545]) + nonc_f = mt19937.noncentral_f + desired = np.array([3.83710578542563, + 8.74926819712029, + 0.48892943835401]) self.set_seed() actual = nonc_f(dfnum * 3, dfden, nonc) @@ -1301,9 +1337,6 @@ def test_noncentral_f(self): assert_raises(ValueError, nonc_f, bad_dfnum * 3, dfden, nonc) assert_raises(ValueError, nonc_f, dfnum * 3, bad_dfden, nonc) assert_raises(ValueError, nonc_f, dfnum * 3, dfden, bad_nonc) - assert_raises(ValueError, mt_nonc_f, bad_dfnum * 3, dfden, nonc) - assert_raises(ValueError, mt_nonc_f, dfnum * 3, bad_dfden, nonc) - assert_raises(ValueError, mt_nonc_f, dfnum * 3, dfden, bad_nonc) self.set_seed() actual = nonc_f(dfnum, dfden * 3, nonc) @@ -1311,9 +1344,6 @@ def test_noncentral_f(self): assert_raises(ValueError, nonc_f, bad_dfnum, dfden * 3, nonc) assert_raises(ValueError, nonc_f, dfnum, bad_dfden * 3, nonc) assert_raises(ValueError, nonc_f, dfnum, dfden * 3, bad_nonc) - assert_raises(ValueError, mt_nonc_f, bad_dfnum, dfden * 3, nonc) - assert_raises(ValueError, mt_nonc_f, dfnum, bad_dfden * 3, nonc) - assert_raises(ValueError, mt_nonc_f, dfnum, dfden * 3, bad_nonc) self.set_seed() actual = nonc_f(dfnum, dfden, nonc * 3) @@ -1343,10 +1373,10 @@ def test_noncentral_chisquare(self): nonc = [2] bad_df = [-1] bad_nonc = [-2] - nonc_chi = legacy.noncentral_chisquare - desired = np.array([9.0015599467913763, - 4.5804135049718742, - 6.0872302432834564]) + nonc_chi = random.noncentral_chisquare + desired = np.array([2.20478739452297, + 1.45177405755115, + 1.00418921695354]) self.set_seed() actual = nonc_chi(df * 3, nonc) @@ -1368,10 +1398,10 @@ def test_noncentral_chisquare(self): def test_standard_t(self): df = [1] bad_df = [-1] - t = legacy.standard_t - desired = np.array([3.0702872575217643, - 5.8560725167361607, - 1.0274791436474273]) + t = random.standard_t + desired = np.array([0.60081050724244, + -0.90380889829210, + -0.64499590504117]) self.set_seed() actual = t(df * 3) @@ -1401,10 +1431,10 @@ def test_vonmises(self): def test_pareto(self): a = [1] bad_a = [-1] - pareto = legacy.pareto - desired = np.array([1.1405622680198362, - 1.1465519762044529, - 1.0389564467453547]) + pareto = random.pareto + desired = np.array([4.397371719158540, + 22.14707898642946, + 0.968306954322200]) self.set_seed() actual = pareto(a * 3) @@ -1415,10 +1445,10 @@ def test_pareto(self): def test_weibull(self): a = [1] bad_a = [-1] - weibull = legacy.weibull - desired = np.array([0.76106853658845242, - 0.76386282278691653, - 0.71243813125891797]) + weibull = random.weibull + desired = np.array([1.68591211640990, + 3.14186859487914, + 0.67717375919228]) self.set_seed() actual = weibull(a * 3) @@ -1429,10 +1459,10 @@ def test_weibull(self): def test_power(self): a = [1] bad_a = [-1] - power = legacy.power - desired = np.array([0.53283302478975902, - 0.53413660089041659, - 0.50955303552646702]) + power = random.power + desired = np.array([0.81472463783615, + 0.95679800459547, + 0.49194916077287]) self.set_seed() actual = power(a * 3) @@ -1502,10 +1532,10 @@ def test_lognormal(self): mean = [0] sigma = [1] bad_sigma = [-1] - lognormal = legacy.lognormal - desired = np.array([9.1422086044848427, - 8.4013952870126261, - 6.3073234116578671]) + lognormal = random.lognormal + desired = np.array([1.57598396702930, + 0.53392932731280, + 0.94116889802361]) self.set_seed() actual = lognormal(mean * 3, sigma) @@ -1537,10 +1567,10 @@ def test_wald(self): scale = [1] bad_mean = [0] bad_scale = [-2] - wald = legacy.wald - desired = np.array([0.11873681120271318, - 0.12450084820795027, - 0.9096122728408238]) + wald = random.wald + desired = np.array([0.36297361471752, + 0.52190135028254, + 0.55111022040727]) self.set_seed() actual = wald(mean * 3, scale) @@ -1594,6 +1624,10 @@ def test_triangular(self): assert_raises(ValueError, triangular, bad_left_two, bad_mode_two, right * 3) + assert_raises(ValueError, triangular, 10., 0., 20.) + assert_raises(ValueError, triangular, 10., 25., 20.) + assert_raises(ValueError, triangular, 10., 10., 10.) + def test_binomial(self): n = [1] p = [0.5] @@ -1623,8 +1657,8 @@ def test_negative_binomial(self): bad_n = [-1] bad_p_one = [-1] bad_p_two = [1.5] - neg_binom = legacy.negative_binomial - desired = np.array([1, 0, 1]) + neg_binom = random.negative_binomial + desired = np.array([3, 1, 2], dtype=np.int64) self.set_seed() actual = neg_binom(n * 3, p) @@ -1632,9 +1666,6 @@ def test_negative_binomial(self): assert_raises(ValueError, neg_binom, bad_n * 3, p) assert_raises(ValueError, neg_binom, n * 3, bad_p_one) assert_raises(ValueError, neg_binom, n * 3, bad_p_two) - assert_raises(ValueError, mt19937.negative_binomial, bad_n * 3, p) - assert_raises(ValueError, mt19937.negative_binomial, n * 3, bad_p_one) - assert_raises(ValueError, mt19937.negative_binomial, n * 3, bad_p_two) self.set_seed() actual = neg_binom(n, p * 3) @@ -1642,9 +1673,6 @@ def test_negative_binomial(self): assert_raises(ValueError, neg_binom, bad_n, p * 3) assert_raises(ValueError, neg_binom, n, bad_p_one * 3) assert_raises(ValueError, neg_binom, n, bad_p_two * 3) - assert_raises(ValueError, mt19937.negative_binomial, bad_n, p * 3) - assert_raises(ValueError, mt19937.negative_binomial, n, bad_p_one * 3) - assert_raises(ValueError, mt19937.negative_binomial, n, bad_p_two * 3) def test_poisson(self): max_lam = random.poisson_lam_max @@ -1720,6 +1748,11 @@ def test_hypergeometric(self): assert_raises(ValueError, hypergeom, ngood, nbad, bad_nsample_one * 3) assert_raises(ValueError, hypergeom, ngood, nbad, bad_nsample_two * 3) + assert_raises(ValueError, hypergeom, -1, 10, 20) + assert_raises(ValueError, hypergeom, 10, -1, 20) + assert_raises(ValueError, hypergeom, 10, 10, 0) + assert_raises(ValueError, hypergeom, 10, 10, 25) + def test_logseries(self): p = [0.5] bad_p_one = [2] @@ -1835,22 +1868,22 @@ def test_two_arg_funcs(self): out = func(self.argOne, argTwo[0]) assert_equal(out.shape, self.tgtShape) - def test_randint(self): - itype = [np.bool, np.int8, np.uint8, np.int16, np.uint16, - np.int32, np.uint32, np.int64, np.uint64] - func = mt19937.randint - high = np.array([1]) - low = np.array([0]) - - for dt in itype: - out = func(low, high, dtype=dt) - assert_equal(out.shape, self.tgtShape) + def test_randint(self): + itype = [np.bool, np.int8, np.uint8, np.int16, np.uint16, + np.int32, np.uint32, np.int64, np.uint64] + func = mt19937.randint + high = np.array([1]) + low = np.array([0]) + + for dt in itype: + out = func(low, high, dtype=dt) + assert_equal(out.shape, self.tgtShape) - out = func(low[0], high, dtype=dt) - assert_equal(out.shape, self.tgtShape) + out = func(low[0], high, dtype=dt) + assert_equal(out.shape, self.tgtShape) - out = func(low, high[0], dtype=dt) - assert_equal(out.shape, self.tgtShape) + out = func(low, high[0], dtype=dt) + assert_equal(out.shape, self.tgtShape) def test_three_arg_funcs(self): funcs = [mt19937.noncentral_f, mt19937.triangular, diff --git a/numpy/random/randomgen/tests/test_randomstate.py b/numpy/random/randomgen/tests/test_randomstate.py new file mode 100644 index 000000000000..371be78de5bf --- /dev/null +++ b/numpy/random/randomgen/tests/test_randomstate.py @@ -0,0 +1,1808 @@ +import warnings +import pickle + +import numpy as np +from numpy.testing import ( + assert_, assert_raises, assert_equal, assert_warns, + assert_no_warnings, assert_array_equal, assert_array_almost_equal, + suppress_warnings + ) +import sys + +from ...randomgen import MT19937, Xoshiro256StarStar, mtrand as random + + +def assert_mt19937_state_equal(a, b): + assert_equal(a['brng'], b['brng']) + assert_array_equal(a['state']['key'], b['state']['key']) + assert_array_equal(a['state']['pos'], b['state']['pos']) + assert_equal(a['has_gauss'], b['has_gauss']) + assert_equal(a['gauss'], b['gauss']) + + +class TestSeed(object): + def test_scalar(self): + s = random.RandomState(0) + assert_equal(s.randint(1000), 684) + s = random.RandomState(4294967295) + assert_equal(s.randint(1000), 419) + + def test_array(self): + s = random.RandomState(range(10)) + assert_equal(s.randint(1000), 468) + s = random.RandomState(np.arange(10)) + assert_equal(s.randint(1000), 468) + s = random.RandomState([0]) + assert_equal(s.randint(1000), 973) + s = random.RandomState([4294967295]) + assert_equal(s.randint(1000), 265) + + def test_invalid_scalar(self): + # seed must be an unsigned 32 bit integer + assert_raises(TypeError, random.RandomState, -0.5) + assert_raises(ValueError, random.RandomState, -1) + + def test_invalid_array(self): + # seed must be an unsigned 32 bit integer + assert_raises(TypeError, random.RandomState, [-0.5]) + assert_raises(ValueError, random.RandomState, [-1]) + assert_raises(ValueError, random.RandomState, [4294967296]) + assert_raises(ValueError, random.RandomState, [1, 2, 4294967296]) + assert_raises(ValueError, random.RandomState, [1, -2, 4294967296]) + + def test_invalid_array_shape(self): + # gh-9832 + assert_raises(ValueError, random.RandomState, np.array([], + dtype=np.int64)) + assert_raises(ValueError, random.RandomState, [[1, 2, 3]]) + assert_raises(ValueError, random.RandomState, [[1, 2, 3], + [4, 5, 6]]) + + def test_seed_equivalency(self): + rs = random.RandomState(0) + rs2 = random.RandomState(MT19937(0)) + assert_mt19937_state_equal(rs.get_state(legacy=False), + rs2.get_state(legacy=False)) + + def test_invalid_initialization(self): + assert_raises(ValueError, random.RandomState, MT19937) + + +class TestBinomial(object): + def test_n_zero(self): + # Tests the corner case of n == 0 for the binomial distribution. + # binomial(0, p) should be zero for any p in [0, 1]. + # This test addresses issue #3480. + zeros = np.zeros(2, dtype='int') + for p in [0, .5, 1]: + assert_(random.binomial(0, p) == 0) + assert_array_equal(random.binomial(zeros, p), zeros) + + def test_p_is_nan(self): + # Issue #4571. + assert_raises(ValueError, random.binomial, 1, np.nan) + + +class TestMultinomial(object): + def test_basic(self): + random.multinomial(100, [0.2, 0.8]) + + def test_zero_probability(self): + random.multinomial(100, [0.2, 0.8, 0.0, 0.0, 0.0]) + + def test_int_negative_interval(self): + assert_(-5 <= random.randint(-5, -1) < -1) + x = random.randint(-5, -1, 5) + assert_(np.all(-5 <= x)) + assert_(np.all(x < -1)) + + def test_size(self): + # gh-3173 + p = [0.5, 0.5] + assert_equal(random.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.multinomial(1, p, [2, 2]).shape, (2, 2, 2)) + assert_equal(random.multinomial(1, p, (2, 2)).shape, (2, 2, 2)) + assert_equal(random.multinomial(1, p, np.array((2, 2))).shape, + (2, 2, 2)) + + assert_raises(TypeError, random.multinomial, 1, p, + float(1)) + assert_raises(ValueError, random.multinomial, 1, [1.1, .1]) + + +class TestSetState(object): + def setup(self): + self.seed = 1234567890 + self.random_state = random.RandomState(self.seed) + self.state = self.random_state.get_state() + + def test_basic(self): + old = self.random_state.tomaxint(16) + self.random_state.set_state(self.state) + new = self.random_state.tomaxint(16) + assert_(np.all(old == new)) + + def test_gaussian_reset(self): + # Make sure the cached every-other-Gaussian is reset. + old = self.random_state.standard_normal(size=3) + self.random_state.set_state(self.state) + new = self.random_state.standard_normal(size=3) + assert_(np.all(old == new)) + + def test_gaussian_reset_in_media_res(self): + # When the state is saved with a cached Gaussian, make sure the + # cached Gaussian is restored. + + self.random_state.standard_normal() + state = self.random_state.get_state() + old = self.random_state.standard_normal(size=3) + self.random_state.set_state(state) + new = self.random_state.standard_normal(size=3) + assert_(np.all(old == new)) + + def test_backwards_compatibility(self): + # Make sure we can accept old state tuples that do not have the + # cached Gaussian value. + old_state = self.state[:-2] + x1 = self.random_state.standard_normal(size=16) + self.random_state.set_state(old_state) + x2 = self.random_state.standard_normal(size=16) + self.random_state.set_state(self.state) + x3 = self.random_state.standard_normal(size=16) + assert_(np.all(x1 == x2)) + assert_(np.all(x1 == x3)) + + def test_negative_binomial(self): + # Ensure that the negative binomial results take floating point + # arguments without truncation. + self.random_state.negative_binomial(0.5, 0.5) + + def test_get_state_warning(self): + rs = random.RandomState(Xoshiro256StarStar()) + with suppress_warnings() as sup: + w = sup.record(RuntimeWarning) + state = rs.get_state() + assert_(len(w) == 1) + assert isinstance(state, dict) + assert state['brng'] == 'Xoshiro256StarStar' + + def test_invalid_legacy_state_setting(self): + state = self.random_state.get_state() + new_state = ('Unknown', ) + state[1:] + assert_raises(ValueError, self.random_state.set_state, new_state) + assert_raises(TypeError, self.random_state.set_state, + np.array(new_state, dtype=np.object)) + state = self.random_state.get_state(legacy=False) + del state['brng'] + assert_raises(ValueError, self.random_state.set_state, state) + + def test_pickle(self): + self.random_state.seed(0) + self.random_state.random_sample(100) + self.random_state.standard_normal() + pickled = self.random_state.get_state(legacy=False) + assert_equal(pickled['has_gauss'], 1) + rs_unpick = pickle.loads(pickle.dumps(self.random_state)) + unpickled = rs_unpick.get_state(legacy=False) + assert_mt19937_state_equal(pickled, unpickled) + + def test_state_setting(self): + attr_state = self.random_state.__getstate__() + self.random_state.standard_normal() + self.random_state.__setstate__(attr_state) + state = self.random_state.get_state(legacy=False) + assert_mt19937_state_equal(attr_state, state) + + def test_repr(self): + assert repr(self.random_state).startswith('RandomState(MT19937)') + + +class TestRandint(object): + + rfunc = random.randint + + # valid integer/boolean types + itype = [np.bool_, np.int8, np.uint8, np.int16, np.uint16, + np.int32, np.uint32, np.int64, np.uint64] + + def test_unsupported_type(self): + assert_raises(TypeError, self.rfunc, 1, dtype=float) + + def test_bounds_checking(self): + for dt in self.itype: + lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min + ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1 + assert_raises(ValueError, self.rfunc, lbnd - 1, ubnd, dtype=dt) + assert_raises(ValueError, self.rfunc, lbnd, ubnd + 1, dtype=dt) + assert_raises(ValueError, self.rfunc, ubnd, lbnd, dtype=dt) + assert_raises(ValueError, self.rfunc, 1, 0, dtype=dt) + + def test_rng_zero_and_extremes(self): + for dt in self.itype: + lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min + ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1 + + tgt = ubnd - 1 + assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt) + + tgt = lbnd + assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt) + + tgt = (lbnd + ubnd)//2 + assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt) + + def test_full_range(self): + # Test for ticket #1690 + + for dt in self.itype: + lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min + ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1 + + try: + self.rfunc(lbnd, ubnd, dtype=dt) + except Exception as e: + raise AssertionError("No error should have been raised, " + "but one was with the following " + "message:\n\n%s" % str(e)) + + def test_in_bounds_fuzz(self): + # Don't use fixed seed + random.seed() + + for dt in self.itype[1:]: + for ubnd in [4, 8, 16]: + vals = self.rfunc(2, ubnd, size=2**16, dtype=dt) + assert_(vals.max() < ubnd) + assert_(vals.min() >= 2) + + vals = self.rfunc(0, 2, size=2**16, dtype=np.bool_) + + assert_(vals.max() < 2) + assert_(vals.min() >= 0) + + def test_repeatability(self): + import hashlib + # We use a md5 hash of generated sequences of 1000 samples + # in the range [0, 6) for all but bool, where the range + # is [0, 2). Hashes are for little endian numbers. + tgt = {'bool': '7dd3170d7aa461d201a65f8bcf3944b0', + 'int16': '1b7741b80964bb190c50d541dca1cac1', + 'int32': '4dc9fcc2b395577ebb51793e58ed1a05', + 'int64': '17db902806f448331b5a758d7d2ee672', + 'int8': '27dd30c4e08a797063dffac2490b0be6', + 'uint16': '1b7741b80964bb190c50d541dca1cac1', + 'uint32': '4dc9fcc2b395577ebb51793e58ed1a05', + 'uint64': '17db902806f448331b5a758d7d2ee672', + 'uint8': '27dd30c4e08a797063dffac2490b0be6'} + + for dt in self.itype[1:]: + random.seed(1234) + + # view as little endian for hash + if sys.byteorder == 'little': + val = self.rfunc(0, 6, size=1000, dtype=dt) + else: + val = self.rfunc(0, 6, size=1000, dtype=dt).byteswap() + + res = hashlib.md5(val.view(np.int8)).hexdigest() + assert_(tgt[np.dtype(dt).name] == res) + + # bools do not depend on endianness + random.seed(1234) + val = self.rfunc(0, 2, size=1000, dtype=bool).view(np.int8) + res = hashlib.md5(val).hexdigest() + assert_(tgt[np.dtype(bool).name] == res) + + def test_int64_uint64_corner_case(self): + # When stored in Numpy arrays, `lbnd` is casted + # as np.int64, and `ubnd` is casted as np.uint64. + # Checking whether `lbnd` >= `ubnd` used to be + # done solely via direct comparison, which is incorrect + # because when Numpy tries to compare both numbers, + # it casts both to np.float64 because there is + # no integer superset of np.int64 and np.uint64. However, + # `ubnd` is too large to be represented in np.float64, + # causing it be round down to np.iinfo(np.int64).max, + # leading to a ValueError because `lbnd` now equals + # the new `ubnd`. + + dt = np.int64 + tgt = np.iinfo(np.int64).max + lbnd = np.int64(np.iinfo(np.int64).max) + ubnd = np.uint64(np.iinfo(np.int64).max + 1) + + # None of these function calls should + # generate a ValueError now. + actual = random.randint(lbnd, ubnd, dtype=dt) + assert_equal(actual, tgt) + + def test_respect_dtype_singleton(self): + # See gh-7203 + for dt in self.itype: + lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min + ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1 + + sample = self.rfunc(lbnd, ubnd, dtype=dt) + assert_equal(sample.dtype, np.dtype(dt)) + + for dt in (bool, int, np.long): + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + + # gh-7284: Ensure that we get Python data types + sample = self.rfunc(lbnd, ubnd, dtype=dt) + assert_(not hasattr(sample, 'dtype')) + assert_equal(type(sample), dt) + + +class TestRandomDist(object): + # Make sure the random distribution returns the correct value for a + # given seed + + def setup(self): + self.seed = 1234567890 + + def test_rand(self): + random.seed(self.seed) + actual = random.rand(3, 2) + desired = np.array([[0.61879477158567997, 0.59162362775974664], + [0.88868358904449662, 0.89165480011560816], + [0.4575674820298663, 0.7781880808593471]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_randn(self): + random.seed(self.seed) + actual = random.randn(3, 2) + desired = np.array([[1.34016345771863121, 1.73759122771936081], + [1.498988344300628, -0.2286433324536169], + [2.031033998682787, 2.17032494605655257]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_randint(self): + random.seed(self.seed) + actual = random.randint(-99, 99, size=(3, 2)) + desired = np.array([[31, 3], + [-52, 41], + [-48, -66]]) + assert_array_equal(actual, desired) + + def test_random_integers(self): + random.seed(self.seed) + with suppress_warnings() as sup: + w = sup.record(DeprecationWarning) + actual = random.random_integers(-99, 99, size=(3, 2)) + assert_(len(w) == 1) + desired = np.array([[31, 3], + [-52, 41], + [-48, -66]]) + assert_array_equal(actual, desired) + + random.seed(self.seed) + with suppress_warnings() as sup: + w = sup.record(DeprecationWarning) + actual = random.random_integers(198, size=(3, 2)) + assert_(len(w) == 1) + assert_array_equal(actual, desired + 100) + + def test_tomaxint(self): + random.seed(self.seed) + rs = random.RandomState(self.seed) + actual = rs.tomaxint(size=(3, 2)) + if np.iinfo(np.int).max == 2147483647: + desired = np.array([[1328851649, 731237375], + [1270502067, 320041495], + [1908433478, 499156889]], dtype=np.int64) + else: + desired = np.array([[5707374374421908479, 5456764827585442327], + [8196659375100692377, 8224063923314595285], + [4220315081820346526, 7177518203184491332]], + dtype=np.int64) + + assert_equal(actual, desired) + + rs.seed(self.seed) + actual = rs.tomaxint() + assert_equal(actual, desired[0, 0]) + + def test_random_integers_max_int(self): + # Tests whether random_integers can generate the + # maximum allowed Python int that can be converted + # into a C long. Previous implementations of this + # method have thrown an OverflowError when attempting + # to generate this integer. + with suppress_warnings() as sup: + w = sup.record(DeprecationWarning) + actual = random.random_integers(np.iinfo('l').max, + np.iinfo('l').max) + assert_(len(w) == 1) + + desired = np.iinfo('l').max + assert_equal(actual, desired) + + def test_random_integers_deprecated(self): + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + + # DeprecationWarning raised with high == None + assert_raises(DeprecationWarning, + random.random_integers, + np.iinfo('l').max) + + # DeprecationWarning raised with high != None + assert_raises(DeprecationWarning, + random.random_integers, + np.iinfo('l').max, np.iinfo('l').max) + + def test_random_sample(self): + random.seed(self.seed) + actual = random.random_sample((3, 2)) + desired = np.array([[0.61879477158567997, 0.59162362775974664], + [0.88868358904449662, 0.89165480011560816], + [0.4575674820298663, 0.7781880808593471]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_rand_singleton(self): + random.seed(self.seed) + actual = random.rand() + desired = np.array(0.61879477158567997) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_choice_uniform_replace(self): + random.seed(self.seed) + actual = random.choice(4, 4) + desired = np.array([2, 3, 2, 3]) + assert_array_equal(actual, desired) + + def test_choice_nonuniform_replace(self): + random.seed(self.seed) + actual = random.choice(4, 4, p=[0.4, 0.4, 0.1, 0.1]) + desired = np.array([1, 1, 2, 2]) + assert_array_equal(actual, desired) + + def test_choice_uniform_noreplace(self): + random.seed(self.seed) + actual = random.choice(4, 3, replace=False) + desired = np.array([0, 1, 3]) + assert_array_equal(actual, desired) + + def test_choice_nonuniform_noreplace(self): + random.seed(self.seed) + actual = random.choice(4, 3, replace=False, p=[0.1, 0.3, 0.5, 0.1]) + desired = np.array([2, 3, 1]) + assert_array_equal(actual, desired) + + def test_choice_noninteger(self): + random.seed(self.seed) + actual = random.choice(['a', 'b', 'c', 'd'], 4) + desired = np.array(['c', 'd', 'c', 'd']) + assert_array_equal(actual, desired) + + def test_choice_exceptions(self): + sample = random.choice + assert_raises(ValueError, sample, -1, 3) + assert_raises(ValueError, sample, 3., 3) + assert_raises(ValueError, sample, [[1, 2], [3, 4]], 3) + assert_raises(ValueError, sample, [], 3) + assert_raises(ValueError, sample, [1, 2, 3, 4], 3, + p=[[0.25, 0.25], [0.25, 0.25]]) + assert_raises(ValueError, sample, [1, 2], 3, p=[0.4, 0.4, 0.2]) + assert_raises(ValueError, sample, [1, 2], 3, p=[1.1, -0.1]) + assert_raises(ValueError, sample, [1, 2], 3, p=[0.4, 0.4]) + assert_raises(ValueError, sample, [1, 2, 3], 4, replace=False) + # gh-13087 + assert_raises(ValueError, sample, [1, 2, 3], -2, replace=False) + assert_raises(ValueError, sample, [1, 2, 3], (-1,), replace=False) + assert_raises(ValueError, sample, [1, 2, 3], (-1, 1), replace=False) + assert_raises(ValueError, sample, [1, 2, 3], 2, + replace=False, p=[1, 0, 0]) + + def test_choice_return_shape(self): + p = [0.1, 0.9] + # Check scalar + assert_(np.isscalar(random.choice(2, replace=True))) + assert_(np.isscalar(random.choice(2, replace=False))) + assert_(np.isscalar(random.choice(2, replace=True, p=p))) + assert_(np.isscalar(random.choice(2, replace=False, p=p))) + assert_(np.isscalar(random.choice([1, 2], replace=True))) + assert_(random.choice([None], replace=True) is None) + a = np.array([1, 2]) + arr = np.empty(1, dtype=object) + arr[0] = a + assert_(random.choice(arr, replace=True) is a) + + # Check 0-d array + s = tuple() + assert_(not np.isscalar(random.choice(2, s, replace=True))) + assert_(not np.isscalar(random.choice(2, s, replace=False))) + assert_(not np.isscalar(random.choice(2, s, replace=True, p=p))) + assert_(not np.isscalar(random.choice(2, s, replace=False, p=p))) + assert_(not np.isscalar(random.choice([1, 2], s, replace=True))) + assert_(random.choice([None], s, replace=True).ndim == 0) + a = np.array([1, 2]) + arr = np.empty(1, dtype=object) + arr[0] = a + assert_(random.choice(arr, s, replace=True).item() is a) + + # Check multi dimensional array + s = (2, 3) + p = [0.1, 0.1, 0.1, 0.1, 0.4, 0.2] + assert_equal(random.choice(6, s, replace=True).shape, s) + assert_equal(random.choice(6, s, replace=False).shape, s) + assert_equal(random.choice(6, s, replace=True, p=p).shape, s) + assert_equal(random.choice(6, s, replace=False, p=p).shape, s) + assert_equal(random.choice(np.arange(6), s, replace=True).shape, s) + + # Check zero-size + assert_equal(random.randint(0, 0, size=(3, 0, 4)).shape, (3, 0, 4)) + assert_equal(random.randint(0, -10, size=0).shape, (0,)) + assert_equal(random.randint(10, 10, size=0).shape, (0,)) + assert_equal(random.choice(0, size=0).shape, (0,)) + assert_equal(random.choice([], size=(0,)).shape, (0,)) + assert_equal(random.choice(['a', 'b'], size=(3, 0, 4)).shape, + (3, 0, 4)) + assert_raises(ValueError, random.choice, [], 10) + + def test_choice_nan_probabilities(self): + a = np.array([42, 1, 2]) + p = [None, None, None] + assert_raises(ValueError, random.choice, a, p=p) + + def test_bytes(self): + random.seed(self.seed) + actual = random.bytes(10) + desired = b'\x82Ui\x9e\xff\x97+Wf\xa5' + assert_equal(actual, desired) + + def test_shuffle(self): + # Test lists, arrays (of various dtypes), and multidimensional versions + # of both, c-contiguous or not: + for conv in [lambda x: np.array([]), + lambda x: x, + lambda x: np.asarray(x).astype(np.int8), + lambda x: np.asarray(x).astype(np.float32), + lambda x: np.asarray(x).astype(np.complex64), + lambda x: np.asarray(x).astype(object), + lambda x: [(i, i) for i in x], + lambda x: np.asarray([[i, i] for i in x]), + lambda x: np.vstack([x, x]).T, + # gh-11442 + lambda x: (np.asarray([(i, i) for i in x], + [("a", int), ("b", int)]) + .view(np.recarray)), + # gh-4270 + lambda x: np.asarray([(i, i) for i in x], + [("a", object, 1), + ("b", np.int32, 1)])]: + random.seed(self.seed) + alist = conv([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) + random.shuffle(alist) + actual = alist + desired = conv([0, 1, 9, 6, 2, 4, 5, 8, 7, 3]) + assert_array_equal(actual, desired) + + def test_permutation(self): + random.seed(self.seed) + alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] + actual = random.permutation(alist) + desired = [0, 1, 9, 6, 2, 4, 5, 8, 7, 3] + assert_array_equal(actual, desired) + + random.seed(self.seed) + arr_2d = np.atleast_2d([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]).T + actual = random.permutation(arr_2d) + assert_array_equal(actual, np.atleast_2d(desired).T) + + def test_shuffle_masked(self): + # gh-3263 + a = np.ma.masked_values(np.reshape(range(20), (5, 4)) % 3 - 1, -1) + b = np.ma.masked_values(np.arange(20) % 3 - 1, -1) + a_orig = a.copy() + b_orig = b.copy() + for i in range(50): + random.shuffle(a) + assert_equal( + sorted(a.data[~a.mask]), sorted(a_orig.data[~a_orig.mask])) + random.shuffle(b) + assert_equal( + sorted(b.data[~b.mask]), sorted(b_orig.data[~b_orig.mask])) + + def test_beta(self): + random.seed(self.seed) + actual = random.beta(.1, .9, size=(3, 2)) + desired = np.array( + [[1.45341850513746058e-02, 5.31297615662868145e-04], + [1.85366619058432324e-06, 4.19214516800110563e-03], + [1.58405155108498093e-04, 1.26252891949397652e-04]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_binomial(self): + random.seed(self.seed) + actual = random.binomial(100.123, .456, size=(3, 2)) + desired = np.array([[37, 43], + [42, 48], + [46, 45]]) + assert_array_equal(actual, desired) + + random.seed(self.seed) + actual = random.binomial(100.123, .456) + desired = 37 + assert_array_equal(actual, desired) + + def test_chisquare(self): + random.seed(self.seed) + actual = random.chisquare(50, size=(3, 2)) + desired = np.array([[63.87858175501090585, 68.68407748911370447], + [65.77116116901505904, 47.09686762438974483], + [72.3828403199695174, 74.18408615260374006]]) + assert_array_almost_equal(actual, desired, decimal=13) + + def test_dirichlet(self): + random.seed(self.seed) + alpha = np.array([51.72840233779265162, 39.74494232180943953]) + actual = random.dirichlet(alpha, size=(3, 2)) + desired = np.array([[[0.54539444573611562, 0.45460555426388438], + [0.62345816822039413, 0.37654183177960598]], + [[0.55206000085785778, 0.44793999914214233], + [0.58964023305154301, 0.41035976694845688]], + [[0.59266909280647828, 0.40733090719352177], + [0.56974431743975207, 0.43025568256024799]]]) + assert_array_almost_equal(actual, desired, decimal=15) + + random.seed(self.seed) + alpha = np.array([51.72840233779265162, 39.74494232180943953]) + actual = random.dirichlet(alpha) + assert_array_almost_equal(actual, desired[0, 0], decimal=15) + + def test_dirichlet_size(self): + # gh-3173 + p = np.array([51.72840233779265162, 39.74494232180943953]) + assert_equal(random.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.dirichlet(p, [2, 2]).shape, (2, 2, 2)) + assert_equal(random.dirichlet(p, (2, 2)).shape, (2, 2, 2)) + assert_equal(random.dirichlet(p, np.array((2, 2))).shape, (2, 2, 2)) + + assert_raises(TypeError, random.dirichlet, p, float(1)) + + def test_dirichlet_bad_alpha(self): + # gh-2089 + alpha = np.array([5.4e-01, -1.0e-16]) + assert_raises(ValueError, random.dirichlet, alpha) + + def test_exponential(self): + random.seed(self.seed) + actual = random.exponential(1.1234, size=(3, 2)) + desired = np.array([[1.08342649775011624, 1.00607889924557314], + [2.46628830085216721, 2.49668106809923884], + [0.68717433461363442, 1.69175666993575979]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_exponential_0(self): + assert_equal(random.exponential(scale=0), 0) + assert_raises(ValueError, random.exponential, scale=-0.) + + def test_f(self): + random.seed(self.seed) + actual = random.f(12, 77, size=(3, 2)) + desired = np.array([[1.21975394418575878, 1.75135759791559775], + [1.44803115017146489, 1.22108959480396262], + [1.02176975757740629, 1.34431827623300415]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_gamma(self): + random.seed(self.seed) + actual = random.gamma(5, 3, size=(3, 2)) + desired = np.array([[24.60509188649287182, 28.54993563207210627], + [26.13476110204064184, 12.56988482927716078], + [31.71863275789960568, 33.30143302795922011]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_gamma_0(self): + assert_equal(random.gamma(shape=0, scale=0), 0) + assert_raises(ValueError, random.gamma, shape=-0., scale=-0.) + + def test_geometric(self): + random.seed(self.seed) + actual = random.geometric(.123456789, size=(3, 2)) + desired = np.array([[8, 7], + [17, 17], + [5, 12]]) + assert_array_equal(actual, desired) + + def test_gumbel(self): + random.seed(self.seed) + actual = random.gumbel(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[0.19591898743416816, 0.34405539668096674], + [-1.4492522252274278, -1.47374816298446865], + [1.10651090478803416, -0.69535848626236174]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_gumbel_0(self): + assert_equal(random.gumbel(scale=0), 0) + assert_raises(ValueError, random.gumbel, scale=-0.) + + def test_hypergeometric(self): + random.seed(self.seed) + actual = random.hypergeometric(10.1, 5.5, 14, size=(3, 2)) + desired = np.array([[10, 10], + [10, 10], + [9, 9]]) + assert_array_equal(actual, desired) + + # Test nbad = 0 + actual = random.hypergeometric(5, 0, 3, size=4) + desired = np.array([3, 3, 3, 3]) + assert_array_equal(actual, desired) + + actual = random.hypergeometric(15, 0, 12, size=4) + desired = np.array([12, 12, 12, 12]) + assert_array_equal(actual, desired) + + # Test ngood = 0 + actual = random.hypergeometric(0, 5, 3, size=4) + desired = np.array([0, 0, 0, 0]) + assert_array_equal(actual, desired) + + actual = random.hypergeometric(0, 15, 12, size=4) + desired = np.array([0, 0, 0, 0]) + assert_array_equal(actual, desired) + + def test_laplace(self): + random.seed(self.seed) + actual = random.laplace(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[0.66599721112760157, 0.52829452552221945], + [3.12791959514407125, 3.18202813572992005], + [-0.05391065675859356, 1.74901336242837324]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_laplace_0(self): + assert_equal(random.laplace(scale=0), 0) + assert_raises(ValueError, random.laplace, scale=-0.) + + def test_logistic(self): + random.seed(self.seed) + actual = random.logistic(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[1.09232835305011444, 0.8648196662399954], + [4.27818590694950185, 4.33897006346929714], + [-0.21682183359214885, 2.63373365386060332]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_lognormal(self): + random.seed(self.seed) + actual = random.lognormal(mean=.123456789, sigma=2.0, size=(3, 2)) + desired = np.array([[16.50698631688883822, 36.54846706092654784], + [22.67886599981281748, 0.71617561058995771], + [65.72798501792723869, 86.84341601437161273]]) + assert_array_almost_equal(actual, desired, decimal=13) + + def test_lognormal_0(self): + assert_equal(random.lognormal(sigma=0), 1) + assert_raises(ValueError, random.lognormal, sigma=-0.) + + def test_logseries(self): + random.seed(self.seed) + actual = random.logseries(p=.923456789, size=(3, 2)) + desired = np.array([[2, 2], + [6, 17], + [3, 6]]) + assert_array_equal(actual, desired) + + def test_multinomial(self): + random.seed(self.seed) + actual = random.multinomial(20, [1/6.]*6, size=(3, 2)) + desired = np.array([[[4, 3, 5, 4, 2, 2], + [5, 2, 8, 2, 2, 1]], + [[3, 4, 3, 6, 0, 4], + [2, 1, 4, 3, 6, 4]], + [[4, 4, 2, 5, 2, 3], + [4, 3, 4, 2, 3, 4]]]) + assert_array_equal(actual, desired) + + def test_multivariate_normal(self): + random.seed(self.seed) + mean = (.123456789, 10) + cov = [[1, 0], [0, 1]] + size = (3, 2) + actual = random.multivariate_normal(mean, cov, size) + desired = np.array([[[1.463620246718631, 11.73759122771936], + [1.622445133300628, 9.771356667546383]], + [[2.154490787682787, 12.170324946056553], + [1.719909438201865, 9.230548443648306]], + [[0.689515026297799, 9.880729819607714], + [-0.023054015651998, 9.201096623542879]]]) + + assert_array_almost_equal(actual, desired, decimal=15) + + # Check for default size, was raising deprecation warning + actual = random.multivariate_normal(mean, cov) + desired = np.array([0.895289569463708, 9.17180864067987]) + assert_array_almost_equal(actual, desired, decimal=15) + + # Check that non positive-semidefinite covariance warns with + # RuntimeWarning + mean = [0, 0] + cov = [[1, 2], [2, 1]] + assert_warns(RuntimeWarning, random.multivariate_normal, mean, cov) + + # and that it doesn't warn with RuntimeWarning check_valid='ignore' + assert_no_warnings(random.multivariate_normal, mean, cov, + check_valid='ignore') + + # and that it raises with RuntimeWarning check_valid='raises' + assert_raises(ValueError, random.multivariate_normal, mean, cov, + check_valid='raise') + + cov = np.array([[1, 0.1], [0.1, 1]], dtype=np.float32) + with suppress_warnings() as sup: + random.multivariate_normal(mean, cov) + w = sup.record(RuntimeWarning) + assert len(w) == 0 + + mu = np.zeros(2) + cov = np.eye(2) + assert_raises(ValueError, random.multivariate_normal, mean, + cov, check_valid='other') + assert_raises(ValueError, random.multivariate_normal, + np.zeros((2, 1, 1)), cov) + assert_raises(ValueError, random.multivariate_normal, + mu, np.empty((3, 2))) + assert_raises(ValueError, random.multivariate_normal, + mu, np.eye(3)) + + def test_negative_binomial(self): + random.seed(self.seed) + actual = random.negative_binomial(n=100, p=.12345, size=(3, 2)) + desired = np.array([[848, 841], + [892, 611], + [779, 647]]) + assert_array_equal(actual, desired) + + def test_noncentral_chisquare(self): + random.seed(self.seed) + actual = random.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) + desired = np.array([[23.91905354498517511, 13.35324692733826346], + [31.22452661329736401, 16.60047399466177254], + [5.03461598262724586, 17.94973089023519464]]) + assert_array_almost_equal(actual, desired, decimal=14) + + actual = random.noncentral_chisquare(df=.5, nonc=.2, size=(3, 2)) + desired = np.array([[1.47145377828516666, 0.15052899268012659], + [0.00943803056963588, 1.02647251615666169], + [0.332334982684171, 0.15451287602753125]]) + assert_array_almost_equal(actual, desired, decimal=14) + + random.seed(self.seed) + actual = random.noncentral_chisquare(df=5, nonc=0, size=(3, 2)) + desired = np.array([[9.597154162763948, 11.725484450296079], + [10.413711048138335, 3.694475922923986], + [13.484222138963087, 14.377255424602957]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_noncentral_f(self): + random.seed(self.seed) + actual = random.noncentral_f(dfnum=5, dfden=2, nonc=1, + size=(3, 2)) + desired = np.array([[1.40598099674926669, 0.34207973179285761], + [3.57715069265772545, 7.92632662577829805], + [0.43741599463544162, 1.1774208752428319]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_normal(self): + random.seed(self.seed) + actual = random.normal(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[2.80378370443726244, 3.59863924443872163], + [3.121433477601256, -0.33382987590723379], + [4.18552478636557357, 4.46410668111310471]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_normal_0(self): + assert_equal(random.normal(scale=0), 0) + assert_raises(ValueError, random.normal, scale=-0.) + + def test_pareto(self): + random.seed(self.seed) + actual = random.pareto(a=.123456789, size=(3, 2)) + desired = np.array( + [[2.46852460439034849e+03, 1.41286880810518346e+03], + [5.28287797029485181e+07, 6.57720981047328785e+07], + [1.40840323350391515e+02, 1.98390255135251704e+05]]) + # For some reason on 32-bit x86 Ubuntu 12.10 the [1, 0] entry in this + # matrix differs by 24 nulps. Discussion: + # https://mail.python.org/pipermail/numpy-discussion/2012-September/063801.html + # Consensus is that this is probably some gcc quirk that affects + # rounding but not in any important way, so we just use a looser + # tolerance on this test: + np.testing.assert_array_almost_equal_nulp(actual, desired, nulp=30) + + def test_poisson(self): + random.seed(self.seed) + actual = random.poisson(lam=.123456789, size=(3, 2)) + desired = np.array([[0, 0], + [1, 0], + [0, 0]]) + assert_array_equal(actual, desired) + + def test_poisson_exceptions(self): + lambig = np.iinfo('l').max + lamneg = -1 + assert_raises(ValueError, random.poisson, lamneg) + assert_raises(ValueError, random.poisson, [lamneg]*10) + assert_raises(ValueError, random.poisson, lambig) + assert_raises(ValueError, random.poisson, [lambig]*10) + + def test_power(self): + random.seed(self.seed) + actual = random.power(a=.123456789, size=(3, 2)) + desired = np.array([[0.02048932883240791, 0.01424192241128213], + [0.38446073748535298, 0.39499689943484395], + [0.00177699707563439, 0.13115505880863756]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_rayleigh(self): + random.seed(self.seed) + actual = random.rayleigh(scale=10, size=(3, 2)) + desired = np.array([[13.8882496494248393, 13.383318339044731], + [20.95413364294492098, 21.08285015800712614], + [11.06066537006854311, 17.35468505778271009]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_rayleigh_0(self): + assert_equal(random.rayleigh(scale=0), 0) + assert_raises(ValueError, random.rayleigh, scale=-0.) + + def test_standard_cauchy(self): + random.seed(self.seed) + actual = random.standard_cauchy(size=(3, 2)) + desired = np.array([[0.77127660196445336, -6.55601161955910605], + [0.93582023391158309, -2.07479293013759447], + [-4.74601644297011926, 0.18338989290760804]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_standard_exponential(self): + random.seed(self.seed) + actual = random.standard_exponential(size=(3, 2)) + desired = np.array([[0.96441739162374596, 0.89556604882105506], + [2.1953785836319808, 2.22243285392490542], + [0.6116915921431676, 1.50592546727413201]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_standard_gamma(self): + random.seed(self.seed) + actual = random.standard_gamma(shape=3, size=(3, 2)) + desired = np.array([[5.50841531318455058, 6.62953470301903103], + [5.93988484943779227, 2.31044849402133989], + [7.54838614231317084, 8.012756093271868]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_standard_gamma_0(self): + assert_equal(random.standard_gamma(shape=0), 0) + assert_raises(ValueError, random.standard_gamma, shape=-0.) + + def test_standard_normal(self): + random.seed(self.seed) + actual = random.standard_normal(size=(3, 2)) + desired = np.array([[1.34016345771863121, 1.73759122771936081], + [1.498988344300628, -0.2286433324536169], + [2.031033998682787, 2.17032494605655257]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_randn_singleton(self): + random.seed(self.seed) + actual = random.randn() + desired = np.array(1.34016345771863121) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_standard_t(self): + random.seed(self.seed) + actual = random.standard_t(df=10, size=(3, 2)) + desired = np.array([[0.97140611862659965, -0.08830486548450577], + [1.36311143689505321, -0.55317463909867071], + [-0.18473749069684214, 0.61181537341755321]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_triangular(self): + random.seed(self.seed) + actual = random.triangular(left=5.12, mode=10.23, right=20.34, + size=(3, 2)) + desired = np.array([[12.68117178949215784, 12.4129206149193152], + [16.20131377335158263, 16.25692138747600524], + [11.20400690911820263, 14.4978144835829923]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_uniform(self): + random.seed(self.seed) + actual = random.uniform(low=1.23, high=10.54, size=(3, 2)) + desired = np.array([[6.99097932346268003, 6.73801597444323974], + [9.50364421400426274, 9.53130618907631089], + [5.48995325769805476, 8.47493103280052118]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_uniform_range_bounds(self): + fmin = np.finfo('float').min + fmax = np.finfo('float').max + + func = random.uniform + assert_raises(OverflowError, func, -np.inf, 0) + assert_raises(OverflowError, func, 0, np.inf) + assert_raises(OverflowError, func, fmin, fmax) + assert_raises(OverflowError, func, [-np.inf], [0]) + assert_raises(OverflowError, func, [0], [np.inf]) + + # (fmax / 1e17) - fmin is within range, so this should not throw + # account for i386 extended precision DBL_MAX / 1e17 + DBL_MAX > + # DBL_MAX by increasing fmin a bit + random.uniform(low=np.nextafter(fmin, 1), high=fmax / 1e17) + + def test_scalar_exception_propagation(self): + # Tests that exceptions are correctly propagated in distributions + # when called with objects that throw exceptions when converted to + # scalars. + # + # Regression test for gh: 8865 + + class ThrowingFloat(np.ndarray): + def __float__(self): + raise TypeError + + throwing_float = np.array(1.0).view(ThrowingFloat) + assert_raises(TypeError, random.uniform, throwing_float, + throwing_float) + + class ThrowingInteger(np.ndarray): + def __int__(self): + raise TypeError + + throwing_int = np.array(1).view(ThrowingInteger) + assert_raises(TypeError, random.hypergeometric, throwing_int, 1, 1) + + def test_vonmises(self): + random.seed(self.seed) + actual = random.vonmises(mu=1.23, kappa=1.54, size=(3, 2)) + desired = np.array([[2.28567572673902042, 2.89163838442285037], + [0.38198375564286025, 2.57638023113890746], + [1.19153771588353052, 1.83509849681825354]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_vonmises_small(self): + # check infinite loop, gh-4720 + random.seed(self.seed) + r = random.vonmises(mu=0., kappa=1.1e-8, size=10**6) + np.testing.assert_(np.isfinite(r).all()) + + def test_wald(self): + random.seed(self.seed) + actual = random.wald(mean=1.23, scale=1.54, size=(3, 2)) + desired = np.array([[3.82935265715889983, 5.13125249184285526], + [0.35045403618358717, 1.50832396872003538], + [0.24124319895843183, 0.22031101461955038]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_weibull(self): + random.seed(self.seed) + actual = random.weibull(a=1.23, size=(3, 2)) + desired = np.array([[0.97097342648766727, 0.91422896443565516], + [1.89517770034962929, 1.91414357960479564], + [0.67057783752390987, 1.39494046635066793]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_weibull_0(self): + random.seed(self.seed) + assert_equal(random.weibull(a=0, size=12), np.zeros(12)) + assert_raises(ValueError, random.weibull, a=-0.) + + def test_zipf(self): + random.seed(self.seed) + actual = random.zipf(a=1.23, size=(3, 2)) + desired = np.array([[66, 29], + [1, 1], + [3, 13]]) + assert_array_equal(actual, desired) + + +class TestBroadcast(object): + # tests that functions that broadcast behave + # correctly when presented with non-scalar arguments + def setup(self): + self.seed = 123456789 + + def setSeed(self): + random.seed(self.seed) + + # TODO: Include test for randint once it can broadcast + # Can steal the test written in PR #6938 + + def test_uniform(self): + low = [0] + high = [1] + uniform = random.uniform + desired = np.array([0.53283302478975902, + 0.53413660089041659, + 0.50955303552646702]) + + self.setSeed() + actual = uniform(low * 3, high) + assert_array_almost_equal(actual, desired, decimal=14) + + self.setSeed() + actual = uniform(low, high * 3) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_normal(self): + loc = [0] + scale = [1] + bad_scale = [-1] + normal = random.normal + desired = np.array([2.2129019979039612, + 2.1283977976520019, + 1.8417114045748335]) + + self.setSeed() + actual = normal(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, normal, loc * 3, bad_scale) + + self.setSeed() + actual = normal(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, normal, loc, bad_scale * 3) + + def test_beta(self): + a = [1] + b = [2] + bad_a = [-1] + bad_b = [-2] + beta = random.beta + desired = np.array([0.19843558305989056, + 0.075230336409423643, + 0.24976865978980844]) + + self.setSeed() + actual = beta(a * 3, b) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, beta, bad_a * 3, b) + assert_raises(ValueError, beta, a * 3, bad_b) + + self.setSeed() + actual = beta(a, b * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, beta, bad_a, b * 3) + assert_raises(ValueError, beta, a, bad_b * 3) + + def test_exponential(self): + scale = [1] + bad_scale = [-1] + exponential = random.exponential + desired = np.array([0.76106853658845242, + 0.76386282278691653, + 0.71243813125891797]) + + self.setSeed() + actual = exponential(scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, exponential, bad_scale * 3) + + def test_standard_gamma(self): + shape = [1] + bad_shape = [-1] + std_gamma = random.standard_gamma + desired = np.array([0.76106853658845242, + 0.76386282278691653, + 0.71243813125891797]) + + self.setSeed() + actual = std_gamma(shape * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, std_gamma, bad_shape * 3) + + def test_gamma(self): + shape = [1] + scale = [2] + bad_shape = [-1] + bad_scale = [-2] + gamma = random.gamma + desired = np.array([1.5221370731769048, + 1.5277256455738331, + 1.4248762625178359]) + + self.setSeed() + actual = gamma(shape * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gamma, bad_shape * 3, scale) + assert_raises(ValueError, gamma, shape * 3, bad_scale) + + self.setSeed() + actual = gamma(shape, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gamma, bad_shape, scale * 3) + assert_raises(ValueError, gamma, shape, bad_scale * 3) + + def test_f(self): + dfnum = [1] + dfden = [2] + bad_dfnum = [-1] + bad_dfden = [-2] + f = random.f + desired = np.array([0.80038951638264799, + 0.86768719635363512, + 2.7251095168386801]) + + self.setSeed() + actual = f(dfnum * 3, dfden) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, f, bad_dfnum * 3, dfden) + assert_raises(ValueError, f, dfnum * 3, bad_dfden) + + self.setSeed() + actual = f(dfnum, dfden * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, f, bad_dfnum, dfden * 3) + assert_raises(ValueError, f, dfnum, bad_dfden * 3) + + def test_noncentral_f(self): + dfnum = [2] + dfden = [3] + nonc = [4] + bad_dfnum = [0] + bad_dfden = [-1] + bad_nonc = [-2] + nonc_f = random.noncentral_f + desired = np.array([9.1393943263705211, + 13.025456344595602, + 8.8018098359100545]) + + self.setSeed() + actual = nonc_f(dfnum * 3, dfden, nonc) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_f, bad_dfnum * 3, dfden, nonc) + assert_raises(ValueError, nonc_f, dfnum * 3, bad_dfden, nonc) + assert_raises(ValueError, nonc_f, dfnum * 3, dfden, bad_nonc) + + self.setSeed() + actual = nonc_f(dfnum, dfden * 3, nonc) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_f, bad_dfnum, dfden * 3, nonc) + assert_raises(ValueError, nonc_f, dfnum, bad_dfden * 3, nonc) + assert_raises(ValueError, nonc_f, dfnum, dfden * 3, bad_nonc) + + self.setSeed() + actual = nonc_f(dfnum, dfden, nonc * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_f, bad_dfnum, dfden, nonc * 3) + assert_raises(ValueError, nonc_f, dfnum, bad_dfden, nonc * 3) + assert_raises(ValueError, nonc_f, dfnum, dfden, bad_nonc * 3) + + def test_noncentral_f_small_df(self): + self.setSeed() + desired = np.array([6.869638627492048, 0.785880199263955]) + actual = random.noncentral_f(0.9, 0.9, 2, size=2) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_chisquare(self): + df = [1] + bad_df = [-1] + chisquare = random.chisquare + desired = np.array([0.57022801133088286, + 0.51947702108840776, + 0.1320969254923558]) + + self.setSeed() + actual = chisquare(df * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, chisquare, bad_df * 3) + + def test_noncentral_chisquare(self): + df = [1] + nonc = [2] + bad_df = [-1] + bad_nonc = [-2] + nonc_chi = random.noncentral_chisquare + desired = np.array([9.0015599467913763, + 4.5804135049718742, + 6.0872302432834564]) + + self.setSeed() + actual = nonc_chi(df * 3, nonc) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_chi, bad_df * 3, nonc) + assert_raises(ValueError, nonc_chi, df * 3, bad_nonc) + + self.setSeed() + actual = nonc_chi(df, nonc * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_chi, bad_df, nonc * 3) + assert_raises(ValueError, nonc_chi, df, bad_nonc * 3) + + def test_standard_t(self): + df = [1] + bad_df = [-1] + t = random.standard_t + desired = np.array([3.0702872575217643, + 5.8560725167361607, + 1.0274791436474273]) + + self.setSeed() + actual = t(df * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, t, bad_df * 3) + + def test_vonmises(self): + mu = [2] + kappa = [1] + bad_kappa = [-1] + vonmises = random.vonmises + desired = np.array([2.9883443664201312, + -2.7064099483995943, + -1.8672476700665914]) + + self.setSeed() + actual = vonmises(mu * 3, kappa) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, vonmises, mu * 3, bad_kappa) + + self.setSeed() + actual = vonmises(mu, kappa * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, vonmises, mu, bad_kappa * 3) + + def test_pareto(self): + a = [1] + bad_a = [-1] + pareto = random.pareto + desired = np.array([1.1405622680198362, + 1.1465519762044529, + 1.0389564467453547]) + + self.setSeed() + actual = pareto(a * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, pareto, bad_a * 3) + + def test_weibull(self): + a = [1] + bad_a = [-1] + weibull = random.weibull + desired = np.array([0.76106853658845242, + 0.76386282278691653, + 0.71243813125891797]) + + self.setSeed() + actual = weibull(a * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, weibull, bad_a * 3) + + def test_power(self): + a = [1] + bad_a = [-1] + power = random.power + desired = np.array([0.53283302478975902, + 0.53413660089041659, + 0.50955303552646702]) + + self.setSeed() + actual = power(a * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, power, bad_a * 3) + + def test_laplace(self): + loc = [0] + scale = [1] + bad_scale = [-1] + laplace = random.laplace + desired = np.array([0.067921356028507157, + 0.070715642226971326, + 0.019290950698972624]) + + self.setSeed() + actual = laplace(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, laplace, loc * 3, bad_scale) + + self.setSeed() + actual = laplace(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, laplace, loc, bad_scale * 3) + + def test_gumbel(self): + loc = [0] + scale = [1] + bad_scale = [-1] + gumbel = random.gumbel + desired = np.array([0.2730318639556768, + 0.26936705726291116, + 0.33906220393037939]) + + self.setSeed() + actual = gumbel(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gumbel, loc * 3, bad_scale) + + self.setSeed() + actual = gumbel(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gumbel, loc, bad_scale * 3) + + def test_logistic(self): + loc = [0] + scale = [1] + bad_scale = [-1] + logistic = random.logistic + desired = np.array([0.13152135837586171, + 0.13675915696285773, + 0.038216792802833396]) + + self.setSeed() + actual = logistic(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, logistic, loc * 3, bad_scale) + + self.setSeed() + actual = logistic(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, logistic, loc, bad_scale * 3) + + def test_lognormal(self): + mean = [0] + sigma = [1] + bad_sigma = [-1] + lognormal = random.lognormal + desired = np.array([9.1422086044848427, + 8.4013952870126261, + 6.3073234116578671]) + + self.setSeed() + actual = lognormal(mean * 3, sigma) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, lognormal, mean * 3, bad_sigma) + + self.setSeed() + actual = lognormal(mean, sigma * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, lognormal, mean, bad_sigma * 3) + + def test_rayleigh(self): + scale = [1] + bad_scale = [-1] + rayleigh = random.rayleigh + desired = np.array([1.2337491937897689, + 1.2360119924878694, + 1.1936818095781789]) + + self.setSeed() + actual = rayleigh(scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, rayleigh, bad_scale * 3) + + def test_wald(self): + mean = [0.5] + scale = [1] + bad_mean = [0] + bad_scale = [-2] + wald = random.wald + desired = np.array([0.11873681120271318, + 0.12450084820795027, + 0.9096122728408238]) + + self.setSeed() + actual = wald(mean * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, wald, bad_mean * 3, scale) + assert_raises(ValueError, wald, mean * 3, bad_scale) + + self.setSeed() + actual = wald(mean, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, wald, bad_mean, scale * 3) + assert_raises(ValueError, wald, mean, bad_scale * 3) + assert_raises(ValueError, wald, 0.0, 1) + assert_raises(ValueError, wald, 0.5, 0.0) + + def test_triangular(self): + left = [1] + right = [3] + mode = [2] + bad_left_one = [3] + bad_mode_one = [4] + bad_left_two, bad_mode_two = right * 2 + triangular = random.triangular + desired = np.array([2.03339048710429, + 2.0347400359389356, + 2.0095991069536208]) + + self.setSeed() + actual = triangular(left * 3, mode, right) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, triangular, bad_left_one * 3, mode, right) + assert_raises(ValueError, triangular, left * 3, bad_mode_one, right) + assert_raises(ValueError, triangular, bad_left_two * 3, bad_mode_two, + right) + + self.setSeed() + actual = triangular(left, mode * 3, right) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, triangular, bad_left_one, mode * 3, right) + assert_raises(ValueError, triangular, left, bad_mode_one * 3, right) + assert_raises(ValueError, triangular, bad_left_two, bad_mode_two * 3, + right) + + self.setSeed() + actual = triangular(left, mode, right * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, triangular, bad_left_one, mode, right * 3) + assert_raises(ValueError, triangular, left, bad_mode_one, right * 3) + assert_raises(ValueError, triangular, bad_left_two, bad_mode_two, + right * 3) + + assert_raises(ValueError, triangular, 10., 0., 20.) + assert_raises(ValueError, triangular, 10., 25., 20.) + assert_raises(ValueError, triangular, 10., 10., 10.) + + def test_binomial(self): + n = [1] + p = [0.5] + bad_n = [-1] + bad_p_one = [-1] + bad_p_two = [1.5] + binom = random.binomial + desired = np.array([1, 1, 1]) + + self.setSeed() + actual = binom(n * 3, p) + assert_array_equal(actual, desired) + assert_raises(ValueError, binom, bad_n * 3, p) + assert_raises(ValueError, binom, n * 3, bad_p_one) + assert_raises(ValueError, binom, n * 3, bad_p_two) + + self.setSeed() + actual = binom(n, p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, binom, bad_n, p * 3) + assert_raises(ValueError, binom, n, bad_p_one * 3) + assert_raises(ValueError, binom, n, bad_p_two * 3) + + def test_negative_binomial(self): + n = [1] + p = [0.5] + bad_n = [-1] + bad_p_one = [-1] + bad_p_two = [1.5] + neg_binom = random.negative_binomial + desired = np.array([1, 0, 1]) + + self.setSeed() + actual = neg_binom(n * 3, p) + assert_array_equal(actual, desired) + assert_raises(ValueError, neg_binom, bad_n * 3, p) + assert_raises(ValueError, neg_binom, n * 3, bad_p_one) + assert_raises(ValueError, neg_binom, n * 3, bad_p_two) + + self.setSeed() + actual = neg_binom(n, p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, neg_binom, bad_n, p * 3) + assert_raises(ValueError, neg_binom, n, bad_p_one * 3) + assert_raises(ValueError, neg_binom, n, bad_p_two * 3) + + def test_poisson(self): + max_lam = random.RandomState().poisson_lam_max + + lam = [1] + bad_lam_one = [-1] + bad_lam_two = [max_lam * 2] + poisson = random.poisson + desired = np.array([1, 1, 0]) + + self.setSeed() + actual = poisson(lam * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, poisson, bad_lam_one * 3) + assert_raises(ValueError, poisson, bad_lam_two * 3) + + def test_zipf(self): + a = [2] + bad_a = [0] + zipf = random.zipf + desired = np.array([2, 2, 1]) + + self.setSeed() + actual = zipf(a * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, zipf, bad_a * 3) + with np.errstate(invalid='ignore'): + assert_raises(ValueError, zipf, np.nan) + assert_raises(ValueError, zipf, [0, 0, np.nan]) + + def test_geometric(self): + p = [0.5] + bad_p_one = [-1] + bad_p_two = [1.5] + geom = random.geometric + desired = np.array([2, 2, 2]) + + self.setSeed() + actual = geom(p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, geom, bad_p_one * 3) + assert_raises(ValueError, geom, bad_p_two * 3) + + def test_hypergeometric(self): + ngood = [1] + nbad = [2] + nsample = [2] + bad_ngood = [-1] + bad_nbad = [-2] + bad_nsample_one = [0] + bad_nsample_two = [4] + hypergeom = random.hypergeometric + desired = np.array([1, 1, 1]) + + self.setSeed() + actual = hypergeom(ngood * 3, nbad, nsample) + assert_array_equal(actual, desired) + assert_raises(ValueError, hypergeom, bad_ngood * 3, nbad, nsample) + assert_raises(ValueError, hypergeom, ngood * 3, bad_nbad, nsample) + assert_raises(ValueError, hypergeom, ngood * 3, nbad, bad_nsample_one) + assert_raises(ValueError, hypergeom, ngood * 3, nbad, bad_nsample_two) + + self.setSeed() + actual = hypergeom(ngood, nbad * 3, nsample) + assert_array_equal(actual, desired) + assert_raises(ValueError, hypergeom, bad_ngood, nbad * 3, nsample) + assert_raises(ValueError, hypergeom, ngood, bad_nbad * 3, nsample) + assert_raises(ValueError, hypergeom, ngood, nbad * 3, bad_nsample_one) + assert_raises(ValueError, hypergeom, ngood, nbad * 3, bad_nsample_two) + + self.setSeed() + actual = hypergeom(ngood, nbad, nsample * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, hypergeom, bad_ngood, nbad, nsample * 3) + assert_raises(ValueError, hypergeom, ngood, bad_nbad, nsample * 3) + assert_raises(ValueError, hypergeom, ngood, nbad, bad_nsample_one * 3) + assert_raises(ValueError, hypergeom, ngood, nbad, bad_nsample_two * 3) + + assert_raises(ValueError, hypergeom, 10, 10, 25) + + def test_logseries(self): + p = [0.5] + bad_p_one = [2] + bad_p_two = [-1] + logseries = random.logseries + desired = np.array([1, 1, 1]) + + self.setSeed() + actual = logseries(p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, logseries, bad_p_one * 3) + assert_raises(ValueError, logseries, bad_p_two * 3) + + +class TestThread(object): + # make sure each state produces the same sequence even in threads + def setup(self): + self.seeds = range(4) + + def check_function(self, function, sz): + from threading import Thread + + out1 = np.empty((len(self.seeds),) + sz) + out2 = np.empty((len(self.seeds),) + sz) + + # threaded generation + t = [Thread(target=function, args=(random.RandomState(s), o)) + for s, o in zip(self.seeds, out1)] + [x.start() for x in t] + [x.join() for x in t] + + # the same serial + for s, o in zip(self.seeds, out2): + function(random.RandomState(s), o) + + # these platforms change x87 fpu precision mode in threads + if np.intp().dtype.itemsize == 4 and sys.platform == "win32": + assert_array_almost_equal(out1, out2) + else: + assert_array_equal(out1, out2) + + def test_normal(self): + def gen_random(state, out): + out[...] = state.normal(size=10000) + self.check_function(gen_random, sz=(10000,)) + + def test_exp(self): + def gen_random(state, out): + out[...] = state.exponential(scale=np.ones((100, 1000))) + self.check_function(gen_random, sz=(100, 1000)) + + def test_multinomial(self): + def gen_random(state, out): + out[...] = state.multinomial(10, [1/6.]*6, size=10000) + self.check_function(gen_random, sz=(10000, 6)) + + +# See Issue #4263 +class TestSingleEltArrayInput(object): + def setup(self): + self.argOne = np.array([2]) + self.argTwo = np.array([3]) + self.argThree = np.array([4]) + self.tgtShape = (1,) + + def test_one_arg_funcs(self): + funcs = (random.exponential, random.standard_gamma, + random.chisquare, random.standard_t, + random.pareto, random.weibull, + random.power, random.rayleigh, + random.poisson, random.zipf, + random.geometric, random.logseries) + + probfuncs = (random.geometric, random.logseries) + + for func in funcs: + if func in probfuncs: # p < 1.0 + out = func(np.array([0.5])) + + else: + out = func(self.argOne) + + assert_equal(out.shape, self.tgtShape) + + def test_two_arg_funcs(self): + funcs = (random.uniform, random.normal, + random.beta, random.gamma, + random.f, random.noncentral_chisquare, + random.vonmises, random.laplace, + random.gumbel, random.logistic, + random.lognormal, random.wald, + random.binomial, random.negative_binomial) + + probfuncs = (random.binomial, random.negative_binomial) + + for func in funcs: + if func in probfuncs: # p <= 1 + argTwo = np.array([0.5]) + + else: + argTwo = self.argTwo + + out = func(self.argOne, argTwo) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne[0], argTwo) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne, argTwo[0]) + assert_equal(out.shape, self.tgtShape) + +# TODO: Uncomment once randint can broadcast arguments +# def test_randint(self): +# itype = [bool, np.int8, np.uint8, np.int16, np.uint16, +# np.int32, np.uint32, np.int64, np.uint64] +# func = random.randint +# high = np.array([1]) +# low = np.array([0]) +# +# for dt in itype: +# out = func(low, high, dtype=dt) +# self.assert_equal(out.shape, self.tgtShape) +# +# out = func(low[0], high, dtype=dt) +# self.assert_equal(out.shape, self.tgtShape) +# +# out = func(low, high[0], dtype=dt) +# self.assert_equal(out.shape, self.tgtShape) + + def test_three_arg_funcs(self): + funcs = [random.noncentral_f, random.triangular, + random.hypergeometric] + + for func in funcs: + out = func(self.argOne, self.argTwo, self.argThree) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne[0], self.argTwo, self.argThree) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne, self.argTwo[0], self.argThree) + assert_equal(out.shape, self.tgtShape) diff --git a/numpy/random/randomgen/tests/test_randomstate_regression.py b/numpy/random/randomgen/tests/test_randomstate_regression.py new file mode 100644 index 000000000000..cf21ee756b87 --- /dev/null +++ b/numpy/random/randomgen/tests/test_randomstate_regression.py @@ -0,0 +1,157 @@ +import sys +from numpy.testing import ( + assert_, assert_array_equal, assert_raises, + ) +from numpy.compat import long +import numpy as np + +from ...randomgen import mtrand as random + + +class TestRegression(object): + + def test_VonMises_range(self): + # Make sure generated random variables are in [-pi, pi]. + # Regression test for ticket #986. + for mu in np.linspace(-7., 7., 5): + r = random.vonmises(mu, 1, 50) + assert_(np.all(r > -np.pi) and np.all(r <= np.pi)) + + def test_hypergeometric_range(self): + # Test for ticket #921 + assert_(np.all(random.hypergeometric(3, 18, 11, size=10) < 4)) + assert_(np.all(random.hypergeometric(18, 3, 11, size=10) > 0)) + + # Test for ticket #5623 + args = [ + (2**20 - 2, 2**20 - 2, 2**20 - 2), # Check for 32-bit systems + ] + is_64bits = sys.maxsize > 2**32 + if is_64bits and sys.platform != 'win32': + # Check for 64-bit systems + args.append((2**40 - 2, 2**40 - 2, 2**40 - 2)) + for arg in args: + assert_(random.hypergeometric(*arg) > 0) + + def test_logseries_convergence(self): + # Test for ticket #923 + N = 1000 + random.seed(0) + rvsn = random.logseries(0.8, size=N) + # these two frequency counts should be close to theoretical + # numbers with this large sample + # theoretical large N result is 0.49706795 + freq = np.sum(rvsn == 1) / float(N) + msg = "Frequency was %f, should be > 0.45" % freq + assert_(freq > 0.45, msg) + # theoretical large N result is 0.19882718 + freq = np.sum(rvsn == 2) / float(N) + msg = "Frequency was %f, should be < 0.23" % freq + assert_(freq < 0.23, msg) + + def test_permutation_longs(self): + random.seed(1234) + a = random.permutation(12) + random.seed(1234) + b = random.permutation(long(12)) + assert_array_equal(a, b) + + def test_shuffle_mixed_dimension(self): + # Test for trac ticket #2074 + for t in [[1, 2, 3, None], + [(1, 1), (2, 2), (3, 3), None], + [1, (2, 2), (3, 3), None], + [(1, 1), 2, 3, None]]: + random.seed(12345) + shuffled = list(t) + random.shuffle(shuffled) + assert_array_equal(shuffled, [t[0], t[3], t[1], t[2]]) + + def test_call_within_randomstate(self): + # Check that custom RandomState does not call into global state + m = random.RandomState() + res = np.array([0, 8, 7, 2, 1, 9, 4, 7, 0, 3]) + for i in range(3): + random.seed(i) + m.seed(4321) + # If m.state is not honored, the result will change + assert_array_equal(m.choice(10, size=10, p=np.ones(10)/10.), res) + + def test_multivariate_normal_size_types(self): + # Test for multivariate_normal issue with 'size' argument. + # Check that the multivariate_normal size argument can be a + # numpy integer. + random.multivariate_normal([0], [[0]], size=1) + random.multivariate_normal([0], [[0]], size=np.int_(1)) + random.multivariate_normal([0], [[0]], size=np.int64(1)) + + def test_beta_small_parameters(self): + # Test that beta with small a and b parameters does not produce + # NaNs due to roundoff errors causing 0 / 0, gh-5851 + random.seed(1234567890) + x = random.beta(0.0001, 0.0001, size=100) + assert_(not np.any(np.isnan(x)), 'Nans in random.beta') + + def test_choice_sum_of_probs_tolerance(self): + # The sum of probs should be 1.0 with some tolerance. + # For low precision dtypes the tolerance was too tight. + # See numpy github issue 6123. + random.seed(1234) + a = [1, 2, 3] + counts = [4, 4, 2] + for dt in np.float16, np.float32, np.float64: + probs = np.array(counts, dtype=dt) / sum(counts) + c = random.choice(a, p=probs) + assert_(c in a) + assert_raises(ValueError, random.choice, a, p=probs*0.9) + + def test_shuffle_of_array_of_different_length_strings(self): + # Test that permuting an array of different length strings + # will not cause a segfault on garbage collection + # Tests gh-7710 + random.seed(1234) + + a = np.array(['a', 'a' * 1000]) + + for _ in range(100): + random.shuffle(a) + + # Force Garbage Collection - should not segfault. + import gc + gc.collect() + + def test_shuffle_of_array_of_objects(self): + # Test that permuting an array of objects will not cause + # a segfault on garbage collection. + # See gh-7719 + random.seed(1234) + a = np.array([np.arange(1), np.arange(4)]) + + for _ in range(1000): + random.shuffle(a) + + # Force Garbage Collection - should not segfault. + import gc + gc.collect() + + def test_permutation_subclass(self): + class N(np.ndarray): + pass + + random.seed(1) + orig = np.arange(3).view(N) + perm = random.permutation(orig) + assert_array_equal(perm, np.array([0, 2, 1])) + assert_array_equal(orig, np.arange(3).view(N)) + + class M(object): + a = np.arange(5) + + def __array__(self): + return self.a + + random.seed(1) + m = M() + perm = random.permutation(m) + assert_array_equal(perm, np.array([2, 1, 4, 0, 3])) + assert_array_equal(m.__array__(), np.arange(5)) diff --git a/numpy/random/randomgen/tests/test_smoke.py b/numpy/random/randomgen/tests/test_smoke.py index ab6f50e330ca..b00b9efb297d 100644 --- a/numpy/random/randomgen/tests/test_smoke.py +++ b/numpy/random/randomgen/tests/test_smoke.py @@ -2,6 +2,7 @@ import pickle import sys import time +from functools import partial import numpy as np import pytest @@ -152,13 +153,6 @@ def test_jump(self): brng_name = self.rg._basicrng.__class__.__name__ pytest.skip('Jump is not supported by {0}'.format(brng_name)) - def test_random_uintegers(self): - assert_(len(self.rg.random_uintegers(10)) == 10) - - def test_random_raw(self): - assert_(len(self.rg.random_raw(10)) == 10) - assert_(self.rg.random_raw((10, 10)).shape == (10, 10)) - def test_uniform(self): r = self.rg.uniform(-1.0, 0.0, size=10) assert_(len(r) == 10) @@ -200,6 +194,20 @@ def test_standard_exponential(self): assert_(len(self.rg.standard_exponential(10)) == 10) params_0(self.rg.standard_exponential) + def test_standard_exponential_float(self): + randoms = self.rg.standard_exponential(10, dtype='float32') + assert_(len(randoms) == 10) + assert randoms.dtype == np.float32 + params_0(partial(self.rg.standard_exponential, dtype='float32')) + + def test_standard_exponential_float_log(self): + randoms = self.rg.standard_exponential(10, dtype='float32', + method='inv') + assert_(len(randoms) == 10) + assert randoms.dtype == np.float32 + params_0(partial(self.rg.standard_exponential, dtype='float32', + method='inv')) + def test_standard_cauchy(self): assert_(len(self.rg.standard_cauchy(10)) == 10) params_0(self.rg.standard_cauchy) @@ -214,9 +222,9 @@ def test_binomial(self): def test_reset_state(self): state = self.rg.state - int_1 = self.rg.random_raw(1) + int_1 = self.rg.randint(2**31) self.rg.state = state - int_2 = self.rg.random_raw(1) + int_2 = self.rg.randint(2**31) assert_(int_1 == int_2) def test_entropy_init(self): @@ -256,14 +264,14 @@ def test_reset_state_uint32(self): n2 = rg2.randint(0, 2 ** 24, 10, dtype=np.uint32) assert_array_equal(n1, n2) - def test_reset_state_uintegers(self): + def test_reset_state_float(self): rg = RandomGenerator(self.brng(*self.seed)) - rg.random_uintegers(bits=32) + rg.random_sample(dtype='float32') state = rg.state - n1 = rg.random_uintegers(bits=32, size=10) + n1 = rg.random_sample(size=10, dtype='float32') rg2 = RandomGenerator(self.brng()) rg2.state = state - n2 = rg2.random_uintegers(bits=32, size=10) + n2 = rg2.random_sample(size=10, dtype='float32') assert_((n1 == n2).all()) def test_shuffle(self): @@ -679,6 +687,10 @@ def test_output_fill(self): direct = rg.standard_normal(size=size) assert_equal(direct, existing) + sized = np.empty(size) + rg.state = state + rg.standard_normal(out=sized, size=sized.shape) + existing = np.empty(size, dtype=np.float32) rg.state = state rg.standard_normal(out=existing, dtype=np.float32) diff --git a/numpy/random/randomgen/threefry.pyx b/numpy/random/randomgen/threefry.pyx index 63364dc3de46..aa4ce622dd08 100644 --- a/numpy/random/randomgen/threefry.pyx +++ b/numpy/random/randomgen/threefry.pyx @@ -1,8 +1,11 @@ -from __future__ import absolute_import - from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock + import numpy as np from .common import interface @@ -24,10 +27,10 @@ cdef extern from 'src/threefry/threefry.h': ctypedef r123array4x64 threefry4x64_ctr_t struct s_threefry_state: - threefry4x64_ctr_t *ctr; - threefry4x64_key_t *key; - int buffer_pos; - uint64_t buffer[THREEFRY_BUFFER_SIZE]; + threefry4x64_ctr_t *ctr + threefry4x64_key_t *key + int buffer_pos + uint64_t buffer[THREEFRY_BUFFER_SIZE] int has_uint32 uint32_t uinteger @@ -153,13 +156,13 @@ cdef class ThreeFry: the International Conference for High Performance Computing, Networking, Storage and Analysis (SC11), New York, NY: ACM, 2011. """ - cdef threefry_state *rng_state + cdef threefry_state *rng_state cdef brng_t *_brng cdef public object capsule cdef object _ctypes cdef object _cffi cdef object _generator - + cdef public object lock def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(threefry_state)) @@ -167,6 +170,7 @@ cdef class ThreeFry: self.rng_state.key = malloc(sizeof(threefry4x64_key_t)) self._brng = malloc(sizeof(brng_t)) self.seed(seed, counter, key) + self.lock = Lock() self._brng.state = self.rng_state self._brng.next_uint64 = &threefry_uint64 @@ -207,16 +211,39 @@ cdef class ThreeFry: for i in range(THREEFRY_BUFFER_SIZE): self.rng_state.buffer[i] = 0 + def random_raw(self, size=None, output=True): + """ + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. + + Returns + ------- + out : uint or ndarray + Drawn samples. + + Notes + ----- + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. + """ + return random_raw(self._brng, self.lock, size, output) + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - cdef Py_ssize_t i - if method==u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method==u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None, counter=None, key=None): """ @@ -294,7 +321,7 @@ cdef class ThreeFry: key[i] = self.rng_state.key.v[i] for i in range(THREEFRY_BUFFER_SIZE): buffer[i] = self.rng_state.buffer[i] - state = {'counter':ctr,'key':key} + state = {'counter': ctr, 'key': key} return {'brng': self.__class__.__name__, 'state': state, 'buffer': buffer, @@ -385,14 +412,15 @@ cdef class ThreeFry: self._reset_state_variables() return self + @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -401,25 +429,10 @@ cdef class ThreeFry: * next_double - function pointer to produce doubles * brng - pointer to the Basic RNG struct """ + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&threefry_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&threefry_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&threefry_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) - return self.ctypes + return self._ctypes @property def cffi(self): @@ -440,19 +453,8 @@ cdef class ThreeFry: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): diff --git a/numpy/random/randomgen/threefry32.pyx b/numpy/random/randomgen/threefry32.pyx index c4d32a324db0..81f3ee93e040 100644 --- a/numpy/random/randomgen/threefry32.pyx +++ b/numpy/random/randomgen/threefry32.pyx @@ -1,4 +1,7 @@ -from __future__ import absolute_import +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock import numpy as np from cpython.pycapsule cimport PyCapsule_New @@ -23,10 +26,10 @@ cdef extern from 'src/threefry32/threefry32.h': ctypedef r123array4x32 threefry4x32_ctr_t struct s_threefry32_state: - threefry4x32_ctr_t *ctr; - threefry4x32_key_t *key; - int buffer_pos; - uint32_t buffer[THREEFRY_BUFFER_SIZE]; + threefry4x32_ctr_t *ctr + threefry4x32_key_t *key + int buffer_pos + uint32_t buffer[THREEFRY_BUFFER_SIZE] ctypedef s_threefry32_state threefry32_state @@ -156,12 +159,13 @@ cdef class ThreeFry32: the International Conference for High Performance Computing, Networking, Storage and Analysis (SC11), New York, NY: ACM, 2011. """ - cdef threefry32_state *rng_state + cdef threefry32_state *rng_state cdef brng_t *_brng cdef public object capsule cdef object _ctypes cdef object _cffi cdef object _generator + cdef public object lock def __init__(self, seed=None, counter=None, key=None): self.rng_state = malloc(sizeof(threefry32_state)) @@ -169,6 +173,7 @@ cdef class ThreeFry32: self.rng_state.key = malloc(sizeof(threefry4x32_key_t)) self._brng = malloc(sizeof(brng_t)) self.seed(seed, counter, key) + self.lock = Lock() self._brng.state = self.rng_state self._brng.next_uint64 = &threefry32_uint64 @@ -207,16 +212,39 @@ cdef class ThreeFry32: for i in range(THREEFRY_BUFFER_SIZE): self.rng_state.buffer[i] = 0 + def random_raw(self, size=None, output=True): + """ + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. + + Returns + ------- + out : uint or ndarray + Drawn samples. + + Notes + ----- + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. + """ + return random_raw(self._brng, self.lock, size, output) + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - cdef Py_ssize_t i - if method == u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method == u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None, counter=None, key=None): """ @@ -380,14 +408,15 @@ cdef class ThreeFry32: self._reset_state_variables() return self + @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -396,25 +425,10 @@ cdef class ThreeFry32: * next_double - function pointer to produce doubles * brng - pointer to the Basic RNG struct """ + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface( self.rng_state, - ctypes.c_void_p( self.rng_state), - ctypes.cast( &threefry32_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast( &threefry32_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast( &threefry32_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p( self._brng)) - return self.ctypes + return self._ctypes @property def cffi(self): @@ -435,22 +449,8 @@ cdef class ThreeFry32: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface( self.rng_state, - ffi.cast('void *', self.rng_state), - ffi.cast('uint64_t (*)(void *)', - self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)', - self._brng.next_uint32), - ffi.cast('double (*)(void *)', - self._brng.next_double), - ffi.cast('void *', self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): diff --git a/numpy/random/randomgen/xoroshiro128.pyx b/numpy/random/randomgen/xoroshiro128.pyx index a85f1fde5eb4..2ae876ea6be8 100644 --- a/numpy/random/randomgen/xoroshiro128.pyx +++ b/numpy/random/randomgen/xoroshiro128.pyx @@ -1,4 +1,7 @@ -from __future__ import absolute_import +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New @@ -16,15 +19,15 @@ np.import_array() cdef extern from "src/xoroshiro128/xoroshiro128.h": struct s_xoroshiro128_state: - uint64_t s[2] - int has_uint32 - uint32_t uinteger + uint64_t s[2] + int has_uint32 + uint32_t uinteger ctypedef s_xoroshiro128_state xoroshiro128_state uint64_t xoroshiro128_next64(xoroshiro128_state *state) nogil uint32_t xoroshiro128_next32(xoroshiro128_state *state) nogil - void xoroshiro128_jump(xoroshiro128_state *state) + void xoroshiro128_jump(xoroshiro128_state *state) cdef uint64_t xoroshiro128_uint64(void* st) nogil: return xoroshiro128_next64(st) @@ -120,17 +123,19 @@ cdef class Xoroshiro128: .. [1] "xoroshiro+ / xorshift* / xorshift+ generators and the PRNG shootout", http://xorshift.di.unimi.it/ """ - cdef xoroshiro128_state *rng_state + cdef xoroshiro128_state *rng_state cdef brng_t *_brng cdef public object capsule cdef object _ctypes cdef object _cffi cdef object _generator + cdef public object lock def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoroshiro128_state)) self._brng = malloc(sizeof(brng_t)) self.seed(seed) + self.lock = Lock() self._brng.state = self.rng_state self._brng.next_uint64 = &xoroshiro128_uint64 @@ -166,17 +171,39 @@ cdef class Xoroshiro128: self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 + def random_raw(self, size=None, output=True): + """ + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. + + Returns + ------- + out : uint or ndarray + Drawn samples. + + Notes + ----- + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. + """ + return random_raw(self._brng, self.lock, size, output) + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - """Private benchmark command""" - cdef Py_ssize_t i - if method==u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method==u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None): """ @@ -198,7 +225,7 @@ cdef class Xoroshiro128: ValueError If seed values are out of range for the PRNG. """ - ub = 2 ** 64 + ub = 2 ** 64 if seed is None: try: state = random_entropy(4) @@ -273,12 +300,12 @@ cdef class Xoroshiro128: @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -288,24 +315,10 @@ cdef class Xoroshiro128: * brng - pointer to the Basic RNG struct """ - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&xoroshiro128_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&xoroshiro128_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&xoroshiro128_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) - return self.ctypes + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) + + return self._ctypes @property def cffi(self): @@ -326,19 +339,8 @@ cdef class Xoroshiro128: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): diff --git a/numpy/random/randomgen/xorshift1024.pyx b/numpy/random/randomgen/xorshift1024.pyx index 62848bb81363..28b80cc9a96a 100644 --- a/numpy/random/randomgen/xorshift1024.pyx +++ b/numpy/random/randomgen/xorshift1024.pyx @@ -1,4 +1,7 @@ -from __future__ import absolute_import +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New @@ -16,16 +19,16 @@ np.import_array() cdef extern from "src/xorshift1024/xorshift1024.h": struct s_xorshift1024_state: - uint64_t s[16] - int p - int has_uint32 - uint32_t uinteger + uint64_t s[16] + int p + int has_uint32 + uint32_t uinteger ctypedef s_xorshift1024_state xorshift1024_state uint64_t xorshift1024_next64(xorshift1024_state *state) nogil uint32_t xorshift1024_next32(xorshift1024_state *state) nogil - void xorshift1024_jump(xorshift1024_state *state) + void xorshift1024_jump(xorshift1024_state *state) cdef uint64_t xorshift1024_uint64(void* st) nogil: return xorshift1024_next64(st) @@ -126,17 +129,19 @@ cdef class Xorshift1024: generators." CoRR, abs/1403.0930, 2014. """ - cdef xorshift1024_state *rng_state + cdef xorshift1024_state *rng_state cdef brng_t *_brng cdef public object capsule cdef object _ctypes cdef object _cffi cdef object _generator + cdef public object lock def __init__(self, seed=None): self.rng_state = malloc(sizeof(xorshift1024_state)) self._brng = malloc(sizeof(brng_t)) self.seed(seed) + self.lock = Lock() self._brng.state = self.rng_state self._brng.next_uint64 = &xorshift1024_uint64 @@ -172,41 +177,39 @@ cdef class Xorshift1024: self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 - def __random_integer(self, bits=64): + def random_raw(self, size=None, output=True): """ - 64-bit Random Integers from the PRNG + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG Parameters ---------- - bits : {32, 64} - Number of random bits to return + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. Returns ------- - rv : int - Next random value + out : uint or ndarray + Drawn samples. Notes ----- - Testing only + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. """ - if bits == 64: - return self._brng.next_uint64(self._brng.state) - elif bits == 32: - return self._brng.next_uint32(self._brng.state) - else: - raise ValueError('bits must be 32 or 64') + return random_raw(self._brng, self.lock, size, output) def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - cdef Py_ssize_t i - if method==u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method==u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None): """ @@ -229,7 +232,7 @@ cdef class Xorshift1024: If seed values are out of range for the PRNG. """ - ub = 2 ** 64 + ub = 2 ** 64 if seed is None: try: state = random_entropy(32) @@ -285,7 +288,7 @@ cdef class Xorshift1024: for i in range(16): s[i] = self.rng_state.s[i] return {'brng': self.__class__.__name__, - 'state': {'s':s,'p':self.rng_state.p}, + 'state': {'s': s, 'p': self.rng_state.p}, 'has_uint32': self.rng_state.has_uint32, 'uinteger': self.rng_state.uinteger} @@ -306,12 +309,12 @@ cdef class Xorshift1024: @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -320,25 +323,10 @@ cdef class Xorshift1024: * next_double - function pointer to produce doubles * brng - pointer to the Basic RNG struct """ + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&xorshift1024_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&xorshift1024_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&xorshift1024_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) - return self.ctypes + return self._ctypes @property def cffi(self): @@ -359,19 +347,8 @@ cdef class Xorshift1024: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): diff --git a/numpy/random/randomgen/xoshiro256starstar.pyx b/numpy/random/randomgen/xoshiro256starstar.pyx index 2d1e1955ee36..d45540aa9a23 100644 --- a/numpy/random/randomgen/xoshiro256starstar.pyx +++ b/numpy/random/randomgen/xoshiro256starstar.pyx @@ -1,11 +1,14 @@ -from __future__ import absolute_import - from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock + from .common import interface from .common cimport * from .distributions cimport brng_t @@ -16,15 +19,15 @@ np.import_array() cdef extern from "src/xoshiro256starstar/xoshiro256starstar.h": struct s_xoshiro256starstar_state: - uint64_t s[4] - int has_uint32 - uint32_t uinteger + uint64_t s[4] + int has_uint32 + uint32_t uinteger ctypedef s_xoshiro256starstar_state xoshiro256starstar_state uint64_t xoshiro256starstar_next64(xoshiro256starstar_state *state) nogil uint32_t xoshiro256starstar_next32(xoshiro256starstar_state *state) nogil - void xoshiro256starstar_jump(xoshiro256starstar_state *state) + void xoshiro256starstar_jump(xoshiro256starstar_state *state) cdef uint64_t xoshiro256starstar_uint64(void* st) nogil: return xoshiro256starstar_next64(st) @@ -120,17 +123,19 @@ cdef class Xoshiro256StarStar: .. [1] "xoroshiro+ / xorshift* / xorshift+ generators and the PRNG shootout", http://xorshift.di.unimi.it/ """ - cdef xoshiro256starstar_state *rng_state + cdef xoshiro256starstar_state *rng_state cdef brng_t *_brng cdef public object capsule cdef object _ctypes cdef object _cffi cdef object _generator + cdef public object lock def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoshiro256starstar_state)) self._brng = malloc(sizeof(brng_t)) self.seed(seed) + self.lock = Lock() self._brng.state = self.rng_state self._brng.next_uint64 = &xoshiro256starstar_uint64 @@ -166,17 +171,39 @@ cdef class Xoshiro256StarStar: self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 + def random_raw(self, size=None, output=True): + """ + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. + + Returns + ------- + out : uint or ndarray + Drawn samples. + + Notes + ----- + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. + """ + return random_raw(self._brng, self.lock, size, output) + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - """Private benchmark command""" - cdef Py_ssize_t i - if method==u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method==u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None): """ @@ -198,7 +225,7 @@ cdef class Xoshiro256StarStar: ValueError If seed values are out of range for the PRNG. """ - ub = 2 ** 64 + ub = 2 ** 64 if seed is None: try: state = random_entropy(8) @@ -279,12 +306,12 @@ cdef class Xoshiro256StarStar: @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -293,25 +320,10 @@ cdef class Xoshiro256StarStar: * next_double - function pointer to produce doubles * brng - pointer to the Basic RNG struct """ + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&xoshiro256starstar_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&xoshiro256starstar_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&xoshiro256starstar_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) - return self.ctypes + return self._ctypes @property def cffi(self): @@ -332,19 +344,8 @@ cdef class Xoshiro256StarStar: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): diff --git a/numpy/random/randomgen/xoshiro512starstar.pyx b/numpy/random/randomgen/xoshiro512starstar.pyx index 935deecfa898..0a6b104fdad2 100644 --- a/numpy/random/randomgen/xoshiro512starstar.pyx +++ b/numpy/random/randomgen/xoshiro512starstar.pyx @@ -1,4 +1,7 @@ -from __future__ import absolute_import +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock from libc.stdlib cimport malloc, free from cpython.pycapsule cimport PyCapsule_New @@ -16,15 +19,15 @@ np.import_array() cdef extern from "src/xoshiro512starstar/xoshiro512starstar.h": struct s_xoshiro512starstar_state: - uint64_t s[8] - int has_uint32 - uint32_t uinteger + uint64_t s[8] + int has_uint32 + uint32_t uinteger ctypedef s_xoshiro512starstar_state xoshiro512starstar_state uint64_t xoshiro512starstar_next64(xoshiro512starstar_state *state) nogil uint32_t xoshiro512starstar_next32(xoshiro512starstar_state *state) nogil - void xoshiro512starstar_jump(xoshiro512starstar_state *state) + void xoshiro512starstar_jump(xoshiro512starstar_state *state) cdef uint64_t xoshiro512starstar_uint64(void* st) nogil: return xoshiro512starstar_next64(st) @@ -120,17 +123,19 @@ cdef class Xoshiro512StarStar: .. [1] "xoroshiro+ / xorshift* / xorshift+ generators and the PRNG shootout", http://xorshift.di.unimi.it/ """ - cdef xoshiro512starstar_state *rng_state + cdef xoshiro512starstar_state *rng_state cdef brng_t *_brng cdef public object capsule cdef object _ctypes cdef object _cffi cdef object _generator + cdef public object lock def __init__(self, seed=None): self.rng_state = malloc(sizeof(xoshiro512starstar_state)) self._brng = malloc(sizeof(brng_t)) self.seed(seed) + self.lock = Lock() self._brng.state = self.rng_state self._brng.next_uint64 = &xoshiro512starstar_uint64 @@ -166,17 +171,39 @@ cdef class Xoshiro512StarStar: self.rng_state.has_uint32 = 0 self.rng_state.uinteger = 0 + def random_raw(self, size=None, output=True): + """ + random_raw(self, size=None) + + Return randoms as generated by the underlying BasicRNG + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + output : bool, optional + Output values. Used for performance testing since the generated + values are not returned. + + Returns + ------- + out : uint or ndarray + Drawn samples. + + Notes + ----- + This method directly exposes the the raw underlying pseudo-random + number generator. All values are returned as unsigned 64-bit + values irrespective of the number of bits produced by the PRNG. + + See the class docstring for the number of bits returned. + """ + return random_raw(self._brng, self.lock, size, output) + def _benchmark(self, Py_ssize_t cnt, method=u'uint64'): - """Private benchmark command""" - cdef Py_ssize_t i - if method==u'uint64': - for i in range(cnt): - self._brng.next_uint64(self._brng.state) - elif method==u'double': - for i in range(cnt): - self._brng.next_double(self._brng.state) - else: - raise ValueError('Unknown method') + return benchmark(self._brng, self.lock, cnt, method) def seed(self, seed=None): """ @@ -198,7 +225,7 @@ cdef class Xoshiro512StarStar: ValueError If seed values are out of range for the PRNG. """ - ub = 2 ** 64 + ub = 2 ** 64 if seed is None: try: state = random_entropy(16) @@ -273,12 +300,12 @@ cdef class Xoshiro512StarStar: @property def ctypes(self): """ - Ctypes interface + ctypes interface Returns ------- interface : namedtuple - Named tuple containing CFFI wrapper + Named tuple containing ctypes wrapper * state_address - Memory address of the state struct * state - pointer to the state struct @@ -287,25 +314,10 @@ cdef class Xoshiro512StarStar: * next_double - function pointer to produce doubles * brng - pointer to the Basic RNG struct """ + if self._ctypes is None: + self._ctypes = prepare_ctypes(self._brng) - if self._ctypes is not None: - return self._ctypes - - import ctypes - - self._ctypes = interface(self.rng_state, - ctypes.c_void_p(self.rng_state), - ctypes.cast(&xoshiro512starstar_uint64, - ctypes.CFUNCTYPE(ctypes.c_uint64, - ctypes.c_void_p)), - ctypes.cast(&xoshiro512starstar_uint32, - ctypes.CFUNCTYPE(ctypes.c_uint32, - ctypes.c_void_p)), - ctypes.cast(&xoshiro512starstar_double, - ctypes.CFUNCTYPE(ctypes.c_double, - ctypes.c_void_p)), - ctypes.c_void_p(self._brng)) - return self.ctypes + return self._ctypes @property def cffi(self): @@ -326,19 +338,8 @@ cdef class Xoshiro512StarStar: """ if self._cffi is not None: return self._cffi - try: - import cffi - except ImportError: - raise ImportError('cffi is cannot be imported.') - - ffi = cffi.FFI() - self._cffi = interface(self.rng_state, - ffi.cast('void *',self.rng_state), - ffi.cast('uint64_t (*)(void *)',self._brng.next_uint64), - ffi.cast('uint32_t (*)(void *)',self._brng.next_uint32), - ffi.cast('double (*)(void *)',self._brng.next_double), - ffi.cast('void *',self._brng)) - return self.cffi + self._cffi = prepare_cffi(self._brng) + return self._cffi @property def generator(self): From ce5857dad299cb741e18a39a7c9fff0cb94f64f4 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 1 Apr 2019 17:08:41 +0100 Subject: [PATCH 230/279] TST: Incorporate edge tests Incorporate testing of edge cases into main tests Rename test files to describe their purpose --- ...y_mt19937.py => test_generator_mt19937.py} | 501 ++++++++++-------- ... => test_generator_mt19937_regressions.py} | 0 numpy/random/randomgen/tests/test_smoke.py | 5 - 3 files changed, 272 insertions(+), 234 deletions(-) rename numpy/random/randomgen/tests/{test_numpy_mt19937.py => test_generator_mt19937.py} (82%) rename numpy/random/randomgen/tests/{test_numpy_mt19937_regressions.py => test_generator_mt19937_regressions.py} (100%) diff --git a/numpy/random/randomgen/tests/test_numpy_mt19937.py b/numpy/random/randomgen/tests/test_generator_mt19937.py similarity index 82% rename from numpy/random/randomgen/tests/test_numpy_mt19937.py rename to numpy/random/randomgen/tests/test_generator_mt19937.py index b2249b684f67..3c999ab73e2b 100644 --- a/numpy/random/randomgen/tests/test_numpy_mt19937.py +++ b/numpy/random/randomgen/tests/test_generator_mt19937.py @@ -11,7 +11,7 @@ from ...randomgen import RandomGenerator, MT19937 -random = mt19937 = RandomGenerator(MT19937()) +random = RandomGenerator(MT19937()) class TestSeed(object): @@ -44,6 +44,9 @@ def test_invalid_array(self): assert_raises(ValueError, MT19937, [1, 2, 4294967296]) assert_raises(ValueError, MT19937, [1, -2, 4294967296]) + def test_noninstantized_brng(self): + assert_raises(ValueError, RandomGenerator, MT19937) + class TestBinomial(object): def test_n_zero(self): @@ -77,15 +80,15 @@ def test_int_negative_interval(self): def test_size(self): # gh-3173 p = [0.5, 0.5] - assert_equal(mt19937.multinomial(1, p, np.uint32(1)).shape, (1, 2)) - assert_equal(mt19937.multinomial(1, p, np.uint32(1)).shape, (1, 2)) - assert_equal(mt19937.multinomial(1, p, np.uint32(1)).shape, (1, 2)) - assert_equal(mt19937.multinomial(1, p, [2, 2]).shape, (2, 2, 2)) - assert_equal(mt19937.multinomial(1, p, (2, 2)).shape, (2, 2, 2)) - assert_equal(mt19937.multinomial(1, p, np.array((2, 2))).shape, + assert_equal(random.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.multinomial(1, p, [2, 2]).shape, (2, 2, 2)) + assert_equal(random.multinomial(1, p, (2, 2)).shape, (2, 2, 2)) + assert_equal(random.multinomial(1, p, np.array((2, 2))).shape, (2, 2, 2)) - assert_raises(TypeError, mt19937.multinomial, 1, p, + assert_raises(TypeError, random.multinomial, 1, p, float(1)) def test_invalid_prob(self): @@ -132,7 +135,7 @@ def test_negative_binomial(self): class TestRandint(object): - rfunc = mt19937.randint + rfunc = random.randint # valid integer/boolean types itype = [bool, np.int8, np.uint8, np.int16, np.uint16, @@ -244,7 +247,7 @@ def test_full_range_array(self): def test_in_bounds_fuzz(self): # Don't use fixed seed - mt19937.seed() + random.seed() for dt in self.itype[1:]: for ubnd in [4, 8, 16]: @@ -263,13 +266,13 @@ def test_scalar_array_equiv(self): ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 size = 1000 - mt19937.seed(1234) + random.seed(1234) scalar = self.rfunc(lbnd, ubnd, size=size, dtype=dt) - mt19937.seed(1234) + random.seed(1234) scalar_array = self.rfunc([lbnd], [ubnd], size=size, dtype=dt) - mt19937.seed(1234) + random.seed(1234) array = self.rfunc([lbnd] * size, [ubnd] * size, size=size, dtype=dt) assert_array_equal(scalar, scalar_array) @@ -291,7 +294,7 @@ def test_repeatability(self): 'uint8': '27dd30c4e08a797063dffac2490b0be6'} for dt in self.itype[1:]: - mt19937.seed(1234) + random.seed(1234) # view as little endian for hash if sys.byteorder == 'little': @@ -303,7 +306,7 @@ def test_repeatability(self): assert_(tgt[np.dtype(dt).name] == res) # bools do not depend on endianness - mt19937.seed(1234) + random.seed(1234) val = self.rfunc(0, 2, size=1000, dtype=bool).view(np.int8) res = hashlib.md5(val).hexdigest() assert_(tgt[np.dtype(bool).name] == res) @@ -316,15 +319,15 @@ def test_repeatability_broadcasting(self): np.bool, bool, np.bool_) else np.iinfo(dt).max + 1 # view as little endian for hash - mt19937.seed(1234) + random.seed(1234) val = self.rfunc(lbnd, ubnd, size=1000, dtype=dt) - mt19937.seed(1234) + random.seed(1234) val_bc = self.rfunc([lbnd] * 1000, ubnd, dtype=dt) assert_array_equal(val, val_bc) - mt19937.seed(1234) + random.seed(1234) val_bc = self.rfunc([lbnd] * 1000, [ubnd] * 1000, dtype=dt) assert_array_equal(val, val_bc) @@ -349,7 +352,7 @@ def test_int64_uint64_corner_case(self): # None of these function calls should # generate a ValueError now. - actual = mt19937.randint(lbnd, ubnd, dtype=dt) + actual = random.randint(lbnd, ubnd, dtype=dt) assert_equal(actual, tgt) def test_respect_dtype_singleton(self): @@ -400,34 +403,34 @@ def setup(self): self.seed = 1234567890 def test_rand(self): - mt19937.seed(self.seed) - actual = mt19937.rand(3, 2) + random.seed(self.seed) + actual = random.rand(3, 2) desired = np.array([[0.61879477158567997, 0.59162362775974664], [0.88868358904449662, 0.89165480011560816], [0.4575674820298663, 0.7781880808593471]]) assert_array_almost_equal(actual, desired, decimal=15) def test_rand_singleton(self): - mt19937.seed(self.seed) - actual = mt19937.rand() + random.seed(self.seed) + actual = random.rand() desired = 0.61879477158567997 assert_array_almost_equal(actual, desired, decimal=15) def test_randn(self): - mt19937.seed(self.seed) - actual = mt19937.randn(3, 2) + random.seed(self.seed) + actual = random.randn(3, 2) desired = np.array([[-3.472754000610961, -0.108938564229143], [-0.245965753396411, -0.704101550261701], [0.360102487116356, 0.127832101772367]]) assert_array_almost_equal(actual, desired, decimal=15) - mt19937.seed(self.seed) - actual = mt19937.randn() + random.seed(self.seed) + actual = random.randn() assert_array_almost_equal(actual, desired[0, 0], decimal=15) def test_randint(self): - mt19937.seed(self.seed) - actual = mt19937.randint(-99, 99, size=(3, 2)) + random.seed(self.seed) + actual = random.randint(-99, 99, size=(3, 2)) desired = np.array([[31, 3], [-52, 41], [-48, -66]]) @@ -436,9 +439,9 @@ def test_randint(self): def test_randint_masked(self): # Test masked rejection sampling algorithm to generate array of # uint32 in an interval. - mt19937.seed(self.seed) - actual = mt19937.randint(0, 99, size=(3, 2), dtype=np.uint32, - use_masked=True) + random.seed(self.seed) + actual = random.randint(0, 99, size=(3, 2), dtype=np.uint32, + use_masked=True) desired = np.array([[2, 47], [12, 51], [33, 43]], dtype=np.uint32) @@ -446,9 +449,9 @@ def test_randint_masked(self): def test_randint_lemire_32(self): # Test lemire algorithm to generate array of uint32 in an interval. - mt19937.seed(self.seed) - actual = mt19937.randint(0, 99, size=(3, 2), dtype=np.uint32, - use_masked=False) + random.seed(self.seed) + actual = random.randint(0, 99, size=(3, 2), dtype=np.uint32, + use_masked=False) desired = np.array([[61, 33], [58, 14], [87, 23]], dtype=np.uint32) @@ -456,19 +459,19 @@ def test_randint_lemire_32(self): def test_randint_lemire_64(self): # Test lemire algorithm to generate array of uint64 in an interval. - mt19937.seed(self.seed) - actual = mt19937.randint(0, 99 + 0xFFFFFFFFF, size=(3, 2), - dtype=np.uint64, use_masked=False) + random.seed(self.seed) + actual = random.randint(0, 99 + 0xFFFFFFFFF, size=(3, 2), + dtype=np.uint64, use_masked=False) desired = np.array([[42523252834, 40656066204], [61069871386, 61274051182], [31443797706, 53476677934]], dtype=np.uint64) assert_array_equal(actual, desired) def test_random_integers(self): - mt19937.seed(self.seed) + random.seed(self.seed) with suppress_warnings() as sup: w = sup.record(DeprecationWarning) - actual = mt19937.random_integers(-99, 99, size=(3, 2)) + actual = random.random_integers(-99, 99, size=(3, 2)) assert_(len(w) == 1) desired = np.array([[31, 3], [-52, 41], @@ -483,8 +486,8 @@ def test_random_integers_max_int(self): # to generate this integer. with suppress_warnings() as sup: w = sup.record(DeprecationWarning) - actual = mt19937.random_integers(np.iinfo('l').max, - np.iinfo('l').max) + actual = random.random_integers(np.iinfo('l').max, + np.iinfo('l').max) assert_(len(w) == 1) desired = np.iinfo('l').max @@ -496,70 +499,76 @@ def test_random_integers_deprecated(self): # DeprecationWarning raised with high == None assert_raises(DeprecationWarning, - mt19937.random_integers, + random.random_integers, np.iinfo('l').max) # DeprecationWarning raised with high != None assert_raises(DeprecationWarning, - mt19937.random_integers, + random.random_integers, np.iinfo('l').max, np.iinfo('l').max) def test_random_sample(self): - mt19937.seed(self.seed) - actual = mt19937.random_sample((3, 2)) + random.seed(self.seed) + actual = random.random_sample((3, 2)) desired = np.array([[0.61879477158567997, 0.59162362775974664], [0.88868358904449662, 0.89165480011560816], [0.4575674820298663, 0.7781880808593471]]) assert_array_almost_equal(actual, desired, decimal=15) - mt19937.seed(self.seed) - actual = mt19937.random_sample() + random.seed(self.seed) + actual = random.random_sample() assert_array_almost_equal(actual, desired[0, 0], decimal=15) def test_random_sample_float(self): - mt19937.seed(self.seed) - actual = mt19937.random_sample((3, 2)) + random.seed(self.seed) + actual = random.random_sample((3, 2)) desired = np.array([[0.6187948, 0.5916236], [0.8886836, 0.8916548], [0.4575675, 0.7781881]]) assert_array_almost_equal(actual, desired, decimal=7) + def test_random_sample_float_scalar(self): + random.seed(self.seed) + actual = random.random_sample(dtype=np.float32) + desired = 0.6187948 + assert_array_almost_equal(actual, desired, decimal=7) + def test_random_sample_unsupported_type(self): - assert_raises(TypeError, mt19937.random_sample, dtype='int32') + assert_raises(TypeError, random.random_sample, dtype='int32') def test_choice_uniform_replace(self): - mt19937.seed(self.seed) - actual = mt19937.choice(4, 4) + random.seed(self.seed) + actual = random.choice(4, 4) desired = np.array([2, 3, 2, 3]) assert_array_equal(actual, desired) def test_choice_nonuniform_replace(self): - mt19937.seed(self.seed) - actual = mt19937.choice(4, 4, p=[0.4, 0.4, 0.1, 0.1]) + random.seed(self.seed) + actual = random.choice(4, 4, p=[0.4, 0.4, 0.1, 0.1]) desired = np.array([1, 1, 2, 2]) assert_array_equal(actual, desired) def test_choice_uniform_noreplace(self): - mt19937.seed(self.seed) - actual = mt19937.choice(4, 3, replace=False) + random.seed(self.seed) + actual = random.choice(4, 3, replace=False) desired = np.array([0, 1, 3]) assert_array_equal(actual, desired) def test_choice_nonuniform_noreplace(self): - mt19937.seed(self.seed) - actual = mt19937.choice(4, 3, replace=False, - p=[0.1, 0.3, 0.5, 0.1]) + random.seed(self.seed) + actual = random.choice(4, 3, replace=False, + p=[0.1, 0.3, 0.5, 0.1]) desired = np.array([2, 3, 1]) assert_array_equal(actual, desired) def test_choice_noninteger(self): - mt19937.seed(self.seed) - actual = mt19937.choice(['a', 'b', 'c', 'd'], 4) + random.seed(self.seed) + actual = random.choice(['a', 'b', 'c', 'd'], 4) desired = np.array(['c', 'd', 'c', 'd']) assert_array_equal(actual, desired) def test_choice_exceptions(self): - sample = mt19937.choice + sample = random.choice assert_raises(ValueError, sample, -1, 3) assert_raises(ValueError, sample, 3., 3) assert_raises(ValueError, sample, [[1, 2], [3, 4]], 3) @@ -580,57 +589,57 @@ def test_choice_exceptions(self): def test_choice_return_shape(self): p = [0.1, 0.9] # Check scalar - assert_(np.isscalar(mt19937.choice(2, replace=True))) - assert_(np.isscalar(mt19937.choice(2, replace=False))) - assert_(np.isscalar(mt19937.choice(2, replace=True, p=p))) - assert_(np.isscalar(mt19937.choice(2, replace=False, p=p))) - assert_(np.isscalar(mt19937.choice([1, 2], replace=True))) - assert_(mt19937.choice([None], replace=True) is None) + assert_(np.isscalar(random.choice(2, replace=True))) + assert_(np.isscalar(random.choice(2, replace=False))) + assert_(np.isscalar(random.choice(2, replace=True, p=p))) + assert_(np.isscalar(random.choice(2, replace=False, p=p))) + assert_(np.isscalar(random.choice([1, 2], replace=True))) + assert_(random.choice([None], replace=True) is None) a = np.array([1, 2]) arr = np.empty(1, dtype=object) arr[0] = a - assert_(mt19937.choice(arr, replace=True) is a) + assert_(random.choice(arr, replace=True) is a) # Check 0-d array s = tuple() - assert_(not np.isscalar(mt19937.choice(2, s, replace=True))) - assert_(not np.isscalar(mt19937.choice(2, s, replace=False))) - assert_(not np.isscalar(mt19937.choice(2, s, replace=True, p=p))) - assert_(not np.isscalar(mt19937.choice(2, s, replace=False, p=p))) - assert_(not np.isscalar(mt19937.choice([1, 2], s, replace=True))) - assert_(mt19937.choice([None], s, replace=True).ndim == 0) + assert_(not np.isscalar(random.choice(2, s, replace=True))) + assert_(not np.isscalar(random.choice(2, s, replace=False))) + assert_(not np.isscalar(random.choice(2, s, replace=True, p=p))) + assert_(not np.isscalar(random.choice(2, s, replace=False, p=p))) + assert_(not np.isscalar(random.choice([1, 2], s, replace=True))) + assert_(random.choice([None], s, replace=True).ndim == 0) a = np.array([1, 2]) arr = np.empty(1, dtype=object) arr[0] = a - assert_(mt19937.choice(arr, s, replace=True).item() is a) + assert_(random.choice(arr, s, replace=True).item() is a) # Check multi dimensional array s = (2, 3) p = [0.1, 0.1, 0.1, 0.1, 0.4, 0.2] - assert_(mt19937.choice(6, s, replace=True).shape, s) - assert_(mt19937.choice(6, s, replace=False).shape, s) - assert_(mt19937.choice(6, s, replace=True, p=p).shape, s) - assert_(mt19937.choice(6, s, replace=False, p=p).shape, s) - assert_(mt19937.choice(np.arange(6), s, replace=True).shape, s) + assert_(random.choice(6, s, replace=True).shape, s) + assert_(random.choice(6, s, replace=False).shape, s) + assert_(random.choice(6, s, replace=True, p=p).shape, s) + assert_(random.choice(6, s, replace=False, p=p).shape, s) + assert_(random.choice(np.arange(6), s, replace=True).shape, s) # Check zero-size - assert_equal(mt19937.randint(0, 0, size=(3, 0, 4)).shape, (3, 0, 4)) - assert_equal(mt19937.randint(0, -10, size=0).shape, (0,)) - assert_equal(mt19937.randint(10, 10, size=0).shape, (0,)) - assert_equal(mt19937.choice(0, size=0).shape, (0,)) - assert_equal(mt19937.choice([], size=(0,)).shape, (0,)) - assert_equal(mt19937.choice(['a', 'b'], size=(3, 0, 4)).shape, + assert_equal(random.randint(0, 0, size=(3, 0, 4)).shape, (3, 0, 4)) + assert_equal(random.randint(0, -10, size=0).shape, (0,)) + assert_equal(random.randint(10, 10, size=0).shape, (0,)) + assert_equal(random.choice(0, size=0).shape, (0,)) + assert_equal(random.choice([], size=(0,)).shape, (0,)) + assert_equal(random.choice(['a', 'b'], size=(3, 0, 4)).shape, (3, 0, 4)) - assert_raises(ValueError, mt19937.choice, [], 10) + assert_raises(ValueError, random.choice, [], 10) def test_choice_nan_probabilities(self): a = np.array([42, 1, 2]) p = [None, None, None] - assert_raises(ValueError, mt19937.choice, a, p=p) + assert_raises(ValueError, random.choice, a, p=p) def test_bytes(self): - mt19937.seed(self.seed) - actual = mt19937.bytes(10) + random.seed(self.seed) + actual = random.bytes(10) desired = b'\x82Ui\x9e\xff\x97+Wf\xa5' assert_equal(actual, desired) @@ -654,9 +663,9 @@ def test_shuffle(self): lambda x: np.asarray([(i, i) for i in x], [("a", object, 1), ("b", np.int32, 1)])]: - mt19937.seed(self.seed) + random.seed(self.seed) alist = conv([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) - mt19937.shuffle(alist) + random.shuffle(alist) actual = alist desired = conv([0, 1, 9, 6, 2, 4, 5, 8, 7, 3]) assert_array_equal(actual, desired) @@ -668,28 +677,28 @@ def test_shuffle_masked(self): a_orig = a.copy() b_orig = b.copy() for i in range(50): - mt19937.shuffle(a) + random.shuffle(a) assert_equal( sorted(a.data[~a.mask]), sorted(a_orig.data[~a_orig.mask])) - mt19937.shuffle(b) + random.shuffle(b) assert_equal( sorted(b.data[~b.mask]), sorted(b_orig.data[~b_orig.mask])) def test_permutation(self): - mt19937.seed(self.seed) + random.seed(self.seed) alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] - actual = mt19937.permutation(alist) + actual = random.permutation(alist) desired = [0, 1, 9, 6, 2, 4, 5, 8, 7, 3] assert_array_equal(actual, desired) - mt19937.seed(self.seed) + random.seed(self.seed) arr_2d = np.atleast_2d([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]).T - actual = mt19937.permutation(arr_2d) + actual = random.permutation(arr_2d) assert_array_equal(actual, np.atleast_2d(desired).T) def test_beta(self): - mt19937.seed(self.seed) - actual = mt19937.beta(.1, .9, size=(3, 2)) + random.seed(self.seed) + actual = random.beta(.1, .9, size=(3, 2)) desired = np.array( [[1.45341850513746058e-02, 5.31297615662868145e-04], [1.85366619058432324e-06, 4.19214516800110563e-03], @@ -697,25 +706,25 @@ def test_beta(self): assert_array_almost_equal(actual, desired, decimal=15) def test_binomial(self): - mt19937.seed(self.seed) - actual = mt19937.binomial(100.123, .456, size=(3, 2)) + random.seed(self.seed) + actual = random.binomial(100.123, .456, size=(3, 2)) desired = np.array([[37, 43], [42, 48], [46, 45]]) assert_array_equal(actual, desired) def test_chisquare(self): - mt19937.seed(self.seed) - actual = mt19937.chisquare(50, size=(3, 2)) + random.seed(self.seed) + actual = random.chisquare(50, size=(3, 2)) desired = np.array([[22.2534560369812, 46.9302393710074], [52.9974164611614, 85.3559029505718], [46.1580841240719, 36.1933148548090]]) assert_array_almost_equal(actual, desired, decimal=13) def test_dirichlet(self): - mt19937.seed(self.seed) + random.seed(self.seed) alpha = np.array([51.72840233779265162, 39.74494232180943953]) - actual = mt19937.dirichlet(alpha, size=(3, 2)) + actual = random.dirichlet(alpha, size=(3, 2)) desired = np.array([[[0.444382290764855, 0.555617709235145], [0.468440809291970, 0.531559190708030]], [[0.613461427360549, 0.386538572639451], @@ -724,24 +733,29 @@ def test_dirichlet(self): [0.558550925712797, 0.441449074287203]]]) assert_array_almost_equal(actual, desired, decimal=15) bad_alpha = np.array([5.4e-01, -1.0e-16]) - assert_raises(ValueError, mt19937.dirichlet, bad_alpha) + assert_raises(ValueError, random.dirichlet, bad_alpha) + + random.seed(self.seed) + alpha = np.array([51.72840233779265162, 39.74494232180943953]) + actual = random.dirichlet(alpha) + assert_array_almost_equal(actual, desired[0, 0], decimal=15) def test_dirichlet_size(self): # gh-3173 p = np.array([51.72840233779265162, 39.74494232180943953]) - assert_equal(mt19937.dirichlet(p, np.uint32(1)).shape, (1, 2)) - assert_equal(mt19937.dirichlet(p, np.uint32(1)).shape, (1, 2)) - assert_equal(mt19937.dirichlet(p, np.uint32(1)).shape, (1, 2)) - assert_equal(mt19937.dirichlet(p, [2, 2]).shape, (2, 2, 2)) - assert_equal(mt19937.dirichlet(p, (2, 2)).shape, (2, 2, 2)) - assert_equal(mt19937.dirichlet(p, np.array((2, 2))).shape, (2, 2, 2)) + assert_equal(random.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(random.dirichlet(p, [2, 2]).shape, (2, 2, 2)) + assert_equal(random.dirichlet(p, (2, 2)).shape, (2, 2, 2)) + assert_equal(random.dirichlet(p, np.array((2, 2))).shape, (2, 2, 2)) - assert_raises(TypeError, mt19937.dirichlet, p, float(1)) + assert_raises(TypeError, random.dirichlet, p, float(1)) def test_dirichlet_bad_alpha(self): # gh-2089 alpha = np.array([5.4e-01, -1.0e-16]) - assert_raises(ValueError, mt19937.dirichlet, alpha) + assert_raises(ValueError, random.dirichlet, alpha) def test_exponential(self): random.seed(self.seed) @@ -752,8 +766,8 @@ def test_exponential(self): assert_array_almost_equal(actual, desired, decimal=15) def test_exponential_0(self): - assert_equal(mt19937.exponential(scale=0), 0) - assert_raises(ValueError, mt19937.exponential, scale=-0.) + assert_equal(random.exponential(scale=0), 0) + assert_raises(ValueError, random.exponential, scale=-0.) def test_f(self): random.seed(self.seed) @@ -772,70 +786,70 @@ def test_gamma(self): assert_array_almost_equal(actual, desired, decimal=14) def test_gamma_0(self): - assert_equal(mt19937.gamma(shape=0, scale=0), 0) - assert_raises(ValueError, mt19937.gamma, shape=-0., scale=-0.) + assert_equal(random.gamma(shape=0, scale=0), 0) + assert_raises(ValueError, random.gamma, shape=-0., scale=-0.) def test_geometric(self): - mt19937.seed(self.seed) - actual = mt19937.geometric(.123456789, size=(3, 2)) + random.seed(self.seed) + actual = random.geometric(.123456789, size=(3, 2)) desired = np.array([[8, 7], [17, 17], [5, 12]]) assert_array_equal(actual, desired) def test_gumbel(self): - mt19937.seed(self.seed) - actual = mt19937.gumbel(loc=.123456789, scale=2.0, size=(3, 2)) + random.seed(self.seed) + actual = random.gumbel(loc=.123456789, scale=2.0, size=(3, 2)) desired = np.array([[0.19591898743416816, 0.34405539668096674], [-1.4492522252274278, -1.47374816298446865], [1.10651090478803416, -0.69535848626236174]]) assert_array_almost_equal(actual, desired, decimal=15) def test_gumbel_0(self): - assert_equal(mt19937.gumbel(scale=0), 0) - assert_raises(ValueError, mt19937.gumbel, scale=-0.) + assert_equal(random.gumbel(scale=0), 0) + assert_raises(ValueError, random.gumbel, scale=-0.) def test_hypergeometric(self): - mt19937.seed(self.seed) - actual = mt19937.hypergeometric(10.1, 5.5, 14, size=(3, 2)) + random.seed(self.seed) + actual = random.hypergeometric(10.1, 5.5, 14, size=(3, 2)) desired = np.array([[10, 10], [10, 10], [9, 9]]) assert_array_equal(actual, desired) # Test nbad = 0 - actual = mt19937.hypergeometric(5, 0, 3, size=4) + actual = random.hypergeometric(5, 0, 3, size=4) desired = np.array([3, 3, 3, 3]) assert_array_equal(actual, desired) - actual = mt19937.hypergeometric(15, 0, 12, size=4) + actual = random.hypergeometric(15, 0, 12, size=4) desired = np.array([12, 12, 12, 12]) assert_array_equal(actual, desired) # Test ngood = 0 - actual = mt19937.hypergeometric(0, 5, 3, size=4) + actual = random.hypergeometric(0, 5, 3, size=4) desired = np.array([0, 0, 0, 0]) assert_array_equal(actual, desired) - actual = mt19937.hypergeometric(0, 15, 12, size=4) + actual = random.hypergeometric(0, 15, 12, size=4) desired = np.array([0, 0, 0, 0]) assert_array_equal(actual, desired) def test_laplace(self): - mt19937.seed(self.seed) - actual = mt19937.laplace(loc=.123456789, scale=2.0, size=(3, 2)) + random.seed(self.seed) + actual = random.laplace(loc=.123456789, scale=2.0, size=(3, 2)) desired = np.array([[0.66599721112760157, 0.52829452552221945], [3.12791959514407125, 3.18202813572992005], [-0.05391065675859356, 1.74901336242837324]]) assert_array_almost_equal(actual, desired, decimal=15) def test_laplace_0(self): - assert_equal(mt19937.laplace(scale=0), 0) - assert_raises(ValueError, mt19937.laplace, scale=-0.) + assert_equal(random.laplace(scale=0), 0) + assert_raises(ValueError, random.laplace, scale=-0.) def test_logistic(self): - mt19937.seed(self.seed) - actual = mt19937.logistic(loc=.123456789, scale=2.0, size=(3, 2)) + random.seed(self.seed) + actual = random.logistic(loc=.123456789, scale=2.0, size=(3, 2)) desired = np.array([[1.09232835305011444, 0.8648196662399954], [4.27818590694950185, 4.33897006346929714], [-0.21682183359214885, 2.63373365386060332]]) @@ -850,20 +864,20 @@ def test_lognormal(self): assert_array_almost_equal(actual, desired, decimal=13) def test_lognormal_0(self): - assert_equal(mt19937.lognormal(sigma=0), 1) - assert_raises(ValueError, mt19937.lognormal, sigma=-0.) + assert_equal(random.lognormal(sigma=0), 1) + assert_raises(ValueError, random.lognormal, sigma=-0.) def test_logseries(self): - mt19937.seed(self.seed) - actual = mt19937.logseries(p=.923456789, size=(3, 2)) + random.seed(self.seed) + actual = random.logseries(p=.923456789, size=(3, 2)) desired = np.array([[2, 2], [6, 17], [3, 6]]) assert_array_equal(actual, desired) def test_multinomial(self): - mt19937.seed(self.seed) - actual = mt19937.multinomial(20, [1 / 6.] * 6, size=(3, 2)) + random.seed(self.seed) + actual = random.multinomial(20, [1 / 6.] * 6, size=(3, 2)) desired = np.array([[[4, 3, 5, 4, 2, 2], [5, 2, 8, 2, 2, 1]], [[3, 4, 3, 6, 0, 4], @@ -879,7 +893,6 @@ def test_multivariate_normal(self): size = (3, 2) actual = random.multivariate_normal(mean, cov, size) np.set_printoptions(precision=20) - print(actual) desired = np.array([[[-3.34929721161096100, 9.891061435770858], [-0.12250896439641100, 9.295898449738300]], [[0.48355927611635563, 10.127832101772366], @@ -898,31 +911,31 @@ def test_multivariate_normal(self): # RuntimeWarning mean = [0, 0] cov = [[1, 2], [2, 1]] - assert_warns(RuntimeWarning, mt19937.multivariate_normal, mean, cov) + assert_warns(RuntimeWarning, random.multivariate_normal, mean, cov) # and that it doesn't warn with RuntimeWarning check_valid='ignore' - assert_no_warnings(mt19937.multivariate_normal, mean, cov, + assert_no_warnings(random.multivariate_normal, mean, cov, check_valid='ignore') # and that it raises with RuntimeWarning check_valid='raises' - assert_raises(ValueError, mt19937.multivariate_normal, mean, cov, + assert_raises(ValueError, random.multivariate_normal, mean, cov, check_valid='raise') cov = np.array([[1, 0.1], [0.1, 1]], dtype=np.float32) with suppress_warnings() as sup: - mt19937.multivariate_normal(mean, cov) + random.multivariate_normal(mean, cov) w = sup.record(RuntimeWarning) assert len(w) == 0 mu = np.zeros(2) cov = np.eye(2) - assert_raises(ValueError, mt19937.multivariate_normal, mean, cov, + assert_raises(ValueError, random.multivariate_normal, mean, cov, check_valid='other') - assert_raises(ValueError, mt19937.multivariate_normal, + assert_raises(ValueError, random.multivariate_normal, np.zeros((2, 1, 1)), cov) - assert_raises(ValueError, mt19937.multivariate_normal, + assert_raises(ValueError, random.multivariate_normal, mu, np.empty((3, 2))) - assert_raises(ValueError, mt19937.multivariate_normal, + assert_raises(ValueError, random.multivariate_normal, mu, np.eye(3)) def test_negative_binomial(self): @@ -972,14 +985,12 @@ def test_normal(self): assert_array_almost_equal(actual, desired, decimal=15) def test_normal_0(self): - assert_equal(mt19937.normal(scale=0), 0) - assert_raises(ValueError, mt19937.normal, scale=-0.) + assert_equal(random.normal(scale=0), 0) + assert_raises(ValueError, random.normal, scale=-0.) def test_pareto(self): random.seed(self.seed) actual = random.pareto(a=.123456789, size=(3, 2)) - np.set_printoptions(precision=20) - print(actual) desired = np.array([[5.6883528121891552e+16, 4.0569373841667057e+03], [1.2854967019379475e+12, 6.5833156486851483e+04], [1.1281132447159091e+01, 3.1895968171107006e+08]]) @@ -992,8 +1003,8 @@ def test_pareto(self): np.testing.assert_array_almost_equal_nulp(actual, desired, nulp=30) def test_poisson(self): - mt19937.seed(self.seed) - actual = mt19937.poisson(lam=.123456789, size=(3, 2)) + random.seed(self.seed) + actual = random.poisson(lam=.123456789, size=(3, 2)) desired = np.array([[0, 0], [1, 0], [0, 0]]) @@ -1002,10 +1013,10 @@ def test_poisson(self): def test_poisson_exceptions(self): lambig = np.iinfo('l').max lamneg = -1 - assert_raises(ValueError, mt19937.poisson, lamneg) - assert_raises(ValueError, mt19937.poisson, [lamneg] * 10) - assert_raises(ValueError, mt19937.poisson, lambig) - assert_raises(ValueError, mt19937.poisson, [lambig] * 10) + assert_raises(ValueError, random.poisson, lamneg) + assert_raises(ValueError, random.poisson, [lamneg] * 10) + assert_raises(ValueError, random.poisson, lambig) + assert_raises(ValueError, random.poisson, [lambig] * 10) def test_power(self): random.seed(self.seed) @@ -1016,16 +1027,16 @@ def test_power(self): assert_array_almost_equal(actual, desired, decimal=15) def test_rayleigh(self): - mt19937.seed(self.seed) - actual = mt19937.rayleigh(scale=10, size=(3, 2)) + random.seed(self.seed) + actual = random.rayleigh(scale=10, size=(3, 2)) desired = np.array([[13.8882496494248393, 13.383318339044731], [20.95413364294492098, 21.08285015800712614], [11.06066537006854311, 17.35468505778271009]]) assert_array_almost_equal(actual, desired, decimal=14) def test_rayleigh_0(self): - assert_equal(mt19937.rayleigh(scale=0), 0) - assert_raises(ValueError, mt19937.rayleigh, scale=-0.) + assert_equal(random.rayleigh(scale=0), 0) + assert_raises(ValueError, random.rayleigh, scale=-0.) def test_standard_cauchy(self): random.seed(self.seed) @@ -1036,13 +1047,16 @@ def test_standard_cauchy(self): assert_array_almost_equal(actual, desired, decimal=15) def test_standard_exponential(self): - mt19937.seed(self.seed) - actual = mt19937.standard_exponential(size=(3, 2), method='inv') + random.seed(self.seed) + actual = random.standard_exponential(size=(3, 2), method='inv') desired = np.array([[0.96441739162374596, 0.89556604882105506], [2.1953785836319808, 2.22243285392490542], [0.6116915921431676, 1.50592546727413201]]) assert_array_almost_equal(actual, desired, decimal=15) + def test_standard_expoential_type_error(self): + assert_raises(TypeError, random.standard_exponential, dtype=np.int32) + def test_standard_gamma(self): random.seed(self.seed) actual = random.standard_gamma(shape=3, size=(3, 2)) @@ -1051,6 +1065,12 @@ def test_standard_gamma(self): [0.92121813690910, 1.12853552328470]]) assert_array_almost_equal(actual, desired, decimal=14) + def test_standard_gammma_scalar_float(self): + random.seed(self.seed) + actual = random.standard_gamma(3, dtype=np.float32) + desired = 1.3877466 + assert_array_almost_equal(actual, desired, decimal=7) + def test_standard_gamma_float(self): random.seed(self.seed) actual = random.standard_gamma(shape=3, size=(3, 2)) @@ -1059,13 +1079,33 @@ def test_standard_gamma_float(self): [0.9212181, 1.1285355]]) assert_array_almost_equal(actual, desired, decimal=7) + def test_standard_gammma_float_out(self): + actual = np.zeros((3, 2), dtype=np.float32) + random.seed(self.seed) + random.standard_gamma(10.0, out=actual, dtype=np.float32) + desired = np.array([[6.9824033, 7.3731737], + [14.860578, 7.5327270], + [11.767488, 6.2320185]], dtype=np.float32) + assert_array_almost_equal(actual, desired, decimal=7) + + random.seed(self.seed) + random.standard_gamma(10.0, out=actual, size=(3, 2), dtype=np.float32) + assert_array_almost_equal(actual, desired, decimal=7) + def test_standard_gamma_unknown_type(self): assert_raises(TypeError, random.standard_gamma, 1., dtype='int32') + def test_out_size_mismatch(self): + out = np.zeros(10) + assert_raises(ValueError, random.standard_gamma, 10.0, size=20, + out=out) + assert_raises(ValueError, random.standard_gamma, 10.0, size=(10, 1), + out=out) + def test_standard_gamma_0(self): - assert_equal(mt19937.standard_gamma(shape=0), 0) - assert_raises(ValueError, mt19937.standard_gamma, shape=-0.) + assert_equal(random.standard_gamma(shape=0), 0) + assert_raises(ValueError, random.standard_gamma, shape=-0.) def test_standard_normal(self): random.seed(self.seed) @@ -1075,6 +1115,9 @@ def test_standard_normal(self): [0.360102487116356, 0.127832101772367]]) assert_array_almost_equal(actual, desired, decimal=15) + def test_standard_normal_unsupported_type(self): + assert_raises(TypeError, random.standard_normal, dtype=np.int32) + def test_standard_t(self): random.seed(self.seed) actual = random.standard_t(df=10, size=(3, 2)) @@ -1084,17 +1127,17 @@ def test_standard_t(self): assert_array_almost_equal(actual, desired, decimal=15) def test_triangular(self): - mt19937.seed(self.seed) - actual = mt19937.triangular(left=5.12, mode=10.23, right=20.34, - size=(3, 2)) + random.seed(self.seed) + actual = random.triangular(left=5.12, mode=10.23, right=20.34, + size=(3, 2)) desired = np.array([[12.68117178949215784, 12.4129206149193152], [16.20131377335158263, 16.25692138747600524], [11.20400690911820263, 14.4978144835829923]]) assert_array_almost_equal(actual, desired, decimal=14) def test_uniform(self): - mt19937.seed(self.seed) - actual = mt19937.uniform(low=1.23, high=10.54, size=(3, 2)) + random.seed(self.seed) + actual = random.uniform(low=1.23, high=10.54, size=(3, 2)) desired = np.array([[6.99097932346268003, 6.73801597444323974], [9.50364421400426274, 9.53130618907631089], [5.48995325769805476, 8.47493103280052118]]) @@ -1104,7 +1147,7 @@ def test_uniform_range_bounds(self): fmin = np.finfo('float').min fmax = np.finfo('float').max - func = mt19937.uniform + func = random.uniform assert_raises(OverflowError, func, -np.inf, 0) assert_raises(OverflowError, func, 0, np.inf) assert_raises(OverflowError, func, fmin, fmax) @@ -1114,7 +1157,7 @@ def test_uniform_range_bounds(self): # (fmax / 1e17) - fmin is within range, so this should not throw # account for i386 extended precision DBL_MAX / 1e17 + DBL_MAX > # DBL_MAX by increasing fmin a bit - mt19937.uniform(low=np.nextafter(fmin, 1), high=fmax / 1e17) + random.uniform(low=np.nextafter(fmin, 1), high=fmax / 1e17) def test_scalar_exception_propagation(self): # Tests that exceptions are correctly propagated in distributions @@ -1128,7 +1171,7 @@ def __float__(self): raise TypeError throwing_float = np.array(1.0).view(ThrowingFloat) - assert_raises(TypeError, mt19937.uniform, + assert_raises(TypeError, random.uniform, throwing_float, throwing_float) class ThrowingInteger(np.ndarray): @@ -1136,11 +1179,11 @@ def __int__(self): raise TypeError throwing_int = np.array(1).view(ThrowingInteger) - assert_raises(TypeError, mt19937.hypergeometric, throwing_int, 1, 1) + assert_raises(TypeError, random.hypergeometric, throwing_int, 1, 1) def test_vonmises(self): - mt19937.seed(self.seed) - actual = mt19937.vonmises(mu=1.23, kappa=1.54, size=(3, 2)) + random.seed(self.seed) + actual = random.vonmises(mu=1.23, kappa=1.54, size=(3, 2)) desired = np.array([[2.28567572673902042, 2.89163838442285037], [0.38198375564286025, 2.57638023113890746], [1.19153771588353052, 1.83509849681825354]]) @@ -1148,8 +1191,8 @@ def test_vonmises(self): def test_vonmises_small(self): # check infinite loop, gh-4720 - mt19937.seed(self.seed) - r = mt19937.vonmises(mu=0., kappa=1.1e-8, size=10 ** 6) + random.seed(self.seed) + r = random.vonmises(mu=0., kappa=1.1e-8, size=10 ** 6) assert_(np.isfinite(r).all()) def test_wald(self): @@ -1169,13 +1212,13 @@ def test_weibull(self): assert_array_almost_equal(actual, desired, decimal=15) def test_weibull_0(self): - mt19937.seed(self.seed) - assert_equal(mt19937.weibull(a=0, size=12), np.zeros(12)) - assert_raises(ValueError, mt19937.weibull, a=-0.) + random.seed(self.seed) + assert_equal(random.weibull(a=0, size=12), np.zeros(12)) + assert_raises(ValueError, random.weibull, a=-0.) def test_zipf(self): - mt19937.seed(self.seed) - actual = mt19937.zipf(a=1.23, size=(3, 2)) + random.seed(self.seed) + actual = random.zipf(a=1.23, size=(3, 2)) desired = np.array([[66, 29], [1, 1], [3, 13]]) @@ -1220,20 +1263,20 @@ def test_normal(self): actual = normal(loc * 3, scale) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc * 3, bad_scale) - assert_raises(ValueError, mt19937.normal, loc * 3, bad_scale) + assert_raises(ValueError, random.normal, loc * 3, bad_scale) self.set_seed() actual = normal(loc, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc, bad_scale * 3) - assert_raises(ValueError, mt19937.normal, loc, bad_scale * 3) + assert_raises(ValueError, random.normal, loc, bad_scale * 3) def test_beta(self): a = [1] b = [2] bad_a = [-1] bad_b = [-2] - beta = mt19937.beta + beta = random.beta desired = np.array([0.63222080311226, 0.33310522220774, 0.64494078460190]) @@ -1251,7 +1294,7 @@ def test_beta(self): def test_exponential(self): scale = [1] bad_scale = [-1] - exponential = mt19937.exponential + exponential = random.exponential desired = np.array([1.68591211640990, 3.14186859487914, 0.67717375919228]) @@ -1264,7 +1307,7 @@ def test_exponential(self): def test_standard_gamma(self): shape = [1] bad_shape = [-1] - std_gamma = mt19937.standard_gamma + std_gamma = random.standard_gamma desired = np.array([1.68591211640990, 3.14186859487914, 0.67717375919228]) @@ -1279,7 +1322,7 @@ def test_gamma(self): scale = [2] bad_shape = [-1] bad_scale = [-2] - gamma = mt19937.gamma + gamma = random.gamma desired = np.array([3.37182423281980, 6.28373718975827, 1.35434751838456]) @@ -1301,7 +1344,7 @@ def test_f(self): dfden = [2] bad_dfnum = [-1] bad_dfden = [-2] - f = mt19937.f + f = random.f desired = np.array([0.84207044881810, 3.08607209903483, 3.12823105933169]) @@ -1325,14 +1368,14 @@ def test_noncentral_f(self): bad_dfnum = [0] bad_dfden = [-1] bad_nonc = [-2] - nonc_f = mt19937.noncentral_f + nonc_f = random.noncentral_f desired = np.array([3.83710578542563, 8.74926819712029, 0.48892943835401]) self.set_seed() actual = nonc_f(dfnum * 3, dfden, nonc) - mt_nonc_f = mt19937.noncentral_f + mt_nonc_f = random.noncentral_f assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, nonc_f, bad_dfnum * 3, dfden, nonc) assert_raises(ValueError, nonc_f, dfnum * 3, bad_dfden, nonc) @@ -1380,7 +1423,7 @@ def test_noncentral_chisquare(self): self.set_seed() actual = nonc_chi(df * 3, nonc) - mt_nonc_chi2 = mt19937.noncentral_chisquare + mt_nonc_chi2 = random.noncentral_chisquare assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, nonc_chi, bad_df * 3, nonc) assert_raises(ValueError, nonc_chi, df * 3, bad_nonc) @@ -1407,7 +1450,7 @@ def test_standard_t(self): actual = t(df * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, t, bad_df * 3) - assert_raises(ValueError, mt19937.standard_t, bad_df * 3) + assert_raises(ValueError, random.standard_t, bad_df * 3) def test_vonmises(self): mu = [2] @@ -1440,7 +1483,7 @@ def test_pareto(self): actual = pareto(a * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, pareto, bad_a * 3) - assert_raises(ValueError, mt19937.pareto, bad_a * 3) + assert_raises(ValueError, random.pareto, bad_a * 3) def test_weibull(self): a = [1] @@ -1454,7 +1497,7 @@ def test_weibull(self): actual = weibull(a * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, weibull, bad_a * 3) - assert_raises(ValueError, mt19937.weibull, bad_a * 3) + assert_raises(ValueError, random.weibull, bad_a * 3) def test_power(self): a = [1] @@ -1468,7 +1511,7 @@ def test_power(self): actual = power(a * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, power, bad_a * 3) - assert_raises(ValueError, mt19937.power, bad_a * 3) + assert_raises(ValueError, random.power, bad_a * 3) def test_laplace(self): loc = [0] @@ -1526,7 +1569,7 @@ def test_logistic(self): actual = logistic(loc, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, logistic, loc, bad_scale * 3) - assert_equal(mt19937.logistic(1.0, 0.0), 1.0) + assert_equal(random.logistic(1.0, 0.0), 1.0) def test_lognormal(self): mean = [0] @@ -1541,13 +1584,13 @@ def test_lognormal(self): actual = lognormal(mean * 3, sigma) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, lognormal, mean * 3, bad_sigma) - assert_raises(ValueError, mt19937.lognormal, mean * 3, bad_sigma) + assert_raises(ValueError, random.lognormal, mean * 3, bad_sigma) self.set_seed() actual = lognormal(mean, sigma * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, lognormal, mean, bad_sigma * 3) - assert_raises(ValueError, mt19937.lognormal, mean, bad_sigma * 3) + assert_raises(ValueError, random.lognormal, mean, bad_sigma * 3) def test_rayleigh(self): scale = [1] @@ -1577,16 +1620,16 @@ def test_wald(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, wald, bad_mean * 3, scale) assert_raises(ValueError, wald, mean * 3, bad_scale) - assert_raises(ValueError, mt19937.wald, bad_mean * 3, scale) - assert_raises(ValueError, mt19937.wald, mean * 3, bad_scale) + assert_raises(ValueError, random.wald, bad_mean * 3, scale) + assert_raises(ValueError, random.wald, mean * 3, bad_scale) self.set_seed() actual = wald(mean, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, wald, bad_mean, scale * 3) assert_raises(ValueError, wald, mean, bad_scale * 3) - assert_raises(ValueError, mt19937.wald, bad_mean, scale * 3) - assert_raises(ValueError, mt19937.wald, mean, bad_scale * 3) + assert_raises(ValueError, random.wald, bad_mean, scale * 3) + assert_raises(ValueError, random.wald, mean, bad_scale * 3) def test_triangular(self): left = [1] @@ -1823,14 +1866,14 @@ def setup(self): self.tgtShape = (1,) def test_one_arg_funcs(self): - funcs = (mt19937.exponential, mt19937.standard_gamma, - mt19937.chisquare, mt19937.standard_t, - mt19937.pareto, mt19937.weibull, - mt19937.power, mt19937.rayleigh, - mt19937.poisson, mt19937.zipf, - mt19937.geometric, mt19937.logseries) + funcs = (random.exponential, random.standard_gamma, + random.chisquare, random.standard_t, + random.pareto, random.weibull, + random.power, random.rayleigh, + random.poisson, random.zipf, + random.geometric, random.logseries) - probfuncs = (mt19937.geometric, mt19937.logseries) + probfuncs = (random.geometric, random.logseries) for func in funcs: if func in probfuncs: # p < 1.0 @@ -1842,15 +1885,15 @@ def test_one_arg_funcs(self): assert_equal(out.shape, self.tgtShape) def test_two_arg_funcs(self): - funcs = (mt19937.uniform, mt19937.normal, - mt19937.beta, mt19937.gamma, - mt19937.f, mt19937.noncentral_chisquare, - mt19937.vonmises, mt19937.laplace, - mt19937.gumbel, mt19937.logistic, - mt19937.lognormal, mt19937.wald, - mt19937.binomial, mt19937.negative_binomial) + funcs = (random.uniform, random.normal, + random.beta, random.gamma, + random.f, random.noncentral_chisquare, + random.vonmises, random.laplace, + random.gumbel, random.logistic, + random.lognormal, random.wald, + random.binomial, random.negative_binomial) - probfuncs = (mt19937.binomial, mt19937.negative_binomial) + probfuncs = (random.binomial, random.negative_binomial) for func in funcs: if func in probfuncs: # p <= 1 @@ -1871,7 +1914,7 @@ def test_two_arg_funcs(self): def test_randint(self): itype = [np.bool, np.int8, np.uint8, np.int16, np.uint16, np.int32, np.uint32, np.int64, np.uint64] - func = mt19937.randint + func = random.randint high = np.array([1]) low = np.array([0]) @@ -1886,8 +1929,8 @@ def test_randint(self): assert_equal(out.shape, self.tgtShape) def test_three_arg_funcs(self): - funcs = [mt19937.noncentral_f, mt19937.triangular, - mt19937.hypergeometric] + funcs = [random.noncentral_f, random.triangular, + random.hypergeometric] for func in funcs: out = func(self.argOne, self.argTwo, self.argThree) diff --git a/numpy/random/randomgen/tests/test_numpy_mt19937_regressions.py b/numpy/random/randomgen/tests/test_generator_mt19937_regressions.py similarity index 100% rename from numpy/random/randomgen/tests/test_numpy_mt19937_regressions.py rename to numpy/random/randomgen/tests/test_generator_mt19937_regressions.py diff --git a/numpy/random/randomgen/tests/test_smoke.py b/numpy/random/randomgen/tests/test_smoke.py index b00b9efb297d..15f6142a37ff 100644 --- a/numpy/random/randomgen/tests/test_smoke.py +++ b/numpy/random/randomgen/tests/test_smoke.py @@ -237,11 +237,6 @@ def test_seed(self): rg2 = RandomGenerator(self.brng(*self.seed)) rg.random_sample() rg2.random_sample() - if not comp_state(rg.state, rg2.state): - for key in rg.state: - print(key) - print(rg.state[key]) - print(rg2.state[key]) assert_(comp_state(rg.state, rg2.state)) def test_reset_state_gauss(self): From ac66298eef7b005864c99caa28a2174bcf163c05 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 1 Apr 2019 21:00:21 +0100 Subject: [PATCH 231/279] MAINT/DOC: Update import locations Import import locatiosn to reflect numpy paths --- numpy/random/randomgen/dsfmt.pyx | 6 +++--- numpy/random/randomgen/examples/cython/extending.pyx | 4 ++-- .../randomgen/examples/cython/extending_distributions.pyx | 6 +++--- numpy/random/randomgen/generator.pyx | 4 +++- numpy/random/randomgen/mt19937.pyx | 6 +++--- numpy/random/randomgen/pcg32.pyx | 2 +- numpy/random/randomgen/pcg64.pyx | 2 +- numpy/random/randomgen/philox.pyx | 2 +- numpy/random/randomgen/tests/test_against_numpy.py | 2 +- numpy/random/randomgen/threefry.pyx | 2 +- numpy/random/randomgen/threefry32.pyx | 2 +- numpy/random/randomgen/xoroshiro128.pyx | 2 +- numpy/random/randomgen/xorshift1024.pyx | 2 +- numpy/random/randomgen/xoshiro256starstar.pyx | 2 +- numpy/random/randomgen/xoshiro512starstar.pyx | 2 +- 15 files changed, 24 insertions(+), 22 deletions(-) diff --git a/numpy/random/randomgen/dsfmt.pyx b/numpy/random/randomgen/dsfmt.pyx index 129caafff17a..9fa7588f9cad 100644 --- a/numpy/random/randomgen/dsfmt.pyx +++ b/numpy/random/randomgen/dsfmt.pyx @@ -103,8 +103,8 @@ cdef class DSFMT: generators should be initialized with the same seed to ensure that the segments come from the same sequence. - >>> from randomgen.entropy import random_entropy - >>> from randomgen import RandomGenerator, DSFMT + >>> from numpy.random.randomgen.entropy import random_entropy + >>> from numpy.random.randomgen import RandomGenerator, DSFMT >>> seed = random_entropy() >>> rs = [RandomGenerator(DSFMT(seed)) for _ in range(10)] # Advance rs[i] by i jumps @@ -397,7 +397,7 @@ cdef class DSFMT: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator used this instance as the basic RNG """ if self._generator is None: diff --git a/numpy/random/randomgen/examples/cython/extending.pyx b/numpy/random/randomgen/examples/cython/extending.pyx index a8d314bb19a3..b472312b41d8 100644 --- a/numpy/random/randomgen/examples/cython/extending.pyx +++ b/numpy/random/randomgen/examples/cython/extending.pyx @@ -6,8 +6,8 @@ import numpy as np cimport numpy as np cimport cython -from randomgen.common cimport brng_t -from randomgen.xoroshiro128 import Xoroshiro128 +from numpy.random.randomgen.common cimport brng_t +from numpy.random.randomgen import Xoroshiro128 np.import_array() diff --git a/numpy/random/randomgen/examples/cython/extending_distributions.pyx b/numpy/random/randomgen/examples/cython/extending_distributions.pyx index 03f04af041a5..26d749b10c51 100644 --- a/numpy/random/randomgen/examples/cython/extending_distributions.pyx +++ b/numpy/random/randomgen/examples/cython/extending_distributions.pyx @@ -3,9 +3,9 @@ import numpy as np cimport numpy as np cimport cython from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer -from randomgen.common cimport * -from randomgen.distributions cimport random_gauss_zig -from randomgen.xoroshiro128 import Xoroshiro128 +from numpy.random.randomgen.common cimport * +from numpy.random.randomgen.distributions cimport random_gauss_zig +from numpy.random.randomgen import Xoroshiro128 @cython.boundscheck(False) diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index ffd269f9820b..8a5143164e01 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -411,7 +411,9 @@ cdef class RandomGenerator: Examples -------- - >>> rg = np.random.randomgen.RandomGenerator() # need a RandomGenerator object + Need to construct a RandomGenerator object + + >>> rg = np.random.randomgen.RandomGenerator() >>> rg.tomaxint((2,2,2)) array([[[1170048599, 1600360186], # random [ 739731006, 1947757578]], diff --git a/numpy/random/randomgen/mt19937.pyx b/numpy/random/randomgen/mt19937.pyx index f6c76e7ab1bd..235f12be7b15 100644 --- a/numpy/random/randomgen/mt19937.pyx +++ b/numpy/random/randomgen/mt19937.pyx @@ -99,8 +99,8 @@ cdef class MT19937: generators should be initialized with the same seed to ensure that the segments come from the same sequence. - >>> from randomgen.entropy import random_entropy - >>> from randomgen import RandomGenerator, MT19937 + >>> from numpy.random.randomgen.entropy import random_entropy + >>> from numpy.random.randomgen import RandomGenerator, MT19937 >>> seed = random_entropy() >>> rs = [RandomGenerator(MT19937(seed) for _ in range(10)] # Advance rs[i] by i jumps @@ -354,7 +354,7 @@ cdef class MT19937: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator used this instance as the core PRNG """ if self._generator is None: diff --git a/numpy/random/randomgen/pcg32.pyx b/numpy/random/randomgen/pcg32.pyx index b163f3f950cd..b48108a4cc23 100644 --- a/numpy/random/randomgen/pcg32.pyx +++ b/numpy/random/randomgen/pcg32.pyx @@ -377,7 +377,7 @@ cdef class PCG32: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator used this instance as the core PRNG """ if self._generator is None: diff --git a/numpy/random/randomgen/pcg64.pyx b/numpy/random/randomgen/pcg64.pyx index d69535111b27..3572b17ca7a5 100644 --- a/numpy/random/randomgen/pcg64.pyx +++ b/numpy/random/randomgen/pcg64.pyx @@ -431,7 +431,7 @@ cdef class PCG64: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator using this instance as the core RNG """ if self._generator is None: diff --git a/numpy/random/randomgen/philox.pyx b/numpy/random/randomgen/philox.pyx index 05f3b17b4c51..235c76e6b5da 100644 --- a/numpy/random/randomgen/philox.pyx +++ b/numpy/random/randomgen/philox.pyx @@ -472,7 +472,7 @@ cdef class Philox: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator used this instance as the core PRNG """ if self._generator is None: diff --git a/numpy/random/randomgen/tests/test_against_numpy.py b/numpy/random/randomgen/tests/test_against_numpy.py index 14f21aad3a2d..8a9ef2962750 100644 --- a/numpy/random/randomgen/tests/test_against_numpy.py +++ b/numpy/random/randomgen/tests/test_against_numpy.py @@ -6,7 +6,7 @@ import pytest from numpy.random.randomgen import RandomGenerator, MT19937, generator -from numpy.random.randomgen.mtrand import RandomState +from numpy.random import RandomState def compare_0_input(f1, f2): diff --git a/numpy/random/randomgen/threefry.pyx b/numpy/random/randomgen/threefry.pyx index aa4ce622dd08..03d245ea1e60 100644 --- a/numpy/random/randomgen/threefry.pyx +++ b/numpy/random/randomgen/threefry.pyx @@ -463,7 +463,7 @@ cdef class ThreeFry: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator used this instance as the core PRNG """ if self._generator is None: diff --git a/numpy/random/randomgen/threefry32.pyx b/numpy/random/randomgen/threefry32.pyx index 81f3ee93e040..e497926f55cf 100644 --- a/numpy/random/randomgen/threefry32.pyx +++ b/numpy/random/randomgen/threefry32.pyx @@ -459,7 +459,7 @@ cdef class ThreeFry32: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator used this instance as the core PRNG """ if self._generator is None: diff --git a/numpy/random/randomgen/xoroshiro128.pyx b/numpy/random/randomgen/xoroshiro128.pyx index 2ae876ea6be8..be10cb430ba1 100644 --- a/numpy/random/randomgen/xoroshiro128.pyx +++ b/numpy/random/randomgen/xoroshiro128.pyx @@ -349,7 +349,7 @@ cdef class Xoroshiro128: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator used this instance as the basic RNG """ if self._generator is None: diff --git a/numpy/random/randomgen/xorshift1024.pyx b/numpy/random/randomgen/xorshift1024.pyx index 28b80cc9a96a..bff569990871 100644 --- a/numpy/random/randomgen/xorshift1024.pyx +++ b/numpy/random/randomgen/xorshift1024.pyx @@ -357,7 +357,7 @@ cdef class Xorshift1024: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator used this instance as the core PRNG """ if self._generator is None: diff --git a/numpy/random/randomgen/xoshiro256starstar.pyx b/numpy/random/randomgen/xoshiro256starstar.pyx index d45540aa9a23..175c6e7e6896 100644 --- a/numpy/random/randomgen/xoshiro256starstar.pyx +++ b/numpy/random/randomgen/xoshiro256starstar.pyx @@ -354,7 +354,7 @@ cdef class Xoshiro256StarStar: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator used this instance as the basic RNG """ if self._generator is None: diff --git a/numpy/random/randomgen/xoshiro512starstar.pyx b/numpy/random/randomgen/xoshiro512starstar.pyx index 0a6b104fdad2..96d62ea68797 100644 --- a/numpy/random/randomgen/xoshiro512starstar.pyx +++ b/numpy/random/randomgen/xoshiro512starstar.pyx @@ -348,7 +348,7 @@ cdef class Xoshiro512StarStar: Returns ------- - gen : randomgen.generator.RandomGenerator + gen : numpy.random.randomgen.generator.RandomGenerator Random generator used this instance as the basic RNG """ if self._generator is None: From 67bcddb88fe84ee2044f2b9f96f3b81aac17aa0f Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 1 Apr 2019 23:22:48 +0100 Subject: [PATCH 232/279] TST: Fix test tolerance Correct tolerance on float32 tests Remove set_printoptions --- numpy/random/randomgen/bounded_integers.pxd.in | 2 -- numpy/random/randomgen/bounded_integers.pyx.in | 1 - numpy/random/randomgen/common.pxd | 2 -- numpy/random/randomgen/setup.py | 2 -- .../randomgen/tests/test_generator_mt19937.py | 17 +++++++---------- .../tests/test_generator_mt19937_regressions.py | 2 -- 6 files changed, 7 insertions(+), 19 deletions(-) diff --git a/numpy/random/randomgen/bounded_integers.pxd.in b/numpy/random/randomgen/bounded_integers.pxd.in index 50df0c7897cf..4ab389fd923e 100644 --- a/numpy/random/randomgen/bounded_integers.pxd.in +++ b/numpy/random/randomgen/bounded_integers.pxd.in @@ -1,5 +1,3 @@ -from __future__ import absolute_import - from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t) import numpy as np diff --git a/numpy/random/randomgen/bounded_integers.pyx.in b/numpy/random/randomgen/bounded_integers.pyx.in index 56d558b14175..03068a8fd088 100644 --- a/numpy/random/randomgen/bounded_integers.pyx.in +++ b/numpy/random/randomgen/bounded_integers.pyx.in @@ -1,6 +1,5 @@ #!python #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True -from __future__ import absolute_import import numpy as np cimport numpy as np diff --git a/numpy/random/randomgen/common.pxd b/numpy/random/randomgen/common.pxd index 824225cebf95..491b23d3d873 100644 --- a/numpy/random/randomgen/common.pxd +++ b/numpy/random/randomgen/common.pxd @@ -1,7 +1,5 @@ #cython: language_level=3 -from __future__ import absolute_import - from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, intptr_t, uintptr_t) diff --git a/numpy/random/randomgen/setup.py b/numpy/random/randomgen/setup.py index 94680e73e617..5b7be45599c8 100644 --- a/numpy/random/randomgen/setup.py +++ b/numpy/random/randomgen/setup.py @@ -1,5 +1,3 @@ -from __future__ import division, print_function - from os.path import join import sys import os diff --git a/numpy/random/randomgen/tests/test_generator_mt19937.py b/numpy/random/randomgen/tests/test_generator_mt19937.py index 3c999ab73e2b..cad3ef4d66cd 100644 --- a/numpy/random/randomgen/tests/test_generator_mt19937.py +++ b/numpy/random/randomgen/tests/test_generator_mt19937.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import sys import warnings @@ -892,7 +890,6 @@ def test_multivariate_normal(self): cov = [[1, 0], [0, 1]] size = (3, 2) actual = random.multivariate_normal(mean, cov, size) - np.set_printoptions(precision=20) desired = np.array([[[-3.34929721161096100, 9.891061435770858], [-0.12250896439641100, 9.295898449738300]], [[0.48355927611635563, 10.127832101772366], @@ -1069,7 +1066,7 @@ def test_standard_gammma_scalar_float(self): random.seed(self.seed) actual = random.standard_gamma(3, dtype=np.float32) desired = 1.3877466 - assert_array_almost_equal(actual, desired, decimal=7) + assert_array_almost_equal(actual, desired, decimal=6) def test_standard_gamma_float(self): random.seed(self.seed) @@ -1077,20 +1074,20 @@ def test_standard_gamma_float(self): desired = np.array([[2.2848352, 3.2989952], [11.124923, 2.1678442], [0.9212181, 1.1285355]]) - assert_array_almost_equal(actual, desired, decimal=7) + assert_array_almost_equal(actual, desired, decimal=5) def test_standard_gammma_float_out(self): actual = np.zeros((3, 2), dtype=np.float32) random.seed(self.seed) random.standard_gamma(10.0, out=actual, dtype=np.float32) - desired = np.array([[6.9824033, 7.3731737], - [14.860578, 7.5327270], - [11.767488, 6.2320185]], dtype=np.float32) - assert_array_almost_equal(actual, desired, decimal=7) + desired = np.array([[6.9824033, 7.3731737], + [14.860578, 7.5327270], + [11.767487, 6.2320185]], dtype=np.float32) + assert_array_almost_equal(actual, desired, decimal=5) random.seed(self.seed) random.standard_gamma(10.0, out=actual, size=(3, 2), dtype=np.float32) - assert_array_almost_equal(actual, desired, decimal=7) + assert_array_almost_equal(actual, desired, decimal=5) def test_standard_gamma_unknown_type(self): assert_raises(TypeError, random.standard_gamma, 1., diff --git a/numpy/random/randomgen/tests/test_generator_mt19937_regressions.py b/numpy/random/randomgen/tests/test_generator_mt19937_regressions.py index 13569e950606..75064720fb97 100644 --- a/numpy/random/randomgen/tests/test_generator_mt19937_regressions.py +++ b/numpy/random/randomgen/tests/test_generator_mt19937_regressions.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import sys from numpy.testing import (assert_, assert_array_equal) from numpy.compat import long From 783e88f373e8465bbcb2fc1890fc7ff44080dd5d Mon Sep 17 00:00:00 2001 From: adeak Date: Tue, 2 Apr 2019 07:03:19 +0200 Subject: [PATCH 233/279] BUG/MAINT: fix reference count error on invalid input to ndarray.flat (#13176) Fixes gh-13165, where a double decref could occur on the error path. Folded into this commit is some related control flow cleanup requested at review time. --- numpy/core/src/multiarray/iterators.c | 50 +++++++++++++-------------- numpy/core/tests/test_multiarray.py | 16 +++++++++ 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/numpy/core/src/multiarray/iterators.c b/numpy/core/src/multiarray/iterators.c index a3bc8e742fac..62a0575389c1 100644 --- a/numpy/core/src/multiarray/iterators.c +++ b/numpy/core/src/multiarray/iterators.c @@ -539,6 +539,7 @@ iter_subscript(PyArrayIterObject *self, PyObject *ind) char *dptr; int size; PyObject *obj = NULL; + PyObject *new; PyArray_CopySwapFunc *copyswap; if (ind == Py_Ellipsis) { @@ -640,35 +641,34 @@ iter_subscript(PyArrayIterObject *self, PyObject *ind) obj = ind; } - if (PyArray_Check(obj)) { - /* Check for Boolean object */ - if (PyArray_TYPE((PyArrayObject *)obj) == NPY_BOOL) { - ret = iter_subscript_Bool(self, (PyArrayObject *)obj); - Py_DECREF(indtype); - } - /* Check for integer array */ - else if (PyArray_ISINTEGER((PyArrayObject *)obj)) { - PyObject *new; - new = PyArray_FromAny(obj, indtype, 0, 0, - NPY_ARRAY_FORCECAST | NPY_ARRAY_ALIGNED, NULL); - if (new == NULL) { - goto fail; - } - Py_DECREF(obj); - obj = new; - new = iter_subscript_int(self, (PyArrayObject *)obj); - Py_DECREF(obj); - return new; - } - else { - goto fail; - } + /* Any remaining valid input is an array or has been turned into one */ + if (!PyArray_Check(obj)) { + goto fail; + } + + /* Check for Boolean array */ + if (PyArray_TYPE((PyArrayObject *)obj) == NPY_BOOL) { + ret = iter_subscript_Bool(self, (PyArrayObject *)obj); + Py_DECREF(indtype); Py_DECREF(obj); return (PyObject *)ret; } - else { - Py_DECREF(indtype); + + /* Only integer arrays left */ + if (!PyArray_ISINTEGER((PyArrayObject *)obj)) { + goto fail; + } + + Py_INCREF(indtype); + new = PyArray_FromAny(obj, indtype, 0, 0, + NPY_ARRAY_FORCECAST | NPY_ARRAY_ALIGNED, NULL); + if (new == NULL) { + goto fail; } + Py_DECREF(indtype); + Py_DECREF(obj); + Py_SETREF(new, iter_subscript_int(self, (PyArrayObject *)new)); + return new; fail: diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index ae2fd3cf42ef..c45029599bd4 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -4893,6 +4893,22 @@ def test___array__(self): assert_(e.flags.writebackifcopy is False) assert_(f.flags.writebackifcopy is False) + @pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts") + def test_refcount(self): + # includes regression test for reference count error gh-13165 + inds = [np.intp(0), np.array([True]*self.a.size), np.array([0]), None] + indtype = np.dtype(np.intp) + rc_indtype = sys.getrefcount(indtype) + for ind in inds: + rc_ind = sys.getrefcount(ind) + for _ in range(100): + try: + self.a.flat[ind] + except IndexError: + pass + assert_(abs(sys.getrefcount(ind) - rc_ind) < 50) + assert_(abs(sys.getrefcount(indtype) - rc_indtype) < 50) + class TestResize(object): def test_basic(self): From e8bd8644f3dad183b878fe6d4c1b7ec9ee5adf49 Mon Sep 17 00:00:00 2001 From: Kriti Singh Date: Tue, 2 Apr 2019 10:36:44 +0530 Subject: [PATCH 234/279] DOC: Correctly document the minimum required Sphinx version (#13231) --- doc/source/docs/howto_build_docs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/docs/howto_build_docs.rst b/doc/source/docs/howto_build_docs.rst index cdf490c373f0..98d1b88ba5ef 100644 --- a/doc/source/docs/howto_build_docs.rst +++ b/doc/source/docs/howto_build_docs.rst @@ -5,7 +5,7 @@ Building the NumPy API and reference docs ========================================= We currently use Sphinx_ for generating the API and reference -documentation for NumPy. You will need Sphinx 1.0.1 or newer. +documentation for NumPy. You will need Sphinx 1.8.3 or newer. If you only want to get the documentation, note that pre-built versions can be found at From 68f2480dea178c03da285fab89def6f803ed4031 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 2 Apr 2019 08:16:32 +0100 Subject: [PATCH 235/279] DOC: Improve mtrand docstrings Remove excess underscores Fix lognormal docstring Standardize whitesapce --- numpy/random/mtrand/mtrand.pyx | 45 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx index f49299f5587e..24826d52d14d 100644 --- a/numpy/random/mtrand/mtrand.pyx +++ b/numpy/random/mtrand/mtrand.pyx @@ -866,10 +866,9 @@ cdef class RandomState: """ tomaxint(size=None) - Random integers between 0 and ``sys.maxint``, inclusive. - Return a sample of uniformly distributed random integers in the interval - [0, ``sys.maxint``]. + [0, ``np.iinfo(np.int).max``]. The np.int type translates to the C long + integer type and its precision is platform dependent. Parameters ---------- @@ -891,16 +890,15 @@ cdef class RandomState: Examples -------- - >>> RS = np.random.mtrand.RandomState() # need a RandomState object - >>> RS.tomaxint((2,2,2)) - array([[[1170048599, 1600360186], + >>> rs = np.random.RandomState() # need a RandomState object + >>> rs.tomaxint((2,2,2)) + array([[[1170048599, 1600360186], # random [ 739731006, 1947757578]], [[1871712945, 752307660], [1601631370, 1479324245]]]) - >>> import sys - >>> sys.maxint + >>> np.iinfo(np.int).max 2147483647 - >>> RS.tomaxint((2,2,2)) < sys.maxint + >>> rs.tomaxint((2,2,2)) < np.iinfo(np.int).max array([[[ True, True], [ True, True]], [[ True, True], @@ -1056,12 +1054,12 @@ cdef class RandomState: entries in a. Returns - -------- + ------- samples : single item or ndarray The generated random samples Raises - ------- + ------ ValueError If a is an int and less than zero, if a or p are not 1-dimensional, if a is an array-like of size 0, if p is not a vector of @@ -1070,11 +1068,11 @@ cdef class RandomState: size See Also - --------- + -------- randint, shuffle, permutation Examples - --------- + -------- Generate a uniform random sample from np.arange(5) of size 3: >>> np.random.choice(5, 3) @@ -1421,6 +1419,7 @@ cdef class RandomState: >>> 3 + 2.5 * np.random.randn(2, 4) array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], # random [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) # random + """ if len(args) == 0: return self.standard_normal() @@ -1436,8 +1435,8 @@ cdef class RandomState: Return random integers of type np.int from the "discrete uniform" distribution in the closed interval [`low`, `high`]. If `high` is None (the default), then results are from [1, `low`]. The np.int - type translates to the C long type used by Python 2 for "short" - integers and its precision is platform dependent. + type translates to the C long integer type and its precision + is platform dependent. This function has been deprecated. Use randint instead. @@ -1708,7 +1707,7 @@ cdef class RandomState: .. math:: f(x; a,b) = \\frac{1}{B(\\alpha, \\beta)} x^{\\alpha - 1} (1 - x)^{\\beta - 1}, - where the normalisation, B, is the beta function, + where the normalization, B, is the beta function, .. math:: B(\\alpha, \\beta) = \\int_0^1 t^{\\alpha - 1} (1 - t)^{\\beta - 1} dt. @@ -2329,7 +2328,7 @@ cdef class RandomState: Draw samples from a noncentral chi-square distribution. - The noncentral :math:`\\chi^2` distribution is a generalisation of + The noncentral :math:`\\chi^2` distribution is a generalization of the :math:`\\chi^2` distribution. Parameters @@ -2359,7 +2358,7 @@ cdef class RandomState: .. math:: P(x;df,nonc) = \\sum^{\\infty}_{i=0} \\frac{e^{-nonc/2}(nonc/2)^{i}}{i!} - \\P_{Y_{df+2i}}(x), + P_{Y_{df+2i}}(x), where :math:`Y_{q}` is the Chi-square with q degrees of freedom. @@ -2395,6 +2394,7 @@ cdef class RandomState: >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), ... bins=200, density=True) >>> plt.show() + """ cdef ndarray odf, ononc cdef double fdf, fnonc @@ -2921,7 +2921,7 @@ cdef class RandomState: Parameters ---------- a : float or array_like of floats - Parameter of the distribution. Should be greater than zero. + Parameter of the distribution. Must be non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -3434,7 +3434,7 @@ cdef class RandomState: >>> # values, drawn from a normal distribution. >>> b = [] >>> for i in range(1000): - ... a = 10. + np.random.random(100) + ... a = 10. + np.random.standard_normal(100) ... b.append(np.product(a)) >>> b = np.array(b) / np.min(b) # scale values to be positive @@ -4052,7 +4052,7 @@ cdef class RandomState: Parameters ---------- a : float or array_like of floats - Distribution parameter. Should be greater than 1. + Distribution parameter. Must be greater than 1. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -4590,7 +4590,7 @@ cdef class RandomState: Draw samples from a multinomial distribution. - The multinomial distribution is a multivariate generalisation of the + The multinomial distribution is a multivariate generalization of the binomial distribution. Take an experiment with one of ``p`` possible outcomes. An example of such an experiment is throwing a dice, where the outcome can be 1 through 6. Each sample drawn from the @@ -4731,7 +4731,6 @@ cdef class RandomState: Notes ----- - The Dirichlet distribution is a distribution over vectors :math:`x` that fulfil the conditions :math:`x_i>0` and :math:`\\sum_{i=1}^k x_i = 1`. From 28211265d903df95fd4a1c41798061329351fa96 Mon Sep 17 00:00:00 2001 From: Andras Deak Date: Tue, 2 Apr 2019 10:39:51 +0200 Subject: [PATCH 236/279] MAINT: replace SETREF with assignment to ret array in ndarray.flat --- numpy/core/src/multiarray/iterators.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/numpy/core/src/multiarray/iterators.c b/numpy/core/src/multiarray/iterators.c index 62a0575389c1..9fcdc91b2f61 100644 --- a/numpy/core/src/multiarray/iterators.c +++ b/numpy/core/src/multiarray/iterators.c @@ -667,8 +667,9 @@ iter_subscript(PyArrayIterObject *self, PyObject *ind) } Py_DECREF(indtype); Py_DECREF(obj); - Py_SETREF(new, iter_subscript_int(self, (PyArrayObject *)new)); - return new; + ret = (PyArrayObject *)iter_subscript_int(self, (PyArrayObject *)new); + Py_DECREF(new); + return (PyObject *)ret; fail: From bf2feeee642cee34688e93c5301830199083d6eb Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 2 Apr 2019 10:05:32 +0100 Subject: [PATCH 237/279] MAINT: Remove complex_normal Remove complex normal Remove future imports --- numpy/random/randomgen/common.pxd | 11 - numpy/random/randomgen/dsfmt.pyx | 1 - numpy/random/randomgen/generator.pyx | 201 ++---------------- numpy/random/randomgen/mt19937.pyx | 1 - numpy/random/randomgen/mtrand.pyx | 50 ++--- numpy/random/randomgen/pcg32.pyx | 1 - numpy/random/randomgen/pcg64.pyx | 1 - numpy/random/randomgen/philox.pyx | 1 - numpy/random/randomgen/tests/test_smoke.py | 64 ------ numpy/random/randomgen/threefry.pyx | 1 - numpy/random/randomgen/threefry32.pyx | 1 - numpy/random/randomgen/xoroshiro128.pyx | 1 - numpy/random/randomgen/xorshift1024.pyx | 1 - numpy/random/randomgen/xoshiro256starstar.pyx | 1 - numpy/random/randomgen/xoshiro512starstar.pyx | 1 - 15 files changed, 43 insertions(+), 294 deletions(-) diff --git a/numpy/random/randomgen/common.pxd b/numpy/random/randomgen/common.pxd index 491b23d3d873..37182a29d6bf 100644 --- a/numpy/random/randomgen/common.pxd +++ b/numpy/random/randomgen/common.pxd @@ -98,14 +98,3 @@ cdef object discrete_broadcast_iii(void *func, void *state, object size, object np.ndarray a_arr, object a_name, constraint_type a_constraint, np.ndarray b_arr, object b_name, constraint_type b_constraint, np.ndarray c_arr, object c_name, constraint_type c_constraint) - -cdef inline void compute_complex(double *rv_r, double *rv_i, double loc_r, - double loc_i, double var_r, double var_i, double rho) nogil: - cdef double scale_c, scale_i, scale_r - - scale_c = sqrt(1 - rho * rho) - scale_r = sqrt(var_r) - scale_i = sqrt(var_i) - - rv_i[0] = loc_i + scale_i * (rho * rv_r[0] + scale_c * rv_i[0]) - rv_r[0] = loc_r + scale_r * rv_r[0] diff --git a/numpy/random/randomgen/dsfmt.pyx b/numpy/random/randomgen/dsfmt.pyx index 9fa7588f9cad..9a7199e856ec 100644 --- a/numpy/random/randomgen/dsfmt.pyx +++ b/numpy/random/randomgen/dsfmt.pyx @@ -10,7 +10,6 @@ except ImportError: import numpy as np cimport numpy as np -from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index 8a5143164e01..0ca02e9127fe 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -4,8 +4,7 @@ import operator import warnings from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer -from cpython cimport (Py_INCREF, PyComplex_RealAsDouble, - PyComplex_ImagAsDouble, PyComplex_FromDoubles, PyFloat_AsDouble) +from cpython cimport (Py_INCREF, PyFloat_AsDouble) from libc cimport string from libc.stdlib cimport malloc, free cimport numpy as np @@ -386,10 +385,9 @@ cdef class RandomGenerator: """ tomaxint(size=None) - Random integers between 0 and ``sys.maxint``, inclusive. - Return a sample of uniformly distributed random integers in the interval - [0, ``sys.maxint``]. + [0, ``np.iinfo(np.int).max``]. The np.int type translates to the C long + integer type and its precision is platform dependent. Parameters ---------- @@ -411,18 +409,15 @@ cdef class RandomGenerator: Examples -------- - Need to construct a RandomGenerator object - - >>> rg = np.random.randomgen.RandomGenerator() + >>> rg = np.random.randomgen.RandomGenerator() # need a RandomGenerator object >>> rg.tomaxint((2,2,2)) array([[[1170048599, 1600360186], # random [ 739731006, 1947757578]], [[1871712945, 752307660], [1601631370, 1479324245]]]) - >>> import sys - >>> sys.maxint + >>> np.iinfo(np.int).max 2147483647 - >>> rg.tomaxint((2,2,2)) < sys.maxint + >>> rg.tomaxint((2,2,2)) < np.iinfo(np.int).max array([[[ True, True], [ True, True]], [[ True, True], @@ -1006,9 +1001,11 @@ cdef class RandomGenerator: Random integers of type np.int between `low` and `high`, inclusive. - Return random integers of type np.int64 from the "discrete uniform" + Return random integers of type np.int from the "discrete uniform" distribution in the closed interval [`low`, `high`]. If `high` is - None (the default), then results are from [1, `low`]. + None (the default), then results are from [1, `low`]. The np.int + type translates to the C long integer type and its precision + is platform dependent. This function has been deprecated. Use randint instead. @@ -1053,7 +1050,7 @@ cdef class RandomGenerator: 4 # random >>> type(np.random.random_integers(5)) - >>> np.random.random_integers(5, size=(3, 2)) + >>> np.random.random_integers(5, size=(3,2)) array([[5, 4], # random [3, 3], [4, 5]]) @@ -1267,168 +1264,6 @@ cdef class RandomGenerator: 0.0, '', CONS_NONE, None) - def complex_normal(self, loc=0.0, gamma=1.0, relation=0.0, size=None): - """ - complex_normal(loc=0.0, gamma=1.0, relation=0.0, size=None) - - Draw random samples from a complex normal (Gaussian) distribution. - - Parameters - ---------- - loc : complex or array_like of complex - Mean of the distribution. - gamma : float, complex or array_like of float or complex - Variance of the distribution - relation : float, complex or array_like of float or complex - Relation between the two component normals - size : int or tuple of ints, optional - Output shape. If the given shape is, e.g., ``(m, n, k)``, then - ``m * n * k`` samples are drawn. If size is ``None`` (default), - a single value is returned if ``loc``, ``gamma`` and ``relation`` - are all scalars. Otherwise, - ``np.broadcast(loc, gamma, relation).size`` samples are drawn. - - Returns - ------- - out : ndarray or scalar - Drawn samples from the parameterized complex normal distribution. - - See Also - -------- - numpy.random.normal : random values from a real-valued normal - distribution - - Notes - ----- - **EXPERIMENTAL** Not part of official NumPy RandomState, may change until - formal release on PyPi. - - Complex normals are generated from a bivariate normal where the - variance of the real component is 0.5 Re(gamma + relation), the - variance of the imaginary component is 0.5 Re(gamma - relation), and - the covariance between the two is 0.5 Im(relation). The implied - covariance matrix must be positive semi-definite and so both variances - must be zero and the covariance must be weakly smaller than the - product of the two standard deviations. - - References - ---------- - .. [1] Wikipedia, "Complex normal distribution", - https://en.wikipedia.org/wiki/Complex_normal_distribution - .. [2] Leigh J. Halliwell, "Complex Random Variables" in "Casualty - Actuarial Society E-Forum", Fall 2015. - - Examples - -------- - Draw samples from the distribution: - - >>> s = np.random.complex_normal(size=1000) - - """ - cdef np.ndarray ogamma, orelation, oloc, randoms, v_real, v_imag, rho - cdef double *randoms_data - cdef double fgamma_r, fgamma_i, frelation_r, frelation_i, frho, fvar_r, fvar_i, \ - floc_r, floc_i, f_real, f_imag, i_r_scale, r_scale, i_scale, f_rho - cdef np.npy_intp i, j, n, n2 - cdef np.broadcast it - - oloc = np.PyArray_FROM_OTF(loc, np.NPY_COMPLEX128, np.NPY_ALIGNED) - ogamma = np.PyArray_FROM_OTF(gamma, np.NPY_COMPLEX128, np.NPY_ALIGNED) - orelation = np.PyArray_FROM_OTF(relation, np.NPY_COMPLEX128, np.NPY_ALIGNED) - - if np.PyArray_NDIM(ogamma) == np.PyArray_NDIM(orelation) == np.PyArray_NDIM(oloc) == 0: - floc_r = PyComplex_RealAsDouble(loc) - floc_i = PyComplex_ImagAsDouble(loc) - fgamma_r = PyComplex_RealAsDouble(gamma) - fgamma_i = PyComplex_ImagAsDouble(gamma) - frelation_r = PyComplex_RealAsDouble(relation) - frelation_i = 0.5 * PyComplex_ImagAsDouble(relation) - - fvar_r = 0.5 * (fgamma_r + frelation_r) - fvar_i = 0.5 * (fgamma_r - frelation_r) - if fgamma_i != 0: - raise ValueError('Im(gamma) != 0') - if fvar_i < 0: - raise ValueError('Re(gamma - relation) < 0') - if fvar_r < 0: - raise ValueError('Re(gamma + relation) < 0') - f_rho = 0.0 - if fvar_i > 0 and fvar_r > 0: - f_rho = frelation_i / sqrt(fvar_i * fvar_r) - if f_rho > 1.0 or f_rho < -1.0: - raise ValueError('Im(relation) ** 2 > Re(gamma ** 2 - relation** 2)') - - if size is None: - f_real = random_gauss_zig(self._brng) - f_imag = random_gauss_zig(self._brng) - - compute_complex(&f_real, &f_imag, floc_r, floc_i, fvar_r, fvar_i, f_rho) - return PyComplex_FromDoubles(f_real, f_imag) - - randoms = np.empty(size, np.complex128) - randoms_data = np.PyArray_DATA(randoms) - n = np.PyArray_SIZE(randoms) - - i_r_scale = sqrt(1 - f_rho * f_rho) - r_scale = sqrt(fvar_r) - i_scale = sqrt(fvar_i) - j = 0 - with self.lock, nogil: - for i in range(n): - f_real = random_gauss_zig(self._brng) - f_imag = random_gauss_zig(self._brng) - randoms_data[j+1] = floc_i + i_scale * (f_rho * f_real + i_r_scale * f_imag) - randoms_data[j] = floc_r + r_scale * f_real - j += 2 - - return randoms - - gpc = ogamma + orelation - gmc = ogamma - orelation - v_real = (0.5 * np.real(gpc)) - if np.any(np.less(v_real, 0)): - raise ValueError('Re(gamma + relation) < 0') - v_imag = (0.5 * np.real(gmc)) - if np.any(np.less(v_imag, 0)): - raise ValueError('Re(gamma - relation) < 0') - if np.any(np.not_equal(np.imag(ogamma), 0)): - raise ValueError('Im(gamma) != 0') - - cov = 0.5 * np.imag(orelation) - rho = np.zeros_like(cov) - idx = (v_real.flat > 0) & (v_imag.flat > 0) - rho.flat[idx] = cov.flat[idx] / np.sqrt(v_real.flat[idx] * v_imag.flat[idx]) - if np.any(cov.flat[~idx] != 0) or np.any(np.abs(rho) > 1): - raise ValueError('Im(relation) ** 2 > Re(gamma ** 2 - relation ** 2)') - - if size is not None: - randoms = np.empty(size, np.complex128) - else: - it = np.PyArray_MultiIterNew4(oloc, v_real, v_imag, rho) - randoms = np.empty(it.shape, np.complex128) - - randoms_data = np.PyArray_DATA(randoms) - n = np.PyArray_SIZE(randoms) - - it = np.PyArray_MultiIterNew5(randoms, oloc, v_real, v_imag, rho) - with self.lock, nogil: - n2 = 2 * n # Avoid compiler noise for cast - for i in range(n2): - randoms_data[i] = random_gauss_zig(self._brng) - with nogil: - j = 0 - for i in range(n): - floc_r= (np.PyArray_MultiIter_DATA(it, 1))[0] - floc_i= (np.PyArray_MultiIter_DATA(it, 1))[1] - fvar_r = (np.PyArray_MultiIter_DATA(it, 2))[0] - fvar_i = (np.PyArray_MultiIter_DATA(it, 3))[0] - f_rho = (np.PyArray_MultiIter_DATA(it, 4))[0] - compute_complex(&randoms_data[j], &randoms_data[j+1], floc_r, floc_i, fvar_r, fvar_i, f_rho) - j += 2 - np.PyArray_MultiIter_NEXT(it) - - return randoms - def standard_gamma(self, shape, size=None, dtype=np.float64, out=None): """ standard_gamma(shape, size=None, dtype='d', out=None) @@ -1838,7 +1673,7 @@ cdef class RandomGenerator: Draw samples from a noncentral chi-square distribution. - The noncentral :math:`\\chi^2` distribution is a generalisation of + The noncentral :math:`\\chi^2` distribution is a generalization of the :math:`\\chi^2` distribution. Parameters @@ -2723,7 +2558,7 @@ cdef class RandomGenerator: >>> def logist(x, loc, scale): ... return np.exp((loc-x)/scale)/(scale*(1+np.exp((loc-x)/scale))**2) >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\ - ... logist(bins, loc, scale).max()) + ... logist(bins, loc, scale).max()) >>> plt.show() """ @@ -2821,7 +2656,7 @@ cdef class RandomGenerator: >>> # values, drawn from a normal distribution. >>> b = [] >>> for i in range(1000): - ... a = 10. + np.random.randn(100) + ... a = 10. + np.random.standard_normal(100) ... b.append(np.product(a)) >>> b = np.array(b) / np.min(b) # scale values to be positive @@ -3161,6 +2996,7 @@ cdef class RandomGenerator: >>> sum(np.random.binomial(9, 0.1, 20000) == 0)/20000. # answer = 0.38885, or 38%. + """ # Uses a custom implementation since self._binomial is required @@ -3285,7 +3121,7 @@ cdef class RandomGenerator: for each successive well, that is what is the probability of a single success after drilling 5 wells, after 6 wells, etc.? - >>> s = np.random.negative_binomial(1, 0.9, 100000) + >>> s = np.random.negative_binomial(1, 0.1, 100000) >>> for i in range(1, 11): # doctest: +SKIP ... probability = sum(s>> rs = np.random.RandomState() # need a RandomGenerator object + >>> rs = np.random.RandomState() # need a RandomState object >>> rs.tomaxint((2,2,2)) array([[[1170048599, 1600360186], # random [ 739731006, 1947757578]], [[1871712945, 752307660], [1601631370, 1479324245]]]) - >>> import sys - >>> sys.maxint + >>> np.iinfo(np.int).max 2147483647 - >>> rs.tomaxint((2,2,2)) < sys.maxint + >>> rs.tomaxint((2,2,2)) < np.iinfo(np.int).max array([[[ True, True], [ True, True]], [[ True, True], @@ -531,7 +530,7 @@ cdef class RandomState: Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a single value is returned. - dtype : {str, dtype}, optional + dtype : dtype, optional Desired dtype of the result. All dtypes are determined by their name, i.e., 'int64', 'int', etc, so byteorder is not available and a specific precision may have different C types depending @@ -557,7 +556,7 @@ cdef class RandomState: >>> np.random.randint(2, size=10) array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) # random >>> np.random.randint(1, size=10) - array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) # random + array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) Generate a 2 x 4 array of ints between 0 and 4, inclusive: @@ -666,12 +665,12 @@ cdef class RandomState: entries in a. Returns - -------- + ------- samples : single item or ndarray The generated random samples Raises - ------- + ------ ValueError If a is an int and less than zero, if a or p are not 1-dimensional, if a is an array-like of size 0, if p is not a vector of @@ -680,11 +679,11 @@ cdef class RandomState: size See Also - --------- + -------- randint, shuffle, permutation Examples - --------- + -------- Generate a uniform random sample from np.arange(5) of size 3: >>> np.random.choice(5, 3) @@ -1034,6 +1033,7 @@ cdef class RandomState: >>> 3 + 2.5 * np.random.randn(2, 4) array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], # random [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) # random + """ if len(args) == 0: return self.standard_normal() @@ -1049,8 +1049,8 @@ cdef class RandomState: Return random integers of type np.int from the "discrete uniform" distribution in the closed interval [`low`, `high`]. If `high` is None (the default), then results are from [1, `low`]. The np.int - type translates to the C long type used by Python 2 for "short" - integers and its precision is platform dependent. + type translates to the C long integer type and its precision + is platform dependent. This function has been deprecated. Use randint instead. @@ -1690,7 +1690,7 @@ cdef class RandomState: Draw samples from a noncentral chi-square distribution. - The noncentral :math:`\\chi^2` distribution is a generalisation of + The noncentral :math:`\\chi^2` distribution is a generalization of the :math:`\\chi^2` distribution. Parameters @@ -1756,6 +1756,7 @@ cdef class RandomState: >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), ... bins=200, density=True) >>> plt.show() + """ return cont(&legacy_noncentral_chisquare, self._aug_state, size, self.lock, 2, df, 'df', CONS_POSITIVE, @@ -2212,7 +2213,7 @@ cdef class RandomState: Parameters ---------- a : float or array_like of floats - Parameter of the distribution. Should be greater than zero. + Parameter of the distribution. Must be non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2573,8 +2574,8 @@ cdef class RandomState: >>> def logist(x, loc, scale): ... return np.exp((loc-x)/scale)/(scale*(1+np.exp((loc-x)/scale))**2) - >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\\ - ... logist(bins, loc, scale).max()) + >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\ + ... logist(bins, loc, scale).max()) >>> plt.show() """ @@ -2672,7 +2673,7 @@ cdef class RandomState: >>> # values, drawn from a normal distribution. >>> b = [] >>> for i in range(1000): - ... a = 10. + np.random.random(100) + ... a = 10. + np.random.standard_normal(100) ... b.append(np.product(a)) >>> b = np.array(b) / np.min(b) # scale values to be positive @@ -3236,7 +3237,7 @@ cdef class RandomState: Parameters ---------- a : float or array_like of floats - Distribution parameter. Should be greater than 1. + Distribution parameter. Must be greater than 1. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -3721,7 +3722,7 @@ cdef class RandomState: Draw samples from a multinomial distribution. - The multinomial distribution is a multivariate generalisation of the + The multinomial distribution is a multivariate generalization of the binomial distribution. Take an experiment with one of ``p`` possible outcomes. An example of such an experiment is throwing a dice, where the outcome can be 1 through 6. Each sample drawn from the @@ -3869,7 +3870,6 @@ cdef class RandomState: Notes ----- - The Dirichlet distribution is a distribution over vectors :math:`x` that fulfil the conditions :math:`x_i>0` and :math:`\\sum_{i=1}^k x_i = 1`. diff --git a/numpy/random/randomgen/pcg32.pyx b/numpy/random/randomgen/pcg32.pyx index b48108a4cc23..5f2b34807da2 100644 --- a/numpy/random/randomgen/pcg32.pyx +++ b/numpy/random/randomgen/pcg32.pyx @@ -9,7 +9,6 @@ except ImportError: import numpy as np cimport numpy as np -from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy diff --git a/numpy/random/randomgen/pcg64.pyx b/numpy/random/randomgen/pcg64.pyx index 3572b17ca7a5..f67d9623cc33 100644 --- a/numpy/random/randomgen/pcg64.pyx +++ b/numpy/random/randomgen/pcg64.pyx @@ -9,7 +9,6 @@ except ImportError: import numpy as np cimport numpy as np -from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy diff --git a/numpy/random/randomgen/philox.pyx b/numpy/random/randomgen/philox.pyx index 235c76e6b5da..70afd55ab2da 100644 --- a/numpy/random/randomgen/philox.pyx +++ b/numpy/random/randomgen/philox.pyx @@ -8,7 +8,6 @@ except ImportError: import numpy as np -from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array diff --git a/numpy/random/randomgen/tests/test_smoke.py b/numpy/random/randomgen/tests/test_smoke.py index 15f6142a37ff..816ce6ddcd76 100644 --- a/numpy/random/randomgen/tests/test_smoke.py +++ b/numpy/random/randomgen/tests/test_smoke.py @@ -315,70 +315,6 @@ def test_chisquare(self): assert_(len(vals) == 10) params_1(self.rg.chisquare) - def test_complex_normal(self): - st = self.rg.state - vals = self.rg.complex_normal( - 2.0 + 7.0j, 10.0, 5.0 - 5.0j, size=10) - assert_(len(vals) == 10) - - self.rg.state = st - vals2 = [self.rg.complex_normal( - 2.0 + 7.0j, 10.0, 5.0 - 5.0j) for _ in range(10)] - np.testing.assert_allclose(vals, vals2) - - self.rg.state = st - vals3 = self.rg.complex_normal( - 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j) - np.testing.assert_allclose(vals, vals3) - - self.rg.state = st - norms = self.rg.standard_normal(size=20) - norms = np.reshape(norms, (10, 2)) - cov = 0.5 * (-5.0) - v_real = 7.5 - v_imag = 2.5 - rho = cov / np.sqrt(v_real * v_imag) - imag = 7 + np.sqrt(v_imag) * (rho * - norms[:, 0] + np.sqrt(1 - rho ** 2) * - norms[:, 1]) - real = 2 + np.sqrt(v_real) * norms[:, 0] - vals4 = [re + im * (0 + 1.0j) for re, im in zip(real, imag)] - - np.testing.assert_allclose(vals4, vals) - - def test_complex_normal_bm(self): - st = self.rg.state - vals = self.rg.complex_normal( - 2.0 + 7.0j, 10.0, 5.0 - 5.0j, size=10) - assert_(len(vals) == 10) - - self.rg.state = st - vals2 = [self.rg.complex_normal( - 2.0 + 7.0j, 10.0, 5.0 - 5.0j) for _ in range(10)] - np.testing.assert_allclose(vals, vals2) - - self.rg.state = st - vals3 = self.rg.complex_normal( - 2.0 + 7.0j * np.ones(10), 10.0 * np.ones(1), 5.0 - 5.0j) - np.testing.assert_allclose(vals, vals3) - - def test_complex_normal_zero_variance(self): - st = self.rg.state - c = self.rg.complex_normal(0, 1.0, 1.0) - assert_almost_equal(c.imag, 0.0) - self.rg.state = st - n = self.rg.standard_normal() - np.testing.assert_allclose(c, n, atol=1e-8) - - st = self.rg.state - c = self.rg.complex_normal(0, 1.0, -1.0) - assert_almost_equal(c.real, 0.0) - self.rg.state = st - self.rg.standard_normal() - n = self.rg.standard_normal() - assert_almost_equal(c.real, 0.0) - np.testing.assert_allclose(c.imag, n, atol=1e-8) - def test_exponential(self): vals = self.rg.exponential(2.0, 10) assert_(len(vals) == 10) diff --git a/numpy/random/randomgen/threefry.pyx b/numpy/random/randomgen/threefry.pyx index 03d245ea1e60..8140c6a9b72a 100644 --- a/numpy/random/randomgen/threefry.pyx +++ b/numpy/random/randomgen/threefry.pyx @@ -8,7 +8,6 @@ except ImportError: import numpy as np -from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array diff --git a/numpy/random/randomgen/threefry32.pyx b/numpy/random/randomgen/threefry32.pyx index e497926f55cf..1fa98eabdd29 100644 --- a/numpy/random/randomgen/threefry32.pyx +++ b/numpy/random/randomgen/threefry32.pyx @@ -7,7 +7,6 @@ import numpy as np from cpython.pycapsule cimport PyCapsule_New from libc.stdlib cimport malloc, free -from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array diff --git a/numpy/random/randomgen/xoroshiro128.pyx b/numpy/random/randomgen/xoroshiro128.pyx index be10cb430ba1..7795500e8ea1 100644 --- a/numpy/random/randomgen/xoroshiro128.pyx +++ b/numpy/random/randomgen/xoroshiro128.pyx @@ -9,7 +9,6 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array diff --git a/numpy/random/randomgen/xorshift1024.pyx b/numpy/random/randomgen/xorshift1024.pyx index bff569990871..3c7ffac52c54 100644 --- a/numpy/random/randomgen/xorshift1024.pyx +++ b/numpy/random/randomgen/xorshift1024.pyx @@ -9,7 +9,6 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array diff --git a/numpy/random/randomgen/xoshiro256starstar.pyx b/numpy/random/randomgen/xoshiro256starstar.pyx index 175c6e7e6896..c3856b6f7651 100644 --- a/numpy/random/randomgen/xoshiro256starstar.pyx +++ b/numpy/random/randomgen/xoshiro256starstar.pyx @@ -9,7 +9,6 @@ try: except ImportError: from dummy_threading import Lock -from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array diff --git a/numpy/random/randomgen/xoshiro512starstar.pyx b/numpy/random/randomgen/xoshiro512starstar.pyx index 96d62ea68797..761d1f1d0b20 100644 --- a/numpy/random/randomgen/xoshiro512starstar.pyx +++ b/numpy/random/randomgen/xoshiro512starstar.pyx @@ -9,7 +9,6 @@ from cpython.pycapsule cimport PyCapsule_New import numpy as np cimport numpy as np -from .common import interface from .common cimport * from .distributions cimport brng_t from .entropy import random_entropy, seed_by_array From 564cffee1307be942a124429e805a68fd516830a Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 2 Apr 2019 12:54:37 +0300 Subject: [PATCH 238/279] BUG: fix docstring tests --- numpy/random/randomgen/mtrand.pyx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/numpy/random/randomgen/mtrand.pyx b/numpy/random/randomgen/mtrand.pyx index fcc7a1d7dea7..4f81f92d1077 100644 --- a/numpy/random/randomgen/mtrand.pyx +++ b/numpy/random/randomgen/mtrand.pyx @@ -135,8 +135,8 @@ cdef class RandomState: The best method to access seed is to directly use a basic RNG instance. This example demonstrates this best practice. - >>> from np.random.randomgen import MT19937 - >>> from np.random import RandomState + >>> from numpy.random.randomgen import MT19937 + >>> from numpy.random import RandomState >>> brng = MT19937(123456789) >>> rs = RandomState(brng) >>> brng.seed(987654321) @@ -148,7 +148,6 @@ cdef class RandomState: """ self._basicrng.seed(*args, **kwargs) self._reset_gauss() - return self def get_state(self, legacy=True): """ @@ -2574,7 +2573,7 @@ cdef class RandomState: >>> def logist(x, loc, scale): ... return np.exp((loc-x)/scale)/(scale*(1+np.exp((loc-x)/scale))**2) - >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\ + >>> plt.plot(bins, logist(bins, loc, scale)*count.max(), ... logist(bins, loc, scale).max()) >>> plt.show() From 173a21081277dca440ede99d861ed09c941725fa Mon Sep 17 00:00:00 2001 From: Assem <38026074+yesass@users.noreply.github.com> Date: Tue, 2 Apr 2019 17:44:01 +0600 Subject: [PATCH 239/279] DOC: fix docstring for floor_divide (#13242) * DOC: fix docstring for floor_divide --- numpy/core/code_generators/ufunc_docstrings.py | 4 ++-- numpy/ma/core.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/numpy/core/code_generators/ufunc_docstrings.py b/numpy/core/code_generators/ufunc_docstrings.py index 6dd6982dfe6a..7591a7952fe4 100644 --- a/numpy/core/code_generators/ufunc_docstrings.py +++ b/numpy/core/code_generators/ufunc_docstrings.py @@ -1313,7 +1313,7 @@ def add_newdoc(place, name, doc): """ Return the largest integer smaller or equal to the division of the inputs. It is equivalent to the Python ``//`` operator and pairs with the - Python ``%`` (`remainder`), function so that ``b = a % b + b * (a // b)`` + Python ``%`` (`remainder`), function so that ``a = a % b + b * (a // b)`` up to roundoff. Parameters @@ -2607,7 +2607,7 @@ def add_newdoc(place, name, doc): >>> a = np.array([[1, 0], ... [0, 1]]) - >>> b = np.array([[4, 1], + >>> b = np.array([[4, 1], ... [2, 2]]) >>> np.matmul(a, b) array([[4, 1], diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 1f5bc2a51841..90aff6ec8c59 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -3450,7 +3450,7 @@ def mask(self): # We could try to force a reshape, but that wouldn't work in some # cases. return self._mask - + @mask.setter def mask(self, value): self.__setmask__(value) From c06c33906df825c2ec316c3d7b33a5ed656a703e Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 2 Apr 2019 18:14:36 +0100 Subject: [PATCH 240/279] MAINT: Sync with upstream changes Pull in BasicRNG source changes from original author Small doc fixes --- numpy/random/randomgen/generator.pyx | 4 +- numpy/random/randomgen/mtrand.pyx | 4 +- .../src/xoroshiro128/xoroshiro128-benchmark.c | 6 +- .../xoroshiro128/xoroshiro128-test-data-gen.c | 33 +- .../randomgen/src/xoroshiro128/xoroshiro128.c | 46 +- .../randomgen/src/xoroshiro128/xoroshiro128.h | 22 +- .../src/xoroshiro128/xoroshiro128plus.orig.c | 81 +- .../src/xorshift1024/xorshift1024.orig.c | 4 +- .../tests/data/xoroshiro128-testset-1.csv | 1998 ++++++++--------- .../tests/data/xoroshiro128-testset-2.csv | 1998 ++++++++--------- numpy/random/randomgen/tests/test_direct.py | 32 +- .../randomgen/tests/test_randomstate.py | 4 +- 12 files changed, 2130 insertions(+), 2102 deletions(-) diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index 0ca02e9127fe..b05f490334fe 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -2557,8 +2557,8 @@ cdef class RandomGenerator: >>> def logist(x, loc, scale): ... return np.exp((loc-x)/scale)/(scale*(1+np.exp((loc-x)/scale))**2) - >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\ - ... logist(bins, loc, scale).max()) + >>> lgst_val = logist(bins, loc, scale) + >>> plt.plot(bins, lgst_val * count.max() / lgst_val.max()) >>> plt.show() """ diff --git a/numpy/random/randomgen/mtrand.pyx b/numpy/random/randomgen/mtrand.pyx index 4f81f92d1077..2f89f5eb0cd7 100644 --- a/numpy/random/randomgen/mtrand.pyx +++ b/numpy/random/randomgen/mtrand.pyx @@ -2573,8 +2573,8 @@ cdef class RandomState: >>> def logist(x, loc, scale): ... return np.exp((loc-x)/scale)/(scale*(1+np.exp((loc-x)/scale))**2) - >>> plt.plot(bins, logist(bins, loc, scale)*count.max(), - ... logist(bins, loc, scale).max()) + >>> lgst_val = logist(bins, loc, scale) + >>> plt.plot(bins, lgst_val * count.max() / lgst_val.max()) >>> plt.show() """ diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c index 108058eeb103..9a7b52bfbf29 100644 --- a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c +++ b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c @@ -14,14 +14,16 @@ #define N 1000000000 -int main() { +int main() +{ uint64_t count = 0, sum = 0; uint64_t seed = 0xDEADBEAF; s[0] = splitmix64_next(&seed); s[1] = splitmix64_next(&seed); int i; clock_t begin = clock(); - for (i = 0; i < N; i++) { + for (i = 0; i < N; i++) + { sum += next(); count++; } diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c index d95260eca176..d50e63f5e6da 100644 --- a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c +++ b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c @@ -21,50 +21,61 @@ #define N 1000 -int main() { +int main() +{ uint64_t sum = 0; uint64_t state, seed = 0xDEADBEAF; state = seed; int i; - for (i = 0; i < 2; i++) { + for (i = 0; i < 2; i++) + { s[i] = splitmix64_next(&state); } uint64_t store[N]; - for (i = 0; i < N; i++) { + for (i = 0; i < N; i++) + { store[i] = next(); } FILE *fp; fp = fopen("xoroshiro128-testset-1.csv", "w"); - if (fp == NULL) { + if (fp == NULL) + { printf("Couldn't open file\n"); return -1; } fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); - for (i = 0; i < N; i++) { + for (i = 0; i < N; i++) + { fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); - if (i == 999) { + if (i == 999) + { printf("%d, 0x%" PRIx64 "\n", i, store[i]); } } fclose(fp); seed = state = 0; - for (i = 0; i < 2; i++) { + for (i = 0; i < 2; i++) + { s[i] = splitmix64_next(&state); } - for (i = 0; i < N; i++) { + for (i = 0; i < N; i++) + { store[i] = next(); } fp = fopen("xoroshiro128-testset-2.csv", "w"); - if (fp == NULL) { + if (fp == NULL) + { printf("Couldn't open file\n"); return -1; } fprintf(fp, "seed, 0x%" PRIx64 "\n", seed); - for (i = 0; i < N; i++) { + for (i = 0; i < N; i++) + { fprintf(fp, "%d, 0x%" PRIx64 "\n", i, store[i]); - if (i == 999) { + if (i == 999) + { printf("%d, 0x%" PRIx64 "\n", i, store[i]); } } diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.c b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.c index 981aeab8478c..060eb8a518c1 100644 --- a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.c +++ b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.c @@ -1,4 +1,4 @@ -/* Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org) +/* Written in 2016-2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) To the extent possible under law, the author has dedicated all copyright and related and neighboring rights to this software to the public domain @@ -6,29 +6,28 @@ worldwide. This software is distributed without any warranty. See . */ -/* This is the successor to xorshift128+. It is the fastest full-period - generator passing BigCrush without systematic failures, but due to the - relatively short period it is acceptable only for applications with a - mild amount of parallelism; otherwise, use a xorshift1024* generator. - - Beside passing BigCrush, this generator passes the PractRand test suite - up to (and included) 16TB, with the exception of binary rank tests, as - the lowest bit of this generator is an LFSR of degree 128. The next bit - can be described by an LFSR of degree 8256, but in the long run it will - fail linearity tests, too. The other bits needs a much higher degree to - be represented as LFSRs. +/* This is xoroshiro128+ 1.0, our best and fastest small-state generator + for floating-point numbers. We suggest to use its upper bits for + floating-point generation, as it is slightly faster than + xoroshiro128**. It passes all tests we are aware of except for the four + lower bits, which might fail linearity tests (and just those), so if + low linear complexity is not considered an issue (as it is usually the + case) it can be used to generate 64-bit outputs, too; moreover, this + generator has a very mild Hamming-weight dependency making our test + (http://prng.di.unimi.it/hwd.php) fail after 5 TB of output; we believe + this slight bias cannot affect any application. If you are concerned, + use xoroshiro128** or xoshiro256+. We suggest to use a sign test to extract a random Boolean value, and right shifts to extract subsets of bits. - Note that the generator uses a simulated rotate operation, which most C - compilers will turn into a single instruction. In Java, you can use - Long.rotateLeft(). In languages that do not make low-level rotation - instructions accessible xorshift128+ could be faster. - The state must be seeded so that it is not everywhere zero. If you have a 64-bit seed, we suggest to seed a splitmix64 generator and use its - output to fill s. */ + output to fill s. + + NOTE: the parameters (a=24, b=16, b=37) of this version give slightly + better results in our test than the 2016 version (a=55, b=14, c=36). +*/ #include "xoroshiro128.h" @@ -36,17 +35,20 @@ extern INLINE uint64_t xoroshiro128_next64(xoroshiro128_state *state); extern INLINE uint32_t xoroshiro128_next32(xoroshiro128_state *state); -void xoroshiro128_jump(xoroshiro128_state *state) { +void xoroshiro128_jump(xoroshiro128_state *state) +{ int i, b; uint64_t s0; uint64_t s1; - static const uint64_t JUMP[] = {0xbeac0467eba5facb, 0xd86b048b86aa9922}; + static const uint64_t JUMP[] = {0xdf900294d8f554a5, 0x170865df4b3201fc}; s0 = 0; s1 = 0; for (i = 0; i < sizeof JUMP / sizeof *JUMP; i++) - for (b = 0; b < 64; b++) { - if (JUMP[i] & UINT64_C(1) << b) { + for (b = 0; b < 64; b++) + { + if (JUMP[i] & UINT64_C(1) << b) + { s0 ^= state->s[0]; s1 ^= state->s[1]; } diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.h b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.h index 40cb39218908..0db82b173839 100644 --- a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.h +++ b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.h @@ -14,35 +14,41 @@ #define INLINE inline #endif -typedef struct s_xoroshiro128_state { +typedef struct s_xoroshiro128_state +{ uint64_t s[2]; int has_uint32; uint32_t uinteger; } xoroshiro128_state; -static INLINE uint64_t rotl(const uint64_t x, int k) { +static INLINE uint64_t rotl(const uint64_t x, int k) +{ return (x << k) | (x >> (64 - k)); } -static INLINE uint64_t xoroshiro128_next(uint64_t *s) { +static INLINE uint64_t xoroshiro128_next(uint64_t *s) +{ const uint64_t s0 = s[0]; uint64_t s1 = s[1]; const uint64_t result = s0 + s1; s1 ^= s0; - s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b - s[1] = rotl(s1, 36); // c + s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b + s[1] = rotl(s1, 37); // c return result; } -static INLINE uint64_t xoroshiro128_next64(xoroshiro128_state *state) { +static INLINE uint64_t xoroshiro128_next64(xoroshiro128_state *state) +{ return xoroshiro128_next(&state->s[0]); } -static INLINE uint32_t xoroshiro128_next32(xoroshiro128_state *state) { +static INLINE uint32_t xoroshiro128_next32(xoroshiro128_state *state) +{ uint64_t next; - if (state->has_uint32) { + if (state->has_uint32) + { state->has_uint32 = 0; return state->uinteger; } diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c index c0293cc2b586..1b5f46e4bdb5 100644 --- a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c +++ b/numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c @@ -1,4 +1,4 @@ -/* Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org) +/* Written in 2016-2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) To the extent possible under law, the author has dedicated all copyright and related and neighboring rights to this software to the public domain @@ -8,44 +8,45 @@ See . */ #include -/* This is the successor to xorshift128+. It is the fastest full-period - generator passing BigCrush without systematic failures, but due to the - relatively short period it is acceptable only for applications with a - mild amount of parallelism; otherwise, use a xorshift1024* generator. - - Beside passing BigCrush, this generator passes the PractRand test suite - up to (and included) 16TB, with the exception of binary rank tests, as - the lowest bit of this generator is an LFSR of degree 128. The next bit - can be described by an LFSR of degree 8256, but in the long run it will - fail linearity tests, too. The other bits needs a much higher degree to - be represented as LFSRs. +/* This is xoroshiro128+ 1.0, our best and fastest small-state generator + for floating-point numbers. We suggest to use its upper bits for + floating-point generation, as it is slightly faster than + xoroshiro128**. It passes all tests we are aware of except for the four + lower bits, which might fail linearity tests (and just those), so if + low linear complexity is not considered an issue (as it is usually the + case) it can be used to generate 64-bit outputs, too; moreover, this + generator has a very mild Hamming-weight dependency making our test + (http://prng.di.unimi.it/hwd.php) fail after 5 TB of output; we believe + this slight bias cannot affect any application. If you are concerned, + use xoroshiro128** or xoshiro256+. We suggest to use a sign test to extract a random Boolean value, and right shifts to extract subsets of bits. - Note that the generator uses a simulated rotate operation, which most C - compilers will turn into a single instruction. In Java, you can use - Long.rotateLeft(). In languages that do not make low-level rotation - instructions accessible xorshift128+ could be faster. - The state must be seeded so that it is not everywhere zero. If you have a 64-bit seed, we suggest to seed a splitmix64 generator and use its - output to fill s. */ + output to fill s. + + NOTE: the parameters (a=24, b=16, b=37) of this version give slightly + better results in our test than the 2016 version (a=55, b=14, c=36). +*/ uint64_t s[2]; -static inline uint64_t rotl(const uint64_t x, int k) { +static inline uint64_t rotl(const uint64_t x, int k) +{ return (x << k) | (x >> (64 - k)); } -uint64_t next(void) { +uint64_t next(void) +{ const uint64_t s0 = s[0]; uint64_t s1 = s[1]; const uint64_t result = s0 + s1; s1 ^= s0; - s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b - s[1] = rotl(s1, 36); // c + s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b + s[1] = rotl(s1, 37); // c return result; } @@ -54,14 +55,42 @@ uint64_t next(void) { to 2^64 calls to next(); it can be used to generate 2^64 non-overlapping subsequences for parallel computations. */ -void jump(void) { - static const uint64_t JUMP[] = {0xbeac0467eba5facb, 0xd86b048b86aa9922}; +void jump(void) +{ + static const uint64_t JUMP[] = {0xdf900294d8f554a5, 0x170865df4b3201fc}; uint64_t s0 = 0; uint64_t s1 = 0; for (int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) - for (int b = 0; b < 64; b++) { - if (JUMP[i] & UINT64_C(1) << b) { + for (int b = 0; b < 64; b++) + { + if (JUMP[i] & UINT64_C(1) << b) + { + s0 ^= s[0]; + s1 ^= s[1]; + } + next(); + } + s[0] = s0; + s[1] = s1; +} + +/* This is the long-jump function for the generator. It is equivalent to + 2^96 calls to next(); it can be used to generate 2^32 starting points, + from each of which jump() will generate 2^32 non-overlapping + subsequences for parallel distributed computations. */ + +void long_jump(void) +{ + static const uint64_t LONG_JUMP[] = {0xd2a98b26625eee7b, 0xdddf9b1090aa7ac1}; + + uint64_t s0 = 0; + uint64_t s1 = 0; + for (int i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++) + for (int b = 0; b < 64; b++) + { + if (LONG_JUMP[i] & UINT64_C(1) << b) + { s0 ^= s[0]; s1 ^= s[1]; } diff --git a/numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.c b/numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.c index e4f899fb7b09..03c1c17fe800 100644 --- a/numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.c +++ b/numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.c @@ -14,7 +14,7 @@ See . */ linear dependencies from one of the lowest bits. The previous multiplier was 1181783497276652981 (M_8 in the paper). If you need to tell apart the two generators, you can refer to this generator as - xorshift1024*φ and to the previous one as xorshift1024*M_8. + xorshift1024φ and to the previous one as xorshift1024*M_8. This is a fast, high-quality generator. If 1024 bits of state are too much, try a xoroshiro128+ generator. @@ -36,7 +36,7 @@ int p; uint64_t next(void) { const uint64_t s0 = s[p]; uint64_t s1 = s[p = (p + 1) & 15]; - s1 ^= s1 << 31; // a + s1 ^= s1 << 31; // a s[p] = s1 ^ s0 ^ (s1 >> 11) ^ (s0 >> 30); // b,c return s[p] * 0x9e3779b97f4a7c13; } diff --git a/numpy/random/randomgen/tests/data/xoroshiro128-testset-1.csv b/numpy/random/randomgen/tests/data/xoroshiro128-testset-1.csv index 8289ff27eb96..4ef7172e1735 100644 --- a/numpy/random/randomgen/tests/data/xoroshiro128-testset-1.csv +++ b/numpy/random/randomgen/tests/data/xoroshiro128-testset-1.csv @@ -1,1001 +1,1001 @@ seed, 0xdeadbeaf 0, 0x86f9f4feeebed928 -1, 0xcd2c9d2d1dc1c071 -2, 0x94741e0555641979 -3, 0x81eed88d38a9138e -4, 0x54b9f49cd0035507 -5, 0x8c112b85821a173a -6, 0x51f4c2eabf05c192 -7, 0xefa6a9ad4ca56d94 -8, 0xd3bd969b3aeb5457 -9, 0xcd4f28af5618e25a -10, 0xa20fd197fb60aad -11, 0x796b5146f61afc52 -12, 0xf6fe619effce6d62 -13, 0x763ed6613d00e8bd -14, 0x333d357571b249c -15, 0xc2a39f35ba8f4ce6 -16, 0xae35d916c6cf8a2b -17, 0xfdfaa6b7eb9591d3 -18, 0x52668584489de943 -19, 0xca982b4b760effb8 -20, 0x32c7256797c26f09 -21, 0x3115b9539d722cc -22, 0x5183f1d23dd2f56e -23, 0xa0a2a2c524e6650c -24, 0x3191f4b5260e5a2d -25, 0x1eebe2655fb4f190 -26, 0x5781c6b75a253a88 -27, 0xae45a39543b4140d -28, 0xfc62724b20d2df78 -29, 0x3770290ba157dc9c -30, 0xc4731569807dbff4 -31, 0xd42ec771a7a0a08f -32, 0x743276e0eb868d75 -33, 0x37f95d1ba1faebc6 -34, 0x3b4800b089a323cf -35, 0x437fa9c71af61839 -36, 0x1cab936dd28c6f1c -37, 0xe9d60347286dd9f0 -38, 0x716625cbd57bbd63 -39, 0xbd6c0f5e6aea7288 -40, 0x7c782d5b111a89f3 -41, 0xaeb1b9478b99970 -42, 0xbdffccb6a96cb533 -43, 0x9423e6ea789f29f1 -44, 0x53df9a7a0ea73fe6 -45, 0x7d9bec5c15c7e349 -46, 0xd1fc83fcf223aea5 -47, 0xd1dce35338ad3bab -48, 0x297bd5f1cf79e758 -49, 0x19ec39a6191419da -50, 0x45e57323ad58071b -51, 0x395bcbebe1ddf611 -52, 0x22d9065efb013222 -53, 0x4ea2d534fd9fecb3 -54, 0x9b9779e1edeb2e27 -55, 0x1ba777ba576a236e -56, 0x23cf95e34d62dd3f -57, 0x6d1689730795e6bd -58, 0x24e510f9d2f65379 -59, 0x1e12d607e78701e8 -60, 0x3347fe3ddc50a23e -61, 0x331754f825305d97 -62, 0xf21a675c0344709c -63, 0xcc9bd2062ae5fb39 -64, 0xd2dcd3a1ee6afe9e -65, 0xbdb0388382c408d1 -66, 0x19476497aaef64ad -67, 0x906dfff3b1181dd7 -68, 0x47edd3c528f4c753 -69, 0xba2a0f289279aec2 -70, 0x710bc73fd1c732a9 -71, 0xe0238b1ab604610d -72, 0x10f68d7eb0d19e19 -73, 0xc13654f8b8f3d9b7 -74, 0x112c76bf71ad04a9 -75, 0x4b9d965062e9a0fd -76, 0xe0b13496fec19aa8 -77, 0x999493dababe73c8 -78, 0x87104db5240f12fb -79, 0x8fc8dff016c96a13 -80, 0x3eff4853e8b167a8 -81, 0x438b6f5c3d10b85d -82, 0xc2f94a0707d949f5 -83, 0x87981b13beefb01f -84, 0x1718db5072923bb2 -85, 0xbe7ae4310234b5f1 -86, 0x3ad4306f2b2b3b47 -87, 0x9de166baaf152f81 -88, 0xebca2cf057a00802 -89, 0x99bfd19b5e0a87b2 -90, 0x5ae7b3ab9d2623c0 -91, 0x8de5811587a53d2e -92, 0x629a57a87d068ee4 -93, 0xfd80a82607740601 -94, 0x5758bfc8610d0b8b -95, 0x8f0c00fab932c1f5 -96, 0x3d49bd296a34582d -97, 0xc99c1bb8319ce526 -98, 0x1dd5ba47ac1443ba -99, 0xb5a40a33c9ca1cf9 -100, 0xa1025156b711394c -101, 0xdb3ef94ee8bc71a4 -102, 0x6d3292123ffa9bc9 -103, 0x4b9683ebf2f98d1f -104, 0x4d1a4709b547bfe7 -105, 0x3623a9c4054355b1 -106, 0xed15f8852d329b4d -107, 0x60ef76852f40e346 -108, 0xe64c2bfc6d0ef2dc -109, 0xf286f874cfb68ee2 -110, 0xb1b07a7ca9268329 -111, 0xf618a9bfe00b7cdd -112, 0x54a40c4f52cab527 -113, 0x5007a4d41eaf0af1 -114, 0x6fa7f2210a7b7f3a -115, 0x7b448faa473ad765 -116, 0x901b6276232cb3c2 -117, 0xd69d06b85d118dfd -118, 0xf8fb03c5dfef937a -119, 0x5a53e96d5ebc4689 -120, 0xe24e81bbd9772b3c -121, 0xa996ed94405e1811 -122, 0x7d8712833a4cbd96 -123, 0xd8b81a509f392481 -124, 0x76b52a270551424b -125, 0x4c854325eaa4ef23 -126, 0xc8823e5a74757b2f -127, 0x9ac8deb0aa215a3f -128, 0x89641160b3eeafdd -129, 0x17781aba3d908856 -130, 0xd12e5f215de0a3b4 -131, 0xd94cd412b8bef057 -132, 0x40e85ebd5844b9e8 -133, 0xa581cf7ef62e70a2 -134, 0x74953df639f8a9a2 -135, 0xaa92c9804434caa6 -136, 0xf186398542a15448 -137, 0xa0888e1233d64da3 -138, 0x277d14f22bc64c91 -139, 0x2851b3b5fc49ad5 -140, 0x68182666788909 -141, 0x5ea068625e49839 -142, 0x63bac5a5d225e8db -143, 0x2dd9db0ad24aff05 -144, 0x3f637e71528ad6ad -145, 0xe3b7ba911c4fe47 -146, 0xe4bcf50c8ada7ab6 -147, 0x4470ffb01cd6980c -148, 0x377cfdbe8e810731 -149, 0xdb33ff37954849c7 -150, 0xb622ead14010ad64 -151, 0x6c44d65c7a81a5cb -152, 0xd99a3fca5a5d9fce -153, 0x24e7360e1ee2efd4 -154, 0xbd927a3fb576d81 -155, 0x1ea3f2b7c909ffb7 -156, 0x48aedb2bec244a7e -157, 0xc17d9539cf53a5f7 -158, 0xe4ea45fcf4de590b -159, 0xe1d863ebb77cb7de -160, 0x8ecf0bc8d88fefe4 -161, 0xa881cef3b3209e05 -162, 0x8f34a14a6978afb6 -163, 0xed4e2e5e1f4966fe -164, 0xede897e11cbe230d -165, 0xd344af5e50042d6 -166, 0xb2739594ba906c81 -167, 0x83c0bbde6d95b632 -168, 0x6b7ae9d1c4af98b2 -169, 0xc4b8f6816eae17f -170, 0xf8e3a6bf7855bd3b -171, 0x9f64ff72d6357488 -172, 0x50b6a304f9543f58 -173, 0x330e8281e591cc6e -174, 0x15dfdd5af7b421e3 -175, 0x8d3224e62524222c -176, 0x90d89d139a75b44f -177, 0xf6efb68e15639dce -178, 0x98cf64777861f844 -179, 0xa031e78e4b3a7b3a -180, 0xa3647dbd85c538eb -181, 0x73656c8c77d9c56 -182, 0x88840b683d4fdb72 -183, 0x3b84749774eac55 -184, 0xb9b753a86ec15b39 -185, 0x31ab026ace06b686 -186, 0x4fd37ef5b5b1d284 -187, 0x7cc6c46fb114a76 -188, 0x463ff22f392dbd4c -189, 0x188c3718f2068889 -190, 0x769892f97d895302 -191, 0x9838246e76757b6f -192, 0x546a68f394c391ee -193, 0xc9e32a7d2a7fb559 -194, 0xd84ac91984217239 -195, 0x82ef273042519aaf -196, 0x79650a2c9bf2a812 -197, 0xb7aa6dc1c23eaecb -198, 0x60326b9e25b055d -199, 0x6b17c296feac0e6a -200, 0x7813f405baa0d85 -201, 0xb9d52400dcb399d2 -202, 0xfb588178727e0012 -203, 0x448763bafa3d9095 -204, 0xd63fd1757e94e19f -205, 0x2bc98e05f296e73 -206, 0x9e05ff0a641889cb -207, 0x1e1716c76c9a8990 -208, 0x9e2f67e555f5389 -209, 0x430a8a612033934b -210, 0xd49a74a4d8743bf -211, 0x7b08085a0b4aee34 -212, 0x2c0482984960e7c1 -213, 0xae26bcde5d8fe8fa -214, 0x8f40022b951f98c9 -215, 0xcc59b599dd0383a6 -216, 0xb6833d7a5e00c373 -217, 0x3e025759aba46bdb -218, 0x2558a3dd775dee09 -219, 0xdcd8370368d091a8 -220, 0x9e55348e5734fa9f -221, 0x1061a08056830eea -222, 0xdca96b36adc5ed23 -223, 0x8563d7d016fe5d7b -224, 0xa3fb6b79b0095ee3 -225, 0xb887cd180ae6f882 -226, 0x670e10186fda74a9 -227, 0xa25f08a01b69032e -228, 0x5d90bfde7e21c0c8 -229, 0xb1b154f328250786 -230, 0xe0050135775487f3 -231, 0xbd7001fa00656593 -232, 0xcb6136e259180b69 -233, 0xf7480387c0872215 -234, 0x2e478a3efc5a7ec4 -235, 0xeb1cad9cb7d82f45 -236, 0x5d4c127c6c060ca3 -237, 0x1f9efe7a0bc11db5 -238, 0x59b9712ac8f24207 -239, 0xb94edcfe7b8e7ded -240, 0x474b672b27aef61b -241, 0xc2150760d3da0859 -242, 0x1146d26c90b6becb -243, 0x52926b0e9e820413 -244, 0x24f2b065f78bdaa5 -245, 0xf94b5372ca68e5e -246, 0xfdf3e645313db1fa -247, 0x181af7ab689d2ec7 -248, 0x1e275b8f25520a3 -249, 0x1f287f3ff3d55dc8 -250, 0xa035801d4747cae9 -251, 0xba6ed878f55ebd -252, 0x74d6598302a5c786 -253, 0xe92ce6198f39ded4 -254, 0x7b811ab7cda273c9 -255, 0x9d17fb60483addd4 -256, 0xf2b457f77ba326f -257, 0x32e5956d2a580c90 -258, 0xcba559493cdd2b6 -259, 0x59276c178ca0e7a6 -260, 0x509681deb2f0160b -261, 0x1bc2df48eb8f2a3a -262, 0xbe7f17f92c808cd8 -263, 0xebbcd3a312ab80b7 -264, 0xef85e7595c591a83 -265, 0x914028c61432c620 -266, 0x7d8f67244eb3ea9e -267, 0xa0512684d8ca4355 -268, 0x5a12209ada976a9c -269, 0xfa0cf430c33df55c -270, 0xd514dc8064688736 -271, 0xc5020a78e10201f7 -272, 0x9df7e30707f4591b -273, 0xbc41eeb3c45f4ba2 -274, 0x2b5605d64a470e5d -275, 0x77753b9a125af99a -276, 0x7ba925c3af8e2a4 -277, 0x46c1dadcd05c1165 -278, 0xcb64cd52411f993 -279, 0xa6c3c1f065f7c758 -280, 0xad68088813a0068a -281, 0x6dd039e4b9d4631a -282, 0x528f220f2f54270e -283, 0xfe565ea36805959e -284, 0x3f2edbdc64385933 -285, 0xf0ea2fe07768bf3a -286, 0xd120fe046bfafc74 -287, 0x85c1b029a6d56aa1 -288, 0xb03c986da026593d -289, 0xd126fed2a4ca68a7 -290, 0x7e63d8216bc42201 -291, 0xadbfd88dcf50e179 -292, 0x6c1c1308ee42ca66 -293, 0xf5415a024cbf5458 -294, 0x4e50d4d388352815 -295, 0x38949c203a1a34ab -296, 0x3a35d5ff38274f23 -297, 0xc96c009af2982c00 -298, 0x581691437bf0b1e7 -299, 0x793d1a61f0b0dcf8 -300, 0xa36a3b1c3e39c61e -301, 0xff2938c1b78db0fc -302, 0x1e82a7fc6b7c4725 -303, 0xd91883febcf4672e -304, 0x22c55d5c95f1d985 -305, 0x3fc97236c50bfce1 -306, 0x28a3e0c7a4380bcb -307, 0x2c072113ce5f2570 -308, 0x9c816b6af1d912a3 -309, 0x83698f6af8e41daa -310, 0xa7b1b189d398eae5 -311, 0xb5b44ce05dd0867e -312, 0x5ceaebf68b501f84 -313, 0xdf384c2545db9168 -314, 0xa75eae42ad85396f -315, 0x88273ff551afa924 -316, 0xda2c47046eabd9f0 -317, 0x18d83b83988fa9bb -318, 0xeed5ad076674a6ac -319, 0x28d969bd36a0d5e8 -320, 0x9259eebb564cfd98 -321, 0xdc2e175377ffcd6a -322, 0xcdb19c84396bc51d -323, 0xeaa3a7674b5e5da8 -324, 0x9bd54f94110b36a -325, 0x88d96179c0a35528 -326, 0xea1536654ceee668 -327, 0xdd1cc9d40ad3ea60 -328, 0xe9106bddc3221293 -329, 0xe096d5b5acd9ff46 -330, 0x4cb27170156f9265 -331, 0xd0d3e5b9edadb2bb -332, 0xf75347484f2af9b4 -333, 0x6170333a4e6885d5 -334, 0x99a50b6b702b80ba -335, 0x10629a67c9781899 -336, 0x374a33743030da9d -337, 0x289fdbd0bc89f257 -338, 0xa67c56d1bc5dc5dc -339, 0x38e90cd1dd6d64f2 -340, 0xcc5ed5dc4955655e -341, 0x723d33bae999723d -342, 0x46af17f0c981605a -343, 0xd1d3a915f899b0ff -344, 0x9a60c9bee03dcb43 -345, 0x11753a29a1d9201 -346, 0x491c99adde4e0a73 -347, 0x634437d6dc4388ea -348, 0x5f4cf58d810069e0 -349, 0x8d950ed29ac1703d -350, 0xa6330099182b17e3 -351, 0xfc9bf9a5cd4ea35d -352, 0x4560dc5769ff741b -353, 0x374a9ff29ee966ba -354, 0x16a9bd5c9214e40d -355, 0x46fdfb2899af3e80 -356, 0xe2eff8b6ad57da07 -357, 0xa67c709690485024 -358, 0x87551c8907b62ead -359, 0xde03a75e08382365 -360, 0x6744ad2be09ed2c1 -361, 0xb34ec9f71efb1f48 -362, 0x4fb71847ea9a525a -363, 0x10ffcd51ebb2f5b9 -364, 0x489431753bfacc7b -365, 0x7a9cc00b29aa7802 -366, 0x8017011d2285ce9d -367, 0xd54d90e061d61b87 -368, 0xa41a40e4a81526a -369, 0x47b5ba075adc3b4c -370, 0xb8cbbc5498cc428b -371, 0x6165fcf1ef4795b -372, 0x57926a7aebb26866 -373, 0x226ec9794dd0714f -374, 0x2759cca87ce9a2ed -375, 0xb41a74ac376c84d3 -376, 0x3e8101b52e2518a6 -377, 0xc8f18bb165e3db1d -378, 0x187f3ef2ff1093d2 -379, 0xb5c1069cdbe57e46 -380, 0xd3f342f3104a5902 -381, 0xf32e59c6c7b8458 -382, 0xfdb39f79b5b1f574 -383, 0x526dce2fc3115682 -384, 0x1a2e8128c0180ae -385, 0x5eead6a0e587e4c6 -386, 0x450e7d15d282c580 -387, 0x931a6cd04be42fe5 -388, 0xb4d321f03fb71277 -389, 0x32479d856fd9bdfa -390, 0xa28dc713e419022a -391, 0x6c8dcea6b5adbb14 -392, 0x4ae7b8d58ef7aa3d -393, 0x49903e3fbd56493e -394, 0x5238b0c9ee856f3b -395, 0x77deab4c733cb2 -396, 0xea5d74aec663c8dc -397, 0x899afbc707b0899 -398, 0x56a9418f18219182 -399, 0xb42801a6445d852a -400, 0xd8462e581c7cd53b -401, 0x802701332acff0c8 -402, 0x309618a5c049ddaf -403, 0x66f6d281cd986fa -404, 0x53f089859dd3e861 -405, 0x497078aabbed67cd -406, 0x9cdc9d89a2e1cc9 -407, 0x871b1721c6f463c4 -408, 0xe9f8872d8f113d84 -409, 0x48e03acc1ff301b -410, 0x79d5f73993eb02ef -411, 0x5ac76f9f2329e39b -412, 0x878c2c8d84a9643a -413, 0xd1d0786d40a7391d -414, 0xf024ad81eea63787 -415, 0x9f96b1146e5354b3 -416, 0xa85fd9a5bc0fc195 -417, 0xafd0522c28edfd2f -418, 0x6c1aa508159a1fcd -419, 0x873f632373719c87 -420, 0x5db129eaa27ff3d1 -421, 0xd81037e5b49f399d -422, 0xa40a347abfc43a81 -423, 0x314452aabf5a95b1 -424, 0x6f8642230a3edee8 -425, 0x2aaa01f7cc73fb09 -426, 0xa0ebf15ee345343 -427, 0x19fddca117f16f35 -428, 0x111be87b23ca2143 -429, 0x46de5fd13663c896 -430, 0x2dacbe0fca5e4efe -431, 0xd534f9dce19043c7 -432, 0x7a548f9a35a6759b -433, 0x3c6f046dd15b6fe3 -434, 0x1f7a17cbfc090519 -435, 0xd8a282357a83d2ce -436, 0x96a8a5cfb5be2843 -437, 0xce416b54c95c6006 -438, 0xcda9d6127cb716cb -439, 0xb062a607b35aef78 -440, 0x141e913718707191 -441, 0xef829605cf4aa346 -442, 0xb9555c4c76d6a7c4 -443, 0xd41bd4a1593170ca -444, 0x2e00143ad3d88b4d -445, 0x1afa722d16ac1d47 -446, 0xa22530a5d53159c8 -447, 0x17f76921e5633a50 -448, 0x8e3ed4b11072799f -449, 0xedb6ace0cb513a05 -450, 0x8dbf3d235449385e -451, 0xd01fb688b01b798f -452, 0x8e3aa7aa93ab0436 -453, 0x8b18ef4c8cc20636 -454, 0xf40181de15f5029a -455, 0xfcf54366f31c924b -456, 0x7b16e64f5c3a1d71 -457, 0x6b5f96df49784c48 -458, 0xcb5914727615bb07 -459, 0xf228f7b32ec2d237 -460, 0x37c51a8a1b854a84 -461, 0x63484491b02c7fac -462, 0x526a9f0a571e170a -463, 0xeb8d59e7fbbe583a -464, 0x4fd1fa3bd32b8c84 -465, 0x825ba1ed08b31e1f -466, 0x644d2cadd8ddeeb2 -467, 0x3874924732d3c6d7 -468, 0xd2679fee287a403a -469, 0x17ddb27712b6cdb9 -470, 0xcce6bed3fa81f460 -471, 0x8a2df0f2ccb3f028 -472, 0x85d166e4456aae72 -473, 0x5dc4ce3fab56777 -474, 0x555b2c69b6eabb7 -475, 0x873bc152fdb3717d -476, 0x5670068eb7d52805 -477, 0x7f776ca61f79e219 -478, 0xa8b51d2bd8c8c939 -479, 0x50345828de969faa -480, 0xbefa083bfbd71b60 -481, 0x883809b883dffdca -482, 0x49ccf930ea76fce8 -483, 0x97cc45c4c2dcf12b -484, 0x4d3aef2e2a4a450b -485, 0xc7ed768e40efd44d -486, 0x5530c69ecdc47b2c -487, 0x2fbb8ad65b3e777a -488, 0x45234e14d9fd969d -489, 0xb6a758912ec87c9d -490, 0xb35f335efeac2d3b -491, 0x21efc82b1e65a1cf -492, 0x897db9fe20a2702f -493, 0x444042b714793c27 -494, 0x37356cc844e57cb7 -495, 0x602ecce617309266 -496, 0x4ea323a5d93363b7 -497, 0x2c2f0344303d7067 -498, 0x983de14baf7a9234 -499, 0xc4edde0900601361 -500, 0x12574e754cf862a8 -501, 0x82eb774465a3a83b -502, 0x115fd6ada32ab10 -503, 0xce23f43213ea118a -504, 0x912e289389130f18 -505, 0x977464bbb2fc0cd9 -506, 0xeb944201e2747c79 -507, 0xa41dae77205e05ee -508, 0x66c91981aba16d08 -509, 0xbd4aefbeb385af57 -510, 0xd7c7d36c0ec75862 -511, 0x492e43720ebee40c -512, 0xf44861d4636833df -513, 0xb9fb92c7203e2a1a -514, 0xd75f7f48e860938b -515, 0x8235d433d3e773f8 -516, 0x36cc65bb70a32774 -517, 0x3898d9516512bffa -518, 0x4f5c36707161dc35 -519, 0xa35e3d81512f0a8e -520, 0x4ae50933ef7bd3b9 -521, 0x641dc03f71dc81f3 -522, 0xc6002d833e1d768e -523, 0x6c7d94f79b7a1956 -524, 0x4027405ac3c6e666 -525, 0xab69f022928e86d8 -526, 0x90272e57839563ab -527, 0x56e78769f743d98 -528, 0xb5c7931145b93a39 -529, 0x253fbe3201939650 -530, 0x5325825cbe56c3a9 -531, 0x159aa2be6163c7bf -532, 0x56b8d5a5ed375c9 -533, 0xbd4b45a7cce10f56 -534, 0x2f799de5fd80339e -535, 0x40232bd30ebb82d2 -536, 0xc10e2198616b20a6 -537, 0x6a13ecc0b52813f -538, 0xfafd5d5b466ee59e -539, 0x810cbf398208d400 -540, 0x7137dc6f08e5b6d3 -541, 0xfe59d9caf7564d0c -542, 0x3117cae7c6ee6927 -543, 0x89e83cf15785a430 -544, 0x386b6daed57236e1 -545, 0xc2e6fb38df98a4dc -546, 0x496513da22e1e53e -547, 0x57efdf29edd94aab -548, 0x3433ac46ce163ef3 -549, 0x296565c39cba14f3 -550, 0x1ce89ad8ff370a6f -551, 0xcb12c5a7db52fd27 -552, 0x8125373ad475530a -553, 0x75ed8dda02fd5bbc -554, 0xaf2c279596340f93 -555, 0x18c7f80478479a56 -556, 0x14edf2ed871d9c41 -557, 0xf35731f0b8d26e4a -558, 0x2cace2d1996272bd -559, 0x84c3b017f5b12bb8 -560, 0x441c286a303c81c8 -561, 0x92a7c594c92b2353 -562, 0xb175a7a7e0cab31f -563, 0x501d7003cb9e530d -564, 0x1e9d3dea32bb5d6 -565, 0x60756fd6e4b239d2 -566, 0xf979b4c7ddf4bb22 -567, 0x1e5c0ba3d2797a7a -568, 0x94590d4209c70c70 -569, 0xc5dbc6ef6fd8c203 -570, 0x46a0eb4fc61727f2 -571, 0xe3ddaa7f4033fcb0 -572, 0x4fc177555a6b2f9b -573, 0xce0f6ab675596a18 -574, 0xe11a08478844ecec -575, 0x47054780433de44 -576, 0x89a3be9609dc2a34 -577, 0x9ea612c49a4c170f -578, 0x8212e9db2df9ca7d -579, 0xdf1cedac92affa7c -580, 0xc21b0ff068580e5a -581, 0x49168be340b1ade -582, 0xce3a5fd54225a6a9 -583, 0x80ecff24ec6cdb9f -584, 0xd14429e950a1a21e -585, 0xc66a1ad3cad8f9a6 -586, 0xcc76bdca3ded453c -587, 0x748165a5cb8b6bd -588, 0xcc77eb3966db7c5d -589, 0xbaceadcc1db342d6 -590, 0x33b42e3dc005fc38 -591, 0x43b5661eead65675 -592, 0x356821fd43c46e5 -593, 0x4efdd2444e0c5ffa -594, 0xf84ce60e2c0de959 -595, 0x14a4b1dd26583f04 -596, 0x6ffb885f5fe18b87 -597, 0x8233b6a95b1af132 -598, 0x7e2e9c449dd06b71 -599, 0x736bc96174cd4d97 -600, 0x86591ab3ab385777 -601, 0xb7696e3909a91039 -602, 0xda363e1a90c99d9c -603, 0x793cd7e1855b9a43 -604, 0xa9dbce0ccacd24c2 -605, 0x5d9a1d9b06fcf2f2 -606, 0xa7db7fd7c2b50d55 -607, 0x13c85aaefd37bf77 -608, 0xcba5689a383aa436 -609, 0x7dcbc3e297d2bd31 -610, 0x9860da13006164e8 -611, 0xda3be955750ba8a6 -612, 0x57f6a78ac6d2cb3 -613, 0x861ed21955702cef -614, 0x3cfdfb6fa0763186 -615, 0xd075f803b072f140 -616, 0x6b1622638e94a714 -617, 0x6f4b177c0213a295 -618, 0x26c113226bbfa72 -619, 0xbcb962e03d008ba7 -620, 0x1e50555d6e75d9b9 -621, 0xd67082f15ff0086 -622, 0x20766d0fc6bd729b -623, 0xeea24b2ecc4db639 -624, 0x3136637be559ec83 -625, 0xd3f2c641faccfcf8 -626, 0xe43f5bfe95bfb2c2 -627, 0xbc801108984335e3 -628, 0x19ff6b0c435e06a1 -629, 0x7b8f28c44eb5195d -630, 0x375460c52c467757 -631, 0x534f4697a2a2f0d3 -632, 0xbd1aed6c1a94e586 -633, 0x9dec33a59dd000e1 -634, 0x4611fc38e6902126 -635, 0x1296da2fca821b09 -636, 0xce4684ac8861a6b7 -637, 0x16bdaa7a0563d3c8 -638, 0x22a6a8b6de1fcd10 -639, 0xeed5c457b2d2a399 -640, 0xb66c697c0e328f69 -641, 0xe678d6d573b2dc21 -642, 0xd0a78328399774d2 -643, 0x7fee339fadd44eaa -644, 0x32c2da48753c8818 -645, 0x691f87af10bc6f5c -646, 0xe382722ac6ebdbb3 -647, 0x28bb87557931a39f -648, 0xc3aba948d7d22fa6 -649, 0x3ce7016f24e2f50b -650, 0x863b408ab8161d28 -651, 0x1e3d2d6746c16b31 -652, 0xe5a21dc5843a37d6 -653, 0x8ecb559ea375c81d -654, 0xff2681b83a599f98 -655, 0xcd9893140d02b725 -656, 0x80294d390a4e1a08 -657, 0x254166d362613f84 -658, 0xd2c336ba5b4ae618 -659, 0xef79a05286b75aaf -660, 0x704140e00e02ea9f -661, 0xa2623b124bb92365 -662, 0x2225846e393c249b -663, 0x95676d7c7aae81a3 -664, 0xe0cbe12ba194b3d9 -665, 0xda8ca3d800ea6152 -666, 0x8b2c2f63db05c887 -667, 0xf14012751ef435e9 -668, 0x33820fbd9a06d78 -669, 0xf37375a008192ae8 -670, 0xaa2c34f4b405589e -671, 0xd26bbda155ac158b -672, 0x418b108b101ea70d -673, 0xb9648a82ca0617d7 -674, 0xae6e2213c8c0d3e3 -675, 0xda7335c158d64615 -676, 0x78f175a4a89cdf5b -677, 0xac7a07b66a84f751 -678, 0x266019228d3bdb87 -679, 0x3a7798913c66d5a -680, 0x2aa9c173879dc048 -681, 0x67453dc96c3642da -682, 0xbe9ea095f8333cda -683, 0x10998be0d5702361 -684, 0x77a4e1af57a6b02e -685, 0x66356334d32ab0fe -686, 0x2df9585cb5ea1b34 -687, 0x51159b44acaa000f -688, 0xbc433d2fbb8a4953 -689, 0x5a533a3838335feb -690, 0xd57ffb6f839fc89d -691, 0xe7cd85b8d026e706 -692, 0xdd4acea5a81530e7 -693, 0xd7af04b51606fa0f -694, 0xe31e683c116deb37 -695, 0x4e2adf78e2a88fd1 -696, 0xc58b907a61dee8f -697, 0x673e1a4b00b0a2de -698, 0x36b639fa8091f63 -699, 0x7782c303339e2f0a -700, 0xfd84e0fb7774b0be -701, 0x2a6ac41e094d6e25 -702, 0xcf221a0187c8ca32 -703, 0x4e457ef8a6a528dd -704, 0x9a7714c8913ac3a2 -705, 0x5a6513aaec56ddf0 -706, 0x254fc4d74dc56a5 -707, 0x93e1bd37d16ee5f2 -708, 0xd1a16a2aa652c2ce -709, 0xa66ab34e5262848 -710, 0x5e6f429f482e4a2d -711, 0x198eeff9e36608ec -712, 0x3bea433a42228c7b -713, 0x1a85a30f51e1ad8 -714, 0xe80b6a4fdb0d0482 -715, 0xc3e8d0c13f8879e -716, 0xbaa3c52bb9413a89 -717, 0xc2d4614798d79e2e -718, 0xbbd3f6abc551b6a3 -719, 0x282e112e6bdf2de8 -720, 0x615cc8613f4d4518 -721, 0x53b2627138d76555 -722, 0x1b19126726fd77a1 -723, 0x915c0a108cd2d357 -724, 0x1061822da93d9907 -725, 0xe79aee77f55dc17a -726, 0x7b367a3165fbeba7 -727, 0x1894d6a0059bc074 -728, 0x876235ba0475437c -729, 0x2b8f64a5357907dd -730, 0xadabbbf775f4c3a2 -731, 0xf70d7e73e0914757 -732, 0x50c1494071662c91 -733, 0xae3cc90ade2512c8 -734, 0xd73f9d2b66333aa8 -735, 0x46342e130d23dc94 -736, 0x6c8307abda3d568a -737, 0x235d9a334f4eae0c -738, 0x33d0ccce19e66c93 -739, 0xd83559cfbc7acb8 -740, 0x430f65543bfcfad6 -741, 0x5dbe2eb34c5b25cd -742, 0xdcad606d1b515392 -743, 0x6376bc62812519c9 -744, 0xf292cdcbab076b52 -745, 0x5b6669c53c3e9b1 -746, 0xbd5a95d4d51f18ec -747, 0xf71d40c0b07b0a16 -748, 0xa51966e8052a050d -749, 0x7fd18ced5be2d350 -750, 0x82727df4050382b7 -751, 0x7c10a4e48f664caa -752, 0x3712f2d7d2e6bdba -753, 0x2535b833ad6b4ef6 -754, 0x420577375164ff95 -755, 0x68c40b08f579888f -756, 0x8922d2a586203dcd -757, 0xf317b95e3aff246a -758, 0xbbd1c166e380207d -759, 0x9303601189dfdda1 -760, 0xef342abd93377a47 -761, 0x499773d085e7de1a -762, 0xd204bb687ac202ea -763, 0x19ffb5b90619622a -764, 0xc59bff0531dfbe98 -765, 0x8c6d480a717445db -766, 0x8c3c030ca187e2f4 -767, 0x53f0740df18d7b6a -768, 0x1a5eed54662e3c6e -769, 0xbb29a94e32f03c3c -770, 0xdb0df407c4bbc009 -771, 0x6c0a9f4598ac0ba8 -772, 0x2e0ac7251648f892 -773, 0xb4555f7c1e3fe8ac -774, 0x2cd8ce106d8e441d -775, 0x608e38e439a239d5 -776, 0x1bb66d4c2a2ca5a8 -777, 0xc32ec47253591fa6 -778, 0xd3974f6f2b8b038a -779, 0xdcbfd9eb4a9b1626 -780, 0x8589b3e6fc1ba06b -781, 0x81f34f1da9f27f9a -782, 0xd3bdd7496dcc21bd -783, 0x7c963559e1c47305 -784, 0x5817e571d2fcc113 -785, 0x4f35fea60a0582c8 -786, 0xb851f167a0bda1c2 -787, 0xf57e13249380eddb -788, 0x570e69bf38151a56 -789, 0x117feac919f19d69 -790, 0x49ce46af93025c96 -791, 0x4220f6c18e8e1f9a -792, 0xf082699d8fd5070b -793, 0xccd31756abff1928 -794, 0xbf9d4ab46de14d1 -795, 0xf2e0be2c2bbbc823 -796, 0x6e9b495ef22563ed -797, 0x9a609cdcff6e3152 -798, 0xbbd2e5dafc83fcd4 -799, 0xac153055d6c5770c -800, 0x312bbcdd6b681016 -801, 0x3ed60c24fd5a2f3a -802, 0xc7f3b2948dcdf5c9 -803, 0x8cc631df1fac1c1d -804, 0x77f4aab62a657d61 -805, 0x2f43e30323829573 -806, 0x5b7d20ab0ef901b6 -807, 0x7fa99ec817785705 -808, 0x5c95cf94241f1e3c -809, 0xafa2d371f8f579e1 -810, 0xe4c314c4017e2e77 -811, 0xf672b575a585c0b3 -812, 0x6600a50a45d6ecdb -813, 0xe06c0d7edb63485b -814, 0xf1b45b82f4d0e8f1 -815, 0x41581d87cc1b759b -816, 0x8807b689eddf602e -817, 0x9e11d2949076d4c0 -818, 0x9f3b430319e48bb1 -819, 0xb27fa37d89396b64 -820, 0xd930a0cc6723c8b0 -821, 0x935fe6e9c7a57eaf -822, 0x184f5dba2f19591a -823, 0x513f86165d0adb73 -824, 0x4f2cd09cb85aef51 -825, 0xda66728c1901a11c -826, 0x2445b8938b33db42 -827, 0x98fd86e4b89be5e8 -828, 0x2f752d8769747705 -829, 0x2cb9b42b98ce0c0a -830, 0xf3314e0e0c57d31b -831, 0xf9c382d55868b2df -832, 0x83264a41539ec2c6 -833, 0xa2b3674f0adc1d0f -834, 0x2dd7ad1d92001e7e -835, 0xee210f6047a94713 -836, 0x71a18140729bbcfa -837, 0x415058c01e01384b -838, 0x6cc2e2079c9de72a -839, 0x8561a9093d2b5d72 -840, 0xd6c276d566895b2 -841, 0x57cb2804836f4867 -842, 0x78becdfda7fd91d6 -843, 0x4046a94c8377a3 -844, 0xadaaaa0d558d261a -845, 0x56ef182050db8865 -846, 0xbc28289519f6ebe5 -847, 0xbe7b95e4334540fe -848, 0x384b9838c105f8c8 -849, 0xecfb823fc8815c7e -850, 0xafdbbb2bfa8bdff8 -851, 0xed33653dbeb638b8 -852, 0xf4164289a7a6dc1 -853, 0x6e5cc51c2a3a8b20 -854, 0xdd59a99d16116f34 -855, 0xd48f95ba89787b5 -856, 0xacf9753586b8be7d -857, 0xc0430da7c73bf373 -858, 0x25320aec467ee989 -859, 0x5108e8f4be4f8d8 -860, 0x69b1c7d23ff502c1 -861, 0x7c08bd62caea3313 -862, 0x4285d5b8ce1d19fc -863, 0xbe03dc19cc3be0ad -864, 0x182cdb615e4d4147 -865, 0xf75270e6096d5d1a -866, 0x467b7ac524d17060 -867, 0xb0960b398a111ec3 -868, 0x126c099178f50090 -869, 0x19980d353ddb289d -870, 0xd4b394e2c0305403 -871, 0x5972d7c748938602 -872, 0x276461c9da39bec4 -873, 0x6b3a2046d6ebdce3 -874, 0x4c55d74597c27388 -875, 0x363bf469f4f673be -876, 0x9b26d4e69d36f584 -877, 0x21d441f573e56b6f -878, 0xc29509f2a1e9c4c8 -879, 0x5178088ff6e62d5e -880, 0x902f8ecd57128a7 -881, 0x479fddd275330bae -882, 0xf56ac8b6f6364526 -883, 0x4904060a896d759f -884, 0x1c0f1f4e800bbfe6 -885, 0x9b03bcb77880240d -886, 0x2f35904d9867379d -887, 0xf88a05a4dd6928e7 -888, 0xb5341282b6781021 -889, 0x225910a217522b71 -890, 0xa76bac3bf3675285 -891, 0xf19973940d9a57d -892, 0x9f6ef608ed4291d6 -893, 0xec63cdbf5911fb10 -894, 0x8a359dd4ec3b41ec -895, 0x8373d0d4e6af7261 -896, 0xfc6a14169335e7d5 -897, 0xf06ff499b6856cda -898, 0x71f5ce76943ec9e8 -899, 0x9417034d7879b92b -900, 0xfa0e3c78f47c0276 -901, 0xea9ebf817a3e3b93 -902, 0x7c08ff3d42e19a10 -903, 0x8697e5798f9bab52 -904, 0x10eb4dab88e4ce59 -905, 0xbd11bc073298b46c -906, 0xf46483b5fea2427b -907, 0xafed38960dd33a59 -908, 0xf7a00b0413eb47f6 -909, 0x4233464f10e7666c -910, 0x7ce6db32b60aba3a -911, 0xf9ae9414469308da -912, 0xf5c4e8e04c008924 -913, 0xb89c735c89bdafde -914, 0x8b815ec319546463 -915, 0xdd57dedbf1fa66e -916, 0xdc0bba0705548598 -917, 0x1ed685fb6c966b2f -918, 0xd9afc3ac4319d72a -919, 0xed7c7e9407e71351 -920, 0x585b44a509258719 -921, 0xdf9eac3020de19aa -922, 0x102102d94b983d57 -923, 0x85dbeaa806a02e79 -924, 0x4bacf4194786b961 -925, 0x32bf2fed8ab9b611 -926, 0xce94384eb215dd1f -927, 0xfd1da2a7795c4801 -928, 0x149b31c0a14f7d02 -929, 0x4e01962d69248840 -930, 0x41d509a1c742473c -931, 0x46105403c2b4e56d -932, 0xe6fca820341c56e4 -933, 0xf1982bf03572ac79 -934, 0x9f99e2fb3cc2715e -935, 0x6e3bd2ca3d50faf2 -936, 0xd0aea8d0fee1014 -937, 0xda0ededd067cc72b -938, 0x56c42899c5af28b7 -939, 0x8c4883568ff28ba2 -940, 0xad9019516b75c1d3 -941, 0x3aa1b33682aaf348 -942, 0x31187b962cf65f58 -943, 0x7f2cc27ce4c8459a -944, 0xb75ee9bbf97014c3 -945, 0x8eb8f42b9a9c3024 -946, 0x5b7dcf683a3c14c5 -947, 0xa258b18ccb7cb3c4 -948, 0x7587bc7015c145f5 -949, 0x7536427aff38edd3 -950, 0x437b33489ef425b7 -951, 0x22febd7e96538bfd -952, 0x9fefcc49d567b35e -953, 0xfd756268183d7d6d -954, 0x480df3a7112b2eea -955, 0xfd02a24b1eed9e6a -956, 0xcb3b6c96d65ab879 -957, 0x19f8b328f365f6c8 -958, 0x7d5d20e6328ef6cd -959, 0x8d74057415768152 -960, 0xcba11867467079a2 -961, 0xf86138cf35f091fb -962, 0xdb3204b36a02eb61 -963, 0x8974a7786d5f6894 -964, 0xc8445cca1175a023 -965, 0x1523bfeb2f088c15 -966, 0x4e39bb650d7c4de0 -967, 0x91c9e9ff5b823702 -968, 0x7c3a6850a7c143e7 -969, 0x131999c480253f47 -970, 0x3ac336af37f6a4e7 -971, 0xb057ae911b406d5a -972, 0xde0b70c5f9d5be60 -973, 0x93fd54e75618a86a -974, 0x3955e207acb1f65c -975, 0xa33450c2890b0b61 -976, 0xc6294720e971cd52 -977, 0x89cb13a5b1364169 -978, 0xa6fbc61118b44104 -979, 0xba0651279f93958b -980, 0x6995c30cf06ed3dd -981, 0xd75cd3472c5f86a9 -982, 0xb18d90ce11dfe2ad -983, 0xd69200ae86d53222 -984, 0xe73fc25107e53e90 -985, 0xc1edc96f67bcb096 -986, 0x587cc0fc53992abe -987, 0x2139d74bc6f3edff -988, 0x1b4609bbfa08b543 -989, 0x564e5d7acb190539 -990, 0x1099ce214921efbf -991, 0x7764cd537ccb1b55 -992, 0x4232db7dbdad3998 -993, 0x54c970b3ca338f24 -994, 0xf28c8f460244de6a -995, 0xbd37dcd3829c5a4b -996, 0xefbfe21ef1ab13ae -997, 0x6df8dfc0a865d4a3 -998, 0x5e65a5bfa3f4d555 -999, 0xf6affb932cc9f3f2 +1, 0xb3617382bfd2bb33 +2, 0x4314c03ca1908f7a +3, 0xfdbe2ea0213dab80 +4, 0x6076f6f829c64721 +5, 0x6587411cc85fa712 +6, 0x4778e74dc7f92125 +7, 0x6ada4530f4cf01c8 +8, 0xe0ddb30ce61b5172 +9, 0x2998c6e98e79ae50 +10, 0xfb8cb09917a0e99a +11, 0x7df546933cbeabcc +12, 0x972407f8132f16c2 +13, 0x6dcfab42a6d97aaa +14, 0xcbd39869fb69f683 +15, 0xaa789636ea4daf4c +16, 0xe364dbbff8064dbd +17, 0xf639489e242feaca +18, 0xa3454eb3b12942b7 +19, 0xbaa569d8f934bc14 +20, 0xbfe4a0166c493f06 +21, 0x96dec770408b339d +22, 0xc75a3b26b2702eec +23, 0x4752a021254c0915 +24, 0x35edf588263b9bbc +25, 0xa97342f217e541c2 +26, 0xea9bc6a01b4b7d83 +27, 0x93cec444361979b5 +28, 0x8ed5719f5ba9a424 +29, 0x8e1dead734d410b1 +30, 0x1f63a442ce77d4db +31, 0x3c36e0a05da986de +32, 0xc6c10658893be094 +33, 0x196ed853b1167184 +34, 0x8b06218d6a34950a +35, 0xac51e33319f103a4 +36, 0xdf47e4b0ef46c70 +37, 0xf34775455325aea0 +38, 0xf341953786525c76 +39, 0xe9b85d99c1115696 +40, 0x4432daff0305cfed +41, 0x34cc1bfed7b9676f +42, 0x87d19c7db528ca12 +43, 0xaa767030e19682b1 +44, 0xac39890dafd308ef +45, 0x92a6d833ca6a68c2 +46, 0x6626523fdceed4ba +47, 0xa609844feb22593c +48, 0x3d68f39a561a7c78 +49, 0xee2b74bafbe9a80e +50, 0x7f23ba8a58a0226a +51, 0x8900ca1c9d5550b6 +52, 0x781ff936e2d8abfc +53, 0x960fa9c6da5eeab3 +54, 0xdc316a7a5161cd +55, 0x61f6096510d22bdd +56, 0x1c1fc069b6643ce7 +57, 0x3105b8feea7651bb +58, 0x4ea8c76afedfa6e5 +59, 0x55cce3ba46b2ff82 +60, 0x32ce23a4e59a9ddb +61, 0x5d8b33b817a1e1c2 +62, 0x6861f95a5dbc833d +63, 0x1af405acc0346f1e +64, 0x4bea8e5e87e6b3cd +65, 0x6a79d9021478eb80 +66, 0xbd1512cd44c0d03e +67, 0x870719b2e322e44 +68, 0x10eaf80ea8e95a14 +69, 0xad85fdbe2e6d99ec +70, 0x47e9f8f63db20254 +71, 0x69ca77aa6a12ff2d +72, 0x385ec684f96ed9aa +73, 0x573a97f8103f9ea8 +74, 0x57a94ba1ca505197 +75, 0xcb4bbe5444b0b4ae +76, 0xcbe456413a8d1566 +77, 0x67a21dc37357827e +78, 0x992ea6028ade725c +79, 0x89cc89e9570792f2 +80, 0x2b4873ae2a6260c6 +81, 0xec8e07e9204eac1a +82, 0x6bc898204729c23c +83, 0x7d086557a49d391d +84, 0xfa16b7ede631dfd9 +85, 0xf2710cc7516fd414 +86, 0x9aef67d70498456d +87, 0x518f9fc570ea091e +88, 0xe765ca35b2293f35 +89, 0xb06015f656a5ce97 +90, 0xc0154acff67d930 +91, 0x1cb3b41de66b3964 +92, 0x41a024e712b0d577 +93, 0x921572c63007b7a7 +94, 0xb2864274d855fbb9 +95, 0xe555774f7bbf0590 +96, 0x2d15198702e750fc +97, 0x3fb422e738e347c8 +98, 0x8562515206baf50 +99, 0x13dcd174d6640321 +100, 0x2c2d1d739e2243c4 +101, 0xc41b5f458215c274 +102, 0xa6d7e86d348f1f4b +103, 0x9d78f189583149c7 +104, 0x685ac4ec5ac7c326 +105, 0xfb998afb22666cfe +106, 0x5b9df8c77816280b +107, 0x2ebad315b4a6de5e +108, 0xb70f296a67a1ee71 +109, 0x3b714a6ba151c3c0 +110, 0xa0b64d501736310f +111, 0x17f827804629ad52 +112, 0x46ed287bdea3217b +113, 0xb26d12305a6fb5eb +114, 0x184247bba474368b +115, 0x542b93986dd5ea3 +116, 0xb8a0cc8fbd9a193b +117, 0x7a89dcac9c85a621 +118, 0x48d466d072a44c78 +119, 0xada1f7e65a517caa +120, 0xf6febf549d553ec3 +121, 0x19cf94cb14dadd59 +122, 0x9087aeca4e923157 +123, 0x1afb1bb6e2fc9f3e +124, 0x6192b1b315392ddc +125, 0xedcd055d2840341f +126, 0x396cfce39b432fa7 +127, 0x183319afd1d0cf9 +128, 0x917409d968c3620a +129, 0x5868095709377c1b +130, 0x84e1f92faddbb86a +131, 0x45c5ecb0c1bf2a92 +132, 0xc5a7f84f16b52592 +133, 0xb389866b9cca1c35 +134, 0x7924255948cb4bb8 +135, 0x6b4a33d0810f1d99 +136, 0x749800294244b46 +137, 0x4ce2e9d74a34c543 +138, 0x3bf47c412961da25 +139, 0x35ecd46092b0d494 +140, 0x360703f0b4c8fd18 +141, 0xef4f039e6428f8bd +142, 0xfc63479c9833ab9f +143, 0xc660fc00994c3490 +144, 0x57a055abc0afd99c +145, 0xe83bee603058ba87 +146, 0xa6c06409fab71942 +147, 0x8ee4675a90f2eded +148, 0xef7240fbaaa4454e +149, 0x73d0378b4855e043 +150, 0x4039e6cd0da81154 +151, 0x3e4261378314b8ef +152, 0x5f891423c2a77d05 +153, 0xd57c43570ff9cc37 +154, 0x3c69a08bb46e066c +155, 0xe265cba3cabb6fd8 +156, 0xd9bed8fe0179a58a +157, 0x882255210140b153 +158, 0x7d212a20e03003a2 +159, 0x5821c48f435aa8db +160, 0x3ff2fc230e4fc421 +161, 0x7617ac677d8703e2 +162, 0x306c8cf9c6be23ef +163, 0xd7728cfebc614ab4 +164, 0xeddb425f79076eee +165, 0x76e61bc49c5b61e7 +166, 0x803610661e501d33 +167, 0x52c2968fd8b30ba9 +168, 0x56c3d2813aabf019 +169, 0x895c1923a0f7f8b8 +170, 0x2bb50b203d52d465 +171, 0x6987baec87355c0c +172, 0x1186c9e7e524b89a +173, 0xd72695cdee9d1e41 +174, 0x1aed250f3b25eb65 +175, 0x7a98d55cc9b790cf +176, 0xe3f84b1f0a3436a2 +177, 0x929f43e01cdb529b +178, 0xee439860101d371f +179, 0xc30f8f543ea1391 +180, 0x51470330a3a9555c +181, 0x13cbcd8728edb72b +182, 0xc2ff37a63d496acc +183, 0x38a775bab54c9e5 +184, 0xd3b9a106f7cae82e +185, 0x409dbb706362645f +186, 0x6756c88f065e228d +187, 0xfca59c508b33a615 +188, 0x4f1a85c2cf7f70b +189, 0xde05e1f080183683 +190, 0x58cc04c78668d30e +191, 0x29a6cdaabc128bd4 +192, 0x7fd48a7175d7080b +193, 0xf62615d9f1a4c0e0 +194, 0xc0bcdabf943a9882 +195, 0x2e17eaa18c30cbe9 +196, 0x23b0a7bf11059cdf +197, 0x980faafc56997e96 +198, 0x5df31ba1971bc9b +199, 0xf2918ccd892a579b +200, 0x863c265ba908fbd0 +201, 0x6c4d8604d73771f +202, 0x8231891e28337ca1 +203, 0xcf1bca7019e17620 +204, 0xc2914444386dd7b2 +205, 0xb2940f2f54af1342 +206, 0x5f94a7742182144 +207, 0xdd84510e416c55a9 +208, 0xed6cabbc034639b6 +209, 0x8ec7d280a1dc818e +210, 0xff9c27aafcdf6ad8 +211, 0xe4eb67cd34584e9e +212, 0xde9094e8bd9372fc +213, 0xf72c5d7a9f648bff +214, 0xab84eec6625de3ab +215, 0x31401a873557b3f0 +216, 0x3a92ea998fbe33e0 +217, 0x938f51440df1e372 +218, 0x1b8adb3266aa2b20 +219, 0x52614e3f539aa97e +220, 0x8c3910405c2b6db5 +221, 0x5678fa580938f1d0 +222, 0xaecec4c57c393677 +223, 0x25387b15ce263e99 +224, 0xa2064849456b89fc +225, 0xf3d6abe7c5ccbf89 +226, 0x71306e8ce5f15360 +227, 0x9100205404028ff +228, 0x473f2c3ee60b5ff8 +229, 0xa98cccbcb30fd354 +230, 0x150886f18c2a8abe +231, 0x73a10ec9d0a3e5b +232, 0xa04d37f64652298d +233, 0xc47af08c27df64bd +234, 0x127ec96954fef972 +235, 0xd8ce70375554f482 +236, 0xdb2e3388772bb0b3 +237, 0x843d9952b8e93044 +238, 0xb4c50aa1b3ff8dc0 +239, 0x41d43b3662be19e4 +240, 0x5de18309d9cb944c +241, 0xbfcbc63f45cf4998 +242, 0xc58ce67bd9f221ba +243, 0xeb3c7f7349d6876b +244, 0xbd38b8331d766037 +245, 0x5c0de7cf313bef77 +246, 0xe8984144d81c9ab8 +247, 0x42ba3a205f55572 +248, 0x316372b92fd6df46 +249, 0xe7c4b5535873e7fc +250, 0xec4b062406fad890 +251, 0xcb9254c0853f3bc6 +252, 0x6fbb40d1758c5a4c +253, 0xa17b63cb93c12094 +254, 0x3e00a27f4b51696a +255, 0x7dcec0f01bead947 +256, 0x1a8b827e9d0658c4 +257, 0x75929c838a9fc9eb +258, 0x165b162560d5bcc +259, 0x2320fd4ab2fbe43 +260, 0xf0ca89e97c60154b +261, 0x90a3b09348c0caf8 +262, 0xac1516105437f9d0 +263, 0x8f11e6454bea6007 +264, 0x19b8a0c5805ebeec +265, 0x3105e78b4e2f11b0 +266, 0x8c365bc66d26d165 +267, 0xdccf55c3bf85167a +268, 0x926c88470d3a703a +269, 0xe5421ab183b63c89 +270, 0x9fbcfd19c800e684 +271, 0x618b70d50ad85d44 +272, 0xcdc7b4b5f83386e1 +273, 0xb03b91dccaff6125 +274, 0xf470624fdbde22b7 +275, 0xac2f659be06a08ea +276, 0xa49f1af1a29abb77 +277, 0x5c2e94fe6a5d7978 +278, 0xf12b8c7cfa17f5f4 +279, 0xa8c4c5c917203a0e +280, 0xd1ea9aa8c49fa551 +281, 0x7363288bd7b40258 +282, 0xb3668a32f1b36dfe +283, 0xeebdb9e4377e3fc2 +284, 0xa07bf94365ce0a90 +285, 0x49a75731b3efe51b +286, 0x29af2e86886df8db +287, 0x84cab4d861631a0b +288, 0xec45e2345d9c1114 +289, 0x9e0aca51ba3aef2b +290, 0xef6db51f7d2239c0 +291, 0x6bd53260a01e4992 +292, 0x5ff887fc83732499 +293, 0xef39c88e15608f39 +294, 0x166883224e645f35 +295, 0xb296e3561ccc419c +296, 0x342081199780e04b +297, 0xdf24e8c78a472e +298, 0xa64a89e743ae2617 +299, 0x6cc623876bd66b3d +300, 0x45066f03a3fae72d +301, 0x99030d380d113008 +302, 0x891b6637052d6ed2 +303, 0x8ac4de1d3bacdd5c +304, 0x6bd4540970e747b5 +305, 0xb48125e69019055f +306, 0xefc03dc62eee31b8 +307, 0xbb61f62afc671564 +308, 0xf941c67dc61e4f9 +309, 0x58dfbb0f8cdf6857 +310, 0xfdd423db3734d952 +311, 0xddbef0ea939712bc +312, 0x64cb6c97a176d099 +313, 0x57d73985fa34a17e +314, 0xa5241bd90d5a351c +315, 0xc2669439928e2f29 +316, 0x4a00c61ffe77951b +317, 0x562532cdc210a37 +318, 0xe2fb88acfe451d04 +319, 0x8b4053716affaa4a +320, 0x208616d3e2ef242b +321, 0xf830a95da5ba3676 +322, 0xbf01348d4133f007 +323, 0xd44cd6d38e4b2c1a +324, 0xa577c236744b677e +325, 0x1a08ee02ccfaf7d4 +326, 0x94b364baa2e88b22 +327, 0x1278a7e8f3886173 +328, 0x5e5c595c284d8555 +329, 0xe81240395bfc355f +330, 0x5c72a5e76ba9777f +331, 0x30c5587516d5dd3b +332, 0x3a01ab159c61cc3 +333, 0x921a5153ca306f87 +334, 0x499d0410a755a3c3 +335, 0xe35523f8c25a0e36 +336, 0x923135834356ca2e +337, 0xf0d3cfbca4b9c1f6 +338, 0x523ba92f35c890b5 +339, 0x32791ee78e661d2d +340, 0xb8def8bec5d4833f +341, 0x8ddf479407495133 +342, 0x32af2693e93bea72 +343, 0xfe7c577a150a526b +344, 0x29f322d80b5d31e7 +345, 0x770f1c2f276aac75 +346, 0x710d900fa16454bc +347, 0xad35a054b19a6419 +348, 0xf8543705d2221c4d +349, 0x1a208f09dcd992e6 +350, 0xc6fe24f4478fae54 +351, 0x15af9b23589efa5c +352, 0x77c3cdaf72c7974a +353, 0x8b9ee62898b42805 +354, 0x24d86bd194b32df2 +355, 0x8947894a6f9e06bf +356, 0x8f74894e2ebc9e42 +357, 0x30a460a64ac97b89 +358, 0x985f3b650b19bfd1 +359, 0x6b68d65a7decd3b8 +360, 0x33ca1f7082b77691 +361, 0xe16c9da462bcc4c2 +362, 0x85512fb1e448efc1 +363, 0xd23729cdc1fbf8af +364, 0xb4c48c3dd40c6431 +365, 0xc408b5198e25d53d +366, 0x9c3ede789980eac6 +367, 0xea44b85282535bfc +368, 0x8a4ef27cc51a1368 +369, 0x92b1c10cd267b53c +370, 0xe262b216c571e216 +371, 0x9ab945ad23c45d33 +372, 0xf8a6ee8859691e81 +373, 0xb4387e4124b6ede6 +374, 0x67057ebcb0458cba +375, 0xcfea5995ea0d9036 +376, 0xf60e552368e88671 +377, 0x97a744db9ea2a465 +378, 0xf9bdfa8f7765704d +379, 0x4a092a7483623007 +380, 0xd1ec15e72770f23d +381, 0x9f4bddf29a1ec891 +382, 0x7574533dbfd85aef +383, 0xf336b164aa32c8c1 +384, 0xaecebdd3bb1f6273 +385, 0xcdee4c8c59b621f3 +386, 0x4e62a96f422f045e +387, 0x7954b5c0c33402d9 +388, 0x44284a788c4bd72b +389, 0x3f7f331379400e90 +390, 0xbe47722adce724fa +391, 0x202ec17f30c6dfd3 +392, 0x20e6bd8b12ae33ca +393, 0x56ba93c9a6aa537d +394, 0x2ffaed6a56011829 +395, 0x59bf8fb6387acb10 +396, 0x1d092715f75b4731 +397, 0x4f73c9b5945ea6c5 +398, 0x4f9965a9cef20ef1 +399, 0xcce9d598a9ee3128 +400, 0xad6bf86f41263232 +401, 0xb768dbb67c5e35c0 +402, 0xb5c06fa5f590c5c0 +403, 0x2849f01daca38cdb +404, 0xe31daf6540d3c5a2 +405, 0xa462464c813059e0 +406, 0x98cd0da9a864a13c +407, 0xa0bf6269bcb1c79b +408, 0x354467e29dd2415b +409, 0x8760ca9ca2ed96c1 +410, 0xdcbc0296a9d243e8 +411, 0x940f0679c02babd0 +412, 0x4f389795e70c9b32 +413, 0xcad57ca19c578c20 +414, 0x346870e71ed575ad +415, 0x4dc47ca3f25bc1bf +416, 0x636afe20b8e9f185 +417, 0xb47b4b4dbf6ec559 +418, 0x8634686a6ec85170 +419, 0xc176c9709a40fdc0 +420, 0xaf830009e390dfb0 +421, 0x65cb55acd3653031 +422, 0x52d53d142c15219b +423, 0xffe9258ae4b63350 +424, 0xa118cfbbb64e3f6e +425, 0xf0aa49900685c7bd +426, 0xf4a63180c7a493e0 +427, 0xb219297f315c3905 +428, 0xedbe04b3e65cee75 +429, 0x17578b66c9422dcb +430, 0x93341d13d6f3f307 +431, 0x4cb05e69da41bb0a +432, 0x1f1dad0ac8c3b625 +433, 0x4cc0d69392282fe4 +434, 0xa415bcab7a9e9030 +435, 0x49c4bce139b17cd7 +436, 0x70921ec48102ba98 +437, 0xcce784ad8ecc8ef1 +438, 0x1394434e6983851 +439, 0xdceea9694050de81 +440, 0xdd34ce31271e0733 +441, 0xaa722f329463f189 +442, 0xca65b550f35dd0c9 +443, 0x1477d0711156ff76 +444, 0xeff9d7e1e525c056 +445, 0xf425a4a41487a26c +446, 0xd7a62c18f2ce9451 +447, 0x178ad1414c520698 +448, 0xd5fb19755b8a9cd3 +449, 0xf9b662ac336df748 +450, 0x3ab374b95c09392 +451, 0xb1017e23e64343a2 +452, 0x4e38eaa252f0eda8 +453, 0xe50e9e51d4b9abce +454, 0xaa5d9bfb8193c02c +455, 0x823a22b374b70757 +456, 0x31cebbf89930801b +457, 0xd7c29187bcea4c72 +458, 0xe9118fc76c45cbf1 +459, 0x9c71d746e81ad2de +460, 0x61546ce34ed37e5 +461, 0x93cf2b2f08a9dd70 +462, 0xaa8a0e918d246f1a +463, 0xbd35895f4913143c +464, 0xdfe98084bcf724b5 +465, 0x3711d1a09d3b438c +466, 0xef7a4589307c37f9 +467, 0x174de3c95aad64d +468, 0xa66127748de17435 +469, 0xaa7789614da98e6d +470, 0xa01a9a6570b63f02 +471, 0x52e4422529cdf289 +472, 0x5fa480a033fa2eaf +473, 0x8d950f2a0362d44d +474, 0x264fa25f7b50b19e +475, 0x4f2ed2872e35635e +476, 0x1173eaed49ff03d +477, 0x7cbde5b17f7541b1 +478, 0x80913ce7ba0fd00f +479, 0xae85c98e607af8ab +480, 0xd4349f0a1a724b17 +481, 0x436510b9fdbb00b5 +482, 0x345d25f181b23831 +483, 0x360875f99d1dbc3f +484, 0x77657a493413286e +485, 0xdb45294b3f8dab13 +486, 0x25e84d1be5f5c6d6 +487, 0xbb44ba55be3f453 +488, 0x7d7b2c5077ddb248 +489, 0x4c7e02c08f79a63f +490, 0xea589769295ebac7 +491, 0xcf1159ed1fbbabb2 +492, 0x5f0c199a69956db4 +493, 0xb2c190830b28ba75 +494, 0xfef7b55986f49a19 +495, 0x961eb7b425de477b +496, 0xdb31045f05af950c +497, 0x13bc7a5600b306b9 +498, 0xe4834efcc7d8515c +499, 0x6d3ebda0630a9e64 +500, 0xcf453a9b686cbc0 +501, 0xe1048db43e9dc5ec +502, 0x95b3b95608ff12fe +503, 0xdaa8457f1d3bca37 +504, 0x3913e8473f5593ba +505, 0x3afceee33004c5dc +506, 0xd117393f5e9d11f6 +507, 0x7f462da9314f76e +508, 0xa4fc522c19f1f8d6 +509, 0x7429b79b76acdcfd +510, 0x5a570cb8d216a730 +511, 0x705c4c4af10c7ac7 +512, 0x4abf3a808087344e +513, 0xe6313ab9845d433c +514, 0xb038e24fbbfc7716 +515, 0x80a25d4531599d7c +516, 0xb2b75e488f81693b +517, 0x43b8d27a4dbba2a9 +518, 0xa611ff50d23f05e2 +519, 0x872da217d6fa41a6 +520, 0xb153855cda09b36f +521, 0x3c6f5d7d21da31a7 +522, 0x59a63c7ad79be63f +523, 0x27a4679e83422368 +524, 0x4e8bc4d771b0feaa +525, 0x6719469e9cf2c3d9 +526, 0xb56b708a9a915da5 +527, 0x2594e558e515d19 +528, 0xd6df1e4a0bf1b153 +529, 0x4f7f25d38191e1fe +530, 0xaaaf850ad5e538b0 +531, 0x6355175a813e200c +532, 0xbe7544f56eef5ae9 +533, 0x5c516d87bbf779cb +534, 0x23c180f962a3d2a5 +535, 0x5cb1ac1c4261b281 +536, 0x4717bb3567432de1 +537, 0xeb1285580fa935a0 +538, 0xc50894350d82d33a +539, 0xcd0e2cfea37c3245 +540, 0x298bc40ad881a2b5 +541, 0x466df434870604fc +542, 0xbc1eb2d8ebbd351f +543, 0x357534396e12e369 +544, 0x305a159545ad695a +545, 0x63775f2479bae51a +546, 0x44e266968147590e +547, 0xd733336da0cfd6b9 +548, 0x7b1668635266025e +549, 0xe25f2c506843c3de +550, 0xf9635d39029105fe +551, 0x4098dbd2e7b717fe +552, 0xd58848e50b96b32d +553, 0xdf776a82ade5f937 +554, 0xb86fe57c82d76cf3 +555, 0x8cb4f08fb1f46b4e +556, 0x5df5b1c00ab261ac +557, 0x6726d97935f08d31 +558, 0x4cbc02697842c6ac +559, 0x6c0440408a22bcae +560, 0x2327f06b5ef97cf8 +561, 0xabf95d4d77e37c76 +562, 0xc53b4d7aa97f77d6 +563, 0x6964842fd4206b42 +564, 0xee45d852faa5932a +565, 0x607e303bc41e73e8 +566, 0xe604d0952299ff3a +567, 0xd762802eed4cb935 +568, 0x4cf13e77ae1782aa +569, 0x6780f1ac226eb1e7 +570, 0xc102e38a0e8e8199 +571, 0xb97f0632dec2edb1 +572, 0x43b1a8890a987c2a +573, 0x5603f8d9115551a +574, 0xdd523847a2d2346a +575, 0xd9a6c2e9be51ec7e +576, 0x5c87bb42ff344def +577, 0x1c08b83d807a9322 +578, 0x6c79b279737cd049 +579, 0xc75ee98ecd59cd3c +580, 0x318284b03e77d76e +581, 0x6737a1e79456ce1a +582, 0xefe096a77d952f55 +583, 0x37f780c27a9fdd68 +584, 0xfefed1b3b932191e +585, 0xdf552be0dfc09adf +586, 0x4d210f71c1ccfe6a +587, 0xf524993a9f48c96e +588, 0x6fb8c3c46cb1e951 +589, 0x2ac8c28e67eb7b03 +590, 0xefcb311d060d2897 +591, 0x675c6ca4aba62734 +592, 0x1f5f1df09191b5ed +593, 0x177d32b3b4fe46da +594, 0x58f48456e4a88cf2 +595, 0xec0233251bedcbae +596, 0x11046407a9ce0c19 +597, 0x50eccedfa2531ef9 +598, 0x5769c9369f18c53a +599, 0x879442d615c8f67b +600, 0xc7aee966f982a0a7 +601, 0xaadf9a353e6dffd +602, 0x216d2fcfe81b00f7 +603, 0x8b17b3b2a61765b8 +604, 0x7cc969d82c53763e +605, 0x1b1a5d88afda0c8e +606, 0x21ea1e785061959c +607, 0xbbbf45849572539e +608, 0xf84972b569d342a6 +609, 0x85952fc81713400 +610, 0xf6bccc50b5741a48 +611, 0x35106a9ef28f5be +612, 0x785370b833caca28 +613, 0xc6c5c3d1bbe5b4ef +614, 0xda7658fec38bbb8c +615, 0xd3d1e9de94c6f41e +616, 0x73ad91859892dd7a +617, 0x35621a8da5e3fd19 +618, 0x5530b00cd5c63fb2 +619, 0xfa36112a09c088cd +620, 0x302b7f4fc815cd73 +621, 0x1fa4adb717689692 +622, 0x3a15fd5eb37c731a +623, 0xcc854934e21d4cd7 +624, 0x1d11465a34be290e +625, 0x213b3e59f10b1d60 +626, 0xf923efefe3fd28b8 +627, 0x81b56a961626ed7d +628, 0xe4f41f8c283c8fba +629, 0x374ade85b0260e4e +630, 0x4cf71f967d36fcca +631, 0x705b52b4a9d5d174 +632, 0xdc6f883cf909c428 +633, 0x44dd73ed064e8a3a +634, 0xdcff5a374c2641c1 +635, 0xe3177de93b2197ad +636, 0x71f40cde55876808 +637, 0x4c12e600bd6a1b3 +638, 0xc3940e86b962699c +639, 0x133569f533cf1540 +640, 0xcba6db36e8054239 +641, 0xc7c92f14ee34a962 +642, 0x133c8d42f4690453 +643, 0x2a62456f39aa3030 +644, 0x35354ef813ee1dec +645, 0x35e10f4c2f2fb795 +646, 0xf105e888f10c8397 +647, 0xaa22e206ac7652dd +648, 0x65121135905afd4c +649, 0xe2c49866de9626ca +650, 0xeb6ae66e1a605d02 +651, 0x7379ba1f2f16b81e +652, 0x4a3a91e2f22d4d19 +653, 0x30e4af3cd5e5a24 +654, 0xac59e67a483fa52 +655, 0xc4f027dd48c1e37d +656, 0x91263160b58e9e0d +657, 0xc7672b7fbd4ef6b2 +658, 0xf3262da8a7645caa +659, 0x7a5f4990cab96f40 +660, 0xcec55da0937d86a4 +661, 0xd25017295c98b613 +662, 0xc2c9ad08c34fd189 +663, 0xfb6ca6018b1e019f +664, 0x480ee3cc62324c8e +665, 0xab37c56a10ab0519 +666, 0x13fff4e20b1eb15f +667, 0xab25dc0f003e940e +668, 0xdbadd5f2b73aec35 +669, 0xa7b4d6770d19f43 +670, 0xd28144880c1c5434 +671, 0xa435c41dce914dc5 +672, 0x9883a2e3cddd7ad +673, 0xddb29b179c922b28 +674, 0xed3f6669842e0c39 +675, 0xb663238d46b213a7 +676, 0x6346ef1606873452 +677, 0xe7923ae257befe28 +678, 0x848ce090039c77 +679, 0xb77a6da428f4da49 +680, 0x6d9acffa8252ae03 +681, 0xd90d55fd8f8abf1c +682, 0x28718a78a031f802 +683, 0x8305f9005a1b1d6d +684, 0xd065b82167b53418 +685, 0xec65275154e9da5c +686, 0x292c7a783bc2dc04 +687, 0x71aa213998c2c31a +688, 0x114032c57e9fc4a0 +689, 0x67c3675a88faa9d3 +690, 0x7813f653eef4d4fc +691, 0x50004f43e4f4c43c +692, 0x43d3ac5d63714a93 +693, 0x4142e7030323e77a +694, 0x5da693da8e656d6f +695, 0xac696f7b0818c8b +696, 0x910b5df8803af3fb +697, 0x8d89168d50ded4d6 +698, 0x37c31ab0b2635495 +699, 0x66d97616af36f929 +700, 0x2ada02a3c0389bda +701, 0x62eea272c6334ef +702, 0xc8afae44f45ccc49 +703, 0x4978910fb289af22 +704, 0x64590f6a489183f9 +705, 0x594837052d1ee56f +706, 0x8553a88dd84e460c +707, 0x5c11e1d61832edfe +708, 0x7d5b6fde3c05ef8d +709, 0xfaf96bbdea0d6f11 +710, 0x2112b6f8f25fc3b7 +711, 0x6ce347dc5bd8d9f6 +712, 0xb072e2c4076aa185 +713, 0xf4162f4ab453ead3 +714, 0x369789462fc197c7 +715, 0xe732c5b207c55f3c +716, 0x4689ce674194c32c +717, 0x6bcf28130ebd7bbe +718, 0x4d7a25def10edb97 +719, 0xc4a2283e380f5239 +720, 0xab31536a95f7e336 +721, 0x50c1ecd9e4dec3e4 +722, 0x1bbea15462cfde71 +723, 0x1e7c73d56d6e939d +724, 0x7c46fb35982735db +725, 0x83c23f93c4221593 +726, 0xddc566e8005e0e6e +727, 0xd0551a666c088325 +728, 0x2c57b590ab686557 +729, 0xf2e9351a14724fe1 +730, 0x45d25cf2ebb2ee0d +731, 0xbe23d2a8fc7aea1 +732, 0xc721cb7b65d8dd7b +733, 0xe6642683775efcac +734, 0x6c29ca0adc0a83e0 +735, 0xd0de3128954b2eef +736, 0x7abea9b318f9a544 +737, 0x3a63475d59d64b22 +738, 0xb804c9cd589c817 +739, 0xfc4f880ac9dbc246 +740, 0x414d492c8870732f +741, 0x3ee15c71660a8129 +742, 0x57f4ab3a25da00eb +743, 0x5a1d89d6f9eaa29f +744, 0x60139567a3d66313 +745, 0x5759ec448bbaba05 +746, 0x44d3088d8cf1cc1 +747, 0x77d8019fadba610e +748, 0xcdc729417b13904e +749, 0xdc77421f8b2bfb0e +750, 0x47ae0c4222bc1d4a +751, 0x22768d4b89156cbb +752, 0xa60d3ef97eae8ddb +753, 0x7aa22493dbfceff3 +754, 0x2ee0ee06bf9a5fb +755, 0xd54b7701d7afc96f +756, 0x1aa49ed985a53efb +757, 0x97d6fad17caacdd3 +758, 0x1b2f6dcd1d10fe +759, 0x46347f5bcca0f422 +760, 0xb9dc35c224242d3c +761, 0xb5dd657190fa8a03 +762, 0x50ff9434c7862fae +763, 0x7a05cd5c25bc1209 +764, 0xd5aa141a498560a1 +765, 0x73c62b8d0206e8b1 +766, 0x740f369af4ac9f51 +767, 0xe7479d9a0716b94e +768, 0x8b3d0375452d633 +769, 0x6ed58c4d905dfe37 +770, 0xbefb7f1e9c79f6ed +771, 0xe2cd7ee311d7a8c7 +772, 0x932cfb8178492b88 +773, 0x8e39205fbe47711c +774, 0x149ea35973cc055e +775, 0x96b73b6cfad8ad7c +776, 0x572898ff1f967eef +777, 0x795e8172b62cbf69 +778, 0x4e3d34c5bb921c28 +779, 0x7a4c623c7295f4c3 +780, 0x15b7ca7ef7179a7 +781, 0x48340589636b223f +782, 0xfcd61c186913a7aa +783, 0xf4f7f0cb49d78f5c +784, 0xb9591798ca218218 +785, 0xe304bc438ae109a6 +786, 0xe65890c4bed537f4 +787, 0x54719032d537f085 +788, 0x927bbdd2931be349 +789, 0xfd4a852025d02c14 +790, 0x915a7c2bc713221c +791, 0x4adac4a960ecdf9b +792, 0x58133bde7f0edb25 +793, 0x73d00fa5f091794f +794, 0xcb2fe411bfb56cf3 +795, 0x54a4f66f2c5f6220 +796, 0x125bce09ee493ea +797, 0x766ba624e5f3b266 +798, 0x884478527221bba1 +799, 0x8a1920c18ba6676a +800, 0xb0c08f7fbca3cdbb +801, 0xd3b570c49c774405 +802, 0xae4a55264d8e012f +803, 0x91a25b7c5e5872a9 +804, 0xeb65375cda8296ef +805, 0x149f98de1b29f459 +806, 0xe00a81c67b8ba093 +807, 0xbd7da1f6c6be49f3 +808, 0x4ad7c327a630b482 +809, 0x7efc93c60449206a +810, 0xff182d272189a04c +811, 0x4e7892e8adc82e19 +812, 0x1327926bc36b7f99 +813, 0x9b6a8085d12fca4d +814, 0x34a29cb661d313b9 +815, 0x7b3398923572c6a4 +816, 0x8b3ff461c821a464 +817, 0x8e5581286f82448e +818, 0x82a8d223a7b6937a +819, 0x1a0c750d6029237a +820, 0xf19a0a7f578497a5 +821, 0x2e6a85391da4f651 +822, 0x98676879af572d0e +823, 0x50110f1f738507a0 +824, 0xbe88faea0d4f8cf4 +825, 0x183bdc54555acc08 +826, 0x1d4dd72e0c7a82f1 +827, 0xef500f1dd19059f1 +828, 0xad98db5c386d33a8 +829, 0xa17bbcaea00a9361 +830, 0x8b8967126839c74d +831, 0xcc9d0e484a9b1dfc +832, 0x4216966d5af86872 +833, 0xdc3f8b825876e2ef +834, 0x3ef820c11b63f9f9 +835, 0x78da1c113cdca011 +836, 0x7f74559d9177c87 +837, 0xfde51ee31804305a +838, 0xc491d970fa5ce907 +839, 0x89b0ff390723a6ff +840, 0x7452028822f2d7bd +841, 0x3e55cee332d78047 +842, 0x5dabead1e04596ed +843, 0xc4e878a6ba18aec7 +844, 0xa785fac229f7f353 +845, 0xd95155479c867ad0 +846, 0x678fdb174e3774e3 +847, 0x54106e733d27b887 +848, 0x60bdc0fa294764ec +849, 0x55f1d4270179bd54 +850, 0x80165190a3df59ba +851, 0x81b128a7508d2174 +852, 0x831d78b199fe132f +853, 0x80ee7eba239ed866 +854, 0x359f1906550f62bc +855, 0xe293dd490df5f745 +856, 0xf3362af4b0de9c01 +857, 0x9cdc46fbc7f9bee8 +858, 0xe577a13809850692 +859, 0x1490ed2b4ed8ce8c +860, 0x63b861e371a125f4 +861, 0x49916e67be281c2e +862, 0x1a3a8999e60fe603 +863, 0xa373c8ff642e222b +864, 0x8112bea03196843c +865, 0x29c507a4ee61f7c2 +866, 0x4eedd845cd786583 +867, 0x1d9bdbe51c1aa7c7 +868, 0x3e5d043d5ab768ad +869, 0x8a3c0e9801e39bee +870, 0xc49cd378bfb3c516 +871, 0x1b9ebe1f63af91d4 +872, 0xe44afa8dcf0f28f5 +873, 0xf5a7ab4f9a8d8cc5 +874, 0x8ba7cba3af03234 +875, 0xe79397a55e04d4b2 +876, 0xc49014ba09442ad4 +877, 0xe58a5dd949723f3b +878, 0xd67c781ca27169dc +879, 0x409f1435da244c9a +880, 0x7ec9df0b04c17696 +881, 0x8a34c51bafd6e390 +882, 0x2f60cc0ebb4a781d +883, 0x161283264abcb573 +884, 0x9c9db4bf55a46c8a +885, 0x381e6106ff6053cd +886, 0x6e8fd5a7b8ed1c18 +887, 0x89d0da00aecbae85 +888, 0x1baffa4542d298f9 +889, 0xbf53f2e1dc44d359 +890, 0x4c31d9bd148120a8 +891, 0xc36be4d6404a748b +892, 0x400584c614a63b32 +893, 0x6622b75443cfa5dc +894, 0xbbfcae44c8eec3d +895, 0x28dbf6790e9ad12b +896, 0x7779f5d56f2613c3 +897, 0xd221ad0b4c565a5f +898, 0x4949752332a98b9 +899, 0x5bd9931a164b2717 +900, 0xb5108565cbec069b +901, 0x2e8491298f41ecd8 +902, 0xc94483fba700a620 +903, 0x7c1299ec45d1e22 +904, 0xf37c3a7e7e020358 +905, 0x3635565fc484cbf6 +906, 0xa93b65e210af2a2b +907, 0xcf18d773960a3667 +908, 0xa7529ce40290e679 +909, 0xd539e8afab9ff21f +910, 0x44fa456fc4e2908a +911, 0x138e0dfef16de572 +912, 0xb55ac8aa42abe21f +913, 0xc8a7a9ed90a4920a +914, 0xcc0f0dff8f4f1fc0 +915, 0x78c99cc82195feac +916, 0xa7669ab9998bdb89 +917, 0x2bf510028d6ea80a +918, 0x8995287d2a60326c +919, 0xb3c5676e9772daa7 +920, 0xf210121d1f5cf3cf +921, 0x3ec0fa808fe50e83 +922, 0x42f5269fd9717a58 +923, 0x7603ca20951ebe1a +924, 0x7f75e4c3afca107 +925, 0xa08af524629c434d +926, 0x1d144241418f216e +927, 0x7cabc46fab0dfa3b +928, 0x317172e8fe407c21 +929, 0x2694bf3be80d8b3c +930, 0xdf18b4db02b875c5 +931, 0x5df0cb415bc5a2fd +932, 0x954386c3df63e124 +933, 0xf0ad49aa400ee528 +934, 0x2a941df25bb38eb8 +935, 0x3b43af03f2d3eefe +936, 0x7a58932cec64555d +937, 0xabb56ea03deeaec1 +938, 0x33673826e58f9a52 +939, 0x8cb6fb8e42cd9f80 +940, 0xda88c439fe3b9dbe +941, 0x31cb50c4a69d5883 +942, 0xe2164f69f02e57e4 +943, 0xb6ea04dd0ba2811f +944, 0xb3458306841de334 +945, 0xbc6cd1a3cf526a19 +946, 0x9424b50438e687e2 +947, 0xa668fa546aecdd82 +948, 0xb8783bd3623d86f5 +949, 0x6d4341f1dd170d5c +950, 0x1202c1b457913af9 +951, 0xf2b532602b908de1 +952, 0xb15f6354e6482108 +953, 0x4a542e16c973ef2f +954, 0xcef0b8ef4bcbbf64 +955, 0xdd7090f21726ab28 +956, 0xd53de858192a0094 +957, 0x58e723302bf4d675 +958, 0xc3ffb98f745409ec +959, 0x5489e4fa52210035 +960, 0x3a6a10b142c74d43 +961, 0x69436c7b12a2c4c7 +962, 0xccecdcc046f76f03 +963, 0xa6b9793a0660fc0f +964, 0xf114cd63b38756a5 +965, 0xa44ac409c2246f07 +966, 0x65dd5dde54b6aa26 +967, 0x5df21b90d999494a +968, 0xafc3d89336a6d356 +969, 0x1acc23065a7ba8bd +970, 0x87ff903278b23e2f +971, 0x58e4a44f7e4c012f +972, 0xb2eb460bab7744a1 +973, 0x9b1aa5a17ba581c2 +974, 0x90c87a15edc021b4 +975, 0x43369d9b481b28a5 +976, 0xd05dc8b00763dc1 +977, 0x40f058f20d77b5e6 +978, 0x2502c9829f78bdb4 +979, 0xa5ef6729f601b2d7 +980, 0xab49116e5d404023 +981, 0x6b77c686cd653da8 +982, 0xd99e324ce1468143 +983, 0xb338c64071fd5469 +984, 0x94f67b1e04fb4267 +985, 0x16f34d11e280c73f +986, 0x9a6c4cd947bed4e0 +987, 0xd1bf20f05cd068f0 +988, 0x2ced63b15eaa27e4 +989, 0x95989123251dec6a +990, 0x38906e5a3cb4fb01 +991, 0x4b02f03a01180ba3 +992, 0x67d5842c2b13960a +993, 0x45dc1d0f5981374e +994, 0xe6dbf0961817185a +995, 0xf5717f537c683578 +996, 0xf7a689617ffe5002 +997, 0xdbd1595a8ec1ac24 +998, 0x545db9592b492be4 +999, 0x9e1085dc2c3335ed diff --git a/numpy/random/randomgen/tests/data/xoroshiro128-testset-2.csv b/numpy/random/randomgen/tests/data/xoroshiro128-testset-2.csv index 6c513476bbef..2de341ecda94 100644 --- a/numpy/random/randomgen/tests/data/xoroshiro128-testset-2.csv +++ b/numpy/random/randomgen/tests/data/xoroshiro128-testset-2.csv @@ -1,1001 +1,1001 @@ seed, 0x0 0, 0x509946a41cd733a3 -1, 0x885667b1934bfa -2, 0x1061f9ad258fd5d5 -3, 0x3f8be44897a4317c -4, 0x60da683bea50e6ab -5, 0xd6b52f5379de1de0 -6, 0x2608bc9fedc5b750 -7, 0xb9fac9c7ec9de02a -8, 0xc1942c64262d8742 -9, 0xc2c334fa4c2214b4 -10, 0xe53cfba26ba5ce93 -11, 0xf01f0c9d5398a979 -12, 0x1bfa2ef194eeb86d -13, 0xc9df57572868239 -14, 0x728e35871474105a -15, 0xdc7b1e93de9e112a -16, 0xc4d930cafb32002b -17, 0xf18b0bd68577e055 -18, 0x4929ceed7e690239 -19, 0x3b7a547b356b29d8 -20, 0x660f1cebb7affd72 -21, 0xf850e6052cc5f5c3 -22, 0x931512b017c71f1 -23, 0x8d88b7af3b8731e7 -24, 0x3050de537e8e84e0 -25, 0xc917230b8bd3d552 -26, 0xf58da0814356b478 -27, 0xcfc06b804972be32 -28, 0xe3892682eff28645 -29, 0x55bc734a03ca4fa6 -30, 0xe2f7700a020152b9 -31, 0xcba5a308a8d40969 -32, 0x928b63592b6b2f55 -33, 0xa372b4e0293d90c1 -34, 0xd73e00b1c0fdbb6 -35, 0x43c712d398019cad -36, 0x295d994760c6501b -37, 0xe94236abdd256f1d -38, 0xed4566687d847ec0 -39, 0xd3a838dfcbcb5df1 -40, 0xf4ac54b3d79aae61 -41, 0xcabd8f089de74dc8 -42, 0xd58e132a2cd64b6d -43, 0x4eb8bc55f8993dd2 -44, 0x8e4ee152013579ca -45, 0x1aa7c7e058e02a75 -46, 0x5038184ea8f1dfbe -47, 0xa9af7da9879e99ed -48, 0x267567fe1128a585 -49, 0x3a3d637084865189 -50, 0x35179207577f3a88 -51, 0xc323e40ec505a4a7 -52, 0xd2ff171e3203c51f -53, 0xf524706a4db15f35 -54, 0xbff297a90126dd1c -55, 0xec7517f97c47dbf7 -56, 0xf56604fd9a8a7f3e -57, 0x2a63c3bb1635de13 -58, 0x9c22f64a9b9acfc -59, 0x6fc94c63f4e1b311 -60, 0x955820d474d00924 -61, 0x5a4d25256934ab74 -62, 0x95ea0cf2b73da09e -63, 0x8e21647894c89a8d -64, 0xa6ffd9037f6627ae -65, 0xca5d03082b0007fd -66, 0x2ee116ac7bdd65ce -67, 0xa9e6e172042fa80e -68, 0x4763c82d6e7c3d8d -69, 0x325169a3ff49a8fe -70, 0xe0be054ea126080c -71, 0x4ccc1794542607ba -72, 0x58c480dddafc29d4 -73, 0xedab421340a8d4d -74, 0xd28d8f3c2ab241cc -75, 0xb2a89fabba9566c3 -76, 0x1b12fc8b30a80b49 -77, 0x65e178e0065959ef -78, 0x4adc931b03e25f55 -79, 0xefb7b250b854feff -80, 0xe024be0a14bf3da2 -81, 0x60c2285324a5a642 -82, 0x280dfcde16655ff -83, 0x18c2cbf4c0ba9bb0 -84, 0xcbeea642049c68c -85, 0xa1b19b0b60833fa9 -86, 0x10f72a22ef81e27f -87, 0x5cc3db165dde75b2 -88, 0x947a3c40223e6bd0 -89, 0x5d469f487abb870f -90, 0x1b1f4fea711c039d -91, 0x63b22d9e9616b06c -92, 0x689aa9d9808ffa7c -93, 0x2164f59dcc5f3e03 -94, 0xbdfc99e1f2c1193b -95, 0xdc9e85a6a6b8f61e -96, 0x11ad0ede8657e961 -97, 0x73a69427c838bafa -98, 0xfa4b98f49849cc62 -99, 0x5ccb852e4e18aad9 -100, 0xae102d1e06ad3569 -101, 0x4be41a104f8d8463 -102, 0x723f50acab4314fc -103, 0xd3b7b694a6bb6c38 -104, 0x8bfd1fbedfb8f092 -105, 0x3d5d9aea4d80f37f -106, 0x28cd19af64bfc553 -107, 0xceba7e81e5ec8edc -108, 0xd8c0513fca3ca719 -109, 0xfefef4fd2a0896f0 -110, 0x1aa7320084a97662 -111, 0xf63c0bb8fdae24ea -112, 0x497a5e9d0a13c0d5 -113, 0x37fabc943a07639 -114, 0xb5be9f1d19096cc1 -115, 0x4385acd2ed447c52 -116, 0x8e146c6874b731fd -117, 0x553c3c72c9e05a64 -118, 0xb9cca017a8d4be34 -119, 0x8f8e09bbd56564ef -120, 0xcf6da1a96df67f67 -121, 0x5882a27646d3189e -122, 0x1554cc47896d846f -123, 0x105600be06e72171 -124, 0x95a04162a7ec3791 -125, 0xadeb00515f0d6be0 -126, 0x22ed3d1ca5ebc008 -127, 0x312629837e981334 -128, 0xca916e4cef410dd2 -129, 0x18556a16bdff0e5 -130, 0xfab80417581d6927 -131, 0x40f7ecce118881b5 -132, 0x6a12fe0d0c5f3ca2 -133, 0xd3e2ba4104a669f5 -134, 0xdeb3d714e1fd921b -135, 0x32cc61dc107d240a -136, 0x1a79efae30dbd860 -137, 0xebd6029e65fcefa9 -138, 0x94289c890d17c9b4 -139, 0xd91bbe374cb9f243 -140, 0x3352bdd3eccaa300 -141, 0x5cc9a4bf3127b238 -142, 0xebd9f454d96adb59 -143, 0xd5f61261bb7089ff -144, 0xa743f21be20ce5f2 -145, 0x3d2a78d45bfb1da9 -146, 0x9ebbad453112c987 -147, 0xff48b7b97e3f597b -148, 0x2b57be29ae160a9f -149, 0x90df488fada68e76 -150, 0x785b4250ae46cc0 -151, 0x1c4fdcb6c66db255 -152, 0x3567f33a12172e96 -153, 0xc173a5f010dbe48c -154, 0x859eac8b59dd2bc0 -155, 0x532809d8c8b5378b -156, 0x656f93a00428ed0e -157, 0xd4ee7e2199473a09 -158, 0x9bc701f16ecf35a4 -159, 0xcea39cb296d32304 -160, 0x43fbb2333d392310 -161, 0xc9d66a1062247d -162, 0x271a83a113c42b2f -163, 0xee17f7585ab05734 -164, 0x5e98cde55d0b8ae9 -165, 0x488cc07f036165b3 -166, 0xd78481d7416f6724 -167, 0x681436c7434b6260 -168, 0xc53bd2c997a04ce5 -169, 0x61b5951080b80e26 -170, 0x48f285546280fec1 -171, 0x87ff976327bf74ce -172, 0xc10c08c9bc8b05ee -173, 0xa62f879a73bf12a2 -174, 0x31d7cbb6f9c1acf -175, 0x3e522645e518ee29 -176, 0xb85967a95e811cf8 -177, 0x99f8643751545edd -178, 0x3f962076f920dd9 -179, 0xc92abe52da7ed89c -180, 0xc1fe02e7dba484c9 -181, 0x7904149975239b19 -182, 0x5bfaad7ac409b74b -183, 0xb915e6eba7685946 -184, 0x8b2291b29fd71d66 -185, 0xe57e5709ad0bd967 -186, 0x3fe55bb3338f0f1d -187, 0xf41f8f7a981c05d6 -188, 0x80d3d9160712aa45 -189, 0x2da872bdd8bbffe7 -190, 0x6698441241fe0a4e -191, 0x4870fc969dc6676c -192, 0xd420fc68814fe867 -193, 0x6aa0500b9d8bacb5 -194, 0x55078d31633dcd47 -195, 0x6d758a56c80bd405 -196, 0x122149ae571cb397 -197, 0x22d1134c99ac507b -198, 0xe7d9e27ae05a47d1 -199, 0xd18a73dc45e5a290 -200, 0xb5bc1909e08803e2 -201, 0xe9a1e3ee93f2e109 -202, 0xf040a8f79841c101 -203, 0x9a705a608899152d -204, 0x4f7783a0dab4290f -205, 0x11c5bad24bb23af3 -206, 0x58545a19a22fb881 -207, 0xeeaf5ab573077828 -208, 0x9e036466fd858142 -209, 0xef70bf26fdd6bc94 -210, 0xcc3a2971056cb9f7 -211, 0xef120c86e84d643f -212, 0xa499226ab42f6d7a -213, 0xa85cae4acfa0a29d -214, 0xc8280371e2c25d89 -215, 0x246336f7e63ac4e6 -216, 0x76561f7777c7b915 -217, 0x704f83c71583f0b8 -218, 0x489db8592a76cd3b -219, 0x268d584af17550c3 -220, 0x350e989762428fe -221, 0x6857adc12d13f1bb -222, 0xde62c7d9517260e2 -223, 0xc1f37ee8baac988e -224, 0x714732f71cdd5374 -225, 0x56f01487bfa58c5 -226, 0x5163b23d41d95f14 -227, 0x745150434b747a38 -228, 0xdcf7cd6c6b14b1b -229, 0xd853cc6bc2580f81 -230, 0x693562e66b579775 -231, 0x8f15d6369dbe6678 -232, 0x464c1791098ad19d -233, 0xeeba6610f16ac2b9 -234, 0x3b307cc3c5bf5859 -235, 0x7e82177c4dcb75e0 -236, 0xae5978c33dd3e817 -237, 0xec3c0128360b0b2 -238, 0x2c325b630e904749 -239, 0x237ff1d19b4e7ead -240, 0x3c82e47b67a33956 -241, 0xf38b46203355a168 -242, 0x4df09cfda8d5774c -243, 0x4b06980b33ad6226 -244, 0x7afc1e940df03034 -245, 0xaa093355c596ecb7 -246, 0xbbb5100165d1445f -247, 0x599c0f30608a36d -248, 0xd35999534e29986d -249, 0xd0cae757abc97c36 -250, 0x9ec9f2c24bbe3b70 -251, 0x76b96e93352c2960 -252, 0x4dd3acf1c01ae06c -253, 0x71ebb829cb09312a -254, 0x3234f4c24cdbb897 -255, 0x9b0930936363bc6 -256, 0x2ede98b9aacc3672 -257, 0x7388672bfb4c92c8 -258, 0x53011e6a80763bca -259, 0x69eb6ca56f23129a -260, 0x59d98a723f847ad5 -261, 0x234af2de04ba218 -262, 0x589b028bf0830748 -263, 0x525da4a281c641e5 -264, 0x47ceb48568778c5f -265, 0xa2d73af3a884d972 -266, 0xdc6fab52b39bfe68 -267, 0x7f1a5e5ea6139484 -268, 0x70571bee802a1fa1 -269, 0x489f1d18d9c61c4a -270, 0xd781c38aa8aafbc -271, 0x5aa610ad2539aa57 -272, 0xd71a2a69974ae4a0 -273, 0xe4479465870487bb -274, 0xf714dacd7fc4475b -275, 0x5cb9c32e10d39249 -276, 0x746650ada73de1a3 -277, 0xbdd059359907cd53 -278, 0x38352adeaf41c72a -279, 0x330a370593019b35 -280, 0xc75ff9305bdaf3c3 -281, 0xc64723389b0bd56e -282, 0xbafccbf3fae88f31 -283, 0x3fc2c4b1d35da1fc -284, 0xd9414b4382f59e69 -285, 0xec31e6d32a58f7e1 -286, 0x4763fb9ad6cadb98 -287, 0x5e9817762a380e57 -288, 0x9a670c79b387ff5b -289, 0x467beb71ab258339 -290, 0x23cafda15a336768 -291, 0xe42ebf79e2d170e0 -292, 0xced716e4bbfe75ea -293, 0x1057597f33a23633 -294, 0x563d3fb59a847744 -295, 0x1a3f85cf84ea5e0a -296, 0x7630855876b41b32 -297, 0xb59e3eecb52851b2 -298, 0x26aed463d3769fd2 -299, 0x530d3898b8d043c6 -300, 0x28fa6b7cdc76ae94 -301, 0x99591569d7464343 -302, 0xa46da7d9e275579a -303, 0x30f6e5979a92bcfe -304, 0xaf345d66f7e756d6 -305, 0xdfad061213a92b33 -306, 0x2843134719ff646 -307, 0xbc8699b6d3f04313 -308, 0xacb08fbaeaedce6 -309, 0xe8fd50dc65724bc7 -310, 0x956d0436e93242fd -311, 0xa9c3e3eee8a80b9 -312, 0x9bf71b03710af171 -313, 0xbd61bd65edf3d9ad -314, 0x531b6865fc4f810d -315, 0x58ca69e7da1ea2f2 -316, 0x4946f99ec03e8adf -317, 0x3b9d4f48b1eb484b -318, 0x605be28093b8144a -319, 0xa7a4c6c8f2ade7af -320, 0x729f97c8057a21f6 -321, 0xc97d9d778a4e2932 -322, 0xc173b6c3d0c5168f -323, 0xd400c6f451c927fa -324, 0x611d96eb9e70ecdf -325, 0x3ad1a1709255cd86 -326, 0xf85d02d9fd5678eb -327, 0x495bd5eb58af79ab -328, 0x977bc4282d97381e -329, 0x9a5b1811cde9f133 -330, 0x49b2b9d26ba0977b -331, 0xf6c4e846b99bb87a -332, 0xc399d5f8661b0c8 -333, 0xaf9a91415ddeb79f -334, 0xb93df0259e6f3c5e -335, 0x80ad075b109611b5 -336, 0xf3004a806f25186b -337, 0x89a86842ef14b472 -338, 0xba53e5942ca79cdd -339, 0xc4cd49237032e3a0 -340, 0xb39700c89fc1109d -341, 0xc35fd5106aa40bf7 -342, 0xa0ff3091df2010c7 -343, 0xd4970cd890097774 -344, 0x39e7db9319a17976 -345, 0x56306e9316a184b7 -346, 0xe4d218267f28a145 -347, 0xbaa24a30caf53ebe -348, 0xf4811ee0d51ce11d -349, 0xccb9ece4a25b129d -350, 0x132b2d1c4f092d60 -351, 0x7d5e7a59f14dd113 -352, 0x8ed30762f02d3098 -353, 0x8a92bb806bf9a4c0 -354, 0xd1957618db32f95 -355, 0x3ae37701b1db294a -356, 0xc29e705f675713ad -357, 0x3d12dc6fc3dcc569 -358, 0x7bc096e1e2ca2e43 -359, 0xf58f4f816e71b16d -360, 0x23e6f93c7d0f1050 -361, 0xacaf403b80890da3 -362, 0x7a5e19bf92de04ec -363, 0x72b3638076a857e8 -364, 0xb87601882acb1f3d -365, 0xb51d157f2576ac70 -366, 0x7ef0c2f1ae02af0f -367, 0xd519f6224fb2866 -368, 0xe00a80d729843eab -369, 0x3c95b55c523d0871 -370, 0x81dcfef1772a151f -371, 0xa5b20337760a602d -372, 0xf36049e3e0f98eac -373, 0x21bc3e0f1083016a -374, 0xd8f295098597530f -375, 0x78a2582906003e78 -376, 0x1c5cf0f434493262 -377, 0x2228d56b7da9cc80 -378, 0xc3d7eaedd0f36349 -379, 0xc9ca575c3b6dfe54 -380, 0xb5f03d2d974c91b3 -381, 0xb2f7ce70c56a865c -382, 0x98f33d64e66602ec -383, 0x559904911cb8b69c -384, 0x19c426ae3d196913 -385, 0x818fcd24869feeec -386, 0xf4c52f4b00f4295e -387, 0xbdb808d5fe34cb3f -388, 0x5014922c0ca80ee9 -389, 0x9f7e4c8068fb96d2 -390, 0xec99128e620a2df8 -391, 0xfcbb4fc594857a59 -392, 0x6aebf62bc7c79e4f -393, 0xde8cba80e35ed831 -394, 0x55bb9ced0fcb6fd7 -395, 0xbe7534a18c050ef7 -396, 0xed2e6d1767c7ed5c -397, 0xc88e18ac1064dd88 -398, 0xf71fbae1105d8324 -399, 0xb4431f0a4b807ea4 -400, 0x78de56556e1272d7 -401, 0x34d3e7e84ceed376 -402, 0x72f0ca866b3b182b -403, 0x4747a9b5faaa6dfe -404, 0x5a0f85d879e90288 -405, 0xbecbea458ec061f1 -406, 0x5e0bcff71b1911e3 -407, 0xc2e32dc60548a6ca -408, 0xfa76a9a3d449b8c2 -409, 0x81303b7e225dea8b -410, 0x4aa42b413ca5c63c -411, 0x4d7372d31df5b70d -412, 0x2a408f03bb0499d1 -413, 0xd75529b610d56d9c -414, 0xa6e9d1356654ffbd -415, 0xe10bdb510c440754 -416, 0x8fce6a25abf05e69 -417, 0x21aaf272093d6081 -418, 0xcc18cf69f0f0b2bd -419, 0xbb4e0a1cda31a035 -420, 0x70128e6522fe238d -421, 0xaaeae87b79d223da -422, 0x6882e6705d12bc8f -423, 0x8e110abf1ccb274e -424, 0xb7ebac3cfca55a39 -425, 0x909705e2a6e584ce -426, 0x3b54f18e8f7708cf -427, 0xcac28674d5caa98e -428, 0xdde0e042ad4107a5 -429, 0xfc2ca3a740f903ac -430, 0x9aae84ca64051770 -431, 0x858a0d2d879442e -432, 0x75b3e7d29e357b39 -433, 0x9f6f5487d5ec5ac1 -434, 0xfd95986f2765eed4 -435, 0x2899b60770693140 -436, 0xb8ab9650b7300ee8 -437, 0xaa772209ef643b16 -438, 0x9c98fb4b5946fc61 -439, 0x6f614d64e4a38b84 -440, 0xbe0099b53347a13f -441, 0xe8d05eabf7db8a0e -442, 0x4c849670c59692d5 -443, 0x421d2e32838ebba6 -444, 0x1fb1f7427466dd6b -445, 0xd79d9987fd12fa15 -446, 0xc195d5fedaa613c1 -447, 0xfecdf6c6fb6c4924 -448, 0xd8536233459d6d65 -449, 0xaed30f22454f593c -450, 0x14d427078bb818c1 -451, 0xf7235f42e291617a -452, 0xb1fc436bdb2efb83 -453, 0x21cc3fd0fb82e07b -454, 0x2df968f572e077bb -455, 0xe1b76c513528f8c3 -456, 0x955681442083db83 -457, 0x2e009197f295008c -458, 0x2c258d6b1935587a -459, 0xd10fda2d14ce8e70 -460, 0xd21cdc7f5db09825 -461, 0xe39168a7b3a080cc -462, 0xc82c2a353a812026 -463, 0x6adc63d4bb7f26b0 -464, 0x5d2acdd2deaed807 -465, 0x47c39719b79aee01 -466, 0x5b6351daac993e69 -467, 0x1e2d2cf25d029df -468, 0x671c43218ccc62b -469, 0x783093122682b9c8 -470, 0x8055e091219d2263 -471, 0xa6e7f6bc43717757 -472, 0x91855fe232480a87 -473, 0x554030e74824042 -474, 0xd0c14f8ff34b1a30 -475, 0x13aa852fdea8bca8 -476, 0x27ed292b1a4fa598 -477, 0x3e56548b7095af08 -478, 0x47432aa82a4bfcfc -479, 0xadddde35537dc4c8 -480, 0xadb0d103d29faa1f -481, 0x14818cb71d4cdaf9 -482, 0x31507bcc3d46a5d -483, 0x7407577173399611 -484, 0xac03706bbe4da972 -485, 0x4efb0cae8499469c -486, 0xc6d4bcbc4396a20b -487, 0xd7581757d38762c3 -488, 0x6308e217f7e69120 -489, 0x6931392a2fcf3756 -490, 0xb5a5b36744f09886 -491, 0x8da8292d0bf2ed08 -492, 0x13e0aa8d5a24bd3d -493, 0x1131dbe7a2b97139 -494, 0x2098efd4a1e7108c -495, 0x9c470e15e690e574 -496, 0xe60e3aeb65560eb8 -497, 0x4ae5444669ffc65f -498, 0x911fc7e6820923b8 -499, 0x25b3fbb125c1ae19 -500, 0xa8b6c812471f37f0 -501, 0xe6d9aec89655113e -502, 0x59d24e18c48dd532 -503, 0xc9b320756e0d6c35 -504, 0xb70a2316319c8e2a -505, 0x328a0b16ff39152c -506, 0xc2088e4c8a3298 -507, 0x10bce05ac0971264 -508, 0xe26b5b7655fd4ad5 -509, 0xfb1d818177211481 -510, 0x98d83c41a7196f86 -511, 0x45801b77072aace8 -512, 0x563268328ebfb870 -513, 0x4d26e320a51123fa -514, 0xf531c63a3438f527 -515, 0xd94525fda256c193 -516, 0x883de65d7957b025 -517, 0x7be095e05de1599b -518, 0xd27792977b3a11dd -519, 0xfd179d3c4a5f06fe -520, 0xfbe066b302e09da2 -521, 0xb841424fbd2c7249 -522, 0x566dc3e3f2345fc1 -523, 0x14e8cfa0ee0ab392 -524, 0xf1e11e1841884ad7 -525, 0xc895b028b3b7df26 -526, 0x70f727baee1dc909 -527, 0xc2f4bcd3f8c7905a -528, 0x6d294a99118f9f47 -529, 0x18a723a0ddcf902e -530, 0xac36efa0258143c4 -531, 0xc558a61c40490895 -532, 0x430341fd196a18e7 -533, 0x27fea5b52f4178c7 -534, 0xd0d628d45d51e088 -535, 0xc016cdc47158510a -536, 0x925a6cdd446f0555 -537, 0x5e5a30a2f1d9bd08 -538, 0x918ad9cea082da5b -539, 0x23bb26bfaa0e79d8 -540, 0xf667bd79197706ca -541, 0x9ae3d6e8290fa1d5 -542, 0x20a15e60e0007e64 -543, 0x7d88beb1713a320b -544, 0x2d8b1728e392a6c3 -545, 0xb4cc0ae2c22afad3 -546, 0x749fe3524435e61f -547, 0x137bc8f57e7060a3 -548, 0x8070ee0def7571b -549, 0x2d5cacc36c121329 -550, 0x8408aeea38281006 -551, 0xc05e54af2206ce49 -552, 0xd547b24a26ebd3c2 -553, 0xc66d83645d95b57d -554, 0x8f4187e81ac31f25 -555, 0xe2878187a7ffa7e2 -556, 0xf7802760e1a8b9e9 -557, 0xd7f135ce1d83b5d -558, 0x4e2d5eee2bbad34c -559, 0x9b73503bcada0bcc -560, 0xc3fb41b2fdd2b56e -561, 0xc5958ed587dca76f -562, 0x1029b90ef3fa1e44 -563, 0xeb52236cba057b2f -564, 0xd411396dfa523c6d -565, 0xccb05527609c690f -566, 0xe73e27fd2c6295e0 -567, 0x363628b4f2a7bd3a -568, 0x443bcaaab9b67c72 -569, 0x1142926c0ff02a91 -570, 0x6d7fe0d6fbcb7265 -571, 0xea31775a5191e8a2 -572, 0xc44a633ed2339375 -573, 0x261bfdb83fc7a23b -574, 0x4cb967260869e0e7 -575, 0xf3b7134ffac658c0 -576, 0x97b266a6b95e219a -577, 0x18a5be54082669aa -578, 0x9adbdbfe1ad667c -579, 0x6fd02995faae35b0 -580, 0x9e62832c534ef39f -581, 0xb89e8229d7a85aec -582, 0xa46c8670446a0539 -583, 0x6960eeea3b3a4c70 -584, 0x27901b708cbb4f97 -585, 0xde1abdbbffa9cf6c -586, 0xcadb304d56e1ad33 -587, 0x579b5110955d30c9 -588, 0x77b57f59d61ebdbb -589, 0x900adb153a8037c0 -590, 0x1f5200f1f8be5a4a -591, 0xc491a76e1cefe1f1 -592, 0x6724370243b5d0c9 -593, 0x6cc8e3b9fbb98c87 -594, 0xca1722c5183b2b57 -595, 0xe9a61a3f20c59fec -596, 0x91723ba5418ed1b5 -597, 0x4299a43bd28daf49 -598, 0x8dc266e15f1f32b1 -599, 0x91a22c16ad09703b -600, 0xfe36e6cd32ebd06c -601, 0x30c0d9f9a60a11ae -602, 0xfad538e8bf1a0f03 -603, 0x47c2a0261dc808f6 -604, 0x9148743d0cdc81a -605, 0x17c3f4257197c037 -606, 0xdc8b06b5220c01a7 -607, 0xf9ad586eb09e30f4 -608, 0x702600c123b400c6 -609, 0x9218eef469b0db7e -610, 0xce16c9bac0969bb4 -611, 0xa758408742a37457 -612, 0x2eb094509e812e4a -613, 0x28440b87ce1e0e21 -614, 0xab48eb01ee07e56a -615, 0x85e69345a3649100 -616, 0x517927d4a415e569 -617, 0xd02de9b703206f93 -618, 0x5cae9cf67b9d62a9 -619, 0x8b0e1e0c2623250d -620, 0xce893eb84c72510b -621, 0xd97bdcd1e00f8c3d -622, 0x106c1721a5e8546 -623, 0xb4fc0554e61e059a -624, 0x5fad1bc4c54c3136 -625, 0xd09dc05514ba4ad3 -626, 0xc934e2153df00372 -627, 0x3cff94fa0fa2967a -628, 0x4e7ca152c113e934 -629, 0xc5ccf2350fb82ffc -630, 0x10aa453d349b70df -631, 0xf8270070253de14 -632, 0x412b14bc12ef4538 -633, 0xaf83140fc27938c2 -634, 0xf342d1c8c97c7e74 -635, 0x693b4b07b79cfdc2 -636, 0xe859c76fde1be4aa -637, 0x90ac4aa1c012a971 -638, 0xeca381124c9bf23b -639, 0x1f544598d356ab2f -640, 0xbcd78485f20f8339 -641, 0x6b8eb4bf854dcdf5 -642, 0xdb231419a9323609 -643, 0xb2f0167ca051a61a -644, 0x9806e89e8d3ebd15 -645, 0x69ce87797a14c206 -646, 0x143ecc33c23e61f5 -647, 0x3be37d8fbcfc396f -648, 0x2a4336f50c851387 -649, 0xe665ed14a40c6400 -650, 0xc229fc93c03a6a24 -651, 0xb7f27088c74af74 -652, 0x8a8da4fbf5fb90a6 -653, 0x8c54684d5db6a600 -654, 0x11ef0e952c8ad4ec -655, 0x928a518e677b87a6 -656, 0x6b6c8ebe9db7253e -657, 0x9feecd8eaf8a8101 -658, 0x4f270f30f3ad2d0b -659, 0x23798146bff58d75 -660, 0x7d9134e4005b9246 -661, 0x18b5eb6833bb921e -662, 0xff0ef41f6c734814 -663, 0x388b18f678774f4e -664, 0xa51646467be5785e -665, 0x9f96bbe291c9361 -666, 0xce39cac00148c7b1 -667, 0x69d41ab8914f944f -668, 0x579ca60b75dbf4e5 -669, 0x352f2b89c968d81 -670, 0x181d45a561c05553 -671, 0x5a6aeaa048d6a494 -672, 0xd7938433b99408ca -673, 0x13bd6696806f0800 -674, 0x2ca8e35e87037dbb -675, 0x70d9d33ef79088a1 -676, 0xcdcb45940c9ba3e7 -677, 0x2546f21a69a29dc -678, 0xc674c5afa1f9abdf -679, 0x856dfa52fdff93b5 -680, 0x614b66daa02187bb -681, 0x55ce165aee2e205e -682, 0xf34d6cf856f941e3 -683, 0xa4a0ec51b4f25b25 -684, 0x83e6bf89bfe39762 -685, 0xb559b9a68edf3381 -686, 0x9259778b54c31479 -687, 0x4e4e21e81138cacd -688, 0xbbb990cd25c2fb2d -689, 0x38a85ad84d9e31e -690, 0x5b4f4081ffba398d -691, 0xfb12eb300dada910 -692, 0x6975328f3eebcb34 -693, 0x3db017218a6478f0 -694, 0x9397aca7eaa5de14 -695, 0x6f7318d0d9ffed6 -696, 0x40cf276103c34010 -697, 0xeacef8ae2095ec8a -698, 0x80f7593e9ddaa152 -699, 0x8d4bc01f7e5c6520 -700, 0xbbc9606e7518e199 -701, 0xfe71ef90abbaca29 -702, 0x528edfe3e467ed43 -703, 0x52b322c36f60627d -704, 0x9946be5ea3beac73 -705, 0x890745d71a02c404 -706, 0x5570d1bde8bb7993 -707, 0x563fceeff8466dcc -708, 0x62a9ca23db6e4d62 -709, 0x89d6038410c92e8 -710, 0x16bc3b1ea7b90a89 -711, 0x12ff3e9c30d8dde6 -712, 0xe78cb53e8dd40a77 -713, 0x643722181b85d5a -714, 0x73e26524635d78e3 -715, 0x941ccfc41d47c53b -716, 0xadbedec82c31e57c -717, 0x2addd39e7a36aad6 -718, 0xe64d81fa432bb65d -719, 0x1e2e63d01399ca82 -720, 0x760a3c0edbbef3a6 -721, 0x801131e88419a79c -722, 0xa2a75136213dbb6 -723, 0x83e576905753c3ff -724, 0xdbbdab8007c4ea0 -725, 0xbb73b13358898c2d -726, 0x5818372d8fe036f7 -727, 0x3aa052cd647e29d1 -728, 0x235219635ff4abb6 -729, 0xe24e07311fa76b65 -730, 0x4967574b62c3efb8 -731, 0xb04b4c210022e795 -732, 0x3d48e77713ef3fda -733, 0xf4ec1050775fd3b1 -734, 0x38953c604d35190d -735, 0xf731a6450c1e23fe -736, 0xac66ae73ecc6b9dd -737, 0x442e2bcbca5bbaa8 -738, 0xa74a741bd02570bf -739, 0xa85473cbf3b4c45e -740, 0x24d43199c69cdda -741, 0x59f78fa87f895d36 -742, 0x78f5513621dc1813 -743, 0x226c2606635698c9 -744, 0xea39babbad3df384 -745, 0x2f178b076f08f80d -746, 0xaee482470bd9acb5 -747, 0x48571d8c4235c1f6 -748, 0x6569395eec2df1d7 -749, 0xa9b7408c1d67a372 -750, 0x3b9c5ba01aecae9d -751, 0xb047b26325765767 -752, 0x9bb1968c8b6149d4 -753, 0xbba4038fdd341986 -754, 0xc1d23b5b89beaa88 -755, 0xaa9a341db334c8ac -756, 0xaa9337dd1fddf923 -757, 0x9fdf160ed939d68b -758, 0xbf48cdd432d0f148 -759, 0x2a01743f1f7b581b -760, 0xb68d5c631e9fb70a -761, 0xe9ab844ec026cc7b -762, 0x1fabd46f0d5266f0 -763, 0x29e53ae817eec5b -764, 0xeffbebc07500ad4d -765, 0x432ae3b596c1589b -766, 0x48d44f3895d6dc23 -767, 0xcc3a5576e24ec2bf -768, 0xc8f4a042462e95d9 -769, 0x24c12cd6ef57b6 -770, 0xa7896ae26675f69 -771, 0xb98a1790d429c90b -772, 0x71f7ac96dea8ffb6 -773, 0x7878c64cad319f72 -774, 0x65586d63156e1a05 -775, 0xa70ef198e61e2a11 -776, 0xf5a84f622d490449 -777, 0x7789e1c1927e82c6 -778, 0xfe053fdbb586b8fd -779, 0x59a94b735df951c3 -780, 0xdf5e72909ff2bfbd -781, 0x34dc2bd8876a92e5 -782, 0x7e408900bfa3b282 -783, 0x844176cb62d5008b -784, 0x7406e9e156cddc9c -785, 0x6a6d87de33056193 -786, 0x20c388365359e4c -787, 0xdbda2eee6499be64 -788, 0x3574cf8bc4840b47 -789, 0xc2d904ac50e44ee3 -790, 0xb9edf042b0d96102 -791, 0x2ac087f3922dd11e -792, 0xeaf244df29c2a8ae -793, 0xb4243528d8d0649c -794, 0xed67e39d9217e6cd -795, 0xcbdcd1620727437 -796, 0xcc00dec8485d0dfb -797, 0x2e5411679d89f548 -798, 0xdd355c299c05131e -799, 0x6fc81e1e9beb2c8 -800, 0x205ac04eedc0085c -801, 0x8bf73a08c5240640 -802, 0xec6f8daf06673cae -803, 0x6e29f78f0a59638e -804, 0x8c530fd613aeccda -805, 0x58b99ce19626ee04 -806, 0xb16f71c11f209bb9 -807, 0xea1d7ee0e82f9146 -808, 0x5641482551d357fa -809, 0x13fb8eff6efa4b89 -810, 0xca4bdfac87e46ce0 -811, 0x9e2babf08f33b6ad -812, 0x482633792e270729 -813, 0xd5c17bce83e146e9 -814, 0xf8df8169c7ff4df6 -815, 0xad974ea8b3bb7e7d -816, 0x8ad356322d6c0a26 -817, 0x5ba5a24cff70d235 -818, 0xb604ea125e469d44 -819, 0xecb90d0ca42445d9 -820, 0x9c499d3f441e6eb3 -821, 0x2aed9e67fc701d26 -822, 0xb3476334028bed9 -823, 0xba079723415a89fd -824, 0x8684b0e124ebd181 -825, 0x6effee2741402b37 -826, 0x15e734115d68f8a4 -827, 0xafc15b8a9fa93205 -828, 0x9749e35360fcd91 -829, 0x8ffbf6ba4b02bacd -830, 0x2f107b6a820f44ba -831, 0x230cdb06c5f7422b -832, 0x2149918883f7c858 -833, 0x3e8eb9dbfb832b71 -834, 0x871f0b4369d3dbc3 -835, 0x3553e06132e55fa4 -836, 0x1ec19fd1ce7a5823 -837, 0xf3908fc23446b3a2 -838, 0xe300b55305c8d7f3 -839, 0x61e4ab3372dce7dc -840, 0xb50f68be3632604f -841, 0xd6d2993fa6d155b9 -842, 0xf9c8d0fed0c90246 -843, 0xdd1b49530387141f -844, 0xd1db9818546e095c -845, 0xb91885ccff43ee8c -846, 0x8d704dca3b7fdb63 -847, 0x8309c9077939df4 -848, 0x6536739d7ae608f7 -849, 0xdab8a503cb9b94a6 -850, 0xc504248b8f69f733 -851, 0xb0ccfb81eb67e3e4 -852, 0x45ac4f949c418493 -853, 0x7763a70137c01376 -854, 0x7f08d6362b17c470 -855, 0xb190bb422946ad46 -856, 0xdafe7dfcb0d71320 -857, 0xec415ea4c54398f5 -858, 0x5955b81204c5657c -859, 0xff1f983c56d6d7cb -860, 0xb25b4a0de0bf393d -861, 0x3a90222bef45f3fc -862, 0xf0eb0903e3695f44 -863, 0x405ecabf26817b33 -864, 0xccf01a062f2351eb -865, 0xa62a5f63e31545b1 -866, 0x673d1baf237668d3 -867, 0xd15db3cddfb0a161 -868, 0xa8adebfc9b5351f6 -869, 0xc297fae49f0b2d08 -870, 0xe5ed1156ab569225 -871, 0xf4aa4bab70aa8c11 -872, 0x8e32dd1eb44c6363 -873, 0xc7aa250f1492e86d -874, 0xc645795d705914cf -875, 0xfdd8a48c0fb81c53 -876, 0x6ad1401f539799fe -877, 0xa157e71b6bdd4254 -878, 0x4cc09814465a6c9e -879, 0xed1f66bd824e39ec -880, 0x6b74f7f6f2d4c16b -881, 0xa3391c0100010ae4 -882, 0xe0f384530c0e7eb -883, 0xf6aeb9f0d64c7159 -884, 0x3d7f6bd980e07a17 -885, 0x8b4e1bd3e782ea4e -886, 0x7b005009d95b7d38 -887, 0xf43f001d5e7326c0 -888, 0x16600ff7361a1721 -889, 0x13778aceafd72087 -890, 0x85d3359c37907c58 -891, 0x7374f768c968d0f -892, 0x2373d89b9b8f9e9a -893, 0x21a3fe7e4dc5cc35 -894, 0xb02abcad4f4ae60 -895, 0xb9eb579582666e3b -896, 0x9c12186973b91695 -897, 0x1bd25ac6911295e7 -898, 0x9f5a90e0fc16ffa2 -899, 0xe3e8f10ce7fbb9e1 -900, 0x5867e566887d2d16 -901, 0xd569aaf2ffead057 -902, 0x678359b93dfd07f1 -903, 0x9fb73a4f1b777d94 -904, 0x5c6b0bcc70df3a54 -905, 0x66fd71a67ed5e59d -906, 0x62f21a6fe936b212 -907, 0x86922151e4b251c4 -908, 0xbfdee56cdeabe8bd -909, 0xbe3bc7c4c2380ffc -910, 0xd09ebebb0e786d49 -911, 0x4951a83005aa22de -912, 0xc1b7da6cf08630c4 -913, 0x8b294b5fef04b0af -914, 0xaca7a47f7fda4d5f -915, 0x70bbddc64b4b1a91 -916, 0xad306a764087085c -917, 0x19b9f11c14adb74a -918, 0xbf1a7d2c83fbbbe -919, 0xb78da8a53fa857 -920, 0x5b614c5060a543b7 -921, 0xb6f32557404d475f -922, 0x9fc53dfe5281f084 -923, 0x43ad9d302c10a475 -924, 0xa4575be2c10fbc13 -925, 0xe58c4c02d5b2bc8a -926, 0xaa838a3e5a16bb55 -927, 0x95c39373858011e1 -928, 0x17a6be18c1801fa -929, 0x835e6c3d99898c27 -930, 0x9af26334bd726505 -931, 0x7addf56712a22afb -932, 0xf619281f6d4d37d0 -933, 0x310c6b1e29ca7eaa -934, 0xe8106bbe1ea0f3c9 -935, 0xc89add421cfe7bb9 -936, 0xe01b7a6885180236 -937, 0xda8cd608ee0eee61 -938, 0x3bb2f5f40a8f4880 -939, 0xd434cddc85946350 -940, 0x6390806f8d1465f -941, 0x2a5f0150c8362cf3 -942, 0xcc6980e968b75f37 -943, 0xd86756899b2c95d2 -944, 0x95ab76b54f439605 -945, 0x1e0d6f6a99569ffc -946, 0xd47b20b72c0f02e3 -947, 0xcd9fff1462fe8a25 -948, 0x71867c57f009bc8b -949, 0x85238c818139a22b -950, 0x58247991b6447ce7 -951, 0x3b41a627153bcc9f -952, 0xa3ddf05f18153e13 -953, 0x21a3d47762fbdbe4 -954, 0x8ee55f20e5c5b14 -955, 0xc3ed8e23589b365f -956, 0xbd12efde1b5e8afc -957, 0x35b81175f738edc8 -958, 0x16b2627c28c952c0 -959, 0xb16a5009047b002b -960, 0x5e4c769bd80bed26 -961, 0x96174863aa73bf6b -962, 0xb3bfe6a2d7d05881 -963, 0x5c0a1757302c3fb6 -964, 0xfcc52e2da058ae67 -965, 0x12b26055c0ea26e8 -966, 0x87d8126b14b8417b -967, 0xc87745c58eaa597f -968, 0xb38b4b4b579ab55 -969, 0x559ece2bb0ca0b32 -970, 0xecbf6af7914a6435 -971, 0xd994b534e3f46c42 -972, 0x67301d5555cbaf1 -973, 0x4b2222c098aecb6a -974, 0x2f1b7acadaa10ffc -975, 0x4c48c65a542d56f4 -976, 0xf3fbde71409cd64c -977, 0xb32e3ef1dc24a7cb -978, 0x229321ce5bcd85 -979, 0xcad7e7dfee447d7a -980, 0x7fddd28936d166a5 -981, 0x928bfb0027da2715 -982, 0x97b17752c6aaa82b -983, 0x3eaca529c941d7c1 -984, 0x91937555520265e -985, 0x8e7e5c3786ee3588 -986, 0x27162348b08a9aca -987, 0x302165a3d76eab04 -988, 0x94111b7672c6bd95 -989, 0x7a471169035fc35a -990, 0xe850ed94b0be86e1 -991, 0xf7a3721d6c85c1cc -992, 0x6727a68e16268dfc -993, 0x65433e82f0e19d29 -994, 0x6109fd616c977544 -995, 0x7068ef83a29cdc70 -996, 0xcef2deae0fccb574 -997, 0xee2a2ee021a6ad5a -998, 0x5195005fba78706c -999, 0x31364d630d333f34 +1, 0xd805fcac6824536e +2, 0xdadc02f3e3cf7be3 +3, 0x622e4dd99d2720e5 +4, 0xaacfd52d630b52bd +5, 0xa94fc32eb4128023 +6, 0x9ee359839e68f625 +7, 0xd9f180e03b686e4f +8, 0xd6825e7d8fc65068 +9, 0x887f15071c20b9d +10, 0x6dc39f8336eeaa66 +11, 0x13d17509661b69b +12, 0xdbe703ea4e61caec +13, 0x1a4deda7c51c5b7b +14, 0xe2f2259fb30bafcc +15, 0x7eb5a4d5f053fcbf +16, 0x4704d55257921919 +17, 0xcfeb1c70eacd6734 +18, 0xed98c92a0d6b8b3e +19, 0x4efb928a052188b7 +20, 0x15617edcea5e98ab +21, 0x8ac022e71a4d1a40 +22, 0xe0ae2cdf81cc05bf +23, 0x11ae6d329bc72f19 +24, 0x5369885a834c1073 +25, 0x7a865692c8495a12 +26, 0xaf752d7df50f6968 +27, 0x4b81c799c968e005 +28, 0x4104e06972751b34 +29, 0x8600214cf598d6f6 +30, 0x444545884a4b0a80 +31, 0x2d13243847e43cfe +32, 0x6064921c3b70601c +33, 0x1b2c2f204185130e +34, 0xac1e21160f7e90f4 +35, 0xa718d564118e2bca +36, 0x25fb8750f330bdc1 +37, 0xcdd8329cb365e06 +38, 0xfdcfbff05c3470e3 +39, 0xcbce143aec5155a5 +40, 0x1d17b5b1e2c3c21 +41, 0x68fe2fbabc30aa23 +42, 0x19086e8dbd448c02 +43, 0xdb7d8126e6f3d1c6 +44, 0x1865e34fb131a69f +45, 0xce3be151debb3e9a +46, 0xdf573313ce569b70 +47, 0x3a7fcf8ef4fd495a +48, 0xe26450c5ec487bcc +49, 0xe99eaeeb35354e +50, 0x959e7e6cb8bf55d4 +51, 0x3ba4778a79b1b758 +52, 0x30e4f35a940c2e04 +53, 0x67717bb8a50f2c22 +54, 0xa9b3e9db4934cd8e +55, 0xe22bc184e5d2ad8d +56, 0x7390583f39dfbb76 +57, 0x19e7ba95b2482b72 +58, 0x549b0c65abc1615f +59, 0x43989e0d7268118a +60, 0x1376e3b4f7319b9c +61, 0x41bc4dd69e4a3eca +62, 0xdb5b777a0a90e830 +63, 0x4885cae86597a2fd +64, 0xe472ab9f66c240b5 +65, 0x387e53bf7d31a3c0 +66, 0xd8826e1be0364bef +67, 0x2a334c6d6f748f84 +68, 0x10c7d9da8f7ba2ce +69, 0x7b23655caa5a3872 +70, 0x4e52d38a6128c877 +71, 0x581cf9ba515b9abc +72, 0x464df6946cf89b19 +73, 0xaf0f20053d807827 +74, 0xddeb1fe3d90b8aa2 +75, 0xccb863176382287e +76, 0x831e79b8d6d91e8b +77, 0x88ed0822fceb3abc +78, 0x66adaa8387e19785 +79, 0x23a5005fb1c9c598 +80, 0x4ab28f3b1585657b +81, 0xd620ca461099e06f +82, 0xf056f4fdf816bab5 +83, 0xeaef5b9b3cdb015c +84, 0xee4f14793695313b +85, 0xaa406259c23ccb33 +86, 0x9ec3e4585b6d933f +87, 0xb5806dfe257e6c7c +88, 0x7bee992cfb5fd41 +89, 0x91a70b316b42bd18 +90, 0x874df34eea24edb5 +91, 0x379a0a3ad79d7db2 +92, 0xeaea9f7eb0292235 +93, 0xf4742d169fbb5198 +94, 0x57a84e20592727d +95, 0x5d8ec89195373de3 +96, 0x22eaeb51baa32533 +97, 0xc3cad6ca8be847bb +98, 0xf316a8b9b6172611 +99, 0xb687d7988a8a2ee5 +100, 0x8635d3f011c6253a +101, 0x2280ec837c98731b +102, 0x2f815c82713ebd61 +103, 0xb2b4c124ac4ea1a9 +104, 0x5db6c0a6a90a1866 +105, 0x3cc317501c96e9f8 +106, 0xd38b689a10819dac +107, 0x1b8a114bbc51341e +108, 0xa276c85761cf5978 +109, 0xe6b3d7d5b3b6dc0c +110, 0x14963fae33e6c2fa +111, 0x88f83f53a67231d7 +112, 0x77aec607b4aacad8 +113, 0x33cddae181b93178 +114, 0xf1bfcef2a7493c7d +115, 0xc4177359c975f669 +116, 0x9d603ef0b6bee8a2 +117, 0xc16ee77a4391d9b1 +118, 0xe93f0736cbd3f398 +119, 0x327500ca9afb0730 +120, 0xd8cba3672638e75d +121, 0xd87f00175eea9770 +122, 0x6680cfd0f0651f47 +123, 0x13287cbd1981e44d +124, 0x9da5fb61bd633e98 +125, 0x2d704f64c4ad5444 +126, 0x4c28b98c2f7349e +127, 0x42d156862c609af0 +128, 0xcbd49a9595d2964e +129, 0x8d54cf464a529131 +130, 0xd6b74f26dd0e313d +131, 0x4ef8b45baf3ec3a7 +132, 0xfc8be973c860481c +133, 0x6112312f08028018 +134, 0x78d492d0049b30bf +135, 0x3160db98b853a1a5 +136, 0x81eb3fabead6d97a +137, 0xfb54ee3224945380 +138, 0x3c62663cd2aa07dd +139, 0xeaa2eff9e2752bb4 +140, 0xbdecb6e8041eccf9 +141, 0x9a135a78514e92a2 +142, 0xacdbb7139969ae66 +143, 0xf71fc98126f511ba +144, 0x1bd6dc2853a20898 +145, 0x6fb80e8eff8b26a3 +146, 0xfff9ba38f9c3664f +147, 0xa4224ddddbe3a700 +148, 0xd76b8f1bc09e35ad +149, 0x1b6c5bdad062aae9 +150, 0xabc5a61088f2a3f4 +151, 0x5160b68fd92f30c +152, 0xb2cd4c619e1cb446 +153, 0xceffe90f16c69c0a +154, 0xd7845f2eb8b1bf67 +155, 0xb6ddd2d76e99be45 +156, 0xf6212b33d0bc1019 +157, 0xdebc75b6e2d6db50 +158, 0x7a6d61de4c4c3a9e +159, 0x473933055a8727a8 +160, 0x83ca458dff43a0aa +161, 0xde2b9e38b321aa3 +162, 0x78ba83864952e9de +163, 0xdb4c6db1049e8406 +164, 0x9c3a30ffdcfac7ee +165, 0xeab6e9a0cf1ecd0a +166, 0x3617b147dd5ce2ca +167, 0xe5c000907864b48e +168, 0x7dcb724b2767b90e +169, 0x4ecd7ad20e75e566 +170, 0xe03be67c421d2942 +171, 0x7e7a68988cd564d3 +172, 0xa8c25e5165919c51 +173, 0xa1d550ed4a39e690 +174, 0x6e7abdcf98453f72 +175, 0xe57eb7d34da3c5b +176, 0x8da6eebbab5ef00a +177, 0x7574363208ed2700 +178, 0xff06b2a934a953b9 +179, 0xf3c8951de92dcabf +180, 0x78b817c0dee711db +181, 0x358522c82c15f627 +182, 0x81d54c2d5ef396b8 +183, 0x1f98c21036a70b27 +184, 0x4d3692ad8d5e5112 +185, 0xb63674f55b06bd46 +186, 0xbf30a7aada9b1cc2 +187, 0x57f75205e81f6b47 +188, 0x37e9ab7e796bd0c9 +189, 0x34aad24654a70694 +190, 0x5602376e46ea14ea +191, 0x3761258bc9e79732 +192, 0xffe7d79561680d75 +193, 0x35b82f78a688b86e +194, 0x42d23cba46456a80 +195, 0xd64f0c226c84d855 +196, 0x6ef5d71859f03982 +197, 0xdb7dabdf5282c818 +198, 0x94ec7253c617acfe +199, 0xcc118236ff2009fd +200, 0x9f91eaee04579472 +201, 0xbf79aadb5a3a4a1e +202, 0xf6ac29ee74fae107 +203, 0xc82643f14e42e045 +204, 0xb08f864a06e4db72 +205, 0x7a2a402f1a000aaf +206, 0x2c2e03247fad91fd +207, 0xe70bb051040fd7bf +208, 0x8d42d479e23862ed +209, 0x3b2b368d659b45f8 +210, 0x96c8d7c31b396bc5 +211, 0x41664c476575aeea +212, 0x303ba0289cd281fa +213, 0x2936193bbe462f68 +214, 0x4a63581937611f45 +215, 0x10f69bed29c2a652 +216, 0xcda3073cb7dd2082 +217, 0x374da8d58157bbdb +218, 0xf3c040dd9a135d51 +219, 0x5ae628cef3e753da +220, 0xafdfa06ac9ed9eda +221, 0x94582756d1cc948b +222, 0xce387a039a43baa5 +223, 0xd9aab74b36032cb4 +224, 0x720e30cbfc81765f +225, 0xba42d487e461d31 +226, 0x445fa16350da585b +227, 0x43a3b57501104e19 +228, 0x55571957e6267eb3 +229, 0x8c1f8cc37a83b2cc +230, 0xdd433be6a0188876 +231, 0xdd0c1053757845fd +232, 0x47d17129bdec523 +233, 0x5fdc39aa7f38cf97 +234, 0x92ab54d8c66e4417 +235, 0xf46a39cdbdee494a +236, 0x6a226e83cc244891 +237, 0xdd2dde8767318719 +238, 0x794e882325646a7 +239, 0xf1d269b9fa82e09b +240, 0x5871ab313f97bbde +241, 0x30a0f742fe7a1746 +242, 0x8f3b8c2ef199341a +243, 0xf280d28fd6ab1ade +244, 0x8b5e8a112798cd0e +245, 0x80cc043e4ace43b +246, 0x1dcd69d6d8f6c527 +247, 0x467dc81c1f462ff8 +248, 0x47e98dba34af7440 +249, 0xae4599c86b11c6d5 +250, 0x4cc5574019676ca9 +251, 0x79b0a34fc332cfbb +252, 0xc5c778c13974e8 +253, 0xa1773cddcb7f3bd +254, 0xae20dcad57acc7e1 +255, 0x11e6e98c02b4ee9f +256, 0xfedb58925c42929 +257, 0x2ab56b3fccf3c5b6 +258, 0x5740e0a90920bbdb +259, 0xe02ea72778a4cc5c +260, 0x7fa9448e7563e3e +261, 0x907603f2ccd28776 +262, 0xc655d1fbe3fbf1e0 +263, 0x40bcc587212acc1b +264, 0x1af8bcb6c4902043 +265, 0xd47a71193454c4ba +266, 0x9e9cb523c3c9dfe9 +267, 0x4b9e107b36ba9f0b +268, 0xc89d86427a63c956 +269, 0x2353f37179b7147 +270, 0x7c6d3c3d67f1f245 +271, 0xf008463da2875270 +272, 0x4494eb9f1d83aca9 +273, 0x84dc57b61ca36077 +274, 0x461480c6f708fec3 +275, 0x6256b05de4b8233c +276, 0x2b02af1084a4dfd5 +277, 0xd4f3bb079fb41a61 +278, 0x83ee412671f4ef78 +279, 0x6c46e97c8f197f8c +280, 0x4d949413ea0d1e9d +281, 0xd7eef89a4d084d17 +282, 0x18f03d6a52592eec +283, 0xaf6fc843c53e63fd +284, 0x551f420f53de9097 +285, 0x4fa8dd599dd1365d +286, 0x399727713519d072 +287, 0xbdf7dbcc18541feb +288, 0x3f2336894ebad1fd +289, 0x903a74b979250389 +290, 0x733313e457a65fe +291, 0xd189b01b9258d1c5 +292, 0xb2d9533680f9a70b +293, 0x2a0929d54aaae5c6 +294, 0x9c6b844de0367b34 +295, 0x341d37b0d1e75bac +296, 0x5cd370014b87cc94 +297, 0x4bdb409173abcb35 +298, 0xafd38d4c9d91240f +299, 0x76d7d551533f344 +300, 0x3779e62cbdef738d +301, 0x211052148f86c129 +302, 0xf2f325e09a17da4e +303, 0x1e874c70b2d62dec +304, 0x412fb842edc1c3f0 +305, 0x23d9f5e6c9d83d27 +306, 0x8e58937e012d3c76 +307, 0xb0ab1175918a765 +308, 0xfc7991f83e0e06fd +309, 0x1066d7c10f16cf5e +310, 0x29a14ec418defe81 +311, 0x20f98e60c158d08f +312, 0x463c0497605efae6 +313, 0xdd02ac91db3f0cb9 +314, 0x434cbbb353edfa66 +315, 0x892ea5a463774836 +316, 0x8e00064e77225923 +317, 0xca7ec8ebe244a404 +318, 0xa9146f68a99e0a77 +319, 0xc85ab0fd6c4c8a99 +320, 0x4a1104cb1287380 +321, 0x25a570b6e2b45828 +322, 0x3e3f5935137b0d61 +323, 0x499d6aa0407317b9 +324, 0x4ab08263445a3fee +325, 0x2dcd45f060d8f5cf +326, 0xa73225adf6418dd1 +327, 0x738ff6caaffb838c +328, 0xa93e4a4d2330026e +329, 0x47421b8206cf7ba8 +330, 0x5d9ad2876b1a4e84 +331, 0x6557edadf965aad3 +332, 0xaeffe33ca45ac0bc +333, 0x2196b20f7074c7d2 +334, 0x351a0c784e1056b4 +335, 0xfefaa1eca46cba97 +336, 0xf58741e34d53876e +337, 0x5942f6de49d5cade +338, 0xe1b0d6514455ac99 +339, 0x456dc6a18b651d36 +340, 0xa8d240033f5c9074 +341, 0x7d758bc84ec678bf +342, 0x21ce28f61ecde645 +343, 0x83b8f058c1b36557 +344, 0xeaf452c4467ea627 +345, 0x60bb8582e53d2f9f +346, 0x9649572eaa40c725 +347, 0x59533356c226c99a +348, 0xc06b7f790fd4fda1 +349, 0xdb7d827921aa5962 +350, 0xd9be204c05438878 +351, 0x67f903bed4fb0450 +352, 0xf8e583b98827118c +353, 0x72c8508fca1e207a +354, 0xcab1df54ae1542dc +355, 0xaaa774d0c8833857 +356, 0x710c4b86e747bbcb +357, 0x8ffc4dd34d5f12db +358, 0x3b1d4fbe64743023 +359, 0x3ca88da03e8d8da2 +360, 0x970b522fdad62c7d +361, 0x7596d74c3e598a71 +362, 0x1e9c86f3b5d93e5b +363, 0x378a3fe78b730c3c +364, 0xfbc82d6ace6346 +365, 0x1eddf6aca48b7ff8 +366, 0xed12c2c2e137a0c6 +367, 0xd2001d92384c365d +368, 0x69a1bad8bc8742eb +369, 0xe1b460d2e65e9a74 +370, 0xeff030a0954e3832 +371, 0x23ac5413d4b3e60 +372, 0x802fffd55c4d2279 +373, 0x1776b952e25fcacb +374, 0x595f3f386b0f524 +375, 0x3f2d5e55b839c40e +376, 0x145202db5650c14d +377, 0xc28858131b702442 +378, 0xa1381d43a4f59fcc +379, 0xb3088835a18600fc +380, 0xca7830bf9187f705 +381, 0xa189dbff019ca64d +382, 0x82ad4b1f88491340 +383, 0x27262f1b70bcc1c7 +384, 0xaa52ad0b4cdc95b9 +385, 0x6898a6e5a791cca8 +386, 0x4c892bd369fb7c7c +387, 0x2c5040316ad789e4 +388, 0x25aceb42f6d853d4 +389, 0x8f3e09dd6e6fcacb +390, 0x35f4e10c7b4e29cf +391, 0x6156e9fcc26a6e83 +392, 0x8a8389e8a9c70fda +393, 0x81219b723a3dd912 +394, 0x631f0c99c62650e +395, 0x9cec1c4f650d6c4c +396, 0x1d3b402d466479aa +397, 0x6d2fc0877f6f8e46 +398, 0x2000b7178225c4c +399, 0xb01c45dca932ffb2 +400, 0x61f25ea549d3b3ef +401, 0xfc0733a134f7bb8c +402, 0xea3ab2a0cc6a366d +403, 0xe26bf2b8fe0db591 +404, 0x3186c9cdd8757ee3 +405, 0x9cb472c0c526cf7b +406, 0xdafe18916dbd33d2 +407, 0xe0b15a3aed330dec +408, 0x7079ae5641dd16cc +409, 0x49b6b9756c347b90 +410, 0xdda875fe11e94d34 +411, 0x8c77fb380278f362 +412, 0x602904b0cd3bc464 +413, 0xd2dc40f56fc531be +414, 0x753175bcc1a93ba0 +415, 0x333a71f4d2d756ea +416, 0x7b862ff73b46e03b +417, 0x9df539d017e9017e +418, 0x4113e5be11f63f2c +419, 0x422942050abc4fd6 +420, 0x737b754e2add8d6a +421, 0x313e6c1ecefdca96 +422, 0x5436d70ed2ee4cdd +423, 0x1db894fde99e34f6 +424, 0xd86bc0b79db9a96f +425, 0x9d904f0aca534217 +426, 0xfb14afbeabfc04df +427, 0x9c4ccba431333edb +428, 0xc7de0af1a5760939 +429, 0x735669225566ce71 +430, 0xf5815dabb0665733 +431, 0xf0a6b7c00d4d569 +432, 0x1448e6fe1432b7af +433, 0x2e0586f6c9e6e7b1 +434, 0x7b75aa00eb44d795 +435, 0x7ba5cfa018a44c87 +436, 0x5854a5f78e636c5e +437, 0xdcbe856037d0228e +438, 0xe8882d90f7259452 +439, 0xcb6ff056c4171c82 +440, 0x4a7bd2245f0e0e32 +441, 0x3e2a40308897a793 +442, 0xe404dfa4d3284167 +443, 0xab022bce6ad8cbc +444, 0xbb5a145064db9976 +445, 0xedd82ddea103ab7e +446, 0xcc906d55fb10a8cc +447, 0x63ba976a36e0cf56 +448, 0xb3ef5ad3129eedba +449, 0x409b01e4107e9dc4 +450, 0x41059d8141efd96e +451, 0x10bc4a29ac5cd941 +452, 0xe2fd0fb5c7787046 +453, 0xba24bd0f8d018cb3 +454, 0xc9cf71f73e6979f5 +455, 0xd79a917354d39e89 +456, 0x44fac8764c14e096 +457, 0x29c2cdcce0ce515c +458, 0x41c6704b232934ac +459, 0x2ace8d883c6ed401 +460, 0x76d37e5aa3c57f87 +461, 0xc7b7ae6275c47624 +462, 0x33e426b3e22bc96d +463, 0x77818a58fdc8b640 +464, 0x49c3b6b021037e35 +465, 0x8a941f067ca1c772 +466, 0x8dac8803caad398f +467, 0x2478a7f23abb4332 +468, 0x98ef79938ccc8b65 +469, 0xdddd5e6776f61726 +470, 0x8d9412cdc85ab90d +471, 0x901946d2c1a63b26 +472, 0xc93fbcced6bacc00 +473, 0xabc3dfbdcc9b8fc +474, 0x6b4ba01186620ec0 +475, 0xbb32573515ef782b +476, 0x174d712e47dc77ee +477, 0xd0528205819fe3ee +478, 0xab1f77e5dc7b0e95 +479, 0x7f86317fcf8bc84a +480, 0xa7806c55ff0b4f49 +481, 0xe8cdce88ac77263 +482, 0x2e497636f939d7c1 +483, 0x9ff5e2c32edc3ee +484, 0x71579e5276731bbf +485, 0x565c679f3f2eb61c +486, 0xc2a747df0c436c +487, 0xfc30f2f9d9489081 +488, 0x74548f1d9581fed5 +489, 0xb5819230ffd9afeb +490, 0x228ff1227ebe13cc +491, 0x38ac137ff54ff158 +492, 0x41ed776d549ca7da +493, 0xb4cfe4cc90297ff +494, 0x17988d6ed8190a5d +495, 0xe27817eb69723f90 +496, 0xbe1cee1533890e29 +497, 0x8ee48e99d9a74f22 +498, 0xa31a5dceb1db5438 +499, 0xeecbbf998e1c0d43 +500, 0x6f8e0b0b2b361b9b +501, 0x2a102fca177728ae +502, 0x55a27f350de42380 +503, 0xc45ace761d5cf37b +504, 0xe14d0182a002d8a6 +505, 0xc05841ad2de5d64 +506, 0xca6b7b7131476892 +507, 0xe4a92da10eada512 +508, 0xf7a33c11f8927959 +509, 0x7b47639e2bcd8c44 +510, 0xaed8ec8dc551d755 +511, 0xba4b5ffd28ad78b7 +512, 0xc30ddd4d1df6ce2b +513, 0xe1b9bd0020b56548 +514, 0x8f73edbced893634 +515, 0x738098d32669cab4 +516, 0x28c03717c5adc3c0 +517, 0xbc044ebe07a8f4f3 +518, 0xc3083814802950fb +519, 0x8639da9ccdd4068 +520, 0x2ac89cfb975e2c41 +521, 0x8e163ccdbc863461 +522, 0x4a60169f9a3648fe +523, 0x6694ab36d7d02548 +524, 0x6b4e5764db952413 +525, 0xbf842329b9a13bfa +526, 0x1c8639cae82e7d92 +527, 0xd5669e818fb34170 +528, 0x1f4df6bc59f9f6aa +529, 0x8b192245d457c5a0 +530, 0xdff62af9d9eb696d +531, 0x53dcf9276ae1ab0f +532, 0xc1c4052d4c9d3c16 +533, 0x5c5f7b33e6aa6e0e +534, 0x482c8e4be2a5d704 +535, 0xc5d1632e532ddf97 +536, 0x92a41d90396b49c6 +537, 0xf895429c172ec71c +538, 0xab3ed20fad9ae896 +539, 0xbecd1ee462ba9dee +540, 0x29e020d2bf854671 +541, 0x4a31b52b2b48d795 +542, 0x14b2c4bf2ff453a2 +543, 0xbd49a5992f3deac2 +544, 0xfe19fe4becf1b1c8 +545, 0xa90ede0ced2811cb +546, 0x409de5d1234b16fb +547, 0x4eb18dd87fdd6cd7 +548, 0x52387faf2214a168 +549, 0x18678b302a911d42 +550, 0x484ccf18cb491bbe +551, 0x8610462c7e48b54d +552, 0xb2b2712e35cc4282 +553, 0x754abdb493e3ce4f +554, 0x352745881ade5eea +555, 0x37d4c7cc6c238692 +556, 0xe7a8061b7c0259d2 +557, 0x187e5ee097b24be1 +558, 0x41af64f7cecc63e0 +559, 0x33612ca0ca35a2bf +560, 0xc8b652dc6cdd0829 +561, 0xd050306acf3314b4 +562, 0x7bb7c4114d5d2347 +563, 0xd583132ce17b2f9c +564, 0x1473fcb33448ece2 +565, 0x5f9d56e869d06300 +566, 0x45c27eae73dd6391 +567, 0x15164b3b33d2c145 +568, 0x32991907d6370c8 +569, 0x9445ff1373a9635b +570, 0xf33ffa711ebc9d97 +571, 0x38dc80e03d8badcf +572, 0xf346f6f42e3c396e +573, 0x47bae2fa3827f514 +574, 0xde0e4fc698e6a6d1 +575, 0xd26d4b4097367afd +576, 0x16dea3bef70fe858 +577, 0x226decb65f433fa0 +578, 0x2e4b7f4915de64c7 +579, 0x4f31a10935fcd415 +580, 0x5e3e420e134d2191 +581, 0x52bf5207327dfe09 +582, 0xd8c4ab9ec015b93a +583, 0x55154818bf1ca7c9 +584, 0xc121666af28dcc9a +585, 0x9904729e1a01bd3c +586, 0x6e9cae3d292339bc +587, 0xf6fb78d385e10840 +588, 0x8fb67f5e56ee1e0b +589, 0xba17083a33230c28 +590, 0x9994a47b97c3dc9f +591, 0x53391314bd23bebb +592, 0x9ad473ee0eacee3b +593, 0xaec807e5cb1f0f18 +594, 0x5d5838c5e16e82ba +595, 0x7c810095640d10df +596, 0x898b9da105d90061 +597, 0x9296de76fe275a73 +598, 0xb118361c5dad2c6d +599, 0x4b9051df7724b504 +600, 0xd91789023183a552 +601, 0xc35ca6285eea0aaf +602, 0xb6fb918229e8bb05 +603, 0x4f3f41b3fe26df66 +604, 0xb63885de73089f64 +605, 0xc55aad297e8db9cc +606, 0x7a5ebc6cbb977bf9 +607, 0x122478e8d6b4b5fa +608, 0x52f69dc782aba318 +609, 0xce068981160e9756 +610, 0x303897ea358b700b +611, 0x9963ff7db9effb75 +612, 0xa3e4224b2372dc4a +613, 0x68d78fde1f0b1e +614, 0xb895f75785c0ec92 +615, 0x3df2981af65f3be6 +616, 0x88b17d18c7584a58 +617, 0x560834beafb27138 +618, 0xfa1d9ee07edbf359 +619, 0xc27c98d528ba33f8 +620, 0x58873114fbc61614 +621, 0x3f8112bff34dd5fc +622, 0xbe7fbc694b26e7a1 +623, 0x323d8907780f85fb +624, 0x7e77f48feec1f69a +625, 0xf6d8ac3573ac4ba4 +626, 0xf013633aaba2cd2c +627, 0x5c3153cd6f9f2fd8 +628, 0x4c3ae3906dc4e92a +629, 0xd2f375cec67af24d +630, 0x31943d0c1139dced +631, 0x95ee9d16c2320163 +632, 0x1c0f03c058441f3b +633, 0xa4dd49a2abbb39a5 +634, 0xcf6c4c9c695783ec +635, 0xbb0ea4c9a55af9ac +636, 0xb6a7a4c82fb232d5 +637, 0xd090cc06191a5d2f +638, 0x653c0a506097397e +639, 0x5a5af47067bba201 +640, 0x23df206d3d6f105 +641, 0x8501560fac79fa17 +642, 0x2b95d59621a424c8 +643, 0xb20ca1d29061c6cd +644, 0x9824922790be5c12 +645, 0xdee7448af6c82ce +646, 0xb57c8ab1b2b0ddb1 +647, 0x9241c7effe12d339 +648, 0xf69967036e960af9 +649, 0xe2e14558fcf89166 +650, 0x23a16c73c276d451 +651, 0x9fdd05ed8828875b +652, 0xc3466fd3814d3253 +653, 0xdfc9c839dc99a11d +654, 0x16693a83f78664fe +655, 0x65da2039561d5402 +656, 0x20b0d78000a063fa +657, 0x6b1346e833500ca1 +658, 0x7aa4a72cf75d077b +659, 0x378c2101d36355d8 +660, 0x95910003849a5839 +661, 0x4ad588ff7fe780cc +662, 0xd64d44efcf333e82 +663, 0x2f16c1742dcd9e7 +664, 0xd52ee978f72d63c2 +665, 0xaebda4339041c968 +666, 0x909d2433eedf9e81 +667, 0x670d7dbb7420f9da +668, 0x2880a01109e20500 +669, 0x7b48c2a4e918f6a1 +670, 0xf38fac2caf78d1c +671, 0x426944a0a0fcca7f +672, 0x24331c63647d4d36 +673, 0xc8e11bd52e232844 +674, 0xe7fb6b0ccc6a867a +675, 0x5c797fb7a7603019 +676, 0x2f6b2971284d996a +677, 0x96a89cf3747fd01f +678, 0x9aaedf8572e12afe +679, 0xdf9e5a2214174223 +680, 0x163ed5bedfd06b59 +681, 0x6c45e87d73677bae +682, 0x97b415906449e5ce +683, 0x53f30cd13d0bca1c +684, 0x86b204c8a1775e1d +685, 0x7ab03915913dbaa3 +686, 0x30767dc8d5a8e96 +687, 0x4b4fd100a4d86d59 +688, 0x65a5dfabb1a06ea1 +689, 0x59632b7fec7ad10e +690, 0x2d436b149509d8 +691, 0x37a45927a3898861 +692, 0x396db74b149f86d4 +693, 0xa1fdf757db1de83 +694, 0x3a08d99d4a60dae3 +695, 0x9df8a778bfd97996 +696, 0xc7196b2c8db56799 +697, 0x9378d20ec50eeffb +698, 0xb9ecc104b558e25c +699, 0x2929a6ddc011e01d +700, 0x5c8e297d48eaa335 +701, 0x9e000149b1821081 +702, 0xa8d080481a874776 +703, 0xedb2e0fcc8695de1 +704, 0x31c38628250d2d1f +705, 0xd92b4c99893c21a0 +706, 0xa56a77e01dffa3e6 +707, 0xa607e4ebc9c39fb5 +708, 0x6c8f5f7df2cddeaa +709, 0x1180c33d565487aa +710, 0xf4c66f402b7c1a21 +711, 0x4bd81bbcbe186a4d +712, 0x623e742bf4cfc10c +713, 0x84074e36e58825dc +714, 0xaa70f6dfdd617ae3 +715, 0xe305ea5aaf5aea74 +716, 0xc4726917aa5914ec +717, 0x317bbc6430cf6442 +718, 0x5b8af46f34f146a2 +719, 0xe4552970afbf97bd +720, 0x20d7a393f8176838 +721, 0x5e4a65ab657c7d2b +722, 0x1e430b0ad9e6fe49 +723, 0xa51866b0155c88d4 +724, 0xf1e2cdf07c51638f +725, 0x50f57c27c4e00a44 +726, 0x23bd9255fbb896d0 +727, 0xa91748820079892f +728, 0xb4d156ae147d6fab +729, 0xb3a474a3480c38a9 +730, 0x45dbbb715f1e3085 +731, 0x585986863049a87c +732, 0x436045cd7d1a9172 +733, 0x236972e814d5a4d +734, 0x2249b5f676f29b8a +735, 0x67fdcd55de80a8a9 +736, 0xd4fe890341189ee6 +737, 0x70e1eac3eb0a498d +738, 0xce1c2beb72f7cff3 +739, 0x50d28189d52b5785 +740, 0x93c740175c287808 +741, 0xf29621c38e8a1044 +742, 0x32d50b2824a59d70 +743, 0x8d595966ab119908 +744, 0xa5750cc7ceb0823 +745, 0xbcdefc996aed9ceb +746, 0xc1d70bb5480e2778 +747, 0x942b3f26a50fec6d +748, 0xa7d4851f6990be3d +749, 0x4086348def6e7c11 +750, 0x18aa95009f903221 +751, 0x3010f2c49ca532ad +752, 0xe9e9b21cd5552b31 +753, 0xd90541d86fbd9566 +754, 0x9240f2d8ffffd945 +755, 0xc7815330b2fd5f62 +756, 0x89040a5ec01115f3 +757, 0x4da5e5bb136d77ec +758, 0xc6a489d50839194b +759, 0x37839dcfaa606c7f +760, 0x8177b7be1443adb8 +761, 0xf588b929a63b0790 +762, 0x900a6482fa22b6de +763, 0x845502c244d08f04 +764, 0xc0a8f114df2a3608 +765, 0x5e201627c73573b9 +766, 0xa371ef9c7fc8ac6c +767, 0xca8a07e82c615463 +768, 0xba00e6e8d1c033db +769, 0xcd76dbe8a10cf399 +770, 0x959fe93180800aec +771, 0x8e77fa85404e4cce +772, 0x7b34e8983b9be1b4 +773, 0x81c0125be3d132bf +774, 0xfdbc9bb181a67f5c +775, 0xf2d7962c98584eaa +776, 0x8922b4291b6d0d41 +777, 0xb8235b21de4093bf +778, 0xc94518b4e632edb7 +779, 0x757f43c099ff5783 +780, 0xc063132013dafb63 +781, 0xfd579036a7030019 +782, 0xa5f0638c9ead0004 +783, 0x7494b34172659deb +784, 0x481772ff25eadcfe +785, 0x72e37428f1e21d99 +786, 0x5cf98e5c40aa77e1 +787, 0xb3ce6c54df0aedf1 +788, 0xf00af8c613bcd8f8 +789, 0xd1237f23a07b0e3a +790, 0xa8fe00d99f32f731 +791, 0x8b85f312af567228 +792, 0xdc2515684772c84d +793, 0x7d11b82c9e31766f +794, 0xf09c8697b3ff95c4 +795, 0xd35ebc77a86212eb +796, 0xadb5a1e95afb5f6d +797, 0x6ed845ef3fcadff1 +798, 0xaeb029f4caacb130 +799, 0x7cce6f1bf0ed8e7c +800, 0x23b6201003d49e50 +801, 0x6dfbf0e3c21a03de +802, 0x4729d4f0e6a9240c +803, 0x40af60788c357e6 +804, 0xcd17f1e93dca508b +805, 0x24a823f6424d2821 +806, 0x35194e11b535d3ef +807, 0x948f055d9436932b +808, 0x4e733969108a5551 +809, 0x3c0816162700c63e +810, 0x7370a331ce8096a2 +811, 0xfcf5caf742e23baf +812, 0xe960bb3fe0308e95 +813, 0x8ef061808248efc7 +814, 0x16c6c5da0fcf1296 +815, 0x14a05c065cffe433 +816, 0x568dd4ba989a423 +817, 0xd20a156a56768914 +818, 0x9872a06bbf694ad8 +819, 0x8ac764e367433878 +820, 0x2453eb53416ca0c4 +821, 0xa59ef657a7de7140 +822, 0x43cb5c3119ddabac +823, 0x645ebee1c5d62133 +824, 0xacf017344a2a6031 +825, 0xc22ebb7b220dba01 +826, 0x9048e327d43fc69c +827, 0xca2319dcd6c49370 +828, 0x63844574971006d8 +829, 0x7ce248cd860d2997 +830, 0x4d5780b45f802359 +831, 0x99798ec46c6536c5 +832, 0x4a42d4a45bdc0a1c +833, 0x75f126405fa990ba +834, 0xa1cf7cf0ee32ac82 +835, 0x12b722bce6d8b9a6 +836, 0x85ace663a1f92677 +837, 0x5f0514135be46137 +838, 0xb86863169f76d2f4 +839, 0x1dfc6f087c8721df +840, 0xde984a38824ac47b +841, 0x249504789c3f7704 +842, 0xaab5d4d12f9df445 +843, 0x863caa50cd8764c9 +844, 0x24cf6ca7a6a8e5ab +845, 0xf293f7488a738c5d +846, 0x2936a321fe93cce5 +847, 0xf5b2504862ce0521 +848, 0x9d6f9350f3a2b4f3 +849, 0x5093102345eb9ef0 +850, 0x20aaace8135cecbb +851, 0x252a8e893ad79698 +852, 0x2c68c7a18c5bb936 +853, 0xf973af891f51cfc0 +854, 0xe5c661b55596bcfd +855, 0x98b08b4904602dbd +856, 0x9fcde37c43372b73 +857, 0xa5d05483d489e6ce +858, 0x8b359f723ae63264 +859, 0xadaa0de5bdbd2d33 +860, 0xa4976d2755a6096 +861, 0x7174d708c2537633 +862, 0x24d86478fd44e33e +863, 0x8a0abcdb74f29fcb +864, 0x1fbf39da74328bcd +865, 0x2c5973fdfcbbf09f +866, 0xe23b300ec45a7b8b +867, 0x69019e93b3633c1d +868, 0x749053f7f30d6029 +869, 0x84aa9ded82b4a5c1 +870, 0xb6bb6cb827d5bcb8 +871, 0x503002036e031d34 +872, 0xba06a59f171023a1 +873, 0x733ccfc01e97abba +874, 0xa34cc599a30202ea +875, 0x7581c12df8a4174 +876, 0x8ee2efea87ff8766 +877, 0x2cd79614de9ff639 +878, 0xb190669d3052a8f0 +879, 0x9f3d98c2c3fc3266 +880, 0x48555e89c5b6184e +881, 0x4b9c73be9c8e8ec2 +882, 0xeee8586bdb309974 +883, 0x823a9e3bb2741bbd +884, 0x94a1a50e42fed547 +885, 0x2d7fcb9382eb1ba1 +886, 0xece0e31c5bb89719 +887, 0x440c75600472ddb2 +888, 0x28990d7882d9563c +889, 0x4e9b55cfdbe05ae9 +890, 0x4dba7e062bc24994 +891, 0x71faedf4414cbab1 +892, 0xb12901b28a65ce11 +893, 0xc0834509da822274 +894, 0x7daf95e13d676f29 +895, 0x6bc8df584cd07431 +896, 0xc614bbb95c749cd6 +897, 0x11d888ab3d6e9f38 +898, 0x8f4b7c7b0bda401b +899, 0x5eae46c2079e6f7d +900, 0x9c6f616b61328d61 +901, 0x9415dd3fea046eeb +902, 0x2b04d5dc9a25c2b2 +903, 0x402fd8a16781cf56 +904, 0xdc0be7170faaf41e +905, 0x23d4fe72e8f2fa1d +906, 0x18909afc53a4bce1 +907, 0xc8cfb6a2c1f230bb +908, 0x8268ee65c393a138 +909, 0x9c6b4210f409a598 +910, 0xe3122eb7e28e1c8a +911, 0xe3f0903f892e2aee +912, 0xc51ead0ad0dd1fb8 +913, 0xb2e7343037d7e6f0 +914, 0x89376733a7d3d9b7 +915, 0x13e1f3b9da7cc130 +916, 0xe1911b0a3fa4089b +917, 0xfdc131f18d761b91 +918, 0x782dbb406f0453f9 +919, 0xa61c1d244fdbea55 +920, 0xa4d2ed4dfd8bf85a +921, 0x3459f746e0a71313 +922, 0xa4f67e188e38d8c9 +923, 0x271dd484aee01e22 +924, 0x1907c912ddab4c06 +925, 0xed295346066663cc +926, 0xbebf878973ec93bb +927, 0x464b6c605cf80b2f +928, 0x924f8c5d8af46c76 +929, 0x8a705a5045a54c51 +930, 0xbe630deef4598083 +931, 0x63a782885bf2ef56 +932, 0x5c408ad85ab683f8 +933, 0x5a35bf59ca6db7f0 +934, 0x995b786bc77fcae8 +935, 0x93ac6c1d806cfe6a +936, 0xdc8ad969faae9220 +937, 0x67eda7e6d2b41375 +938, 0x21d2eeb2f58da10e +939, 0x4209dff5fec899a2 +940, 0x1b30fe5b2d96eddd +941, 0x3959011cb1541a05 +942, 0xfd0400e18394ce3e +943, 0xfff052e033e0ce86 +944, 0x569bb5da57a3cf2e +945, 0x45e0ef9753a2731e +946, 0xf6c64d69371ef3ea +947, 0xff6e5d50e2b29841 +948, 0x57334a6acad31efd +949, 0x3f39b0989b465114 +950, 0x9bf7bda3bc70b5dd +951, 0x44adb420df4b19ae +952, 0xa32ca7df58be9881 +953, 0x1af3b91f5078f255 +954, 0x9b1c0f815dba0781 +955, 0x29a5f5869108b99f +956, 0x890ebd600b286b45 +957, 0x4fdbfbba80a094ba +958, 0xbb42ae41c9679296 +959, 0xf51a153b2e4ea0d2 +960, 0xcb01bcb495a01869 +961, 0x1005c4deb506d28e +962, 0x3e1213bfd6496f47 +963, 0x388f29b4151fb7aa +964, 0xe75b0d72872db802 +965, 0xc764bfae67627d2f +966, 0xb86fd279622fb937 +967, 0x3fc887ebd2afa4e6 +968, 0x850b7ec2436195dc +969, 0x11495c0c0e4d1d34 +970, 0xc98421a7c82ced +971, 0x8337132f8c2eea5a +972, 0x77eb95949a98f2f3 +973, 0xcb325cf4d527f0e3 +974, 0x483192546ec89241 +975, 0x957fba4dd4238c59 +976, 0x6b12c9edf75d9ac6 +977, 0x9e959f3749b97cc4 +978, 0x1d77ee83f6b337c1 +979, 0xf6cf70e9db6bee2a +980, 0x87155a5e5746a82b +981, 0x552b032dc590447e +982, 0xbb939df7cb2dc42d +983, 0x1db106ff15b953c7 +984, 0xcee301b609e43399 +985, 0xe9babbea0fc4b81c +986, 0x8ea4ec5562e67027 +987, 0x422d3637cfb0c29 +988, 0x534c6604cd9cc6c +989, 0x301f4f55a0fdac48 +990, 0xf6c4cc1ea05c27a5 +991, 0xa1f4a4d5b999fbb1 +992, 0x343425e806758ccd +993, 0x9641ccb506ca4b0f +994, 0xa94166fa9641d3f5 +995, 0xf344ca329bff56e1 +996, 0xbc49cac1233860fb +997, 0x9087c97dba7f230 +998, 0xf2acda7714a3d1f6 +999, 0x4d076fb8ea7d9b9a diff --git a/numpy/random/randomgen/tests/test_direct.py b/numpy/random/randomgen/tests/test_direct.py index 5bfc872cb188..6e856de414cb 100644 --- a/numpy/random/randomgen/tests/test_direct.py +++ b/numpy/random/randomgen/tests/test_direct.py @@ -9,7 +9,7 @@ from ...randomgen import RandomGenerator, MT19937, DSFMT, ThreeFry32, ThreeFry, \ PCG32, PCG64, Philox, Xoroshiro128, Xorshift1024, Xoshiro256StarStar, \ - Xoshiro512StarStar + Xoshiro512StarStar, RandomState from ...randomgen.common import interface try: @@ -51,14 +51,6 @@ def uniform32_from_uint64(x): out = (joined >> np.uint32(9)) * (1.0 / 2 ** 23) return out.astype(np.float32) - -def uniform32_from_uint63(x): - x = np.uint64(x) - x = np.uint32(x >> np.uint64(32)) - out = (x >> np.uint32(9)) * (1.0 / 2 ** 23) - return out.astype(np.float32) - - def uniform32_from_uint53(x): x = np.uint64(x) >> np.uint64(16) x = np.uint32(x & np.uint64(0xffffffff)) @@ -73,8 +65,6 @@ def uniform32_from_uint32(x): def uniform32_from_uint(x, bits): if bits == 64: return uniform32_from_uint64(x) - elif bits == 63: - return uniform32_from_uint63(x) elif bits == 53: return uniform32_from_uint53(x) elif bits == 32: @@ -102,16 +92,6 @@ def uniform_from_uint32(x): out[i // 2] = (a * 67108864.0 + b) / 9007199254740992.0 return out - -def uint64_from_uint63(x): - out = np.empty(len(x) // 2, dtype=np.uint64) - for i in range(0, len(x), 2): - a = x[i] & np.uint64(0xffffffff00000000) - b = x[i + 1] >> np.uint64(32) - out[i // 2] = a | b - return out - - def uniform_from_dsfmt(x): return x.view(np.double) - 1.0 @@ -185,15 +165,14 @@ def test_random_raw(self): uints = brng.random_raw(1000, output=False) assert uints is None - @pytest.mark.skip(reason='Polar transform no longer supported') def test_gauss_inv(self): n = 25 - rs = RandomGenerator(self.brng(*self.data1['seed'])) + rs = RandomState(self.brng(*self.data1['seed'])) gauss = rs.standard_normal(n) assert_allclose(gauss, gauss_from_uint(self.data1['data'], n, self.bits)) - rs = RandomGenerator(self.brng(*self.data2['seed'])) + rs = RandomState(self.brng(*self.data2['seed'])) gauss = rs.standard_normal(25) assert_allclose(gauss, gauss_from_uint(self.data2['data'], n, self.bits)) @@ -548,15 +527,14 @@ def test_uniform_double(self): assert_equal(uniform_from_dsfmt(self.data2['data']), rs.random_sample(1000)) - @pytest.mark.skip(reason='Polar transform no longer supported') def test_gauss_inv(self): n = 25 - rs = RandomGenerator(self.brng(*self.data1['seed'])) + rs = RandomState(self.brng(*self.data1['seed'])) gauss = rs.standard_normal(n) assert_allclose(gauss, gauss_from_uint(self.data1['data'], n, 'dsfmt')) - rs = RandomGenerator(self.brng(*self.data2['seed'])) + rs = RandomState(self.brng(*self.data2['seed'])) gauss = rs.standard_normal(25) assert_allclose(gauss, gauss_from_uint(self.data2['data'], n, 'dsfmt')) diff --git a/numpy/random/randomgen/tests/test_randomstate.py b/numpy/random/randomgen/tests/test_randomstate.py index 371be78de5bf..167d1b0aa545 100644 --- a/numpy/random/randomgen/tests/test_randomstate.py +++ b/numpy/random/randomgen/tests/test_randomstate.py @@ -1,5 +1,6 @@ -import warnings import pickle +import sys +import warnings import numpy as np from numpy.testing import ( @@ -7,7 +8,6 @@ assert_no_warnings, assert_array_equal, assert_array_almost_equal, suppress_warnings ) -import sys from ...randomgen import MT19937, Xoshiro256StarStar, mtrand as random From a1c15050b6efd8d2c5b40ae46bcb497260b4e88e Mon Sep 17 00:00:00 2001 From: kikocorreoso Date: Wed, 3 Apr 2019 00:38:11 +0200 Subject: [PATCH 241/279] Update release notes Update release notes to include "nan_to_num" information. --- doc/release/1.17.0-notes.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/release/1.17.0-notes.rst b/doc/release/1.17.0-notes.rst index 7857400e8a59..4e366648a99a 100644 --- a/doc/release/1.17.0-notes.rst +++ b/doc/release/1.17.0-notes.rst @@ -197,6 +197,12 @@ The boolean and integer types are incapable of storing ``np.nan`` and ``np.inf`` which allows us to provide specialized ufuncs that are up to 250x faster than the current approach. +New keywords added to ``np.nan_to_num`` +--------------------------------------- +``np.nan_to_num`` now accepts keywords ``nan``, ``posinf`` and ``neginf`` allowing the +user to define the value to replace the ``nan``s, positive and negative ``np.inf``s +respectively. + Changes ======= From 96e9b1d50cbf957ad4d4805f9dbeae68bd6f1078 Mon Sep 17 00:00:00 2001 From: Tyler Reddy Date: Tue, 2 Apr 2019 15:54:10 -0700 Subject: [PATCH 242/279] TST: fail Azure CI if test failures * fail Azure CI after test publication when there are test failures --- azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d240e587f739..4e8a8d654bb2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -32,7 +32,7 @@ jobs: - task: PublishTestResults@2 inputs: testResultsFiles: '**/test-*.xml' - failTaskOnFailedTests: false + failTaskOnFailedTests: true testRunTitle: 'Publish test results for Python 3.6-32 bit full Linux' - job: macOS pool: @@ -105,7 +105,7 @@ jobs: - task: PublishTestResults@2 inputs: testResultsFiles: '**/test-*.xml' - failTaskOnFailedTests: false + failTaskOnFailedTests: true testRunTitle: 'Publish test results for Python 3.6 64-bit full Mac OS' - job: Windows pool: @@ -208,5 +208,5 @@ jobs: - task: PublishTestResults@2 inputs: testResultsFiles: '**/test-*.xml' - failTaskOnFailedTests: false + failTaskOnFailedTests: true testRunTitle: 'Publish test results for Python $(PYTHON_VERSION) $(BITS)-bit $(TEST_MODE) Windows' From c1bf6a600cb4c8c7261a000f47b11ef8fd9f792d Mon Sep 17 00:00:00 2001 From: vrindaaa <48102157+vrindaaa@users.noreply.github.com> Date: Wed, 3 Apr 2019 21:36:50 +0530 Subject: [PATCH 243/279] DOC : PyArray_Descr.names undocumented (#13234) * Updating the definition of PyArray_Descr struct --- .../reference/c-api.types-and-structures.rst | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/doc/source/reference/c-api.types-and-structures.rst b/doc/source/reference/c-api.types-and-structures.rst index f04d65ee1b63..f411ebc44f26 100644 --- a/doc/source/reference/c-api.types-and-structures.rst +++ b/doc/source/reference/c-api.types-and-structures.rst @@ -203,14 +203,17 @@ PyArrayDescr_Type char kind; char type; char byteorder; - char unused; - int flags; + char flags; int type_num; int elsize; int alignment; PyArray_ArrayDescr *subarray; PyObject *fields; + PyObject *names; PyArray_ArrFuncs *f; + PyObject *metadata; + NpyAuxData *c_metadata; + npy_hash_t hash; } PyArray_Descr; .. c:member:: PyTypeObject *PyArray_Descr.typeobj @@ -242,7 +245,7 @@ PyArrayDescr_Type endian), '=' (native), '\|' (irrelevant, ignore). All builtin data- types have byteorder '='. -.. c:member:: int PyArray_Descr.flags +.. c:member:: char PyArray_Descr.flags A data-type bit-flag that determines if the data-type exhibits object- array like behavior. Each bit in this member is a flag which are named @@ -377,6 +380,11 @@ PyArrayDescr_Type normally a Python string. These tuples are placed in this dictionary keyed by name (and also title if given). +.. c:member:: PyObject *PyArray_Descr.names + + An ordered tuple of field names. It is NULL if no field is + defined. + .. c:member:: PyArray_ArrFuncs *PyArray_Descr.f A pointer to a structure containing functions that the type needs @@ -384,6 +392,20 @@ PyArrayDescr_Type thing as the universal functions (ufuncs) described later. Their signatures can vary arbitrarily. +.. c:member:: PyObject *PyArray_Descr.metadata + + Metadata about this dtype. + +.. c:member:: NpyAuxData *PyArray_Descr.c_metadata + + Metadata specific to the C implementation + of the particular dtype. Added for NumPy 1.7.0. + +.. c:member:: Npy_hash_t *PyArray_Descr.hash + + Currently unused. Reserved for future use in caching + hash values. + .. c:type:: PyArray_ArrFuncs Functions implementing internal features. Not all of these From 0a9c313cbe3e625fc1fbe47b37e71d768884afce Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 2 Apr 2019 12:54:37 +0300 Subject: [PATCH 244/279] BUG: fix docstring tests --- numpy/random/randomgen/mtrand.pyx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/numpy/random/randomgen/mtrand.pyx b/numpy/random/randomgen/mtrand.pyx index fcc7a1d7dea7..d5a60e23dd15 100644 --- a/numpy/random/randomgen/mtrand.pyx +++ b/numpy/random/randomgen/mtrand.pyx @@ -135,8 +135,8 @@ cdef class RandomState: The best method to access seed is to directly use a basic RNG instance. This example demonstrates this best practice. - >>> from np.random.randomgen import MT19937 - >>> from np.random import RandomState + >>> from numpy.random.randomgen import MT19937 + >>> from numpy.random import RandomState >>> brng = MT19937(123456789) >>> rs = RandomState(brng) >>> brng.seed(987654321) @@ -148,7 +148,6 @@ cdef class RandomState: """ self._basicrng.seed(*args, **kwargs) self._reset_gauss() - return self def get_state(self, legacy=True): """ From b7e01f3af73bc7d86431f70928fab37319b085c3 Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 2 Apr 2019 13:17:02 +0300 Subject: [PATCH 245/279] MAINT: move documentation, add to autosummary --- .gitignore | 2 +- doc/source/conf.py | 4 +++- doc/source/{random => reference/randomgen}/brng/dsfmt.rst | 0 doc/source/{random => reference/randomgen}/brng/index.rst | 0 doc/source/{random => reference/randomgen}/brng/mt19937.rst | 0 doc/source/{random => reference/randomgen}/brng/pcg32.rst | 0 doc/source/{random => reference/randomgen}/brng/pcg64.rst | 0 doc/source/{random => reference/randomgen}/brng/philox.rst | 0 doc/source/{random => reference/randomgen}/brng/threefry.rst | 0 .../{random => reference/randomgen}/brng/threefry32.rst | 0 .../{random => reference/randomgen}/brng/xoroshiro128.rst | 0 .../{random => reference/randomgen}/brng/xorshift1024.rst | 0 .../randomgen}/brng/xoshiro256starstar.rst | 0 .../randomgen}/brng/xoshiro512starstar.rst | 0 doc/source/{random => reference/randomgen}/change-log.rst | 0 doc/source/{random => reference/randomgen}/conf.py | 0 doc/source/{random => reference/randomgen}/entropy.rst | 0 doc/source/{random => reference/randomgen}/extending.rst | 0 doc/source/{random => reference/randomgen}/generator.rst | 0 doc/source/{random => reference/randomgen}/index.rst | 0 doc/source/{random => reference/randomgen}/legacy.rst | 0 doc/source/{random => reference/randomgen}/multithreading.rst | 0 .../{random => reference/randomgen}/new-or-different.rst | 0 doc/source/{random => reference/randomgen}/parallel.rst | 0 doc/source/{random => reference/randomgen}/performance.py | 0 doc/source/{random => reference/randomgen}/performance.rst | 0 doc/source/{random => reference/randomgen}/references.rst | 0 27 files changed, 4 insertions(+), 2 deletions(-) rename doc/source/{random => reference/randomgen}/brng/dsfmt.rst (100%) rename doc/source/{random => reference/randomgen}/brng/index.rst (100%) rename doc/source/{random => reference/randomgen}/brng/mt19937.rst (100%) rename doc/source/{random => reference/randomgen}/brng/pcg32.rst (100%) rename doc/source/{random => reference/randomgen}/brng/pcg64.rst (100%) rename doc/source/{random => reference/randomgen}/brng/philox.rst (100%) rename doc/source/{random => reference/randomgen}/brng/threefry.rst (100%) rename doc/source/{random => reference/randomgen}/brng/threefry32.rst (100%) rename doc/source/{random => reference/randomgen}/brng/xoroshiro128.rst (100%) rename doc/source/{random => reference/randomgen}/brng/xorshift1024.rst (100%) rename doc/source/{random => reference/randomgen}/brng/xoshiro256starstar.rst (100%) rename doc/source/{random => reference/randomgen}/brng/xoshiro512starstar.rst (100%) rename doc/source/{random => reference/randomgen}/change-log.rst (100%) rename doc/source/{random => reference/randomgen}/conf.py (100%) rename doc/source/{random => reference/randomgen}/entropy.rst (100%) rename doc/source/{random => reference/randomgen}/extending.rst (100%) rename doc/source/{random => reference/randomgen}/generator.rst (100%) rename doc/source/{random => reference/randomgen}/index.rst (100%) rename doc/source/{random => reference/randomgen}/legacy.rst (100%) rename doc/source/{random => reference/randomgen}/multithreading.rst (100%) rename doc/source/{random => reference/randomgen}/new-or-different.rst (100%) rename doc/source/{random => reference/randomgen}/parallel.rst (100%) rename doc/source/{random => reference/randomgen}/performance.py (100%) rename doc/source/{random => reference/randomgen}/performance.rst (100%) rename doc/source/{random => reference/randomgen}/references.rst (100%) diff --git a/.gitignore b/.gitignore index 8926a73bd62c..e8c8f290889e 100644 --- a/.gitignore +++ b/.gitignore @@ -167,7 +167,7 @@ numpy/core/src/umath/test_rational.c numpy/core/src/umath/umath_tests.c numpy/distutils/__config__.py numpy/linalg/umath_linalg.c -doc/source/reference/generated +doc/source/**/generated/ benchmarks/results benchmarks/html benchmarks/env diff --git a/doc/source/conf.py b/doc/source/conf.py index 072a3b44e5dc..d7812d1430fa 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -234,7 +234,9 @@ def setup(app): # ----------------------------------------------------------------------------- import glob -autosummary_generate = glob.glob("reference/*.rst") +autosummary_generate = (glob.glob("reference/*.rst") + + glob.glob("reference/randomgen/*.rst") + + glob.glob("reference/randomgen/brng/*.rst")) # ----------------------------------------------------------------------------- # Coverage checker diff --git a/doc/source/random/brng/dsfmt.rst b/doc/source/reference/randomgen/brng/dsfmt.rst similarity index 100% rename from doc/source/random/brng/dsfmt.rst rename to doc/source/reference/randomgen/brng/dsfmt.rst diff --git a/doc/source/random/brng/index.rst b/doc/source/reference/randomgen/brng/index.rst similarity index 100% rename from doc/source/random/brng/index.rst rename to doc/source/reference/randomgen/brng/index.rst diff --git a/doc/source/random/brng/mt19937.rst b/doc/source/reference/randomgen/brng/mt19937.rst similarity index 100% rename from doc/source/random/brng/mt19937.rst rename to doc/source/reference/randomgen/brng/mt19937.rst diff --git a/doc/source/random/brng/pcg32.rst b/doc/source/reference/randomgen/brng/pcg32.rst similarity index 100% rename from doc/source/random/brng/pcg32.rst rename to doc/source/reference/randomgen/brng/pcg32.rst diff --git a/doc/source/random/brng/pcg64.rst b/doc/source/reference/randomgen/brng/pcg64.rst similarity index 100% rename from doc/source/random/brng/pcg64.rst rename to doc/source/reference/randomgen/brng/pcg64.rst diff --git a/doc/source/random/brng/philox.rst b/doc/source/reference/randomgen/brng/philox.rst similarity index 100% rename from doc/source/random/brng/philox.rst rename to doc/source/reference/randomgen/brng/philox.rst diff --git a/doc/source/random/brng/threefry.rst b/doc/source/reference/randomgen/brng/threefry.rst similarity index 100% rename from doc/source/random/brng/threefry.rst rename to doc/source/reference/randomgen/brng/threefry.rst diff --git a/doc/source/random/brng/threefry32.rst b/doc/source/reference/randomgen/brng/threefry32.rst similarity index 100% rename from doc/source/random/brng/threefry32.rst rename to doc/source/reference/randomgen/brng/threefry32.rst diff --git a/doc/source/random/brng/xoroshiro128.rst b/doc/source/reference/randomgen/brng/xoroshiro128.rst similarity index 100% rename from doc/source/random/brng/xoroshiro128.rst rename to doc/source/reference/randomgen/brng/xoroshiro128.rst diff --git a/doc/source/random/brng/xorshift1024.rst b/doc/source/reference/randomgen/brng/xorshift1024.rst similarity index 100% rename from doc/source/random/brng/xorshift1024.rst rename to doc/source/reference/randomgen/brng/xorshift1024.rst diff --git a/doc/source/random/brng/xoshiro256starstar.rst b/doc/source/reference/randomgen/brng/xoshiro256starstar.rst similarity index 100% rename from doc/source/random/brng/xoshiro256starstar.rst rename to doc/source/reference/randomgen/brng/xoshiro256starstar.rst diff --git a/doc/source/random/brng/xoshiro512starstar.rst b/doc/source/reference/randomgen/brng/xoshiro512starstar.rst similarity index 100% rename from doc/source/random/brng/xoshiro512starstar.rst rename to doc/source/reference/randomgen/brng/xoshiro512starstar.rst diff --git a/doc/source/random/change-log.rst b/doc/source/reference/randomgen/change-log.rst similarity index 100% rename from doc/source/random/change-log.rst rename to doc/source/reference/randomgen/change-log.rst diff --git a/doc/source/random/conf.py b/doc/source/reference/randomgen/conf.py similarity index 100% rename from doc/source/random/conf.py rename to doc/source/reference/randomgen/conf.py diff --git a/doc/source/random/entropy.rst b/doc/source/reference/randomgen/entropy.rst similarity index 100% rename from doc/source/random/entropy.rst rename to doc/source/reference/randomgen/entropy.rst diff --git a/doc/source/random/extending.rst b/doc/source/reference/randomgen/extending.rst similarity index 100% rename from doc/source/random/extending.rst rename to doc/source/reference/randomgen/extending.rst diff --git a/doc/source/random/generator.rst b/doc/source/reference/randomgen/generator.rst similarity index 100% rename from doc/source/random/generator.rst rename to doc/source/reference/randomgen/generator.rst diff --git a/doc/source/random/index.rst b/doc/source/reference/randomgen/index.rst similarity index 100% rename from doc/source/random/index.rst rename to doc/source/reference/randomgen/index.rst diff --git a/doc/source/random/legacy.rst b/doc/source/reference/randomgen/legacy.rst similarity index 100% rename from doc/source/random/legacy.rst rename to doc/source/reference/randomgen/legacy.rst diff --git a/doc/source/random/multithreading.rst b/doc/source/reference/randomgen/multithreading.rst similarity index 100% rename from doc/source/random/multithreading.rst rename to doc/source/reference/randomgen/multithreading.rst diff --git a/doc/source/random/new-or-different.rst b/doc/source/reference/randomgen/new-or-different.rst similarity index 100% rename from doc/source/random/new-or-different.rst rename to doc/source/reference/randomgen/new-or-different.rst diff --git a/doc/source/random/parallel.rst b/doc/source/reference/randomgen/parallel.rst similarity index 100% rename from doc/source/random/parallel.rst rename to doc/source/reference/randomgen/parallel.rst diff --git a/doc/source/random/performance.py b/doc/source/reference/randomgen/performance.py similarity index 100% rename from doc/source/random/performance.py rename to doc/source/reference/randomgen/performance.py diff --git a/doc/source/random/performance.rst b/doc/source/reference/randomgen/performance.rst similarity index 100% rename from doc/source/random/performance.rst rename to doc/source/reference/randomgen/performance.rst diff --git a/doc/source/random/references.rst b/doc/source/reference/randomgen/references.rst similarity index 100% rename from doc/source/random/references.rst rename to doc/source/reference/randomgen/references.rst From fc94ef30f60418246259014e2407936217dc73a1 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 3 Apr 2019 21:17:00 +0300 Subject: [PATCH 246/279] DOC: add randomgen docs --- doc/Makefile | 3 +- doc/source/conf.py | 27 ++- doc/source/reference/randomgen/brng/dsfmt.rst | 4 +- .../reference/randomgen/brng/mt19937.rst | 4 +- doc/source/reference/randomgen/brng/pcg32.rst | 4 +- doc/source/reference/randomgen/brng/pcg64.rst | 4 +- .../reference/randomgen/brng/philox.rst | 4 +- .../reference/randomgen/brng/threefry.rst | 4 +- .../reference/randomgen/brng/threefry32.rst | 4 +- .../reference/randomgen/brng/xoroshiro128.rst | 4 +- .../reference/randomgen/brng/xorshift1024.rst | 4 +- .../randomgen/brng/xoshiro256starstar.rst | 4 +- .../randomgen/brng/xoshiro512starstar.rst | 4 +- doc/source/reference/randomgen/conf.py | 221 ------------------ doc/source/reference/randomgen/entropy.rst | 2 +- doc/source/reference/randomgen/generator.rst | 7 +- doc/source/reference/randomgen/index.rst | 10 +- doc/source/reference/randomgen/legacy.rst | 10 +- 18 files changed, 56 insertions(+), 268 deletions(-) delete mode 100644 doc/source/reference/randomgen/conf.py diff --git a/doc/Makefile b/doc/Makefile index cb8f8a397fd1..d39d2c091e13 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -41,7 +41,8 @@ help: @echo " upload USERNAME=... RELEASE=... to upload built docs to docs.scipy.org" clean: - -rm -rf build/* source/reference/generated + -rm -rf build/* + find . -name generated -type d -prune -exec rm -rf "{}" ";" gitwash-update: rm -rf source/dev/gitwash diff --git a/doc/source/conf.py b/doc/source/conf.py index d7812d1430fa..dec8fff05b2f 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -19,11 +19,19 @@ sys.path.insert(0, os.path.abspath('../sphinxext')) -extensions = ['sphinx.ext.autodoc', 'numpydoc', - 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', - 'sphinx.ext.doctest', 'sphinx.ext.autosummary', - 'sphinx.ext.graphviz', 'sphinx.ext.ifconfig', - 'matplotlib.sphinxext.plot_directive'] +extensions = [ + 'sphinx.ext.autodoc', + 'numpydoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.coverage', + 'sphinx.ext.doctest', + 'sphinx.ext.autosummary', + 'sphinx.ext.graphviz', + 'sphinx.ext.ifconfig', + 'matplotlib.sphinxext.plot_directive', + 'IPython.sphinxext.ipython_console_highlighting', + 'IPython.sphinxext.ipython_directive', +] if sphinx.__version__ >= "1.4": extensions.append('sphinx.ext.imgmath') @@ -234,9 +242,7 @@ def setup(app): # ----------------------------------------------------------------------------- import glob -autosummary_generate = (glob.glob("reference/*.rst") + - glob.glob("reference/randomgen/*.rst") + - glob.glob("reference/randomgen/brng/*.rst")) +autosummary_generate = True # ----------------------------------------------------------------------------- # Coverage checker @@ -357,3 +363,8 @@ def linkcode_resolve(domain, info): else: return "https://github.com/numpy/numpy/blob/v%s/numpy/%s%s" % ( numpy.__version__, fn, linespec) + +doctest_global_setup = ''' +import numpy as np +from numpy.random import randomgen +''' diff --git a/doc/source/reference/randomgen/brng/dsfmt.rst b/doc/source/reference/randomgen/brng/dsfmt.rst index bd660c938d54..ffe3421eb48d 100644 --- a/doc/source/reference/randomgen/brng/dsfmt.rst +++ b/doc/source/reference/randomgen/brng/dsfmt.rst @@ -1,9 +1,9 @@ Double SIMD Mersenne Twister (dSFMT) ------------------------------------ -.. module:: randomgen.dsfmt +.. module:: numpy.random.randomgen.dsfmt -.. currentmodule:: randomgen.dsfmt +.. currentmodule:: numpy.random.randomgen.dsfmt .. autoclass:: DSFMT diff --git a/doc/source/reference/randomgen/brng/mt19937.rst b/doc/source/reference/randomgen/brng/mt19937.rst index 23f8e45940a0..0a9a52235223 100644 --- a/doc/source/reference/randomgen/brng/mt19937.rst +++ b/doc/source/reference/randomgen/brng/mt19937.rst @@ -1,9 +1,9 @@ Mersenne Twister (MT19937) -------------------------- -.. module:: randomgen.mt19937 +.. module:: numpy.random.randomgen.mt19937 -.. currentmodule:: randomgen.mt19937 +.. currentmodule:: numpy.random.randomgen.mt19937 .. autoclass:: MT19937 diff --git a/doc/source/reference/randomgen/brng/pcg32.rst b/doc/source/reference/randomgen/brng/pcg32.rst index 1854b4c68dd9..9b06a72d7a86 100644 --- a/doc/source/reference/randomgen/brng/pcg32.rst +++ b/doc/source/reference/randomgen/brng/pcg32.rst @@ -1,9 +1,9 @@ Parallel Congruent Generator (32-bit, PCG32) -------------------------------------------- -.. module:: randomgen.pcg32 +.. module:: numpy.random.randomgen.pcg32 -.. currentmodule:: randomgen.pcg32 +.. currentmodule:: numpy.random.randomgen.pcg32 .. autoclass:: PCG32 diff --git a/doc/source/reference/randomgen/brng/pcg64.rst b/doc/source/reference/randomgen/brng/pcg64.rst index 496825dc456a..92345dd57c53 100644 --- a/doc/source/reference/randomgen/brng/pcg64.rst +++ b/doc/source/reference/randomgen/brng/pcg64.rst @@ -1,9 +1,9 @@ Parallel Congruent Generator (64-bit, PCG64) -------------------------------------------- -.. module:: randomgen.pcg64 +.. module:: numpy.random.randomgen.pcg64 -.. currentmodule:: randomgen.pcg64 +.. currentmodule:: numpy.random.randomgen.pcg64 .. autoclass:: PCG64 diff --git a/doc/source/reference/randomgen/brng/philox.rst b/doc/source/reference/randomgen/brng/philox.rst index c2ffc44eb1fa..bc1e5618a1e0 100644 --- a/doc/source/reference/randomgen/brng/philox.rst +++ b/doc/source/reference/randomgen/brng/philox.rst @@ -1,9 +1,9 @@ Philox Counter-based RNG ------------------------ -.. module:: randomgen.philox +.. module:: numpy.random.randomgen.philox -.. currentmodule:: randomgen.philox +.. currentmodule:: numpy.random.randomgen.philox .. autoclass:: Philox diff --git a/doc/source/reference/randomgen/brng/threefry.rst b/doc/source/reference/randomgen/brng/threefry.rst index 98141d6486c5..4b013d63aa05 100644 --- a/doc/source/reference/randomgen/brng/threefry.rst +++ b/doc/source/reference/randomgen/brng/threefry.rst @@ -1,9 +1,9 @@ ThreeFry Counter-based RNG -------------------------- -.. module:: randomgen.threefry +.. module:: numpy.random.randomgen.threefry -.. currentmodule:: randomgen.threefry +.. currentmodule:: numpy.random.randomgen.threefry .. autoclass:: ThreeFry diff --git a/doc/source/reference/randomgen/brng/threefry32.rst b/doc/source/reference/randomgen/brng/threefry32.rst index 2869cbac887c..efaf5db8ded5 100644 --- a/doc/source/reference/randomgen/brng/threefry32.rst +++ b/doc/source/reference/randomgen/brng/threefry32.rst @@ -1,9 +1,9 @@ ThreeFry32 Counter-based RNG ---------------------------- -.. module:: randomgen.threefry32 +.. module:: numpy.random.randomgen.threefry32 -.. currentmodule:: randomgen.threefry32 +.. currentmodule:: numpy.random.randomgen.threefry32 .. autoclass:: ThreeFry32 diff --git a/doc/source/reference/randomgen/brng/xoroshiro128.rst b/doc/source/reference/randomgen/brng/xoroshiro128.rst index 3d6735c621d2..98c78725eb53 100644 --- a/doc/source/reference/randomgen/brng/xoroshiro128.rst +++ b/doc/source/reference/randomgen/brng/xoroshiro128.rst @@ -1,9 +1,9 @@ Xoroshiro128+ ------------- -.. module:: randomgen.xoroshiro128 +.. module:: numpy.random.randomgen.xoroshiro128 -.. currentmodule:: randomgen.xoroshiro128 +.. currentmodule:: numpy.random.randomgen.xoroshiro128 .. autoclass:: Xoroshiro128 diff --git a/doc/source/reference/randomgen/brng/xorshift1024.rst b/doc/source/reference/randomgen/brng/xorshift1024.rst index 38b293dcd6f8..47fb5adb5a4d 100644 --- a/doc/source/reference/randomgen/brng/xorshift1024.rst +++ b/doc/source/reference/randomgen/brng/xorshift1024.rst @@ -1,9 +1,9 @@ Xorshift1024*φ -------------- -.. module:: randomgen.xorshift1024 +.. module:: numpy.random.randomgen.xorshift1024 -.. currentmodule:: randomgen.xorshift1024 +.. currentmodule:: numpy.random.randomgen.xorshift1024 .. autoclass:: Xorshift1024 diff --git a/doc/source/reference/randomgen/brng/xoshiro256starstar.rst b/doc/source/reference/randomgen/brng/xoshiro256starstar.rst index 903e76bbbd20..3fe8799485c8 100644 --- a/doc/source/reference/randomgen/brng/xoshiro256starstar.rst +++ b/doc/source/reference/randomgen/brng/xoshiro256starstar.rst @@ -1,9 +1,9 @@ Xoshiro256** ------------ -.. module:: randomgen.xoshiro256starstar +.. module:: numpy.random.randomgen.xoshiro256starstar -.. currentmodule:: randomgen.xoshiro256starstar +.. currentmodule:: numpy.random.randomgen.xoshiro256starstar .. autoclass:: Xoshiro256StarStar diff --git a/doc/source/reference/randomgen/brng/xoshiro512starstar.rst b/doc/source/reference/randomgen/brng/xoshiro512starstar.rst index 3501b2c9c85e..945305fe4bbe 100644 --- a/doc/source/reference/randomgen/brng/xoshiro512starstar.rst +++ b/doc/source/reference/randomgen/brng/xoshiro512starstar.rst @@ -1,9 +1,9 @@ Xoshiro512** ------------ -.. module:: randomgen.xoshiro512starstar +.. module:: numpy.random.randomgen.xoshiro512starstar -.. currentmodule:: randomgen.xoshiro512starstar +.. currentmodule:: numpy.random.randomgen.xoshiro512starstar .. autoclass:: Xoshiro512StarStar diff --git a/doc/source/reference/randomgen/conf.py b/doc/source/reference/randomgen/conf.py deleted file mode 100644 index d4290d173d9c..000000000000 --- a/doc/source/reference/randomgen/conf.py +++ /dev/null @@ -1,221 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/stable/config - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) -import guzzle_sphinx_theme -import randomgen - -# -- Project information ----------------------------------------------------- - -project = 'RandomGen' -copyright = '2018, Kevin Sheppard' -author = 'Kevin Sheppard' - -# The short X.Y version. - -version = randomgen.__version__ -if '+' in version: - version = version.split('+') - version = ''.join((version[0], ' (+', version[1].split('.')[0], ')')) -# The full version, including alpha/beta/rc tags. -release = randomgen.__version__ - -# -- General configuration --------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.napoleon', - 'sphinx.ext.autodoc', - 'sphinx.ext.extlinks', - 'sphinx.ext.todo', - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.autosummary', - 'sphinx.ext.mathjax', - 'sphinx.ext.githubpages', - 'IPython.sphinxext.ipython_console_highlighting', - 'IPython.sphinxext.ipython_directive' -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path . -exclude_patterns = [] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -# html_theme = 'alabaster' -# html_theme = 'sphinx_rtd_theme' -# html_theme_path = ["_themes", ] -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -html_translator_class = 'guzzle_sphinx_theme.HTMLTranslator' -html_theme_path = guzzle_sphinx_theme.html_theme_path() -html_theme = 'guzzle_sphinx_theme' - -# Register the theme as an extension to generate a sitemap.xml -extensions.append("guzzle_sphinx_theme") - -# Guzzle theme options (see theme.conf for more information) -html_theme_options = { - # Set the name of the project to appear in the sidebar - "project_nav_name": project + u" " + version, -} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} -html_sidebars = { - '**': ['logo-text.html', 'globaltoc.html', 'searchbox.html'] -} - -# If false, no module index is generated. -html_domain_indices = True - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'RandomGendoc' - - -# -- Options for LaTeX output ------------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'RandomGen.tex', 'RandomGen Documentation', - 'Kevin Sheppard', 'manual'), -] - - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'RandomGen', 'RandomGen Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ---------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'RandomGen', 'RandomGen Documentation', - author, 'RandomGen', 'Alternative random number generators for Python.', - 'Miscellaneous'), -] - - -# -- Extension configuration ------------------------------------------------- - -# -- Options for intersphinx extension --------------------------------------- - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = { - 'statsmodels': ('http://www.statsmodels.org/dev/', None), - 'matplotlib': ('https://matplotlib.org', None), - 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None), - 'python': ('https://docs.python.org/3', None), - 'numpy': ('https://docs.scipy.org/doc/numpy', None), - 'np': ('https://docs.scipy.org/doc/numpy', None), - 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), - 'pd': ('https://pandas.pydata.org/pandas-docs/stable/', None), -} - -autosummary_generate = True - -doctest_global_setup = """ -import numpy as np - -import randomgen - -import matplotlib.pyplot - -def show(*args, **kwargs): - return - -matplotlib.pyplot.show = show -""" diff --git a/doc/source/reference/randomgen/entropy.rst b/doc/source/reference/randomgen/entropy.rst index 3e50c892fc1d..6814edfbe752 100644 --- a/doc/source/reference/randomgen/entropy.rst +++ b/doc/source/reference/randomgen/entropy.rst @@ -1,6 +1,6 @@ System Entropy ============== -.. module:: randomgen.entropy +.. module:: numpy.random.randomgen.entropy .. autofunction:: random_entropy diff --git a/doc/source/reference/randomgen/generator.rst b/doc/source/reference/randomgen/generator.rst index dba51eb6d00f..791766aa7b65 100644 --- a/doc/source/reference/randomgen/generator.rst +++ b/doc/source/reference/randomgen/generator.rst @@ -12,7 +12,7 @@ distributions. The default basic RNG used by changed by passing an instantized basic RNG to :class:`~randomgen.generator.RandomGenerator`. -.. currentmodule:: randomgen.generator +.. currentmodule:: numpy.random.randomgen.generator .. autoclass:: RandomGenerator @@ -37,8 +37,6 @@ Simple random data ~RandomGenerator.random_sample ~RandomGenerator.choice ~RandomGenerator.bytes - ~RandomGenerator.random_uintegers - ~RandomGenerator.random_raw Permutations ============ @@ -56,7 +54,6 @@ Distributions ~RandomGenerator.beta ~RandomGenerator.binomial ~RandomGenerator.chisquare - ~RandomGenerator.complex_normal ~RandomGenerator.dirichlet ~RandomGenerator.exponential ~RandomGenerator.f @@ -88,4 +85,4 @@ Distributions ~RandomGenerator.vonmises ~RandomGenerator.wald ~RandomGenerator.weibull - ~RandomGenerator.zipf \ No newline at end of file + ~RandomGenerator.zipf diff --git a/doc/source/reference/randomgen/index.rst b/doc/source/reference/randomgen/index.rst index eac8c1ef12e8..67d0441a2de4 100644 --- a/doc/source/reference/randomgen/index.rst +++ b/doc/source/reference/randomgen/index.rst @@ -1,9 +1,11 @@ -RandomGen -========= +Randomgen.RandomGen +=================== This package contains replacements for the NumPy :class:`~numpy.random.RandomState` object that allows the core random number generator be be changed. +.. current_module numpy.random.randomgen + Quick Start ----------- @@ -187,14 +189,14 @@ Random Generator .. toctree:: :maxdepth: 1 - Random Generation + generator legacy Basic Random Number Generators ------------------------------ .. toctree:: - :maxdepth: 3 + :maxdepth: 1 Basic Random Number Generators diff --git a/doc/source/reference/randomgen/legacy.rst b/doc/source/reference/randomgen/legacy.rst index a0ee90d4f2b5..ef71ec76d906 100644 --- a/doc/source/reference/randomgen/legacy.rst +++ b/doc/source/reference/randomgen/legacy.rst @@ -33,7 +33,7 @@ when accessing the state so that these extra values are saved. lg.standard_exponential() -.. currentmodule:: randomgen.legacy.legacy +.. currentmodule:: numpy.random.randomgen.legacy .. autoclass:: LegacyGenerator @@ -44,7 +44,8 @@ Seeding and State .. autosummary:: :toctree: generated/ - ~LegacyGenerator.state + ~LegacyGenerator.get_state + ~LegacyGenerator.set_state Simple random data ================== @@ -58,8 +59,6 @@ Simple random data ~LegacyGenerator.random_sample ~LegacyGenerator.choice ~LegacyGenerator.bytes - ~LegacyGenerator.random_uintegers - ~LegacyGenerator.random_raw Permutations ============ @@ -77,7 +76,6 @@ Distributions ~LegacyGenerator.beta ~LegacyGenerator.binomial ~LegacyGenerator.chisquare - ~LegacyGenerator.complex_normal ~LegacyGenerator.dirichlet ~LegacyGenerator.exponential ~LegacyGenerator.f @@ -109,4 +107,4 @@ Distributions ~LegacyGenerator.vonmises ~LegacyGenerator.wald ~LegacyGenerator.weibull - ~LegacyGenerator.zipf \ No newline at end of file + ~LegacyGenerator.zipf From ef2601a3ed38abb3b4a6d4cfef5dbb913b216b72 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 3 Apr 2019 21:37:26 +0300 Subject: [PATCH 247/279] BUILD: re-apply update of numpydoc to latest master --- doc/sphinxext | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinxext b/doc/sphinxext index de21addd6560..e47b9404963a 160000 --- a/doc/sphinxext +++ b/doc/sphinxext @@ -1 +1 @@ -Subproject commit de21addd6560576151938a4bc59543d55ce6f085 +Subproject commit e47b9404963ad2a75a11d167416038275c50d1c5 From f486ca24f20ca5d4de43191ef2d647c87c37ac1a Mon Sep 17 00:00:00 2001 From: kikocorreoso Date: Wed, 3 Apr 2019 21:40:30 +0200 Subject: [PATCH 248/279] fix (``code``s) sphinx parse warning --- doc/release/1.17.0-notes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/release/1.17.0-notes.rst b/doc/release/1.17.0-notes.rst index 4e366648a99a..1155449a7bf3 100644 --- a/doc/release/1.17.0-notes.rst +++ b/doc/release/1.17.0-notes.rst @@ -200,7 +200,7 @@ approach. New keywords added to ``np.nan_to_num`` --------------------------------------- ``np.nan_to_num`` now accepts keywords ``nan``, ``posinf`` and ``neginf`` allowing the -user to define the value to replace the ``nan``s, positive and negative ``np.inf``s +user to define the value to replace the ``nan``, positive and negative ``np.inf`` values respectively. From e6ab3267c9c6cd7e92634d12992d5cc8b826006a Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 4 Apr 2019 13:57:52 +0300 Subject: [PATCH 249/279] BUG: _mtrand => _rand --- numpy/random/randomgen/mtrand.pyx | 104 +++++++++++++++--------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/numpy/random/randomgen/mtrand.pyx b/numpy/random/randomgen/mtrand.pyx index 2f89f5eb0cd7..83801659a8ed 100644 --- a/numpy/random/randomgen/mtrand.pyx +++ b/numpy/random/randomgen/mtrand.pyx @@ -4117,55 +4117,55 @@ cdef class RandomState: self.shuffle(idx) return arr[idx] -_mtrand = RandomState() - -beta = _mtrand.beta -binomial = _mtrand.binomial -bytes = _mtrand.bytes -chisquare = _mtrand.chisquare -choice = _mtrand.choice -dirichlet = _mtrand.dirichlet -exponential = _mtrand.exponential -f = _mtrand.f -gamma = _mtrand.gamma -get_state = _mtrand.get_state -geometric = _mtrand.geometric -gumbel = _mtrand.gumbel -hypergeometric = _mtrand.hypergeometric -laplace = _mtrand.laplace -logistic = _mtrand.logistic -lognormal = _mtrand.lognormal -logseries = _mtrand.logseries -multinomial = _mtrand.multinomial -multivariate_normal = _mtrand.multivariate_normal -negative_binomial = _mtrand.negative_binomial -noncentral_chisquare = _mtrand.noncentral_chisquare -noncentral_f = _mtrand.noncentral_f -normal = _mtrand.normal -pareto = _mtrand.pareto -permutation = _mtrand.permutation -poisson = _mtrand.poisson -power = _mtrand.power -rand = _mtrand.rand -randint = _mtrand.randint -randn = _mtrand.randn -random = _mtrand.random_sample -random_integers = _mtrand.random_integers -random_sample = _mtrand.random_sample -ranf = _mtrand.random_sample -rayleigh = _mtrand.rayleigh -sample = _mtrand.random_sample -seed = _mtrand.seed -set_state = _mtrand.set_state -shuffle = _mtrand.shuffle -standard_cauchy = _mtrand.standard_cauchy -standard_exponential = _mtrand.standard_exponential -standard_gamma = _mtrand.standard_gamma -standard_normal = _mtrand.standard_normal -standard_t = _mtrand.standard_t -triangular = _mtrand.triangular -uniform = _mtrand.uniform -vonmises = _mtrand.vonmises -wald = _mtrand.wald -weibull = _mtrand.weibull -zipf = _mtrand.zipf +_rand = RandomState() + +beta = _rand.beta +binomial = _rand.binomial +bytes = _rand.bytes +chisquare = _rand.chisquare +choice = _rand.choice +dirichlet = _rand.dirichlet +exponential = _rand.exponential +f = _rand.f +gamma = _rand.gamma +get_state = _rand.get_state +geometric = _rand.geometric +gumbel = _rand.gumbel +hypergeometric = _rand.hypergeometric +laplace = _rand.laplace +logistic = _rand.logistic +lognormal = _rand.lognormal +logseries = _rand.logseries +multinomial = _rand.multinomial +multivariate_normal = _rand.multivariate_normal +negative_binomial = _rand.negative_binomial +noncentral_chisquare = _rand.noncentral_chisquare +noncentral_f = _rand.noncentral_f +normal = _rand.normal +pareto = _rand.pareto +permutation = _rand.permutation +poisson = _rand.poisson +power = _rand.power +rand = _rand.rand +randint = _rand.randint +randn = _rand.randn +random = _rand.random_sample +random_integers = _rand.random_integers +random_sample = _rand.random_sample +ranf = _rand.random_sample +rayleigh = _rand.rayleigh +sample = _rand.random_sample +seed = _rand.seed +set_state = _rand.set_state +shuffle = _rand.shuffle +standard_cauchy = _rand.standard_cauchy +standard_exponential = _rand.standard_exponential +standard_gamma = _rand.standard_gamma +standard_normal = _rand.standard_normal +standard_t = _rand.standard_t +triangular = _rand.triangular +uniform = _rand.uniform +vonmises = _rand.vonmises +wald = _rand.wald +weibull = _rand.weibull +zipf = _rand.zipf From c62ee1bbe70c113e2b019bb298ff8ec90d0d6cf6 Mon Sep 17 00:00:00 2001 From: spacescientist Date: Thu, 4 Apr 2019 13:25:03 +0200 Subject: [PATCH 250/279] DOC: Small readability improvement --- numpy/random/mtrand/mtrand.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx index 24826d52d14d..c97c166aaec7 100644 --- a/numpy/random/mtrand/mtrand.pyx +++ b/numpy/random/mtrand/mtrand.pyx @@ -3779,8 +3779,8 @@ cdef class RandomState: product p*n <=5, where p = population proportion estimate, and n = number of samples, in which case the binomial distribution is used instead. For example, a sample of 15 people shows 4 who are left - handed, and 11 who are right handed. Then p = 4/15 = 27%. 0.27*15 = 4, - so the binomial distribution should be used in this case. + handed, and 11 who are right handed. Then p = 4/15 = 27%. Since + 0.27*15 = 4, the binomial distribution should be used in this case. References ---------- From 77b2be2c5ae44b43607ed0db8f747e392b7221ac Mon Sep 17 00:00:00 2001 From: Tyler Reddy Date: Tue, 2 Apr 2019 12:17:14 -0700 Subject: [PATCH 251/279] TST: use POWER8 OpenBLAS for CI --- .travis.yml | 2 ++ tools/travis-before-install.sh | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/.travis.yml b/.travis.yml index 7498e1d66ca0..061d8de1a0b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,6 +69,8 @@ matrix: env: # for matrix annotation only - PPC64_LE=1 + # use POWER8 OpenBLAS build, not system ATLAS + - ATLAS=None before_install: - ./tools/travis-before-install.sh diff --git a/tools/travis-before-install.sh b/tools/travis-before-install.sh index c334e91ae782..db1f0bc5c0bb 100755 --- a/tools/travis-before-install.sh +++ b/tools/travis-before-install.sh @@ -25,6 +25,17 @@ if [ -n "$INSTALL_PICKLE5" ]; then pip install pickle5 fi +if [ -n "$PPC64_LE" ]; then + # build script for POWER8 OpenBLAS available here: + # https://github.com/tylerjereddy/openblas-static-gcc/blob/master/power8 + # built on GCC compile farm machine named gcc112 + # manually uploaded tarball to an unshared Dropbox location + wget -O openblas-power8.tar.gz https://www.dropbox.com/s/zcwhk7c2zptwy0s/openblas-v0.3.5-ppc64le-power8.tar.gz?dl=0 + tar zxvf openblas-power8.tar.gz + sudo cp -r ./64/lib/* /usr/lib + sudo cp ./64/include/* /usr/include +fi + pip install --upgrade pip setuptools pip install nose pytz cython pytest if [ -n "$USE_ASV" ]; then pip install asv; fi From 8fdacfc041bce4f63a4172d56da4520a3040b79d Mon Sep 17 00:00:00 2001 From: Warren Weckesser Date: Fri, 5 Apr 2019 14:59:32 -0400 Subject: [PATCH 252/279] MAINT: f2py: Add a cast to avoid a compiler warning. The warning [...]/fortranobject.c:138:18: warning: comparison of integers of different signs: 'Py_ssize_t' (aka 'long') and 'unsigned long' [-Wsign-compare] if (size < sizeof(notalloc)) { ~~~~ ^ ~~~~~~~~~~~~~~~~ occurs 17 times when scipy is built. The change in this pull request casts `size` to `size_t` before comparing it to `sizeof(...)`. A previous check has already eliminated the possibility that `size` is negative, so this cast is safe. --- numpy/f2py/src/fortranobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/f2py/src/fortranobject.c b/numpy/f2py/src/fortranobject.c index 78b06f0662e3..4a981bf558ab 100644 --- a/numpy/f2py/src/fortranobject.c +++ b/numpy/f2py/src/fortranobject.c @@ -135,7 +135,7 @@ format_def(char *buf, Py_ssize_t size, FortranDataDef def) if (def.data == NULL) { static const char notalloc[] = ", not allocated"; - if (size < sizeof(notalloc)) { + if ((size_t) size < sizeof(notalloc)) { return -1; } memcpy(p, notalloc, sizeof(notalloc)); From 97e3c508e05bd365e26fcc18930fc85881b37718 Mon Sep 17 00:00:00 2001 From: Tyler Reddy Date: Fri, 5 Apr 2019 14:11:34 -0700 Subject: [PATCH 253/279] TST: use OpenBLAS for ARMv8 CI --- shippable.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/shippable.yml b/shippable.yml index 82ee9461f1ff..75d2dcafe740 100644 --- a/shippable.yml +++ b/shippable.yml @@ -22,7 +22,15 @@ runtime: build: ci: # install dependencies - - sudo apt-get install gcc gfortran libblas-dev liblapack-dev + - sudo apt-get install gcc gfortran + # ARMv8 OpenBLAS built using script available here: + # https://github.com/tylerjereddy/openblas-static-gcc/tree/master/ARMv8 + # build done on GCC compile farm machine named gcc115 + # tarball uploaded manually to an unshared Dropbox location + - wget -O openblas-v0.3.5-armv8.tar.gz https://www.dropbox.com/s/pbqkxzlmih4cky1/openblas-v0.3.5-armv8.tar.gz?dl=0 + - tar zxvf openblas-v0.3.5-armv8.tar.gz + - sudo cp -r ./64/lib/* /usr/lib + - sudo cp ./64/include/* /usr/include # add pathlib for Python 2, otherwise many tests are skipped - pip install --upgrade pip # we will pay the ~13 minute cost of compiling Cython only when a new From 91ba86f691c2d062bd2e8c1eec0721b5a1d301e4 Mon Sep 17 00:00:00 2001 From: Christopher Whelan Date: Fri, 5 Apr 2019 17:06:21 -0700 Subject: [PATCH 254/279] ENH: vectorize np.abs for unsigned ints and half, improving performance up to 12x --- numpy/core/src/umath/loops.c.src | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index abfd883f7cf4..1017bb94a675 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -1027,13 +1027,10 @@ NPY_NO_EXPORT void * #c = u,u,u,ul,ull# */ -NPY_NO_EXPORT void +NPY_NO_EXPORT NPY_GCC_OPT_3 void @TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { - UNARY_LOOP { - const @type@ in1 = *(@type@ *)ip1; - *((@type@ *)op1) = in1; - } + UNARY_LOOP_FAST(@type@, @type@, *out = in); } NPY_NO_EXPORT NPY_GCC_OPT_3 void @@ -2231,13 +2228,10 @@ HALF_conjugate(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNU } } -NPY_NO_EXPORT void +NPY_NO_EXPORT NPY_GCC_OPT_3 void HALF_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { - UNARY_LOOP { - const npy_half in1 = *(npy_half *)ip1; - *((npy_half *)op1) = in1&0x7fffu; - } + UNARY_LOOP_FAST(npy_half, npy_half, *out = in&0x7fffu); } NPY_NO_EXPORT void From 0be3fe42539ab935339d0c2bb5c0205ce4b0a8fa Mon Sep 17 00:00:00 2001 From: vrindaaa <48102157+vrindaaa@users.noreply.github.com> Date: Sun, 7 Apr 2019 00:22:13 +0530 Subject: [PATCH 255/279] DOC : Correcting bug on Documentation Page (Byteswapping) (#13262) * Correcting bug on Documentation Page : Byteswapping * Changing name of variable --- numpy/doc/byteswapping.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/numpy/doc/byteswapping.py b/numpy/doc/byteswapping.py index f9491ed432bc..7a749c8d5513 100644 --- a/numpy/doc/byteswapping.py +++ b/numpy/doc/byteswapping.py @@ -31,16 +31,16 @@ 3 + 2, the 4 bytes in memory would contain respectively: 0, 1, 3, 2. The bytes I have loaded from the file would have these contents: ->>> big_end_str = chr(0) + chr(1) + chr(3) + chr(2) ->>> big_end_str -'\\x00\\x01\\x03\\x02' +>>> big_end_buffer = bytearray([0,1,3,2]) +>>> big_end_buffer +bytearray(b'\\x00\\x01\\x03\\x02') We might want to use an ``ndarray`` to access these integers. In that case, we can create an array around this memory, and tell numpy that there are two integers, and that they are 16 bit and big-endian: >>> import numpy as np ->>> big_end_arr = np.ndarray(shape=(2,),dtype='>i2', buffer=big_end_str) +>>> big_end_arr = np.ndarray(shape=(2,),dtype='>i2', buffer=big_end_buffer) >>> big_end_arr[0] 1 >>> big_end_arr[1] @@ -53,7 +53,7 @@ In fact, why don't we try that? ->>> little_end_u4 = np.ndarray(shape=(1,),dtype='>> little_end_u4 = np.ndarray(shape=(1,),dtype='>> little_end_u4[0] == 1 * 256**1 + 3 * 256**2 + 2 * 256**3 True @@ -97,7 +97,7 @@ We make something where they don't match: ->>> wrong_end_dtype_arr = np.ndarray(shape=(2,),dtype='>> wrong_end_dtype_arr = np.ndarray(shape=(2,),dtype='>> wrong_end_dtype_arr[0] 256 @@ -110,7 +110,7 @@ Note the array has not changed in memory: ->>> fixed_end_dtype_arr.tobytes() == big_end_str +>>> fixed_end_dtype_arr.tobytes() == big_end_buffer True Data and type endianness don't match, change data to match dtype @@ -126,7 +126,7 @@ Now the array *has* changed in memory: ->>> fixed_end_mem_arr.tobytes() == big_end_str +>>> fixed_end_mem_arr.tobytes() == big_end_buffer False Data and dtype endianness match, swap data and dtype @@ -140,7 +140,7 @@ >>> swapped_end_arr = big_end_arr.byteswap().newbyteorder() >>> swapped_end_arr[0] 1 ->>> swapped_end_arr.tobytes() == big_end_str +>>> swapped_end_arr.tobytes() == big_end_buffer False An easier way of casting the data to a specific dtype and byte ordering @@ -149,7 +149,7 @@ >>> swapped_end_arr = big_end_arr.astype('>> swapped_end_arr[0] 1 ->>> swapped_end_arr.tobytes() == big_end_str +>>> swapped_end_arr.tobytes() == big_end_buffer False """ From 306bc58e9b5784e3c94f0f82157308fc74318079 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Sat, 6 Apr 2019 21:06:07 +0200 Subject: [PATCH 256/279] BUG: Fix null pointer dereference in PyArray_DTypeFromObjectHelper --- numpy/core/src/multiarray/common.c | 2 +- numpy/core/tests/test_regression.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c index addb67732f31..52694d49122a 100644 --- a/numpy/core/src/multiarray/common.c +++ b/numpy/core/src/multiarray/common.c @@ -343,7 +343,7 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, typestr = PyDict_GetItemString(ip, "typestr"); #if defined(NPY_PY3K) /* Allow unicode type strings */ - if (PyUnicode_Check(typestr)) { + if (typestr && PyUnicode_Check(typestr)) { tmp = PyUnicode_AsASCIIString(typestr); typestr = tmp; } diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 1ba0cda2134c..4b551d8aaaf2 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -2448,3 +2448,9 @@ def test_pickle_datetime64_array(self): for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): dumped = pickle.dumps(arr, protocol=proto) assert_equal(pickle.loads(dumped), arr) + + def test_bad_array_interface(self): + class T(object): + __array_interface__ = {} + + np.array([T()]) From 31f942d773e74a94c829b70064c6b2b9e78c86a0 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 8 Apr 2019 10:11:07 +0100 Subject: [PATCH 257/279] BUG: Correct handling of nans Improve consistency of nan handling Prevent nans prducing values from int functions --- numpy/random/randomgen/common.pxd | 1 + numpy/random/randomgen/common.pyx | 39 +++++++++++-------- numpy/random/randomgen/generator.pyx | 38 +++++++++--------- numpy/random/randomgen/mtrand.pyx | 38 +++++++++--------- .../src/distributions/distributions.c | 7 +++- .../src/distributions/distributions.h | 2 +- .../src/legacy/distributions-boxmuller.c | 10 ++++- .../randomgen/tests/test_against_numpy.py | 8 ++-- 8 files changed, 80 insertions(+), 63 deletions(-) diff --git a/numpy/random/randomgen/common.pxd b/numpy/random/randomgen/common.pxd index 37182a29d6bf..f6748e5aa27d 100644 --- a/numpy/random/randomgen/common.pxd +++ b/numpy/random/randomgen/common.pxd @@ -16,6 +16,7 @@ cdef enum ConstraintType: CONS_NONE CONS_NON_NEGATIVE CONS_POSITIVE + CONS_POSITIVE_NOT_NAN CONS_BOUNDED_0_1 CONS_BOUNDED_0_1_NOTNAN CONS_BOUNDED_GT_0_1 diff --git a/numpy/random/randomgen/common.pyx b/numpy/random/randomgen/common.pyx index 2ade3e821cc4..1f7cd40cac76 100644 --- a/numpy/random/randomgen/common.pyx +++ b/numpy/random/randomgen/common.pyx @@ -295,52 +295,57 @@ cdef uint64_t MAXSIZE = sys.maxsize cdef int check_array_constraint(np.ndarray val, object name, constraint_type cons) except -1: if cons == CONS_NON_NEGATIVE: - if np.any(np.signbit(val)) or np.any(np.isnan(val)): + if np.any(np.logical_and(np.logical_not(np.isnan(val)), np.signbit(val))): raise ValueError(name + " < 0") - elif cons == CONS_POSITIVE: - if not np.all(np.greater(val, 0)): + elif cons == CONS_POSITIVE or cons == CONS_POSITIVE_NOT_NAN: + if cons == CONS_POSITIVE_NOT_NAN and np.any(np.isnan(val)): + raise ValueError(name + " must not be NaN") + elif np.any(np.less_equal(val, 0)): raise ValueError(name + " <= 0") elif cons == CONS_BOUNDED_0_1: if not np.all(np.greater_equal(val, 0)) or \ not np.all(np.less_equal(val, 1)): - raise ValueError(name + " < 0 or " + name + " > 1") + raise ValueError("{0} < 0 , {0} > 1 or {0} contains NaNs".format(name)) elif cons == CONS_BOUNDED_GT_0_1: if not np.all(np.greater(val, 0)) or not np.all(np.less_equal(val, 1)): - raise ValueError(name + " <= 0 or " + name + " > 1") + raise ValueError("{0} <= 0 , {0} > 1 or {0} contains NaNs".format(name)) elif cons == CONS_GT_1: if not np.all(np.greater(val, 1)): - raise ValueError(name + " <= 1") + raise ValueError("{0} <= 1 or {0} contains NaNs".format(name)) elif cons == CONS_GTE_1: if not np.all(np.greater_equal(val, 1)): - raise ValueError(name + " < 1") + raise ValueError("{0} < 1 or {0} contains NaNs".format(name)) elif cons == CONS_POISSON: if not np.all(np.less_equal(val, POISSON_LAM_MAX)): - raise ValueError(name + " value too large") - if not np.all(np.greater_equal(val, 0.0)): - raise ValueError(name + " < 0") + raise ValueError("{0} value too large".format(name)) + elif not np.all(np.greater_equal(val, 0.0)): + raise ValueError("{0} < 0 or {0} contains NaNs".format(name)) return 0 cdef int check_constraint(double val, object name, constraint_type cons) except -1: + cdef bint is_nan if cons == CONS_NON_NEGATIVE: - if np.signbit(val) or np.isnan(val): + if not np.isnan(val) and np.signbit(val): raise ValueError(name + " < 0") - elif cons == CONS_POSITIVE: - if not (val > 0): + elif cons == CONS_POSITIVE or cons == CONS_POSITIVE_NOT_NAN: + if cons == CONS_POSITIVE_NOT_NAN and np.isnan(val): + raise ValueError(name + " must not be NaN") + elif val <= 0: raise ValueError(name + " <= 0") elif cons == CONS_BOUNDED_0_1: if not (val >= 0) or not (val <= 1): - raise ValueError(name + " < 0 or " + name + " > 1") + raise ValueError("{0} < 0 , {0} > 1 or {0} is NaN".format(name)) elif cons == CONS_GT_1: if not (val > 1): - raise ValueError(name + " <= 1") + raise ValueError("{0} <= 1 or {0} is NaN".format(name)) elif cons == CONS_GTE_1: if not (val >= 1): - raise ValueError(name + " < 1") + raise ValueError("{0} < 1 or {0} is NaN".format(name)) elif cons == CONS_POISSON: if not (val >= 0): - raise ValueError(name + " < 0") + raise ValueError("{0} < 0 or {0} is NaN".format(name)) elif not (val <= POISSON_LAM_MAX): raise ValueError(name + " value too large") diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index b05f490334fe..a244bca578d3 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -903,7 +903,7 @@ cdef class RandomGenerator: Parameters ---------- d0, d1, ..., dn : int, optional - The dimensions of the returned array, should all be positive. + The dimensions of the returned array, must be non-negative. If no argument is given a single Python float is returned. dtype : {str, dtype}, optional Desired dtype of the result, either 'd' (or 'float64') or 'f' @@ -953,7 +953,7 @@ cdef class RandomGenerator: Parameters ---------- d0, d1, ..., dn : int, optional - The dimensions of the returned array, should be all positive. + The dimensions of the returned array, must be non-negative. If no argument is given a single Python float is returned. dtype : {str, dtype}, optional Desired dtype of the result, either 'd' (or 'float64') or 'f' @@ -1442,7 +1442,7 @@ cdef class RandomGenerator: Samples are drawn from an F distribution with specified parameters, `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of - freedom in denominator), where both parameters should be greater than + freedom in denominator), where both parameters must be greater than zero. The random variate of the F distribution (also known as the @@ -1453,9 +1453,9 @@ cdef class RandomGenerator: Parameters ---------- dfnum : float or array_like of floats - Degrees of freedom in numerator, should be > 0. + Degrees of freedom in numerator, must be > 0. dfden : float or array_like of float - Degrees of freedom in denominator, should be > 0. + Degrees of freedom in denominator, must be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1536,15 +1536,15 @@ cdef class RandomGenerator: Parameters ---------- dfnum : float or array_like of floats - Numerator degrees of freedom, should be > 0. + Numerator degrees of freedom, must be > 0. .. versionchanged:: 1.14.0 Earlier NumPy versions required dfnum > 1. dfden : float or array_like of floats - Denominator degrees of freedom, should be > 0. + Denominator degrees of freedom, must be > 0. nonc : float or array_like of floats Non-centrality parameter, the sum of the squares of the numerator - means, should be >= 0. + means, must be >= 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1613,7 +1613,7 @@ cdef class RandomGenerator: Parameters ---------- df : float or array_like of floats - Number of degrees of freedom, should be > 0. + Number of degrees of freedom, must be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1679,12 +1679,12 @@ cdef class RandomGenerator: Parameters ---------- df : float or array_like of floats - Degrees of freedom, should be > 0. + Degrees of freedom, must be > 0. .. versionchanged:: 1.10.0 Earlier NumPy versions required dfnum > 1. nonc : float or array_like of floats - Non-centrality, should be non-negative. + Non-centrality, must be non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1825,7 +1825,7 @@ cdef class RandomGenerator: Parameters ---------- df : float or array_like of floats - Degrees of freedom, should be > 0. + Degrees of freedom, must be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2015,7 +2015,7 @@ cdef class RandomGenerator: Parameters ---------- a : float or array_like of floats - Shape of the distribution. Must all be positive. + Shape of the distribution. Must be positive. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2831,9 +2831,9 @@ cdef class RandomGenerator: Lower limit. mode : float or array_like of floats The value where the peak of the distribution occurs. - The value should fulfill the condition ``left <= mode <= right``. + The value must fulfill the condition ``left <= mode <= right``. right : float or array_like of floats - Upper limit, should be larger than `left`. + Upper limit, must be larger than `left`. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -3128,7 +3128,7 @@ cdef class RandomGenerator: """ return disc(&random_negative_binomial, self._brng, size, self.lock, 2, 0, - n, 'n', CONS_POSITIVE, + n, 'n', CONS_POSITIVE_NOT_NAN, p, 'p', CONS_BOUNDED_0_1, 0.0, '', CONS_NONE) @@ -3144,7 +3144,7 @@ cdef class RandomGenerator: Parameters ---------- lam : float or array_like of floats - Expectation of interval, should be >= 0. A sequence of expectation + Expectation of interval, must be >= 0. A sequence of expectation intervals must be broadcastable over the requested size. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then @@ -3483,7 +3483,7 @@ cdef class RandomGenerator: Notes ----- - The probability density for the Log Series distribution is + The probability mass function for the Log Series distribution is .. math:: P(k) = \\frac{-p^k}{k \\ln(1-p)}, @@ -3717,7 +3717,7 @@ cdef class RandomGenerator: Number of experiments. pvals : sequence of floats, length p Probabilities of each of the ``p`` different outcomes. These - should sum to 1 (however, the last element is always assumed to + must sum to 1 (however, the last element is always assumed to account for the remaining probability, as long as ``sum(pvals[:-1]) <= 1)``. size : int or tuple of ints, optional diff --git a/numpy/random/randomgen/mtrand.pyx b/numpy/random/randomgen/mtrand.pyx index 2f89f5eb0cd7..875ba491d3a7 100644 --- a/numpy/random/randomgen/mtrand.pyx +++ b/numpy/random/randomgen/mtrand.pyx @@ -2,7 +2,7 @@ #cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3 import operator import warnings -from collections.abc import Mapping + from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from cpython cimport (Py_INCREF, PyFloat_AsDouble) from libc cimport string @@ -250,7 +250,7 @@ cdef class RandomState: Vol. 8, No. 1, pp. 3-30, Jan. 1998. """ - if isinstance(state, Mapping): + if isinstance(state, dict): if 'brng' not in state or 'state' not in state: raise ValueError('state dictionary is not valid.') st = state @@ -955,7 +955,7 @@ cdef class RandomState: Parameters ---------- d0, d1, ..., dn : int, optional - The dimensions of the returned array, should all be positive. + The dimensions of the returned array, must be non-negative. If no argument is given a single Python float is returned. Returns @@ -1001,7 +1001,7 @@ cdef class RandomState: Parameters ---------- d0, d1, ..., dn : int, optional - The dimensions of the returned array, should be all positive. + The dimensions of the returned array, must be non-negative. If no argument is given a single Python float is returned. Returns @@ -1458,7 +1458,7 @@ cdef class RandomState: Samples are drawn from an F distribution with specified parameters, `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of - freedom in denominator), where both parameters should be greater than + freedom in denominator), where both parameters must be greater than zero. The random variate of the F distribution (also known as the @@ -1469,9 +1469,9 @@ cdef class RandomState: Parameters ---------- dfnum : float or array_like of floats - Degrees of freedom in numerator, should be > 0. + Degrees of freedom in numerator, must be > 0. dfden : float or array_like of float - Degrees of freedom in denominator, should be > 0. + Degrees of freedom in denominator, must be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1552,15 +1552,15 @@ cdef class RandomState: Parameters ---------- dfnum : float or array_like of floats - Numerator degrees of freedom, should be > 0. + Numerator degrees of freedom, must be > 0. .. versionchanged:: 1.14.0 Earlier NumPy versions required dfnum > 1. dfden : float or array_like of floats - Denominator degrees of freedom, should be > 0. + Denominator degrees of freedom, must be > 0. nonc : float or array_like of floats Non-centrality parameter, the sum of the squares of the numerator - means, should be >= 0. + means, must be >= 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1629,7 +1629,7 @@ cdef class RandomState: Parameters ---------- df : float or array_like of floats - Number of degrees of freedom, should be > 0. + Number of degrees of freedom, must be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1695,12 +1695,12 @@ cdef class RandomState: Parameters ---------- df : float or array_like of floats - Degrees of freedom, should be > 0. + Degrees of freedom, must be > 0. .. versionchanged:: 1.10.0 Earlier NumPy versions required dfnum > 1. nonc : float or array_like of floats - Non-centrality, should be non-negative. + Non-centrality, must be non-negative. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -1841,7 +1841,7 @@ cdef class RandomState: Parameters ---------- df : float or array_like of floats - Degrees of freedom, should be > 0. + Degrees of freedom, must be > 0. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2031,7 +2031,7 @@ cdef class RandomState: Parameters ---------- a : float or array_like of floats - Shape of the distribution. Must all be positive. + Shape of the distribution. Must be positive. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -2847,9 +2847,9 @@ cdef class RandomState: Lower limit. mode : float or array_like of floats The value where the peak of the distribution occurs. - The value should fulfill the condition ``left <= mode <= right``. + The value must fulfill the condition ``left <= mode <= right``. right : float or array_like of floats - Upper limit, should be larger than `left`. + Upper limit, must be larger than `left`. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), @@ -3160,7 +3160,7 @@ cdef class RandomState: Parameters ---------- lam : float or array_like of floats - Expectation of interval, should be >= 0. A sequence of expectation + Expectation of interval, must be >= 0. A sequence of expectation intervals must be broadcastable over the requested size. size : int or tuple of ints, optional Output shape. If the given shape is, e.g., ``(m, n, k)``, then @@ -3735,7 +3735,7 @@ cdef class RandomState: Number of experiments. pvals : sequence of floats, length p Probabilities of each of the ``p`` different outcomes. These - should sum to 1 (however, the last element is always assumed to + must sum to 1 (however, the last element is always assumed to account for the remaining probability, as long as ``sum(pvals[:-1]) <= 1)``. size : int or tuple of ints, optional diff --git a/numpy/random/randomgen/src/distributions/distributions.c b/numpy/random/randomgen/src/distributions/distributions.c index 20cdbe8632bf..83806de38997 100644 --- a/numpy/random/randomgen/src/distributions/distributions.c +++ b/numpy/random/randomgen/src/distributions/distributions.c @@ -899,6 +899,9 @@ int64_t random_binomial(brng_t *brng_state, double p, int64_t n, } double random_noncentral_chisquare(brng_t *brng_state, double df, double nonc) { + if (npy_isnan(nonc)){ + return NPY_NAN; + } if (nonc == 0) { return random_chisquare(brng_state, df); } @@ -939,7 +942,9 @@ double random_vonmises(brng_t *brng_state, double mu, double kappa) { double U, V, W, Y, Z; double result, mod; int neg; - + if (npy_isnan(kappa)){ + return NPY_NAN; + } if (kappa < 1e-8) { return M_PI * (2 * next_double(brng_state) - 1); } else { diff --git a/numpy/random/randomgen/src/distributions/distributions.h b/numpy/random/randomgen/src/distributions/distributions.h index 5cf9c72b25bc..7ca31a16cba6 100644 --- a/numpy/random/randomgen/src/distributions/distributions.h +++ b/numpy/random/randomgen/src/distributions/distributions.h @@ -20,7 +20,7 @@ typedef int bool; #include "Python.h" #include "numpy/npy_common.h" -#include +#include "numpy/npy_math.h" #ifdef _WIN32 #if _MSC_VER == 1500 diff --git a/numpy/random/randomgen/src/legacy/distributions-boxmuller.c b/numpy/random/randomgen/src/legacy/distributions-boxmuller.c index 768de066ced2..e96d3f19a0cb 100644 --- a/numpy/random/randomgen/src/legacy/distributions-boxmuller.c +++ b/numpy/random/randomgen/src/legacy/distributions-boxmuller.c @@ -12,6 +12,7 @@ double legacy_gauss(aug_brng_t *aug_state) { return temp; } else { double f, x1, x2, r2; + double f, x1, x2, r2; do { x1 = 2.0 * legacy_double(aug_state) - 1.0; @@ -103,6 +104,7 @@ double legacy_chisquare(aug_brng_t *aug_state, double df) { double legacy_noncentral_chisquare(aug_brng_t *aug_state, double df, double nonc) { + double out; if (nonc == 0) { return legacy_chisquare(aug_state, df); } @@ -112,7 +114,13 @@ double legacy_noncentral_chisquare(aug_brng_t *aug_state, double df, return Chi2 + n * n; } else { const long i = random_poisson(aug_state->basicrng, nonc / 2.0); - return legacy_chisquare(aug_state, df + 2 * i); + out = legacy_chisquare(aug_state, df + 2 * i); + /* Insert nan guard here to avoid changing the stream */ + if (npy_isnan(nonc)){ + return NPY_NAN; + } else { + return out; + } } } diff --git a/numpy/random/randomgen/tests/test_against_numpy.py b/numpy/random/randomgen/tests/test_against_numpy.py index 8a9ef2962750..b0fcdfb710f1 100644 --- a/numpy/random/randomgen/tests/test_against_numpy.py +++ b/numpy/random/randomgen/tests/test_against_numpy.py @@ -570,11 +570,9 @@ def test_multivariate_normal(self): self._is_state_common_legacy() -funcs = [generator.exponential, - generator.zipf, - generator.chisquare, - generator.logseries, - generator.poisson] +funcs = [randomgen.generator.zipf, + randomgen.generator.logseries, + randomgen.generator.poisson] ids = [f.__name__ for f in funcs] From 80a1873ac72f58d33088b90da474c2410131c948 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 8 Apr 2019 13:28:47 +0300 Subject: [PATCH 258/279] BUG: rework imports for random.mtrand._rand --- numpy/random/__init__.py | 11 ++----- numpy/random/randomgen/mtrand.pyx | 52 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/numpy/random/__init__.py b/numpy/random/__init__.py index b5ff1cfcab4b..53e9477975c0 100644 --- a/numpy/random/__init__.py +++ b/numpy/random/__init__.py @@ -136,16 +136,11 @@ 'zipf' ] -# from .mtrand import * -from .randomgen.mtrand import RandomState -mtrand = RandomState() -for _x in dir(mtrand): - if _x[0] != '_' and _x not in ('poisson_lam_max', 'state'): - locals()[_x] = getattr(mtrand, _x) -del _x +from .randomgen import mtrand +from .randomgen.mtrand import * # Some aliases: -ranf = random = sample = mtrand.random_sample +ranf = random = sample = random_sample __all__.extend(['ranf', 'random', 'sample']) def __RandomState_ctor(): diff --git a/numpy/random/randomgen/mtrand.pyx b/numpy/random/randomgen/mtrand.pyx index db63e6714e95..b5d6ff9bc9b9 100644 --- a/numpy/random/randomgen/mtrand.pyx +++ b/numpy/random/randomgen/mtrand.pyx @@ -4169,3 +4169,55 @@ vonmises = _rand.vonmises wald = _rand.wald weibull = _rand.weibull zipf = _rand.zipf + +__all__ = [ + 'beta', + 'binomial', + 'bytes', + 'chisquare', + 'choice', + 'dirichlet', + 'exponential', + 'f', + 'gamma', + 'geometric', + 'get_state', + 'gumbel', + 'hypergeometric', + 'laplace', + 'logistic', + 'lognormal', + 'logseries', + 'multinomial', + 'multivariate_normal', + 'negative_binomial', + 'noncentral_chisquare', + 'noncentral_f', + 'normal', + 'pareto', + 'permutation', + 'poisson', + 'power', + 'rand', + 'randint', + 'randn', + 'random_integers', + 'random_sample', + 'rayleigh', + 'seed', + 'set_state', + 'shuffle', + 'standard_cauchy', + 'standard_exponential', + 'standard_gamma', + 'standard_normal', + 'standard_t', + 'triangular', + 'uniform', + 'vonmises', + 'wald', + 'weibull', + 'zipf', + 'RandomState', +] + From d77d18df6e4124845cacb7ccb109758c75160742 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 8 Apr 2019 13:30:00 +0300 Subject: [PATCH 259/279] DOC: add exclude-members for numpydoc method-as-link handling --- doc/source/reference/randomgen/brng/dsfmt.rst | 1 + doc/source/reference/randomgen/brng/mt19937.rst | 1 + doc/source/reference/randomgen/brng/pcg32.rst | 1 + doc/source/reference/randomgen/brng/pcg64.rst | 1 + doc/source/reference/randomgen/brng/philox.rst | 1 + doc/source/reference/randomgen/brng/threefry.rst | 1 + doc/source/reference/randomgen/brng/threefry32.rst | 1 + doc/source/reference/randomgen/brng/xoroshiro128.rst | 1 + doc/source/reference/randomgen/brng/xorshift1024.rst | 1 + doc/source/reference/randomgen/brng/xoshiro256starstar.rst | 1 + doc/source/reference/randomgen/brng/xoshiro512starstar.rst | 1 + doc/source/reference/randomgen/generator.rst | 4 ++-- doc/source/reference/randomgen/legacy.rst | 4 ++-- 13 files changed, 15 insertions(+), 4 deletions(-) diff --git a/doc/source/reference/randomgen/brng/dsfmt.rst b/doc/source/reference/randomgen/brng/dsfmt.rst index ffe3421eb48d..f9de48d61dcf 100644 --- a/doc/source/reference/randomgen/brng/dsfmt.rst +++ b/doc/source/reference/randomgen/brng/dsfmt.rst @@ -7,6 +7,7 @@ Double SIMD Mersenne Twister (dSFMT) .. autoclass:: DSFMT + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/brng/mt19937.rst b/doc/source/reference/randomgen/brng/mt19937.rst index 0a9a52235223..7739e16ce1b5 100644 --- a/doc/source/reference/randomgen/brng/mt19937.rst +++ b/doc/source/reference/randomgen/brng/mt19937.rst @@ -6,6 +6,7 @@ Mersenne Twister (MT19937) .. currentmodule:: numpy.random.randomgen.mt19937 .. autoclass:: MT19937 + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/brng/pcg32.rst b/doc/source/reference/randomgen/brng/pcg32.rst index 9b06a72d7a86..aaf3929e87b3 100644 --- a/doc/source/reference/randomgen/brng/pcg32.rst +++ b/doc/source/reference/randomgen/brng/pcg32.rst @@ -6,6 +6,7 @@ Parallel Congruent Generator (32-bit, PCG32) .. currentmodule:: numpy.random.randomgen.pcg32 .. autoclass:: PCG32 + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/brng/pcg64.rst b/doc/source/reference/randomgen/brng/pcg64.rst index 92345dd57c53..94e73e491910 100644 --- a/doc/source/reference/randomgen/brng/pcg64.rst +++ b/doc/source/reference/randomgen/brng/pcg64.rst @@ -6,6 +6,7 @@ Parallel Congruent Generator (64-bit, PCG64) .. currentmodule:: numpy.random.randomgen.pcg64 .. autoclass:: PCG64 + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/brng/philox.rst b/doc/source/reference/randomgen/brng/philox.rst index bc1e5618a1e0..091c4d3e0e8e 100644 --- a/doc/source/reference/randomgen/brng/philox.rst +++ b/doc/source/reference/randomgen/brng/philox.rst @@ -6,6 +6,7 @@ Philox Counter-based RNG .. currentmodule:: numpy.random.randomgen.philox .. autoclass:: Philox + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/brng/threefry.rst b/doc/source/reference/randomgen/brng/threefry.rst index 4b013d63aa05..4f5c56bae866 100644 --- a/doc/source/reference/randomgen/brng/threefry.rst +++ b/doc/source/reference/randomgen/brng/threefry.rst @@ -6,6 +6,7 @@ ThreeFry Counter-based RNG .. currentmodule:: numpy.random.randomgen.threefry .. autoclass:: ThreeFry + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/brng/threefry32.rst b/doc/source/reference/randomgen/brng/threefry32.rst index efaf5db8ded5..bd85db4a7141 100644 --- a/doc/source/reference/randomgen/brng/threefry32.rst +++ b/doc/source/reference/randomgen/brng/threefry32.rst @@ -6,6 +6,7 @@ ThreeFry32 Counter-based RNG .. currentmodule:: numpy.random.randomgen.threefry32 .. autoclass:: ThreeFry32 + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/brng/xoroshiro128.rst b/doc/source/reference/randomgen/brng/xoroshiro128.rst index 98c78725eb53..6796c44577c0 100644 --- a/doc/source/reference/randomgen/brng/xoroshiro128.rst +++ b/doc/source/reference/randomgen/brng/xoroshiro128.rst @@ -6,6 +6,7 @@ Xoroshiro128+ .. currentmodule:: numpy.random.randomgen.xoroshiro128 .. autoclass:: Xoroshiro128 + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/brng/xorshift1024.rst b/doc/source/reference/randomgen/brng/xorshift1024.rst index 47fb5adb5a4d..64df7e050d01 100644 --- a/doc/source/reference/randomgen/brng/xorshift1024.rst +++ b/doc/source/reference/randomgen/brng/xorshift1024.rst @@ -6,6 +6,7 @@ Xorshift1024*φ .. currentmodule:: numpy.random.randomgen.xorshift1024 .. autoclass:: Xorshift1024 + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/brng/xoshiro256starstar.rst b/doc/source/reference/randomgen/brng/xoshiro256starstar.rst index 3fe8799485c8..7603e6f1beba 100644 --- a/doc/source/reference/randomgen/brng/xoshiro256starstar.rst +++ b/doc/source/reference/randomgen/brng/xoshiro256starstar.rst @@ -6,6 +6,7 @@ Xoshiro256** .. currentmodule:: numpy.random.randomgen.xoshiro256starstar .. autoclass:: Xoshiro256StarStar + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/brng/xoshiro512starstar.rst b/doc/source/reference/randomgen/brng/xoshiro512starstar.rst index 945305fe4bbe..64f95f7509c2 100644 --- a/doc/source/reference/randomgen/brng/xoshiro512starstar.rst +++ b/doc/source/reference/randomgen/brng/xoshiro512starstar.rst @@ -6,6 +6,7 @@ Xoshiro512** .. currentmodule:: numpy.random.randomgen.xoshiro512starstar .. autoclass:: Xoshiro512StarStar + :exclude-members: Seeding and State ================= diff --git a/doc/source/reference/randomgen/generator.rst b/doc/source/reference/randomgen/generator.rst index 791766aa7b65..d59efd68c802 100644 --- a/doc/source/reference/randomgen/generator.rst +++ b/doc/source/reference/randomgen/generator.rst @@ -14,8 +14,8 @@ changed by passing an instantized basic RNG to .. currentmodule:: numpy.random.randomgen.generator -.. autoclass:: - RandomGenerator +.. autoclass:: RandomGenerator + :exclude-members: Seed and State Manipulation =========================== diff --git a/doc/source/reference/randomgen/legacy.rst b/doc/source/reference/randomgen/legacy.rst index ef71ec76d906..c0e72517bb3b 100644 --- a/doc/source/reference/randomgen/legacy.rst +++ b/doc/source/reference/randomgen/legacy.rst @@ -35,8 +35,8 @@ when accessing the state so that these extra values are saved. .. currentmodule:: numpy.random.randomgen.legacy -.. autoclass:: - LegacyGenerator +.. autoclass:: LegacyGenerator + :exclude-members: Seeding and State ================= From b1c743a74ffbc9d2ca3b8dae289a105a877aa020 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 8 Apr 2019 15:14:56 +0300 Subject: [PATCH 260/279] add randomgen documentation to the tree --- doc/source/reference/routines.rst | 1 + doc/sphinxext | 2 +- numpy/random/randomgen/src/legacy/distributions-boxmuller.c | 1 - numpy/random/randomgen/tests/test_against_numpy.py | 6 +++--- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/source/reference/routines.rst b/doc/source/reference/routines.rst index a9e80480b870..0ed99cbdac36 100644 --- a/doc/source/reference/routines.rst +++ b/doc/source/reference/routines.rst @@ -42,6 +42,7 @@ indentation. routines.padding routines.polynomials routines.random + randomgen/index routines.set routines.sort routines.statistics diff --git a/doc/sphinxext b/doc/sphinxext index e47b9404963a..40b3733b4bf4 160000 --- a/doc/sphinxext +++ b/doc/sphinxext @@ -1 +1 @@ -Subproject commit e47b9404963ad2a75a11d167416038275c50d1c5 +Subproject commit 40b3733b4bf4604ff7622b5eab592edcef750591 diff --git a/numpy/random/randomgen/src/legacy/distributions-boxmuller.c b/numpy/random/randomgen/src/legacy/distributions-boxmuller.c index e96d3f19a0cb..5d3ba27f8218 100644 --- a/numpy/random/randomgen/src/legacy/distributions-boxmuller.c +++ b/numpy/random/randomgen/src/legacy/distributions-boxmuller.c @@ -12,7 +12,6 @@ double legacy_gauss(aug_brng_t *aug_state) { return temp; } else { double f, x1, x2, r2; - double f, x1, x2, r2; do { x1 = 2.0 * legacy_double(aug_state) - 1.0; diff --git a/numpy/random/randomgen/tests/test_against_numpy.py b/numpy/random/randomgen/tests/test_against_numpy.py index b0fcdfb710f1..431c7bd85d24 100644 --- a/numpy/random/randomgen/tests/test_against_numpy.py +++ b/numpy/random/randomgen/tests/test_against_numpy.py @@ -570,9 +570,9 @@ def test_multivariate_normal(self): self._is_state_common_legacy() -funcs = [randomgen.generator.zipf, - randomgen.generator.logseries, - randomgen.generator.poisson] +funcs = [generator.zipf, + generator.logseries, + generator.poisson] ids = [f.__name__ for f in funcs] From 61c090bfc367110332a845bf381496e064aed86d Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 8 Apr 2019 10:11:07 +0100 Subject: [PATCH 261/279] BUG: Correct handling of nans Improve consistency of nan handling Prevent nans prducing values from int functions --- numpy/random/randomgen/src/legacy/distributions-boxmuller.c | 1 + 1 file changed, 1 insertion(+) diff --git a/numpy/random/randomgen/src/legacy/distributions-boxmuller.c b/numpy/random/randomgen/src/legacy/distributions-boxmuller.c index 5d3ba27f8218..e96d3f19a0cb 100644 --- a/numpy/random/randomgen/src/legacy/distributions-boxmuller.c +++ b/numpy/random/randomgen/src/legacy/distributions-boxmuller.c @@ -12,6 +12,7 @@ double legacy_gauss(aug_brng_t *aug_state) { return temp; } else { double f, x1, x2, r2; + double f, x1, x2, r2; do { x1 = 2.0 * legacy_double(aug_state) - 1.0; From 686e9db4b99697376687ad3c583fc46a25064622 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 8 Apr 2019 12:33:40 +0100 Subject: [PATCH 262/279] TST: Add tests for nan guards Add tests to ensure guards work Synchronize with randomgen Remove comments no longer relevant --- numpy/random/randomgen/common.pyx | 3 + .../src/legacy/distributions-boxmuller.c | 1 - numpy/random/randomgen/tests/test_direct.py | 6 +- .../randomgen/tests/test_generator_mt19937.py | 127 +++++---- .../randomgen/tests/test_randomstate.py | 241 +++++++++++------- 5 files changed, 233 insertions(+), 145 deletions(-) diff --git a/numpy/random/randomgen/common.pyx b/numpy/random/randomgen/common.pyx index 1f7cd40cac76..ebd2e60d107d 100644 --- a/numpy/random/randomgen/common.pyx +++ b/numpy/random/randomgen/common.pyx @@ -337,6 +337,9 @@ cdef int check_constraint(double val, object name, constraint_type cons) except elif cons == CONS_BOUNDED_0_1: if not (val >= 0) or not (val <= 1): raise ValueError("{0} < 0 , {0} > 1 or {0} is NaN".format(name)) + elif cons == CONS_BOUNDED_GT_0_1: + if not val >0 or not val <= 1: + raise ValueError("{0} <= 0 , {0} > 1 or {0} contains NaNs".format(name)) elif cons == CONS_GT_1: if not (val > 1): raise ValueError("{0} <= 1 or {0} is NaN".format(name)) diff --git a/numpy/random/randomgen/src/legacy/distributions-boxmuller.c b/numpy/random/randomgen/src/legacy/distributions-boxmuller.c index e96d3f19a0cb..5d3ba27f8218 100644 --- a/numpy/random/randomgen/src/legacy/distributions-boxmuller.c +++ b/numpy/random/randomgen/src/legacy/distributions-boxmuller.c @@ -12,7 +12,6 @@ double legacy_gauss(aug_brng_t *aug_state) { return temp; } else { double f, x1, x2, r2; - double f, x1, x2, r2; do { x1 = 2.0 * legacy_double(aug_state) - 1.0; diff --git a/numpy/random/randomgen/tests/test_direct.py b/numpy/random/randomgen/tests/test_direct.py index 6e856de414cb..22fdcd865944 100644 --- a/numpy/random/randomgen/tests/test_direct.py +++ b/numpy/random/randomgen/tests/test_direct.py @@ -233,14 +233,14 @@ def test_seed_out_of_range_array(self): def test_repr(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert 'RandomGenerator' in rs.__repr__() - assert str(hex(id(rs)))[2:].upper() in rs.__repr__() + assert 'RandomGenerator' in repr(rs) + assert '{:#x}'.format(id(rs)).upper().replace('X', 'x') in repr(rs) def test_str(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) assert 'RandomGenerator' in str(rs) assert str(self.brng.__name__) in str(rs) - assert str(hex(id(rs)))[2:].upper() not in str(rs) + assert '{:#x}'.format(id(rs)).upper().replace('X', 'x') not in str(rs) def test_generator(self): brng = self.brng(*self.data1['seed']) diff --git a/numpy/random/randomgen/tests/test_generator_mt19937.py b/numpy/random/randomgen/tests/test_generator_mt19937.py index cad3ef4d66cd..10dd8733a8b9 100644 --- a/numpy/random/randomgen/tests/test_generator_mt19937.py +++ b/numpy/random/randomgen/tests/test_generator_mt19937.py @@ -53,8 +53,7 @@ def test_n_zero(self): # This test addresses issue #3480. zeros = np.zeros(2, dtype='int') for p in [0, .5, 1]: - val = random.binomial(0, p) - assert val == 0 + assert_(random.binomial(0, p) == 0) assert_array_equal(random.binomial(zeros, p), zeros) def test_p_is_nan(self): @@ -96,40 +95,40 @@ def test_invalid_prob(self): class TestSetState(object): def setup(self): self.seed = 1234567890 - self.brng = RandomGenerator(MT19937(self.seed)) - self.state = self.brng.state + self.rg = RandomGenerator(MT19937(self.seed)) + self.state = self.rg.state self.legacy_state = (self.state['brng'], self.state['state']['key'], self.state['state']['pos']) def test_basic(self): - old = self.brng.tomaxint(16) - self.brng.state = self.state - new = self.brng.tomaxint(16) + old = self.rg.tomaxint(16) + self.rg.state = self.state + new = self.rg.tomaxint(16) assert_(np.all(old == new)) def test_gaussian_reset(self): # Make sure the cached every-other-Gaussian is reset. - old = self.brng.standard_normal(size=3) - self.brng.state = self.state - new = self.brng.standard_normal(size=3) + old = self.rg.standard_normal(size=3) + self.rg.state = self.state + new = self.rg.standard_normal(size=3) assert_(np.all(old == new)) def test_gaussian_reset_in_media_res(self): # When the state is saved with a cached Gaussian, make sure the # cached Gaussian is restored. - self.brng.standard_normal() - state = self.brng.state - old = self.brng.standard_normal(size=3) - self.brng.state = state - new = self.brng.standard_normal(size=3) + self.rg.standard_normal() + state = self.rg.state + old = self.rg.standard_normal(size=3) + self.rg.state = state + new = self.rg.standard_normal(size=3) assert_(np.all(old == new)) def test_negative_binomial(self): # Ensure that the negative binomial results take floating point # arguments without truncation. - self.brng.negative_binomial(0.5, 0.5) + self.rg.negative_binomial(0.5, 0.5) class TestRandint(object): @@ -554,8 +553,7 @@ def test_choice_uniform_noreplace(self): def test_choice_nonuniform_noreplace(self): random.seed(self.seed) - actual = random.choice(4, 3, replace=False, - p=[0.1, 0.3, 0.5, 0.1]) + actual = random.choice(4, 3, replace=False, p=[0.1, 0.3, 0.5, 0.1]) desired = np.array([2, 3, 1]) assert_array_equal(actual, desired) @@ -614,11 +612,11 @@ def test_choice_return_shape(self): # Check multi dimensional array s = (2, 3) p = [0.1, 0.1, 0.1, 0.1, 0.4, 0.2] - assert_(random.choice(6, s, replace=True).shape, s) - assert_(random.choice(6, s, replace=False).shape, s) - assert_(random.choice(6, s, replace=True, p=p).shape, s) - assert_(random.choice(6, s, replace=False, p=p).shape, s) - assert_(random.choice(np.arange(6), s, replace=True).shape, s) + assert_equal(random.choice(6, s, replace=True).shape, s) + assert_equal(random.choice(6, s, replace=False).shape, s) + assert_equal(random.choice(6, s, replace=True, p=p).shape, s) + assert_equal(random.choice(6, s, replace=False, p=p).shape, s) + assert_equal(random.choice(np.arange(6), s, replace=True).shape, s) # Check zero-size assert_equal(random.randint(0, 0, size=(3, 0, 4)).shape, (3, 0, 4)) @@ -711,6 +709,11 @@ def test_binomial(self): [46, 45]]) assert_array_equal(actual, desired) + random.seed(self.seed) + actual = random.binomial(100.123, .456) + desired = 37 + assert_array_equal(actual, desired) + def test_chisquare(self): random.seed(self.seed) actual = random.chisquare(50, size=(3, 2)) @@ -795,6 +798,16 @@ def test_geometric(self): [5, 12]]) assert_array_equal(actual, desired) + def test_geometric_exceptions(self): + assert_raises(ValueError, random.geometric, 1.1) + assert_raises(ValueError, random.geometric, [1.1] * 10) + assert_raises(ValueError, random.geometric, -0.1) + assert_raises(ValueError, random.geometric, [-0.1] * 10) + with suppress_warnings() as sup: + sup.record(RuntimeWarning) + assert_raises(ValueError, random.geometric, np.nan) + assert_raises(ValueError, random.geometric, [np.nan] * 10) + def test_gumbel(self): random.seed(self.seed) actual = random.gumbel(loc=.123456789, scale=2.0, size=(3, 2)) @@ -873,6 +886,12 @@ def test_logseries(self): [3, 6]]) assert_array_equal(actual, desired) + def test_logseries_exceptions(self): + with suppress_warnings() as sup: + sup.record(RuntimeWarning) + assert_raises(ValueError, random.logseries, np.nan) + assert_raises(ValueError, random.logseries, [np.nan] * 10) + def test_multinomial(self): random.seed(self.seed) actual = random.multinomial(20, [1 / 6.] * 6, size=(3, 2)) @@ -943,6 +962,13 @@ def test_negative_binomial(self): [723, 751]]) assert_array_equal(actual, desired) + def test_negative_binomial_exceptions(self): + with suppress_warnings() as sup: + sup.record(RuntimeWarning) + assert_raises(ValueError, random.negative_binomial, 100, np.nan) + assert_raises(ValueError, random.negative_binomial, 100, + [np.nan] * 10) + def test_noncentral_chisquare(self): random.seed(self.seed) actual = random.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) @@ -973,6 +999,11 @@ def test_noncentral_f(self): [1.16362730891403, 2.54104276581491]]) assert_array_almost_equal(actual, desired, decimal=14) + def test_noncentral_f_nan(self): + random.seed(self.seed) + actual = random.noncentral_f(dfnum=5, dfden=2, nonc=np.nan) + assert np.isnan(actual) + def test_normal(self): random.seed(self.seed) actual = random.normal(loc=.123456789, scale=2.0, size=(3, 2)) @@ -993,7 +1024,7 @@ def test_pareto(self): [1.1281132447159091e+01, 3.1895968171107006e+08]]) # For some reason on 32-bit x86 Ubuntu 12.10 the [1, 0] entry in this # matrix differs by 24 nulps. Discussion: - # http://mail.scipy.org/pipermail/numpy-discussion/2012-September/063801.html + # https://mail.python.org/pipermail/numpy-discussion/2012-September/063801.html # Consensus is that this is probably some gcc quirk that affects # rounding but not in any important way, so we just use a looser # tolerance on this test: @@ -1014,6 +1045,10 @@ def test_poisson_exceptions(self): assert_raises(ValueError, random.poisson, [lamneg] * 10) assert_raises(ValueError, random.poisson, lambig) assert_raises(ValueError, random.poisson, [lambig] * 10) + with suppress_warnings() as sup: + sup.record(RuntimeWarning) + assert_raises(ValueError, random.poisson, np.nan) + assert_raises(ValueError, random.poisson, [np.nan] * 10) def test_power(self): random.seed(self.seed) @@ -1168,8 +1203,8 @@ def __float__(self): raise TypeError throwing_float = np.array(1.0).view(ThrowingFloat) - assert_raises(TypeError, random.uniform, - throwing_float, throwing_float) + assert_raises(TypeError, random.uniform, throwing_float, + throwing_float) class ThrowingInteger(np.ndarray): def __int__(self): @@ -1189,9 +1224,14 @@ def test_vonmises(self): def test_vonmises_small(self): # check infinite loop, gh-4720 random.seed(self.seed) - r = random.vonmises(mu=0., kappa=1.1e-8, size=10 ** 6) + r = random.vonmises(mu=0., kappa=1.1e-8, size=10**6) assert_(np.isfinite(r).all()) + def test_vonmises_nan(self): + random.seed(self.seed) + r = random.vonmises(mu=0., kappa=np.nan) + assert_(np.isnan(r)) + def test_wald(self): random.seed(self.seed) actual = random.wald(mean=1.23, scale=1.54, size=(3, 2)) @@ -1372,8 +1412,9 @@ def test_noncentral_f(self): self.set_seed() actual = nonc_f(dfnum * 3, dfden, nonc) - mt_nonc_f = random.noncentral_f assert_array_almost_equal(actual, desired, decimal=14) + assert np.all(np.isnan(nonc_f(dfnum, dfden, [np.nan] * 3))) + assert_raises(ValueError, nonc_f, bad_dfnum * 3, dfden, nonc) assert_raises(ValueError, nonc_f, dfnum * 3, bad_dfden, nonc) assert_raises(ValueError, nonc_f, dfnum * 3, dfden, bad_nonc) @@ -1391,9 +1432,12 @@ def test_noncentral_f(self): assert_raises(ValueError, nonc_f, bad_dfnum, dfden, nonc * 3) assert_raises(ValueError, nonc_f, dfnum, bad_dfden, nonc * 3) assert_raises(ValueError, nonc_f, dfnum, dfden, bad_nonc * 3) - assert_raises(ValueError, mt_nonc_f, bad_dfnum, dfden, nonc * 3) - assert_raises(ValueError, mt_nonc_f, dfnum, bad_dfden, nonc * 3) - assert_raises(ValueError, mt_nonc_f, dfnum, dfden, bad_nonc * 3) + + def test_noncentral_f_small_df(self): + self.set_seed() + desired = np.array([21.57878070681719, 1.17110217503908]) + actual = random.noncentral_f(0.9, 0.9, 2, size=2) + assert_array_almost_equal(actual, desired, decimal=14) def test_chisquare(self): df = [1] @@ -1420,20 +1464,15 @@ def test_noncentral_chisquare(self): self.set_seed() actual = nonc_chi(df * 3, nonc) - mt_nonc_chi2 = random.noncentral_chisquare assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, nonc_chi, bad_df * 3, nonc) assert_raises(ValueError, nonc_chi, df * 3, bad_nonc) - assert_raises(ValueError, mt_nonc_chi2, bad_df * 3, nonc) - assert_raises(ValueError, mt_nonc_chi2, df * 3, bad_nonc) self.set_seed() actual = nonc_chi(df, nonc * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, nonc_chi, bad_df, nonc * 3) assert_raises(ValueError, nonc_chi, df, bad_nonc * 3) - assert_raises(ValueError, mt_nonc_chi2, bad_df, nonc * 3) - assert_raises(ValueError, mt_nonc_chi2, df, bad_nonc * 3) def test_standard_t(self): df = [1] @@ -1645,24 +1684,24 @@ def test_triangular(self): assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, triangular, bad_left_one * 3, mode, right) assert_raises(ValueError, triangular, left * 3, bad_mode_one, right) - assert_raises(ValueError, triangular, - bad_left_two * 3, bad_mode_two, right) + assert_raises(ValueError, triangular, bad_left_two * 3, bad_mode_two, + right) self.set_seed() actual = triangular(left, mode * 3, right) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, triangular, bad_left_one, mode * 3, right) assert_raises(ValueError, triangular, left, bad_mode_one * 3, right) - assert_raises(ValueError, triangular, bad_left_two, - bad_mode_two * 3, right) + assert_raises(ValueError, triangular, bad_left_two, bad_mode_two * 3, + right) self.set_seed() actual = triangular(left, mode, right * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, triangular, bad_left_one, mode, right * 3) assert_raises(ValueError, triangular, left, bad_mode_one, right * 3) - assert_raises(ValueError, triangular, bad_left_two, - bad_mode_two, right * 3) + assert_raises(ValueError, triangular, bad_left_two, bad_mode_two, + right * 3) assert_raises(ValueError, triangular, 10., 0., 20.) assert_raises(ValueError, triangular, 10., 25., 20.) @@ -1739,6 +1778,9 @@ def test_zipf(self): actual = zipf(a * 3) assert_array_equal(actual, desired) assert_raises(ValueError, zipf, bad_a * 3) + with np.errstate(invalid='ignore'): + assert_raises(ValueError, zipf, np.nan) + assert_raises(ValueError, zipf, [0, 0, np.nan]) def test_geometric(self): p = [0.5] @@ -1809,7 +1851,6 @@ def test_logseries(self): class TestThread(object): # make sure each state produces the same sequence even in threads - def setup(self): self.seeds = range(4) diff --git a/numpy/random/randomgen/tests/test_randomstate.py b/numpy/random/randomgen/tests/test_randomstate.py index 167d1b0aa545..6adde6c2ab33 100644 --- a/numpy/random/randomgen/tests/test_randomstate.py +++ b/numpy/random/randomgen/tests/test_randomstate.py @@ -109,7 +109,9 @@ def test_size(self): assert_raises(TypeError, random.multinomial, 1, p, float(1)) - assert_raises(ValueError, random.multinomial, 1, [1.1, .1]) + + def test_invalid_prob(self): + assert_raises(ValueError, random.multinomial, 100, [1.1, 0.2]) class TestSetState(object): @@ -352,6 +354,12 @@ def test_rand(self): [0.4575674820298663, 0.7781880808593471]]) assert_array_almost_equal(actual, desired, decimal=15) + def test_rand_singleton(self): + random.seed(self.seed) + actual = random.rand() + desired = 0.61879477158567997 + assert_array_almost_equal(actual, desired, decimal=15) + def test_randn(self): random.seed(self.seed) actual = random.randn(3, 2) @@ -360,6 +368,10 @@ def test_randn(self): [2.031033998682787, 2.17032494605655257]]) assert_array_almost_equal(actual, desired, decimal=15) + random.seed(self.seed) + actual = random.randn() + assert_array_almost_equal(actual, desired[0, 0], decimal=15) + def test_randint(self): random.seed(self.seed) actual = random.randint(-99, 99, size=(3, 2)) @@ -443,11 +455,9 @@ def test_random_sample(self): [0.4575674820298663, 0.7781880808593471]]) assert_array_almost_equal(actual, desired, decimal=15) - def test_rand_singleton(self): random.seed(self.seed) - actual = random.rand() - desired = np.array(0.61879477158567997) - assert_array_almost_equal(actual, desired, decimal=15) + actual = random.random_sample() + assert_array_almost_equal(actual, desired[0, 0], decimal=15) def test_choice_uniform_replace(self): random.seed(self.seed) @@ -582,18 +592,6 @@ def test_shuffle(self): desired = conv([0, 1, 9, 6, 2, 4, 5, 8, 7, 3]) assert_array_equal(actual, desired) - def test_permutation(self): - random.seed(self.seed) - alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] - actual = random.permutation(alist) - desired = [0, 1, 9, 6, 2, 4, 5, 8, 7, 3] - assert_array_equal(actual, desired) - - random.seed(self.seed) - arr_2d = np.atleast_2d([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]).T - actual = random.permutation(arr_2d) - assert_array_equal(actual, np.atleast_2d(desired).T) - def test_shuffle_masked(self): # gh-3263 a = np.ma.masked_values(np.reshape(range(20), (5, 4)) % 3 - 1, -1) @@ -608,6 +606,18 @@ def test_shuffle_masked(self): assert_equal( sorted(b.data[~b.mask]), sorted(b_orig.data[~b_orig.mask])) + def test_permutation(self): + random.seed(self.seed) + alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] + actual = random.permutation(alist) + desired = [0, 1, 9, 6, 2, 4, 5, 8, 7, 3] + assert_array_equal(actual, desired) + + random.seed(self.seed) + arr_2d = np.atleast_2d([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]).T + actual = random.permutation(arr_2d) + assert_array_equal(actual, np.atleast_2d(desired).T) + def test_beta(self): random.seed(self.seed) actual = random.beta(.1, .9, size=(3, 2)) @@ -649,6 +659,8 @@ def test_dirichlet(self): [[0.59266909280647828, 0.40733090719352177], [0.56974431743975207, 0.43025568256024799]]]) assert_array_almost_equal(actual, desired, decimal=15) + bad_alpha = np.array([5.4e-01, -1.0e-16]) + assert_raises(ValueError, random.dirichlet, bad_alpha) random.seed(self.seed) alpha = np.array([51.72840233779265162, 39.74494232180943953]) @@ -712,6 +724,16 @@ def test_geometric(self): [5, 12]]) assert_array_equal(actual, desired) + def test_geometric_exceptions(self): + assert_raises(ValueError, random.geometric, 1.1) + assert_raises(ValueError, random.geometric, [1.1] * 10) + assert_raises(ValueError, random.geometric, -0.1) + assert_raises(ValueError, random.geometric, [-0.1] * 10) + with suppress_warnings() as sup: + sup.record(RuntimeWarning) + assert_raises(ValueError, random.geometric, np.nan) + assert_raises(ValueError, random.geometric, [np.nan] * 10) + def test_gumbel(self): random.seed(self.seed) actual = random.gumbel(loc=.123456789, scale=2.0, size=(3, 2)) @@ -790,9 +812,15 @@ def test_logseries(self): [3, 6]]) assert_array_equal(actual, desired) + def test_logseries_exceptions(self): + with suppress_warnings() as sup: + sup.record(RuntimeWarning) + assert_raises(ValueError, random.logseries, np.nan) + assert_raises(ValueError, random.logseries, [np.nan] * 10) + def test_multinomial(self): random.seed(self.seed) - actual = random.multinomial(20, [1/6.]*6, size=(3, 2)) + actual = random.multinomial(20, [1 / 6.] * 6, size=(3, 2)) desired = np.array([[[4, 3, 5, 4, 2, 2], [5, 2, 8, 2, 2, 1]], [[3, 4, 3, 6, 0, 4], @@ -843,8 +871,8 @@ def test_multivariate_normal(self): mu = np.zeros(2) cov = np.eye(2) - assert_raises(ValueError, random.multivariate_normal, mean, - cov, check_valid='other') + assert_raises(ValueError, random.multivariate_normal, mean, cov, + check_valid='other') assert_raises(ValueError, random.multivariate_normal, np.zeros((2, 1, 1)), cov) assert_raises(ValueError, random.multivariate_normal, @@ -860,6 +888,13 @@ def test_negative_binomial(self): [779, 647]]) assert_array_equal(actual, desired) + def test_negative_binomial_exceptions(self): + with suppress_warnings() as sup: + sup.record(RuntimeWarning) + assert_raises(ValueError, random.negative_binomial, 100, np.nan) + assert_raises(ValueError, random.negative_binomial, 100, + [np.nan] * 10) + def test_noncentral_chisquare(self): random.seed(self.seed) actual = random.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) @@ -890,6 +925,11 @@ def test_noncentral_f(self): [0.43741599463544162, 1.1774208752428319]]) assert_array_almost_equal(actual, desired, decimal=14) + def test_noncentral_f_nan(self): + random.seed(self.seed) + actual = random.noncentral_f(dfnum=5, dfden=2, nonc=np.nan) + assert np.isnan(actual) + def test_normal(self): random.seed(self.seed) actual = random.normal(loc=.123456789, scale=2.0, size=(3, 2)) @@ -929,9 +969,13 @@ def test_poisson_exceptions(self): lambig = np.iinfo('l').max lamneg = -1 assert_raises(ValueError, random.poisson, lamneg) - assert_raises(ValueError, random.poisson, [lamneg]*10) + assert_raises(ValueError, random.poisson, [lamneg] * 10) assert_raises(ValueError, random.poisson, lambig) - assert_raises(ValueError, random.poisson, [lambig]*10) + assert_raises(ValueError, random.poisson, [lambig] * 10) + with suppress_warnings() as sup: + sup.record(RuntimeWarning) + assert_raises(ValueError, random.poisson, np.nan) + assert_raises(ValueError, random.poisson, [np.nan] * 10) def test_power(self): random.seed(self.seed) @@ -1026,8 +1070,8 @@ def test_uniform_range_bounds(self): func = random.uniform assert_raises(OverflowError, func, -np.inf, 0) - assert_raises(OverflowError, func, 0, np.inf) - assert_raises(OverflowError, func, fmin, fmax) + assert_raises(OverflowError, func, 0, np.inf) + assert_raises(OverflowError, func, fmin, fmax) assert_raises(OverflowError, func, [-np.inf], [0]) assert_raises(OverflowError, func, [0], [np.inf]) @@ -1070,7 +1114,12 @@ def test_vonmises_small(self): # check infinite loop, gh-4720 random.seed(self.seed) r = random.vonmises(mu=0., kappa=1.1e-8, size=10**6) - np.testing.assert_(np.isfinite(r).all()) + assert_(np.isfinite(r).all()) + + def test_vonmises_nan(self): + random.seed(self.seed) + r = random.vonmises(mu=0., kappa=np.nan) + assert_(np.isnan(r)) def test_wald(self): random.seed(self.seed) @@ -1108,12 +1157,9 @@ class TestBroadcast(object): def setup(self): self.seed = 123456789 - def setSeed(self): + def set_seed(self): random.seed(self.seed) - # TODO: Include test for randint once it can broadcast - # Can steal the test written in PR #6938 - def test_uniform(self): low = [0] high = [1] @@ -1122,11 +1168,11 @@ def test_uniform(self): 0.53413660089041659, 0.50955303552646702]) - self.setSeed() + self.set_seed() actual = uniform(low * 3, high) assert_array_almost_equal(actual, desired, decimal=14) - self.setSeed() + self.set_seed() actual = uniform(low, high * 3) assert_array_almost_equal(actual, desired, decimal=14) @@ -1139,12 +1185,12 @@ def test_normal(self): 2.1283977976520019, 1.8417114045748335]) - self.setSeed() + self.set_seed() actual = normal(loc * 3, scale) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc * 3, bad_scale) - self.setSeed() + self.set_seed() actual = normal(loc, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, normal, loc, bad_scale * 3) @@ -1159,13 +1205,13 @@ def test_beta(self): 0.075230336409423643, 0.24976865978980844]) - self.setSeed() + self.set_seed() actual = beta(a * 3, b) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, beta, bad_a * 3, b) assert_raises(ValueError, beta, a * 3, bad_b) - self.setSeed() + self.set_seed() actual = beta(a, b * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, beta, bad_a, b * 3) @@ -1179,7 +1225,7 @@ def test_exponential(self): 0.76386282278691653, 0.71243813125891797]) - self.setSeed() + self.set_seed() actual = exponential(scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, exponential, bad_scale * 3) @@ -1192,7 +1238,7 @@ def test_standard_gamma(self): 0.76386282278691653, 0.71243813125891797]) - self.setSeed() + self.set_seed() actual = std_gamma(shape * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, std_gamma, bad_shape * 3) @@ -1207,13 +1253,13 @@ def test_gamma(self): 1.5277256455738331, 1.4248762625178359]) - self.setSeed() + self.set_seed() actual = gamma(shape * 3, scale) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, gamma, bad_shape * 3, scale) assert_raises(ValueError, gamma, shape * 3, bad_scale) - self.setSeed() + self.set_seed() actual = gamma(shape, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, gamma, bad_shape, scale * 3) @@ -1229,13 +1275,13 @@ def test_f(self): 0.86768719635363512, 2.7251095168386801]) - self.setSeed() + self.set_seed() actual = f(dfnum * 3, dfden) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, f, bad_dfnum * 3, dfden) assert_raises(ValueError, f, dfnum * 3, bad_dfden) - self.setSeed() + self.set_seed() actual = f(dfnum, dfden * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, f, bad_dfnum, dfden * 3) @@ -1253,21 +1299,23 @@ def test_noncentral_f(self): 13.025456344595602, 8.8018098359100545]) - self.setSeed() + self.set_seed() actual = nonc_f(dfnum * 3, dfden, nonc) assert_array_almost_equal(actual, desired, decimal=14) + assert np.all(np.isnan(nonc_f(dfnum, dfden, [np.nan] * 3))) + assert_raises(ValueError, nonc_f, bad_dfnum * 3, dfden, nonc) assert_raises(ValueError, nonc_f, dfnum * 3, bad_dfden, nonc) assert_raises(ValueError, nonc_f, dfnum * 3, dfden, bad_nonc) - self.setSeed() + self.set_seed() actual = nonc_f(dfnum, dfden * 3, nonc) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, nonc_f, bad_dfnum, dfden * 3, nonc) assert_raises(ValueError, nonc_f, dfnum, bad_dfden * 3, nonc) assert_raises(ValueError, nonc_f, dfnum, dfden * 3, bad_nonc) - self.setSeed() + self.set_seed() actual = nonc_f(dfnum, dfden, nonc * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, nonc_f, bad_dfnum, dfden, nonc * 3) @@ -1275,7 +1323,7 @@ def test_noncentral_f(self): assert_raises(ValueError, nonc_f, dfnum, dfden, bad_nonc * 3) def test_noncentral_f_small_df(self): - self.setSeed() + self.set_seed() desired = np.array([6.869638627492048, 0.785880199263955]) actual = random.noncentral_f(0.9, 0.9, 2, size=2) assert_array_almost_equal(actual, desired, decimal=14) @@ -1288,7 +1336,7 @@ def test_chisquare(self): 0.51947702108840776, 0.1320969254923558]) - self.setSeed() + self.set_seed() actual = chisquare(df * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, chisquare, bad_df * 3) @@ -1303,13 +1351,13 @@ def test_noncentral_chisquare(self): 4.5804135049718742, 6.0872302432834564]) - self.setSeed() + self.set_seed() actual = nonc_chi(df * 3, nonc) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, nonc_chi, bad_df * 3, nonc) assert_raises(ValueError, nonc_chi, df * 3, bad_nonc) - self.setSeed() + self.set_seed() actual = nonc_chi(df, nonc * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, nonc_chi, bad_df, nonc * 3) @@ -1323,10 +1371,11 @@ def test_standard_t(self): 5.8560725167361607, 1.0274791436474273]) - self.setSeed() + self.set_seed() actual = t(df * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, t, bad_df * 3) + assert_raises(ValueError, random.standard_t, bad_df * 3) def test_vonmises(self): mu = [2] @@ -1337,12 +1386,12 @@ def test_vonmises(self): -2.7064099483995943, -1.8672476700665914]) - self.setSeed() + self.set_seed() actual = vonmises(mu * 3, kappa) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, vonmises, mu * 3, bad_kappa) - self.setSeed() + self.set_seed() actual = vonmises(mu, kappa * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, vonmises, mu, bad_kappa * 3) @@ -1355,10 +1404,11 @@ def test_pareto(self): 1.1465519762044529, 1.0389564467453547]) - self.setSeed() + self.set_seed() actual = pareto(a * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, pareto, bad_a * 3) + assert_raises(ValueError, random.pareto, bad_a * 3) def test_weibull(self): a = [1] @@ -1368,10 +1418,11 @@ def test_weibull(self): 0.76386282278691653, 0.71243813125891797]) - self.setSeed() + self.set_seed() actual = weibull(a * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, weibull, bad_a * 3) + assert_raises(ValueError, random.weibull, bad_a * 3) def test_power(self): a = [1] @@ -1381,10 +1432,11 @@ def test_power(self): 0.53413660089041659, 0.50955303552646702]) - self.setSeed() + self.set_seed() actual = power(a * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, power, bad_a * 3) + assert_raises(ValueError, random.power, bad_a * 3) def test_laplace(self): loc = [0] @@ -1395,12 +1447,12 @@ def test_laplace(self): 0.070715642226971326, 0.019290950698972624]) - self.setSeed() + self.set_seed() actual = laplace(loc * 3, scale) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, laplace, loc * 3, bad_scale) - self.setSeed() + self.set_seed() actual = laplace(loc, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, laplace, loc, bad_scale * 3) @@ -1414,12 +1466,12 @@ def test_gumbel(self): 0.26936705726291116, 0.33906220393037939]) - self.setSeed() + self.set_seed() actual = gumbel(loc * 3, scale) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, gumbel, loc * 3, bad_scale) - self.setSeed() + self.set_seed() actual = gumbel(loc, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, gumbel, loc, bad_scale * 3) @@ -1433,15 +1485,16 @@ def test_logistic(self): 0.13675915696285773, 0.038216792802833396]) - self.setSeed() + self.set_seed() actual = logistic(loc * 3, scale) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, logistic, loc * 3, bad_scale) - self.setSeed() + self.set_seed() actual = logistic(loc, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, logistic, loc, bad_scale * 3) + assert_equal(random.logistic(1.0, 0.0), 1.0) def test_lognormal(self): mean = [0] @@ -1452,15 +1505,17 @@ def test_lognormal(self): 8.4013952870126261, 6.3073234116578671]) - self.setSeed() + self.set_seed() actual = lognormal(mean * 3, sigma) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, lognormal, mean * 3, bad_sigma) + assert_raises(ValueError, random.lognormal, mean * 3, bad_sigma) - self.setSeed() + self.set_seed() actual = lognormal(mean, sigma * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, lognormal, mean, bad_sigma * 3) + assert_raises(ValueError, random.lognormal, mean, bad_sigma * 3) def test_rayleigh(self): scale = [1] @@ -1470,7 +1525,7 @@ def test_rayleigh(self): 1.2360119924878694, 1.1936818095781789]) - self.setSeed() + self.set_seed() actual = rayleigh(scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, rayleigh, bad_scale * 3) @@ -1485,13 +1540,15 @@ def test_wald(self): 0.12450084820795027, 0.9096122728408238]) - self.setSeed() + self.set_seed() actual = wald(mean * 3, scale) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, wald, bad_mean * 3, scale) assert_raises(ValueError, wald, mean * 3, bad_scale) + assert_raises(ValueError, random.wald, bad_mean * 3, scale) + assert_raises(ValueError, random.wald, mean * 3, bad_scale) - self.setSeed() + self.set_seed() actual = wald(mean, scale * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, wald, bad_mean, scale * 3) @@ -1511,7 +1568,7 @@ def test_triangular(self): 2.0347400359389356, 2.0095991069536208]) - self.setSeed() + self.set_seed() actual = triangular(left * 3, mode, right) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, triangular, bad_left_one * 3, mode, right) @@ -1519,7 +1576,7 @@ def test_triangular(self): assert_raises(ValueError, triangular, bad_left_two * 3, bad_mode_two, right) - self.setSeed() + self.set_seed() actual = triangular(left, mode * 3, right) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, triangular, bad_left_one, mode * 3, right) @@ -1527,7 +1584,7 @@ def test_triangular(self): assert_raises(ValueError, triangular, bad_left_two, bad_mode_two * 3, right) - self.setSeed() + self.set_seed() actual = triangular(left, mode, right * 3) assert_array_almost_equal(actual, desired, decimal=14) assert_raises(ValueError, triangular, bad_left_one, mode, right * 3) @@ -1548,14 +1605,14 @@ def test_binomial(self): binom = random.binomial desired = np.array([1, 1, 1]) - self.setSeed() + self.set_seed() actual = binom(n * 3, p) assert_array_equal(actual, desired) assert_raises(ValueError, binom, bad_n * 3, p) assert_raises(ValueError, binom, n * 3, bad_p_one) assert_raises(ValueError, binom, n * 3, bad_p_two) - self.setSeed() + self.set_seed() actual = binom(n, p * 3) assert_array_equal(actual, desired) assert_raises(ValueError, binom, bad_n, p * 3) @@ -1571,14 +1628,14 @@ def test_negative_binomial(self): neg_binom = random.negative_binomial desired = np.array([1, 0, 1]) - self.setSeed() + self.set_seed() actual = neg_binom(n * 3, p) assert_array_equal(actual, desired) assert_raises(ValueError, neg_binom, bad_n * 3, p) assert_raises(ValueError, neg_binom, n * 3, bad_p_one) assert_raises(ValueError, neg_binom, n * 3, bad_p_two) - self.setSeed() + self.set_seed() actual = neg_binom(n, p * 3) assert_array_equal(actual, desired) assert_raises(ValueError, neg_binom, bad_n, p * 3) @@ -1594,7 +1651,7 @@ def test_poisson(self): poisson = random.poisson desired = np.array([1, 1, 0]) - self.setSeed() + self.set_seed() actual = poisson(lam * 3) assert_array_equal(actual, desired) assert_raises(ValueError, poisson, bad_lam_one * 3) @@ -1606,7 +1663,7 @@ def test_zipf(self): zipf = random.zipf desired = np.array([2, 2, 1]) - self.setSeed() + self.set_seed() actual = zipf(a * 3) assert_array_equal(actual, desired) assert_raises(ValueError, zipf, bad_a * 3) @@ -1621,7 +1678,7 @@ def test_geometric(self): geom = random.geometric desired = np.array([2, 2, 2]) - self.setSeed() + self.set_seed() actual = geom(p * 3) assert_array_equal(actual, desired) assert_raises(ValueError, geom, bad_p_one * 3) @@ -1638,7 +1695,7 @@ def test_hypergeometric(self): hypergeom = random.hypergeometric desired = np.array([1, 1, 1]) - self.setSeed() + self.set_seed() actual = hypergeom(ngood * 3, nbad, nsample) assert_array_equal(actual, desired) assert_raises(ValueError, hypergeom, bad_ngood * 3, nbad, nsample) @@ -1646,7 +1703,7 @@ def test_hypergeometric(self): assert_raises(ValueError, hypergeom, ngood * 3, nbad, bad_nsample_one) assert_raises(ValueError, hypergeom, ngood * 3, nbad, bad_nsample_two) - self.setSeed() + self.set_seed() actual = hypergeom(ngood, nbad * 3, nsample) assert_array_equal(actual, desired) assert_raises(ValueError, hypergeom, bad_ngood, nbad * 3, nsample) @@ -1654,7 +1711,7 @@ def test_hypergeometric(self): assert_raises(ValueError, hypergeom, ngood, nbad * 3, bad_nsample_one) assert_raises(ValueError, hypergeom, ngood, nbad * 3, bad_nsample_two) - self.setSeed() + self.set_seed() actual = hypergeom(ngood, nbad, nsample * 3) assert_array_equal(actual, desired) assert_raises(ValueError, hypergeom, bad_ngood, nbad, nsample * 3) @@ -1662,6 +1719,9 @@ def test_hypergeometric(self): assert_raises(ValueError, hypergeom, ngood, nbad, bad_nsample_one * 3) assert_raises(ValueError, hypergeom, ngood, nbad, bad_nsample_two * 3) + assert_raises(ValueError, hypergeom, -1, 10, 20) + assert_raises(ValueError, hypergeom, 10, -1, 20) + assert_raises(ValueError, hypergeom, 10, 10, 0) assert_raises(ValueError, hypergeom, 10, 10, 25) def test_logseries(self): @@ -1671,7 +1731,7 @@ def test_logseries(self): logseries = random.logseries desired = np.array([1, 1, 1]) - self.setSeed() + self.set_seed() actual = logseries(p * 3) assert_array_equal(actual, desired) assert_raises(ValueError, logseries, bad_p_one * 3) @@ -1708,16 +1768,19 @@ def check_function(self, function, sz): def test_normal(self): def gen_random(state, out): out[...] = state.normal(size=10000) + self.check_function(gen_random, sz=(10000,)) def test_exp(self): def gen_random(state, out): out[...] = state.exponential(scale=np.ones((100, 1000))) + self.check_function(gen_random, sz=(100, 1000)) def test_multinomial(self): def gen_random(state, out): - out[...] = state.multinomial(10, [1/6.]*6, size=10000) + out[...] = state.multinomial(10, [1 / 6.] * 6, size=10000) + self.check_function(gen_random, sz=(10000, 6)) @@ -1775,24 +1838,6 @@ def test_two_arg_funcs(self): out = func(self.argOne, argTwo[0]) assert_equal(out.shape, self.tgtShape) -# TODO: Uncomment once randint can broadcast arguments -# def test_randint(self): -# itype = [bool, np.int8, np.uint8, np.int16, np.uint16, -# np.int32, np.uint32, np.int64, np.uint64] -# func = random.randint -# high = np.array([1]) -# low = np.array([0]) -# -# for dt in itype: -# out = func(low, high, dtype=dt) -# self.assert_equal(out.shape, self.tgtShape) -# -# out = func(low[0], high, dtype=dt) -# self.assert_equal(out.shape, self.tgtShape) -# -# out = func(low, high[0], dtype=dt) -# self.assert_equal(out.shape, self.tgtShape) - def test_three_arg_funcs(self): funcs = [random.noncentral_f, random.triangular, random.hypergeometric] From c4d6c5d94cf7ae592777e836d25eb6cd876740b8 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 8 Apr 2019 23:00:41 +0300 Subject: [PATCH 263/279] BUILD: add ipython for documentation example syntax highlighting --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cc01e8851bf5..e7fbf55fe6a9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,7 +20,7 @@ jobs: command: | python3 -m venv venv . venv/bin/activate - pip install cython sphinx>=1.8.3 matplotlib + pip install cython sphinx>=1.8.5 matplotlib ipython sudo apt-get update sudo apt-get install -y graphviz texlive-fonts-recommended texlive-latex-recommended texlive-latex-extra texlive-generic-extra latexmk texlive-xetex From b728205741edbf770bda94be203fb7b24039c2ee Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Mon, 8 Apr 2019 22:30:07 +0200 Subject: [PATCH 264/279] Add benchmark for sorting random array. --- benchmarks/benchmarks/bench_function_base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmarks/benchmarks/bench_function_base.py b/benchmarks/benchmarks/bench_function_base.py index 07ada2bbb26b..7ea8c39b0222 100644 --- a/benchmarks/benchmarks/bench_function_base.py +++ b/benchmarks/benchmarks/bench_function_base.py @@ -199,6 +199,7 @@ class Sort(Benchmark): ['quick', 'merge', 'heap'], ['float64', 'int64', 'uint64'], [ + ('random',), ('ordered',), ('reversed',), ('uniform',), From 23446e949561044a15120bcd26fd645edde12190 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 8 Apr 2019 23:23:44 +0300 Subject: [PATCH 265/279] DOC: fix docstring --- doc/source/reference/randomgen/new-or-different.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/reference/randomgen/new-or-different.rst b/doc/source/reference/randomgen/new-or-different.rst index 6598c13feb36..0a27b9aa158c 100644 --- a/doc/source/reference/randomgen/new-or-different.rst +++ b/doc/source/reference/randomgen/new-or-different.rst @@ -35,7 +35,7 @@ What's New or Different .. ipython:: python - from randomgen import Xoroshiro128 + from numpy.random.randomgen import Xoroshiro128 import numpy.random rg = Xoroshiro128().generator %timeit rg.standard_normal(100000) From 96cacd74e50d972df8f6c8704b0f4b3c3dfbc81c Mon Sep 17 00:00:00 2001 From: Tyler Moncur Date: Thu, 28 Mar 2019 00:34:19 -0600 Subject: [PATCH 266/279] ENH: use rotated companion matrix to reduce error --- numpy/polynomial/polynomial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/polynomial/polynomial.py b/numpy/polynomial/polynomial.py index e3eb7ec5aaaa..bada4321ec31 100644 --- a/numpy/polynomial/polynomial.py +++ b/numpy/polynomial/polynomial.py @@ -1429,7 +1429,7 @@ def polyroots(c): return np.array([-c[0]/c[1]]) m = polycompanion(c) - r = la.eigvals(m) + r = la.eigvals(m[::-1,::-1]) r.sort() return r From 732d52a4c3cd91b8a2e20b99823fcd233dc32112 Mon Sep 17 00:00:00 2001 From: Tyler Moncur Date: Mon, 8 Apr 2019 17:00:10 -0600 Subject: [PATCH 267/279] ENH: rotate companion matrix for all polynomial bases --- numpy/polynomial/chebyshev.py | 3 ++- numpy/polynomial/hermite.py | 3 ++- numpy/polynomial/hermite_e.py | 3 ++- numpy/polynomial/laguerre.py | 3 ++- numpy/polynomial/legendre.py | 3 ++- numpy/polynomial/polynomial.py | 5 +++-- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/numpy/polynomial/chebyshev.py b/numpy/polynomial/chebyshev.py index 836f473636e0..c37b2c6d623d 100644 --- a/numpy/polynomial/chebyshev.py +++ b/numpy/polynomial/chebyshev.py @@ -1743,7 +1743,8 @@ def chebroots(c): if len(c) == 2: return np.array([-c[0]/c[1]]) - m = chebcompanion(c) + # rotated companion matrix reduces error + m = chebcompanion(c)[::-1,::-1] r = la.eigvals(m) r.sort() return r diff --git a/numpy/polynomial/hermite.py b/numpy/polynomial/hermite.py index dcd0a2b4d29a..3870d1054a4a 100644 --- a/numpy/polynomial/hermite.py +++ b/numpy/polynomial/hermite.py @@ -1476,7 +1476,8 @@ def hermroots(c): if len(c) == 2: return np.array([-.5*c[0]/c[1]]) - m = hermcompanion(c) + # rotated companion matrix reduces error + m = hermcompanion(c)[::-1,::-1] r = la.eigvals(m) r.sort() return r diff --git a/numpy/polynomial/hermite_e.py b/numpy/polynomial/hermite_e.py index 48e5eab207f2..b12c0d792c98 100644 --- a/numpy/polynomial/hermite_e.py +++ b/numpy/polynomial/hermite_e.py @@ -1471,7 +1471,8 @@ def hermeroots(c): if len(c) == 2: return np.array([-c[0]/c[1]]) - m = hermecompanion(c) + # rotated companion matrix reduces error + m = hermecompanion(c)[::-1,::-1] r = la.eigvals(m) r.sort() return r diff --git a/numpy/polynomial/laguerre.py b/numpy/polynomial/laguerre.py index 41d15142ae1f..e103dde92f28 100644 --- a/numpy/polynomial/laguerre.py +++ b/numpy/polynomial/laguerre.py @@ -1475,7 +1475,8 @@ def lagroots(c): if len(c) == 2: return np.array([1 + c[0]/c[1]]) - m = lagcompanion(c) + # rotated companion matrix reduces error + m = lagcompanion(c)[::-1,::-1] r = la.eigvals(m) r.sort() return r diff --git a/numpy/polynomial/legendre.py b/numpy/polynomial/legendre.py index d56e2ae2c0e7..9eec9740d9c9 100644 --- a/numpy/polynomial/legendre.py +++ b/numpy/polynomial/legendre.py @@ -1505,7 +1505,8 @@ def legroots(c): if len(c) == 2: return np.array([-c[0]/c[1]]) - m = legcompanion(c) + # rotated companion matrix reduces error + m = legcompanion(c)[::-1,::-1] r = la.eigvals(m) r.sort() return r diff --git a/numpy/polynomial/polynomial.py b/numpy/polynomial/polynomial.py index bada4321ec31..afa330502602 100644 --- a/numpy/polynomial/polynomial.py +++ b/numpy/polynomial/polynomial.py @@ -1428,8 +1428,9 @@ def polyroots(c): if len(c) == 2: return np.array([-c[0]/c[1]]) - m = polycompanion(c) - r = la.eigvals(m[::-1,::-1]) + # rotated companion matrix reduces error + m = polycompanion(c)[::-1,::-1] + r = la.eigvals(m) r.sort() return r From 4006dc3529f1d27741d31d7a65a3a517aaf2b794 Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 9 Apr 2019 16:58:40 +0300 Subject: [PATCH 268/279] DOC: update numpydoc to latest master --- doc/sphinxext | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinxext b/doc/sphinxext index e47b9404963a..a482f66913c1 160000 --- a/doc/sphinxext +++ b/doc/sphinxext @@ -1 +1 @@ -Subproject commit e47b9404963ad2a75a11d167416038275c50d1c5 +Subproject commit a482f66913c1079d7439770f0119b55376bb1b81 From e7b8ba69696161639d065646ddf93cab5ed302e9 Mon Sep 17 00:00:00 2001 From: kikocorreoso Date: Tue, 9 Apr 2019 18:20:43 +0200 Subject: [PATCH 269/279] fix test name --- numpy/lib/tests/test_type_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/lib/tests/test_type_check.py b/numpy/lib/tests/test_type_check.py index 1a6af3b6c070..87382c149fa1 100644 --- a/numpy/lib/tests/test_type_check.py +++ b/numpy/lib/tests/test_type_check.py @@ -447,7 +447,7 @@ def test_complex_bad2(self): # !! changes #assert_all(vals.real < -1e10) and assert_all(np.isfinite(vals)) - def test_do_not_rewrite__previous_keyword(self): + def test_do_not_rewrite_previous_keyword(self): # This is done to test that when, for instance, nan=np.inf then these # values are not rewritten by posinf keyword to the posinf value. with np.errstate(divide='ignore', invalid='ignore'): From 000939ad2d6ec57ca1ab173243ae56350cd3b97f Mon Sep 17 00:00:00 2001 From: kikocorreoso Date: Tue, 9 Apr 2019 18:49:22 +0200 Subject: [PATCH 270/279] update tests --- numpy/lib/tests/test_type_check.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/numpy/lib/tests/test_type_check.py b/numpy/lib/tests/test_type_check.py index 87382c149fa1..b3f114b92968 100644 --- a/numpy/lib/tests/test_type_check.py +++ b/numpy/lib/tests/test_type_check.py @@ -365,9 +365,8 @@ def test_generic(self): with np.errstate(divide='ignore', invalid='ignore'): vals = nan_to_num(np.array((-1., 0, 1))/0., nan=10, posinf=20, neginf=30) - assert_all(vals[0] == 30) and assert_all(np.isfinite(vals[0])) - assert_(vals[1] == 10) - assert_all(vals[2] == 20) and assert_all(np.isfinite(vals[2])) + assert_equal(vals, [30, 10, 20]) + assert_all(np.isfinite(vals[[0, 2]])) assert_equal(type(vals), np.ndarray) # perform the same test but in-place @@ -387,9 +386,8 @@ def test_generic(self): result = nan_to_num(vals, copy=False, nan=10, posinf=20, neginf=30) assert_(result is vals) - assert_all(vals[0] == 30) and assert_all(np.isfinite(vals[0])) - assert_(vals[1] == 10) - assert_all(vals[2] == 20) and assert_all(np.isfinite(vals[2])) + assert_equal(vals, [30, 10, 20]) + assert_all(np.isfinite(vals[[0, 2]])) assert_equal(type(vals), np.ndarray) def test_array(self): @@ -452,9 +450,9 @@ def test_do_not_rewrite_previous_keyword(self): # values are not rewritten by posinf keyword to the posinf value. with np.errstate(divide='ignore', invalid='ignore'): vals = nan_to_num(np.array((-1., 0, 1))/0., nan=np.inf, posinf=999) - assert_all(vals[0] < -1e10) and assert_all(np.isfinite(vals[0])) - assert_(vals[1] == np.inf) - assert_all(vals[2] == 999) and assert_all(np.isfinite(vals[2])) + assert_all(np.isfinite(vals[[0, 2]])) + assert_all(vals[0] < -1e10) + assert_equal(vals[[1, 2]], [np.inf, 999]) assert_equal(type(vals), np.ndarray) From 2d801443b873f200afc8bb4b0f2f7abc4a5191ee Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 10 Apr 2019 00:50:42 +0300 Subject: [PATCH 271/279] BENCH: convert bencmarks to asv format --- _randomgen/benchmark.py | 201 -------------------------- benchmarks/benchmarks/bench_random.py | 99 +++++++++++++ 2 files changed, 99 insertions(+), 201 deletions(-) delete mode 100644 _randomgen/benchmark.py diff --git a/_randomgen/benchmark.py b/_randomgen/benchmark.py deleted file mode 100644 index c4c4ab93d8f6..000000000000 --- a/_randomgen/benchmark.py +++ /dev/null @@ -1,201 +0,0 @@ -import os -import struct -import timeit - -import numpy as np -import pandas as pd -from numpy.random import RandomState - -rs = RandomState() - -SETUP = ''' -import numpy as np -if '{brng}' == 'numpy': - import numpy.random - rg = numpy.random.RandomState() -else: - from randomgen import RandomGenerator, {brng} - rg = RandomGenerator({brng}()) -rg.random_sample() -''' - -scale_32 = scale_64 = 1 -if struct.calcsize('P') == 8 and os.name != 'nt': - # 64 bit - scale_32 = 0.5 -else: - scale_64 = 2 - -PRNGS = ['DSFMT', 'PCG64', 'PCG32', 'MT19937', 'Xoroshiro128', 'Xorshift1024', - 'Xoshiro256StarStar', 'Xoshiro512StarStar', 'Philox', 'ThreeFry', - 'ThreeFry32', 'numpy'] - - -def timer(code, setup): - return 1000 * min(timeit.Timer(code, setup=setup).repeat(10, 10)) / 10.0 - - -def print_legend(legend): - print('\n' + legend + '\n' + '*' * max(60, len(legend))) - - -def run_timer(dist, command, numpy_command=None, setup='', random_type=''): - print('-' * 80) - if numpy_command is None: - numpy_command = command - - res = {} - for brng in PRNGS: - cmd = numpy_command if brng == 'numpy' else command - res[brng] = timer(cmd, setup=setup.format(brng=brng)) - - s = pd.Series(res) - t = s.apply(lambda x: '{0:0.2f} ms'.format(x)) - print_legend('Time to produce 1,000,000 ' + random_type) - print(t.sort_index()) - - p = 1000.0 / s - p = p.apply(lambda x: '{0:0.2f} million'.format(x)) - print_legend(random_type + ' per second') - print(p.sort_index()) - - baseline = [k for k in p.index if 'numpy' in k][0] - p = 1000.0 / s - p = p / p[baseline] * 100 - 100 - p = p.drop(baseline, 0) - p = p.apply(lambda x: '{0:0.1f}%'.format(x)) - print_legend('Speed-up relative to NumPy') - print(p.sort_index()) - print('-' * 80) - - -def timer_raw(): - dist = 'random_raw' - command = 'rg.random_raw(size=1000000, output=False)' - info = np.iinfo(np.int32) - command_numpy = 'rg.random_integers({max},size=1000000)' - command_numpy = command_numpy.format(max=info.max) - run_timer(dist, command, command_numpy, SETUP, 'Raw Values') - - -def timer_uniform(): - dist = 'random_sample' - command = 'rg.random_sample(1000000)' - run_timer(dist, command, None, SETUP, 'Uniforms') - - -def timer_bounded(bits=8, max=95, use_masked=True): - """ - Timer for 8-bit bounded values. - - Parameters - ---------- - bits : {8, 16, 32, 64} - Bit width of unsigned output type - max : int - Upper bound for range. Lower is always 0. Must be <= 2**bits. - use_masked: bool - If True, masking and rejection sampling is used to generate a random - number in an interval. If False, Lemire's algorithm is used if - available to generate a random number in an interval. - - Notes - ----- - Lemire's algorithm has improved performance when {max}+1 is not a - power of two. - """ - if bits not in (8, 16, 32, 64): - raise ValueError('bits must be one of 8, 16, 32, 64.') - minimum = 0 - - dist = 'random_uintegers' - - if use_masked: # Use masking & rejection. - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint{bits}, use_masked=True)' - else: # Use Lemire's algo. - command = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint{bits}, use_masked=False)' - - command = command.format(min=minimum, max=max, bits=bits) - - command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint{bits})' - command_numpy = command_numpy.format(min=minimum, max=max, bits=bits) - - run_timer(dist, command, command_numpy, SETUP, - '{bits}-bit bounded unsigned integers (max={max}, ' - 'use_masked={use_masked})'.format(max=max, use_masked=use_masked, bits=bits)) - - -def timer_32bit(): - info = np.iinfo(np.uint32) - minimum, maximum = info.min, info.max - dist = 'random_uintegers' - command = 'rg.random_uintegers(1000000, 32)' - command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint32)' - command_numpy = command_numpy.format(min=minimum, max=maximum) - run_timer(dist, command, command_numpy, SETUP, '32-bit unsigned integers') - - -def timer_64bit(): - info = np.iinfo(np.uint64) - minimum, maximum = info.min, info.max - dist = 'random_uintegers' - command = 'rg.random_uintegers(1000000)' - command_numpy = 'rg.randint({min}, {max}+1, 1000000, dtype=np.uint64)' - command_numpy = command_numpy.format(min=minimum, max=maximum) - run_timer(dist, command, command_numpy, SETUP, '64-bit unsigned integers') - - -def timer_normal_zig(): - dist = 'standard_normal' - command = 'rg.standard_normal(1000000)' - command_numpy = 'rg.standard_normal(1000000)' - run_timer(dist, command, command_numpy, SETUP, - 'Standard normals (Ziggurat)') - - -if __name__ == '__main__': - import argparse - - parser = argparse.ArgumentParser() - parser.add_argument('-f', '--full', - help='Run benchmarks for a wide range of distributions.' - ' If not provided, only tests the production of ' - 'uniform values.', - dest='full', action='store_true') - parser.add_argument('-bi', '--bounded-ints', - help='Included benchmark coverage of the bounded ' - 'integer generators in a full run.', - dest='bounded_ints', action='store_true') - args = parser.parse_args() - - timer_uniform() - if args.full: - timer_raw() - if args.bounded_ints: - timer_bounded(use_masked=True) - timer_bounded(max=64, use_masked=False) # Worst case for Numpy. - timer_bounded(max=95, use_masked=False) # Typ. avrg. case for Numpy. - timer_bounded(max=127, use_masked=False) # Best case for Numpy. - - timer_bounded(16, use_masked=True) - timer_bounded(16, max=1024, use_masked=False) # Worst case for Numpy. - timer_bounded(16, max=1535, use_masked=False) # Typ. avrg. case for Numpy. - timer_bounded(16, max=2047, use_masked=False) # Best case for Numpy. - - timer_32bit() - - if args.bounded_ints: - timer_bounded(32, use_masked=True) - timer_bounded(32, max=1024, use_masked=False) # Worst case for Numpy. - timer_bounded(32, max=1535, use_masked=False) # Typ. avrg. case for Numpy. - timer_bounded(32, max=2047, use_masked=False) # Best case for Numpy. - - timer_64bit() - - if args.bounded_ints: - timer_bounded(64, use_masked=True) - timer_bounded(64, max=1024, use_masked=False) # Worst case for Numpy. - timer_bounded(64, max=1535, use_masked=False) # Typ. avrg. case for Numpy. - timer_bounded(64, max=2047, use_masked=False) # Best case for Numpy. - - timer_normal_zig() diff --git a/benchmarks/benchmarks/bench_random.py b/benchmarks/benchmarks/bench_random.py index 9d84d83d310a..38a079e84d6c 100644 --- a/benchmarks/benchmarks/bench_random.py +++ b/benchmarks/benchmarks/bench_random.py @@ -4,6 +4,8 @@ import numpy as np +from numpy.random import RandomState +from numpy.random.randomgen import RandomGenerator class Random(Benchmark): params = ['normal', 'uniform', 'weibull 1', 'binomial 10 0.5', @@ -80,3 +82,100 @@ def time_permutation_2d(self): def time_permutation_int(self): np.random.permutation(self.n) + +nom_size = 100000 + +class RNG(Benchmark): + param_names = ['rng'] + params = ['DSFMT', 'PCG64', 'PCG32', 'MT19937', 'Xoroshiro128', + 'Xorshift1024', 'Xoshiro256StarStar', 'Xoshiro512StarStar', + 'Philox', 'ThreeFry', 'ThreeFry32', 'numpy'] + + def setup(self, brng): + if brng == 'numpy': + self.rg = np.random.RandomState() + else: + self.rg = RandomGenerator(getattr(np.random.randomgen, brng)()) + self.rg.random_sample() + self.int32info = np.iinfo(np.int32) + self.uint32info = np.iinfo(np.uint32) + self.uint64info = np.iinfo(np.uint64) + + def time_raw(self, brng): + if brng == 'numpy': + self.rg.random_integers(self.int32info.max, size=nom_size) + else: + self.rg.random_integers(self.int32info.max, size=nom_size) + + def time_32bit(self, brng): + min, max = self.uint32info.min, self.uint32info.max + self.rg.randint(min, max + 1, nom_size, dtype=np.uint32) + + def time_64bit(self, brng): + min, max = self.uint64info.min, self.uint64info.max + self.rg.randint(min, max + 1, nom_size, dtype=np.uint64) + + def time_normal_zig(self, brng): + self.rg.standard_normal(nom_size) + +class Bounded(Benchmark): + u8 = np.uint8 + u16 = np.uint16 + u32 = np.uint32 + u64 = np.uint64 + param_names = ['rng', 'dt_max_masked'] + params = [['DSFMT', 'PCG64', 'PCG32', 'MT19937', 'Xoroshiro128', + 'Xorshift1024', 'Xoshiro256StarStar', 'Xoshiro512StarStar', + 'Philox', 'ThreeFry', 'ThreeFry32', 'numpy'], + [[u8, 95, True], + [u8, 64, False], # Worst case for legacy + [u8, 95, False], # Typ. avg. case for legacy + [u8, 127, False], # Best case for legacy + [u16, 95, True], + [u16, 1024, False], # Worst case for legacy + [u16, 1535, False], # Typ. avg. case for legacy + [u16, 2047, False], # Best case for legacy + [u32, 95, True], + [u32, 1024, False], # Worst case for legacy + [u32, 1535, False], # Typ. avg. case for legacy + [u32, 2047, False], # Best case for legacy + [u64, 95, True], + [u64, 1024, False], # Worst case for legacy + [u64, 1535, False], # Typ. avg. case for legacy + [u64, 2047, False], # Best case for legacy + ]] + + def setup(self, brng, args): + if brng == 'numpy': + self.rg = np.random.RandomState() + else: + self.rg = RandomGenerator(getattr(np.random.randomgen, brng)()) + self.rg.random_sample() + + def time_bounded(self, brng, args): + """ + Timer for 8-bit bounded values. + + Parameters (packed as args) + ---------- + dt : {uint8, uint16, uint32, unit64} + output dtype + max : int + Upper bound for range. Lower is always 0. Must be <= 2**bits. + use_masked: bool + If True, masking and rejection sampling is used to generate a random + number in an interval. If False, Lemire's algorithm is used if + available to generate a random number in an interval. + + Notes + ----- + Lemire's algorithm has improved performance when max+1 is not a + power of two. + """ + dt, max, use_masked = args + if brng == 'numpy': + self.rg.randint(0, max + 1, nom_size, dtype=dt) + else: + self.rg.randint(0, max + 1, nom_size, dtype=dt, + use_masked=use_masked) + From d05327b1d6b2b7bea6ba8a3ed4c7aaef6d01a540 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 10 Apr 2019 00:52:03 +0300 Subject: [PATCH 272/279] MAINT: remove files that were part of the origal repo --- _randomgen/.gitattributes | 1 - _randomgen/.gitignore | 26 --- _randomgen/.travis.yml | 72 --------- _randomgen/README-git.md | 26 --- _randomgen/README.md | 288 --------------------------------- _randomgen/README.rst | 320 ------------------------------------- _randomgen/setup.py | 325 -------------------------------------- 7 files changed, 1058 deletions(-) delete mode 100644 _randomgen/.gitattributes delete mode 100644 _randomgen/.gitignore delete mode 100644 _randomgen/.travis.yml delete mode 100644 _randomgen/README-git.md delete mode 100644 _randomgen/README.md delete mode 100644 _randomgen/README.rst delete mode 100644 _randomgen/setup.py diff --git a/_randomgen/.gitattributes b/_randomgen/.gitattributes deleted file mode 100644 index 9b447556a4c4..000000000000 --- a/_randomgen/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -randomgen/_version.py export-subst diff --git a/_randomgen/.gitignore b/_randomgen/.gitignore deleted file mode 100644 index 381421b399e9..000000000000 --- a/_randomgen/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -.idea/ -build/ -*.egg-info/ -*.pyd -*.pyc -*.html -*.obj -*.exe -**/Random123 -settings.json -*.so -randomgen/bounded_integers.pyx -randomgen/bounded_integers.pxd -randomgen/bounded_integers.c -randomgen/common.c -randomgen/dsfmt.c -randomgen/entropy.c -randomgen/generator.c -randomgen/mt19937.c -randomgen/pcg32.c -randomgen/pcg64.c -randomgen/philox.c -randomgen/threefry.c -randomgen/threefry32.c -randomgen/xoroshiro128.c -randomgen/xorshift1024.c diff --git a/_randomgen/.travis.yml b/_randomgen/.travis.yml deleted file mode 100644 index 89c5be3fad84..000000000000 --- a/_randomgen/.travis.yml +++ /dev/null @@ -1,72 +0,0 @@ -group: edge -dist: trusty -sudo: required -language: python - -env: - global: - # Doctr deploy key for bashtage/randomgen - - secure: "czwFlflS1lcfbSQ9ktv+pLAPV9/6+wmwiMTyIYyv5xgQVWRL5NRebWH+ZhQ6s2T5x17wFMtlafcAvkdV0CHQZLru34V2UNldCapuEtQ8b32EDHBXHKbs45b7SSkLx4TFXdjiJurleY4ZIKle0gX6BW21zYBwaHJqbN6I8nRv9Rp47XEU1UV1Mdf/PhfTnxY31rFrPYL77xeWJzoFfT8zao39V4gQds+1Ag7FjdNVdSDVKwDduF4kS7tIbKqb4M+jsbc3PIKyP9nyQpEQF5ebJuG7mqXJhVJGEL83rBx8MLFPA/1X3cUzKacgKyp2+Wmlt0EVhwCa1aRf9cSK6I7TbMC7/eGtDnC2ToiRlFJurVRblaEmhzVQS1yQ4Dkooqsj9hNVl6nhu7JfR52GLogns33Ec/yYuRcWcULKSlR5Cerfef/5YijBEhlr9X76SJiOpjvS4lwWFYX+h8xzuVhRLGwIVB9oQNllxYItzcDSGmRx+EOMXWASHmoUDnBOZg4GMVukqOcF5l0ynoepiA1YHLdZlMy6SB3P7BZKF/aNCOn9nXw+N9X4U/yUpkM3Pb7HoGdNrC8RO4SwrNjGrarkdEB6e1lBReK/dqcylaF/mpK9VLpfQszDI8xnR4VCmlEM+le0xOsyHfeGciabdI4KH0i0SfYl4ls5XrN+CaqFWdo=" - - PYPI=false - -cache: - directories: - - $HOME/.cache/pip - -matrix: - fast_finish: true - include: - - os: linux - env: [PYTHON=2.7, NUMPY=1.13, CYTHON=0.26] - - os: linux - env: [PYTHON=2.7] - - os: linux - env: [PYTHON=3.5, NUMPY=1.14] - - os: linux - env: [PYTHON=3.6, NUMPY=1.15, CYTHON=0.27] - - os: linux - python: 3.6 - env: [PYPI=true] - - os: linux - env: [PYTHON=3.7, DOCBUILD=true] - - os: osx - language: generic - env: [PYTHON=3.6] - - -before_install: - - git fetch --tags - - if [[ $PYPI = true ]]; then source ci/pypi-install.sh; else source ci/conda-install.sh; fi - - pip install tempita coverage coveralls pytest-cov codecov -q - - pip list - - export BUILD_DIR=${PWD} - - if [[ ${DOCBUILD} == true ]]; then pip install sphinx sphinx_rtd_theme guzzle_sphinx_theme ipython doctr -q; fi - - gcc --version || true - - clang --version || true - -install: - - python setup.py develop - -script: - - set -e - - pytest randomgen - - | - if [[ ${DOCBUILD} == true ]]; then - cd ${BUILD_DIR}/doc - make html - make html - cd ${BUILD_DIR} - doctr deploy devel --build-tags - if [[ -z ${TRAVIS_TAG} ]]; then - echo "Not a tagged build." - else - doctr deploy . --build-tags - fi - fi - -after_success: - - | - if [[ ${DOCBUILD} == true ]]; then - cd ${BUILD_DIR} - python benchmark.py; - fi diff --git a/_randomgen/README-git.md b/_randomgen/README-git.md deleted file mode 100644 index c771693902b6..000000000000 --- a/_randomgen/README-git.md +++ /dev/null @@ -1,26 +0,0 @@ -These are the bash commands used to get the bashtage/randomgen repo into numpy/numpy - -```bash -# from a directory just above a numpy git checkout -git clone https://github.com/bashtage/randomgen.git -cd randomgen -# rewrite the checkout, pushing the content into '_randomgen' -git filter-branch --index-filter ' - git ls-files -s | - sed "s-\t-\t_randomgen/-" | - GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && - mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE -' HEAD -# write this file, commit it -git add _randomgen/README-git.md -git commit -m"Add README-git.md" -git checkout -b randomgen -cd ../numpy -git checkout -b randomgen -git remote add randomgen ../randomgen -git fetch randomgen randomgen -git merge --allow-unrelated-histories randomgen/randomgen -git remote remove randomgen -# Now all the randomgen commits are on the randomgen branch in numpy, -# and there is a subdirectory _randomgen with the content -``` diff --git a/_randomgen/README.md b/_randomgen/README.md deleted file mode 100644 index 2e8073645f30..000000000000 --- a/_randomgen/README.md +++ /dev/null @@ -1,288 +0,0 @@ -# RandomGen - -[![Travis Build Status](https://travis-ci.org/bashtage/randomgen.svg?branch=master)](https://travis-ci.org/bashtage/randomgen) -[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true)](https://ci.appveyor.com/project/bashtage/randomgen/branch/master) -[![PyPI version](https://badge.fury.io/py/randomgen.svg)](https://pypi.org/project/randomgen/) - -Random Number Generator using settable Basic RNG interface for future -NumPy RandomState evolution. - -This is a library and generic interface for alternative random -generators in Python and NumPy. - -## Python 2.7 Support - -v1.16 is the final major version that supports Python 2.7. Any bugs -in v1.16 will be patched until the end of 2019. All future releases -are Python 3, with an initial minimum version of 3.5. - -## Compatibility Warning - -`RandomGenerator` does not support Box-Muller normal variates and so it not -100% compatible with NumPy (or randomstate). Box-Muller normals are slow -to generate and all functions which previously relied on Box-Muller -normals now use the faster Ziggurat implementation. If you require backward -compatibility, a legacy generator, ``LegacyGenerator``, has been created -which can fully reproduce the sequence produced by NumPy. - -## Features - -* Replacement for NumPy's RandomState - - ```python - from randomgen import RandomGenerator, MT19937 - rnd = RandomGenerator(MT19937()) - x = rnd.standard_normal(100) - y = rnd.random_sample(100) - z = rnd.randn(10,10) - ``` - -* Default random generator is a fast generator called Xoroshiro128plus -* Support for random number generators that support independent streams - and jumping ahead so that sub-streams can be generated -* Faster random number generation, especially for normal, standard - exponential and standard gamma using the Ziggurat method - - ```python - from randomgen import RandomGenerator - # Default basic PRNG is Xoroshiro128 - rnd = RandomGenerator() - w = rnd.standard_normal(10000) - x = rnd.standard_exponential(10000) - y = rnd.standard_gamma(5.5, 10000) - ``` - -* Support for 32-bit floating randoms for core generators. - Currently supported: - - * Uniforms (`random_sample`) - * Exponentials (`standard_exponential`, both Inverse CDF and Ziggurat) - * Normals (`standard_normal`) - * Standard Gammas (via `standard_gamma`) - - **WARNING**: The 32-bit generators are **experimental** and subject - to change. - - **Note**: There are _no_ plans to extend the alternative precision - generation to all distributions. - -* Support for filling existing arrays using `out` keyword argument. Currently - supported in (both 32- and 64-bit outputs) - - * Uniforms (`random_sample`) - * Exponentials (`standard_exponential`) - * Normals (`standard_normal`) - * Standard Gammas (via `standard_gamma`) - -* Support for Lemire's method of generating uniform integers on an - arbitrary interval by setting `use_masked=True`. - -## Included Pseudo Random Number Generators - -This module includes a number of alternative random -number generators in addition to the MT19937 that is included in NumPy. -The RNGs include: - -* [MT19937](https://github.com/numpy/numpy/blob/master/numpy/random/mtrand/), - the NumPy rng -* [dSFMT](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/) a - SSE2-aware version of the MT19937 generator that is especially fast at - generating doubles -* [xoroshiro128+](http://xoroshiro.di.unimi.it/), - [xorshift1024*φ](http://xorshift.di.unimi.it/), - [xoshiro256**](http://xorshift.di.unimi.it/), - and [xoshiro512**](http://xorshift.di.unimi.it/) -* [PCG64](http://www.pcg-random.org/) -* ThreeFry and Philox from [Random123](https://www.deshawresearch.com/resources_random123.html) - -## Differences from `numpy.random.RandomState` - -### New Features - -* `standard_normal`, `normal`, `randn` and `multivariate_normal` all - use the much faster (100%+) Ziggurat method. -* `standard_gamma` and `gamma` both use the much faster Ziggurat method. -* `standard_exponential` `exponential` both support an additional - `method` keyword argument which can be `inv` or - `zig` where `inv` corresponds to the current method using the inverse - CDF and `zig` uses the much faster (100%+) Ziggurat method. -* Core random number generators can produce either single precision - (`np.float32`) or double precision (`np.float64`, the default) using - the optional keyword argument `dtype` -* Core random number generators can fill existing arrays using the - `out` keyword argument -* Standardizes integer-values random values as int64 for all platforms. -* `randint` supports generating using rejection sampling on masked - values (the default) or Lemire's method. Lemire's method can be much - faster when the required interval length is much smaller than the - closes power of 2. - -### New Functions - -* `random_entropy` - Read from the system entropy provider, which is - commonly used in cryptographic applications -* `random_raw` - Direct access to the values produced by the underlying - PRNG. The range of the values returned depends on the specifics of the - PRNG implementation. -* `random_uintegers` - unsigned integers, either 32- (`[0, 2**32-1]`) - or 64-bit (`[0, 2**64-1]`) -* `jump` - Jumps RNGs that support it. `jump` moves the state a great - distance. _Only available if supported by the RNG._ -* `advance` - Advanced the RNG 'as-if' a number of draws were made, - without actually drawing the numbers. _Only available if supported by - the RNG._ - -## Status - -* Builds and passes all tests on: - * Linux 32/64 bit, Python 2.7, 3.4, 3.5, 3.6, 3.6 - * PC-BSD (FreeBSD) 64-bit, Python 2.7 - * OSX 64-bit, Python 2.7, 3.5, 3.6, 3.7 - * Windows 32/64 bit, Python 2.7, 3.5, 3.6 and 3.7 - -## Version - -The version matched the latest version of NumPy where -`LegacyGenerator(MT19937())` passes all NumPy test. - -## Documentation - -Documentation for the latest release is available on -[my GitHub pages](http://bashtage.github.io/randomgen/). Documentation for -the latest commit (unreleased) is available under -[devel](http://bashtage.github.io/randomgen/devel/). - -## Plans - -This module is essentially complete. There are a few rough edges that -need to be smoothed. - -* Creation of additional streams from where supported - (i.e. a `next_stream()` method) - -## Requirements -Building requires: - -* Python (2.7, 3.5, 3.6, 3.7) -* NumPy (1.13, 1.14, 1.15, 1.16) -* Cython (0.26+) -* tempita (0.5+), if not provided by Cython - -Testing requires pytest (4.0+). - -**Note:** it might work with other versions but only tested with these -versions. - -## Development and Testing - -All development has been on 64-bit Linux, and it is regularly tested on -Travis-CI (Linux/OSX) and Appveyor (Windows). The library is occasionally -tested on Linux 32-bit and Free BSD 11.1. - -Basic tests are in place for all RNGs. The MT19937 is tested against -NumPy's implementation for identical results. It also passes NumPy's -test suite where still relevant. - -## Installing - -Either install from PyPi using - -```bash -pip install randomgen -``` - -or, if you want the latest version, - -```bash -pip install git+https://github.com/bashtage/randomgen.git -``` - -or from a cloned repo, - -```bash -python setup.py install -``` - -### SSE2 - -`dSFTM` makes use of SSE2 by default. If you have a very old computer -or are building on non-x86, you can install using: - -```bash -python setup.py install --no-sse2 -``` - -### Windows - -Either use a binary installer, or if building from scratch, use -Python 3.6 with Visual Studio 2015/2017 Community Edition. It can also -be build using Microsoft Visual C++ Compiler for Python 2.7 and -Python 2.7. - -## Using - -The separate generators are importable from `randomgen` - -```python -from randomgen import RandomGenerator, ThreeFry, PCG64, MT19937 -rg = RandomGenerator(ThreeFry()) -rg.random_sample(100) - -rg = RandomGenerator(PCG64()) -rg.random_sample(100) - -# Identical to NumPy -rg = RandomGenerator(MT19937()) -rg.random_sample(100) -``` - -## License - -Standard NCSA, plus sub licenses for components. - -## Performance - -Performance is promising, and even the mt19937 seems to be faster than -NumPy's mt19937. - - Speed-up relative to NumPy (Uniform Doubles) - ************************************************************ - DSFMT 184.9% - MT19937 17.3% - PCG32 83.3% - PCG64 108.3% - Philox -4.9% - ThreeFry -12.0% - ThreeFry32 -63.9% - Xoroshiro128 159.5% - Xorshift1024 150.4% - Xoshiro256StarStar 145.7% - Xoshiro512StarStar 113.1% - - Speed-up relative to NumPy (64-bit unsigned integers) - ************************************************************ - DSFMT 17.4% - MT19937 7.8% - PCG32 60.3% - PCG64 73.5% - Philox -25.5% - ThreeFry -30.5% - ThreeFry32 -67.8% - Xoroshiro128 124.0% - Xorshift1024 109.4% - Xoshiro256StarStar 100.3% - Xoshiro512StarStar 63.5% - - Speed-up relative to NumPy (Standard normals) - ************************************************************ - DSFMT 183.0% - MT19937 169.0% - PCG32 240.7% - PCG64 231.6% - Philox 131.3% - ThreeFry 118.3% - ThreeFry32 21.6% - Xoroshiro128 332.1% - Xorshift1024 232.4% - Xoshiro256StarStar 306.6% - Xoshiro512StarStar 274.6% diff --git a/_randomgen/README.rst b/_randomgen/README.rst deleted file mode 100644 index 7e91b898d17e..000000000000 --- a/_randomgen/README.rst +++ /dev/null @@ -1,320 +0,0 @@ -RandomGen -========= - -|Travis Build Status| |Appveyor Build Status| |PyPI version| - -Random Number Generator using settable Basic RNG interface for future -NumPy RandomState evolution. - -This is a library and generic interface for alternative random -generators in Python and NumPy. - -Python 2.7 Support ------------------- - -Release 1.16.0 is the final version that supports Python 2.7. Any bugs -in v1.16.0 will be patched until the end of 2019. All future releases -are Python 3, with an initial minimum version of 3.5. - -Compatibility Warning ---------------------- - -``RandomGenerator`` does not support Box-Muller normal variates and so -it not 100% compatible with NumPy (or randomstate). Box-Muller normals -are slow to generate and all functions which previously relied on -Box-Muller normals now use the faster Ziggurat implementation. If you -require backward compatibility, a legacy generator, ``LegacyGenerator``, -has been created which can fully reproduce the sequence produced by -NumPy. - -Features --------- - -- Replacement for NumPy’s RandomState - - .. code:: python - - from randomgen import RandomGenerator, MT19937 - rnd = RandomGenerator(MT19937()) - x = rnd.standard_normal(100) - y = rnd.random_sample(100) - z = rnd.randn(10,10) - -- Default random generator is a fast generator called Xoroshiro128plus -- Support for random number generators that support independent streams - and jumping ahead so that sub-streams can be generated -- Faster random number generation, especially for normal, standard - exponential and standard gamma using the Ziggurat method - - .. code:: python - - from randomgen import RandomGenerator - # Default basic PRNG is Xoroshiro128 - rnd = RandomGenerator() - w = rnd.standard_normal(10000) - x = rnd.standard_exponential(10000) - y = rnd.standard_gamma(5.5, 10000) - -- Support for 32-bit floating randoms for core generators. Currently - supported: - - - Uniforms (``random_sample``) - - Exponentials (``standard_exponential``, both Inverse CDF and - Ziggurat) - - Normals (``standard_normal``) - - Standard Gammas (via ``standard_gamma``) - - **WARNING**: The 32-bit generators are **experimental** and subject - to change. - - **Note**: There are *no* plans to extend the alternative precision - generation to all distributions. - -- Support for filling existing arrays using ``out`` keyword argument. - Currently supported in (both 32- and 64-bit outputs) - - - Uniforms (``random_sample``) - - Exponentials (``standard_exponential``) - - Normals (``standard_normal``) - - Standard Gammas (via ``standard_gamma``) - -- Support for Lemire’s method of generating uniform integers on an - arbitrary interval by setting ``use_masked=True``. - -Included Pseudo Random Number Generators ----------------------------------------- - -This module includes a number of alternative random number generators in -addition to the MT19937 that is included in NumPy. The RNGs include: - -- `MT19937 `__, - the NumPy rng -- `dSFMT `__ a - SSE2-aware version of the MT19937 generator that is especially fast - at generating doubles -- `xoroshiro128+ `__, - `xorshift1024*φ `__, - `xoshiro256*\* `__, and - `xoshiro512*\* `__ -- `PCG64 `__ -- ThreeFry and Philox from - `Random123 `__ - -Differences from ``numpy.random.RandomState`` ---------------------------------------------- - -New Features -~~~~~~~~~~~~ - -- ``standard_normal``, ``normal``, ``randn`` and - ``multivariate_normal`` all use the much faster (100%+) Ziggurat - method. -- ``standard_gamma`` and ``gamma`` both use the much faster Ziggurat - method. -- ``standard_exponential`` ``exponential`` both support an additional - ``method`` keyword argument which can be ``inv`` or ``zig`` where - ``inv`` corresponds to the current method using the inverse CDF and - ``zig`` uses the much faster (100%+) Ziggurat method. -- Core random number generators can produce either single precision - (``np.float32``) or double precision (``np.float64``, the default) - using the optional keyword argument ``dtype`` -- Core random number generators can fill existing arrays using the - ``out`` keyword argument -- Standardizes integer-values random values as int64 for all platforms. -- ``randint`` supports generating using rejection sampling on masked - values (the default) or Lemire’s method. Lemire’s method can be much - faster when the required interval length is much smaller than the - closes power of 2. - -New Functions -~~~~~~~~~~~~~ - -- ``random_entropy`` - Read from the system entropy provider, which is - commonly used in cryptographic applications -- ``random_raw`` - Direct access to the values produced by the - underlying PRNG. The range of the values returned depends on the - specifics of the PRNG implementation. -- ``random_uintegers`` - unsigned integers, either 32- - (``[0, 2**32-1]``) or 64-bit (``[0, 2**64-1]``) -- ``jump`` - Jumps RNGs that support it. ``jump`` moves the state a - great distance. *Only available if supported by the RNG.* -- ``advance`` - Advanced the RNG ‘as-if’ a number of draws were made, - without actually drawing the numbers. *Only available if supported by - the RNG.* - -Status ------- - -- Builds and passes all tests on: - - - Linux 32/64 bit, Python 2.7, 3.5, 3.6, 3.7 - - PC-BSD (FreeBSD) 64-bit, Python 2.7 - - OSX 64-bit, Python 2.7, 3.5, 3.6, 3.7 - - Windows 32/64 bit, Python 2.7, 3.5, 3.6, and 3.7 - -Version -------- - -The version matched the latest version of NumPy where -``LegacyGenerator(MT19937())`` passes all NumPy test. - -Documentation -------------- - -Documentation for the latest release is available on `my GitHub -pages `__. Documentation for the -latest commit (unreleased) is available under -`devel `__. - -Plans ------ - -This module is essentially complete. There are a few rough edges that -need to be smoothed. - -- Creation of additional streams from where supported (i.e. a - ``next_stream()`` method) - -Requirements ------------- - -Building requires: - -- Python (2.7, 3.5, 3.6, 3.7) -- NumPy (1.13, 1.14, 1.15, 1.16) -- Cython (0.26+) -- tempita (0.5+), if not provided by Cython - -Testing requires pytest (4.0+). - -**Note:** it might work with other versions but only tested with these -versions. - -Development and Testing ------------------------ - -All development has been on 64-bit Linux, and it is regularly tested on -Travis-CI (Linux/OSX) and Appveyor (Windows). The library is -occasionally tested on Linux 32-bit and Free BSD 11.1. - -Basic tests are in place for all RNGs. The MT19937 is tested against -NumPy’s implementation for identical results. It also passes NumPy’s -test suite where still relevant. - -Installing ----------- - -Either install from PyPi using - -.. code:: bash - - pip install randomgen - -or, if you want the latest version, - -.. code:: bash - - pip install git+https://github.com/bashtage/randomgen.git - -or from a cloned repo, - -.. code:: bash - - python setup.py install - -SSE2 -~~~~ - -``dSFTM`` makes use of SSE2 by default. If you have a very old computer -or are building on non-x86, you can install using: - -.. code:: bash - - python setup.py install --no-sse2 - -Windows -~~~~~~~ - -Either use a binary installer, or if building from scratch, use Python -3.6 with Visual Studio 2015/2017 Community Edition. It can also be build -using Microsoft Visual C++ Compiler for Python 2.7 and Python 2.7. - -Using ------ - -The separate generators are importable from ``randomgen`` - -.. code:: python - - from randomgen import RandomGenerator, ThreeFry, PCG64, MT19937 - rg = RandomGenerator(ThreeFry()) - rg.random_sample(100) - - rg = RandomGenerator(PCG64()) - rg.random_sample(100) - - # Identical to NumPy - rg = RandomGenerator(MT19937()) - rg.random_sample(100) - -License -------- - -Standard NCSA, plus sub licenses for components. - -Performance ------------ - -Performance is promising, and even the mt19937 seems to be faster than -NumPy’s mt19937. - -:: - - Speed-up relative to NumPy (Uniform Doubles) - ************************************************************ - DSFMT 184.9% - MT19937 17.3% - PCG32 83.3% - PCG64 108.3% - Philox -4.9% - ThreeFry -12.0% - ThreeFry32 -63.9% - Xoroshiro128 159.5% - Xorshift1024 150.4% - Xoshiro256StarStar 145.7% - Xoshiro512StarStar 113.1% - - Speed-up relative to NumPy (64-bit unsigned integers) - ************************************************************ - DSFMT 17.4% - MT19937 7.8% - PCG32 60.3% - PCG64 73.5% - Philox -25.5% - ThreeFry -30.5% - ThreeFry32 -67.8% - Xoroshiro128 124.0% - Xorshift1024 109.4% - Xoshiro256StarStar 100.3% - Xoshiro512StarStar 63.5% - - Speed-up relative to NumPy (Standard normals) - ************************************************************ - DSFMT 183.0% - MT19937 169.0% - PCG32 240.7% - PCG64 231.6% - Philox 131.3% - ThreeFry 118.3% - ThreeFry32 21.6% - Xoroshiro128 332.1% - Xorshift1024 232.4% - Xoshiro256StarStar 306.6% - Xoshiro512StarStar 274.6% - -.. |Travis Build Status| image:: https://travis-ci.org/bashtage/randomgen.svg?branch=master - :target: https://travis-ci.org/bashtage/randomgen -.. |Appveyor Build Status| image:: https://ci.appveyor.com/api/projects/status/odc5c4ukhru5xicl/branch/master?svg=true - :target: https://ci.appveyor.com/project/bashtage/randomgen/branch/master -.. |PyPI version| image:: https://badge.fury.io/py/randomgen.svg - :target: https://pypi.org/project/randomgen/ diff --git a/_randomgen/setup.py b/_randomgen/setup.py deleted file mode 100644 index f8eb8f81147a..000000000000 --- a/_randomgen/setup.py +++ /dev/null @@ -1,325 +0,0 @@ -import os -import glob -import platform -import struct -import sys -from os.path import join - -import Cython.Compiler.Options -import numpy as np -from Cython.Build import cythonize -from setuptools import setup, find_packages, Distribution -from setuptools.extension import Extension - -try: - import Cython.Tempita as tempita -except ImportError: - try: - import tempita - except ImportError: - raise ImportError('tempita required to install, ' - 'use pip install tempita') - -try: - import pypandoc - # With an input file: it will infer the input format from the filename - with open('README.rst', 'wb') as readme: - readme.write(pypandoc.convert_file('README.md', 'rst').encode('utf8')) -except ImportError: - import warnings - warnings.warn( - 'Unable to import pypandoc. Do not use this as a release build!') - -import versioneer - -with open('requirements.txt') as f: - required = f.read().splitlines() - -Cython.Compiler.Options.annotate = True - -# Make a guess as to whether SSE2 is present for now, TODO: Improve -USE_SSE2 = False -for k in platform.uname(): - for val in ('x86', 'i686', 'i386', 'amd64'): - USE_SSE2 = USE_SSE2 or val in k.lower() -print('Building with SSE?: {0}'.format(USE_SSE2)) -if '--no-sse2' in sys.argv: - USE_SSE2 = False - sys.argv.remove('--no-sse2') - -MOD_DIR = './randomgen' - -DEBUG = False -PCG_EMULATED_MATH = False - -EXTRA_INCLUDE_DIRS = [] -EXTRA_LINK_ARGS = [] -EXTRA_LIBRARIES = ['m'] if os.name != 'nt' else [] -# Undef for manylinux -EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else [ - '-std=c99', '-U__GNUC_GNU_INLINE__'] -if os.name == 'nt': - EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] - if DEBUG: - EXTRA_LINK_ARGS += ['-debug'] - EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] - if sys.version_info < (3, 0): - EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] - -PCG64_DEFS = [] -if sys.maxsize < 2 ** 32 or os.name == 'nt': - # Force emulated mode here - PCG_EMULATED_MATH = True - PCG64_DEFS += [('PCG_FORCE_EMULATED_128BIT_MATH', '1')] - -DSFMT_DEFS = [('DSFMT_MEXP', '19937')] -if USE_SSE2: - if os.name == 'nt': - EXTRA_COMPILE_ARGS += ['/wd4146', '/GL'] - if struct.calcsize('P') < 8: - EXTRA_COMPILE_ARGS += ['/arch:SSE2'] - else: - EXTRA_COMPILE_ARGS += ['-msse2'] - DSFMT_DEFS += [('HAVE_SSE2', '1')] -if struct.calcsize('P') < 8: - PCG_EMULATED_MATH = True - -files = glob.glob('./randomgen/*.in') -for templated_file in files: - output_file_name = os.path.splitext(templated_file)[0] - if (os.path.exists(output_file_name) and - (os.path.getmtime(templated_file) < os.path.getmtime(output_file_name))): - continue - with open(templated_file, 'r') as source_file: - template = tempita.Template(source_file.read()) - with open(output_file_name, 'w') as output_file: - output_file.write(template.substitute()) - - -extensions = [Extension('randomgen.entropy', - sources=[join(MOD_DIR, 'entropy.pyx'), - join(MOD_DIR, 'src', 'entropy', 'entropy.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join(MOD_DIR, 'src', - 'entropy')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.dsfmt", - ["randomgen/dsfmt.pyx", - join(MOD_DIR, 'src', 'dsfmt', 'dSFMT.c'), - join(MOD_DIR, 'src', 'dsfmt', 'dSFMT-jump.c'), - join(MOD_DIR, 'src', 'aligned_malloc', 'aligned_malloc.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join(MOD_DIR, 'src', - 'dsfmt')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - define_macros=DSFMT_DEFS, - ), - Extension("randomgen.mt19937", - ["randomgen/mt19937.pyx", - join(MOD_DIR, 'src', 'mt19937', 'mt19937.c'), - join(MOD_DIR, 'src', 'mt19937', 'mt19937-jump.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join(MOD_DIR, 'src', - 'mt19937')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.philox", - ["randomgen/philox.pyx", - join(MOD_DIR, 'src', 'philox', 'philox.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join(MOD_DIR, 'src', - 'philox')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.pcg64", - ["randomgen/pcg64.pyx", - join(MOD_DIR, 'src', 'pcg64', 'pcg64.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join(MOD_DIR, 'src', - 'pcg64')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - define_macros=PCG64_DEFS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.pcg32", - ["randomgen/pcg32.pyx", - join(MOD_DIR, 'src', 'pcg32', 'pcg32.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join(MOD_DIR, 'src', - 'pcg32')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.threefry", - ["randomgen/threefry.pyx", - join(MOD_DIR, 'src', 'threefry', 'threefry.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join(MOD_DIR, 'src', - 'threefry')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.threefry32", - ["randomgen/threefry32.pyx", - join(MOD_DIR, 'src', 'threefry32', 'threefry32.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join(MOD_DIR, 'src', - 'threefry32')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.xoroshiro128", - ["randomgen/xoroshiro128.pyx", - join(MOD_DIR, 'src', 'xoroshiro128', - 'xoroshiro128.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join( - MOD_DIR, 'src', - 'xoroshiro128')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.xorshift1024", - ["randomgen/xorshift1024.pyx", - join(MOD_DIR, 'src', 'xorshift1024', - 'xorshift1024.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join(MOD_DIR, 'src', - 'xorshift1024')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.xoshiro256starstar", - ["randomgen/xoshiro256starstar.pyx", - join(MOD_DIR, 'src', 'xoshiro256starstar', - 'xoshiro256starstar.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join( - MOD_DIR, 'src', - 'xoshiro256starstar')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.xoshiro512starstar", - ["randomgen/xoshiro512starstar.pyx", - join(MOD_DIR, 'src', 'xoshiro512starstar', - 'xoshiro512starstar.c')], - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include(), - join( - MOD_DIR, 'src', - 'xoshiro512starstar')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.generator", - ["randomgen/generator.pyx", - join(MOD_DIR, 'src', 'distributions', - 'distributions.c')], - libraries=EXTRA_LIBRARIES, - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.common", - ["randomgen/common.pyx"], - libraries=EXTRA_LIBRARIES, - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.bounded_integers", - ["randomgen/bounded_integers.pyx", - join(MOD_DIR, 'src', 'distributions', - 'distributions.c')], - libraries=EXTRA_LIBRARIES, - include_dirs=EXTRA_INCLUDE_DIRS + [np.get_include()], - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - Extension("randomgen.legacy._legacy", - ["randomgen/legacy/_legacy.pyx", - join(MOD_DIR, 'src', 'legacy', - 'distributions-boxmuller.c'), - join(MOD_DIR, 'src', 'distributions', 'distributions.c')], - libraries=EXTRA_LIBRARIES, - include_dirs=EXTRA_INCLUDE_DIRS + - [np.get_include()] + [join(MOD_DIR, 'legacy')], - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS - ), - ] - - -classifiers = ['Development Status :: 5 - Production/Stable', - 'Environment :: Console', - 'Intended Audience :: End Users/Desktop', - 'Intended Audience :: Financial and Insurance Industry', - 'Intended Audience :: Information Technology', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: POSIX :: Linux', - 'Operating System :: Unix', - 'Programming Language :: C', - 'Programming Language :: Cython', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Topic :: Adaptive Technologies', - 'Topic :: Artistic Software', - 'Topic :: Office/Business :: Financial', - 'Topic :: Scientific/Engineering', - 'Topic :: Security :: Cryptography'] - - -class BinaryDistribution(Distribution): - def is_pure(self): - return False - - -setup( - name='randomgen', - version=versioneer.get_version(), - classifiers=classifiers, - cmdclass=versioneer.get_cmdclass(), - ext_modules=cythonize(extensions, - compile_time_env={"PCG_EMULATED_MATH": PCG_EMULATED_MATH}, - compiler_directives={'language_level': '3'}), - packages=find_packages(), - package_dir={'randomgen': './randomgen'}, - package_data={'': ['*.h', '*.pxi', '*.pyx', '*.pxd', '*.in'], - 'randomgen.tests.data': ['*.csv']}, - include_package_data=True, - license='NSCA', - author='Kevin Sheppard', - author_email='kevin.k.sheppard@gmail.com', - distclass=BinaryDistribution, - long_description=open('README.rst').read(), - description='Random generator supporting multiple PRNGs', - url='https://github.com/bashtage/randomgen', - keywords=['pseudo random numbers', 'PRNG', 'RNG', 'RandomState', 'random', - 'random numbers', 'parallel random numbers', 'PCG', - 'XorShift', 'dSFMT', 'MT19937', 'Random123', 'ThreeFry', - 'Philox'], - zip_safe=False, - install_requires=required -) From 0b62364145d71c7704b64c70156d52fa63200ce8 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Mon, 8 Apr 2019 22:30:07 +0200 Subject: [PATCH 273/279] Add benchmark for sorting random array. --- benchmarks/benchmarks/bench_function_base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmarks/benchmarks/bench_function_base.py b/benchmarks/benchmarks/bench_function_base.py index 07ada2bbb26b..7ea8c39b0222 100644 --- a/benchmarks/benchmarks/bench_function_base.py +++ b/benchmarks/benchmarks/bench_function_base.py @@ -199,6 +199,7 @@ class Sort(Benchmark): ['quick', 'merge', 'heap'], ['float64', 'int64', 'uint64'], [ + ('random',), ('ordered',), ('reversed',), ('uniform',), From ad1528197400592fb3444143bd7d112ec6de0239 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 10 Apr 2019 07:44:02 +0300 Subject: [PATCH 274/279] MAINT: fix merge from master --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e7fbf55fe6a9..ff26afeb8a89 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,7 +20,7 @@ jobs: command: | python3 -m venv venv . venv/bin/activate - pip install cython sphinx>=1.8.5 matplotlib ipython + pip install cython sphinx==1.8.5 matplotlib ipython sudo apt-get update sudo apt-get install -y graphviz texlive-fonts-recommended texlive-latex-recommended texlive-latex-extra texlive-generic-extra latexmk texlive-xetex From a8027f727ef3a60ca82934d00faafe2651afb0b3 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 10 Apr 2019 11:49:08 +0300 Subject: [PATCH 275/279] DOC: rework randomgen docs to integrate with numpy and fix some links --- doc/source/reference/randomgen/extending.rst | 2 + doc/source/reference/randomgen/generator.rst | 22 ++-- doc/source/reference/randomgen/index.rst | 120 +++++++++---------- numpy/random/randomgen/generator.pyx | 2 +- 4 files changed, 72 insertions(+), 74 deletions(-) diff --git a/doc/source/reference/randomgen/extending.rst b/doc/source/reference/randomgen/extending.rst index c9d987b59ece..64f2ddcc16ce 100644 --- a/doc/source/reference/randomgen/extending.rst +++ b/doc/source/reference/randomgen/extending.rst @@ -59,6 +59,8 @@ directly in Numba after compiling the file distributions.c into a DLL or so. An example showing the use of a more complicated distribution is in the examples folder. +.. _randomgen_cython: + Cython ====== diff --git a/doc/source/reference/randomgen/generator.rst b/doc/source/reference/randomgen/generator.rst index d59efd68c802..59ae03d0678d 100644 --- a/doc/source/reference/randomgen/generator.rst +++ b/doc/source/reference/randomgen/generator.rst @@ -1,18 +1,16 @@ +.. currentmodule:: numpy.random.randomgen + Random Generator ---------------- -The :class:`~randomgen.generator.RandomGenerator` provides access to -a wide range of distributions, and served as a replacement for -:class:`~numpy.random.RandomState`. The main difference between -the two is that :class:`~randomgen.generator.RandomGenerator` relies -on an additional basic RNG to manage state and generate the random -bits which are then transformed into random values from useful -distributions. The default basic RNG used by -:class:`~randomgen.generator.RandomGenerator` is -:class:`~randomgen.xoroshiro128.Xoroshiro128`. The basic RNG can be -changed by passing an instantized basic RNG to -:class:`~randomgen.generator.RandomGenerator`. +The :class:`~RandomGenerator` provides access to +a wide range of distributions, and served as a replacement for +:class:`~numpy.random.RandomState`. The main difference between +the two is that ``RandomGenerator`` relies on an additional basic RNG to +manage state and generate the random bits, which are then transformed into +random values from useful distributions. The default basic RNG used by +``RandomGenerator`` is :class:`~xoroshiro128.Xoroshiro128`. The basic RNG can be +changed by passing an instantized basic RNG to ``RandomGenerator``. -.. currentmodule:: numpy.random.randomgen.generator .. autoclass:: RandomGenerator :exclude-members: diff --git a/doc/source/reference/randomgen/index.rst b/doc/source/reference/randomgen/index.rst index 67d0441a2de4..a8b6f1c9b3ff 100644 --- a/doc/source/reference/randomgen/index.rst +++ b/doc/source/reference/randomgen/index.rst @@ -1,17 +1,21 @@ -Randomgen.RandomGen -=================== -This package contains replacements for the NumPy -:class:`~numpy.random.RandomState` object that allows the core random number -generator be be changed. - .. current_module numpy.random.randomgen +numpy.random.randomgen +====================== + +This package modernizes the legacy +`~numpy.random.RandomState` object and allows changing the core random +number generator (RNG). The `~numpy.random.randomgen.RandomGenerator` can +be initialized with a number of different RNGs, and exposes many different +probability distributions. + + Quick Start ----------- -Like :mod:`numpy.random`, RandomGen can be used at the module level. -This uses the default :class:`~randomgen.generator.RandomGenerator` which -uses normals provided by :class:`~randomgen.xoroshiro128.Xoroshiro128`. +By default, `generator.RandomGenerator` uses normals provided by +`xoroshiro128.Xoroshiro128` which will be faster than the legacy methods in +`numpy.random` .. code-block:: python @@ -19,12 +23,11 @@ uses normals provided by :class:`~randomgen.xoroshiro128.Xoroshiro128`. import randomgen.generator as random random.standard_normal() -:class:`~randomgen.generator.RandomGenerator` can also be used as a -replacement for :class:`~numpy.random.RandomState`, although the random -values are generated by :class:`~randomgen.xoroshiro128.Xoroshiro128`. It -also isn't possible to directly seed a -:class:`~randomgen.generator.RandomGenerator`. - +`numpy.random.randomgen.RandomGenerator` can also be used as a replacement for +`~numpy.random.RandomState`, although the random values are generated by +`~numpyrandom.randomgen.xoroshiro128.Xoroshiro128`. Since ``randomgen`` +separates the `~numpy.random.randomgen.RandomGenerator` from the RNG, it is not +possible to directly seed the generator. .. code-block:: python @@ -34,9 +37,9 @@ also isn't possible to directly seed a rg.standard_normal() -Seeds can be passed to any of the basic RNGs. Here :class:`~randomgen.mt19937.MT19937` -is used and the :class:`~randomgen.generator.RandomGenerator` is accessed via -the property :attr:`~randomgen.mt19937.MT19937.generator`. +Seeds can be passed to any of the basic RNGs. Here `numpy.random.randomgen. +mt19937.MT19937` is used and the `~numpy.random.randomgen.RandomGenerator` is +accessed via the attribute `~numpy.random.randomgen.mt19937.MT19937.generator`. .. code-block:: python @@ -48,24 +51,23 @@ the property :attr:`~randomgen.mt19937.MT19937.generator`. Introduction ------------ RandomGen takes a different approach to producing random numbers from the -:class:`numpy.random.RandomState` object used in NumPy. Random number -generation is separated into two components, a basic RNG and a random -generator. +:class:`numpy.random.RandomState` object. Random number generation is +separated into two components, a basic RNG and a random generator. -The basic RNG has a limited set of responsibilities -- it manages the +The basic RNG has a limited set of responsibilities. It manages the underlying RNG state and provides functions to produce random doubles and random unsigned 32- and 64-bit values. The basic random generator also handles all seeding since this varies when using alternative basic RNGs. -The random generator (:class:`~randomgen.generator.RandomGenerator`) takes the +The `random generator <~numpy.random.randomgen.RandomGenerator>` takes the basic RNG-provided functions and transforms them into more useful distributions, e.g., simulated normal random values. This structure allows alternative basic RNGs to be used without code duplication. -The :class:`~randomgen.generator.RandomGenerator` is the user-facing object +The `~numpy.random.randomgen.RandomGenerator` is the user-facing object that is nearly identical to :class:`~numpy.random.RandomState`. The canonical -method to initialize a generator passes a basic RNG -- -:class:`~randomgen.mt19937.MT19937`, the underlying RNG in NumPy -- as the +method to initialize a generator passes a basic RNG -- `~numpy.random. +randomgen.mt19937.MT19937`, the underlying RNG in NumPy -- as the sole argument. Note that the basic RNG must be instantized. .. code-block:: python @@ -81,9 +83,9 @@ Seed information is directly passed to the basic RNG. rg = RandomGenerator(MT19937(12345)) rg.random_sample() -A shorthand method is also available which uses the -:meth:`~randomgen.mt19937.MT19937.generator` property from a basic RNG to -access an embedded random generator. +A shorthand method is also available which uses the `~numpy.random.randomgen. +mt19937.MT19937.generator` property from a basic RNG to access an embedded +random generator. .. code-block:: python @@ -95,13 +97,14 @@ What's New or Different .. warning:: The Box-Muller method used to produce NumPy's normals is no longer available - in :class:`~randomgen.generator.RandomGenerator`. It is not possible to - reproduce the random values using :class:`~randomgen.generator.RandomGenerator` - for the normal distribution or any other distribution that relies on the - normal such as the gamma or student's t. If you require backward compatibility, a - legacy generator, :class:`~randomgen.legacy.LegacyGenerator`, has been created - which can fully reproduce the sequence produced by NumPy. - + in `~numpy.random.randomgen.RandomGenerator`. It is not possible to + reproduce the random values using `~numpy.random.randomgen.RandomGenerator` + for the normal distribution or any other distribution that + relies on the normal such as the gamma or student's t. If you require + backward compatibility, a legacy generator, `~numpy.random.randomgen.legacy. + LegacyGenerator`, has been created which can fully reproduce the sequence + produced by NumPy. + * The normal, exponential and gamma generators use 256-step Ziggurat methods which are 2-10 times faster than NumPy's Box-Muller or inverse CDF implementations. @@ -110,20 +113,18 @@ What's New or Different select distributions * Optional ``out`` argument that allows existing arrays to be filled for select distributions -* Simulate from the complex normal distribution - (:meth:`~randomgen.generator.RandomGenerator.complex_normal`) -* :func:`~randomgen.entropy.random_entropy` provides access to the system +* `~numpy.random.randomgen.entropy.random_entropy` provides access to the system source of randomness that is used in cryptographic applications (e.g., ``/dev/urandom`` on Unix). -* All basic random generators functions to produce doubles, uint64s and - uint32s via CTypes (:meth:`~randomgen.xoroshiro128.Xoroshiro128.ctypes`) - and CFFI (:meth:`~randomgen.xoroshiro128.Xoroshiro128.cffi`). This allows - these basic RNGs to be used in numba. +* All basic random generators functions can produce doubles, uint64s and + uint32s via CTypes (`~numpy.random.randomgen.xoroshiro128.Xoroshiro128.ctypes`) + and CFFI (:meth:`~numpy.random.randomgen.xoroshiro128.Xoroshiro128.cffi`). + This allows these basic RNGs to be used in numba. * The basic random number generators can be used in downstream projects via - Cython. + :ref:`Cython `. * Support for Lemire’s method [Lemire]_ of generating uniform integers on an arbitrary interval by setting ``use_masked=True`` in - (:meth:`~randomgen.generator.RandomGenerator.randint`). + `~umpy.random.randomgen.generator.RandomGenerator.randint`. See :ref:`new-or-different` for a complete list of improvements and @@ -144,9 +145,9 @@ The main innovation is the inclusion of a number of alternative pseudo-random nu generators, 'in addition' to the standard PRNG in NumPy. The included PRNGs are: * MT19937 - The standard NumPy generator. Produces identical results to NumPy - using the same seed/state. Adds a jump function that advances the generator - as-if 2**128 draws have been made (:meth:`~randomgen.mt19937.MT19937.jump`). - See `NumPy's documentation`_. + using the same seed/state. Adds a + `~numpy.random.randomgen.mt19937.MT19937.jump` function that advances the + generator as-if ``2**128`` draws have been made. See `numpy.random`. * dSFMT - SSE2 enabled versions of the MT19937 generator. Theoretically the same, but with a different state and so it is not possible to produce a sequence identical to MT19937. Supports ``jump`` and so can @@ -154,31 +155,30 @@ generators, 'in addition' to the standard PRNG in NumPy. The included PRNGs are * XoroShiro128+ - Improved version of XorShift128+ with better performance and statistical quality. Like the XorShift generators, it can be jumped to produce multiple streams in parallel applications. See - :meth:`~randomgen.xoroshiro128.Xoroshiro128.jump` for details. + `~numpy.random.randomgen.xoroshiro128.Xoroshiro128.jump` for details. More information about this PRNG is available at the `xorshift, xoroshiro and xoshiro authors' page`_. * XorShift1024*φ - Fast fast generator based on the XSadd generator. Supports ``jump`` and so can be used in parallel applications. See the documentation for - :meth:`~randomgen.xorshift1024.Xorshift1024.jump` for details. More information - about these PRNGs is available at the + `~numpy.random.randomgen.xorshift1024.Xorshift1024.jump` for details. More + information about these PRNGs is available at the `xorshift, xoroshiro and xoshiro authors' page`_. * Xorshiro256** and Xorshiro512** - The most recently introduced XOR, shift, and rotate generator. Supports ``jump`` and so can be used in parallel applications. See the documentation for - :meth:`~randomgen.xoshiro256starstar.Xoshirt256StarStar.jump` for details. More - information about these PRNGs is available at the + `~numpy.random.randomgen.xoshiro256starstar.Xoshirt256StarStar.jump` for + details. More information about these PRNGs is available at the `xorshift, xoroshiro and xoshiro authors' page`_. * PCG-64 - Fast generator that support many parallel streams and can be advanced by an arbitrary amount. See the documentation for - :meth:`~randomgen.pcg64.PCG64.advance`. PCG-64 has a period of + `~numpy.random.randomgen.pcg64.PCG64.advance`. PCG-64 has a period of :math:`2^{128}`. See the `PCG author's page`_ for more details about this class of PRNG. * ThreeFry and Philox - counter-based generators capable of being advanced an arbitrary number of steps or generating independent streams. See the `Random123`_ page for more details about this class of PRNG. -.. _`NumPy's documentation`: https://docs.scipy.org/doc/numpy/reference/routines.random.html .. _`dSFMT authors' page`: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/ .. _`xorshift, xoroshiro and xoshiro authors' page`: http://xoroshiro.di.unimi.it/ .. _`PCG author's page`: http://www.pcg-random.org/ @@ -215,14 +215,12 @@ New Features Changes ~~~~~~~ + +This package was developed independently of NumPy and was integrated in version +1.17.0. The original repo is at https://github.com/bashtage/randomgen. + .. toctree:: :maxdepth: 2 Change Log -Indices and tables -~~~~~~~~~~~~~~~~~~ - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index a244bca578d3..ab68d0165dfe 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -49,7 +49,7 @@ cdef class RandomGenerator: Notes ----- - The Python stdlib module "random" contains pseudo-random number generator + The Python stdlib module `random` contains pseudo-random number generator with a number of methods that are similar to the ones available in ``RandomGenerator``. It uses Mersenne Twister, and this basic RNG can be accessed using ``MT19937``. ``RandomGenerator``, besides being From 95ee88f1916dc54341392d06980e0b02e3471561 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 11 Apr 2019 10:35:54 +0300 Subject: [PATCH 276/279] ENH: remove convenience functions, require explicit call to gen.brng --- doc/source/reference/randomgen/generator.rst | 7 +- .../reference/randomgen/new-or-different.rst | 4 +- numpy/random/randomgen/generator.pyx | 72 +----- .../randomgen/tests/test_against_numpy.py | 21 +- numpy/random/randomgen/tests/test_direct.py | 104 ++++---- .../randomgen/tests/test_generator_mt19937.py | 167 ++++++------- .../test_generator_mt19937_regressions.py | 24 +- numpy/random/randomgen/tests/test_smoke.py | 226 +++++++++--------- 8 files changed, 285 insertions(+), 340 deletions(-) diff --git a/doc/source/reference/randomgen/generator.rst b/doc/source/reference/randomgen/generator.rst index 59ae03d0678d..54325f4d37ee 100644 --- a/doc/source/reference/randomgen/generator.rst +++ b/doc/source/reference/randomgen/generator.rst @@ -15,13 +15,12 @@ changed by passing an instantized basic RNG to ``RandomGenerator``. .. autoclass:: RandomGenerator :exclude-members: -Seed and State Manipulation -=========================== +Accessing the RNG +================= .. autosummary:: :toctree: generated/ - ~RandomGenerator.seed - ~RandomGenerator.state + ~RandomGenerator.brng Simple random data ================== diff --git a/doc/source/reference/randomgen/new-or-different.rst b/doc/source/reference/randomgen/new-or-different.rst index 0a27b9aa158c..089efd6fb880 100644 --- a/doc/source/reference/randomgen/new-or-different.rst +++ b/doc/source/reference/randomgen/new-or-different.rst @@ -64,9 +64,9 @@ What's New or Different .. ipython:: python - rg.seed(0) + rg.brng.seed(0) rg.random_sample(3, dtype='d') - rg.seed(0) + rg.brng.seed(0) rg.random_sample(3, dtype='f') * Optional ``out`` argument that allows existing arrays to be filled for diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/randomgen/generator.pyx index ab68d0165dfe..e68edb98ab15 100644 --- a/numpy/random/randomgen/generator.pyx +++ b/numpy/random/randomgen/generator.pyx @@ -72,7 +72,7 @@ cdef class RandomGenerator: >>> rg = MT19937().generator >>> rg.standard_normal() """ - cdef public object _basicrng + cdef public object brng cdef brng_t *_brng cdef binomial_t *_binomial cdef object lock @@ -81,7 +81,7 @@ cdef class RandomGenerator: def __init__(self, brng=None): if brng is None: brng = Xoroshiro128() - self._basicrng = brng + self.brng = brng capsule = brng.capsule cdef const char *name = "BasicRNG" @@ -99,79 +99,21 @@ cdef class RandomGenerator: def __str__(self): _str = self.__class__.__name__ - _str += '(' + self._basicrng.__class__.__name__ + ')' + _str += '(' + self.brng.__class__.__name__ + ')' return _str # Pickling support: def __getstate__(self): - return self.state + return self.brng.state def __setstate__(self, state): - self.state = state + self.brng.state = state def __reduce__(self): from ._pickle import __generator_ctor return (__generator_ctor, - (self.state['brng'],), - self.state) - - def seed(self, *args, **kwargs): - """ - Reseed the basic RNG. - - Parameters depend on the basic RNG used. - - Notes - ----- - Arguments are directly passed to the basic RNG. This is a convenience - function. - - The best method to access seed is to directly use a basic RNG instance. - This example demonstrates this best practice. - - >>> from numpy.random.randomgen import RandomGenerator, PCG64 - >>> brng = PCG64(1234567891011) - >>> rg = brng.generator - >>> brng.seed(1110987654321) - - The method used to create the generator is not important. - - >>> brng = PCG64(1234567891011) - >>> rg = RandomGenerator(brng) - >>> brng.seed(1110987654321) - - These best practice examples are equivalent to - - >>> rg = RandomGenerator(PCG64(1234567891011)) - >>> rg.seed(1110987654321) - - """ - # TODO: Should this remain - self._basicrng.seed(*args, **kwargs) - return self - - @property - def state(self): - """ - Get or set the Basic RNG's state - - Returns - ------- - state : dict - Dictionary containing the information required to describe the - state of the Basic RNG - - Notes - ----- - This is a trivial pass-through function. RandomGenerator does not - directly contain or manipulate the basic RNG's state. - - """ - return self._basicrng.state - - @state.setter - def state(self, value): - self._basicrng.state = value + (self.brng.state['brng'],), + self.brng.state) def random_sample(self, size=None, dtype=np.float64, out=None): """ diff --git a/numpy/random/randomgen/tests/test_against_numpy.py b/numpy/random/randomgen/tests/test_against_numpy.py index 431c7bd85d24..70decfae7788 100644 --- a/numpy/random/randomgen/tests/test_against_numpy.py +++ b/numpy/random/randomgen/tests/test_against_numpy.py @@ -98,12 +98,12 @@ def setup_class(cls): cls.rg = RandomGenerator(cls.brng(*cls.seed)) cls.rs = RandomState(cls.brng(*cls.seed)) cls.nprs = cls.np.RandomState(*cls.seed) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls._set_common_state() @classmethod def _set_common_state(cls): - state = cls.rg.state + state = cls.rg.brng.state st = [[]] * 5 st[0] = 'MT19937' st[1] = state['state']['key'] @@ -125,7 +125,7 @@ def _set_common_state_legacy(cls): def _is_state_common(self): state = self.nprs.get_state() - state2 = self.rg.state + state2 = self.rg.brng.state assert (state[1] == state2['state']['key']).all() assert (state[2] == state2['state']['pos']) @@ -138,10 +138,10 @@ def _is_state_common_legacy(self): assert_allclose(state[4], state2['gauss'], atol=1e-10) def test_common_seed(self): - self.rg.seed(1234) + self.rg.brng.seed(1234) self.nprs.seed(1234) self._is_state_common() - self.rg.seed(23456) + self.rg.brng.seed(23456) self.nprs.seed(23456) self._is_state_common() @@ -149,8 +149,8 @@ def test_numpy_state(self): nprs = np.random.RandomState() nprs.standard_normal(99) state = nprs.get_state() - self.rg.state = state - state2 = self.rg.state + self.rg.brng.state = state + state2 = self.rg.brng.state assert (state[1] == state2['state']['key']).all() assert (state[2] == state2['state']['pos']) @@ -383,7 +383,7 @@ def test_scalar(self): assert_equal(s1.randint(1000), 419) assert_equal(s1.randint(1000), s.randint(1000)) - self.rg.seed(4294967295) + self.rg.brng.seed(4294967295) self.nprs.seed(4294967295) self._is_state_common() @@ -403,9 +403,10 @@ def test_array(self): def test_dir(self): nprs_d = set(dir(self.nprs)) rs_d = dir(self.rg) - excluded = {'get_state', 'set_state'} + excluded = {'get_state', 'set_state', '_basicrng', 'seed', '__getstate__'} nprs_d.difference_update(excluded) - assert (len(nprs_d.difference(rs_d)) == 0) + d = nprs_d.difference(rs_d) + assert (len(d) == 0) npmod = dir(numpy.random) mod = dir(generator) diff --git a/numpy/random/randomgen/tests/test_direct.py b/numpy/random/randomgen/tests/test_direct.py index 22fdcd865944..ec7a795d39c4 100644 --- a/numpy/random/randomgen/tests/test_direct.py +++ b/numpy/random/randomgen/tests/test_direct.py @@ -206,30 +206,30 @@ def test_uniform_float(self): def test_seed_float(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(self.seed_error_type, rs.seed, np.pi) - assert_raises(self.seed_error_type, rs.seed, -np.pi) + assert_raises(self.seed_error_type, rs.brng.seed, np.pi) + assert_raises(self.seed_error_type, rs.brng.seed, -np.pi) def test_seed_float_array(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(self.seed_error_type, rs.seed, np.array([np.pi])) - assert_raises(self.seed_error_type, rs.seed, np.array([-np.pi])) - assert_raises(ValueError, rs.seed, np.array([np.pi, -np.pi])) - assert_raises(TypeError, rs.seed, np.array([0, np.pi])) - assert_raises(TypeError, rs.seed, [np.pi]) - assert_raises(TypeError, rs.seed, [0, np.pi]) + assert_raises(self.seed_error_type, rs.brng.seed, np.array([np.pi])) + assert_raises(self.seed_error_type, rs.brng.seed, np.array([-np.pi])) + assert_raises(ValueError, rs.brng.seed, np.array([np.pi, -np.pi])) + assert_raises(TypeError, rs.brng.seed, np.array([0, np.pi])) + assert_raises(TypeError, rs.brng.seed, [np.pi]) + assert_raises(TypeError, rs.brng.seed, [0, np.pi]) def test_seed_out_of_range(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(ValueError, rs.seed, 2 ** (2 * self.bits + 1)) - assert_raises(ValueError, rs.seed, -1) + assert_raises(ValueError, rs.brng.seed, 2 ** (2 * self.bits + 1)) + assert_raises(ValueError, rs.brng.seed, -1) def test_seed_out_of_range_array(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(ValueError, rs.seed, [2 ** (2 * self.bits + 1)]) - assert_raises(ValueError, rs.seed, [-1]) + assert_raises(ValueError, rs.brng.seed, [2 ** (2 * self.bits + 1)]) + assert_raises(ValueError, rs.brng.seed, [-1]) def test_repr(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) @@ -412,18 +412,18 @@ def setup_class(cls): def test_seed_float_array(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(self.seed_error_type, rs.seed, np.array([np.pi])) - assert_raises(self.seed_error_type, rs.seed, np.array([-np.pi])) - assert_raises(self.seed_error_type, rs.seed, np.array([np.pi, -np.pi])) - assert_raises(self.seed_error_type, rs.seed, np.array([0, np.pi])) - assert_raises(self.seed_error_type, rs.seed, [np.pi]) - assert_raises(self.seed_error_type, rs.seed, [0, np.pi]) + assert_raises(self.seed_error_type, rs.brng.seed, np.array([np.pi])) + assert_raises(self.seed_error_type, rs.brng.seed, np.array([-np.pi])) + assert_raises(self.seed_error_type, rs.brng.seed, np.array([np.pi, -np.pi])) + assert_raises(self.seed_error_type, rs.brng.seed, np.array([0, np.pi])) + assert_raises(self.seed_error_type, rs.brng.seed, [np.pi]) + assert_raises(self.seed_error_type, rs.brng.seed, [0, np.pi]) def test_seed_out_of_range_array(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(self.seed_error_type, rs.seed, + assert_raises(self.seed_error_type, rs.brng.seed, [2 ** (2 * self.bits + 1)]) - assert_raises(self.seed_error_type, rs.seed, [-1]) + assert_raises(self.seed_error_type, rs.brng.seed, [-1]) class TestPhilox(Base): @@ -464,43 +464,45 @@ def setup_class(cls): def test_seed_out_of_range(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(ValueError, rs.seed, 2 ** (self.bits + 1)) - assert_raises(ValueError, rs.seed, -1) - assert_raises(ValueError, rs.seed, 2 ** (2 * self.bits + 1)) + assert_raises(ValueError, rs.brng.seed, 2 ** (self.bits + 1)) + assert_raises(ValueError, rs.brng.seed, -1) + assert_raises(ValueError, rs.brng.seed, 2 ** (2 * self.bits + 1)) def test_seed_out_of_range_array(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(ValueError, rs.seed, [2 ** (self.bits + 1)]) - assert_raises(ValueError, rs.seed, [-1]) - assert_raises(TypeError, rs.seed, [2 ** (2 * self.bits + 1)]) + assert_raises(ValueError, rs.brng.seed, [2 ** (self.bits + 1)]) + assert_raises(ValueError, rs.brng.seed, [-1]) + assert_raises(TypeError, rs.brng.seed, [2 ** (2 * self.bits + 1)]) def test_seed_float(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(TypeError, rs.seed, np.pi) - assert_raises(TypeError, rs.seed, -np.pi) + assert_raises(TypeError, rs.brng.seed, np.pi) + assert_raises(TypeError, rs.brng.seed, -np.pi) def test_seed_float_array(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(TypeError, rs.seed, np.array([np.pi])) - assert_raises(TypeError, rs.seed, np.array([-np.pi])) - assert_raises(TypeError, rs.seed, np.array([np.pi, -np.pi])) - assert_raises(TypeError, rs.seed, np.array([0, np.pi])) - assert_raises(TypeError, rs.seed, [np.pi]) - assert_raises(TypeError, rs.seed, [0, np.pi]) + brng = rs.brng + assert_raises(TypeError, brng.seed, np.array([np.pi])) + assert_raises(TypeError, brng.seed, np.array([-np.pi])) + assert_raises(TypeError, brng.seed, np.array([np.pi, -np.pi])) + assert_raises(TypeError, brng.seed, np.array([0, np.pi])) + assert_raises(TypeError, brng.seed, [np.pi]) + assert_raises(TypeError, brng.seed, [0, np.pi]) def test_state_tuple(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) - state = rs.state + brng = rs.brng + state = brng.state desired = rs.randint(2 ** 16) tup = (state['brng'], state['state']['key'], state['state']['pos']) - rs.state = tup + brng.state = tup actual = rs.randint(2 ** 16) assert_equal(actual, desired) tup = tup + (0, 0.0) - rs.state = tup + brng.state = tup actual = rs.randint(2 ** 16) assert_equal(actual, desired) @@ -542,25 +544,25 @@ def test_gauss_inv(self): def test_seed_out_of_range_array(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(ValueError, rs.seed, [2 ** (self.bits + 1)]) - assert_raises(ValueError, rs.seed, [-1]) - assert_raises(TypeError, rs.seed, [2 ** (2 * self.bits + 1)]) + assert_raises(ValueError, rs.brng.seed, [2 ** (self.bits + 1)]) + assert_raises(ValueError, rs.brng.seed, [-1]) + assert_raises(TypeError, rs.brng.seed, [2 ** (2 * self.bits + 1)]) def test_seed_float(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(TypeError, rs.seed, np.pi) - assert_raises(TypeError, rs.seed, -np.pi) + assert_raises(TypeError, rs.brng.seed, np.pi) + assert_raises(TypeError, rs.brng.seed, -np.pi) def test_seed_float_array(self): # GH #82 rs = RandomGenerator(self.brng(*self.data1['seed'])) - assert_raises(TypeError, rs.seed, np.array([np.pi])) - assert_raises(TypeError, rs.seed, np.array([-np.pi])) - assert_raises(TypeError, rs.seed, np.array([np.pi, -np.pi])) - assert_raises(TypeError, rs.seed, np.array([0, np.pi])) - assert_raises(TypeError, rs.seed, [np.pi]) - assert_raises(TypeError, rs.seed, [0, np.pi]) + assert_raises(TypeError, rs.brng.seed, np.array([np.pi])) + assert_raises(TypeError, rs.brng.seed, np.array([-np.pi])) + assert_raises(TypeError, rs.brng.seed, np.array([np.pi, -np.pi])) + assert_raises(TypeError, rs.brng.seed, np.array([0, np.pi])) + assert_raises(TypeError, rs.brng.seed, [np.pi]) + assert_raises(TypeError, rs.brng.seed, [0, np.pi]) def test_uniform_float(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) @@ -578,9 +580,9 @@ def test_uniform_float(self): def test_buffer_reset(self): rs = RandomGenerator(self.brng(*self.data1['seed'])) rs.random_sample(1) - assert rs.state['buffer_loc'] != 382 - rs.seed(*self.data1['seed']) - assert rs.state['buffer_loc'] == 382 + assert rs.brng.state['buffer_loc'] != 382 + rs.brng.seed(*self.data1['seed']) + assert rs.brng.state['buffer_loc'] == 382 class TestThreeFry32(Base): diff --git a/numpy/random/randomgen/tests/test_generator_mt19937.py b/numpy/random/randomgen/tests/test_generator_mt19937.py index 10dd8733a8b9..4ab20d73c071 100644 --- a/numpy/random/randomgen/tests/test_generator_mt19937.py +++ b/numpy/random/randomgen/tests/test_generator_mt19937.py @@ -96,21 +96,22 @@ class TestSetState(object): def setup(self): self.seed = 1234567890 self.rg = RandomGenerator(MT19937(self.seed)) - self.state = self.rg.state + self.brng = self.rg.brng + self.state = self.brng.state self.legacy_state = (self.state['brng'], self.state['state']['key'], self.state['state']['pos']) def test_basic(self): old = self.rg.tomaxint(16) - self.rg.state = self.state + self.brng.state = self.state new = self.rg.tomaxint(16) assert_(np.all(old == new)) def test_gaussian_reset(self): # Make sure the cached every-other-Gaussian is reset. old = self.rg.standard_normal(size=3) - self.rg.state = self.state + self.brng.state = self.state new = self.rg.standard_normal(size=3) assert_(np.all(old == new)) @@ -119,9 +120,9 @@ def test_gaussian_reset_in_media_res(self): # cached Gaussian is restored. self.rg.standard_normal() - state = self.rg.state + state = self.brng.state old = self.rg.standard_normal(size=3) - self.rg.state = state + self.brng.state = state new = self.rg.standard_normal(size=3) assert_(np.all(old == new)) @@ -244,7 +245,7 @@ def test_full_range_array(self): def test_in_bounds_fuzz(self): # Don't use fixed seed - random.seed() + random.brng.seed() for dt in self.itype[1:]: for ubnd in [4, 8, 16]: @@ -263,13 +264,13 @@ def test_scalar_array_equiv(self): ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 size = 1000 - random.seed(1234) + random.brng.seed(1234) scalar = self.rfunc(lbnd, ubnd, size=size, dtype=dt) - random.seed(1234) + random.brng.seed(1234) scalar_array = self.rfunc([lbnd], [ubnd], size=size, dtype=dt) - random.seed(1234) + random.brng.seed(1234) array = self.rfunc([lbnd] * size, [ubnd] * size, size=size, dtype=dt) assert_array_equal(scalar, scalar_array) @@ -291,7 +292,7 @@ def test_repeatability(self): 'uint8': '27dd30c4e08a797063dffac2490b0be6'} for dt in self.itype[1:]: - random.seed(1234) + random.brng.seed(1234) # view as little endian for hash if sys.byteorder == 'little': @@ -303,7 +304,7 @@ def test_repeatability(self): assert_(tgt[np.dtype(dt).name] == res) # bools do not depend on endianness - random.seed(1234) + random.brng.seed(1234) val = self.rfunc(0, 2, size=1000, dtype=bool).view(np.int8) res = hashlib.md5(val).hexdigest() assert_(tgt[np.dtype(bool).name] == res) @@ -316,15 +317,15 @@ def test_repeatability_broadcasting(self): np.bool, bool, np.bool_) else np.iinfo(dt).max + 1 # view as little endian for hash - random.seed(1234) + random.brng.seed(1234) val = self.rfunc(lbnd, ubnd, size=1000, dtype=dt) - random.seed(1234) + random.brng.seed(1234) val_bc = self.rfunc([lbnd] * 1000, ubnd, dtype=dt) assert_array_equal(val, val_bc) - random.seed(1234) + random.brng.seed(1234) val_bc = self.rfunc([lbnd] * 1000, [ubnd] * 1000, dtype=dt) assert_array_equal(val, val_bc) @@ -400,7 +401,7 @@ def setup(self): self.seed = 1234567890 def test_rand(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.rand(3, 2) desired = np.array([[0.61879477158567997, 0.59162362775974664], [0.88868358904449662, 0.89165480011560816], @@ -408,25 +409,25 @@ def test_rand(self): assert_array_almost_equal(actual, desired, decimal=15) def test_rand_singleton(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.rand() desired = 0.61879477158567997 assert_array_almost_equal(actual, desired, decimal=15) def test_randn(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.randn(3, 2) desired = np.array([[-3.472754000610961, -0.108938564229143], [-0.245965753396411, -0.704101550261701], [0.360102487116356, 0.127832101772367]]) assert_array_almost_equal(actual, desired, decimal=15) - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.randn() assert_array_almost_equal(actual, desired[0, 0], decimal=15) def test_randint(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.randint(-99, 99, size=(3, 2)) desired = np.array([[31, 3], [-52, 41], @@ -436,7 +437,7 @@ def test_randint(self): def test_randint_masked(self): # Test masked rejection sampling algorithm to generate array of # uint32 in an interval. - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.randint(0, 99, size=(3, 2), dtype=np.uint32, use_masked=True) desired = np.array([[2, 47], @@ -446,7 +447,7 @@ def test_randint_masked(self): def test_randint_lemire_32(self): # Test lemire algorithm to generate array of uint32 in an interval. - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.randint(0, 99, size=(3, 2), dtype=np.uint32, use_masked=False) desired = np.array([[61, 33], @@ -456,7 +457,7 @@ def test_randint_lemire_32(self): def test_randint_lemire_64(self): # Test lemire algorithm to generate array of uint64 in an interval. - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.randint(0, 99 + 0xFFFFFFFFF, size=(3, 2), dtype=np.uint64, use_masked=False) desired = np.array([[42523252834, 40656066204], @@ -465,7 +466,7 @@ def test_randint_lemire_64(self): assert_array_equal(actual, desired) def test_random_integers(self): - random.seed(self.seed) + random.brng.seed(self.seed) with suppress_warnings() as sup: w = sup.record(DeprecationWarning) actual = random.random_integers(-99, 99, size=(3, 2)) @@ -505,19 +506,19 @@ def test_random_integers_deprecated(self): np.iinfo('l').max, np.iinfo('l').max) def test_random_sample(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.random_sample((3, 2)) desired = np.array([[0.61879477158567997, 0.59162362775974664], [0.88868358904449662, 0.89165480011560816], [0.4575674820298663, 0.7781880808593471]]) assert_array_almost_equal(actual, desired, decimal=15) - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.random_sample() assert_array_almost_equal(actual, desired[0, 0], decimal=15) def test_random_sample_float(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.random_sample((3, 2)) desired = np.array([[0.6187948, 0.5916236], [0.8886836, 0.8916548], @@ -525,7 +526,7 @@ def test_random_sample_float(self): assert_array_almost_equal(actual, desired, decimal=7) def test_random_sample_float_scalar(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.random_sample(dtype=np.float32) desired = 0.6187948 assert_array_almost_equal(actual, desired, decimal=7) @@ -534,31 +535,31 @@ def test_random_sample_unsupported_type(self): assert_raises(TypeError, random.random_sample, dtype='int32') def test_choice_uniform_replace(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.choice(4, 4) desired = np.array([2, 3, 2, 3]) assert_array_equal(actual, desired) def test_choice_nonuniform_replace(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.choice(4, 4, p=[0.4, 0.4, 0.1, 0.1]) desired = np.array([1, 1, 2, 2]) assert_array_equal(actual, desired) def test_choice_uniform_noreplace(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.choice(4, 3, replace=False) desired = np.array([0, 1, 3]) assert_array_equal(actual, desired) def test_choice_nonuniform_noreplace(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.choice(4, 3, replace=False, p=[0.1, 0.3, 0.5, 0.1]) desired = np.array([2, 3, 1]) assert_array_equal(actual, desired) def test_choice_noninteger(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.choice(['a', 'b', 'c', 'd'], 4) desired = np.array(['c', 'd', 'c', 'd']) assert_array_equal(actual, desired) @@ -634,7 +635,7 @@ def test_choice_nan_probabilities(self): assert_raises(ValueError, random.choice, a, p=p) def test_bytes(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.bytes(10) desired = b'\x82Ui\x9e\xff\x97+Wf\xa5' assert_equal(actual, desired) @@ -659,7 +660,7 @@ def test_shuffle(self): lambda x: np.asarray([(i, i) for i in x], [("a", object, 1), ("b", np.int32, 1)])]: - random.seed(self.seed) + random.brng.seed(self.seed) alist = conv([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) random.shuffle(alist) actual = alist @@ -681,19 +682,19 @@ def test_shuffle_masked(self): sorted(b.data[~b.mask]), sorted(b_orig.data[~b_orig.mask])) def test_permutation(self): - random.seed(self.seed) + random.brng.seed(self.seed) alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] actual = random.permutation(alist) desired = [0, 1, 9, 6, 2, 4, 5, 8, 7, 3] assert_array_equal(actual, desired) - random.seed(self.seed) + random.brng.seed(self.seed) arr_2d = np.atleast_2d([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]).T actual = random.permutation(arr_2d) assert_array_equal(actual, np.atleast_2d(desired).T) def test_beta(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.beta(.1, .9, size=(3, 2)) desired = np.array( [[1.45341850513746058e-02, 5.31297615662868145e-04], @@ -702,20 +703,20 @@ def test_beta(self): assert_array_almost_equal(actual, desired, decimal=15) def test_binomial(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.binomial(100.123, .456, size=(3, 2)) desired = np.array([[37, 43], [42, 48], [46, 45]]) assert_array_equal(actual, desired) - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.binomial(100.123, .456) desired = 37 assert_array_equal(actual, desired) def test_chisquare(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.chisquare(50, size=(3, 2)) desired = np.array([[22.2534560369812, 46.9302393710074], [52.9974164611614, 85.3559029505718], @@ -723,7 +724,7 @@ def test_chisquare(self): assert_array_almost_equal(actual, desired, decimal=13) def test_dirichlet(self): - random.seed(self.seed) + random.brng.seed(self.seed) alpha = np.array([51.72840233779265162, 39.74494232180943953]) actual = random.dirichlet(alpha, size=(3, 2)) desired = np.array([[[0.444382290764855, 0.555617709235145], @@ -736,7 +737,7 @@ def test_dirichlet(self): bad_alpha = np.array([5.4e-01, -1.0e-16]) assert_raises(ValueError, random.dirichlet, bad_alpha) - random.seed(self.seed) + random.brng.seed(self.seed) alpha = np.array([51.72840233779265162, 39.74494232180943953]) actual = random.dirichlet(alpha) assert_array_almost_equal(actual, desired[0, 0], decimal=15) @@ -759,7 +760,7 @@ def test_dirichlet_bad_alpha(self): assert_raises(ValueError, random.dirichlet, alpha) def test_exponential(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.exponential(1.1234, size=(3, 2)) desired = np.array([[5.350682337747634, 1.152307441755771], [3.867015473358779, 1.538765912839396], @@ -771,7 +772,7 @@ def test_exponential_0(self): assert_raises(ValueError, random.exponential, scale=-0.) def test_f(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.f(12, 77, size=(3, 2)) desired = np.array([[0.809498839488467, 2.867222762455471], [0.588036831639353, 1.012185639664636], @@ -779,7 +780,7 @@ def test_f(self): assert_array_almost_equal(actual, desired, decimal=15) def test_gamma(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.gamma(5, 3, size=(3, 2)) desired = np.array([[12.46569350177219, 16.46580642087044], [43.65744473309084, 11.98722785682592], @@ -791,7 +792,7 @@ def test_gamma_0(self): assert_raises(ValueError, random.gamma, shape=-0., scale=-0.) def test_geometric(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.geometric(.123456789, size=(3, 2)) desired = np.array([[8, 7], [17, 17], @@ -809,7 +810,7 @@ def test_geometric_exceptions(self): assert_raises(ValueError, random.geometric, [np.nan] * 10) def test_gumbel(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.gumbel(loc=.123456789, scale=2.0, size=(3, 2)) desired = np.array([[0.19591898743416816, 0.34405539668096674], [-1.4492522252274278, -1.47374816298446865], @@ -821,7 +822,7 @@ def test_gumbel_0(self): assert_raises(ValueError, random.gumbel, scale=-0.) def test_hypergeometric(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.hypergeometric(10.1, 5.5, 14, size=(3, 2)) desired = np.array([[10, 10], [10, 10], @@ -847,7 +848,7 @@ def test_hypergeometric(self): assert_array_equal(actual, desired) def test_laplace(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.laplace(loc=.123456789, scale=2.0, size=(3, 2)) desired = np.array([[0.66599721112760157, 0.52829452552221945], [3.12791959514407125, 3.18202813572992005], @@ -859,7 +860,7 @@ def test_laplace_0(self): assert_raises(ValueError, random.laplace, scale=-0.) def test_logistic(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.logistic(loc=.123456789, scale=2.0, size=(3, 2)) desired = np.array([[1.09232835305011444, 0.8648196662399954], [4.27818590694950185, 4.33897006346929714], @@ -867,7 +868,7 @@ def test_logistic(self): assert_array_almost_equal(actual, desired, decimal=15) def test_lognormal(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.lognormal(mean=.123456789, sigma=2.0, size=(3, 2)) desired = np.array([[1.0894838661036e-03, 9.0990021488311e-01], [6.9178869932225e-01, 2.7672077560016e-01], @@ -879,7 +880,7 @@ def test_lognormal_0(self): assert_raises(ValueError, random.lognormal, sigma=-0.) def test_logseries(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.logseries(p=.923456789, size=(3, 2)) desired = np.array([[2, 2], [6, 17], @@ -893,7 +894,7 @@ def test_logseries_exceptions(self): assert_raises(ValueError, random.logseries, [np.nan] * 10) def test_multinomial(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.multinomial(20, [1 / 6.] * 6, size=(3, 2)) desired = np.array([[[4, 3, 5, 4, 2, 2], [5, 2, 8, 2, 2, 1]], @@ -904,7 +905,7 @@ def test_multinomial(self): assert_array_equal(actual, desired) def test_multivariate_normal(self): - random.seed(self.seed) + random.brng.seed(self.seed) mean = (.123456789, 10) cov = [[1, 0], [0, 1]] size = (3, 2) @@ -955,7 +956,7 @@ def test_multivariate_normal(self): mu, np.eye(3)) def test_negative_binomial(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.negative_binomial(n=100, p=.12345, size=(3, 2)) desired = np.array([[521, 736], [665, 690], @@ -970,7 +971,7 @@ def test_negative_binomial_exceptions(self): [np.nan] * 10) def test_noncentral_chisquare(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) desired = np.array([[9.47783251920357, 10.02066178260461], [3.15869984192364, 10.5581565031544], @@ -983,7 +984,7 @@ def test_noncentral_chisquare(self): [1.41985055641800, 0.15451287602753]]) assert_array_almost_equal(actual, desired, decimal=14) - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.noncentral_chisquare(df=5, nonc=0, size=(3, 2)) desired = np.array([[3.64881368071039, 5.48224544747803], [20.41999842025404, 3.44075915187367], @@ -991,7 +992,7 @@ def test_noncentral_chisquare(self): assert_array_almost_equal(actual, desired, decimal=14) def test_noncentral_f(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.noncentral_f(dfnum=5, dfden=2, nonc=1, size=(3, 2)) desired = np.array([[1.22680230963236, 2.56457837623956], @@ -1000,12 +1001,12 @@ def test_noncentral_f(self): assert_array_almost_equal(actual, desired, decimal=14) def test_noncentral_f_nan(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.noncentral_f(dfnum=5, dfden=2, nonc=np.nan) assert np.isnan(actual) def test_normal(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.normal(loc=.123456789, scale=2.0, size=(3, 2)) desired = np.array([[-6.822051212221923, -0.094420339458285], [-0.368474717792823, -1.284746311523402], @@ -1017,7 +1018,7 @@ def test_normal_0(self): assert_raises(ValueError, random.normal, scale=-0.) def test_pareto(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.pareto(a=.123456789, size=(3, 2)) desired = np.array([[5.6883528121891552e+16, 4.0569373841667057e+03], [1.2854967019379475e+12, 6.5833156486851483e+04], @@ -1031,7 +1032,7 @@ def test_pareto(self): np.testing.assert_array_almost_equal_nulp(actual, desired, nulp=30) def test_poisson(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.poisson(lam=.123456789, size=(3, 2)) desired = np.array([[0, 0], [1, 0], @@ -1051,7 +1052,7 @@ def test_poisson_exceptions(self): assert_raises(ValueError, random.poisson, [np.nan] * 10) def test_power(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.power(a=.123456789, size=(3, 2)) desired = np.array([[9.328833342693975e-01, 2.742250409261003e-02], [7.684513237993961e-01, 9.297548209160028e-02], @@ -1059,7 +1060,7 @@ def test_power(self): assert_array_almost_equal(actual, desired, decimal=15) def test_rayleigh(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.rayleigh(scale=10, size=(3, 2)) desired = np.array([[13.8882496494248393, 13.383318339044731], [20.95413364294492098, 21.08285015800712614], @@ -1071,7 +1072,7 @@ def test_rayleigh_0(self): assert_raises(ValueError, random.rayleigh, scale=-0.) def test_standard_cauchy(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.standard_cauchy(size=(3, 2)) desired = np.array([[31.87809592667601, 0.349332782046838], [2.816995747731641, 10.552372563459114], @@ -1079,7 +1080,7 @@ def test_standard_cauchy(self): assert_array_almost_equal(actual, desired, decimal=15) def test_standard_exponential(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.standard_exponential(size=(3, 2), method='inv') desired = np.array([[0.96441739162374596, 0.89556604882105506], [2.1953785836319808, 2.22243285392490542], @@ -1090,7 +1091,7 @@ def test_standard_expoential_type_error(self): assert_raises(TypeError, random.standard_exponential, dtype=np.int32) def test_standard_gamma(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.standard_gamma(shape=3, size=(3, 2)) desired = np.array([[2.28483515569645, 3.29899524967824], [11.12492298902645, 2.16784417297277], @@ -1098,13 +1099,13 @@ def test_standard_gamma(self): assert_array_almost_equal(actual, desired, decimal=14) def test_standard_gammma_scalar_float(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.standard_gamma(3, dtype=np.float32) desired = 1.3877466 assert_array_almost_equal(actual, desired, decimal=6) def test_standard_gamma_float(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.standard_gamma(shape=3, size=(3, 2)) desired = np.array([[2.2848352, 3.2989952], [11.124923, 2.1678442], @@ -1113,14 +1114,14 @@ def test_standard_gamma_float(self): def test_standard_gammma_float_out(self): actual = np.zeros((3, 2), dtype=np.float32) - random.seed(self.seed) + random.brng.seed(self.seed) random.standard_gamma(10.0, out=actual, dtype=np.float32) desired = np.array([[6.9824033, 7.3731737], [14.860578, 7.5327270], [11.767487, 6.2320185]], dtype=np.float32) assert_array_almost_equal(actual, desired, decimal=5) - random.seed(self.seed) + random.brng.seed(self.seed) random.standard_gamma(10.0, out=actual, size=(3, 2), dtype=np.float32) assert_array_almost_equal(actual, desired, decimal=5) @@ -1140,7 +1141,7 @@ def test_standard_gamma_0(self): assert_raises(ValueError, random.standard_gamma, shape=-0.) def test_standard_normal(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.standard_normal(size=(3, 2)) desired = np.array([[-3.472754000610961, -0.108938564229143], [-0.245965753396411, -0.704101550261701], @@ -1151,7 +1152,7 @@ def test_standard_normal_unsupported_type(self): assert_raises(TypeError, random.standard_normal, dtype=np.int32) def test_standard_t(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.standard_t(df=10, size=(3, 2)) desired = np.array([[-3.68722108185508, -0.672031186266171], [2.900224996448669, -0.199656996187739], @@ -1159,7 +1160,7 @@ def test_standard_t(self): assert_array_almost_equal(actual, desired, decimal=15) def test_triangular(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.triangular(left=5.12, mode=10.23, right=20.34, size=(3, 2)) desired = np.array([[12.68117178949215784, 12.4129206149193152], @@ -1168,7 +1169,7 @@ def test_triangular(self): assert_array_almost_equal(actual, desired, decimal=14) def test_uniform(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.uniform(low=1.23, high=10.54, size=(3, 2)) desired = np.array([[6.99097932346268003, 6.73801597444323974], [9.50364421400426274, 9.53130618907631089], @@ -1214,7 +1215,7 @@ def __int__(self): assert_raises(TypeError, random.hypergeometric, throwing_int, 1, 1) def test_vonmises(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.vonmises(mu=1.23, kappa=1.54, size=(3, 2)) desired = np.array([[2.28567572673902042, 2.89163838442285037], [0.38198375564286025, 2.57638023113890746], @@ -1223,17 +1224,17 @@ def test_vonmises(self): def test_vonmises_small(self): # check infinite loop, gh-4720 - random.seed(self.seed) + random.brng.seed(self.seed) r = random.vonmises(mu=0., kappa=1.1e-8, size=10**6) assert_(np.isfinite(r).all()) def test_vonmises_nan(self): - random.seed(self.seed) + random.brng.seed(self.seed) r = random.vonmises(mu=0., kappa=np.nan) assert_(np.isnan(r)) def test_wald(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.wald(mean=1.23, scale=1.54, size=(3, 2)) desired = np.array([[0.10653278160339, 0.98771068102461], [0.89276055317879, 0.13640126419923], @@ -1241,7 +1242,7 @@ def test_wald(self): assert_array_almost_equal(actual, desired, decimal=14) def test_weibull(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.weibull(a=1.23, size=(3, 2)) desired = np.array([[3.557276979846361, 1.020870580998542], [2.731847777612348, 1.29148068905082], @@ -1249,12 +1250,12 @@ def test_weibull(self): assert_array_almost_equal(actual, desired, decimal=15) def test_weibull_0(self): - random.seed(self.seed) + random.brng.seed(self.seed) assert_equal(random.weibull(a=0, size=12), np.zeros(12)) assert_raises(ValueError, random.weibull, a=-0.) def test_zipf(self): - random.seed(self.seed) + random.brng.seed(self.seed) actual = random.zipf(a=1.23, size=(3, 2)) desired = np.array([[66, 29], [1, 1], @@ -1269,7 +1270,7 @@ def setup(self): self.seed = 123456789 def set_seed(self): - random.seed(self.seed) + random.brng.seed(self.seed) def test_uniform(self): low = [0] diff --git a/numpy/random/randomgen/tests/test_generator_mt19937_regressions.py b/numpy/random/randomgen/tests/test_generator_mt19937_regressions.py index 75064720fb97..5a93599c54c2 100644 --- a/numpy/random/randomgen/tests/test_generator_mt19937_regressions.py +++ b/numpy/random/randomgen/tests/test_generator_mt19937_regressions.py @@ -36,7 +36,7 @@ def test_hypergeometric_range(self): def test_logseries_convergence(self): # Test for ticket #923 N = 1000 - mt19937.seed(0) + mt19937.brng.seed(0) rvsn = mt19937.logseries(0.8, size=N) # these two frequency counts should be close to theoretical # numbers with this large sample @@ -50,9 +50,9 @@ def test_logseries_convergence(self): assert_(freq < 0.23, msg) def test_permutation_longs(self): - mt19937.seed(1234) + mt19937.brng.seed(1234) a = mt19937.permutation(12) - mt19937.seed(1234) + mt19937.brng.seed(1234) b = mt19937.permutation(long(12)) assert_array_equal(a, b) @@ -62,7 +62,7 @@ def test_shuffle_mixed_dimension(self): [(1, 1), (2, 2), (3, 3), None], [1, (2, 2), (3, 3), None], [(1, 1), 2, 3, None]]: - mt19937.seed(12345) + mt19937.brng.seed(12345) shuffled = list(t) mt19937.shuffle(shuffled) assert_array_equal(shuffled, [t[0], t[3], t[1], t[2]]) @@ -72,8 +72,8 @@ def test_call_within_randomstate(self): m = RandomGenerator(MT19937()) # mt19937.RandomState() res = np.array([0, 8, 7, 2, 1, 9, 4, 7, 0, 3]) for i in range(3): - mt19937.seed(i) - m.seed(4321) + mt19937.brng.seed(i) + m.brng.seed(4321) # If m.state is not honored, the result will change assert_array_equal(m.choice(10, size=10, p=np.ones(10)/10.), res) @@ -88,7 +88,7 @@ def test_multivariate_normal_size_types(self): def test_beta_small_parameters(self): # Test that beta with small a and b parameters does not produce # NaNs due to roundoff errors causing 0 / 0, gh-5851 - mt19937.seed(1234567890) + mt19937.brng.seed(1234567890) x = mt19937.beta(0.0001, 0.0001, size=100) assert_(not np.any(np.isnan(x)), 'Nans in mt19937.beta') @@ -96,7 +96,7 @@ def test_choice_sum_of_probs_tolerance(self): # The sum of probs should be 1.0 with some tolerance. # For low precision dtypes the tolerance was too tight. # See numpy github issue 6123. - mt19937.seed(1234) + mt19937.brng.seed(1234) a = [1, 2, 3] counts = [4, 4, 2] for dt in np.float16, np.float32, np.float64: @@ -110,7 +110,7 @@ def test_shuffle_of_array_of_different_length_strings(self): # Test that permuting an array of different length strings # will not cause a segfault on garbage collection # Tests gh-7710 - mt19937.seed(1234) + mt19937.brng.seed(1234) a = np.array(['a', 'a' * 1000]) @@ -125,7 +125,7 @@ def test_shuffle_of_array_of_objects(self): # Test that permuting an array of objects will not cause # a segfault on garbage collection. # See gh-7719 - mt19937.seed(1234) + mt19937.brng.seed(1234) a = np.array([np.arange(1), np.arange(4)]) for _ in range(1000): @@ -139,7 +139,7 @@ def test_permutation_subclass(self): class N(np.ndarray): pass - mt19937.seed(1) + mt19937.brng.seed(1) orig = np.arange(3).view(N) perm = mt19937.permutation(orig) assert_array_equal(perm, np.array([0, 2, 1])) @@ -151,7 +151,7 @@ class M(object): def __array__(self): return self.a - mt19937.seed(1) + mt19937.brng.seed(1) m = M() perm = mt19937.permutation(m) assert_array_equal(perm, np.array([2, 1, 4, 0, 3])) diff --git a/numpy/random/randomgen/tests/test_smoke.py b/numpy/random/randomgen/tests/test_smoke.py index 816ce6ddcd76..e42ca269f64b 100644 --- a/numpy/random/randomgen/tests/test_smoke.py +++ b/numpy/random/randomgen/tests/test_smoke.py @@ -106,7 +106,7 @@ def setup_class(cls): cls.advance = None cls.seed = [12345] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -118,39 +118,39 @@ def _extra_setup(cls): cls.seed_error = TypeError def _reset_state(self): - self.rg.state = self.initial_state + self.rg.brng.state = self.initial_state def test_init(self): rg = RandomGenerator(self.brng()) - state = rg.state + state = rg.brng.state rg.standard_normal(1) rg.standard_normal(1) - rg.state = state - new_state = rg.state + rg.brng.state = state + new_state = rg.brng.state assert_(comp_state(state, new_state)) def test_advance(self): - state = self.rg.state - if hasattr(self.rg._basicrng, 'advance'): - self.rg._basicrng.advance(self.advance) - assert_(not comp_state(state, self.rg.state)) + state = self.rg.brng.state + if hasattr(self.rg.brng, 'advance'): + self.rg.brng.advance(self.advance) + assert_(not comp_state(state, self.rg.brng.state)) else: - brng_name = self.rg._basicrng.__class__.__name__ + brng_name = self.rg.brng.__class__.__name__ pytest.skip('Advance is not supported by {0}'.format(brng_name)) def test_jump(self): - state = self.rg.state - if hasattr(self.rg._basicrng, 'jump'): - self.rg._basicrng.jump() - jumped_state = self.rg.state + state = self.rg.brng.state + if hasattr(self.rg.brng, 'jump'): + self.rg.brng.jump() + jumped_state = self.rg.brng.state assert_(not comp_state(state, jumped_state)) self.rg.random_sample(2 * 3 * 5 * 7 * 11 * 13 * 17) - self.rg.state = state - self.rg._basicrng.jump() - rejumped_state = self.rg.state + self.rg.brng.state = state + self.rg.brng.jump() + rejumped_state = self.rg.brng.state assert_(comp_state(jumped_state, rejumped_state)) else: - brng_name = self.rg._basicrng.__class__.__name__ + brng_name = self.rg.brng.__class__.__name__ pytest.skip('Jump is not supported by {0}'.format(brng_name)) def test_uniform(self): @@ -221,51 +221,51 @@ def test_binomial(self): assert_(self.rg.binomial(1000, .5) >= 0) def test_reset_state(self): - state = self.rg.state + state = self.rg.brng.state int_1 = self.rg.randint(2**31) - self.rg.state = state + self.rg.brng.state = state int_2 = self.rg.randint(2**31) assert_(int_1 == int_2) def test_entropy_init(self): rg = RandomGenerator(self.brng()) rg2 = RandomGenerator(self.brng()) - assert_(not comp_state(rg.state, rg2.state)) + assert_(not comp_state(rg.brng.state, rg2.brng.state)) def test_seed(self): rg = RandomGenerator(self.brng(*self.seed)) rg2 = RandomGenerator(self.brng(*self.seed)) rg.random_sample() rg2.random_sample() - assert_(comp_state(rg.state, rg2.state)) + assert_(comp_state(rg.brng.state, rg2.brng.state)) def test_reset_state_gauss(self): rg = RandomGenerator(self.brng(*self.seed)) rg.standard_normal() - state = rg.state + state = rg.brng.state n1 = rg.standard_normal(size=10) rg2 = RandomGenerator(self.brng()) - rg2.state = state + rg2.brng.state = state n2 = rg2.standard_normal(size=10) assert_array_equal(n1, n2) def test_reset_state_uint32(self): rg = RandomGenerator(self.brng(*self.seed)) rg.randint(0, 2 ** 24, 120, dtype=np.uint32) - state = rg.state + state = rg.brng.state n1 = rg.randint(0, 2 ** 24, 10, dtype=np.uint32) rg2 = RandomGenerator(self.brng()) - rg2.state = state + rg2.brng.state = state n2 = rg2.randint(0, 2 ** 24, 10, dtype=np.uint32) assert_array_equal(n1, n2) def test_reset_state_float(self): rg = RandomGenerator(self.brng(*self.seed)) rg.random_sample(dtype='float32') - state = rg.state + state = rg.brng.state n1 = rg.random_sample(size=10, dtype='float32') rg2 = RandomGenerator(self.brng()) - rg2.state = state + rg2.brng.state = state n2 = rg2.random_sample(size=10, dtype='float32') assert_((n1 == n2).all()) @@ -354,29 +354,29 @@ def test_negative_binomial(self): assert_(len(vals) == 10) def test_rand(self): - state = self.rg.state + state = self.rg.brng.state vals = self.rg.rand(10, 10, 10) - self.rg.state = state + self.rg.brng.state = state assert_((vals == self.rg.random_sample((10, 10, 10))).all()) assert_(vals.shape == (10, 10, 10)) vals = self.rg.rand(10, 10, 10, dtype=np.float32) assert_(vals.shape == (10, 10, 10)) def test_randn(self): - state = self.rg.state + state = self.rg.brng.state vals = self.rg.randn(10, 10, 10) - self.rg.state = state + self.rg.brng.state = state assert_equal(vals, self.rg.standard_normal((10, 10, 10))) assert_equal(vals.shape, (10, 10, 10)) - state = self.rg.state + state = self.rg.brng.state vals = self.rg.randn(10, 10, 10) - self.rg.state = state + self.rg.brng.state = state assert_equal(vals, self.rg.standard_normal((10, 10, 10))) - state = self.rg.state + state = self.rg.brng.state self.rg.randn(10, 10, 10) - self.rg.state = state + self.rg.brng.state = state vals = self.rg.randn(10, 10, 10, dtype=np.float32) assert_(vals.shape == (10, 10, 10)) @@ -487,12 +487,12 @@ def test_pickle(self): pick = pickle.dumps(self.rg) unpick = pickle.loads(pick) assert_((type(self.rg) == type(unpick))) - assert_(comp_state(self.rg.state, unpick.state)) + assert_(comp_state(self.rg.brng.state, unpick.brng.state)) pick = pickle.dumps(self.rg) unpick = pickle.loads(pick) assert_((type(self.rg) == type(unpick))) - assert_(comp_state(self.rg.state, unpick.state)) + assert_(comp_state(self.rg.brng.state, unpick.brng.state)) def test_seed_array(self): if self.seed_vector_bits is None: @@ -505,32 +505,32 @@ def test_seed_array(self): else: dtype = np.uint64 seed = np.array([1], dtype=dtype) - self.rg.seed(seed) - state1 = self.rg.state - self.rg.seed(1) - state2 = self.rg.state + self.rg.brng.seed(seed) + state1 = self.rg.brng.state + self.rg.brng.seed(1) + state2 = self.rg.brng.state assert_(comp_state(state1, state2)) seed = np.arange(4, dtype=dtype) - self.rg.seed(seed) - state1 = self.rg.state - self.rg.seed(seed[0]) - state2 = self.rg.state + self.rg.brng.seed(seed) + state1 = self.rg.brng.state + self.rg.brng.seed(seed[0]) + state2 = self.rg.brng.state assert_(not comp_state(state1, state2)) seed = np.arange(1500, dtype=dtype) - self.rg.seed(seed) - state1 = self.rg.state - self.rg.seed(seed[0]) - state2 = self.rg.state + self.rg.brng.seed(seed) + state1 = self.rg.brng.state + self.rg.brng.seed(seed[0]) + state2 = self.rg.brng.state assert_(not comp_state(state1, state2)) seed = 2 ** np.mod(np.arange(1500, dtype=dtype), self.seed_vector_bits - 1) + 1 - self.rg.seed(seed) - state1 = self.rg.state - self.rg.seed(seed[0]) - state2 = self.rg.state + self.rg.brng.seed(seed) + state1 = self.rg.brng.state + self.rg.brng.seed(seed[0]) + state2 = self.rg.brng.state assert_(not comp_state(state1, state2)) def test_seed_array_error(self): @@ -541,164 +541,164 @@ def test_seed_array_error(self): seed = -1 with pytest.raises(ValueError): - self.rg.seed(seed) + self.rg.brng.seed(seed) seed = np.array([-1], dtype=np.int32) with pytest.raises(ValueError): - self.rg.seed(seed) + self.rg.brng.seed(seed) seed = np.array([1, 2, 3, -5], dtype=np.int32) with pytest.raises(ValueError): - self.rg.seed(seed) + self.rg.brng.seed(seed) seed = np.array([1, 2, 3, out_of_bounds]) with pytest.raises(ValueError): - self.rg.seed(seed) + self.rg.brng.seed(seed) def test_uniform_float(self): rg = RandomGenerator(self.brng(12345)) warmup(rg) - state = rg.state + state = rg.brng.state r1 = rg.random_sample(11, dtype=np.float32) rg2 = RandomGenerator(self.brng()) warmup(rg2) - rg2.state = state + rg2.brng.state = state r2 = rg2.random_sample(11, dtype=np.float32) assert_array_equal(r1, r2) assert_equal(r1.dtype, np.float32) - assert_(comp_state(rg.state, rg2.state)) + assert_(comp_state(rg.brng.state, rg2.brng.state)) def test_gamma_floats(self): rg = RandomGenerator(self.brng()) warmup(rg) - state = rg.state + state = rg.brng.state r1 = rg.standard_gamma(4.0, 11, dtype=np.float32) rg2 = RandomGenerator(self.brng()) warmup(rg2) - rg2.state = state + rg2.brng.state = state r2 = rg2.standard_gamma(4.0, 11, dtype=np.float32) assert_array_equal(r1, r2) assert_equal(r1.dtype, np.float32) - assert_(comp_state(rg.state, rg2.state)) + assert_(comp_state(rg.brng.state, rg2.brng.state)) def test_normal_floats(self): rg = RandomGenerator(self.brng()) warmup(rg) - state = rg.state + state = rg.brng.state r1 = rg.standard_normal(11, dtype=np.float32) rg2 = RandomGenerator(self.brng()) warmup(rg2) - rg2.state = state + rg2.brng.state = state r2 = rg2.standard_normal(11, dtype=np.float32) assert_array_equal(r1, r2) assert_equal(r1.dtype, np.float32) - assert_(comp_state(rg.state, rg2.state)) + assert_(comp_state(rg.brng.state, rg2.brng.state)) def test_normal_zig_floats(self): rg = RandomGenerator(self.brng()) warmup(rg) - state = rg.state + state = rg.brng.state r1 = rg.standard_normal(11, dtype=np.float32) rg2 = RandomGenerator(self.brng()) warmup(rg2) - rg2.state = state + rg2.brng.state = state r2 = rg2.standard_normal(11, dtype=np.float32) assert_array_equal(r1, r2) assert_equal(r1.dtype, np.float32) - assert_(comp_state(rg.state, rg2.state)) + assert_(comp_state(rg.brng.state, rg2.brng.state)) def test_output_fill(self): rg = self.rg - state = rg.state + state = rg.brng.state size = (31, 7, 97) existing = np.empty(size) - rg.state = state + rg.brng.state = state rg.standard_normal(out=existing) - rg.state = state + rg.brng.state = state direct = rg.standard_normal(size=size) assert_equal(direct, existing) sized = np.empty(size) - rg.state = state + rg.brng.state = state rg.standard_normal(out=sized, size=sized.shape) existing = np.empty(size, dtype=np.float32) - rg.state = state + rg.brng.state = state rg.standard_normal(out=existing, dtype=np.float32) - rg.state = state + rg.brng.state = state direct = rg.standard_normal(size=size, dtype=np.float32) assert_equal(direct, existing) def test_output_filling_uniform(self): rg = self.rg - state = rg.state + state = rg.brng.state size = (31, 7, 97) existing = np.empty(size) - rg.state = state + rg.brng.state = state rg.random_sample(out=existing) - rg.state = state + rg.brng.state = state direct = rg.random_sample(size=size) assert_equal(direct, existing) existing = np.empty(size, dtype=np.float32) - rg.state = state + rg.brng.state = state rg.random_sample(out=existing, dtype=np.float32) - rg.state = state + rg.brng.state = state direct = rg.random_sample(size=size, dtype=np.float32) assert_equal(direct, existing) def test_output_filling_exponential(self): rg = self.rg - state = rg.state + state = rg.brng.state size = (31, 7, 97) existing = np.empty(size) - rg.state = state + rg.brng.state = state rg.standard_exponential(out=existing) - rg.state = state + rg.brng.state = state direct = rg.standard_exponential(size=size) assert_equal(direct, existing) existing = np.empty(size, dtype=np.float32) - rg.state = state + rg.brng.state = state rg.standard_exponential(out=existing, dtype=np.float32) - rg.state = state + rg.brng.state = state direct = rg.standard_exponential(size=size, dtype=np.float32) assert_equal(direct, existing) def test_output_filling_gamma(self): rg = self.rg - state = rg.state + state = rg.brng.state size = (31, 7, 97) existing = np.zeros(size) - rg.state = state + rg.brng.state = state rg.standard_gamma(1.0, out=existing) - rg.state = state + rg.brng.state = state direct = rg.standard_gamma(1.0, size=size) assert_equal(direct, existing) existing = np.zeros(size, dtype=np.float32) - rg.state = state + rg.brng.state = state rg.standard_gamma(1.0, out=existing, dtype=np.float32) - rg.state = state + rg.brng.state = state direct = rg.standard_gamma(1.0, size=size, dtype=np.float32) assert_equal(direct, existing) def test_output_filling_gamma_broadcast(self): rg = self.rg - state = rg.state + state = rg.brng.state size = (31, 7, 97) mu = np.arange(97.0) + 1.0 existing = np.zeros(size) - rg.state = state + rg.brng.state = state rg.standard_gamma(mu, out=existing) - rg.state = state + rg.brng.state = state direct = rg.standard_gamma(mu, size=size) assert_equal(direct, existing) existing = np.zeros(size, dtype=np.float32) - rg.state = state + rg.brng.state = state rg.standard_gamma(mu, out=existing, dtype=np.float32) - rg.state = state + rg.brng.state = state direct = rg.standard_gamma(mu, size=size, dtype=np.float32) assert_equal(direct, existing) @@ -796,7 +796,7 @@ def setup_class(cls): cls.advance = None cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = 32 cls._extra_setup() cls.seed_error = ValueError @@ -805,8 +805,8 @@ def test_numpy_state(self): nprg = np.random.RandomState() nprg.standard_normal(99) state = nprg.get_state() - self.rg.state = state - state2 = self.rg.state + self.rg.brng.state = state + state2 = self.rg.brng.state assert_((state[1] == state2['state']['key']).all()) assert_((state[2] == state2['state']['pos'])) @@ -819,7 +819,7 @@ def setup_class(cls): cls.seed = [2 ** 96 + 2 ** 48 + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1, 2 ** 21 + 2 ** 16 + 2 ** 5 + 1] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = None cls._extra_setup() @@ -832,20 +832,20 @@ def test_seed_array_error(self): seed = -1 with pytest.raises(ValueError): - self.rg.seed(seed) + self.rg.brng.seed(seed) error_type = ValueError if self.seed_vector_bits else TypeError seed = np.array([-1], dtype=np.int32) with pytest.raises(error_type): - self.rg.seed(seed) + self.rg.brng.seed(seed) seed = np.array([1, 2, 3, -5], dtype=np.int32) with pytest.raises(error_type): - self.rg.seed(seed) + self.rg.brng.seed(seed) seed = np.array([1, 2, 3, out_of_bounds]) with pytest.raises(error_type): - self.rg.seed(seed) + self.rg.brng.seed(seed) class TestPhilox(RNG): @@ -855,7 +855,7 @@ def setup_class(cls): cls.advance = 2**63 + 2**31 + 2**15 + 1 cls.seed = [12345] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -867,7 +867,7 @@ def setup_class(cls): cls.advance = 2 ** 63 + 2 ** 31 + 2 ** 15 + 1 cls.seed = [12345] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -879,7 +879,7 @@ def setup_class(cls): cls.advance = None cls.seed = [12345] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -891,7 +891,7 @@ def setup_class(cls): cls.advance = None cls.seed = [12345] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -903,7 +903,7 @@ def setup_class(cls): cls.advance = None cls.seed = [12345] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -915,7 +915,7 @@ def setup_class(cls): cls.advance = None cls.seed = [12345] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = 64 cls._extra_setup() @@ -927,7 +927,7 @@ def setup_class(cls): cls.advance = None cls.seed = [12345] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls._extra_setup() cls.seed_vector_bits = 32 @@ -939,7 +939,7 @@ def setup_class(cls): cls.advance = 2**63 + 2**31 + 2**15 + 1 cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = 64 cls._extra_setup() cls.seed_error = ValueError @@ -972,6 +972,6 @@ def setup_class(cls): cls.seed = [2 ** 48 + 2 ** 21 + 2 ** 16 + 2 ** 5 + 1, 2 ** 21 + 2 ** 16 + 2 ** 5 + 1] cls.rg = RandomGenerator(cls.brng(*cls.seed)) - cls.initial_state = cls.rg.state + cls.initial_state = cls.rg.brng.state cls.seed_vector_bits = None cls._extra_setup() From 469bf4c3379c4339320ac447d14d57d1591038e7 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 12 Apr 2019 00:35:52 +0300 Subject: [PATCH 277/279] ENH: move code out of numpy.random.randomgen into numpy.random --- numpy/random/{randomgen => }/LICENSE.md | 0 numpy/random/__init__.py | 36 +- numpy/random/{mtrand => _mtrand}/Python.pxi | 0 .../{mtrand => _mtrand}/distributions.c | 0 .../{mtrand => _mtrand}/distributions.h | 0 .../{mtrand => _mtrand}/generate_mtrand_c.py | 0 numpy/random/{mtrand => _mtrand}/initarray.c | 0 numpy/random/{mtrand => _mtrand}/initarray.h | 0 numpy/random/{mtrand => _mtrand}/mtrand.pyx | 0 .../{mtrand => _mtrand}/mtrand_py_helper.h | 0 numpy/random/{mtrand => _mtrand}/numpy.pxd | 0 .../randint_helpers.pxi.in | 0 numpy/random/{mtrand => _mtrand}/randomkit.c | 0 numpy/random/{mtrand => _mtrand}/randomkit.h | 0 numpy/random/{randomgen => }/_pickle.py | 0 .../{randomgen => }/bounded_integers.pxd.in | 0 .../{randomgen => }/bounded_integers.pyx.in | 0 numpy/random/{randomgen => }/common.pxd | 0 numpy/random/{randomgen => }/common.pyx | 0 .../random/{randomgen => }/distributions.pxd | 0 numpy/random/{randomgen => }/dsfmt.pyx | 0 numpy/random/{randomgen => }/entropy.pyx | 0 .../examples/cython/extending.pyx | 0 .../cython/extending_distributions.pyx | 0 .../{randomgen => }/examples/cython/setup.py | 0 .../examples/numba/extending.py | 0 .../examples/numba/extending_distributions.py | 0 numpy/random/{randomgen => }/generator.pyx | 0 .../random/{randomgen => }/legacy/__init__.py | 0 .../legacy/legacy_distributions.pxd | 0 numpy/random/{randomgen => }/mt19937.pyx | 0 numpy/random/{randomgen => }/mtrand.pyx | 0 numpy/random/{randomgen => }/pcg32.pyx | 0 numpy/random/{randomgen => }/pcg64.pyx | 0 numpy/random/{randomgen => }/philox.pyx | 0 numpy/random/randomgen/__init__.py | 21 - numpy/random/randomgen/_version.py | 520 ------------------ numpy/random/randomgen/setup.py | 191 ------- numpy/random/randomgen/tests/data/__init__.py | 0 numpy/random/setup.py | 153 +++++- .../src/aligned_malloc/aligned_malloc.c | 0 .../src/aligned_malloc/aligned_malloc.h | 0 .../{randomgen => }/src/common/LICENSE.md | 0 .../{randomgen => }/src/common/inttypes.h | 0 .../{randomgen => }/src/common/stdint.h | 0 .../src/distributions/LICENSE.md | 0 .../src/distributions/binomial.h | 0 .../src/distributions/distributions.c | 0 .../src/distributions/distributions.h | 0 .../src/distributions/ziggurat.h | 0 .../src/distributions/ziggurat_constants.h | 0 .../src/dsfmt/128-bit-jump.poly.txt | 0 .../src/dsfmt/96-bit-jump.poly.txt | 0 .../{randomgen => }/src/dsfmt/LICENSE.md | 0 .../{randomgen => }/src/dsfmt/calc-jump.cpp | 0 .../src/dsfmt/dSFMT-benchmark.c | 0 .../src/dsfmt/dSFMT-calc-jump.hpp | 0 .../{randomgen => }/src/dsfmt/dSFMT-common.h | 0 .../{randomgen => }/src/dsfmt/dSFMT-jump.c | 0 .../{randomgen => }/src/dsfmt/dSFMT-jump.h | 0 .../{randomgen => }/src/dsfmt/dSFMT-params.h | 0 .../src/dsfmt/dSFMT-params19937.h | 0 .../{randomgen => }/src/dsfmt/dSFMT-poly.h | 0 .../src/dsfmt/dSFMT-test-gen.c | 0 .../random/{randomgen => }/src/dsfmt/dSFMT.c | 0 .../random/{randomgen => }/src/dsfmt/dSFMT.h | 0 .../{randomgen => }/src/entropy/LICENSE.md | 0 .../{randomgen => }/src/entropy/entropy.c | 0 .../{randomgen => }/src/entropy/entropy.h | 0 .../{randomgen => }/src/legacy/LICENSE.md | 0 .../src/legacy/distributions-boxmuller.c | 0 .../src/legacy/distributions-boxmuller.h | 0 .../{randomgen => }/src/mt19937/LICENSE.md | 0 .../src/mt19937/mt19937-benchmark.c | 0 .../src/mt19937/mt19937-jump.c | 0 .../src/mt19937/mt19937-jump.h | 0 .../src/mt19937/mt19937-poly.h | 0 .../src/mt19937/mt19937-test-data-gen.c | 0 .../{randomgen => }/src/mt19937/mt19937.c | 0 .../{randomgen => }/src/mt19937/mt19937.h | 0 .../{randomgen => }/src/mt19937/randomkit.c | 0 .../{randomgen => }/src/mt19937/randomkit.h | 0 .../{randomgen => }/src/pcg32/LICENSE.md | 0 .../src/pcg32/pcg-advance-64.c | 0 .../src/pcg32/pcg32-test-data-gen.c | 0 .../random/{randomgen => }/src/pcg32/pcg32.c | 0 .../random/{randomgen => }/src/pcg32/pcg32.h | 0 .../{randomgen => }/src/pcg32/pcg_variants.h | 0 .../{randomgen => }/src/pcg64/LICENSE.md | 0 .../src/pcg64/pcg64-benchmark.c | 0 .../src/pcg64/pcg64-test-data-gen.c | 0 .../random/{randomgen => }/src/pcg64/pcg64.c | 0 .../random/{randomgen => }/src/pcg64/pcg64.h | 0 .../{randomgen => }/src/pcg64/pcg64.orig.c | 0 .../{randomgen => }/src/pcg64/pcg64.orig.h | 0 .../{randomgen => }/src/philox/LICENSE.md | 0 .../src/philox/philox-benchmark.c | 0 .../src/philox/philox-test-data-gen.c | 0 .../{randomgen => }/src/philox/philox.c | 0 .../{randomgen => }/src/philox/philox.h | 0 .../{randomgen => }/src/splitmix64/LICENSE.md | 0 .../src/splitmix64/splitmix64.c | 0 .../src/splitmix64/splitmix64.h | 0 .../src/splitmix64/splitmix64.orig.c | 0 .../{randomgen => }/src/threefry/LICENSE.md | 0 .../src/threefry/threefry-benchmark.c | 0 .../src/threefry/threefry-orig.c | 0 .../src/threefry/threefry-test-data-gen.c | 0 .../{randomgen => }/src/threefry/threefry.c | 0 .../{randomgen => }/src/threefry/threefry.h | 0 .../{randomgen => }/src/threefry32/LICENSE.md | 0 .../src/threefry32/threefry32-test-data-gen.c | 0 .../src/threefry32/threefry32.c | 0 .../src/threefry32/threefry32.h | 0 .../src/xoroshiro128/LICENSE.md | 0 .../src/xoroshiro128/xoroshiro128-benchmark.c | 0 .../xoroshiro128/xoroshiro128-test-data-gen.c | 0 .../src/xoroshiro128/xoroshiro128.c | 0 .../src/xoroshiro128/xoroshiro128.h | 0 .../src/xoroshiro128/xoroshiro128plus.orig.c | 0 .../src/xoroshiro128/xoroshiro128plus.orig.h | 0 .../src/xorshift1024/LICENSE.md | 0 .../src/xorshift1024/xorshift1024-benchmark.c | 0 .../xorshift1024/xorshift1024-test-data-gen.c | 0 .../src/xorshift1024/xorshift1024.c | 0 .../src/xorshift1024/xorshift1024.h | 0 .../src/xorshift1024/xorshift1024.orig.c | 0 .../src/xorshift1024/xorshift1024.orig.h | 0 .../src/xoshiro256starstar/LICENSE.md | 0 .../xoshiro256starstar-test-data-gen.c | 0 .../xoshiro256starstar/xoshiro256starstar.c | 0 .../xoshiro256starstar/xoshiro256starstar.h | 0 .../xoshiro256starstar.orig.c | 0 .../xoshiro256starstar.orig.h | 0 .../src/xoshiro512starstar/LICENSE.md | 0 .../xoshiro512starstar-test-data-gen.c | 0 .../xoshiro512starstar/xoshiro512starstar.c | 0 .../xoshiro512starstar/xoshiro512starstar.h | 0 .../xoshiro512starstar.orig.c | 0 .../xoshiro512starstar.orig.h | 0 .../tests => tests/data}/__init__.py | 0 .../tests/data/dSFMT-testset-1.csv | 0 .../tests/data/dSFMT-testset-2.csv | 0 .../tests/data/mt19937-testset-1.csv | 0 .../tests/data/mt19937-testset-2.csv | 0 .../tests/data/pcg32-testset-1.csv | 0 .../tests/data/pcg32-testset-2.csv | 0 .../tests/data/pcg64-testset-1.csv | 0 .../tests/data/pcg64-testset-2.csv | 0 .../tests/data/philox-testset-1.csv | 0 .../tests/data/philox-testset-2.csv | 0 .../tests/data/threefry-testset-1.csv | 0 .../tests/data/threefry-testset-2.csv | 0 .../tests/data/threefry32-testset-1.csv | 0 .../tests/data/threefry32-testset-2.csv | 0 .../tests/data/xoroshiro128-testset-1.csv | 0 .../tests/data/xoroshiro128-testset-2.csv | 0 .../tests/data/xorshift1024-testset-1.csv | 0 .../tests/data/xorshift1024-testset-2.csv | 0 .../data/xoshiro256starstar-testset-1.csv | 0 .../data/xoshiro256starstar-testset-2.csv | 0 .../data/xoshiro512starstar-testset-1.csv | 0 .../data/xoshiro512starstar-testset-2.csv | 0 .../tests/test_against_numpy.py | 0 .../{randomgen => }/tests/test_direct.py | 0 .../tests/test_generator_mt19937.py | 0 .../test_generator_mt19937_regressions.py | 0 .../{randomgen => }/tests/test_randomstate.py | 0 .../tests/test_randomstate_regression.py | 0 .../{randomgen => }/tests/test_smoke.py | 0 numpy/random/{randomgen => }/threefry.pyx | 0 numpy/random/{randomgen => }/threefry32.pyx | 0 numpy/random/{randomgen => }/xoroshiro128.pyx | 0 numpy/random/{randomgen => }/xorshift1024.pyx | 0 .../{randomgen => }/xoshiro256starstar.pyx | 0 .../{randomgen => }/xoshiro512starstar.pyx | 0 setup.py | 4 +- 177 files changed, 182 insertions(+), 743 deletions(-) rename numpy/random/{randomgen => }/LICENSE.md (100%) rename numpy/random/{mtrand => _mtrand}/Python.pxi (100%) rename numpy/random/{mtrand => _mtrand}/distributions.c (100%) rename numpy/random/{mtrand => _mtrand}/distributions.h (100%) rename numpy/random/{mtrand => _mtrand}/generate_mtrand_c.py (100%) rename numpy/random/{mtrand => _mtrand}/initarray.c (100%) rename numpy/random/{mtrand => _mtrand}/initarray.h (100%) rename numpy/random/{mtrand => _mtrand}/mtrand.pyx (100%) rename numpy/random/{mtrand => _mtrand}/mtrand_py_helper.h (100%) rename numpy/random/{mtrand => _mtrand}/numpy.pxd (100%) rename numpy/random/{mtrand => _mtrand}/randint_helpers.pxi.in (100%) rename numpy/random/{mtrand => _mtrand}/randomkit.c (100%) rename numpy/random/{mtrand => _mtrand}/randomkit.h (100%) rename numpy/random/{randomgen => }/_pickle.py (100%) rename numpy/random/{randomgen => }/bounded_integers.pxd.in (100%) rename numpy/random/{randomgen => }/bounded_integers.pyx.in (100%) rename numpy/random/{randomgen => }/common.pxd (100%) rename numpy/random/{randomgen => }/common.pyx (100%) rename numpy/random/{randomgen => }/distributions.pxd (100%) rename numpy/random/{randomgen => }/dsfmt.pyx (100%) rename numpy/random/{randomgen => }/entropy.pyx (100%) rename numpy/random/{randomgen => }/examples/cython/extending.pyx (100%) rename numpy/random/{randomgen => }/examples/cython/extending_distributions.pyx (100%) rename numpy/random/{randomgen => }/examples/cython/setup.py (100%) rename numpy/random/{randomgen => }/examples/numba/extending.py (100%) rename numpy/random/{randomgen => }/examples/numba/extending_distributions.py (100%) rename numpy/random/{randomgen => }/generator.pyx (100%) rename numpy/random/{randomgen => }/legacy/__init__.py (100%) rename numpy/random/{randomgen => }/legacy/legacy_distributions.pxd (100%) rename numpy/random/{randomgen => }/mt19937.pyx (100%) rename numpy/random/{randomgen => }/mtrand.pyx (100%) rename numpy/random/{randomgen => }/pcg32.pyx (100%) rename numpy/random/{randomgen => }/pcg64.pyx (100%) rename numpy/random/{randomgen => }/philox.pyx (100%) delete mode 100644 numpy/random/randomgen/__init__.py delete mode 100644 numpy/random/randomgen/_version.py delete mode 100644 numpy/random/randomgen/setup.py delete mode 100644 numpy/random/randomgen/tests/data/__init__.py rename numpy/random/{randomgen => }/src/aligned_malloc/aligned_malloc.c (100%) rename numpy/random/{randomgen => }/src/aligned_malloc/aligned_malloc.h (100%) rename numpy/random/{randomgen => }/src/common/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/common/inttypes.h (100%) rename numpy/random/{randomgen => }/src/common/stdint.h (100%) rename numpy/random/{randomgen => }/src/distributions/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/distributions/binomial.h (100%) rename numpy/random/{randomgen => }/src/distributions/distributions.c (100%) rename numpy/random/{randomgen => }/src/distributions/distributions.h (100%) rename numpy/random/{randomgen => }/src/distributions/ziggurat.h (100%) rename numpy/random/{randomgen => }/src/distributions/ziggurat_constants.h (100%) rename numpy/random/{randomgen => }/src/dsfmt/128-bit-jump.poly.txt (100%) rename numpy/random/{randomgen => }/src/dsfmt/96-bit-jump.poly.txt (100%) rename numpy/random/{randomgen => }/src/dsfmt/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/dsfmt/calc-jump.cpp (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT-benchmark.c (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT-calc-jump.hpp (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT-common.h (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT-jump.c (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT-jump.h (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT-params.h (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT-params19937.h (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT-poly.h (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT-test-gen.c (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT.c (100%) rename numpy/random/{randomgen => }/src/dsfmt/dSFMT.h (100%) rename numpy/random/{randomgen => }/src/entropy/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/entropy/entropy.c (100%) rename numpy/random/{randomgen => }/src/entropy/entropy.h (100%) rename numpy/random/{randomgen => }/src/legacy/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/legacy/distributions-boxmuller.c (100%) rename numpy/random/{randomgen => }/src/legacy/distributions-boxmuller.h (100%) rename numpy/random/{randomgen => }/src/mt19937/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/mt19937/mt19937-benchmark.c (100%) rename numpy/random/{randomgen => }/src/mt19937/mt19937-jump.c (100%) rename numpy/random/{randomgen => }/src/mt19937/mt19937-jump.h (100%) rename numpy/random/{randomgen => }/src/mt19937/mt19937-poly.h (100%) rename numpy/random/{randomgen => }/src/mt19937/mt19937-test-data-gen.c (100%) rename numpy/random/{randomgen => }/src/mt19937/mt19937.c (100%) rename numpy/random/{randomgen => }/src/mt19937/mt19937.h (100%) rename numpy/random/{randomgen => }/src/mt19937/randomkit.c (100%) rename numpy/random/{randomgen => }/src/mt19937/randomkit.h (100%) rename numpy/random/{randomgen => }/src/pcg32/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/pcg32/pcg-advance-64.c (100%) rename numpy/random/{randomgen => }/src/pcg32/pcg32-test-data-gen.c (100%) rename numpy/random/{randomgen => }/src/pcg32/pcg32.c (100%) rename numpy/random/{randomgen => }/src/pcg32/pcg32.h (100%) rename numpy/random/{randomgen => }/src/pcg32/pcg_variants.h (100%) rename numpy/random/{randomgen => }/src/pcg64/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/pcg64/pcg64-benchmark.c (100%) rename numpy/random/{randomgen => }/src/pcg64/pcg64-test-data-gen.c (100%) rename numpy/random/{randomgen => }/src/pcg64/pcg64.c (100%) rename numpy/random/{randomgen => }/src/pcg64/pcg64.h (100%) rename numpy/random/{randomgen => }/src/pcg64/pcg64.orig.c (100%) rename numpy/random/{randomgen => }/src/pcg64/pcg64.orig.h (100%) rename numpy/random/{randomgen => }/src/philox/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/philox/philox-benchmark.c (100%) rename numpy/random/{randomgen => }/src/philox/philox-test-data-gen.c (100%) rename numpy/random/{randomgen => }/src/philox/philox.c (100%) rename numpy/random/{randomgen => }/src/philox/philox.h (100%) rename numpy/random/{randomgen => }/src/splitmix64/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/splitmix64/splitmix64.c (100%) rename numpy/random/{randomgen => }/src/splitmix64/splitmix64.h (100%) rename numpy/random/{randomgen => }/src/splitmix64/splitmix64.orig.c (100%) rename numpy/random/{randomgen => }/src/threefry/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/threefry/threefry-benchmark.c (100%) rename numpy/random/{randomgen => }/src/threefry/threefry-orig.c (100%) rename numpy/random/{randomgen => }/src/threefry/threefry-test-data-gen.c (100%) rename numpy/random/{randomgen => }/src/threefry/threefry.c (100%) rename numpy/random/{randomgen => }/src/threefry/threefry.h (100%) rename numpy/random/{randomgen => }/src/threefry32/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/threefry32/threefry32-test-data-gen.c (100%) rename numpy/random/{randomgen => }/src/threefry32/threefry32.c (100%) rename numpy/random/{randomgen => }/src/threefry32/threefry32.h (100%) rename numpy/random/{randomgen => }/src/xoroshiro128/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/xoroshiro128/xoroshiro128-benchmark.c (100%) rename numpy/random/{randomgen => }/src/xoroshiro128/xoroshiro128-test-data-gen.c (100%) rename numpy/random/{randomgen => }/src/xoroshiro128/xoroshiro128.c (100%) rename numpy/random/{randomgen => }/src/xoroshiro128/xoroshiro128.h (100%) rename numpy/random/{randomgen => }/src/xoroshiro128/xoroshiro128plus.orig.c (100%) rename numpy/random/{randomgen => }/src/xoroshiro128/xoroshiro128plus.orig.h (100%) rename numpy/random/{randomgen => }/src/xorshift1024/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/xorshift1024/xorshift1024-benchmark.c (100%) rename numpy/random/{randomgen => }/src/xorshift1024/xorshift1024-test-data-gen.c (100%) rename numpy/random/{randomgen => }/src/xorshift1024/xorshift1024.c (100%) rename numpy/random/{randomgen => }/src/xorshift1024/xorshift1024.h (100%) rename numpy/random/{randomgen => }/src/xorshift1024/xorshift1024.orig.c (100%) rename numpy/random/{randomgen => }/src/xorshift1024/xorshift1024.orig.h (100%) rename numpy/random/{randomgen => }/src/xoshiro256starstar/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c (100%) rename numpy/random/{randomgen => }/src/xoshiro256starstar/xoshiro256starstar.c (100%) rename numpy/random/{randomgen => }/src/xoshiro256starstar/xoshiro256starstar.h (100%) rename numpy/random/{randomgen => }/src/xoshiro256starstar/xoshiro256starstar.orig.c (100%) rename numpy/random/{randomgen => }/src/xoshiro256starstar/xoshiro256starstar.orig.h (100%) rename numpy/random/{randomgen => }/src/xoshiro512starstar/LICENSE.md (100%) rename numpy/random/{randomgen => }/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c (100%) rename numpy/random/{randomgen => }/src/xoshiro512starstar/xoshiro512starstar.c (100%) rename numpy/random/{randomgen => }/src/xoshiro512starstar/xoshiro512starstar.h (100%) rename numpy/random/{randomgen => }/src/xoshiro512starstar/xoshiro512starstar.orig.c (100%) rename numpy/random/{randomgen => }/src/xoshiro512starstar/xoshiro512starstar.orig.h (100%) rename numpy/random/{randomgen/tests => tests/data}/__init__.py (100%) rename numpy/random/{randomgen => }/tests/data/dSFMT-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/dSFMT-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/data/mt19937-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/mt19937-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/data/pcg32-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/pcg32-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/data/pcg64-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/pcg64-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/data/philox-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/philox-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/data/threefry-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/threefry-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/data/threefry32-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/threefry32-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/data/xoroshiro128-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/xoroshiro128-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/data/xorshift1024-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/xorshift1024-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/data/xoshiro256starstar-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/xoshiro256starstar-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/data/xoshiro512starstar-testset-1.csv (100%) rename numpy/random/{randomgen => }/tests/data/xoshiro512starstar-testset-2.csv (100%) rename numpy/random/{randomgen => }/tests/test_against_numpy.py (100%) rename numpy/random/{randomgen => }/tests/test_direct.py (100%) rename numpy/random/{randomgen => }/tests/test_generator_mt19937.py (100%) rename numpy/random/{randomgen => }/tests/test_generator_mt19937_regressions.py (100%) rename numpy/random/{randomgen => }/tests/test_randomstate.py (100%) rename numpy/random/{randomgen => }/tests/test_randomstate_regression.py (100%) rename numpy/random/{randomgen => }/tests/test_smoke.py (100%) rename numpy/random/{randomgen => }/threefry.pyx (100%) rename numpy/random/{randomgen => }/threefry32.pyx (100%) rename numpy/random/{randomgen => }/xoroshiro128.pyx (100%) rename numpy/random/{randomgen => }/xorshift1024.pyx (100%) rename numpy/random/{randomgen => }/xoshiro256starstar.pyx (100%) rename numpy/random/{randomgen => }/xoshiro512starstar.pyx (100%) diff --git a/numpy/random/randomgen/LICENSE.md b/numpy/random/LICENSE.md similarity index 100% rename from numpy/random/randomgen/LICENSE.md rename to numpy/random/LICENSE.md diff --git a/numpy/random/__init__.py b/numpy/random/__init__.py index 53e9477975c0..89015d6a29e1 100644 --- a/numpy/random/__init__.py +++ b/numpy/random/__init__.py @@ -83,6 +83,22 @@ set_state Set state of generator. ==================== ========================================================= +==================== ========================================================= +Random Number Streams that work with RandomGenerator +============================================================================== +MT19937 +DSFMT +PCG32 +PCG64 +Philox +ThreeFry +ThreeFry32 +Xoroshiro128 +Xoroshift1024 +Xoshiro256StarStar +Xoshiro512StarStar +==================== ========================================================= + """ from __future__ import division, absolute_import, print_function @@ -136,8 +152,24 @@ 'zipf' ] -from .randomgen import mtrand -from .randomgen.mtrand import * +from . import mtrand +from .mtrand import * +from .dsfmt import DSFMT +from .generator import RandomGenerator +from .mt19937 import MT19937 +from .pcg32 import PCG32 +from .pcg64 import PCG64 +from .philox import Philox +from .threefry import ThreeFry +from .threefry32 import ThreeFry32 +from .xoroshiro128 import Xoroshiro128 +from .xorshift1024 import Xorshift1024 +from .xoshiro256starstar import Xoshiro256StarStar +from .xoshiro512starstar import Xoshiro512StarStar +from .mtrand import RandomState +__all__ += ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'PCG32', 'Philox', + 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024', + 'Xoshiro256StarStar', 'Xoshiro512StarStar', 'RandomState'] # Some aliases: ranf = random = sample = random_sample diff --git a/numpy/random/mtrand/Python.pxi b/numpy/random/_mtrand/Python.pxi similarity index 100% rename from numpy/random/mtrand/Python.pxi rename to numpy/random/_mtrand/Python.pxi diff --git a/numpy/random/mtrand/distributions.c b/numpy/random/_mtrand/distributions.c similarity index 100% rename from numpy/random/mtrand/distributions.c rename to numpy/random/_mtrand/distributions.c diff --git a/numpy/random/mtrand/distributions.h b/numpy/random/_mtrand/distributions.h similarity index 100% rename from numpy/random/mtrand/distributions.h rename to numpy/random/_mtrand/distributions.h diff --git a/numpy/random/mtrand/generate_mtrand_c.py b/numpy/random/_mtrand/generate_mtrand_c.py similarity index 100% rename from numpy/random/mtrand/generate_mtrand_c.py rename to numpy/random/_mtrand/generate_mtrand_c.py diff --git a/numpy/random/mtrand/initarray.c b/numpy/random/_mtrand/initarray.c similarity index 100% rename from numpy/random/mtrand/initarray.c rename to numpy/random/_mtrand/initarray.c diff --git a/numpy/random/mtrand/initarray.h b/numpy/random/_mtrand/initarray.h similarity index 100% rename from numpy/random/mtrand/initarray.h rename to numpy/random/_mtrand/initarray.h diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/_mtrand/mtrand.pyx similarity index 100% rename from numpy/random/mtrand/mtrand.pyx rename to numpy/random/_mtrand/mtrand.pyx diff --git a/numpy/random/mtrand/mtrand_py_helper.h b/numpy/random/_mtrand/mtrand_py_helper.h similarity index 100% rename from numpy/random/mtrand/mtrand_py_helper.h rename to numpy/random/_mtrand/mtrand_py_helper.h diff --git a/numpy/random/mtrand/numpy.pxd b/numpy/random/_mtrand/numpy.pxd similarity index 100% rename from numpy/random/mtrand/numpy.pxd rename to numpy/random/_mtrand/numpy.pxd diff --git a/numpy/random/mtrand/randint_helpers.pxi.in b/numpy/random/_mtrand/randint_helpers.pxi.in similarity index 100% rename from numpy/random/mtrand/randint_helpers.pxi.in rename to numpy/random/_mtrand/randint_helpers.pxi.in diff --git a/numpy/random/mtrand/randomkit.c b/numpy/random/_mtrand/randomkit.c similarity index 100% rename from numpy/random/mtrand/randomkit.c rename to numpy/random/_mtrand/randomkit.c diff --git a/numpy/random/mtrand/randomkit.h b/numpy/random/_mtrand/randomkit.h similarity index 100% rename from numpy/random/mtrand/randomkit.h rename to numpy/random/_mtrand/randomkit.h diff --git a/numpy/random/randomgen/_pickle.py b/numpy/random/_pickle.py similarity index 100% rename from numpy/random/randomgen/_pickle.py rename to numpy/random/_pickle.py diff --git a/numpy/random/randomgen/bounded_integers.pxd.in b/numpy/random/bounded_integers.pxd.in similarity index 100% rename from numpy/random/randomgen/bounded_integers.pxd.in rename to numpy/random/bounded_integers.pxd.in diff --git a/numpy/random/randomgen/bounded_integers.pyx.in b/numpy/random/bounded_integers.pyx.in similarity index 100% rename from numpy/random/randomgen/bounded_integers.pyx.in rename to numpy/random/bounded_integers.pyx.in diff --git a/numpy/random/randomgen/common.pxd b/numpy/random/common.pxd similarity index 100% rename from numpy/random/randomgen/common.pxd rename to numpy/random/common.pxd diff --git a/numpy/random/randomgen/common.pyx b/numpy/random/common.pyx similarity index 100% rename from numpy/random/randomgen/common.pyx rename to numpy/random/common.pyx diff --git a/numpy/random/randomgen/distributions.pxd b/numpy/random/distributions.pxd similarity index 100% rename from numpy/random/randomgen/distributions.pxd rename to numpy/random/distributions.pxd diff --git a/numpy/random/randomgen/dsfmt.pyx b/numpy/random/dsfmt.pyx similarity index 100% rename from numpy/random/randomgen/dsfmt.pyx rename to numpy/random/dsfmt.pyx diff --git a/numpy/random/randomgen/entropy.pyx b/numpy/random/entropy.pyx similarity index 100% rename from numpy/random/randomgen/entropy.pyx rename to numpy/random/entropy.pyx diff --git a/numpy/random/randomgen/examples/cython/extending.pyx b/numpy/random/examples/cython/extending.pyx similarity index 100% rename from numpy/random/randomgen/examples/cython/extending.pyx rename to numpy/random/examples/cython/extending.pyx diff --git a/numpy/random/randomgen/examples/cython/extending_distributions.pyx b/numpy/random/examples/cython/extending_distributions.pyx similarity index 100% rename from numpy/random/randomgen/examples/cython/extending_distributions.pyx rename to numpy/random/examples/cython/extending_distributions.pyx diff --git a/numpy/random/randomgen/examples/cython/setup.py b/numpy/random/examples/cython/setup.py similarity index 100% rename from numpy/random/randomgen/examples/cython/setup.py rename to numpy/random/examples/cython/setup.py diff --git a/numpy/random/randomgen/examples/numba/extending.py b/numpy/random/examples/numba/extending.py similarity index 100% rename from numpy/random/randomgen/examples/numba/extending.py rename to numpy/random/examples/numba/extending.py diff --git a/numpy/random/randomgen/examples/numba/extending_distributions.py b/numpy/random/examples/numba/extending_distributions.py similarity index 100% rename from numpy/random/randomgen/examples/numba/extending_distributions.py rename to numpy/random/examples/numba/extending_distributions.py diff --git a/numpy/random/randomgen/generator.pyx b/numpy/random/generator.pyx similarity index 100% rename from numpy/random/randomgen/generator.pyx rename to numpy/random/generator.pyx diff --git a/numpy/random/randomgen/legacy/__init__.py b/numpy/random/legacy/__init__.py similarity index 100% rename from numpy/random/randomgen/legacy/__init__.py rename to numpy/random/legacy/__init__.py diff --git a/numpy/random/randomgen/legacy/legacy_distributions.pxd b/numpy/random/legacy/legacy_distributions.pxd similarity index 100% rename from numpy/random/randomgen/legacy/legacy_distributions.pxd rename to numpy/random/legacy/legacy_distributions.pxd diff --git a/numpy/random/randomgen/mt19937.pyx b/numpy/random/mt19937.pyx similarity index 100% rename from numpy/random/randomgen/mt19937.pyx rename to numpy/random/mt19937.pyx diff --git a/numpy/random/randomgen/mtrand.pyx b/numpy/random/mtrand.pyx similarity index 100% rename from numpy/random/randomgen/mtrand.pyx rename to numpy/random/mtrand.pyx diff --git a/numpy/random/randomgen/pcg32.pyx b/numpy/random/pcg32.pyx similarity index 100% rename from numpy/random/randomgen/pcg32.pyx rename to numpy/random/pcg32.pyx diff --git a/numpy/random/randomgen/pcg64.pyx b/numpy/random/pcg64.pyx similarity index 100% rename from numpy/random/randomgen/pcg64.pyx rename to numpy/random/pcg64.pyx diff --git a/numpy/random/randomgen/philox.pyx b/numpy/random/philox.pyx similarity index 100% rename from numpy/random/randomgen/philox.pyx rename to numpy/random/philox.pyx diff --git a/numpy/random/randomgen/__init__.py b/numpy/random/randomgen/__init__.py deleted file mode 100644 index 1af2fc3b200c..000000000000 --- a/numpy/random/randomgen/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -from .dsfmt import DSFMT -from .generator import RandomGenerator -from .mt19937 import MT19937 -from .pcg32 import PCG32 -from .pcg64 import PCG64 -from .philox import Philox -from .threefry import ThreeFry -from .threefry32 import ThreeFry32 -from .xoroshiro128 import Xoroshiro128 -from .xorshift1024 import Xorshift1024 -from .xoshiro256starstar import Xoshiro256StarStar -from .xoshiro512starstar import Xoshiro512StarStar -from .mtrand import RandomState -__all__ = ['RandomGenerator', 'DSFMT', 'MT19937', 'PCG64', 'PCG32', 'Philox', - 'ThreeFry', 'ThreeFry32', 'Xoroshiro128', 'Xorshift1024', - 'Xoshiro256StarStar', 'Xoshiro512StarStar', 'RandomState'] - -#from ._version import get_versions - -#__version__ = get_versions()['version'] -#del get_versions diff --git a/numpy/random/randomgen/_version.py b/numpy/random/randomgen/_version.py deleted file mode 100644 index e400e3efb65d..000000000000 --- a/numpy/random/randomgen/_version.py +++ /dev/null @@ -1,520 +0,0 @@ - -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. Generated by -# versioneer-0.18 (https://github.com/warner/python-versioneer) - -"""Git implementation of _version.py.""" - -import errno -import os -import re -import subprocess -import sys - - -def get_keywords(): - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "$Format:%d$" - git_full = "$Format:%H$" - git_date = "$Format:%ci$" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_config(): - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "pep440" - cfg.tag_prefix = "" - cfg.parentdir_prefix = "randomgen-" - cfg.versionfile_source = "randomgen/_version.py" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, p.returncode - return stdout, p.returncode - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%d" % pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -def get_versions(): - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): - root = os.path.dirname(root) - except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} diff --git a/numpy/random/randomgen/setup.py b/numpy/random/randomgen/setup.py deleted file mode 100644 index 5b7be45599c8..000000000000 --- a/numpy/random/randomgen/setup.py +++ /dev/null @@ -1,191 +0,0 @@ -from os.path import join -import sys -import os -import platform -import struct -from distutils.dep_util import newer -from distutils.msvccompiler import get_build_version as get_msvc_build_version - -def needs_mingw_ftime_workaround(): - # We need the mingw workaround for _ftime if the msvc runtime version is - # 7.1 or above and we build with mingw ... - # ... but we can't easily detect compiler version outside distutils command - # context, so we will need to detect in randomkit whether we build with gcc - msver = get_msvc_build_version() - if msver and msver >= 8: - return True - - return False - - -def configuration(parent_package='',top_path=None): - from numpy.distutils.misc_util import Configuration, get_mathlibs - config = Configuration('randomgen', parent_package, top_path) - - def generate_libraries(ext, build_dir): - config_cmd = config.get_config_cmd() - libs = get_mathlibs() - if sys.platform == 'win32': - libs.append('Advapi32') - ext.libraries.extend(libs) - return None - - # enable unix large file support on 32 bit systems - # (64 bit off_t, lseek -> lseek64 etc.) - if sys.platform[:3] == "aix": - defs = [('_LARGE_FILES', None)] - else: - defs = [('_FILE_OFFSET_BITS', '64'), - ('_LARGEFILE_SOURCE', '1'), - ('_LARGEFILE64_SOURCE', '1')] - if needs_mingw_ftime_workaround(): - defs.append(("NPY_NEEDS_MINGW_TIME_WORKAROUND", None)) - - libs = [] - defs.append(('NPY_NO_DEPRECATED_API', 0)) - config.add_data_dir('tests') - - ############################## - # randomgen - ############################## - - # Make a guess as to whether SSE2 is present for now, TODO: Improve - USE_SSE2 = False - for k in platform.uname(): - for val in ('x86', 'i686', 'i386', 'amd64'): - USE_SSE2 = USE_SSE2 or val in k.lower() - print('Building with SSE?: {0}'.format(USE_SSE2)) - if '--no-sse2' in sys.argv: - USE_SSE2 = False - sys.argv.remove('--no-sse2') - - DEBUG = False - PCG_EMULATED_MATH = False - EXTRA_LINK_ARGS = [] - EXTRA_LIBRARIES = ['m'] if os.name != 'nt' else [] - EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else [ - '-std=c99', '-U__GNUC_GNU_INLINE__'] - if os.name == 'nt': - EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] - if DEBUG: - EXTRA_LINK_ARGS += ['-debug'] - EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] - if sys.version_info < (3, 0): - EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] - - PCG64_DEFS = [] - # TODO: remove the unconditional forced emulation, move code from pcg64.pyx - # to an #ifdef - if 1 or sys.maxsize < 2 ** 32 or os.name == 'nt': - # Force emulated mode here - PCG_EMULATED_MATH = True - PCG64_DEFS += [('PCG_FORCE_EMULATED_128BIT_MATH', '1')] - - if struct.calcsize('P') < 8: - PCG_EMULATED_MATH = True - defs.append(('PCG_EMULATED_MATH', int(PCG_EMULATED_MATH))) - - DSFMT_DEFS = [('DSFMT_MEXP', '19937')] - if USE_SSE2: - if os.name == 'nt': - EXTRA_COMPILE_ARGS += ['/wd4146', '/GL'] - if struct.calcsize('P') < 8: - EXTRA_COMPILE_ARGS += ['/arch:SSE2'] - else: - EXTRA_COMPILE_ARGS += ['-msse2'] - DSFMT_DEFS += [('HAVE_SSE2', '1')] - - config.add_extension('entropy', - sources=['entropy.c', 'src/entropy/entropy.c'], - include_dirs=[join('randomgen', 'src', 'entropy')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=[join('src', 'splitmix64', 'splitmix.h'), - join('src', 'entropy', 'entropy.h'), - 'entropy.pyx', - ], - define_macros=defs, - ) - config.add_extension('dsfmt', - sources=['dsfmt.c', 'src/dsfmt/dSFMT.c', - 'src/dsfmt/dSFMT-jump.c', - 'src/aligned_malloc/aligned_malloc.c'], - include_dirs=[join('src', 'dsfmt')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=[join('src', 'dsfmt', 'dsfmt.h'), - 'dsfmt.pyx', - ], - define_macros=defs + DSFMT_DEFS, - ) - for gen in ['mt19937']: - # gen.pyx, src/gen/gen.c, src/gen/gen-jump.c - config.add_extension(gen, - sources=['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen), - 'src/{0}/{0}-jump.c'.format(gen)], - include_dirs=[join('src', gen)], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=['%s.pyx' % gen], - define_macros=defs, - ) - for gen in ['philox', 'threefry', 'threefry32', - 'xoroshiro128', 'xorshift1024', 'xoshiro256starstar', - 'xoshiro512starstar', - 'pcg64', 'pcg32', - ]: - # gen.pyx, src/gen/gen.c - if gen == 'pcg64': - _defs = defs + PCG64_DEFS - else: - _defs = defs - config.add_extension(gen, - sources=['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen)], - include_dirs=[join('src', gen)], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=['%s.pyx' % gen], - define_macros=_defs, - ) - for gen in ['common']: - # gen.pyx - config.add_extension(gen, - sources=['{0}.c'.format(gen)], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=['%s.pyx' % gen], - define_macros=defs, - ) - for gen in ['generator', 'bounded_integers']: - # gen.pyx, src/distributions/distributions.c - config.add_extension(gen, - sources=['{0}.c'.format(gen), - join('src', 'distributions', - 'distributions.c')], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=['%s.pyx' % gen], - define_macros=defs, - ) - config.add_extension('mtrand', - sources=['mtrand.c', - 'src/legacy/distributions-boxmuller.c', - 'src/distributions/distributions.c' ], - include_dirs=['.', 'legacy'], - libraries=EXTRA_LIBRARIES, - extra_compile_args=EXTRA_COMPILE_ARGS, - extra_link_args=EXTRA_LINK_ARGS, - depends=['mtrand.pyx'], - define_macros=defs + DSFMT_DEFS, - ) - config.add_subpackage('legacy') - return config -if __name__ == '__main__': - from numpy.distutils.core import setup - setup(configuration=configuration) diff --git a/numpy/random/randomgen/tests/data/__init__.py b/numpy/random/randomgen/tests/data/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/numpy/random/setup.py b/numpy/random/setup.py index 481c4e380a88..088764791bb1 100644 --- a/numpy/random/setup.py +++ b/numpy/random/setup.py @@ -46,21 +46,160 @@ def generate_libraries(ext, build_dir): libs = [] defs.append(('NPY_NO_DEPRECATED_API', 0)) # Configure mtrand - config.add_extension('mtrand', - sources=[join('mtrand', x) for x in + config.add_extension('_mtrand', + sources=[join('_mtrand', x) for x in ['mtrand.c', 'randomkit.c', 'initarray.c', 'distributions.c']]+[generate_libraries], libraries=libs, - depends=[join('mtrand', '*.h'), - join('mtrand', '*.pyx'), - join('mtrand', '*.pxi'),], + depends=[join('_mtrand', '*.h'), + join('_mtrand', '*.pyx'), + join('_mtrand', '*.pxi'),], define_macros=defs, ) - config.add_data_files(('.', join('mtrand', 'randomkit.h'))) + config.add_data_files(('.', join('_mtrand', 'randomkit.h'))) config.add_data_dir('tests') - config.add_subpackage('randomgen') + ############################## + # randomgen + ############################## + + # Make a guess as to whether SSE2 is present for now, TODO: Improve + USE_SSE2 = False + for k in platform.uname(): + for val in ('x86', 'i686', 'i386', 'amd64'): + USE_SSE2 = USE_SSE2 or val in k.lower() + print('Building with SSE?: {0}'.format(USE_SSE2)) + if '--no-sse2' in sys.argv: + USE_SSE2 = False + sys.argv.remove('--no-sse2') + + DEBUG = False + PCG_EMULATED_MATH = False + EXTRA_LINK_ARGS = [] + EXTRA_LIBRARIES = ['m'] if os.name != 'nt' else [] + EXTRA_COMPILE_ARGS = [] if os.name == 'nt' else [ + '-std=c99', '-U__GNUC_GNU_INLINE__'] + if os.name == 'nt': + EXTRA_LINK_ARGS = ['/LTCG', '/OPT:REF', 'Advapi32.lib', 'Kernel32.lib'] + if DEBUG: + EXTRA_LINK_ARGS += ['-debug'] + EXTRA_COMPILE_ARGS += ["-Zi", "/Od"] + if sys.version_info < (3, 0): + EXTRA_INCLUDE_DIRS += [join(MOD_DIR, 'src', 'common')] + + PCG64_DEFS = [] + # TODO: remove the unconditional forced emulation, move code from pcg64.pyx + # to an #ifdef + if 1 or sys.maxsize < 2 ** 32 or os.name == 'nt': + # Force emulated mode here + PCG_EMULATED_MATH = True + PCG64_DEFS += [('PCG_FORCE_EMULATED_128BIT_MATH', '1')] + + if struct.calcsize('P') < 8: + PCG_EMULATED_MATH = True + defs.append(('PCG_EMULATED_MATH', int(PCG_EMULATED_MATH))) + + DSFMT_DEFS = [('DSFMT_MEXP', '19937')] + if USE_SSE2: + if os.name == 'nt': + EXTRA_COMPILE_ARGS += ['/wd4146', '/GL'] + if struct.calcsize('P') < 8: + EXTRA_COMPILE_ARGS += ['/arch:SSE2'] + else: + EXTRA_COMPILE_ARGS += ['-msse2'] + DSFMT_DEFS += [('HAVE_SSE2', '1')] + + config.add_extension('entropy', + sources=['entropy.c', 'src/entropy/entropy.c'], + include_dirs=[join('randomgen', 'src', 'entropy')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('src', 'splitmix64', 'splitmix.h'), + join('src', 'entropy', 'entropy.h'), + 'entropy.pyx', + ], + define_macros=defs, + ) + config.add_extension('dsfmt', + sources=['dsfmt.c', 'src/dsfmt/dSFMT.c', + 'src/dsfmt/dSFMT-jump.c', + 'src/aligned_malloc/aligned_malloc.c'], + include_dirs=[join('src', 'dsfmt')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=[join('src', 'dsfmt', 'dsfmt.h'), + 'dsfmt.pyx', + ], + define_macros=defs + DSFMT_DEFS, + ) + for gen in ['mt19937']: + # gen.pyx, src/gen/gen.c, src/gen/gen-jump.c + config.add_extension(gen, + sources=['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen), + 'src/{0}/{0}-jump.c'.format(gen)], + include_dirs=[join('src', gen)], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=['%s.pyx' % gen], + define_macros=defs, + ) + for gen in ['philox', 'threefry', 'threefry32', + 'xoroshiro128', 'xorshift1024', 'xoshiro256starstar', + 'xoshiro512starstar', + 'pcg64', 'pcg32', + ]: + # gen.pyx, src/gen/gen.c + if gen == 'pcg64': + _defs = defs + PCG64_DEFS + else: + _defs = defs + config.add_extension(gen, + sources=['{0}.c'.format(gen), 'src/{0}/{0}.c'.format(gen)], + include_dirs=[join('src', gen)], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=['%s.pyx' % gen], + define_macros=_defs, + ) + for gen in ['common']: + # gen.pyx + config.add_extension(gen, + sources=['{0}.c'.format(gen)], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=['%s.pyx' % gen], + define_macros=defs, + ) + for gen in ['generator', 'bounded_integers']: + # gen.pyx, src/distributions/distributions.c + config.add_extension(gen, + sources=['{0}.c'.format(gen), + join('src', 'distributions', + 'distributions.c')], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=['%s.pyx' % gen], + define_macros=defs, + ) + config.add_extension('mtrand', + sources=['mtrand.c', + 'src/legacy/distributions-boxmuller.c', + 'src/distributions/distributions.c' ], + include_dirs=['.', 'legacy'], + libraries=EXTRA_LIBRARIES, + extra_compile_args=EXTRA_COMPILE_ARGS, + extra_link_args=EXTRA_LINK_ARGS, + depends=['mtrand.pyx'], + define_macros=defs + DSFMT_DEFS, + ) + config.add_subpackage('legacy') return config if __name__ == '__main__': diff --git a/numpy/random/randomgen/src/aligned_malloc/aligned_malloc.c b/numpy/random/src/aligned_malloc/aligned_malloc.c similarity index 100% rename from numpy/random/randomgen/src/aligned_malloc/aligned_malloc.c rename to numpy/random/src/aligned_malloc/aligned_malloc.c diff --git a/numpy/random/randomgen/src/aligned_malloc/aligned_malloc.h b/numpy/random/src/aligned_malloc/aligned_malloc.h similarity index 100% rename from numpy/random/randomgen/src/aligned_malloc/aligned_malloc.h rename to numpy/random/src/aligned_malloc/aligned_malloc.h diff --git a/numpy/random/randomgen/src/common/LICENSE.md b/numpy/random/src/common/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/common/LICENSE.md rename to numpy/random/src/common/LICENSE.md diff --git a/numpy/random/randomgen/src/common/inttypes.h b/numpy/random/src/common/inttypes.h similarity index 100% rename from numpy/random/randomgen/src/common/inttypes.h rename to numpy/random/src/common/inttypes.h diff --git a/numpy/random/randomgen/src/common/stdint.h b/numpy/random/src/common/stdint.h similarity index 100% rename from numpy/random/randomgen/src/common/stdint.h rename to numpy/random/src/common/stdint.h diff --git a/numpy/random/randomgen/src/distributions/LICENSE.md b/numpy/random/src/distributions/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/distributions/LICENSE.md rename to numpy/random/src/distributions/LICENSE.md diff --git a/numpy/random/randomgen/src/distributions/binomial.h b/numpy/random/src/distributions/binomial.h similarity index 100% rename from numpy/random/randomgen/src/distributions/binomial.h rename to numpy/random/src/distributions/binomial.h diff --git a/numpy/random/randomgen/src/distributions/distributions.c b/numpy/random/src/distributions/distributions.c similarity index 100% rename from numpy/random/randomgen/src/distributions/distributions.c rename to numpy/random/src/distributions/distributions.c diff --git a/numpy/random/randomgen/src/distributions/distributions.h b/numpy/random/src/distributions/distributions.h similarity index 100% rename from numpy/random/randomgen/src/distributions/distributions.h rename to numpy/random/src/distributions/distributions.h diff --git a/numpy/random/randomgen/src/distributions/ziggurat.h b/numpy/random/src/distributions/ziggurat.h similarity index 100% rename from numpy/random/randomgen/src/distributions/ziggurat.h rename to numpy/random/src/distributions/ziggurat.h diff --git a/numpy/random/randomgen/src/distributions/ziggurat_constants.h b/numpy/random/src/distributions/ziggurat_constants.h similarity index 100% rename from numpy/random/randomgen/src/distributions/ziggurat_constants.h rename to numpy/random/src/distributions/ziggurat_constants.h diff --git a/numpy/random/randomgen/src/dsfmt/128-bit-jump.poly.txt b/numpy/random/src/dsfmt/128-bit-jump.poly.txt similarity index 100% rename from numpy/random/randomgen/src/dsfmt/128-bit-jump.poly.txt rename to numpy/random/src/dsfmt/128-bit-jump.poly.txt diff --git a/numpy/random/randomgen/src/dsfmt/96-bit-jump.poly.txt b/numpy/random/src/dsfmt/96-bit-jump.poly.txt similarity index 100% rename from numpy/random/randomgen/src/dsfmt/96-bit-jump.poly.txt rename to numpy/random/src/dsfmt/96-bit-jump.poly.txt diff --git a/numpy/random/randomgen/src/dsfmt/LICENSE.md b/numpy/random/src/dsfmt/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/dsfmt/LICENSE.md rename to numpy/random/src/dsfmt/LICENSE.md diff --git a/numpy/random/randomgen/src/dsfmt/calc-jump.cpp b/numpy/random/src/dsfmt/calc-jump.cpp similarity index 100% rename from numpy/random/randomgen/src/dsfmt/calc-jump.cpp rename to numpy/random/src/dsfmt/calc-jump.cpp diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT-benchmark.c b/numpy/random/src/dsfmt/dSFMT-benchmark.c similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT-benchmark.c rename to numpy/random/src/dsfmt/dSFMT-benchmark.c diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT-calc-jump.hpp b/numpy/random/src/dsfmt/dSFMT-calc-jump.hpp similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT-calc-jump.hpp rename to numpy/random/src/dsfmt/dSFMT-calc-jump.hpp diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT-common.h b/numpy/random/src/dsfmt/dSFMT-common.h similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT-common.h rename to numpy/random/src/dsfmt/dSFMT-common.h diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT-jump.c b/numpy/random/src/dsfmt/dSFMT-jump.c similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT-jump.c rename to numpy/random/src/dsfmt/dSFMT-jump.c diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT-jump.h b/numpy/random/src/dsfmt/dSFMT-jump.h similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT-jump.h rename to numpy/random/src/dsfmt/dSFMT-jump.h diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT-params.h b/numpy/random/src/dsfmt/dSFMT-params.h similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT-params.h rename to numpy/random/src/dsfmt/dSFMT-params.h diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT-params19937.h b/numpy/random/src/dsfmt/dSFMT-params19937.h similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT-params19937.h rename to numpy/random/src/dsfmt/dSFMT-params19937.h diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT-poly.h b/numpy/random/src/dsfmt/dSFMT-poly.h similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT-poly.h rename to numpy/random/src/dsfmt/dSFMT-poly.h diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT-test-gen.c b/numpy/random/src/dsfmt/dSFMT-test-gen.c similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT-test-gen.c rename to numpy/random/src/dsfmt/dSFMT-test-gen.c diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT.c b/numpy/random/src/dsfmt/dSFMT.c similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT.c rename to numpy/random/src/dsfmt/dSFMT.c diff --git a/numpy/random/randomgen/src/dsfmt/dSFMT.h b/numpy/random/src/dsfmt/dSFMT.h similarity index 100% rename from numpy/random/randomgen/src/dsfmt/dSFMT.h rename to numpy/random/src/dsfmt/dSFMT.h diff --git a/numpy/random/randomgen/src/entropy/LICENSE.md b/numpy/random/src/entropy/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/entropy/LICENSE.md rename to numpy/random/src/entropy/LICENSE.md diff --git a/numpy/random/randomgen/src/entropy/entropy.c b/numpy/random/src/entropy/entropy.c similarity index 100% rename from numpy/random/randomgen/src/entropy/entropy.c rename to numpy/random/src/entropy/entropy.c diff --git a/numpy/random/randomgen/src/entropy/entropy.h b/numpy/random/src/entropy/entropy.h similarity index 100% rename from numpy/random/randomgen/src/entropy/entropy.h rename to numpy/random/src/entropy/entropy.h diff --git a/numpy/random/randomgen/src/legacy/LICENSE.md b/numpy/random/src/legacy/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/legacy/LICENSE.md rename to numpy/random/src/legacy/LICENSE.md diff --git a/numpy/random/randomgen/src/legacy/distributions-boxmuller.c b/numpy/random/src/legacy/distributions-boxmuller.c similarity index 100% rename from numpy/random/randomgen/src/legacy/distributions-boxmuller.c rename to numpy/random/src/legacy/distributions-boxmuller.c diff --git a/numpy/random/randomgen/src/legacy/distributions-boxmuller.h b/numpy/random/src/legacy/distributions-boxmuller.h similarity index 100% rename from numpy/random/randomgen/src/legacy/distributions-boxmuller.h rename to numpy/random/src/legacy/distributions-boxmuller.h diff --git a/numpy/random/randomgen/src/mt19937/LICENSE.md b/numpy/random/src/mt19937/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/mt19937/LICENSE.md rename to numpy/random/src/mt19937/LICENSE.md diff --git a/numpy/random/randomgen/src/mt19937/mt19937-benchmark.c b/numpy/random/src/mt19937/mt19937-benchmark.c similarity index 100% rename from numpy/random/randomgen/src/mt19937/mt19937-benchmark.c rename to numpy/random/src/mt19937/mt19937-benchmark.c diff --git a/numpy/random/randomgen/src/mt19937/mt19937-jump.c b/numpy/random/src/mt19937/mt19937-jump.c similarity index 100% rename from numpy/random/randomgen/src/mt19937/mt19937-jump.c rename to numpy/random/src/mt19937/mt19937-jump.c diff --git a/numpy/random/randomgen/src/mt19937/mt19937-jump.h b/numpy/random/src/mt19937/mt19937-jump.h similarity index 100% rename from numpy/random/randomgen/src/mt19937/mt19937-jump.h rename to numpy/random/src/mt19937/mt19937-jump.h diff --git a/numpy/random/randomgen/src/mt19937/mt19937-poly.h b/numpy/random/src/mt19937/mt19937-poly.h similarity index 100% rename from numpy/random/randomgen/src/mt19937/mt19937-poly.h rename to numpy/random/src/mt19937/mt19937-poly.h diff --git a/numpy/random/randomgen/src/mt19937/mt19937-test-data-gen.c b/numpy/random/src/mt19937/mt19937-test-data-gen.c similarity index 100% rename from numpy/random/randomgen/src/mt19937/mt19937-test-data-gen.c rename to numpy/random/src/mt19937/mt19937-test-data-gen.c diff --git a/numpy/random/randomgen/src/mt19937/mt19937.c b/numpy/random/src/mt19937/mt19937.c similarity index 100% rename from numpy/random/randomgen/src/mt19937/mt19937.c rename to numpy/random/src/mt19937/mt19937.c diff --git a/numpy/random/randomgen/src/mt19937/mt19937.h b/numpy/random/src/mt19937/mt19937.h similarity index 100% rename from numpy/random/randomgen/src/mt19937/mt19937.h rename to numpy/random/src/mt19937/mt19937.h diff --git a/numpy/random/randomgen/src/mt19937/randomkit.c b/numpy/random/src/mt19937/randomkit.c similarity index 100% rename from numpy/random/randomgen/src/mt19937/randomkit.c rename to numpy/random/src/mt19937/randomkit.c diff --git a/numpy/random/randomgen/src/mt19937/randomkit.h b/numpy/random/src/mt19937/randomkit.h similarity index 100% rename from numpy/random/randomgen/src/mt19937/randomkit.h rename to numpy/random/src/mt19937/randomkit.h diff --git a/numpy/random/randomgen/src/pcg32/LICENSE.md b/numpy/random/src/pcg32/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/pcg32/LICENSE.md rename to numpy/random/src/pcg32/LICENSE.md diff --git a/numpy/random/randomgen/src/pcg32/pcg-advance-64.c b/numpy/random/src/pcg32/pcg-advance-64.c similarity index 100% rename from numpy/random/randomgen/src/pcg32/pcg-advance-64.c rename to numpy/random/src/pcg32/pcg-advance-64.c diff --git a/numpy/random/randomgen/src/pcg32/pcg32-test-data-gen.c b/numpy/random/src/pcg32/pcg32-test-data-gen.c similarity index 100% rename from numpy/random/randomgen/src/pcg32/pcg32-test-data-gen.c rename to numpy/random/src/pcg32/pcg32-test-data-gen.c diff --git a/numpy/random/randomgen/src/pcg32/pcg32.c b/numpy/random/src/pcg32/pcg32.c similarity index 100% rename from numpy/random/randomgen/src/pcg32/pcg32.c rename to numpy/random/src/pcg32/pcg32.c diff --git a/numpy/random/randomgen/src/pcg32/pcg32.h b/numpy/random/src/pcg32/pcg32.h similarity index 100% rename from numpy/random/randomgen/src/pcg32/pcg32.h rename to numpy/random/src/pcg32/pcg32.h diff --git a/numpy/random/randomgen/src/pcg32/pcg_variants.h b/numpy/random/src/pcg32/pcg_variants.h similarity index 100% rename from numpy/random/randomgen/src/pcg32/pcg_variants.h rename to numpy/random/src/pcg32/pcg_variants.h diff --git a/numpy/random/randomgen/src/pcg64/LICENSE.md b/numpy/random/src/pcg64/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/pcg64/LICENSE.md rename to numpy/random/src/pcg64/LICENSE.md diff --git a/numpy/random/randomgen/src/pcg64/pcg64-benchmark.c b/numpy/random/src/pcg64/pcg64-benchmark.c similarity index 100% rename from numpy/random/randomgen/src/pcg64/pcg64-benchmark.c rename to numpy/random/src/pcg64/pcg64-benchmark.c diff --git a/numpy/random/randomgen/src/pcg64/pcg64-test-data-gen.c b/numpy/random/src/pcg64/pcg64-test-data-gen.c similarity index 100% rename from numpy/random/randomgen/src/pcg64/pcg64-test-data-gen.c rename to numpy/random/src/pcg64/pcg64-test-data-gen.c diff --git a/numpy/random/randomgen/src/pcg64/pcg64.c b/numpy/random/src/pcg64/pcg64.c similarity index 100% rename from numpy/random/randomgen/src/pcg64/pcg64.c rename to numpy/random/src/pcg64/pcg64.c diff --git a/numpy/random/randomgen/src/pcg64/pcg64.h b/numpy/random/src/pcg64/pcg64.h similarity index 100% rename from numpy/random/randomgen/src/pcg64/pcg64.h rename to numpy/random/src/pcg64/pcg64.h diff --git a/numpy/random/randomgen/src/pcg64/pcg64.orig.c b/numpy/random/src/pcg64/pcg64.orig.c similarity index 100% rename from numpy/random/randomgen/src/pcg64/pcg64.orig.c rename to numpy/random/src/pcg64/pcg64.orig.c diff --git a/numpy/random/randomgen/src/pcg64/pcg64.orig.h b/numpy/random/src/pcg64/pcg64.orig.h similarity index 100% rename from numpy/random/randomgen/src/pcg64/pcg64.orig.h rename to numpy/random/src/pcg64/pcg64.orig.h diff --git a/numpy/random/randomgen/src/philox/LICENSE.md b/numpy/random/src/philox/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/philox/LICENSE.md rename to numpy/random/src/philox/LICENSE.md diff --git a/numpy/random/randomgen/src/philox/philox-benchmark.c b/numpy/random/src/philox/philox-benchmark.c similarity index 100% rename from numpy/random/randomgen/src/philox/philox-benchmark.c rename to numpy/random/src/philox/philox-benchmark.c diff --git a/numpy/random/randomgen/src/philox/philox-test-data-gen.c b/numpy/random/src/philox/philox-test-data-gen.c similarity index 100% rename from numpy/random/randomgen/src/philox/philox-test-data-gen.c rename to numpy/random/src/philox/philox-test-data-gen.c diff --git a/numpy/random/randomgen/src/philox/philox.c b/numpy/random/src/philox/philox.c similarity index 100% rename from numpy/random/randomgen/src/philox/philox.c rename to numpy/random/src/philox/philox.c diff --git a/numpy/random/randomgen/src/philox/philox.h b/numpy/random/src/philox/philox.h similarity index 100% rename from numpy/random/randomgen/src/philox/philox.h rename to numpy/random/src/philox/philox.h diff --git a/numpy/random/randomgen/src/splitmix64/LICENSE.md b/numpy/random/src/splitmix64/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/splitmix64/LICENSE.md rename to numpy/random/src/splitmix64/LICENSE.md diff --git a/numpy/random/randomgen/src/splitmix64/splitmix64.c b/numpy/random/src/splitmix64/splitmix64.c similarity index 100% rename from numpy/random/randomgen/src/splitmix64/splitmix64.c rename to numpy/random/src/splitmix64/splitmix64.c diff --git a/numpy/random/randomgen/src/splitmix64/splitmix64.h b/numpy/random/src/splitmix64/splitmix64.h similarity index 100% rename from numpy/random/randomgen/src/splitmix64/splitmix64.h rename to numpy/random/src/splitmix64/splitmix64.h diff --git a/numpy/random/randomgen/src/splitmix64/splitmix64.orig.c b/numpy/random/src/splitmix64/splitmix64.orig.c similarity index 100% rename from numpy/random/randomgen/src/splitmix64/splitmix64.orig.c rename to numpy/random/src/splitmix64/splitmix64.orig.c diff --git a/numpy/random/randomgen/src/threefry/LICENSE.md b/numpy/random/src/threefry/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/threefry/LICENSE.md rename to numpy/random/src/threefry/LICENSE.md diff --git a/numpy/random/randomgen/src/threefry/threefry-benchmark.c b/numpy/random/src/threefry/threefry-benchmark.c similarity index 100% rename from numpy/random/randomgen/src/threefry/threefry-benchmark.c rename to numpy/random/src/threefry/threefry-benchmark.c diff --git a/numpy/random/randomgen/src/threefry/threefry-orig.c b/numpy/random/src/threefry/threefry-orig.c similarity index 100% rename from numpy/random/randomgen/src/threefry/threefry-orig.c rename to numpy/random/src/threefry/threefry-orig.c diff --git a/numpy/random/randomgen/src/threefry/threefry-test-data-gen.c b/numpy/random/src/threefry/threefry-test-data-gen.c similarity index 100% rename from numpy/random/randomgen/src/threefry/threefry-test-data-gen.c rename to numpy/random/src/threefry/threefry-test-data-gen.c diff --git a/numpy/random/randomgen/src/threefry/threefry.c b/numpy/random/src/threefry/threefry.c similarity index 100% rename from numpy/random/randomgen/src/threefry/threefry.c rename to numpy/random/src/threefry/threefry.c diff --git a/numpy/random/randomgen/src/threefry/threefry.h b/numpy/random/src/threefry/threefry.h similarity index 100% rename from numpy/random/randomgen/src/threefry/threefry.h rename to numpy/random/src/threefry/threefry.h diff --git a/numpy/random/randomgen/src/threefry32/LICENSE.md b/numpy/random/src/threefry32/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/threefry32/LICENSE.md rename to numpy/random/src/threefry32/LICENSE.md diff --git a/numpy/random/randomgen/src/threefry32/threefry32-test-data-gen.c b/numpy/random/src/threefry32/threefry32-test-data-gen.c similarity index 100% rename from numpy/random/randomgen/src/threefry32/threefry32-test-data-gen.c rename to numpy/random/src/threefry32/threefry32-test-data-gen.c diff --git a/numpy/random/randomgen/src/threefry32/threefry32.c b/numpy/random/src/threefry32/threefry32.c similarity index 100% rename from numpy/random/randomgen/src/threefry32/threefry32.c rename to numpy/random/src/threefry32/threefry32.c diff --git a/numpy/random/randomgen/src/threefry32/threefry32.h b/numpy/random/src/threefry32/threefry32.h similarity index 100% rename from numpy/random/randomgen/src/threefry32/threefry32.h rename to numpy/random/src/threefry32/threefry32.h diff --git a/numpy/random/randomgen/src/xoroshiro128/LICENSE.md b/numpy/random/src/xoroshiro128/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/xoroshiro128/LICENSE.md rename to numpy/random/src/xoroshiro128/LICENSE.md diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c b/numpy/random/src/xoroshiro128/xoroshiro128-benchmark.c similarity index 100% rename from numpy/random/randomgen/src/xoroshiro128/xoroshiro128-benchmark.c rename to numpy/random/src/xoroshiro128/xoroshiro128-benchmark.c diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c b/numpy/random/src/xoroshiro128/xoroshiro128-test-data-gen.c similarity index 100% rename from numpy/random/randomgen/src/xoroshiro128/xoroshiro128-test-data-gen.c rename to numpy/random/src/xoroshiro128/xoroshiro128-test-data-gen.c diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.c b/numpy/random/src/xoroshiro128/xoroshiro128.c similarity index 100% rename from numpy/random/randomgen/src/xoroshiro128/xoroshiro128.c rename to numpy/random/src/xoroshiro128/xoroshiro128.c diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128.h b/numpy/random/src/xoroshiro128/xoroshiro128.h similarity index 100% rename from numpy/random/randomgen/src/xoroshiro128/xoroshiro128.h rename to numpy/random/src/xoroshiro128/xoroshiro128.h diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c b/numpy/random/src/xoroshiro128/xoroshiro128plus.orig.c similarity index 100% rename from numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.c rename to numpy/random/src/xoroshiro128/xoroshiro128plus.orig.c diff --git a/numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.h b/numpy/random/src/xoroshiro128/xoroshiro128plus.orig.h similarity index 100% rename from numpy/random/randomgen/src/xoroshiro128/xoroshiro128plus.orig.h rename to numpy/random/src/xoroshiro128/xoroshiro128plus.orig.h diff --git a/numpy/random/randomgen/src/xorshift1024/LICENSE.md b/numpy/random/src/xorshift1024/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/xorshift1024/LICENSE.md rename to numpy/random/src/xorshift1024/LICENSE.md diff --git a/numpy/random/randomgen/src/xorshift1024/xorshift1024-benchmark.c b/numpy/random/src/xorshift1024/xorshift1024-benchmark.c similarity index 100% rename from numpy/random/randomgen/src/xorshift1024/xorshift1024-benchmark.c rename to numpy/random/src/xorshift1024/xorshift1024-benchmark.c diff --git a/numpy/random/randomgen/src/xorshift1024/xorshift1024-test-data-gen.c b/numpy/random/src/xorshift1024/xorshift1024-test-data-gen.c similarity index 100% rename from numpy/random/randomgen/src/xorshift1024/xorshift1024-test-data-gen.c rename to numpy/random/src/xorshift1024/xorshift1024-test-data-gen.c diff --git a/numpy/random/randomgen/src/xorshift1024/xorshift1024.c b/numpy/random/src/xorshift1024/xorshift1024.c similarity index 100% rename from numpy/random/randomgen/src/xorshift1024/xorshift1024.c rename to numpy/random/src/xorshift1024/xorshift1024.c diff --git a/numpy/random/randomgen/src/xorshift1024/xorshift1024.h b/numpy/random/src/xorshift1024/xorshift1024.h similarity index 100% rename from numpy/random/randomgen/src/xorshift1024/xorshift1024.h rename to numpy/random/src/xorshift1024/xorshift1024.h diff --git a/numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.c b/numpy/random/src/xorshift1024/xorshift1024.orig.c similarity index 100% rename from numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.c rename to numpy/random/src/xorshift1024/xorshift1024.orig.c diff --git a/numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.h b/numpy/random/src/xorshift1024/xorshift1024.orig.h similarity index 100% rename from numpy/random/randomgen/src/xorshift1024/xorshift1024.orig.h rename to numpy/random/src/xorshift1024/xorshift1024.orig.h diff --git a/numpy/random/randomgen/src/xoshiro256starstar/LICENSE.md b/numpy/random/src/xoshiro256starstar/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/xoshiro256starstar/LICENSE.md rename to numpy/random/src/xoshiro256starstar/LICENSE.md diff --git a/numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c b/numpy/random/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c similarity index 100% rename from numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c rename to numpy/random/src/xoshiro256starstar/xoshiro256starstar-test-data-gen.c diff --git a/numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.c b/numpy/random/src/xoshiro256starstar/xoshiro256starstar.c similarity index 100% rename from numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.c rename to numpy/random/src/xoshiro256starstar/xoshiro256starstar.c diff --git a/numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.h b/numpy/random/src/xoshiro256starstar/xoshiro256starstar.h similarity index 100% rename from numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.h rename to numpy/random/src/xoshiro256starstar/xoshiro256starstar.h diff --git a/numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c b/numpy/random/src/xoshiro256starstar/xoshiro256starstar.orig.c similarity index 100% rename from numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.c rename to numpy/random/src/xoshiro256starstar/xoshiro256starstar.orig.c diff --git a/numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h b/numpy/random/src/xoshiro256starstar/xoshiro256starstar.orig.h similarity index 100% rename from numpy/random/randomgen/src/xoshiro256starstar/xoshiro256starstar.orig.h rename to numpy/random/src/xoshiro256starstar/xoshiro256starstar.orig.h diff --git a/numpy/random/randomgen/src/xoshiro512starstar/LICENSE.md b/numpy/random/src/xoshiro512starstar/LICENSE.md similarity index 100% rename from numpy/random/randomgen/src/xoshiro512starstar/LICENSE.md rename to numpy/random/src/xoshiro512starstar/LICENSE.md diff --git a/numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c b/numpy/random/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c similarity index 100% rename from numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c rename to numpy/random/src/xoshiro512starstar/xoshiro512starstar-test-data-gen.c diff --git a/numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.c b/numpy/random/src/xoshiro512starstar/xoshiro512starstar.c similarity index 100% rename from numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.c rename to numpy/random/src/xoshiro512starstar/xoshiro512starstar.c diff --git a/numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.h b/numpy/random/src/xoshiro512starstar/xoshiro512starstar.h similarity index 100% rename from numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.h rename to numpy/random/src/xoshiro512starstar/xoshiro512starstar.h diff --git a/numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c b/numpy/random/src/xoshiro512starstar/xoshiro512starstar.orig.c similarity index 100% rename from numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.c rename to numpy/random/src/xoshiro512starstar/xoshiro512starstar.orig.c diff --git a/numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h b/numpy/random/src/xoshiro512starstar/xoshiro512starstar.orig.h similarity index 100% rename from numpy/random/randomgen/src/xoshiro512starstar/xoshiro512starstar.orig.h rename to numpy/random/src/xoshiro512starstar/xoshiro512starstar.orig.h diff --git a/numpy/random/randomgen/tests/__init__.py b/numpy/random/tests/data/__init__.py similarity index 100% rename from numpy/random/randomgen/tests/__init__.py rename to numpy/random/tests/data/__init__.py diff --git a/numpy/random/randomgen/tests/data/dSFMT-testset-1.csv b/numpy/random/tests/data/dSFMT-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/dSFMT-testset-1.csv rename to numpy/random/tests/data/dSFMT-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/dSFMT-testset-2.csv b/numpy/random/tests/data/dSFMT-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/dSFMT-testset-2.csv rename to numpy/random/tests/data/dSFMT-testset-2.csv diff --git a/numpy/random/randomgen/tests/data/mt19937-testset-1.csv b/numpy/random/tests/data/mt19937-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/mt19937-testset-1.csv rename to numpy/random/tests/data/mt19937-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/mt19937-testset-2.csv b/numpy/random/tests/data/mt19937-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/mt19937-testset-2.csv rename to numpy/random/tests/data/mt19937-testset-2.csv diff --git a/numpy/random/randomgen/tests/data/pcg32-testset-1.csv b/numpy/random/tests/data/pcg32-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/pcg32-testset-1.csv rename to numpy/random/tests/data/pcg32-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/pcg32-testset-2.csv b/numpy/random/tests/data/pcg32-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/pcg32-testset-2.csv rename to numpy/random/tests/data/pcg32-testset-2.csv diff --git a/numpy/random/randomgen/tests/data/pcg64-testset-1.csv b/numpy/random/tests/data/pcg64-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/pcg64-testset-1.csv rename to numpy/random/tests/data/pcg64-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/pcg64-testset-2.csv b/numpy/random/tests/data/pcg64-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/pcg64-testset-2.csv rename to numpy/random/tests/data/pcg64-testset-2.csv diff --git a/numpy/random/randomgen/tests/data/philox-testset-1.csv b/numpy/random/tests/data/philox-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/philox-testset-1.csv rename to numpy/random/tests/data/philox-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/philox-testset-2.csv b/numpy/random/tests/data/philox-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/philox-testset-2.csv rename to numpy/random/tests/data/philox-testset-2.csv diff --git a/numpy/random/randomgen/tests/data/threefry-testset-1.csv b/numpy/random/tests/data/threefry-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/threefry-testset-1.csv rename to numpy/random/tests/data/threefry-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/threefry-testset-2.csv b/numpy/random/tests/data/threefry-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/threefry-testset-2.csv rename to numpy/random/tests/data/threefry-testset-2.csv diff --git a/numpy/random/randomgen/tests/data/threefry32-testset-1.csv b/numpy/random/tests/data/threefry32-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/threefry32-testset-1.csv rename to numpy/random/tests/data/threefry32-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/threefry32-testset-2.csv b/numpy/random/tests/data/threefry32-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/threefry32-testset-2.csv rename to numpy/random/tests/data/threefry32-testset-2.csv diff --git a/numpy/random/randomgen/tests/data/xoroshiro128-testset-1.csv b/numpy/random/tests/data/xoroshiro128-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/xoroshiro128-testset-1.csv rename to numpy/random/tests/data/xoroshiro128-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/xoroshiro128-testset-2.csv b/numpy/random/tests/data/xoroshiro128-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/xoroshiro128-testset-2.csv rename to numpy/random/tests/data/xoroshiro128-testset-2.csv diff --git a/numpy/random/randomgen/tests/data/xorshift1024-testset-1.csv b/numpy/random/tests/data/xorshift1024-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/xorshift1024-testset-1.csv rename to numpy/random/tests/data/xorshift1024-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/xorshift1024-testset-2.csv b/numpy/random/tests/data/xorshift1024-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/xorshift1024-testset-2.csv rename to numpy/random/tests/data/xorshift1024-testset-2.csv diff --git a/numpy/random/randomgen/tests/data/xoshiro256starstar-testset-1.csv b/numpy/random/tests/data/xoshiro256starstar-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/xoshiro256starstar-testset-1.csv rename to numpy/random/tests/data/xoshiro256starstar-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/xoshiro256starstar-testset-2.csv b/numpy/random/tests/data/xoshiro256starstar-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/xoshiro256starstar-testset-2.csv rename to numpy/random/tests/data/xoshiro256starstar-testset-2.csv diff --git a/numpy/random/randomgen/tests/data/xoshiro512starstar-testset-1.csv b/numpy/random/tests/data/xoshiro512starstar-testset-1.csv similarity index 100% rename from numpy/random/randomgen/tests/data/xoshiro512starstar-testset-1.csv rename to numpy/random/tests/data/xoshiro512starstar-testset-1.csv diff --git a/numpy/random/randomgen/tests/data/xoshiro512starstar-testset-2.csv b/numpy/random/tests/data/xoshiro512starstar-testset-2.csv similarity index 100% rename from numpy/random/randomgen/tests/data/xoshiro512starstar-testset-2.csv rename to numpy/random/tests/data/xoshiro512starstar-testset-2.csv diff --git a/numpy/random/randomgen/tests/test_against_numpy.py b/numpy/random/tests/test_against_numpy.py similarity index 100% rename from numpy/random/randomgen/tests/test_against_numpy.py rename to numpy/random/tests/test_against_numpy.py diff --git a/numpy/random/randomgen/tests/test_direct.py b/numpy/random/tests/test_direct.py similarity index 100% rename from numpy/random/randomgen/tests/test_direct.py rename to numpy/random/tests/test_direct.py diff --git a/numpy/random/randomgen/tests/test_generator_mt19937.py b/numpy/random/tests/test_generator_mt19937.py similarity index 100% rename from numpy/random/randomgen/tests/test_generator_mt19937.py rename to numpy/random/tests/test_generator_mt19937.py diff --git a/numpy/random/randomgen/tests/test_generator_mt19937_regressions.py b/numpy/random/tests/test_generator_mt19937_regressions.py similarity index 100% rename from numpy/random/randomgen/tests/test_generator_mt19937_regressions.py rename to numpy/random/tests/test_generator_mt19937_regressions.py diff --git a/numpy/random/randomgen/tests/test_randomstate.py b/numpy/random/tests/test_randomstate.py similarity index 100% rename from numpy/random/randomgen/tests/test_randomstate.py rename to numpy/random/tests/test_randomstate.py diff --git a/numpy/random/randomgen/tests/test_randomstate_regression.py b/numpy/random/tests/test_randomstate_regression.py similarity index 100% rename from numpy/random/randomgen/tests/test_randomstate_regression.py rename to numpy/random/tests/test_randomstate_regression.py diff --git a/numpy/random/randomgen/tests/test_smoke.py b/numpy/random/tests/test_smoke.py similarity index 100% rename from numpy/random/randomgen/tests/test_smoke.py rename to numpy/random/tests/test_smoke.py diff --git a/numpy/random/randomgen/threefry.pyx b/numpy/random/threefry.pyx similarity index 100% rename from numpy/random/randomgen/threefry.pyx rename to numpy/random/threefry.pyx diff --git a/numpy/random/randomgen/threefry32.pyx b/numpy/random/threefry32.pyx similarity index 100% rename from numpy/random/randomgen/threefry32.pyx rename to numpy/random/threefry32.pyx diff --git a/numpy/random/randomgen/xoroshiro128.pyx b/numpy/random/xoroshiro128.pyx similarity index 100% rename from numpy/random/randomgen/xoroshiro128.pyx rename to numpy/random/xoroshiro128.pyx diff --git a/numpy/random/randomgen/xorshift1024.pyx b/numpy/random/xorshift1024.pyx similarity index 100% rename from numpy/random/randomgen/xorshift1024.pyx rename to numpy/random/xorshift1024.pyx diff --git a/numpy/random/randomgen/xoshiro256starstar.pyx b/numpy/random/xoshiro256starstar.pyx similarity index 100% rename from numpy/random/randomgen/xoshiro256starstar.pyx rename to numpy/random/xoshiro256starstar.pyx diff --git a/numpy/random/randomgen/xoshiro512starstar.pyx b/numpy/random/xoshiro512starstar.pyx similarity index 100% rename from numpy/random/randomgen/xoshiro512starstar.pyx rename to numpy/random/xoshiro512starstar.pyx diff --git a/setup.py b/setup.py index e2eaaeee55e2..e1fdfaddebb7 100755 --- a/setup.py +++ b/setup.py @@ -197,10 +197,10 @@ def run(self): def generate_cython(): cwd = os.path.abspath(os.path.dirname(__file__)) print("Cythonizing sources") - for d in ('mtrand', 'randomgen', 'randomgen/legacy'): + for d in ('random/_mtrand', 'random'): p = subprocess.call([sys.executable, os.path.join(cwd, 'tools', 'cythonize.py'), - 'numpy/random/{0}'.format(d)], + 'numpy/{0}'.format(d)], cwd=cwd) if p != 0: raise RuntimeError("Running cythonize failed!") From bbdf80d7bebac459f0622e5c94a14633fc477bfc Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 11 Apr 2019 07:59:21 +0100 Subject: [PATCH 278/279] ENH: Extend multinomial Extend multinomial to allow broadcasting --- numpy/random/distributions.pxd | 3 + numpy/random/generator.pyx | 65 +++++++++++++------ numpy/random/mtrand.pyx | 27 +++----- .../random/src/distributions/distributions.c | 22 ++++++- .../random/src/distributions/distributions.h | 3 + numpy/random/tests/test_generator_mt19937.py | 17 +++++ 6 files changed, 97 insertions(+), 40 deletions(-) diff --git a/numpy/random/distributions.pxd b/numpy/random/distributions.pxd index ddb7a84bf190..5047aed9a325 100644 --- a/numpy/random/distributions.pxd +++ b/numpy/random/distributions.pxd @@ -144,3 +144,6 @@ cdef extern from "src/distributions/distributions.h": np.npy_bool off, np.npy_bool rng, np.npy_intp cnt, bint use_masked, np.npy_bool *out) nogil + + void random_multinomial(brng_t *brng_state, int64_t n, int64_t *mnix, + double *pix, np.npy_intp d, binomial_t *binomial) nogil diff --git a/numpy/random/generator.pyx b/numpy/random/generator.pyx index e68edb98ab15..fd63fb7a3e2f 100644 --- a/numpy/random/generator.pyx +++ b/numpy/random/generator.pyx @@ -3655,7 +3655,7 @@ cdef class RandomGenerator: Parameters ---------- - n : int + n : int or array-like of ints Number of experiments. pvals : sequence of floats, length p Probabilities of each of the ``p`` different outcomes. These @@ -3694,6 +3694,18 @@ cdef class RandomGenerator: For the first run, we threw 3 times 1, 4 times 2, etc. For the second, we threw 2 times 1, 4 times 2, etc. + Now, do one experiment throwing the dice 10 time, and 10 times again, + and another throwing the dice 20 times, and 20 times again: + + >>> np.random.multinomial([[10], [20]], [1/6.]*6, size=2) + array([[[2, 4, 0, 1, 2, 1], + [1, 3, 0, 3, 1, 2]], + [[1, 4, 4, 4, 4, 3], + [3, 3, 2, 5, 5, 2]]]) # random + + The first array shows the outcomes of throwing the dice 10 times, and + the second shows the outcomes from throwing the dice 20 times. + A loaded die is more likely to land on number 6: >>> np.random.multinomial(100, [1/7.]*5 + [2/7.]) @@ -3714,19 +3726,43 @@ cdef class RandomGenerator: array([100, 0]) """ - cdef np.npy_intp d, i, j, dn, sz - cdef np.ndarray parr "arrayObject_parr", mnarr "arrayObject_mnarr" + + cdef np.npy_intp d, i, sz, offset + cdef np.ndarray parr, mnarr, on, temp_arr cdef double *pix cdef int64_t *mnix - cdef double Sum + cdef int64_t ni + cdef np.broadcast it d = len(pvals) + on = np.PyArray_FROM_OTF(n, np.NPY_INT64, np.NPY_ALIGNED) parr = np.PyArray_FROM_OTF(pvals, np.NPY_DOUBLE, np.NPY_ALIGNED) pix = np.PyArray_DATA(parr) if kahan_sum(pix, d-1) > (1.0 + 1e-12): raise ValueError("sum(pvals[:-1]) > 1.0") + if np.PyArray_NDIM(on) != 0: # vector + if size is None: + it = np.PyArray_MultiIterNew1(on) + else: + temp = np.empty(size, dtype=np.int8) + temp_arr = temp + it = np.PyArray_MultiIterNew2(on, temp_arr) + shape = it.shape + (d,) + multin = np.zeros(shape, dtype=np.int64) + mnarr = multin + mnix = np.PyArray_DATA(mnarr) + offset = 0 + sz = it.size + with self.lock, nogil: + for i in range(sz): + ni = (np.PyArray_MultiIter_DATA(it, 0))[0] + random_multinomial(self._brng, ni, &mnix[offset], pix, d, self._binomial) + offset += d + np.PyArray_MultiIter_NEXT(it) + return multin + if size is None: shape = (d,) else: @@ -3739,23 +3775,12 @@ cdef class RandomGenerator: mnarr = multin mnix = np.PyArray_DATA(mnarr) sz = np.PyArray_SIZE(mnarr) - + ni = n + offset = 0 with self.lock, nogil: - i = 0 - while i < sz: - Sum = 1.0 - dn = n - for j in range(d-1): - mnix[i+j] = random_binomial(self._brng, pix[j]/Sum, dn, - self._binomial) - dn = dn - mnix[i+j] - if dn <= 0: - break - Sum = Sum - pix[j] - if dn > 0: - mnix[i+d-1] = dn - - i = i + d + for i in range(sz // d): + random_multinomial(self._brng, ni, &mnix[offset], pix, d, self._binomial) + offset += d return multin diff --git a/numpy/random/mtrand.pyx b/numpy/random/mtrand.pyx index b5d6ff9bc9b9..b49ce32f226b 100644 --- a/numpy/random/mtrand.pyx +++ b/numpy/random/mtrand.pyx @@ -3790,11 +3790,11 @@ cdef class RandomState: array([100, 0]) """ - cdef np.npy_intp d, i, j, dn, sz - cdef np.ndarray parr "arrayObject_parr", mnarr "arrayObject_mnarr" + cdef np.npy_intp d, i, sz, offset + cdef np.ndarray parr, mnarr cdef double *pix cdef int64_t *mnix - cdef double Sum + cdef int64_t ni d = len(pvals) parr = np.PyArray_FROM_OTF(pvals, np.NPY_DOUBLE, np.NPY_ALIGNED) @@ -3815,23 +3815,12 @@ cdef class RandomState: mnarr = multin mnix = np.PyArray_DATA(mnarr) sz = np.PyArray_SIZE(mnarr) - + ni = n + offset = 0 with self.lock, nogil: - i = 0 - while i < sz: - Sum = 1.0 - dn = n - for j in range(d-1): - mnix[i+j] = random_binomial(self._brng, pix[j]/Sum, dn, - self._binomial) - dn = dn - mnix[i+j] - if dn <= 0: - break - Sum = Sum - pix[j] - if dn > 0: - mnix[i+d-1] = dn - - i = i + d + for i in range(sz // d): + random_multinomial(self._brng, ni, &mnix[offset], pix, d, self._binomial) + offset += d return multin diff --git a/numpy/random/src/distributions/distributions.c b/numpy/random/src/distributions/distributions.c index 83806de38997..1bb7bcdcdf9d 100644 --- a/numpy/random/src/distributions/distributions.c +++ b/numpy/random/src/distributions/distributions.c @@ -1179,8 +1179,10 @@ int64_t random_hypergeometric(brng_t *brng_state, int64_t good, int64_t bad, int64_t sample) { if (sample > 10) { return random_hypergeometric_hrua(brng_state, good, bad, sample); - } else { + } else if (sample > 0) { return random_hypergeometric_hyp(brng_state, good, bad, sample); + } else { + return 0; } } @@ -1809,3 +1811,21 @@ void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, npy_bool rng, out[i] = buffered_bounded_bool(brng_state, off, rng, mask, &bcnt, &buf); } } + +void random_multinomial(brng_t *brng_state, int64_t n, int64_t *mnix, + double *pix, npy_intp d, binomial_t *binomial) { + double remaining_p = 1.0; + npy_intp j; + int64_t dn = n; + for (j = 0; j < (d - 1); j++) { + mnix[j] = random_binomial(brng_state, pix[j] / remaining_p, dn, binomial); + dn = dn - mnix[j]; + if (dn <= 0) { + break; + } + remaining_p -= pix[j]; + if (dn > 0) { + mnix[d - 1] = dn; + } + } +} diff --git a/numpy/random/src/distributions/distributions.h b/numpy/random/src/distributions/distributions.h index 7ca31a16cba6..8ec4a83e8b3e 100644 --- a/numpy/random/src/distributions/distributions.h +++ b/numpy/random/src/distributions/distributions.h @@ -217,4 +217,7 @@ DECLDIR void random_bounded_bool_fill(brng_t *brng_state, npy_bool off, npy_bool rng, npy_intp cnt, bool use_masked, npy_bool *out); +DECLDIR void random_multinomial(brng_t *brng_state, int64_t n, int64_t *mnix, + double *pix, npy_intp d, binomial_t *binomial); + #endif diff --git a/numpy/random/tests/test_generator_mt19937.py b/numpy/random/tests/test_generator_mt19937.py index 4ab20d73c071..e78a572da860 100644 --- a/numpy/random/tests/test_generator_mt19937.py +++ b/numpy/random/tests/test_generator_mt19937.py @@ -1849,6 +1849,23 @@ def test_logseries(self): assert_raises(ValueError, logseries, bad_p_one * 3) assert_raises(ValueError, logseries, bad_p_two * 3) + def test_multinomial(self): + random.seed(self.seed) + actual = random.multinomial([5, 20], [1 / 6.] * 6, size=(3, 2)) + desired = np.array([[[1, 1, 1, 1, 0, 1], + [4, 5, 1, 4, 3, 3]], + [[1, 1, 1, 0, 0, 2], + [2, 0, 4, 3, 7, 4]], + [[1, 2, 0, 0, 2, 2], + [3, 2, 3, 4, 2, 6]]], dtype=np.int64) + assert_array_equal(actual, desired) + + random.seed(self.seed) + actual = random.multinomial([5, 20], [1 / 6.] * 6) + desired = np.array([[1, 1, 1, 1, 0, 1], + [4, 5, 1, 4, 3, 3]], dtype=np.int64) + assert_array_equal(actual, desired) + class TestThread(object): # make sure each state produces the same sequence even in threads From 732b62a9e86f857de161290d3f6fb39f02a284f4 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 11 Apr 2019 23:08:14 +0100 Subject: [PATCH 279/279] BUG/ENH: Fix zipf changes missed in NumPy Fix zipf changes missed in NumPy Enable 0 as valid input for hypergeometric --- numpy/random/generator.pyx | 2 +- .../random/src/distributions/distributions.c | 30 +++++++++++-------- numpy/random/tests/test_generator_mt19937.py | 12 +++----- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/numpy/random/generator.pyx b/numpy/random/generator.pyx index fd63fb7a3e2f..8fbdd4f45c58 100644 --- a/numpy/random/generator.pyx +++ b/numpy/random/generator.pyx @@ -3639,7 +3639,7 @@ cdef class RandomGenerator: x.shape = tuple(final_shape) return x - def multinomial(self, np.npy_intp n, object pvals, size=None): + def multinomial(self, object n, object pvals, size=None): """ multinomial(n, pvals, size=None) diff --git a/numpy/random/src/distributions/distributions.c b/numpy/random/src/distributions/distributions.c index 1bb7bcdcdf9d..5f49b68be4c7 100644 --- a/numpy/random/src/distributions/distributions.c +++ b/numpy/random/src/distributions/distributions.c @@ -1048,25 +1048,31 @@ int64_t random_geometric(brng_t *brng_state, double p) { } int64_t random_zipf(brng_t *brng_state, double a) { - double T, U, V; - int64_t X; double am1, b; am1 = a - 1.0; b = pow(2.0, am1); - do { - U = 1.0 - next_double(brng_state); - V = next_double(brng_state); - X = (int64_t)floor(pow(U, -1.0 / am1)); - /* The real result may be above what can be represented in a int64. - * It will get casted to -sys.maxint-1. Since this is - * a straightforward rejection algorithm, we can just reject this value - * in the rejection condition below. This function then models a Zipf + while (1) { + double T, U, V, X; + + U = 1.0 - random_double(brng_state); + V = random_double(brng_state); + X = floor(pow(U, -1.0 / am1)); + /* + * The real result may be above what can be represented in a signed + * long. Since this is a straightforward rejection algorithm, we can + * just reject this value. This function then models a Zipf * distribution truncated to sys.maxint. */ + if (X > LONG_MAX || X < 1.0) { + continue; + } + T = pow(1.0 + 1.0 / X, am1); - } while (((V * X * (T - 1.0) / (b - 1.0)) > (T / b)) || X < 1); - return X; + if (V * X * (T - 1.0) / (b - 1.0) <= T / b) { + return (long)X; + } + } } double random_triangular(brng_t *brng_state, double left, double mode, diff --git a/numpy/random/tests/test_generator_mt19937.py b/numpy/random/tests/test_generator_mt19937.py index e78a572da860..7d25b3970392 100644 --- a/numpy/random/tests/test_generator_mt19937.py +++ b/numpy/random/tests/test_generator_mt19937.py @@ -804,8 +804,7 @@ def test_geometric_exceptions(self): assert_raises(ValueError, random.geometric, [1.1] * 10) assert_raises(ValueError, random.geometric, -0.1) assert_raises(ValueError, random.geometric, [-0.1] * 10) - with suppress_warnings() as sup: - sup.record(RuntimeWarning) + with np.errstate(invalid='ignore'): assert_raises(ValueError, random.geometric, np.nan) assert_raises(ValueError, random.geometric, [np.nan] * 10) @@ -888,8 +887,7 @@ def test_logseries(self): assert_array_equal(actual, desired) def test_logseries_exceptions(self): - with suppress_warnings() as sup: - sup.record(RuntimeWarning) + with np.errstate(invalid='ignore'): assert_raises(ValueError, random.logseries, np.nan) assert_raises(ValueError, random.logseries, [np.nan] * 10) @@ -964,8 +962,7 @@ def test_negative_binomial(self): assert_array_equal(actual, desired) def test_negative_binomial_exceptions(self): - with suppress_warnings() as sup: - sup.record(RuntimeWarning) + with np.errstate(invalid='ignore'): assert_raises(ValueError, random.negative_binomial, 100, np.nan) assert_raises(ValueError, random.negative_binomial, 100, [np.nan] * 10) @@ -1046,8 +1043,7 @@ def test_poisson_exceptions(self): assert_raises(ValueError, random.poisson, [lamneg] * 10) assert_raises(ValueError, random.poisson, lambig) assert_raises(ValueError, random.poisson, [lambig] * 10) - with suppress_warnings() as sup: - sup.record(RuntimeWarning) + with np.errstate(invalid='ignore'): assert_raises(ValueError, random.poisson, np.nan) assert_raises(ValueError, random.poisson, [np.nan] * 10)