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
......
This diff is collapsed.
...@@ -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