diff options
author | Matti Picus <matti.picus@gmail.com> | 2020-03-17 00:02:06 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-16 17:02:06 -0500 |
commit | 4f2b219647ae6a7928590be2b709894ae2403274 (patch) | |
tree | 5448d5f350fdcbc2546f82dfe80bd4d3e0665ada /numpy | |
parent | f77c5e83c07985aacbddb89525785a3f66ce1b3b (diff) | |
download | numpy-4f2b219647ae6a7928590be2b709894ae2403274.tar.gz |
BUG: add missing c_distributions.pxd, enables cython use of random C-API (gh-15463)
xref gh-14778
As pointed out in the comment by @jamesthomasgriffin, we did not include a pxd file to expose the distribution functions documented in the random c-api. This PR adds a c_distributions.pxd file that exposes them.
Squashed commits:
* BUG: add missing c_distributions.pxd to enable cython use of random C-API
* ENH, TST: add npyrandom library like npymath, test cython use of it
* BUG: actually prefix f-string with f
* MAINT: fixes from review, add _bit_generato_bit_generator.pxd
* STY: fixes from review
* BLD: don't use nprandom library for mtrand legacy build
* TST: WindowsPath cannot be used in subprocess's list2cmdline
* MAINT, API: move _bit_generator to bit_generator
* DOC: add release note about moving bit_generator
* DOC, MAINT: fixes from review
* MAINT: redo dtype determination from review
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/random/__init__.pxd | 2 | ||||
-rw-r--r-- | numpy/random/__init__.py | 2 | ||||
-rw-r--r-- | numpy/random/_examples/cython/extending_distributions.pyx | 45 | ||||
-rw-r--r-- | numpy/random/_examples/cython/setup.py | 8 | ||||
-rw-r--r-- | numpy/random/_generator.pyx | 110 | ||||
-rw-r--r-- | numpy/random/bit_generator.pxd (renamed from numpy/random/_bit_generator.pxd) | 0 | ||||
-rw-r--r-- | numpy/random/bit_generator.pyx (renamed from numpy/random/_bit_generator.pyx) | 2 | ||||
-rw-r--r-- | numpy/random/c_distributions.pxd | 114 | ||||
-rw-r--r-- | numpy/random/setup.py | 72 | ||||
-rw-r--r-- | numpy/random/tests/test_direct.py | 2 | ||||
-rw-r--r-- | numpy/random/tests/test_extending.py | 36 | ||||
-rw-r--r-- | numpy/tests/test_public_api.py | 1 |
12 files changed, 245 insertions, 149 deletions
diff --git a/numpy/random/__init__.pxd b/numpy/random/__init__.pxd index 05e073876..1f9057296 100644 --- a/numpy/random/__init__.pxd +++ b/numpy/random/__init__.pxd @@ -11,4 +11,4 @@ cdef extern from "numpy/random/bitgen.h": ctypedef bitgen bitgen_t -from numpy.random._bit_generator cimport BitGenerator, SeedSequence +from numpy.random.bit_generator cimport BitGenerator, SeedSequence diff --git a/numpy/random/__init__.py b/numpy/random/__init__.py index 0b80999d8..7efa5c07f 100644 --- a/numpy/random/__init__.py +++ b/numpy/random/__init__.py @@ -181,7 +181,7 @@ from . import _common from . import _bounded_integers from ._generator import Generator, default_rng -from ._bit_generator import SeedSequence, BitGenerator +from .bit_generator import SeedSequence, BitGenerator from ._mt19937 import MT19937 from ._pcg64 import PCG64 from ._philox import Philox diff --git a/numpy/random/_examples/cython/extending_distributions.pyx b/numpy/random/_examples/cython/extending_distributions.pyx index 4da6a4b3a..d908e92d0 100644 --- a/numpy/random/_examples/cython/extending_distributions.pyx +++ b/numpy/random/_examples/cython/extending_distributions.pyx @@ -10,6 +10,8 @@ from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer from libc.stdint cimport uint16_t, uint64_t from numpy.random cimport bitgen_t from numpy.random import PCG64 +from numpy.random.c_distributions cimport ( + random_standard_uniform_fill, random_standard_uniform_fill_f) @cython.boundscheck(False) @@ -40,7 +42,7 @@ def uniforms(Py_ssize_t n): randoms = np.asarray(random_values) return randoms - + # cython example 2 @cython.boundscheck(False) @cython.wraparound(False) @@ -72,3 +74,44 @@ def uint10_uniforms(Py_ssize_t n): randoms = np.asarray(random_values) return randoms +# cython example 3 +def uniforms_ex(bit_generator, Py_ssize_t n, dtype=np.float64): + """ + Create an array of `n` uniformly distributed doubles via a "fill" function. + + A 'real' distribution would want to process the values into + some non-uniform distribution + + Parameters + ---------- + bit_generator: BitGenerator instance + n: int + Output vector length + dtype: {str, dtype}, optional + Desired dtype, either 'd' (or 'float64') or 'f' (or 'float32'). The + default dtype value is 'd' + """ + cdef Py_ssize_t i + cdef bitgen_t *rng + cdef const char *capsule_name = "BitGenerator" + cdef np.ndarray randoms + + capsule = bit_generator.capsule + # Optional check that the capsule if from a BitGenerator + if not PyCapsule_IsValid(capsule, capsule_name): + raise ValueError("Invalid pointer to anon_func_state") + # Cast the pointer + rng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name) + + _dtype = np.dtype(dtype) + randoms = np.empty(n, dtype=_dtype) + if _dtype == np.float32: + with bit_generator.lock: + random_standard_uniform_fill_f(rng, n, <float*>np.PyArray_DATA(randoms)) + elif _dtype == np.float64: + with bit_generator.lock: + random_standard_uniform_fill(rng, n, <double*>np.PyArray_DATA(randoms)) + else: + raise TypeError('Unsupported dtype %r for random' % _dtype) + return randoms + diff --git a/numpy/random/_examples/cython/setup.py b/numpy/random/_examples/cython/setup.py index 20cedc4e3..42425c2c1 100644 --- a/numpy/random/_examples/cython/setup.py +++ b/numpy/random/_examples/cython/setup.py @@ -12,7 +12,11 @@ from setuptools.extension import Extension from os.path import join, dirname path = dirname(__file__) +src_dir = join(dirname(path), '..', 'src') defs = [('NPY_NO_DEPRECATED_API', 0)] +inc_path = np.get_include() +# not so nice. We need the random/lib library from numpy +lib_path = join(np.get_include(), '..', '..', 'random', 'lib') extending = Extension("extending", sources=[join(path, 'extending.pyx')], @@ -24,7 +28,9 @@ extending = Extension("extending", ) distributions = Extension("extending_distributions", sources=[join(path, 'extending_distributions.pyx')], - include_dirs=[np.get_include()], + include_dirs=[inc_path], + library_dirs=[lib_path], + libraries=['npyrandom'], define_macros=defs, ) diff --git a/numpy/random/_generator.pyx b/numpy/random/_generator.pyx index a3c2e0976..7766f8b8c 100644 --- a/numpy/random/_generator.pyx +++ b/numpy/random/_generator.pyx @@ -11,6 +11,7 @@ import numpy as np cimport numpy as np from numpy.core.multiarray import normalize_axis_index +from .c_distributions cimport * from libc cimport string from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, int32_t, int64_t, INT64_MAX, SIZE_MAX) @@ -26,117 +27,8 @@ from ._common cimport (POISSON_LAM_MAX, CONS_POSITIVE, CONS_NONE, check_array_constraint, check_constraint, disc, discrete_broadcast_iii, ) - -cdef extern from "numpy/random/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 - - double random_standard_uniform(bitgen_t *bitgen_state) nogil - void random_standard_uniform_fill(bitgen_t* bitgen_state, np.npy_intp cnt, double *out) nogil - double random_standard_exponential(bitgen_t *bitgen_state) nogil - double random_standard_exponential_f(bitgen_t *bitgen_state) nogil - void random_standard_exponential_fill(bitgen_t *bitgen_state, np.npy_intp cnt, double *out) nogil - void random_standard_exponential_fill_f(bitgen_t *bitgen_state, np.npy_intp cnt, double *out) nogil - void random_standard_exponential_inv_fill(bitgen_t *bitgen_state, np.npy_intp cnt, double *out) nogil - void random_standard_exponential_inv_fill_f(bitgen_t *bitgen_state, np.npy_intp cnt, double *out) nogil - double random_standard_normal(bitgen_t* bitgen_state) nogil - void random_standard_normal_fill(bitgen_t *bitgen_state, np.npy_intp count, double *out) nogil - void random_standard_normal_fill_f(bitgen_t *bitgen_state, np.npy_intp count, float *out) nogil - double random_standard_gamma(bitgen_t *bitgen_state, double shape) nogil - - float random_standard_uniform_f(bitgen_t *bitgen_state) nogil - void random_standard_uniform_fill_f(bitgen_t* bitgen_state, np.npy_intp cnt, float *out) nogil - float random_standard_normal_f(bitgen_t* bitgen_state) nogil - float random_standard_gamma_f(bitgen_t *bitgen_state, float shape) nogil - - int64_t random_positive_int64(bitgen_t *bitgen_state) nogil - int32_t random_positive_int32(bitgen_t *bitgen_state) nogil - int64_t random_positive_int(bitgen_t *bitgen_state) nogil - uint64_t random_uint(bitgen_t *bitgen_state) nogil - - double random_normal(bitgen_t *bitgen_state, double loc, double scale) nogil - - double random_gamma(bitgen_t *bitgen_state, double shape, double scale) nogil - float random_gamma_f(bitgen_t *bitgen_state, float shape, float scale) nogil - - double random_exponential(bitgen_t *bitgen_state, double scale) nogil - double random_uniform(bitgen_t *bitgen_state, double lower, double range) nogil - double random_beta(bitgen_t *bitgen_state, double a, double b) nogil - double random_chisquare(bitgen_t *bitgen_state, double df) nogil - double random_f(bitgen_t *bitgen_state, double dfnum, double dfden) nogil - double random_standard_cauchy(bitgen_t *bitgen_state) nogil - double random_pareto(bitgen_t *bitgen_state, double a) nogil - double random_weibull(bitgen_t *bitgen_state, double a) nogil - double random_power(bitgen_t *bitgen_state, double a) nogil - double random_laplace(bitgen_t *bitgen_state, double loc, double scale) nogil - double random_gumbel(bitgen_t *bitgen_state, double loc, double scale) nogil - double random_logistic(bitgen_t *bitgen_state, double loc, double scale) nogil - double random_lognormal(bitgen_t *bitgen_state, double mean, double sigma) nogil - double random_rayleigh(bitgen_t *bitgen_state, double mode) nogil - double random_standard_t(bitgen_t *bitgen_state, double df) nogil - double random_noncentral_chisquare(bitgen_t *bitgen_state, double df, - double nonc) nogil - double random_noncentral_f(bitgen_t *bitgen_state, double dfnum, - double dfden, double nonc) nogil - double random_wald(bitgen_t *bitgen_state, double mean, double scale) nogil - double random_vonmises(bitgen_t *bitgen_state, double mu, double kappa) nogil - double random_triangular(bitgen_t *bitgen_state, double left, double mode, - double right) nogil - - int64_t random_poisson(bitgen_t *bitgen_state, double lam) nogil - int64_t random_negative_binomial(bitgen_t *bitgen_state, double n, double p) nogil - int64_t random_binomial(bitgen_t *bitgen_state, double p, int64_t n, binomial_t *binomial) nogil - int64_t random_logseries(bitgen_t *bitgen_state, double p) nogil - int64_t random_geometric_search(bitgen_t *bitgen_state, double p) nogil - int64_t random_geometric_inversion(bitgen_t *bitgen_state, double p) nogil - int64_t random_geometric(bitgen_t *bitgen_state, double p) nogil - int64_t random_zipf(bitgen_t *bitgen_state, double a) nogil - int64_t random_hypergeometric(bitgen_t *bitgen_state, int64_t good, int64_t bad, - int64_t sample) nogil - - uint64_t random_interval(bitgen_t *bitgen_state, uint64_t max) nogil - - # Generate random uint64 numbers in closed interval [off, off + rng]. - uint64_t random_bounded_uint64(bitgen_t *bitgen_state, - uint64_t off, uint64_t rng, - uint64_t mask, bint use_masked) nogil - - void random_multinomial(bitgen_t *bitgen_state, int64_t n, int64_t *mnix, - double *pix, np.npy_intp d, binomial_t *binomial) nogil - - int random_multivariate_hypergeometric_count(bitgen_t *bitgen_state, - int64_t total, - size_t num_colors, int64_t *colors, - int64_t nsample, - size_t num_variates, int64_t *variates) nogil - void random_multivariate_hypergeometric_marginals(bitgen_t *bitgen_state, - int64_t total, - size_t num_colors, int64_t *colors, - int64_t nsample, - size_t num_variates, int64_t *variates) nogil - np.import_array() - cdef int64_t _safe_sum_nonneg_int64(size_t num_colors, int64_t *colors): """ Sum the values in the array `colors`. diff --git a/numpy/random/_bit_generator.pxd b/numpy/random/bit_generator.pxd index bd5e47a20..bd5e47a20 100644 --- a/numpy/random/_bit_generator.pxd +++ b/numpy/random/bit_generator.pxd diff --git a/numpy/random/_bit_generator.pyx b/numpy/random/bit_generator.pyx index 21d21e6bb..f145ec13d 100644 --- a/numpy/random/_bit_generator.pyx +++ b/numpy/random/bit_generator.pyx @@ -114,7 +114,7 @@ def _coerce_to_uint32_array(x): Examples -------- >>> import numpy as np - >>> from numpy.random._bit_generator import _coerce_to_uint32_array + >>> from numpy.random.bit_generator import _coerce_to_uint32_array >>> _coerce_to_uint32_array(12345) array([12345], dtype=uint32) >>> _coerce_to_uint32_array('12345') diff --git a/numpy/random/c_distributions.pxd b/numpy/random/c_distributions.pxd new file mode 100644 index 000000000..6f905edc1 --- /dev/null +++ b/numpy/random/c_distributions.pxd @@ -0,0 +1,114 @@ +#!python +#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3 +from numpy cimport npy_intp + +from libc.stdint cimport (uint64_t, int32_t, int64_t) +from numpy.random cimport bitgen_t + +cdef extern from "numpy/random/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 + + double random_standard_uniform(bitgen_t *bitgen_state) nogil + void random_standard_uniform_fill(bitgen_t* bitgen_state, npy_intp cnt, double *out) nogil + double random_standard_exponential(bitgen_t *bitgen_state) nogil + double random_standard_exponential_f(bitgen_t *bitgen_state) nogil + void random_standard_exponential_fill(bitgen_t *bitgen_state, npy_intp cnt, double *out) nogil + void random_standard_exponential_fill_f(bitgen_t *bitgen_state, npy_intp cnt, double *out) nogil + void random_standard_exponential_inv_fill(bitgen_t *bitgen_state, npy_intp cnt, double *out) nogil + void random_standard_exponential_inv_fill_f(bitgen_t *bitgen_state, npy_intp cnt, double *out) nogil + double random_standard_normal(bitgen_t* bitgen_state) nogil + void random_standard_normal_fill(bitgen_t *bitgen_state, npy_intp count, double *out) nogil + void random_standard_normal_fill_f(bitgen_t *bitgen_state, npy_intp count, float *out) nogil + double random_standard_gamma(bitgen_t *bitgen_state, double shape) nogil + + float random_standard_uniform_f(bitgen_t *bitgen_state) nogil + void random_standard_uniform_fill_f(bitgen_t* bitgen_state, npy_intp cnt, float *out) nogil + float random_standard_normal_f(bitgen_t* bitgen_state) nogil + float random_standard_gamma_f(bitgen_t *bitgen_state, float shape) nogil + + int64_t random_positive_int64(bitgen_t *bitgen_state) nogil + int32_t random_positive_int32(bitgen_t *bitgen_state) nogil + int64_t random_positive_int(bitgen_t *bitgen_state) nogil + uint64_t random_uint(bitgen_t *bitgen_state) nogil + + double random_normal(bitgen_t *bitgen_state, double loc, double scale) nogil + + double random_gamma(bitgen_t *bitgen_state, double shape, double scale) nogil + float random_gamma_f(bitgen_t *bitgen_state, float shape, float scale) nogil + + double random_exponential(bitgen_t *bitgen_state, double scale) nogil + double random_uniform(bitgen_t *bitgen_state, double lower, double range) nogil + double random_beta(bitgen_t *bitgen_state, double a, double b) nogil + double random_chisquare(bitgen_t *bitgen_state, double df) nogil + double random_f(bitgen_t *bitgen_state, double dfnum, double dfden) nogil + double random_standard_cauchy(bitgen_t *bitgen_state) nogil + double random_pareto(bitgen_t *bitgen_state, double a) nogil + double random_weibull(bitgen_t *bitgen_state, double a) nogil + double random_power(bitgen_t *bitgen_state, double a) nogil + double random_laplace(bitgen_t *bitgen_state, double loc, double scale) nogil + double random_gumbel(bitgen_t *bitgen_state, double loc, double scale) nogil + double random_logistic(bitgen_t *bitgen_state, double loc, double scale) nogil + double random_lognormal(bitgen_t *bitgen_state, double mean, double sigma) nogil + double random_rayleigh(bitgen_t *bitgen_state, double mode) nogil + double random_standard_t(bitgen_t *bitgen_state, double df) nogil + double random_noncentral_chisquare(bitgen_t *bitgen_state, double df, + double nonc) nogil + double random_noncentral_f(bitgen_t *bitgen_state, double dfnum, + double dfden, double nonc) nogil + double random_wald(bitgen_t *bitgen_state, double mean, double scale) nogil + double random_vonmises(bitgen_t *bitgen_state, double mu, double kappa) nogil + double random_triangular(bitgen_t *bitgen_state, double left, double mode, + double right) nogil + + int64_t random_poisson(bitgen_t *bitgen_state, double lam) nogil + int64_t random_negative_binomial(bitgen_t *bitgen_state, double n, double p) nogil + int64_t random_binomial(bitgen_t *bitgen_state, double p, int64_t n, binomial_t *binomial) nogil + int64_t random_logseries(bitgen_t *bitgen_state, double p) nogil + int64_t random_geometric_search(bitgen_t *bitgen_state, double p) nogil + int64_t random_geometric_inversion(bitgen_t *bitgen_state, double p) nogil + int64_t random_geometric(bitgen_t *bitgen_state, double p) nogil + int64_t random_zipf(bitgen_t *bitgen_state, double a) nogil + int64_t random_hypergeometric(bitgen_t *bitgen_state, int64_t good, int64_t bad, + int64_t sample) nogil + + uint64_t random_interval(bitgen_t *bitgen_state, uint64_t max) nogil + + # Generate random uint64 numbers in closed interval [off, off + rng]. + uint64_t random_bounded_uint64(bitgen_t *bitgen_state, + uint64_t off, uint64_t rng, + uint64_t mask, bint use_masked) nogil + + void random_multinomial(bitgen_t *bitgen_state, int64_t n, int64_t *mnix, + double *pix, npy_intp d, binomial_t *binomial) nogil + + int random_multivariate_hypergeometric_count(bitgen_t *bitgen_state, + int64_t total, + size_t num_colors, int64_t *colors, + int64_t nsample, + size_t num_variates, int64_t *variates) nogil + void random_multivariate_hypergeometric_marginals(bitgen_t *bitgen_state, + int64_t total, + size_t num_colors, int64_t *colors, + int64_t nsample, + size_t num_variates, int64_t *variates) nogil + diff --git a/numpy/random/setup.py b/numpy/random/setup.py index 42c00ee5e..5d6ff2c8b 100644 --- a/numpy/random/setup.py +++ b/numpy/random/setup.py @@ -35,8 +35,10 @@ def configuration(parent_package='', top_path=None): config.add_data_dir('_examples') EXTRA_LINK_ARGS = [] - # Math lib - EXTRA_LIBRARIES = ['m'] if os.name != 'nt' else [] + EXTRA_LIBRARIES = ['npyrandom'] + if os.name != 'nt': + # Math lib + EXTRA_LIBRARIES.append('m') # Some bit generators exclude GCC inlining EXTRA_COMPILE_ARGS = ['-U__GNUC_GNU_INLINE__'] @@ -52,78 +54,88 @@ def configuration(parent_package='', top_path=None): PCG64_DEFS = [] # One can force emulated 128-bit arithmetic if one wants. #PCG64_DEFS += [('PCG_FORCE_EMULATED_128BIT_MATH', '1')] + depends = ['__init__.pxd', 'c_distributions.pxd', 'bit_generator.pxd'] + + # npyrandom - a library like npymath + npyrandom_sources = [ + 'src/distributions/logfactorial.c', + 'src/distributions/distributions.c', + 'src/distributions/random_mvhg_count.c', + 'src/distributions/random_mvhg_marginals.c', + 'src/distributions/random_hypergeometric.c', + ] + config.add_installed_library('npyrandom', + sources=npyrandom_sources, + install_dir='lib', + build_info={ + 'include_dirs' : [], # empty list required for creating npyrandom.h + 'extra_compiler_args' : (['/GL-'] if is_msvc else []), + }) for gen in ['mt19937']: # gen.pyx, src/gen/gen.c, src/gen/gen-jump.c - config.add_extension('_{0}'.format(gen), - sources=['_{0}.c'.format(gen), - 'src/{0}/{0}.c'.format(gen), - 'src/{0}/{0}-jump.c'.format(gen)], + config.add_extension(f'_{gen}', + sources=[f'_{gen}.c', + f'src/{gen}/{gen}.c', + f'src/{gen}/{gen}-jump.c'], include_dirs=['.', 'src', join('src', gen)], libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, - depends=['_%s.pyx' % gen], + depends=depends + [f'_{gen}.pyx'], define_macros=defs, ) for gen in ['philox', 'pcg64', 'sfc64']: # gen.pyx, src/gen/gen.c _defs = defs + PCG64_DEFS if gen == 'pcg64' else defs - config.add_extension('_{0}'.format(gen), - sources=['_{0}.c'.format(gen), - 'src/{0}/{0}.c'.format(gen)], + config.add_extension(f'_{gen}', + sources=[f'_{gen}.c', + f'src/{gen}/{gen}.c'], include_dirs=['.', 'src', join('src', gen)], libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, - depends=['_%s.pyx' % gen, '_bit_generator.pyx', - '_bit_generator.pxd'], + depends=depends + [f'_{gen}.pyx', + 'bit_generator.pyx', 'bit_generator.pxd'], define_macros=_defs, ) - for gen in ['_common', '_bit_generator']: + for gen in ['_common', 'bit_generator']: # gen.pyx config.add_extension(gen, - sources=['{0}.c'.format(gen)], + sources=[f'{gen}.c'], libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, include_dirs=['.', 'src'], - depends=['%s.pyx' % gen, '%s.pxd' % gen,], + depends=depends + [f'{gen}.pyx', f'{gen}.pxd',], define_macros=defs, ) - config.add_data_files('{0}.pxd'.format(gen)) - other_srcs = [ - 'src/distributions/logfactorial.c', - 'src/distributions/distributions.c', - 'src/distributions/random_mvhg_count.c', - 'src/distributions/random_mvhg_marginals.c', - 'src/distributions/random_hypergeometric.c', - ] + config.add_data_files('{gen}.pxd') for gen in ['_generator', '_bounded_integers']: # gen.pyx, src/distributions/distributions.c config.add_extension(gen, - sources=['{0}.c'.format(gen)] + other_srcs, + sources=[f'{gen}.c'], libraries=EXTRA_LIBRARIES, extra_compile_args=EXTRA_COMPILE_ARGS, include_dirs=['.', 'src'], extra_link_args=EXTRA_LINK_ARGS, - depends=['%s.pyx' % gen], + depends=depends + [f'{gen}.pyx'], define_macros=defs, ) config.add_data_files('_bounded_integers.pxd') config.add_extension('mtrand', sources=['mtrand.c', 'src/legacy/legacy-distributions.c', - 'src/distributions/logfactorial.c', - 'src/distributions/distributions.c'], + 'src/distributions/distributions.c', + ], include_dirs=['.', 'src', 'src/legacy'], - libraries=EXTRA_LIBRARIES, + libraries=['m'] if os.name != 'nt' else [], extra_compile_args=EXTRA_COMPILE_ARGS, extra_link_args=EXTRA_LINK_ARGS, - depends=['mtrand.pyx'], + depends=depends + ['mtrand.pyx'], define_macros=defs + LEGACY_DEFS, ) - config.add_data_files('__init__.pxd') + config.add_data_files(*depends) return config diff --git a/numpy/random/tests/test_direct.py b/numpy/random/tests/test_direct.py index 4fa69a402..dad12c8a8 100644 --- a/numpy/random/tests/test_direct.py +++ b/numpy/random/tests/test_direct.py @@ -127,7 +127,7 @@ def gauss_from_uint(x, n, bits): return gauss[:n] def test_seedsequence(): - from numpy.random._bit_generator import (ISeedSequence, + from numpy.random.bit_generator import (ISeedSequence, ISpawnableSeedSequence, SeedlessSeedSequence) diff --git a/numpy/random/tests/test_extending.py b/numpy/random/tests/test_extending.py index 64b8803dd..f7efafba9 100644 --- a/numpy/random/tests/test_extending.py +++ b/numpy/random/tests/test_extending.py @@ -4,6 +4,7 @@ import shutil import subprocess import sys import warnings +import numpy as np try: import cffi @@ -42,10 +43,37 @@ else: @pytest.mark.skipif(cython is None, reason="requires cython") @pytest.mark.slow def test_cython(tmp_path): - examples = os.path.join(os.path.dirname(__file__), '..', '_examples') - shutil.copytree(examples, tmp_path / '_examples') - subprocess.check_call([sys.executable, 'setup.py', 'build'], - cwd=str(tmp_path / '_examples' / 'cython')) + srcdir = os.path.join(os.path.dirname(__file__), '..') + shutil.copytree(srcdir, tmp_path / 'random') + # build the examples and "install" them into a temporary directory + env = os.environ.copy() + subprocess.check_call([sys.executable, 'setup.py', 'build', 'install', + '--prefix', str(tmp_path / 'installdir'), + '--single-version-externally-managed', + '--record', str(tmp_path/ 'tmp_install_log.txt'), + ], + cwd=str(tmp_path / 'random' / '_examples' / 'cython'), + env=env) + # get the path to the so's + so1 = so2 = None + with open(tmp_path /'tmp_install_log.txt') as fid: + for line in fid: + if 'extending.' in line: + so1 = line.strip() + if 'extending_distributions' in line: + so2 = line.strip() + assert so1 is not None + assert so2 is not None + # import the so's without adding the directory to sys.path + from importlib.machinery import ExtensionFileLoader + extending = ExtensionFileLoader('extending', so1).load_module() + extending_distributions = ExtensionFileLoader('extending_distributions', so2).load_module() + + # actually test the cython c-extension + from numpy.random import PCG64 + values = extending_distributions.uniforms_ex(PCG64(0), 10, 'd') + assert values.shape == (10,) + assert values.dtype == np.float64 @pytest.mark.skipif(numba is None or cffi is None, reason="requires numba and cffi") diff --git a/numpy/tests/test_public_api.py b/numpy/tests/test_public_api.py index 27ff87f49..fb7ec5d83 100644 --- a/numpy/tests/test_public_api.py +++ b/numpy/tests/test_public_api.py @@ -298,6 +298,7 @@ PRIVATE_BUT_PRESENT_MODULES = ['numpy.' + s for s in [ "matrixlib", "matrixlib.defmatrix", "random.mtrand", + "random.bit_generator", "testing.print_coercion_tables", "testing.utils", ]] |