extending_distributions.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. r"""
  2. Building the required library in this example requires a source distribution
  3. of NumPy or clone of the NumPy git repository since distributions.c is not
  4. included in binary distributions.
  5. On *nix, execute in numpy/random/src/distributions
  6. export ${PYTHON_VERSION}=3.8 # Python version
  7. export PYTHON_INCLUDE=#path to Python's include folder, usually \
  8. ${PYTHON_HOME}/include/python${PYTHON_VERSION}m
  9. export NUMPY_INCLUDE=#path to numpy's include folder, usually \
  10. ${PYTHON_HOME}/lib/python${PYTHON_VERSION}/site-packages/numpy/core/include
  11. gcc -shared -o libdistributions.so -fPIC distributions.c \
  12. -I${NUMPY_INCLUDE} -I${PYTHON_INCLUDE}
  13. mv libdistributions.so ../../_examples/numba/
  14. On Windows
  15. rem PYTHON_HOME and PYTHON_VERSION are setup dependent, this is an example
  16. set PYTHON_HOME=c:\Anaconda
  17. set PYTHON_VERSION=38
  18. cl.exe /LD .\distributions.c -DDLL_EXPORT \
  19. -I%PYTHON_HOME%\lib\site-packages\numpy\core\include \
  20. -I%PYTHON_HOME%\include %PYTHON_HOME%\libs\python%PYTHON_VERSION%.lib
  21. move distributions.dll ../../_examples/numba/
  22. """
  23. import os
  24. import numba as nb
  25. import numpy as np
  26. from cffi import FFI
  27. from numpy.random import PCG64
  28. ffi = FFI()
  29. if os.path.exists('./distributions.dll'):
  30. lib = ffi.dlopen('./distributions.dll')
  31. elif os.path.exists('./libdistributions.so'):
  32. lib = ffi.dlopen('./libdistributions.so')
  33. else:
  34. raise RuntimeError('Required DLL/so file was not found.')
  35. ffi.cdef("""
  36. double random_standard_normal(void *bitgen_state);
  37. """)
  38. x = PCG64()
  39. xffi = x.cffi
  40. bit_generator = xffi.bit_generator
  41. random_standard_normal = lib.random_standard_normal
  42. def normals(n, bit_generator):
  43. out = np.empty(n)
  44. for i in range(n):
  45. out[i] = random_standard_normal(bit_generator)
  46. return out
  47. normalsj = nb.jit(normals, nopython=True)
  48. # Numba requires a memory address for void *
  49. # Can also get address from x.ctypes.bit_generator.value
  50. bit_generator_address = int(ffi.cast('uintptr_t', bit_generator))
  51. norm = normalsj(1000, bit_generator_address)
  52. print(norm[:12])