-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
ENH: expose bit_generator
and random C-API to cython
#15463
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5094692
db01d81
93ec29d
f66326a
6494a44
0e51c6a
a230da9
8c6a68b
ce13211
a111795
74ac4cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
``numpy.random._bit_generator`` moved to ``numpy.random.bit_generator`` | ||
----------------------------------------------------------------------- | ||
|
||
In order to expose `numpy.random.BitGenerator` and `numpy.random.SeedSequence` | ||
to cython, the ``_bitgenerator`` module is now public as | ||
`numpy.random.bit_generator` | ||
|
||
Cython access to the random distributions is provided via a `pxd` file | ||
---------------------------------------------------------------------- | ||
|
||
``c_distributions.pxd`` provides access to the c functions behind many of the | ||
random distributions from Cython, making it convenient to use and extend them. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
r 6D40 ng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name) | ||
|
||
_dtype = np.dtype(dtype) | ||
randoms = np.empty(n, dtype=_dtype) | ||
if _dtype == np.float32: | ||
mattip marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I did not look at it careful enough again right now. This is still incorrect for non-native byte order, would need to add an error branch and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
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 | ||
|
||
mattip marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,11 @@ | |
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') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we invent a better way to spell this? I am not sure, and if it is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is for the |
||
|
||
extending = Extension("extending", | ||
sources=[join(path, 'extending.pyx')], | ||
|
@@ -24,7 +28,9 @@ | |
) | ||
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, | ||
) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
B3FE 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 | ||
|
Uh oh!
There was an error while loading. Please reload this page.