#cython: language_level=3"""This file shows how the to use a BitGenerator to create a distribution."""importnumpyasnpcimportnumpyasnpcimportcythonfromcpython.pycapsulecimportPyCapsule_IsValid,PyCapsule_GetPointerfromlibc.stdintcimportuint16_t,uint64_tfromnumpy.randomcimportbitgen_tfromnumpy.randomimportPCG64fromnumpy.random.c_distributionscimport(random_standard_uniform_fill,random_standard_uniform_fill_f)@cython.boundscheck(False)@cython.wraparound(False)defuniforms(Py_ssize_tn):""" Create an array of `n` uniformly distributed doubles. A 'real' distribution would want to process the values into some non-uniform distribution """cdefPy_ssize_ticdefbitgen_t *rngcdefconstchar *capsule_name="BitGenerator"cdefdouble[::1]random_valuesx=PCG64()capsule=x.capsule# Optional check that the capsule if from a BitGeneratorifnotPyCapsule_IsValid(capsule,capsule_name):raiseValueError("Invalid pointer to anon_func_state")# Cast the pointerrng=<bitgen_t*>PyCapsule_GetPointer(capsule,capsule_name)random_values=np.empty(n,dtype='float64')withx.lock,nogil:foriinrange(n):# Call the functionrandom_values[i]=rng.next_double(rng.state)randoms=np.asarray(random_values)returnrandoms# cython example 2@cython.boundscheck(False)@cython.wraparound(False)defuint10_uniforms(Py_ssize_tn):"""Uniform 10 bit integers stored as 16-bit unsigned integers"""cdefPy_ssize_ticdefbitgen_t *rngcdefconstchar *capsule_name="BitGenerator"cdefuint16_t[::1]random_valuescdefintbits_remainingcdefintwidth=10cdefuint64_tbuff,mask=0x3FFx=PCG64()capsule=x.capsuleifnotPyCapsule_IsValid(capsule,capsule_name):raiseValueError("Invalid pointer to anon_func_state")rng=<bitgen_t*>PyCapsule_GetPointer(capsule,capsule_name)random_values=np.empty(n,dtype='uint16')# Best practice is to release GIL and acquire the lockbits_remaining=0withx.lock,nogil:foriinrange(n):ifbits_remaining<width:buff=rng.next_uint64(rng.state)random_values[i]=buff&maskbuff>>=widthrandoms=np.asarray(random_values)returnrandoms# cython example 3defuniforms_ex(bit_generator,Py_ssize_tn,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' """cdefPy_ssize_ticdefbitgen_t *rngcdefconstchar *capsule_name="BitGenerator"cdefnp.ndarrayrandomscapsule=bit_generator.capsule# Optional check that the capsule if from a BitGeneratorifnotPyCapsule_IsValid(capsule,capsule_name):raiseValueError("Invalid pointer to anon_func_state")# Cast the pointerrng=<bitgen_t*>PyCapsule_GetPointer(capsule,capsule_name)_dtype=np.dtype(dtype)randoms=np.empty(n,dtype=_dtype)if_dtype==np.float32:withbit_generator.lock:random_standard_uniform_fill_f(rng,n,<float*>np.PyArray_DATA(randoms))elif_dtype==np.float64:withbit_generator.lock:random_standard_uniform_fill(rng,n,<double*>np.PyArray_DATA(randoms))else:raiseTypeError('Unsupported dtype %r for random'%_dtype)returnrandoms