####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. # The complete license agreement can be obtained at: # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## import inspect from .library import * from .util import * from .broadcast import * from .base import * from .index import * def create_array(buf, numdims, idims, dtype): out_arr = ct.c_longlong(0) ct.c_dims = dim4(idims[0], idims[1], idims[2], idims[3]) safe_call(clib.af_create_array(ct.pointer(out_arr), ct.c_longlong(buf),\ numdims, ct.pointer(ct.c_dims), dtype)) return out_arr def constant_array(val, d0, d1=None, d2=None, d3=None, dtype=f32): if not isinstance(dtype, ct.c_int): if isinstance(dtype, int): dtype = ct.c_int(dtype) else: raise TypeError("Invalid dtype") out = ct.c_longlong(0) dims = dim4(d0, d1, d2, d3) if isinstance(val, complex): c_real = ct.c_double(val.real) c_imag = ct.c_double(val.imag) if (dtype != c32 and dtype != c64): dtype = c32 safe_call(clib.af_constant_complex(ct.pointer(out), c_real, c_imag,\ 4, ct.pointer(dims), dtype)) elif dtype == s64: c_val = ct.c_longlong(val.real) safe_call(clib.af_constant_long(ct.pointer(out), c_val, 4, ct.pointer(dims))) elif dtype == u64: c_val = ct.c_ulonglong(val.real) safe_call(clib.af_constant_ulong(ct.pointer(out), c_val, 4, ct.pointer(dims))) else: c_val = ct.c_double(val) safe_call(clib.af_constant(ct.pointer(out), c_val, 4, ct.pointer(dims), dtype)) return out def binary_func(lhs, rhs, c_func): out = array() other = rhs if (is_number(rhs)): ldims = dim4_tuple(lhs.dims()) lty = lhs.type() other = array() other.arr = constant_array(rhs, ldims[0], ldims[1], ldims[2], ldims[3], lty) elif not isinstance(rhs, array): raise TypeError("Invalid parameter to binary function") safe_call(c_func(ct.pointer(out.arr), lhs.arr, other.arr, bcast.get())) return out def binary_funcr(lhs, rhs, c_func): out = array() other = lhs if (is_number(lhs)): rdims = dim4_tuple(rhs.dims()) rty = rhs.type() other = array() other.arr = constant_array(lhs, rdims[0], rdims[1], rdims[2], rdims[3], rty) elif not isinstance(lhs, array): raise TypeError("Invalid parameter to binary function") c_func(ct.pointer(out.arr), other.arr, rhs.arr, bcast.get()) return out def transpose(a, conj=False): out = array() safe_call(clib.af_transpose(ct.pointer(out.arr), a.arr, conj)) return out def transpose_inplace(a, conj=False): safe_call(clib.af_transpose_inplace(a.arr, conj)) def ctype_to_lists(ctype_arr, dim, shape, offset=0): if (dim == 0): return list(ctype_arr[offset : offset + shape[0]]) else: dim_len = shape[dim] res = [[]] * dim_len for n in range(dim_len): res[n] = ctype_to_lists(ctype_arr, dim - 1, shape, offset) offset += shape[0] return res def get_info(dims, buf_len): elements = 1 numdims = len(dims) idims = [1]*4 for i in range(numdims): elements *= dims[i] idims[i] = dims[i] if (elements == 0): if (buf_len != 0): idims = [buf_len, 1, 1, 1] numdims = 1 else: raise RuntimeError("Invalid size") return numdims, idims class array(base_array): def __init__(self, src=None, dims=(0,), type_char=None): super(array, self).__init__() buf=None buf_len=0 _type_char='f' dtype = f32 if src is not None: if (isinstance(src, array)): safe_call(clib.af_retain_array(ct.pointer(self.arr), src.arr)) return host = __import__("array") if isinstance(src, host.array): buf,buf_len = src.buffer_info() _type_char = src.typecode numdims, idims = get_info(dims, buf_len) elif isinstance(src, list): tmp = host.array('f', src) buf,buf_len = tmp.buffer_info() _type_char = tmp.typecode numdims, idims = get_info(dims, buf_len) elif isinstance(src, int) or isinstance(src, ct.c_ulonglong): buf = src numdims, idims = get_info(dims, buf_len) elements = 1 for dim in idims: elements *= dim if (elements == 0): raise RuntimeError("Expected dims when src is data pointer") if (type_char is None): raise TypeError("Expected type_char when src is data pointer") _type_char = type_char else: raise TypeError("src is an object of unsupported class") if (type_char is not None and type_char != _type_char): raise TypeError("Can not create array of requested type from input data type") self.arr = create_array(buf, numdims, idims, to_dtype[_type_char]) def copy(self): out = array() safe_call(clib.af_retain_array(ct.pointer(out.arr), self.arr)) return out def __del__(self): if (self.arr.value != 0): clib.af_release_array(self.arr) def elements(self): num = ct.c_ulonglong(0) safe_call(clib.af_get_elements(ct.pointer(num), self.arr)) return num.value def type(self): dty = ct.c_int(f32.value) safe_call(clib.af_get_type(ct.pointer(dty), self.arr)) return dty.value def dims(self): d0 = ct.c_longlong(0) d1 = ct.c_longlong(0) d2 = ct.c_longlong(0) d3 = ct.c_longlong(0) safe_call(clib.af_get_dims(ct.pointer(d0), ct.pointer(d1),\ ct.pointer(d2), ct.pointer(d3), self.arr)) dims = (d0.value,d1.value,d2.value,d3.value) return dims[:self.numdims()] def numdims(self): nd = ct.c_uint(0) safe_call(clib.af_get_numdims(ct.pointer(nd), self.arr)) return nd.value def is_empty(self): res = ct.c_bool(False) safe_call(clib.af_is_empty(ct.pointer(res), self.arr)) return res.value def is_scalar(self): res = ct.c_bool(False) safe_call(clib.af_is_scalar(ct.pointer(res), self.arr)) return res.value def is_row(self): res = ct.c_bool(False) safe_call(clib.af_is_row(ct.pointer(res), self.arr)) return res.value def is_column(self): res = ct.c_bool(False) safe_call(clib.af_is_column(ct.pointer(res), self.arr)) return res.value def is_vector(self): res = ct.c_bool(False) safe_call(clib.af_is_vector(ct.pointer(res), self.arr)) return res.value def is_complex(self): res = ct.c_bool(False) safe_call(clib.af_is_complex(ct.pointer(res), self.arr)) return res.value def is_real(self): res = ct.c_bool(False) safe_call(clib.af_is_real(ct.pointer(res), self.arr)) return res.value def is_double(self): res = ct.c_bool(False) safe_call(clib.af_is_double(ct.pointer(res), self.arr)) return res.value def is_single(self): res = ct.c_bool(False) safe_call(clib.af_is_single(ct.pointer(res), self.arr)) return res.value def is_real_floating(self): res = ct.c_bool(False) safe_call(clib.af_is_realfloating(ct.pointer(res), self.arr)) return res.value def is_floating(self): res = ct.c_bool(False) safe_call(clib.af_is_floating(ct.pointer(res), self.arr)) return res.value def is_integer(self): res = ct.c_bool(False) safe_call(clib.af_is_integer(ct.pointer(res), self.arr)) return res.value def is_bool(self): res = ct.c_bool(False) safe_call(clib.af_is_bool(ct.pointer(res), self.arr)) return res.value def __add__(self, other): return binary_func(self, other, clib.af_add) def __iadd__(self, other): self = binary_func(self, other, clib.af_add) return self def __radd__(self, other): return binary_funcr(other, self, clib.af_add) def __sub__(self, other): return binary_func(self, other, clib.af_sub) def __isub__(self, other): self = binary_func(self, other, clib.af_sub) return self def __rsub__(self, other): return binary_funcr(other, self, clib.af_sub) def __mul__(self, other): return binary_func(self, other, clib.af_mul) def __imul__(self, other): self = binary_func(self, other, clib.af_mul) return self def __rmul__(self, other): return binary_funcr(other, self, clib.af_mul) # Necessary for python3 def __truediv__(self, other): return binary_func(self, other, clib.af_div) def __itruediv__(self, other): self = binary_func(self, other, clib.af_div) return self def __rtruediv__(self, other): return binary_funcr(other, self, clib.af_div) # Necessary for python2 def __div__(self, other): return binary_func(self, other, clib.af_div) def __idiv__(self, other): self = binary_func(self, other, clib.af_div) return self def __rdiv__(self, other): return binary_funcr(other, self, clib.af_div) def __mod__(self, other): return binary_func(self, other, clib.af_mod) def __imod__(self, other): self = binary_func(self, other, clib.af_mod) return self def __rmod__(self, other): return binary_funcr(other, self, clib.af_mod) def __pow__(self, other): return binary_func(self, other, clib.af_pow) def __ipow__(self, other): self = binary_func(self, other, clib.af_pow) return self def __rpow__(self, other): return binary_funcr(other, self, clib.af_pow) def __lt__(self, other): return binary_func(self, other, clib.af_lt) def __gt__(self, other): return binary_func(self, other, clib.af_gt) def __le__(self, other): return binary_func(self, other, clib.af_le) def __ge__(self, other): return binary_func(self, other, clib.af_ge) def __eq__(self, other): return binary_func(self, other, clib.af_eq) def __ne__(self, other): return binary_func(self, other, clib.af_neq) def __and__(self, other): return binary_func(self, other, clib.af_bitand) def __iand__(self, other): self = binary_func(self, other, clib.af_bitand) return self def __or__(self, other): return binary_func(self, other, clib.af_bitor) def __ior__(self, other): self = binary_func(self, other, clib.af_bitor) return self def __xor__(self, other): return binary_func(self, other, clib.af_bitxor) def __ixor__(self, other): self = binary_func(self, other, clib.af_bitxor) return self def __lshift__(self, other): return binary_func(self, other, clib.af_bitshiftl) def __ilshift__(self, other): self = binary_func(self, other, clib.af_bitshiftl) return self def __rshift__(self, other): return binary_func(self, other, clib.af_bitshiftr) def __irshift__(self, other): self = binary_func(self, other, clib.af_bitshiftr) return self def __neg__(self): return 0 - self def __pos__(self): return self def __invert__(self): return self == 0 def __nonzero__(self): return self != 0 # TODO: # def __abs__(self): # return self def __getitem__(self, key): try: out = array() n_dims = self.numdims() inds = get_indices(key, n_dims) safe_call(clib.af_index_gen(ct.pointer(out.arr),\ self.arr, ct.c_longlong(n_dims), ct.pointer(inds))) return out except RuntimeError as e: raise IndexError(str(e)) def __setitem__(self, key, val): try: n_dims = self.numdims() if (is_number(val)): tdims = get_assign_dims(key, self.dims()) other_arr = constant_array(val, tdims[0], tdims[1], tdims[2], tdims[3]) else: other_arr = val.arr out_arr = ct.c_longlong(0) inds = get_indices(key, n_dims) safe_call(clib.af_assign_gen(ct.pointer(out_arr),\ self.arr, ct.c_longlong(n_dims), ct.pointer(inds),\ other_arr)) safe_call(clib.af_release_array(self.arr)) self.arr = out_arr except RuntimeError as e: raise IndexError(str(e)) def to_ctype(self, row_major=False, return_shape=False): if (self.arr.value == 0): raise RuntimeError("Can not call to_ctype on empty array") tmp = transpose(self) if row_major else self ctype_type = to_c_type[self.type()] * self.elements() res = ctype_type() safe_call(clib.af_get_data_ptr(ct.pointer(res), self.arr)) if (return_shape): return res, self.dims() else: return res def to_array(self, row_major=False, return_shape=False): if (self.arr.value == 0): raise RuntimeError("Can not call to_array on empty array") res = self.to_ctype(row_major, return_shape) host = __import__("array") h_type = to_typecode[self.type()] if (return_shape): return host.array(h_type, res[0]), res[1] else: return host.array(h_type, res) def to_list(self, row_major=False): ct_array, shape = self.to_ctype(row_major, True) return ctype_to_lists(ct_array, len(shape) - 1, shape) def display(a): expr = inspect.stack()[1][-2] if (expr is not None): print('%s' % expr[0].split('display(')[1][:-2]) safe_call(clib.af_print_array(a.arr))