def wrapper(a, axis=None, dtype=None, keepdims=False): if not isinstance(axis, tuple): axis = (axis,) if axis[0] is None: # Special case for speed a_flat = a.flat s = func(a_flat, a_flat.d_array, pu.c2f(a_flat.shape, 0)) if keepdims: shape = (1,)*a.ndim else: shape = () ret = afnumpy.ndarray(tuple(shape), dtype=pu.typemap(s.dtype()), af_array=s) else: shape = list(a.shape) s = a.d_array # Do in decreasing axis order to avoid problems with the pop for ax in sorted(axis)[::-1]: # Optimization if(a.shape[ax] > 1): s = func(a, s, pu.c2f(a.shape, ax)) if keepdims: shape[ax] = 1 else: shape.pop(ax) ret = afnumpy.ndarray(tuple(shape), dtype=pu.typemap(s.dtype()), af_array=s) if(dtype is not None): ret = ret.astype(dtype) if(len(shape) == 0): ret = ret[()] return ret
def __index_shape__(A_shape, idx, del_singleton=True): shape = [] for i in range(0,len(idx)): if(idx[i] is None): shape.append(0) elif(isinstance(idx[i],numbers.Number)): if del_singleton: # Remove dimensions indexed with a scalar continue else: shape.append(1) elif(isinstance(idx[i],arrayfire.index.Seq)): if(idx[i].s == arrayfire.af_span): shape.append(A_shape[i]) else: shape.append(idx[i].size) elif(isinstance(idx[i],slice)): shape.append(__slice_len__(idx[i], pu.c2f(A_shape), i)) elif(isinstance(idx[i], arrayfire.Array)): shape.append(idx[i].elements()) elif(isinstance(idx[i],arrayfire.index)): if(idx[i].isspan()): shape.append(A_shape[i]) else: af_idx = idx[i].get() if(af_idx.isBatch): raise ValueError if(af_idx.isSeq): shape.append(arrayfire.seq(af_idx.seq()).size) else: shape.append(af_idx.arr_elements()) else: raise ValueError return pu.c2f(shape)
def __init__(self, shape, dtype=float, buffer=None, offset=0, strides=None, order=None, af_array=None): self._base = None if(offset != 0): raise NotImplementedError('offset must be 0') if(strides is not None): raise NotImplementedError('strides must be None') if(order is not None and order != 'C'): raise NotImplementedError('order must be None') if isinstance(shape, numbers.Number): self._shape = (shape,) else: self._shape = tuple(shape) self.dtype = dtype s_a = numpy.array(pu.c2f(shape),dtype=pu.dim_t) if(s_a.size < 1): # We'll use af_arrays of size (1) to keep scalars s_a = numpy.array((1),dtype=pu.dim_t) if(s_a.size <= 4): if(af_array is not None): # We need to make sure to keep a copy of af_array # Otherwise python will free it and havoc ensues self.d_array = af_array else: out_arr = ctypes.c_void_p(0) if(buffer is not None): arrayfire.backend.get().af_create_array(ctypes.pointer(out_arr), ctypes.c_void_p(buffer.ctypes.data), s_a.size, ctypes.c_void_p(s_a.ctypes.data), pu.typemap(dtype).value) else: arrayfire.backend.get().af_create_handle(ctypes.pointer(out_arr), s_a.size, ctypes.c_void_p(s_a.ctypes.data), pu.typemap(dtype).value) self.d_array = arrayfire.Array() self.d_array.arr = out_arr else: raise NotImplementedError('Only up to 4 dimensions are supported') self.h_array = numpy.ndarray(shape,dtype,buffer,offset,strides,order)
def __reshape__(self, newshape, order = 'C'): if(order is not 'C'): raise NotImplementedError if isinstance(newshape,numbers.Number): newshape = (newshape,) # Replace a possible -1 with the if -1 in newshape: newshape = list(newshape) i = newshape.index(-1) newshape[i] = 1 if -1 in newshape: raise ValueError('Only one -1 allowed in shape') newshape[i] = self.size/numpy.prod(newshape) if self.size != numpy.prod(newshape): raise ValueError('total size of new array must be unchanged') if len(newshape) != 0: # No need to modify the af_array for empty shapes af_shape = numpy.array(pu.c2f(newshape), dtype=pu.dim_t) s = arrayfire.Array() # Tracer()() arrayfire.backend.get().af_moddims(ctypes.pointer(s.arr), self.d_array.arr, af_shape.size, ctypes.c_void_p(af_shape.ctypes.data)) # arrayfire.backend.get().af_moddims(ctypes.pointer(self.d_array.arr), self.d_array.arr, af_shape.size, ctypes.c_void_p(af_shape.ctypes.data)) self.d_array = s self.h_array.shape = newshape self._shape = tuple(newshape)
def argsort(self, axis=-1, kind='quicksort', order=None): if kind != 'quicksort': print "argsort 'kind' argument ignored" if order is not None: raise ValueError('order argument is not supported') if(axis < 0): axis = self.ndim+axis val, idx = arrayfire.sort_index(self.d_array, pu.c2f(self.shape, axis)) return ndarray(self.shape, dtype=pu.typemap(idx.dtype()), af_array=idx)
def argmin(self, axis=None): if axis is None: return self.flat.argmin(axis=0) if not isinstance(axis, numbers.Number): raise TypeError('an integer is required for the axis') val, idx = arrayfire.imin(self.d_array, pu.c2f(self.shape, axis)) shape = list(self.shape) shape.pop(axis) if(len(shape)): return ndarray(shape, dtype=pu.typemap(idx.dtype()), af_array=idx) else: return ndarray(shape, dtype=pu.typemap(idx.dtype()), af_array=idx)[()]
def __convert_dim__(shape, idx): # Convert numpy style indexing arguments to arrayfire style # Always returns a list # Should also return the shape of the result # If it's an array just return the array if(isinstance(idx, afnumpy.ndarray)): return [idx.d_array], idx.shape # Otherwise turns thing into a tuple if not isinstance(idx, tuple): idx = (idx,) idx = list(idx) # According to http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html # newaxis is an alias for 'None', and 'None' can be used in place of this with the same result. newaxis = None # Check for Ellipsis. Expand it to ':' such that idx shape matches array shape, ignoring any newaxise # We have to do this because we don't want to trigger comparisons if any(e is Ellipsis for e in idx): for axis in range(0, len(idx)): if(idx[axis] is Ellipsis): i = axis break idx.pop(i) if any(e is Ellipsis for e in idx): raise IndexError('Only a single Ellipsis allowed') while len(idx)-idx.count(newaxis) < len(shape): idx.insert(i, slice(None,None,None)) # Check and remove newaxis. Store their location for final reshape newaxes = [] while newaxis in idx: newaxes.append(idx.index(newaxis)) idx.remove(newaxis) # Append enough ':' to match the dimension of the aray while len(idx) < len(shape): idx.append(slice(None,None,None)) ret = [0]*len(shape) for axis in range(0,len(shape)): af_idx = __npidx_to_afidx__(idx[axis], shape[axis]) ret[pu.c2f(shape,axis)] = af_idx ret_shape = __index_shape__(shape, ret) # Insert new dimensions start from the end so we don't perturb other insertions for n in newaxes[::-1]: ret_shape.insert(n,1) return ret, tuple(ret_shape)
def imag(self): ret_type = numpy.real(numpy.zeros((),dtype=self.dtype)).dtype shape = list(self.shape) if not numpy.issubdtype(self.dtype, numpy.complexfloating): return afnumpy.zeros(self.shape) shape[-1] *= 2 dims = numpy.array(pu.c2f(shape),dtype=pu.dim_t) s = arrayfire.Array() arrayfire.backend.get().af_device_array(ctypes.pointer(s.arr), ctypes.c_void_p(self.d_array.device_ptr()), self.ndim, ctypes.c_void_p(dims.ctypes.data), pu.typemap(ret_type).value) arrayfire.backend.get().af_retain_array(ctypes.pointer(s.arr),s.arr) a = ndarray(shape, dtype=ret_type, af_array=s) ret = a[...,1::2] ret._base = a ret._base_index = (Ellipsis, slice(1,None,2)) return ret
def transpose(self, *axes): if(self.ndim == 1): return self if len(axes) == 0 and self.ndim == 2: s = arrayfire.transpose(self.d_array) else: order = [0,1,2,3] if len(axes) == 0 or axes[0] is None: order[:self.ndim] = order[:self.ndim][::-1] else: if isinstance(axes[0], collections.Iterable): axes = axes[0] for i,ax in enumerate(axes): order[i] = pu.c2f(self.shape, ax) # We have to do this gymnastic due to the fact that arrayfire # uses Fortran order order[:len(axes)] = order[:len(axes)][::-1] #print order s = arrayfire.reorder(self.d_array, order[0],order[1],order[2],order[3]) return ndarray(pu.af_shape(s), dtype=self.dtype, af_array=s)