Skip to content

Commit 4d108bb

Browse files
author
Holger Kohr
committed
ENH: add indexing with None for new axes
1 parent 78afeb8 commit 4d108bb

1 file changed

Lines changed: 101 additions & 4 deletions

File tree

pygpu/gpuarray.pyx

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,83 @@ cdef class GpuArray:
18361836
raise TypeError, "len() of unsized object"
18371837

18381838
def __getitem__(self, key):
1839-
return self.__cgetitem__(key)
1839+
cdef unsigned int i
1840+
1841+
if key is Ellipsis:
1842+
return self.__cgetitem__(key)
1843+
1844+
# A list or a sequence of list should trigger "fancy" indexing.
1845+
# This is not implemented yet.
1846+
# Conversely, if a list contains slice or Ellipsis objects, it behaves
1847+
# the same as a tuple.
1848+
if isinstance(key, list):
1849+
if any(isinstance(k, slice) or k is Ellipsis for k in key):
1850+
return self.__getitem__(tuple(key))
1851+
else:
1852+
raise NotImplementedError, "fancy indexing not supported"
1853+
1854+
try:
1855+
iter(key)
1856+
except TypeError:
1857+
key = (key,)
1858+
else:
1859+
if all(isinstance(k, list) for k in key):
1860+
raise NotImplementedError, "fancy indexing not supported"
1861+
1862+
key = tuple(key)
1863+
1864+
# Need to massage Ellipsis here, to avoid packing it into a tuple.
1865+
if key.count(Ellipsis) > 1:
1866+
raise IndexError, "cannot use more than one Ellipsis"
1867+
1868+
# The following code replaces an Ellipsis found in the key by
1869+
# the corresponding number of slice(None) objects, depending on the
1870+
# number of dimensions. As example, this allows indexing on the last
1871+
# dimension with a[..., 1:] on any array (including 1-dim). This
1872+
# is also required for numpy compat.
1873+
try:
1874+
ell_idx = key.index(Ellipsis)
1875+
except ValueError:
1876+
pass
1877+
else:
1878+
# Need number of axes minus missing dimensions extra slice(None)
1879+
# objects, not counting None entries and the Ellipsis itself
1880+
num_slcs = self.ga.nd - (len(key) - key.count(None) - 1)
1881+
fill_slices = (slice(None),) * num_slcs
1882+
key = key[:ell_idx] + fill_slices + key[ell_idx + 1:]
1883+
1884+
# Remove the None entries for indexing
1885+
getitem_idcs = tuple(k for k in key if k is not None)
1886+
1887+
# For less than 1 index, fill up with slice(None) to the right.
1888+
# This allows indexing a[1:] in multi-dimensional arrays, where the
1889+
# slice is applied along the first axis only. It also allows
1890+
# a[()], which simply is a view in Numpy.
1891+
if len(getitem_idcs) <= 1:
1892+
getitem_idcs = (getitem_idcs +
1893+
(slice(None),) * (self.ga.nd - len(getitem_idcs)))
1894+
1895+
# Slice into array, then reshape, accommodating for None entries in key
1896+
sliced = self.__cgetitem__(getitem_idcs)
1897+
if key.count(None) == 0:
1898+
# Avoid unnecessary reshaping if there was no None
1899+
return sliced
1900+
else:
1901+
new_shape = []
1902+
i = 0
1903+
if sliced.shape:
1904+
for k in key:
1905+
if isinstance(k, int):
1906+
continue
1907+
elif k is None:
1908+
new_shape.append(1)
1909+
else:
1910+
new_shape.append(sliced.shape[i])
1911+
i += 1
1912+
# Add remaining entries from sliced.shape if existing (happens
1913+
# for 1 index or less if ndim >= 2).
1914+
new_shape.extend(sliced.shape[i:])
1915+
return sliced.reshape(new_shape)
18401916

18411917
cdef __cgetitem__(self, key):
18421918
cdef ssize_t *starts
@@ -1896,16 +1972,37 @@ cdef class GpuArray:
18961972
steps[i] = 1
18971973

18981974
return pygpu_index(self, starts, stops, steps)
1975+
18991976
finally:
19001977
free(starts)
19011978
free(stops)
19021979
free(steps)
19031980

19041981
def __setitem__(self, idx, v):
1905-
cdef GpuArray tmp = self.__cgetitem__(idx)
1906-
cdef GpuArray gv = carray(v, self.ga.typecode, False, 'A', 0,
1907-
self.context, GpuArray)
1982+
cdef GpuArray tmp, gv
1983+
1984+
if isinstance(idx, list):
1985+
if any(isinstance(i, slice) or i is Ellipsis for i in idx):
1986+
self.__setitem__(tuple(idx), v)
1987+
else:
1988+
raise NotImplementedError, "fancy indexing not supported"
1989+
try:
1990+
iter(idx)
1991+
except TypeError:
1992+
idx = (idx,)
1993+
else:
1994+
if all(isinstance(i, list) for i in idx):
1995+
raise NotImplementedError, "fancy indexing not supported"
1996+
1997+
idx = tuple(idx)
1998+
1999+
if idx.count(Ellipsis) > 1:
2000+
raise IndexError, "cannot use more than one Ellipsis"
19082001

2002+
# Remove None entries, they should be ignored (as in Numpy)
2003+
idx = tuple(i for i in idx if i is not None)
2004+
tmp = self.__cgetitem__(idx)
2005+
gv = carray(v, self.ga.typecode, False, 'A', 0, self.context, GpuArray)
19092006
array_setarray(tmp, gv)
19102007

19112008
def take1(self, GpuArray idx):

0 commit comments

Comments
 (0)