Commit 8105941c authored by Mark Florisson's avatar Mark Florisson

Support slicing memoryview objects

parent 155a4ef5
...@@ -83,20 +83,16 @@ class CythonScope(ModuleScope): ...@@ -83,20 +83,16 @@ class CythonScope(ModuleScope):
# #
# The view sub-scope # The view sub-scope
# #
self.viewscope = viewscope = ModuleScope(u'cython.view', self, None) self.viewscope = viewscope = ModuleScope(u'view', self, None)
self.declare_module('view', viewscope, None).as_module = viewscope
# Hacky monkey patch
self.viewscope.global_scope = self.global_scope
self.declare_module('view', viewscope, None)
viewscope.is_cython_builtin = True viewscope.is_cython_builtin = True
viewscope.pxd_file_loaded = True viewscope.pxd_file_loaded = True
cythonview_testscope_utility_code.declare_in_scope(viewscope) cythonview_testscope_utility_code.declare_in_scope(viewscope)
view_utility_scope = MemoryView.view_utility_code.declare_in_scope(viewscope) view_utility_scope = MemoryView.view_utility_code.declare_in_scope(viewscope)
MemoryView.memview_fromslice_utility_code.from_scope = view_utility_scope # MemoryView.memview_fromslice_utility_code.from_scope = view_utility_scope
MemoryView.memview_fromslice_utility_code.declare_in_scope(viewscope) # MemoryView.memview_fromslice_utility_code.declare_in_scope(viewscope)
def create_cython_scope(context, create_testscope): def create_cython_scope(context, create_testscope):
......
...@@ -2452,7 +2452,10 @@ class IndexNode(ExprNode): ...@@ -2452,7 +2452,10 @@ class IndexNode(ExprNode):
if isinstance(index, SliceNode): if isinstance(index, SliceNode):
suboffsets_dim = i suboffsets_dim = i
self.memslice_slice = True self.memslice_slice = True
axes.append((access, 'strided')) if packing == 'contig' and index.step.is_none:
axes.append((access, 'contig'))
else:
axes.append((access, 'strided'))
# Coerce start, stop and step to temps of the right type # Coerce start, stop and step to temps of the right type
for attr in ('start', 'stop', 'step'): for attr in ('start', 'stop', 'step'):
......
...@@ -412,15 +412,18 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry): ...@@ -412,15 +412,18 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
for temp in temps: for temp in temps:
code.funcstate.release_temp(temp) code.funcstate.release_temp(temp)
def empty_slice(pos):
none = ExprNodes.NoneNode(pos)
return ExprNodes.SliceNode(pos, start=none,
stop=none, step=none)
def unellipsify(indices, ndim): def unellipsify(indices, ndim):
result = [] result = []
seen_ellipsis = False seen_ellipsis = False
for index in indices: for index in indices:
if isinstance(index, ExprNodes.EllipsisNode): if isinstance(index, ExprNodes.EllipsisNode):
none = ExprNodes.NoneNode(index.pos) full_slice = empty_slice(index.pos)
full_slice = ExprNodes.SliceNode(index.pos, start=none,
stop=none, step=none)
if seen_ellipsis: if seen_ellipsis:
result.append(full_slice) result.append(full_slice)
else: else:
...@@ -430,6 +433,10 @@ def unellipsify(indices, ndim): ...@@ -430,6 +433,10 @@ def unellipsify(indices, ndim):
else: else:
result.append(index) result.append(index)
if len(result) < ndim:
nslices = ndim - len(result)
result.extend([empty_slice(indices[-1].pos)] * nslices)
return result return result
def get_memoryview_flag(access, packing): def get_memoryview_flag(access, packing):
...@@ -950,7 +957,7 @@ def _resolve_AttributeNode(env, node): ...@@ -950,7 +957,7 @@ def _resolve_AttributeNode(env, node):
scope = env scope = env
for modname in modnames: for modname in modnames:
mod = scope.lookup(modname) mod = scope.lookup(modname)
if not mod: if not mod or not mod.as_module:
raise CompileError( raise CompileError(
node.pos, "undeclared name not builtin: %s" % modname) node.pos, "undeclared name not builtin: %s" % modname)
scope = mod.as_module scope = mod.as_module
...@@ -1001,8 +1008,8 @@ cython_array_utility_code = load_memview_cy_utility( ...@@ -1001,8 +1008,8 @@ cython_array_utility_code = load_memview_cy_utility(
context=context, context=context,
requires=[view_utility_code]) requires=[view_utility_code])
memview_fromslice_utility_code = load_memview_cy_utility( # memview_fromslice_utility_code = load_memview_cy_utility(
"MemviewFromSlice", # "MemviewFromSlice",
context=context, # context=context,
requires=[view_utility_code], # requires=[view_utility_code],
) # )
\ No newline at end of file \ No newline at end of file
...@@ -488,6 +488,7 @@ class MemoryViewSliceType(PyrexType): ...@@ -488,6 +488,7 @@ class MemoryViewSliceType(PyrexType):
entry.utility_code_definition = \ entry.utility_code_definition = \
MemoryView.CopyFuncUtilCode(self, to_memview) MemoryView.CopyFuncUtilCode(self, to_memview)
elif attribute in ("is_c_contig", "is_f_contig"):
# is_c_contig and is_f_contig functions # is_c_contig and is_f_contig functions
for (c_or_f, cython_name) in (('c', 'is_c_contig'), ('fortran', 'is_f_contig')): for (c_or_f, cython_name) in (('c', 'is_c_contig'), ('fortran', 'is_f_contig')):
...@@ -564,9 +565,6 @@ class MemoryViewSliceType(PyrexType): ...@@ -564,9 +565,6 @@ class MemoryViewSliceType(PyrexType):
return True return True
def get_to_py_function(self, env, obj): def get_to_py_function(self, env, obj):
import MemoryView
env.use_utility_code(MemoryView.memview_fromslice_utility_code)
to_py_func, from_py_func = self.dtype_object_conversion_funcs(env) to_py_func, from_py_func = self.dtype_object_conversion_funcs(env)
to_py_func = "(PyObject *(*)(char *)) " + to_py_func to_py_func = "(PyObject *(*)(char *)) " + to_py_func
from_py_func = "(int (*)(char *, PyObject *)) " + from_py_func from_py_func = "(int (*)(char *, PyObject *)) " + from_py_func
......
...@@ -120,7 +120,6 @@ cdef class array: ...@@ -120,7 +120,6 @@ cdef class array:
info.format = NULL info.format = NULL
# info.obj = self # info.obj = self
# Py_INCREF(self)
def __releasebuffer__(self, Py_buffer *info): def __releasebuffer__(self, Py_buffer *info):
pass pass
...@@ -184,6 +183,20 @@ cdef extern from *: ...@@ -184,6 +183,20 @@ cdef extern from *:
ctypedef struct PyObject ctypedef struct PyObject
cdef struct __pyx_memoryview "__pyx_memoryview_obj":
Py_buffer view
PyObject *obj
ctypedef struct {{memviewslice_name}}:
__pyx_memoryview *memview
char *data
Py_ssize_t shape[{{max_dims}}]
Py_ssize_t strides[{{max_dims}}]
Py_ssize_t suboffsets[{{max_dims}}]
void __PYX_INC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil)
void __PYX_XDEC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil)
@cname('__pyx_MemviewEnum') @cname('__pyx_MemviewEnum')
cdef class Enum(object): cdef class Enum(object):
...@@ -229,42 +242,34 @@ cdef class memoryview(object): ...@@ -229,42 +242,34 @@ cdef class memoryview(object):
cdef char *get_item_pointer(memoryview self, object index) except NULL: cdef char *get_item_pointer(memoryview self, object index) except NULL:
cdef Py_ssize_t dim cdef Py_ssize_t dim
cdef Py_buffer view = self.view cdef char *itemp = <char *> self.view.buf
cdef char *itemp = <char *> view.buf
if index is Ellipsis: for dim, idx in enumerate(index):
return self _check_index(idx)
itemp = pybuffer_index(&self.view, itemp, idx, dim)
elif isinstance(index, slice):
if index == slice(None):
return self
raise NotImplementedError
else:
if not isinstance(index, tuple):
index = (index,)
tup = _unellipsify(index, self.view.ndim)
if len(tup) != self.view.ndim:
raise NotImplementedError(
"Expected %d indices (got %d)" %
(self.view.ndim, len(tup)))
for dim, idx in enumerate(tup):
_check_index(idx)
itemp = pybuffer_index(&self.view, itemp, idx, dim)
return itemp return itemp
@cname('__pyx_memoryview_getitem') @cname('__pyx_memoryview_getitem')
def __getitem__(memoryview self, object index): def __getitem__(memoryview self, object index):
cdef char *itemp = self.get_item_pointer(index) if index is Ellipsis:
return self.convert_item_to_object(itemp) return self
have_slices, index = _unellipsify(index, self.view.ndim)
cdef char *itemp
if have_slices:
return pybuffer_slice(self, index)
else:
itemp = self.get_item_pointer(index)
return self.convert_item_to_object(itemp)
@cname('__pyx_memoryview_setitem') @cname('__pyx_memoryview_setitem')
def __setitem__(memoryview self, object index, object value): def __setitem__(memoryview self, object index, object value):
have_slices, index = _unellipsify(index, self.view.ndim)
if have_slices:
raise NotImplementedError("Slice assignment not supported yet")
cdef char *itemp = self.get_item_pointer(index) cdef char *itemp = self.get_item_pointer(index)
self.assign_item_from_object(itemp, value) self.assign_item_from_object(itemp, value)
...@@ -297,6 +302,22 @@ cdef class memoryview(object): ...@@ -297,6 +302,22 @@ cdef class memoryview(object):
for i, c in enumerate(bytesvalue): for i, c in enumerate(bytesvalue):
itemp[i] = c itemp[i] = c
property T:
@cname('__pyx_memoryview_transpose')
def __get__(self):
cdef memoryview result = memoryview_copy(self)
cdef int ndim = self.view.ndim
cdef Py_ssize_t *strides = result.view.strides
cdef Py_ssize_t *shape = result.view.shape
# reverse strides and shape
for i in range(ndim / 2):
strides[i], strides[ndim - i] = strides[ndim - i], strides[i]
shape[i], shape[ndim - i] = shape[ndim - i], shape[i]
return result
property _obj: property _obj:
@cname('__pyx_memoryview__get__obj') @cname('__pyx_memoryview__get__obj')
def __get__(self): def __get__(self):
...@@ -306,6 +327,23 @@ cdef class memoryview(object): ...@@ -306,6 +327,23 @@ cdef class memoryview(object):
return self.obj return self.obj
property shape:
@cname('__pyx_memoryview_get_shape')
def __get__(self):
return tuple([self.view.shape[i] for i in xrange(self.view.ndim)])
property strides:
@cname('__pyx_memoryview_get_strides')
def __get__(self):
return tuple([self.view.strides[i] for i in xrange(self.view.ndim)])
property suboffsets:
@cname('__pyx_memoryview_get_suboffsets')
def __get__(self):
return tuple([self.view.suboffsets[i] for i in xrange(self.view.ndim)])
def __repr__(self): def __repr__(self):
return "<MemoryView of %r at 0x%x>" % (self._obj.__class__.__name__, id(self)) return "<MemoryView of %r at 0x%x>" % (self._obj.__class__.__name__, id(self))
...@@ -322,23 +360,130 @@ cdef _check_index(index): ...@@ -322,23 +360,130 @@ cdef _check_index(index):
if not PyIndex_Check(index): if not PyIndex_Check(index):
raise TypeError("Cannot index with %s" % type(index)) raise TypeError("Cannot index with %s" % type(index))
cdef tuple _unellipsify(tuple tup, int ndim): cdef tuple _unellipsify(object index, int ndim):
if Ellipsis in tup: if not isinstance(index, tuple):
result = [] tup = (index,)
for idx, item in enumerate(tup): else:
if item is Ellipsis: tup = index
result = []
have_slices = False
seen_ellipsis = False
for idx, item in enumerate(tup):
if item is Ellipsis:
if not seen_ellipsis:
result.extend([slice(None)] * (ndim - len(tup) + 1)) result.extend([slice(None)] * (ndim - len(tup) + 1))
result.extend(tup[idx + 1:]) result.extend(tup[idx + 1:])
break else:
result.append(slice(None))
have_slices = True
else:
have_slices = have_slices or isinstance(item, slice)
result.append(item) result.append(item)
return tuple(result) nslices = ndim - len(result)
if nslices:
return tup result.extend([slice(None)] * nslices)
for idx in tup:
if isinstance(idx, slice):
return True, tup
return False, tup
@cname('__pyx_pybuffer_slice')
cdef memoryview pybuffer_slice(memoryview memview, object indices):
cdef Py_ssize_t idx, dim, new_dim = 0, suboffset_dim = -1
cdef Py_ssize_t shape, stride
cdef bint negative_step
cdef int new_ndim = 0
cdef {{memviewslice_name}} dst
for dim, index in enumerate(indices):
shape = memview.view.shape[dim]
stride = memview.view.strides[dim]
if PyIndex_Check(index):
idx = index
if idx < 0:
idx += shape
if not 0 <= idx < shape:
raise IndexError("Index out of bounds (axis %d)" % dim)
else:
# index is a slice
new_ndim += 1
start, stop, step = index.start, index.stop, index.step
negative_step = step and step < 0
# set some defaults
if not start:
if negative_step:
start = shape - 1
else:
start = 0
if not stop:
if negative_step:
stop = -1
else:
stop = shape
# check our bounds
if start < 0:
start += shape
if start < 0:
start = 0
elif start >= shape:
start = shape - 1
if stop < 0:
stop += shape
if stop < 0:
stop = 0
elif stop > shape:
stop = shape
step = step or 1
# shape/strides/suboffsets
dst.strides[new_dim] = stride * step
dst.shape[new_dim] = (stop - start) / step
if (stop - start) % step:
dst.shape[new_dim] += 1
dst.suboffsets[new_dim] = memview.view.suboffsets[dim]
# set this for the slicing offset
if negative_step:
idx = stop
else:
idx = start
# Add the slicing or idexing offsets to the right suboffset or base data *
if suboffset_dim < 0:
dst.data += idx * stride
else:
dst.suboffsets[suboffset_dim] += idx * stride
if memview.view.suboffsets[dim]:
if PyIndex_Check(index):
raise IndexError(
"Cannot make indirect dimension %d disappear through "
"indexing, consider slicing with %d:%d" % (dim, idx, idx + 1))
suboffset_dim = new_dim
cdef _memoryviewslice memviewsliceobj
if isinstance(memview, _memoryviewslice):
memviewsliceobj = memview
return memoryview_fromslice(&dst, new_dim,
memviewsliceobj.to_object_func,
memviewsliceobj.to_dtype_func)
else:
return memoryview_fromslice(&dst, new_dim, NULL, NULL)
@cname('__pyx_pybuffer_index') @cname('__pyx_pybuffer_index')
cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, int dim) except NULL: cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index,
int dim) except NULL:
cdef Py_ssize_t shape, stride, suboffset = -1 cdef Py_ssize_t shape, stride, suboffset = -1
cdef Py_ssize_t itemsize = view.itemsize cdef Py_ssize_t itemsize = view.itemsize
cdef char *resultp cdef char *resultp
...@@ -366,25 +511,6 @@ cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, int dim ...@@ -366,25 +511,6 @@ cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, int dim
return resultp return resultp
############### MemviewFromSlice ###############
cdef extern from *:
cdef struct __pyx_memoryview:
Py_buffer view
PyObject *obj
ctypedef struct {{memviewslice_name}}:
__pyx_memoryview *memview
char *data
Py_ssize_t shape[{{max_dims}}]
Py_ssize_t strides[{{max_dims}}]
Py_ssize_t suboffsets[{{max_dims}}]
void __PYX_INC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil)
void __PYX_XDEC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil)
@cname('__pyx_memoryviewslice') @cname('__pyx_memoryviewslice')
cdef class _memoryviewslice(memoryview): cdef class _memoryviewslice(memoryview):
"Internal class for passing memory view slices to Python" "Internal class for passing memory view slices to Python"
...@@ -419,15 +545,14 @@ cdef class _memoryviewslice(memoryview): ...@@ -419,15 +545,14 @@ cdef class _memoryviewslice(memoryview):
@cname('__pyx_memoryview_fromslice') @cname('__pyx_memoryview_fromslice')
cdef memoryview_from_memslice_cwrapper( cdef memoryview_fromslice({{memviewslice_name}} *memviewslice,
{{memviewslice_name}} *memviewslice, int cur_ndim, int ndim,
object (*to_object_func)(char *), object (*to_object_func)(char *),
int (*to_dtype_func)(char *, object) except 0): int (*to_dtype_func)(char *, object) except 0):
assert 0 < cur_ndim <= memviewslice.memview.view.ndim assert 0 < ndim <= memviewslice.memview.view.ndim, (ndim, memviewslice.memview.view.ndim)
cdef _memoryviewslice result = _memoryviewslice(None, 0) cdef _memoryviewslice result = _memoryviewslice(None, 0)
cdef int new_ndim = memviewslice.memview.view.ndim - cur_ndim
result.from_slice = memviewslice[0] result.from_slice = memviewslice[0]
__PYX_INC_MEMVIEW(memviewslice, 1) __PYX_INC_MEMVIEW(memviewslice, 1)
...@@ -435,16 +560,41 @@ cdef memoryview_from_memslice_cwrapper( ...@@ -435,16 +560,41 @@ cdef memoryview_from_memslice_cwrapper(
result.from_object = <object> memviewslice.memview.obj result.from_object = <object> memviewslice.memview.obj
result.view = memviewslice.memview.view result.view = memviewslice.memview.view
result.view.shape = <Py_ssize_t *> (&result.from_slice.shape + new_ndim) result.view.shape = <Py_ssize_t *> &result.from_slice.shape
result.view.strides = <Py_ssize_t *> (&result.from_slice.strides + new_ndim) result.view.strides = <Py_ssize_t *> result.from_slice.strides
result.view.suboffsets = <Py_ssize_t *> (&result.from_slice.suboffsets + new_ndim) result.view.suboffsets = <Py_ssize_t *> &result.from_slice.suboffsets
result.view.ndim = cur_ndim result.view.ndim = ndim
result.to_object_func = to_object_func result.to_object_func = to_object_func
result.to_dtype_func = to_dtype_func result.to_dtype_func = to_dtype_func
return result return result
cdef memoryview_copy(memoryview memview):
cdef {{memviewslice_name}} memviewslice
cdef int dim
cdef object (*to_object_func)(char *)
cdef int (*to_dtype_func)(char *, object) except 0
memviewslice.memview = <__pyx_memoryview *> memview
memviewslice.data = <char *> memview.view.buf
# Copy all of these as from_slice will
for dim in range(memview.view.ndim):
memviewslice.shape[dim] = memview.view.shape[dim]
memviewslice.strides[dim] = memview.view.strides[dim]
memviewslice.suboffsets[dim] = memview.view.suboffsets[dim]
if isinstance(memview, _memoryviewslice):
to_object_func = (<_memoryviewslice> memview).to_object_func
to_dtype_func = (<_memoryviewslice> memview).to_dtype_func
else:
to_object_func = NULL
to_dtype_func = NULL
return memoryview_fromslice(&memviewslice, memview.view.ndim,
to_object_func, to_dtype_func)
############### BufferFormatFromTypeInfo ############### ############### BufferFormatFromTypeInfo ###############
cdef extern from *: cdef extern from *:
ctypedef struct __Pyx_StructField ctypedef struct __Pyx_StructField
......
...@@ -587,3 +587,76 @@ def assign_temporary_to_object(object[:] mslice): ...@@ -587,3 +587,76 @@ def assign_temporary_to_object(object[:] mslice):
""" """
buf = mslice buf = mslice
buf[1] = {3-2: 2+(2*4)-2} buf[1] = {3-2: 2+(2*4)-2}
def test_slicing(arg):
"""
Test simple slicing
>>> test_slicing(IntMockBuffer("A", range(8 * 14 * 11), shape=(8, 14, 11)))
acquired A
3 9 2
1232 -44 4
-1 -1 -1
released A
Test direct slicing, negative slice oob in dim 2
>>> test_slicing(IntMockBuffer("A", range(1 * 2 * 3), shape=(1, 2, 3)))
acquired A
0 0 2
48 -12 4
-1 -1 -1
released A
Test indirect slicing
>>> L = [[range(k * 12 + j * 4, k * 12 + j * 4 + 4) for j in xrange(3)] for k in xrange(5)]
>>> test_slicing(IntMockBuffer("A", L, shape=(5, 3, 4)))
acquired A
2 0 2
8 -4 4
0 0 -1
released A
"""
cdef int[::view.generic, ::view.generic, :] _a = arg
a = _a
b = a[2:8:2, -4:1:-1, 1:3]
print b.shape[0], b.shape[1], b.shape[2]
print b.strides[0], b.strides[1], b.strides[2]
print b.suboffsets[0], b.suboffsets[1], b.suboffsets[2]
cdef int i, j, k
for i in range(b.shape[0]):
for j in range(b.shape[1]):
for k in range(b.shape[2]):
itemA = a[2 + 2 * i, -4 - j, 1 + k]
itemB = b[i, j, k]
assert itemA == itemB, (i, j, k, itemA, itemB)
def test_slicing_and_indexing(arg):
"""
>>> a = IntStridedMockBuffer("A", range(10 * 3 * 5), shape=(10, 3, 5))
>>> test_slicing_and_indexing(a)
acquired A
5 2
60 8
126 113
[111]
released A
"""
cdef int[:, :, :] _a = arg
a = _a
b = a[-5:, 1, 1::2]
c = b[4:1:-1, ::-1]
d = c[2, 1:2]
print b.shape[0], b.shape[1]
print b.strides[0], b.strides[1]
cdef int i, j
for i in range(b.shape[0]):
for j in range(b.shape[1]):
itemA = a[-5 + i, 1, 1 + 2 * j]
itemB = b[i, j]
assert itemA == itemB, (i, j, itemA, itemB)
print c[1, 1], c[2, 0]
print [d[i] for i in range(d.shape[0])]
\ No newline at end of file
...@@ -19,24 +19,30 @@ def test_shape_stride_suboffset(): ...@@ -19,24 +19,30 @@ def test_shape_stride_suboffset():
u''' u'''
>>> test_shape_stride_suboffset() >>> test_shape_stride_suboffset()
5 7 11 5 7 11
616 88 8 77 11 1
-1 -1 -1 -1 -1 -1
<BLANKLINE>
5 7 11 5 7 11
8 40 280 1 5 35
-1 -1 -1 -1 -1 -1
<BLANKLINE>
5 7 11 5 7 11
616 88 8 77 11 1
-1 -1 -1 -1 -1 -1
''' '''
cdef unsigned long[:,:,:] larr = array((5,7,11), sizeof(unsigned long), 'L') cdef char[:,:,:] larr = array((5,7,11), 1, 'b')
print larr.shape[0], larr.shape[1], larr.shape[2] print larr.shape[0], larr.shape[1], larr.shape[2]
print larr.strides[0], larr.strides[1], larr.strides[2] print larr.strides[0], larr.strides[1], larr.strides[2]
print larr.suboffsets[0], larr.suboffsets[1], larr.suboffsets[2] print larr.suboffsets[0], larr.suboffsets[1], larr.suboffsets[2]
larr = array((5,7,11), sizeof(unsigned long), 'L', mode='fortran') print
larr = array((5,7,11), 1, 'b', mode='fortran')
print larr.shape[0], larr.shape[1], larr.shape[2] print larr.shape[0], larr.shape[1], larr.shape[2]
print larr.strides[0], larr.strides[1], larr.strides[2] print larr.strides[0], larr.strides[1], larr.strides[2]
print larr.suboffsets[0], larr.suboffsets[1], larr.suboffsets[2] print larr.suboffsets[0], larr.suboffsets[1], larr.suboffsets[2]
cdef unsigned long[:,:,:] c_contig = larr.copy() print
cdef char[:,:,:] c_contig = larr.copy()
print c_contig.shape[0], c_contig.shape[1], c_contig.shape[2] print c_contig.shape[0], c_contig.shape[1], c_contig.shape[2]
print c_contig.strides[0], c_contig.strides[1], c_contig.strides[2] print c_contig.strides[0], c_contig.strides[1], c_contig.strides[2]
print c_contig.suboffsets[0], c_contig.suboffsets[1], c_contig.suboffsets[2] print c_contig.suboffsets[0], c_contig.suboffsets[1], c_contig.suboffsets[2]
...@@ -161,7 +167,7 @@ def test_is_contiguous(): ...@@ -161,7 +167,7 @@ def test_is_contiguous():
print fort_contig.is_c_contig(), fort_contig.is_f_contig() print fort_contig.is_c_contig(), fort_contig.is_f_contig()
cdef int[:,:,:] strided = fort_contig cdef int[:,:,:] strided = fort_contig
print strided.is_c_contig(), strided.is_f_contig() print strided.is_c_contig(), strided.is_f_contig()
print print
fort_contig = fort_contig.copy_fortran() fort_contig = fort_contig.copy_fortran()
print fort_contig.is_c_contig(), fort_contig.is_f_contig() print fort_contig.is_c_contig(), fort_contig.is_f_contig()
print strided.is_c_contig(), strided.is_f_contig() print strided.is_c_contig(), strided.is_f_contig()
......
# tag: numpy
# mode: run
"""
Test slicing for memoryviews and memoryviewslices
"""
cimport numpy as np
import numpy
def get_array():
# We need to type our array to get a __pyx_get_buffer() that typechecks
# for np.ndarray and calls __getbuffer__ in numpy.pxd
cdef np.ndarray[int, ndim=3] a
a = numpy.arange(8 * 14 * 11).reshape(8, 14, 11)
return a
a = get_array()
def ae(*args):
"assert equals"
for x in args:
if x != args[0]:
raise AssertionError(args)
#
### Test slicing memoryview slices
#
def test_partial_slicing(array):
"""
>>> test_partial_slicing(a)
"""
cdef int[:, :, :] a = array
obj = array[4]
cdef int[:, :] b = a[4, :]
cdef int[:, :] c = a[4]
ae(b.shape[0], c.shape[0], obj.shape[0])
ae(b.shape[1], c.shape[1], obj.shape[1])
ae(b.strides[0], c.strides[0], obj.strides[0])
ae(b.strides[1], c.strides[1], obj.strides[1])
def test_ellipsis(array):
"""
>>> test_ellipsis(a)
"""
cdef int[:, :, :] a = array
cdef int[:, :] b = a[..., 4]
b_obj = array[..., 4]
cdef int[:, :] c = a[4, ...]
c_obj = array[4, ...]
cdef int[:, :] d = a[2:8, ..., 2]
d_obj = array[2:8, ..., 2]
ae(tuple([b.shape[i] for i in range(2)]), b_obj.shape)
ae(tuple([b.strides[i] for i in range(2)]), b_obj.strides)
for i in range(b.shape[0]):
for j in range(b.shape[1]):
ae(b[i, j], b_obj[i, j])
ae(tuple([c.shape[i] for i in range(2)]), c_obj.shape)
ae(tuple([c.strides[i] for i in range(2)]), c_obj.strides)
for i in range(c.shape[0]):
for j in range(c.shape[1]):
ae(c[i, j], c_obj[i, j])
ae(tuple([d.shape[i] for i in range(2)]), d_obj.shape)
ae(tuple([d.strides[i] for i in range(2)]), d_obj.strides)
for i in range(d.shape[0]):
for j in range(d.shape[1]):
ae(d[i, j], d_obj[i, j])
cdef int[:] e = a[..., 5, 6]
e_obj = array[..., 5, 6]
ae(e.shape[0], e_obj.shape[0])
ae(e.strides[0], e_obj.strides[0])
#
### Test slicing memoryview objects
#
def test_partial_slicing_memoryview(array):
"""
>>> test_partial_slicing_memoryview(a)
"""
cdef int[:, :, :] _a = array
a = _a
obj = array[4]
b = a[4, :]
c = a[4]
ae(b.shape[0], c.shape[0], obj.shape[0])
ae(b.shape[1], c.shape[1], obj.shape[1])
ae(b.strides[0], c.strides[0], obj.strides[0])
ae(b.strides[1], c.strides[1], obj.strides[1])
def test_ellipsis_memoryview(array):
"""
>>> test_ellipsis_memoryview(a)
"""
cdef int[:, :, :] _a = array
a = _a
b = a[..., 4]
b_obj = array[..., 4]
c = a[4, ...]
c_obj = array[4, ...]
d = a[2:8, ..., 2]
d_obj = array[2:8, ..., 2]
ae(tuple([b.shape[i] for i in range(2)]), b_obj.shape)
ae(tuple([b.strides[i] for i in range(2)]), b_obj.strides)
for i in range(b.shape[0]):
for j in range(b.shape[1]):
ae(b[i, j], b_obj[i, j])
ae(tuple([c.shape[i] for i in range(2)]), c_obj.shape)
ae(tuple([c.strides[i] for i in range(2)]), c_obj.strides)
for i in range(c.shape[0]):
for j in range(c.shape[1]):
ae(c[i, j], c_obj[i, j])
ae(tuple([d.shape[i] for i in range(2)]), d_obj.shape)
ae(tuple([d.strides[i] for i in range(2)]), d_obj.strides)
for i in range(d.shape[0]):
for j in range(d.shape[1]):
ae(d[i, j], d_obj[i, j])
e = a[..., 5, 6]
e_obj = array[..., 5, 6]
ae(e.shape[0], e_obj.shape[0])
ae(e.strides[0], e_obj.strides[0])
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment