def _construct_native_attribute_struct(ext_type): attrs = dict((name, var.type) for name, var in ext_type.symtab.iteritems()) if ext_type.attribute_struct is None: # No fields to inherit ext_type.attribute_struct = numba.struct(**attrs) else: # Inherit fields from parent fields = [] for name, variable in ext_type.symtab.iteritems(): if name not in ext_type.attribute_struct.fielddict: fields.append((name, variable.type)) ext_type.attribute_struct.fielddict[name] = variable.type # Sort fields by rank fields = numba.struct(fields).fields ext_type.attribute_struct.fields.extend(fields)
def inherit_attributes(ext_type, class_dict): cls = ext_type.py_class if not is_numba_class(cls): # superclass is not a numba class return struct_type = cls.__numba_struct_type vtab_type = cls.__numba_vtab_type verify_base_class_compatibility(cls, struct_type, vtab_type) # Inherit attributes ext_type.attribute_struct = numba.struct(struct_type.fields) for field_name, field_type in ext_type.attribute_struct.fields: ext_type.symtab[field_name] = symtab.Variable(field_type, promotable_type=False) # Inherit methods for method_name, method_type in vtab_type.fields: func_signature = method_type.base_type args = list(func_signature.args) if not (func_signature.is_class or func_signature.is_static): args[0] = ext_type func_signature = func_signature.return_type(*args) ext_type.add_method(method_name, func_signature) ext_type.parent_attr_struct = struct_type ext_type.parent_vtab_type = vtab_type
def compile_extension_methods(env, py_class, ext_type, class_dict, flags): """ Compile extension methods: 1) Process signatures such as @void(double) 2) Infer native attributes through type inference on __init__ 3) Path the extension type with a native attributes struct 4) Infer types for all other methods 5) Update the ext_type with a vtab type 6) Compile all methods """ method_pointers = [] lmethods = [] class_dict['__numba_py_class'] = py_class _process_method_signatures(class_dict, ext_type) _type_infer_init_method(env, class_dict, ext_type, flags) _construct_native_attribute_struct(ext_type) _type_infer_methods(env, class_dict, ext_type, flags) # TODO: patch method call types # Set vtab type before compiling ext_type.vtab_type = numba.struct( [(field_name, field_type.pointer()) for field_name, field_type in ext_type.methods]) _compile_methods(class_dict, env, ext_type, lmethods, method_pointers, flags) return method_pointers, lmethods
def inherit_attributes(ext_type, class_dict): cls = ext_type.py_class if not is_numba_class(cls): # superclass is not a numba class return struct_type = cls.__numba_struct_type vtab_type = cls.__numba_vtab_type verify_base_class_compatibility(cls, struct_type, vtab_type) # Inherit attributes ext_type.attribute_struct = numba.struct(struct_type.fields) for field_name, field_type in ext_type.attribute_struct.fields: ext_type.symtab[field_name] = symtab.Variable(field_type, promotable_type=False) # Inherit methods for method_name, method_type in vtab_type.fields: func_signature = method_type.base_type args = list(func_signature.args) args[0] = ext_type func_signature = func_signature.return_type(*args) ext_type.add_method(method_name, func_signature) ext_type.parent_attr_struct = struct_type ext_type.parent_vtab_type = vtab_type
def resolve_template_type(template_type, template_context): """ After the template context is known, resolve functions on template types E.g. T[:] -> ArrayType(dtype=T) void(T) -> FunctionType(args=[T]) Struct { T arg } -> struct(fields={'arg': T}) T * -> PointerType(base_type=T) Any other compound types? """ r = lambda t: resolve_template_type(t, template_context) if template_type.is_template: template_type = template_type.resolve_template(template_context) elif template_type.is_array: template_type = template_type.copy() template_type.dtype = r(template_type.dtype) elif template_type.is_function: template_type = r(template_type.return_type)(*map(r, template_type.args)) elif template_type.is_struct: S = template_type fields = [] for field_name, field_type in S.fields: fields.append((field_name, r(field_type))) template_type = numba.struct(fields, name=S.name, readonly=S.readonly, packed=S.packed) elif template_type.is_pointer: template_type = r(template_type.base_type).pointer() return template_type
def set_attributes(self, attribute_list): """ Create the symbol table and attribute struct from a list of (varname, attribute_type) """ import numba.symtab self.attribute_struct = numba.struct(attribute_list) self.symtab.update([(name, numba.symtab.Variable(type)) for name, type in attribute_list])
def from_ctypes_type(ctypes_type): """ Convert a ctypes type to a numba type """ if numba.utils.hashable(ctypes_type) and ctypes_type in ctypes_map: return ctypes_map[ctypes_type] elif isinstance(ctypes_type, _ctypes_pointer_type): return from_ctypes_type(ctypes_type._type_).pointer() elif isinstance(ctypes_type, _ctypes_array_type): base_type = from_ctypes_type(ctypes_type._type_) return minitypes.CArrayType(base_type, ctypes_type._length_) elif issubclass(ctypes_type, ctypes.Structure): fields = [(name, from_ctypes_type(field_type)) for name, field_type in ctypes_type._fields_] return numba.struct(fields) else: raise NotImplementedError(ctypes_type)
def build_vtab(vtab_type, method_pointers): assert len(method_pointers) == len(vtab_type.fields) vtab_ctype = numba.struct( [(vtab_name(field_name), field_type) for field_name, field_type in vtab_type.fields]).to_ctypes() methods = [] for (method_name, method_pointer), (field_name, field_type) in zip( method_pointers, vtab_type.fields): assert method_name == field_name method_type_p = field_type.to_ctypes() cmethod = ctypes.cast(ctypes.c_void_p(method_pointer), method_type_p) methods.append(cmethod) vtab = vtab_ctype(*methods) return vtab, vtab_type
def map_type(cffi_type): "Map CFFI type to numba type" kind = getattr(cffi_type, 'kind', '') if kind in ('struct', 'union'): if kind == 'union': result = None else: result = numba.struct([(name, map_type(field.type)) for name, field in cffi_type.fields]) elif kind == 'function': restype = map_type(cffi_type.result) argtypes = [map_type(arg) for arg in cffi_type.args] result = numba.function(restype, argtypes, is_vararg=cffi_type.ellipsis).pointer() else: result = type_map.get(cffi_type) if result is None: raise TypeError(cffi_type) return result
def build_static_vtab(vtable, vtab_struct): """ Create ctypes virtual method table. vtab_type: the vtab struct type (typesystem.struct) method_pointers: a list of method pointers ([int]) """ vtab_ctype = numba.struct( [(vtab_name(field_name), field_type) for field_name, field_type in vtab_struct.fields]).to_ctypes() methods = [] for method, (field_name, field_type) in zip(vtable.methods, vtab_struct.fields): method_type_p = field_type.to_ctypes() method_void_p = ctypes.c_void_p(method.lfunc_pointer) cmethod = ctypes.cast(method_void_p, method_type_p) methods.append(cmethod) vtab = vtab_ctype(*methods) return vtab
def build_vtab(vtab_type, method_pointers): """ Create ctypes virtual method table. vtab_type: the vtab struct type (typesystem.struct) method_pointers: a list of method pointers ([int]) """ assert len(method_pointers) == len(vtab_type.fields) vtab_ctype = numba.struct( [(vtab_name(field_name), field_type) for field_name, field_type in vtab_type.fields]).to_ctypes() methods = [] for (method_name, method_pointer), (field_name, field_type) in zip( method_pointers, vtab_type.fields): assert method_name == field_name method_type_p = field_type.to_ctypes() cmethod = ctypes.cast(ctypes.c_void_p(method_pointer), method_type_p) methods.append(cmethod) vtab = vtab_ctype(*methods) return vtab, vtab_type
def to_struct(self): return numba.struct([(attr, self.attributedict[attr]) for attr in self.attributes])
def wrap_vtable(self, vtable): return extension_types.StaticVtableWrapper(vtable) #------------------------------------------------------------------------ # Hash-based virtual method tables #------------------------------------------------------------------------ # ______________________________________________________________________ # Type Definitions # TODO: Use something like CFFI + type conversion to get these # TODO: types automatically PyCustomSlots_Entry = numba.struct([ ('id', uint64), ('ptr', void.pointer()), ]) PyCustomSlots_Table = numba.struct([ ('flags', uint64), ('m_f', uint64), ('m_g', uint64), ('entries', PyCustomSlots_Entry.pointer()), ('n', uint16), ('b', uint16), ('r', uint8), ('reserved', uint8), # actually: uint16[b], 'b' trailing displacements # ('d', numba.carray(uint16, 0)), #0xffff)), # ('entries_mem', PyCustomSlot_Entry[n]), # 'n' trailing customslot entries ])
def to_struct(self): return numba.struct([(m.name, m.signature.pointer()) for m in self.methods])
""" scalar = array[0, 0] return scalar #------------------------------------------------------------------------ # Test type matching #------------------------------------------------------------------------ T1 = numba.template("T1") T2 = numba.template("T2") T3 = numba.template("T3") T4 = numba.template("T4") A = T1[:, :] F = void(T1) S = numba.struct([('a', T1), ('b', T2.pointer()), ('c', T3[:]), ('d', void(T4))]) P = T2.pointer() type_context1 = { T1: int_, T2: float_, T3: float64, T4: short, } type_context2 = { T1: int_[:, :], T2: void(float32), T3: numba.struct(a=float64, b=float_), T4: short.pointer(), } def test_type_matching(array, func, struct, pointer): """ >>> infer(test_type_matching, template_signature=void(A, F, S, P), ... type_context=type_context1) [('array', int[:, :]), ('func', void (*)(int)), ('pointer', float32 *), ('struct', struct { int a, float32 * b, float64[:] c, void (*)(short) d })] """ func(array[0, 0]) struct.b = pointer
scalar = array[0, 0] return scalar #------------------------------------------------------------------------ # Test type matching #------------------------------------------------------------------------ T1 = numba.template("T1") T2 = numba.template("T2") T3 = numba.template("T3") T4 = numba.template("T4") A = T1[:, :] F = void(T1) S = numba.struct([('a', T1), ('b', T2.pointer()), ('c', T3[:]), ('d', void(T4))]) P = T2.pointer() type_context1 = { T1: int_, T2: float_, T3: float64, T4: short, } type_context2 = { T1: int_[:, :], T2: void(float32), T3: numba.struct(a=float64, b=float_), T4: short.pointer(), }
scalar = array[0, 0] return scalar #------------------------------------------------------------------------ # Test type matching #------------------------------------------------------------------------ T1 = numba.template("T1") T2 = numba.template("T2") T3 = numba.template("T3") T4 = numba.template("T4") A = T1[:, :] F = void(T1) S = numba.struct(a=T1, b=T2.pointer(), c=T3[:], d=void(T4)) P = T2.pointer() type_context1 = { T1: int_, T2: float_, T3: double, T4: short, } type_context2 = { T1: int_[:, :], T2: void(float_), T3: numba.struct(a=double, b=float_), T4: short.pointer(), }
def wrap_vtable(self, vtable): return extension_types.StaticVtableWrapper(vtable) #------------------------------------------------------------------------ # Hash-based virtual method tables #------------------------------------------------------------------------ # ______________________________________________________________________ # Type Definitions # TODO: Use something like CFFI + type conversion to get these # TODO: types automatically PyCustomSlots_Entry = numba.struct([ ('id', uint64), ('ptr', void.pointer()), ]) PyCustomSlots_Table = numba.struct([ ('flags', uint64), ('m_f', uint64), ('m_g', uint64), ('entries', PyCustomSlots_Entry.pointer()), ('n', uint16), ('b', uint16), ('r', uint8), ('reserved', uint8), # actually: uint16[b], 'b' trailing displacements ('d', minitypes.CArrayType(uint16, 0)), #0xffff)), # ('entries_mem', PyCustomSlot_Entry[n]), # 'n' trailing customslot entries ])
import ctypes import unittest from collections import namedtuple from functools import partial import numba from numba import * from numba import ndarray_helpers import llvm.core as lc # ______________________________________________________________________ ArrayType = numba.struct([('data', double.pointer()), ('shape', int64.pointer()), ('strides', int64.pointer())]) Int32 = lc.Type.int(32) const = partial(lc.Constant.int, Int32) zero = const(0) one = const(1) two = const(2) def ptr_at(builder, ptr, idx): return builder.gep(ptr, [const(idx)]) def load_at(builder, ptr, idx): return builder.load(ptr_at(builder, ptr, idx)) def store_at(builder, ptr, idx, val):
""" scalar = array[0, 0] return scalar #------------------------------------------------------------------------ # Test type matching #------------------------------------------------------------------------ T1 = numba.template("T1") T2 = numba.template("T2") T3 = numba.template("T3") T4 = numba.template("T4") A = T1[:, :] F = void(T1) S = numba.struct(a=T1, b=T2.pointer(), c=T3[:], d=void(T4)) P = T2.pointer() type_context1 = { T1: int_, T2: float_, T3: double, T4: short, } type_context2 = { T1: int_[:, :], T2: void(float_), T3: numba.struct(a=double, b=float_), T4: short.pointer(), } def test_type_matching(array, func, struct, pointer): """ >>> infer(test_type_matching, template_signature=void(A, F, S, P), ... type_context=type_context1) [('array', int[:, :]), ('func', void (*)(int)), ('pointer', float *), ('struct', struct { float * b, double[:] c, int a, void (*)(short) d })] """ func(array[0, 0]) struct.b = pointer
scalar = array[0, 0] return scalar # ------------------------------------------------------------------------ # Test type matching # ------------------------------------------------------------------------ T1 = numba.template("T1") T2 = numba.template("T2") T3 = numba.template("T3") T4 = numba.template("T4") A = T1[:, :] F = void(T1) S = numba.struct([("a", T1), ("b", T2.pointer()), ("c", T3[:]), ("d", void(T4))]) P = T2.pointer() type_context1 = {T1: int_, T2: float_, T3: float64, T4: short} type_context2 = {T1: int_[:, :], T2: void(float32), T3: numba.struct(a=float64, b=float_), T4: short.pointer()} def test_type_matching(array, func, struct, pointer): """ >>> infer(test_type_matching, template_signature=void(A, F, S, P), ... type_context=type_context1) [('array', int[:, :]), ('func', void (*)(int)), ('pointer', float32 *), ('struct', struct { int a, float32 * b, float64[:] c, void (*)(short) d })] """ func(array[0, 0]) struct.b = pointer
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
import ctypes import unittest from collections import namedtuple from functools import partial import numba from numba import * from numba import ndarray_helpers import llvm.core as lc # ______________________________________________________________________ ArrayType = numba.struct([('data', double.pointer()), ('shape', int64.pointer()), ('strides', int64.pointer())]) Int32 = lc.Type.int(32) const = partial(lc.Constant.int, Int32) zero = const(0) one = const(1) two = const(2) def ptr_at(builder, ptr, idx): return builder.gep(ptr, [const(idx)]) def load_at(builder, ptr, idx): return builder.load(ptr_at(builder, ptr, idx)) def store_at(builder, ptr, idx, val): builder.store(val, ptr_at(builder, ptr, idx)) class MyArray(object):