Source code for arrayfire.index

#######################################################
# 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
########################################################
"""
Index and Seq classes used in indexing operations.
"""

from .library import *
from .util import *
from .util import _is_number
from .base import *
from .bcast import _bcast_var
import math

[docs]class Seq(ct.Structure): """ arrayfire equivalent of slice Attributes ---------- begin: number Start of the sequence. end : number End of sequence. step : number Step size. Parameters ---------- S: slice or number. """ _fields_ = [("begin", c_double_t), ("end" , c_double_t), ("step" , c_double_t)] def __init__ (self, S): self.begin = c_double_t( 0) self.end = c_double_t(-1) self.step = c_double_t( 1) if _is_number(S): self.begin = c_double_t(S) self.end = c_double_t(S) elif isinstance(S, slice): if (S.step is not None): self.step = c_double_t(S.step) if(S.step < 0): self.begin, self.end = self.end, self.begin if (S.start is not None): self.begin = c_double_t(S.start) if (S.stop is not None): self.end = c_double_t(S.stop) # handle special cases if self.begin >= 0 and self.end >=0 and self.end <= self.begin and self.step >= 0: self.begin = 1 self.end = 1 self.step = 1 elif self.begin < 0 and self.end < 0 and self.end >= self.begin and self.step <= 0: self.begin = -2 self.end = -2 self.step = -1 if (S.stop is not None): self.end = self.end - math.copysign(1, self.step) else: raise IndexError("Invalid type while indexing arrayfire.array")
[docs]class ParallelRange(Seq): """ Class used to parallelize for loop. Inherits from Seq. Attributes ---------- S: slice Parameters ---------- start: number Beginning of parallel range. stop : number End of parallel range. step : number Step size for parallel range. Examples -------- >>> import arrayfire as af >>> a = af.randu(3, 3) >>> b = af.randu(3, 1) >>> c = af.constant(0, 3, 3) >>> for ii in af.ParallelRange(3): ... c[:, ii] = a[:, ii] + b ... >>> af.display(a) [3 3 1 1] 0.4107 0.1794 0.3775 0.8224 0.4198 0.3027 0.9518 0.0081 0.6456 >>> af.display(b) [3 1 1 1] 0.7269 0.7104 0.5201 >>> af.display(c) [3 3 1 1] 1.1377 0.9063 1.1045 1.5328 1.1302 1.0131 1.4719 0.5282 1.1657 """ def __init__(self, start, stop=None, step=None): if (stop is None): stop = start start = 0 self.S = slice(start, stop, step) super(ParallelRange, self).__init__(self.S) def __iter__(self): return self
[docs] def next(self): """ Function called by the iterator in Python 2 """ if _bcast_var.get() is True: _bcast_var.toggle() raise StopIteration else: _bcast_var.toggle() return self
def __next__(self): """ Function called by the iterator in Python 3 """ return self.next()
class _uidx(ct.Union): _fields_ = [("arr", c_void_ptr_t), ("seq", Seq)]
[docs]class Index(ct.Structure): _fields_ = [("idx", _uidx), ("isSeq", c_bool_t), ("isBatch", c_bool_t)] """ Container for the index class in arrayfire C library Attributes ---------- idx.arr: ctypes.c_void_p - Default 0 idx.seq: af.Seq - Default af.Seq(0, -1, 1) isSeq : bool - Default True isBatch : bool - Default False Parameters ----------- idx: key - If of type af.Array, self.idx.arr = idx, self.isSeq = False - If of type af.ParallelRange, self.idx.seq = idx, self.isBatch = True - Default:, self.idx.seq = af.Seq(idx) Note ---- Implemented for internal use only. Use with extreme caution. """ def __init__ (self, idx): self.idx = _uidx() self.isBatch = False self.isSeq = True if isinstance(idx, BaseArray): arr = c_void_ptr_t(0) if (idx.type() == Dtype.b8.value): safe_call(backend.get().af_where(c_pointer(arr), idx.arr)) else: safe_call(backend.get().af_retain_array(c_pointer(arr), idx.arr)) self.idx.arr = arr self.isSeq = False elif isinstance(idx, ParallelRange): self.idx.seq = idx self.isBatch = True else: self.idx.seq = Seq(idx) def __del__(self): if not self.isSeq: # ctypes field variables are automatically # converted to basic C types so we have to # build the void_p from the value again. arr = c_void_ptr_t(self.idx.arr) backend.get().af_release_array(arr)
_span = Index(slice(None)) class _Index4(object): def __init__(self): index_vec = Index * 4 self.array = index_vec(_span, _span, _span, _span) # Do not lose those idx as self.array keeps # no reference to them. Otherwise the destructor # is prematurely called self.idxs = [_span, _span, _span, _span] @property def pointer(self): return c_pointer(self.array) def __getitem__(self, idx): return self.array[idx] def __setitem__(self, idx, value): self.array[idx] = value self.idxs[idx] = value