Numba supports jitting ctypes and CFFI function calls. Numba will automatically figure out the signatures of the functions and data. Below is a gibbs sampling code that accesses ctypes (or CFFI) functions defined in another module ( rk_seed, rk_gamma and rk_normal), and that passes in a pointer to a struct also allocated with ctypes (state_p):
def gibbs(N, thin):
rng.rk_seed(0, rng.state_p)
x = 0
y = 0
samples = np.empty((N,2))
for i in range(N):
for j in range(thin):
x = rng.rk_gamma(rng.state_p, 3.0, 1.0/(y**2+4))
y = rng.rk_normal(rng.state_p, 1.0/(x+1), 1.0/math.sqrt(2+2*x))
samples[i, 0] = x
samples[i, 1] = y
return samples
Note
Passing in ctypes or CFFI libraries to autojit functions does not yet work. However, passing in individual functions does.
Numba allows users to deal with high-level as well as low-level C-like code. Users can access and define new or external stucts, deal with pointers, and call C functions natively.
Note
Type declarations are covered in in Types and Variables.
Structs can be declared on the stack, passed in as arguments, returned from external or Numba functions, or originate from record arrays. Structs currently have copy-by-value semantics, but this is likely to change.
Struct fields can accessed as follows:
- struct.attr
- struct['attr']
- struct[field_index]
An example is shown below:
from numba import struct, jit, double
import numpy as np
record_type = struct([('x', double), ('y', double)])
record_dtype = record_type.get_dtype()
a = np.array([(1.0, 2.0), (3.0, 4.0)], dtype=record_dtype)
@jit(argtypes=[record_type[:]])
def hypot(data):
# return types of numpy functions are inferred
result = np.empty_like(data, dtype=np.float64)
# notice access to structure elements 'x' and 'y' via attribute access
# You can also index by field name or field index:
# data[i].x == data[i]['x'] == data[i][0]
for i in range(data.shape[0]):
result[i] = np.sqrt(data[i].x * data[i].x + data[i].y * data[i].y)
return result
print hypot(a)
# Notice inferred return type
print hypot.signature
# Notice native sqrt calls and for.body direct access to memory...
#print hypot.lfunc
Pointers in Numba can be used in a similar way to C. They can be cast, indexed and operated on with pointer arithmetic. Currently it is however not possible to obtain the address of an lvalue.
An example is shown below:
import numba
from numba import *
from numba.tests.test_support import autojit_py3doc
import numpy as np
int32p = int32.pointer()
voidp = void.pointer()
@autojit_py3doc
def test_pointer_arithmetic():
"""
>>> test_pointer_arithmetic()
48L
"""
p = int32p(Py_uintptr_t(0))
p = p + 10
p += 2
return Py_uintptr_t(p) # 0 + 4 * 12
@autojit_py3doc(locals={"pointer_value": Py_uintptr_t})
def test_pointer_indexing(pointer_value, type_p):
"""
>>> a = np.array([1, 2, 3, 4], dtype=np.float32)
>>> test_pointer_indexing(a.ctypes.data, float32.pointer())
(1.0, 2.0, 3.0, 4.0)
>>> a = np.array([1, 2, 3, 4], dtype=np.int64)
>>> test_pointer_indexing(a.ctypes.data, int64.pointer())
(1L, 2L, 3L, 4L)
"""
p = type_p(pointer_value)
return p[0], p[1], p[2], p[3]
@autojit
def test_compare_null():
"""
>>> test_compare_null()
True
"""
return voidp(Py_uintptr_t(0)) == numba.NULL
numba.testmod()