#cython: language_level=3fromlibc.stdintcimportuint32_tfromcpython.pycapsulecimportPyCapsule_IsValid,PyCapsule_GetPointerimportnumpyasnpcimportnumpyasnpcimportcythonfromnumpy.randomcimportbitgen_tfromnumpy.randomimportPCG64np.import_array()@cython.boundscheck(False)@cython.wraparound(False)defuniform_mean(Py_ssize_tn):cdefPy_ssize_ticdefbitgen_t *rngcdefconstchar *capsule_name="BitGenerator"cdefdouble[::1]random_valuescdefnp.ndarrayrandomsx=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)# Best practice is to acquire the lock whenever generating random values.# This prevents other threads from modifying the state. Acquiring the lock# is only necessary if the GIL is also released, as in this example.withx.lock,nogil:foriinrange(n):random_values[i]=rng.next_double(rng.state)randoms=np.asarray(random_values)returnrandoms.mean()# This function is declared nogil so it can be used without the GIL belowcdefuint32_tbounded_uint(uint32_tlb,uint32_tub,bitgen_t*rng)nogil:cdefuint32_tmask,delta,valmask=delta=ub-lbmask|=mask>>1mask|=mask>>2mask|=mask>>4mask|=mask>>8mask|=mask>>16val=rng.next_uint32(rng.state)&maskwhileval>delta:val=rng.next_uint32(rng.state)&maskreturnlb+val@cython.boundscheck(False)@cython.wraparound(False)defbounded_uints(uint32_tlb,uint32_tub,Py_ssize_tn):cdefPy_ssize_ticdefbitgen_t *rngcdefuint32_t[::1]outcdefconstchar *capsule_name="BitGenerator"x=PCG64()out=np.empty(n,dtype=np.uint32)capsule=x.capsuleifnotPyCapsule_IsValid(capsule,capsule_name):raiseValueError("Invalid pointer to anon_func_state")rng=<bitgen_t*>PyCapsule_GetPointer(capsule,capsule_name)withx.lock,nogil:foriinrange(n):out[i]=bounded_uint(lb,ub,rng)returnnp.asarray(out)