File size: 2,103 Bytes
d65780e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
r"""

Building the required library in this example requires a source distribution

of NumPy or clone of the NumPy git repository since distributions.c is not

included in binary distributions.



On *nix, execute in numpy/random/src/distributions



export ${PYTHON_VERSION}=3.8 # Python version

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 and PYTHON_VERSION are setup dependent, this is an example

set PYTHON_HOME=c:\Anaconda

set PYTHON_VERSION=38

cl.exe /LD .\distributions.c -DDLL_EXPORT \

    -I%PYTHON_HOME%\lib\site-packages\numpy\_core\include \

    -I%PYTHON_HOME%\include %PYTHON_HOME%\libs\python%PYTHON_VERSION%.lib

move distributions.dll ../../_examples/numba/

"""
import os

import numba as nb
import numpy as np
from cffi import FFI

from numpy.random import PCG64

ffi = FFI()
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_standard_normal(void *bitgen_state);

""")
x = PCG64()
xffi = x.cffi
bit_generator = xffi.bit_generator

random_standard_normal = lib.random_standard_normal


def normals(n, bit_generator):
    out = np.empty(n)
    for i in range(n):
        out[i] = random_standard_normal(bit_generator)
    return out


normalsj = nb.jit(normals, nopython=True)

# Numba requires a memory address for void *
# Can also get address from x.ctypes.bit_generator.value
bit_generator_address = int(ffi.cast('uintptr_t', bit_generator))

norm = normalsj(1000, bit_generator_address)
print(norm[:12])