######################################################## 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########################################################"""Array class and helper functions."""importinspectimportosfrom.libraryimport*from.utilimport*from.utilimport_is_numberfrom.bcastimport_bcast_varfrom.baseimport*from.indeximport*from.indeximport_Index4_is_running_in_py_charm="PYCHARM_HOSTED"inos.environ_display_dims_limit=None[docs]defset_display_dims_limit(*dims):""" Sets the dimension limit after which array's data won't get presented to the result of str(arr). Default is None, which means there is no limit. Parameters ---------- *dims : dimension limit args Example ------- set_display_dims_limit(10, 10, 10, 10) """global_display_dims_limit_display_dims_limit=dims [docs]defget_display_dims_limit():""" Gets the dimension limit after which array's data won't get presented to the result of str(arr). Default is None, which means there is no limit. Returns ----------- - tuple of the current limit - None is there is no limit Example ------- get_display_dims_limit() # None set_display_dims_limit(10, 10, 10, 10) get_display_dims_limit() # (10, 10, 10, 10) """return_display_dims_limit def_in_display_dims_limit(dims):if_is_running_in_py_charm:returnFalseif_display_dims_limitisnotNone:limit_len=len(_display_dims_limit)dim_len=len(dims)ifdim_len>limit_len:returnFalseforiinrange(dim_len):ifdims[i]>_display_dims_limit[i]:returnFalsereturnTruedef_create_array(buf,numdims,idims,dtype,is_device):out_arr=c_void_ptr_t(0)c_dims=dim4(idims[0],idims[1],idims[2],idims[3])if(notis_device):safe_call(backend.get().af_create_array(c_pointer(out_arr),c_void_ptr_t(buf),numdims,c_pointer(c_dims),dtype.value))else:safe_call(backend.get().af_device_array(c_pointer(out_arr),c_void_ptr_t(buf),numdims,c_pointer(c_dims),dtype.value))returnout_arrdef_create_strided_array(buf,numdims,idims,dtype,is_device,offset,strides):out_arr=c_void_ptr_t(0)c_dims=dim4(idims[0],idims[1],idims[2],idims[3])ifoffsetisNone:offset=0offset=c_dim_t(offset)ifstridesisNone:strides=(1,idims[0],idims[0]*idims[1],idims[0]*idims[1]*idims[2])whilelen(strides)<4:strides=strides+(strides[-1],)strides=dim4(strides[0],strides[1],strides[2],strides[3])ifis_device:location=Source.deviceelse:location=Source.hostsafe_call(backend.get().af_create_strided_array(c_pointer(out_arr),c_void_ptr_t(buf),offset,numdims,c_pointer(c_dims),c_pointer(strides),dtype.value,location.value))returnout_arrdef_create_empty_array(numdims,idims,dtype):out_arr=c_void_ptr_t(0)ifnumdims==0:returnout_arrc_dims=dim4(idims[0],idims[1],idims[2],idims[3])safe_call(backend.get().af_create_handle(c_pointer(out_arr),numdims,c_pointer(c_dims),dtype.value))returnout_arr[docs]defconstant_array(val,d0,d1=None,d2=None,d3=None,dtype=Dtype.f32):""" Internal function to create a C array. Should not be used externall. """ifnotisinstance(dtype,c_int_t):ifisinstance(dtype,int):dtype=c_int_t(dtype)elifisinstance(dtype,Dtype):dtype=c_int_t(dtype.value)else:raiseTypeError("Invalid dtype")out=c_void_ptr_t(0)dims=dim4(d0,d1,d2,d3)ifisinstance(val,complex):c_real=c_double_t(val.real)c_imag=c_double_t(val.imag)if(dtype.value!=Dtype.c32.valueanddtype.value!=Dtype.c64.value):dtype=Dtype.c32.valuesafe_call(backend.get().af_constant_complex(c_pointer(out),c_real,c_imag,4,c_pointer(dims),dtype))elifdtype.value==Dtype.s64.value:c_val=c_longlong_t(val.real)safe_call(backend.get().af_constant_long(c_pointer(out),c_val,4,c_pointer(dims)))elifdtype.value==Dtype.u64.value:c_val=c_ulonglong_t(val.real)safe_call(backend.get().af_constant_ulong(c_pointer(out),c_val,4,c_pointer(dims)))else:c_val=c_double_t(val)safe_call(backend.get().af_constant(c_pointer(out),c_val,4,c_pointer(dims),dtype))returnout def_binary_func(lhs,rhs,c_func):out=Array()other=rhsif(_is_number(rhs)):ldims=dim4_to_tuple(lhs.dims())rty=implicit_dtype(rhs,lhs.type())other=Array()other.arr=constant_array(rhs,ldims[0],ldims[1],ldims[2],ldims[3],rty.value)elifnotisinstance(rhs,Array):raiseTypeError("Invalid parameter to binary function")safe_call(c_func(c_pointer(out.arr),lhs.arr,other.arr,_bcast_var.get()))returnoutdef_binary_funcr(lhs,rhs,c_func):out=Array()other=lhsif(_is_number(lhs)):rdims=dim4_to_tuple(rhs.dims())lty=implicit_dtype(lhs,rhs.type())other=Array()other.arr=constant_array(lhs,rdims[0],rdims[1],rdims[2],rdims[3],lty.value)elifnotisinstance(lhs,Array):raiseTypeError("Invalid parameter to binary function")c_func(c_pointer(out.arr),other.arr,rhs.arr,_bcast_var.get())returnoutdef_ctype_to_lists(ctype_arr,dim,shape,offset=0):if(dim==0):returnlist(ctype_arr[offset:offset+shape[0]])else:dim_len=shape[dim]res=[[]]*dim_lenforninrange(dim_len):res[n]=_ctype_to_lists(ctype_arr,dim-1,shape,offset)offset+=shape[0]returnresdef_slice_to_length(key,dim):tkey=[key.start,key.stop,key.step]iftkey[0]isNone:tkey[0]=0eliftkey[0]<0:tkey[0]=dim-tkey[0]iftkey[1]isNone:tkey[1]=dimeliftkey[1]<0:tkey[1]=dim-tkey[1]iftkey[2]isNone:tkey[2]=1returnint(((tkey[1]-tkey[0]-1)/tkey[2])+1)def_get_info(dims,buf_len):elements=1numdims=0ifdims:numdims=len(dims)idims=[1]*4foriinrange(numdims):elements*=dims[i]idims[i]=dims[i]elif(buf_len!=0):idims=[buf_len,1,1,1]numdims=1else:raiseRuntimeError("Invalid size")returnnumdims,idimsdef_get_indices(key):inds=_Index4()ifisinstance(key,tuple):n_idx=len(key)forninrange(n_idx):inds[n]=Index(key[n])else:inds[0]=Index(key)returnindsdef_get_assign_dims(key,idims):dims=[1]*4forninrange(len(idims)):dims[n]=idims[n]if_is_number(key):dims[0]=1returndimselifisinstance(key,slice):dims[0]=_slice_to_length(key,idims[0])returndimselifisinstance(key,ParallelRange):dims[0]=_slice_to_length(key.S,idims[0])returndimselifisinstance(key,BaseArray):# If the array is boolean take only the number of nonzerosif(key.dtype()isDtype.b8):dims[0]=int(sum(key))else:dims[0]=key.elements()returndimselifisinstance(key,tuple):n_inds=len(key)forninrange(n_inds):if(_is_number(key[n])):dims[n]=1elif(isinstance(key[n],BaseArray)):# If the array is boolean take only the number of nonzerosif(key[n].dtype()isDtype.b8):dims[n]=int(sum(key[n]))else:dims[n]=key[n].elements()elif(isinstance(key[n],slice)):dims[n]=_slice_to_length(key[n],idims[n])elif(isinstance(key[n],ParallelRange)):dims[n]=_slice_to_length(key[n].S,idims[n])else:raiseIndexError("Invalid type while assigning to arrayfire.array")returndimselse:raiseIndexError("Invalid type while assigning to arrayfire.array")[docs]deftranspose(a,conj=False):""" Perform the transpose on an input. Parameters ----------- a : af.Array Multi dimensional arrayfire array. conj : optional: bool. default: False. Flag to specify if a complex conjugate needs to applied for complex inputs. Returns -------- out : af.Array Containing the tranpose of `a` for all batches. """out=Array()safe_call(backend.get().af_transpose(c_pointer(out.arr),a.arr,conj))returnout [docs]deftranspose_inplace(a,conj=False):""" Perform inplace transpose on an input. Parameters ----------- a : af.Array - Multi dimensional arrayfire array. - Contains transposed values on exit. conj : optional: bool. default: False. Flag to specify if a complex conjugate needs to applied for complex inputs. Note ------- Input `a` needs to be a square matrix or a batch of square matrices. """safe_call(backend.get().af_transpose_inplace(a.arr,conj)) [docs]classArray(BaseArray):""" A multi dimensional array container. Parameters ---------- src : optional: array.array, list or C buffer. default: None. - When `src` is `array.array` or `list`, the data is copied to create the Array() - When `src` is None, an empty buffer is created. dims : optional: tuple of ints. default: (0,) - When using the default values of `dims`, the dims are caclulated as `len(src)` dtype: optional: str or arrayfire.Dtype. default: None. - if str, must be one of the following: - 'f' for float - 'd' for double - 'b' for bool - 'B' for unsigned char - 'h' for signed 16 bit integer - 'H' for unsigned 16 bit integer - 'i' for signed 32 bit integer - 'I' for unsigned 32 bit integer - 'l' for signed 64 bit integer - 'L' for unsigned 64 bit integer - 'F' for 32 bit complex number - 'D' for 64 bit complex number - if arrayfire.Dtype, must be one of the following: - Dtype.f32 for float - Dtype.f64 for double - Dtype.b8 for bool - Dtype.u8 for unsigned char - Dtype.s16 for signed 16 bit integer - Dtype.u16 for unsigned 16 bit integer - Dtype.s32 for signed 32 bit integer - Dtype.u32 for unsigned 32 bit integer - Dtype.s64 for signed 64 bit integer - Dtype.u64 for unsigned 64 bit integer - Dtype.c32 for 32 bit complex number - Dtype.c64 for 64 bit complex number - if None, Dtype.f32 is assumed Attributes ----------- arr: ctypes.c_void_p ctypes variable containing af_array from arrayfire library. Examples -------- Creating an af.Array() from array.array() >>> import arrayfire as af >>> import array >>> a = array.array('f', (1, 2, 3, 4)) >>> b = af.Array(a, (2,2)) >>> af.display(b) [2 2 1 1] 1.0000 3.0000 2.0000 4.0000 Creating an af.Array() from a list >>> import arrayfire as af >>> import array >>> a = [1, 2, 3, 4] >>> b = af.Array(a) >>> af.display(b) [4 1 1 1] 1.0000 2.0000 3.0000 4.0000 Creating an af.Array() from numpy.array() >>> import numpy as np >>> import arrayfire as af >>> a = np.random.random((2,2)) >>> a array([[ 0.33042524, 0.36135449], [ 0.86748649, 0.42199135]]) >>> b = af.Array(a.ctypes.data, a.shape, a.dtype.char) >>> af.display(b) [2 2 1 1] 0.3304 0.8675 0.3614 0.4220 Note ----- - The class is currently limited to 4 dimensions. - arrayfire.Array() uses column major format. - numpy uses row major format by default which can cause issues during conversion """# Numpy checks this attribute to know which class handles binary builtin operations, such as __add__.# Setting to such a high value should make sure that arrayfire has priority over# other classes, ensuring that e.g. numpy.float32(1)*arrayfire.randu(3) is handled by# arrayfire's __radd__() instead of numpy's __add__()__array_priority__=30def__init__(self,src=None,dims=None,dtype=None,is_device=False,offset=None,strides=None):super(Array,self).__init__()buf=Nonebuf_len=0ifdtypeisnotNone:ifisinstance(dtype,str):type_char=dtypeelse:type_char=to_typecode[dtype.value]else:type_char=None_type_char='f'ifsrcisnotNone:if(isinstance(src,Array)):safe_call(backend.get().af_retain_array(c_pointer(self.arr),src.arr))returnhost=__import__("array")ifisinstance(src,host.array):buf,buf_len=src.buffer_info()_type_char=src.typecodenumdims,idims=_get_info(dims,buf_len)elifisinstance(src,list):tmp=host.array('f',src)buf,buf_len=tmp.buffer_info()_type_char=tmp.typecodenumdims,idims=_get_info(dims,buf_len)elifisinstance(src,int)orisinstance(src,c_void_ptr_t):buf=srcifnotisinstance(src,c_void_ptr_t)elsesrc.valuenumdims,idims=_get_info(dims,buf_len)elements=1fordiminidims:elements*=dimif(elements==0):raiseRuntimeError("Expected dims when src is data pointer")if(type_charisNone):raiseTypeError("Expected type_char when src is data pointer")_type_char=type_charelse:raiseTypeError("src is an object of unsupported class")if(type_charisnotNoneandtype_char!=_type_char):raiseTypeError("Can not create array of requested type from input data type")if(offsetisNoneandstridesisNone):self.arr=_create_array(buf,numdims,idims,to_dtype[_type_char],is_device)else:self.arr=_create_strided_array(buf,numdims,idims,to_dtype[_type_char],is_device,offset,strides)else:iftype_charisNone:type_char='f'numdims=len(dims)ifdimselse0idims=[1]*4forninrange(numdims):idims[n]=dims[n]self.arr=_create_empty_array(numdims,idims,to_dtype[type_char])[docs]defas_type(self,ty):""" Cast current array to a specified data type Parameters ---------- ty : Return data type """returncast(self,ty) [docs]defcopy(self):""" Performs a deep copy of the array. Returns ------- out: af.Array() An identical copy of self. """out=Array()safe_call(backend.get().af_copy_array(c_pointer(out.arr),self.arr))returnout def__del__(self):""" Release the C array when going out of scope """ifself.arr.value:backend.get().af_release_array(self.arr)self.arr.value=0[docs]defdevice_ptr(self):""" Return the device pointer exclusively held by the array. Returns -------- ptr : int Contains location of the device pointer Note ---- - This can be used to integrate with custom C code and / or PyCUDA or PyOpenCL. - Implies `af.device.lock_array()`. The device pointer of `a` is not freed by memory manager until `unlock_device_ptr()` is called. - No other arrays will share the same device pointer. - A copy of the memory is done if multiple arrays share the same memory or the array is not the owner of the memory. - In case of a copy the return value points to the newly allocated memory which is now exclusively owned by the array. """ptr=c_void_ptr_t(0)backend.get().af_get_device_ptr(c_pointer(ptr),self.arr)returnptr.value [docs]defraw_ptr(self):""" Return the device pointer held by the array. Returns -------- ptr : int Contains location of the device pointer Note ---- - This can be used to integrate with custom C code and / or PyCUDA or PyOpenCL. - No mem copy is peformed, this function returns the raw device pointer. - This pointer may be shared with other arrays. Use this function with caution. - In particular the JIT compiler will not be aware of the shared arrays. - This results in JITed operations not being immediately visible through the other array. """ptr=c_void_ptr_t(0)backend.get().af_get_raw_ptr(c_pointer(ptr),self.arr)returnptr.value [docs]defoffset(self):""" Return the offset, of the first element relative to the raw pointer. Returns -------- offset : int The offset in number of elements """offset=c_dim_t(0)safe_call(backend.get().af_get_offset(c_pointer(offset),self.arr))returnoffset.value [docs]defstrides(self):""" Return the distance in bytes between consecutive elements for each dimension. Returns -------- strides : tuple The strides for each dimension """s0=c_dim_t(0)s1=c_dim_t(0)s2=c_dim_t(0)s3=c_dim_t(0)safe_call(backend.get().af_get_strides(c_pointer(s0),c_pointer(s1),c_pointer(s2),c_pointer(s3),self.arr))strides=(s0.value,s1.value,s2.value,s3.value)returnstrides[:self.numdims()] [docs]defelements(self):""" Return the number of elements in the array. """num=c_dim_t(0)safe_call(backend.get().af_get_elements(c_pointer(num),self.arr))returnnum.value def__len__(self):return(self.elements())[docs]defallocated(self):""" Returns the number of bytes allocated by the memory manager for the array. """num=c_size_t(0)safe_call(backend.get().af_get_allocated_bytes(c_pointer(num),self.arr))returnnum.value [docs]defdtype(self):""" Return the data type as a arrayfire.Dtype enum value. """dty=c_int_t(Dtype.f32.value)safe_call(backend.get().af_get_type(c_pointer(dty),self.arr))returnto_dtype[to_typecode[dty.value]] [docs]deftype(self):""" Return the data type as an int. """returnself.dtype().value @propertydefT(self):""" Return the transpose of the array """returntranspose(self,False)@propertydefH(self):""" Return the hermitian transpose of the array """returntranspose(self,True)[docs]defdims(self):""" Return the shape of the array as a tuple. """d0=c_dim_t(0)d1=c_dim_t(0)d2=c_dim_t(0)d3=c_dim_t(0)safe_call(backend.get().af_get_dims(c_pointer(d0),c_pointer(d1),c_pointer(d2),c_pointer(d3),self.arr))dims=(d0.value,d1.value,d2.value,d3.value)returndims[:self.numdims()] @propertydefshape(self):""" The shape of the array """returnself.dims()[docs]defnumdims(self):""" Return the number of dimensions of the array. """nd=c_uint_t(0)safe_call(backend.get().af_get_numdims(c_pointer(nd),self.arr))returnnd.value [docs]defis_empty(self):""" Check if the array is empty i.e. it has no elements. """res=c_bool_t(False)safe_call(backend.get().af_is_empty(c_pointer(res),self.arr))returnres.value [docs]defis_scalar(self):""" Check if the array is scalar i.e. it has only one element. """res=c_bool_t(False)safe_call(backend.get().af_is_scalar(c_pointer(res),self.arr))returnres.value [docs]defis_row(self):""" Check if the array is a row i.e. it has a shape of (1, cols). """res=c_bool_t(False)safe_call(backend.get().af_is_row(c_pointer(res),self.arr))returnres.value [docs]defis_column(self):""" Check if the array is a column i.e. it has a shape of (rows, 1). """res=c_bool_t(False)safe_call(backend.get().af_is_column(c_pointer(res),self.arr))returnres.value [docs]defis_vector(self):""" Check if the array is a vector i.e. it has a shape of one of the following: - (rows, 1) - (1, cols) - (1, 1, vols) - (1, 1, 1, batch) """res=c_bool_t(False)safe_call(backend.get().af_is_vector(c_pointer(res),self.arr))returnres.value [docs]defis_sparse(self):""" Check if the array is a sparse matrix. """res=c_bool_t(False)safe_call(backend.get().af_is_sparse(c_pointer(res),self.arr))returnres.value [docs]defis_complex(self):""" Check if the array is of complex type. """res=c_bool_t(False)safe_call(backend.get().af_is_complex(c_pointer(res),self.arr))returnres.value [docs]defis_real(self):""" Check if the array is not of complex type. """res=c_bool_t(False)safe_call(backend.get().af_is_real(c_pointer(res),self.arr))returnres.value [docs]defis_double(self):""" Check if the array is of double precision floating point type. """res=c_bool_t(False)safe_call(backend.get().af_is_double(c_pointer(res),self.arr))returnres.value [docs]defis_single(self):""" Check if the array is of single precision floating point type. """res=c_bool_t(False)safe_call(backend.get().af_is_single(c_pointer(res),self.arr))returnres.value [docs]defis_half(self):""" Check if the array is of half floating point type (fp16). """res=c_bool_t(False)safe_call(backend.get().af_is_half(c_pointer(res),self.arr))returnres.value [docs]defis_real_floating(self):""" Check if the array is real and of floating point type. """res=c_bool_t(False)safe_call(backend.get().af_is_realfloating(c_pointer(res),self.arr))returnres.value [docs]defis_floating(self):""" Check if the array is of floating point type. """res=c_bool_t(False)safe_call(backend.get().af_is_floating(c_pointer(res),self.arr))returnres.value [docs]defis_integer(self):""" Check if the array is of integer type. """res=c_bool_t(False)safe_call(backend.get().af_is_integer(c_pointer(res),self.arr))returnres.value [docs]defis_bool(self):""" Check if the array is of type b8. """res=c_bool_t(False)safe_call(backend.get().af_is_bool(c_pointer(res),self.arr))returnres.value [docs]defis_linear(self):""" Check if all elements of the array are contiguous. """res=c_bool_t(False)safe_call(backend.get().af_is_linear(c_pointer(res),self.arr))returnres.value [docs]defis_owner(self):""" Check if the array owns the raw pointer or is a derived array. """res=c_bool_t(False)safe_call(backend.get().af_is_owner(c_pointer(res),self.arr))returnres.value def__add__(self,other):""" Return self + other. """return_binary_func(self,other,backend.get().af_add)def__iadd__(self,other):""" Perform self += other. """self=_binary_func(self,other,backend.get().af_add)returnselfdef__radd__(self,other):""" Return other + self. """return_binary_funcr(other,self,backend.get().af_add)def__sub__(self,other):""" Return self - other. """return_binary_func(self,other,backend.get().af_sub)def__isub__(self,other):""" Perform self -= other. """self=_binary_func(self,other,backend.get().af_sub)returnselfdef__rsub__(self,other):""" Return other - self. """return_binary_funcr(other,self,backend.get().af_sub)def__mul__(self,other):""" Return self * other. """return_binary_func(self,other,backend.get().af_mul)def__imul__(self,other):""" Perform self *= other. """self=_binary_func(self,other,backend.get().af_mul)returnselfdef__rmul__(self,other):""" Return other * self. """return_binary_funcr(other,self,backend.get().af_mul)def__truediv__(self,other):""" Return self / other. """return_binary_func(self,other,backend.get().af_div)def__itruediv__(self,other):""" Perform self /= other. """self=_binary_func(self,other,backend.get().af_div)returnselfdef__rtruediv__(self,other):""" Return other / self. """return_binary_funcr(other,self,backend.get().af_div)def__div__(self,other):""" Return self / other. """return_binary_func(self,other,backend.get().af_div)def__idiv__(self,other):""" Perform other / self. """self=_binary_func(self,other,backend.get().af_div)returnselfdef__rdiv__(self,other):""" Return other / self. """return_binary_funcr(other,self,backend.get().af_div)def__mod__(self,other):""" Return self % other. """return_binary_func(self,other,backend.get().af_mod)def__imod__(self,other):""" Perform self %= other. """self=_binary_func(self,other,backend.get().af_mod)returnselfdef__rmod__(self,other):""" Return other % self. """return_binary_funcr(other,self,backend.get().af_mod)def__pow__(self,other):""" Return self ** other. """return_binary_func(self,other,backend.get().af_pow)def__ipow__(self,other):""" Perform self **= other. """self=_binary_func(self,other,backend.get().af_pow)returnselfdef__rpow__(self,other):""" Return other ** self. """return_binary_funcr(other,self,backend.get().af_pow)def__lt__(self,other):""" Return self < other. """return_binary_func(self,other,backend.get().af_lt)def__gt__(self,other):""" Return self > other. """return_binary_func(self,other,backend.get().af_gt)def__le__(self,other):""" Return self <= other. """return_binary_func(self,other,backend.get().af_le)def__ge__(self,other):""" Return self >= other. """return_binary_func(self,other,backend.get().af_ge)def__eq__(self,other):""" Return self == other. """return_binary_func(self,other,backend.get().af_eq)def__ne__(self,other):""" Return self != other. """return_binary_func(self,other,backend.get().af_neq)def__and__(self,other):""" Return self & other. """return_binary_func(self,other,backend.get().af_bitand)def__iand__(self,other):""" Perform self &= other. """self=_binary_func(self,other,backend.get().af_bitand)returnselfdef__or__(self,other):""" Return self | other. """return_binary_func(self,other,backend.get().af_bitor)def__ior__(self,other):""" Perform self |= other. """self=_binary_func(self,other,backend.get().af_bitor)returnselfdef__xor__(self,other):""" Return self ^ other. """return_binary_func(self,other,backend.get().af_bitxor)def__ixor__(self,other):""" Perform self ^= other. """self=_binary_func(self,other,backend.get().af_bitxor)returnselfdef__lshift__(self,other):""" Return self << other. """return_binary_func(self,other,backend.get().af_bitshiftl)def__ilshift__(self,other):""" Perform self <<= other. """self=_binary_func(self,other,backend.get().af_bitshiftl)returnselfdef__rshift__(self,other):""" Return self >> other. """return_binary_func(self,other,backend.get().af_bitshiftr)def__irshift__(self,other):""" Perform self >>= other. """self=_binary_func(self,other,backend.get().af_bitshiftr)returnselfdef__neg__(self):""" Return -self """return0-selfdef__pos__(self):""" Return +self """returnselfdef__invert__(self):""" Return ~self """out=Array()safe_call(backend.get().af_bitnot(c_pointer(out.arr),self.arr))returnout[docs]deflogical_not(self):""" Return ~self """out=Array()safe_call(backend.get().af_not(c_pointer(out.arr),self.arr))returnout [docs]deflogical_and(self,other):""" Return self && other. """out=Array()safe_call(backend.get().af_and(c_pointer(out.arr),self.arr,other.arr))#TODO: bcast var?returnout [docs]deflogical_or(self,other):""" Return self || other. """out=Array()safe_call(backend.get().af_or(c_pointer(out.arr),self.arr,other.arr))#TODO: bcast var?returnout def__nonzero__(self):returnself!=0# TODO:# def __abs__(self):# return selfdef__getitem__(self,key):""" Return self[key] Note ---- Ellipsis not supported as key """try:out=Array()n_dims=self.numdims()if(isinstance(key,Array)andkey.type()==Dtype.b8.value):n_dims=1if(count(key)==0):returnoutinds=_get_indices(key)safe_call(backend.get().af_index_gen(c_pointer(out.arr),self.arr,c_dim_t(n_dims),inds.pointer))returnoutexceptRuntimeErrorase:raiseIndexError(str(e))def__setitem__(self,key,val):""" Perform self[key] = val Note ---- Ellipsis not supported as key """try:n_dims=self.numdims()is_boolean_idx=isinstance(key,Array)andkey.type()==Dtype.b8.valueif(is_boolean_idx):n_dims=1num=count(key)if(num==0):returnif(_is_number(val)):tdims=_get_assign_dims(key,self.dims())if(is_boolean_idx):n_dims=1other_arr=constant_array(val,int(num),dtype=self.type())else:other_arr=constant_array(val,tdims[0],tdims[1],tdims[2],tdims[3],self.type())del_other=Trueelse:other_arr=val.arrdel_other=Falseout_arr=c_void_ptr_t(0)inds=_get_indices(key)safe_call(backend.get().af_assign_gen(c_pointer(out_arr),self.arr,c_dim_t(n_dims),inds.pointer,other_arr))safe_call(backend.get().af_release_array(self.arr))ifdel_other:safe_call(backend.get().af_release_array(other_arr))self.arr=out_arrexceptRuntimeErrorase:raiseIndexError(str(e))def_reorder(self):""" Returns a reordered array to help interoperate with row major formats. """ndims=self.numdims()if(ndims==1):returnselfrdims=tuple(reversed(range(ndims)))+tuple(range(ndims,4))out=Array()safe_call(backend.get().af_reorder(c_pointer(out.arr),self.arr,*rdims))returnout[docs]defto_ctype(self,row_major=False,return_shape=False):""" Return the data as a ctype C array after copying to host memory Parameters ----------- row_major: optional: bool. default: False. Specifies if a transpose needs to occur before copying to host memory. return_shape: optional: bool. default: False. Specifies if the shape of the array needs to be returned. Returns ------- If return_shape is False: res: The ctypes array of the appropriate type and length. else : (res, dims): tuple of the ctypes array and the shape of the array """if(self.arr.value==0):raiseRuntimeError("Can not call to_ctype on empty array")tmp=self._reorder()if(row_major)elseselfctype_type=to_c_type[self.type()]*self.elements()res=ctype_type()safe_call(backend.get().af_get_data_ptr(c_pointer(res),self.arr))if(return_shape):returnres,self.dims()else:returnres [docs]defto_array(self,row_major=False,return_shape=False):""" Return the data as array.array Parameters ----------- row_major: optional: bool. default: False. Specifies if a transpose needs to occur before copying to host memory. return_shape: optional: bool. default: False. Specifies if the shape of the array needs to be returned. Returns ------- If return_shape is False: res: array.array of the appropriate type and length. else : (res, dims): array.array and the shape of the array """if(self.arr.value==0):raiseRuntimeError("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):returnhost.array(h_type,res[0]),res[1]else:returnhost.array(h_type,res) [docs]defto_list(self,row_major=False):""" Return the data as list Parameters ----------- row_major: optional: bool. default: False. Specifies if a transpose needs to occur before copying to host memory. return_shape: optional: bool. default: False. Specifies if the shape of the array needs to be returned. Returns ------- If return_shape is False: res: list of the appropriate type and length. else : (res, dims): list and the shape of the array """ct_array,shape=self.to_ctype(row_major,True)return_ctype_to_lists(ct_array,len(shape)-1,shape) [docs]defscalar(self):""" Return the first element of the array """if(self.arr.value==0):raiseRuntimeError("Can not call to_ctype on empty array")ctype_type=to_c_type[self.type()]res=ctype_type()safe_call(backend.get().af_get_scalar(c_pointer(res),self.arr))returnres.value def__str__(self):""" Converts the arrayfire array to string showing its meta data and contents. Note ---- You can also use af.display(a, pres) to display the contents of the array with better precision. """ifnot_in_display_dims_limit(self.dims()):returnself._get_metadata_str()returnself._get_metadata_str(dims=False)+self._as_str()def__repr__(self):""" Displays the meta data of the arrayfire array. Note ---- You can use af.display(a, pres) to display the contents of the array. """returnself._get_metadata_str()def_get_metadata_str(self,dims=True):return'arrayfire.Array()\nType:{}\n{}' \
.format(to_typename[self.type()],'Dims:{}'.format(str(self.dims()))ifdimselse'')def_as_str(self):arr_str=c_char_ptr_t(0)be=backend.get()safe_call(be.af_array_to_string(c_pointer(arr_str),"",self.arr,4,True))py_str=to_str(arr_str)safe_call(be.af_free_host(arr_str))returnpy_strdef__array__(self):""" Constructs a numpy.array from arrayfire.Array """importnumpyasnpres=np.empty(self.dims(),dtype=np.dtype(to_typecode[self.type()]),order='F')safe_call(backend.get().af_get_data_ptr(c_void_ptr_t(res.ctypes.data),self.arr))returnres[docs]defto_ndarray(self,output=None):""" Parameters ----------- output: optional: numpy. default: None Returns ---------- If output is None: Constructs a numpy.array from arrayfire.Array If output is not None: copies content of af.array into numpy array. Note ------ - An exception is thrown when output is not None and it is not contiguous. - When output is None, The returned array is in fortran contiguous order. """ifoutputisNone:returnself.__array__()if(output.dtype!=to_typecode[self.type()]):raiseTypeError("Output is not the same type as the array")if(output.size!=self.elements()):raiseRuntimeError("Output size does not match that of input")flags=output.flagstmp=Noneifflags['F_CONTIGUOUS']:tmp=selfelifflags['C_CONTIGUOUS']:tmp=self._reorder()else:raiseRuntimeError("When output is not None, it must be contiguous")safe_call(backend.get().af_get_data_ptr(c_void_ptr_t(output.ctypes.data),tmp.arr))returnoutput [docs]defdisplay(a,precision=4):""" Displays the contents of an array. Parameters ---------- a : af.Array Multi dimensional arrayfire array precision: int. optional. Specifies the number of precision bits to display """expr=inspect.stack()[1][-2]name=""try:if(exprisnotNone):st=expr[0].find('(')+1en=expr[0].rfind(')')name=expr[0][st:en]exceptIndexError:passsafe_call(backend.get().af_print_array_gen(name.encode('utf-8'),a.arr,c_int_t(precision))) [docs]defsave_array(key,a,filename,append=False):""" Save an array to disk. Parameters ---------- key : str A name / key associated with the array a : af.Array The array to be stored to disk filename : str Location of the data file. append : Boolean. optional. default: False. If the file already exists, specifies if the data should be appended or overwritten. Returns --------- index : int The index of the array stored in the file. """index=c_int_t(-1)safe_call(backend.get().af_save_array(c_pointer(index),key.encode('utf-8'),a.arr,filename.encode('utf-8'),append))returnindex.value [docs]defread_array(filename,index=None,key=None):""" Read an array from disk. Parameters ---------- filename : str Location of the data file. index : int. Optional. Default: None. - The index of the array stored in the file. - If None, key is used. key : str. Optional. Default: None. - A name / key associated with the array - If None, index is used. Returns --------- """assert((indexisnotNone)or(keyisnotNone))out=Array()if(indexisnotNone):safe_call(backend.get().af_read_array_index(c_pointer(out.arr),filename.encode('utf-8'),index))elif(keyisnotNone):safe_call(backend.get().af_read_array_key(c_pointer(out.arr),filename.encode('utf-8'),key.encode('utf-8')))returnout from.algorithmimport(sum,count)from.arithimportcast