Commit e31c8f6f authored by Mark Florisson's avatar Mark Florisson

Support transposing memoryview objects and slices

parent 2e17dee8
...@@ -2892,7 +2892,7 @@ class IndexNode(ExprNode): ...@@ -2892,7 +2892,7 @@ class IndexNode(ExprNode):
buffer_entry = self.buffer_entry() buffer_entry = self.buffer_entry()
if buffer_entry.type.is_buffer: if buffer_entry.type.is_buffer:
negative_indices = entry.type.negative_indices negative_indices = buffer_entry.type.negative_indices
else: else:
negative_indices = Buffer.buffer_defaults['negative_indices'] negative_indices = Buffer.buffer_defaults['negative_indices']
...@@ -3861,6 +3861,7 @@ class AttributeNode(ExprNode): ...@@ -3861,6 +3861,7 @@ class AttributeNode(ExprNode):
entry = None entry = None
is_called = 0 is_called = 0
needs_none_check = True needs_none_check = True
is_memslice_transpose = False
def as_cython_attribute(self): def as_cython_attribute(self):
if (isinstance(self.obj, NameNode) and if (isinstance(self.obj, NameNode) and
...@@ -4061,6 +4062,13 @@ class AttributeNode(ExprNode): ...@@ -4061,6 +4062,13 @@ class AttributeNode(ExprNode):
if obj_type.attributes_known(): if obj_type.attributes_known():
if (obj_type.is_memoryviewslice and not if (obj_type.is_memoryviewslice and not
obj_type.scope.lookup_here(self.attribute)): obj_type.scope.lookup_here(self.attribute)):
if self.attribute == 'T':
self.is_memslice_transpose = True
self.is_temp = True
self.use_managed_ref = True
self.type = self.obj.type
return
else:
obj_type.declare_attribute(self.attribute) obj_type.declare_attribute(self.attribute)
entry = obj_type.scope.lookup_here(self.attribute) entry = obj_type.scope.lookup_here(self.attribute)
if entry and entry.is_member: if entry and entry.is_member:
...@@ -4169,15 +4177,31 @@ class AttributeNode(ExprNode): ...@@ -4169,15 +4177,31 @@ class AttributeNode(ExprNode):
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
elif self.type.is_memoryviewslice: elif self.type.is_memoryviewslice:
if self.initialized_check: if self.is_memslice_transpose:
# transpose the slice
if self.in_nogil_context:
error(self.pos, "Cannot transpose slice in nogil mode")
return
for access, packing in self.type.axes:
if access == 'ptr':
error(self.pos, "Transposing not supported for slices "
"with indirect dimensions")
return
code.putln("%s = %s;" % (self.result(), self.obj.result()))
if self.obj.is_name:
code.put_incref_memoryviewslice(self.result(), have_gil=True)
T = "__pyx_memslice_transpose(&%s) == 0"
code.putln(code.error_goto_if(T % self.result(), self.pos))
elif self.initialized_check:
code.putln( code.putln(
'if (unlikely(!%s.memview)) {' 'if (unlikely(!%s.memview)) {'
'PyErr_SetString(PyExc_AttributeError,' 'PyErr_SetString(PyExc_AttributeError,'
'"Memoryview is not initialized");' '"Memoryview is not initialized");'
'%s' '%s'
'}' % (self.result(), code.error_goto(self.pos))) '}' % (self.result(), code.error_goto(self.pos)))
#code.putln("%s = %s;" % (self.result(),
# self.calculate_result_code()))
else: else:
# result_code contains what is needed, but we may need to insert # result_code contains what is needed, but we may need to insert
# a check and raise an exception # a check and raise an exception
......
...@@ -510,7 +510,6 @@ class MemoryViewSliceType(PyrexType): ...@@ -510,7 +510,6 @@ class MemoryViewSliceType(PyrexType):
entry.utility_code_definition = \ entry.utility_code_definition = \
MemoryView.IsContigFuncUtilCode(c_or_f) MemoryView.IsContigFuncUtilCode(c_or_f)
return True return True
def specialization_suffix(self): def specialization_suffix(self):
......
...@@ -306,17 +306,8 @@ cdef class memoryview(object): ...@@ -306,17 +306,8 @@ cdef class memoryview(object):
property T: property T:
@cname('__pyx_memoryview_transpose') @cname('__pyx_memoryview_transpose')
def __get__(self): def __get__(self):
cdef memoryview result = memoryview_copy(self) cdef _memoryviewslice result = memoryview_copy(self)
transpose_memslice(&result.from_slice)
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 return result
property _obj: property _obj:
...@@ -409,7 +400,7 @@ cdef memoryview memview_slice(memoryview memview, object indices): ...@@ -409,7 +400,7 @@ cdef memoryview memview_slice(memoryview memview, object indices):
memviewsliceobj = memview memviewsliceobj = memview
p_src = &memviewsliceobj.from_slice p_src = &memviewsliceobj.from_slice
else: else:
create_slice(memview, &src) slice_copy(memview, &src)
p_src = &src p_src = &src
# Note: don't use variable src at this point # Note: don't use variable src at this point
...@@ -623,6 +614,30 @@ cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, ...@@ -623,6 +614,30 @@ cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index,
return resultp return resultp
#
### Transposing a memoryviewslice
#
@cname('__pyx_memslice_transpose')
cdef int transpose_memslice({{memviewslice_name}} *memslice) except 0:
cdef int ndim = memslice.memview.view.ndim
cdef Py_ssize_t *shape = memslice.shape
cdef Py_ssize_t *strides = memslice.strides
# reverse strides and shape
cdef int i, j
for i in range(ndim / 2):
j = ndim - 1 - i
strides[i], strides[j] = strides[j], strides[i]
shape[i], shape[j] = shape[j], shape[i]
if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0:
dim = i if memslice.suboffsets[i] >= 0 else j
raise ValueError("Cannot transpose view with indirect dimension "
"(axis %d)" % dim)
return 1
# #
### Creating new memoryview objects from slices and memoryviews ### Creating new memoryview objects from slices and memoryviews
# #
...@@ -694,8 +709,8 @@ cdef memoryview_fromslice({{memviewslice_name}} *memviewslice, ...@@ -694,8 +709,8 @@ cdef memoryview_fromslice({{memviewslice_name}} *memviewslice,
return result return result
@cname('__pyx_memoryview_create_slice') @cname('__pyx_memoryview_slice_copy')
cdef void create_slice(memoryview memview, {{memviewslice_name}} *dst): cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst):
cdef int dim cdef int dim
dst.memview = <__pyx_memoryview *> memview dst.memview = <__pyx_memoryview *> memview
...@@ -712,7 +727,7 @@ cdef memoryview_copy(memoryview memview): ...@@ -712,7 +727,7 @@ cdef memoryview_copy(memoryview memview):
cdef object (*to_object_func)(char *) cdef object (*to_object_func)(char *)
cdef int (*to_dtype_func)(char *, object) except 0 cdef int (*to_dtype_func)(char *, object) except 0
create_slice(memview, &memviewslice) slice_copy(memview, &memviewslice)
if isinstance(memview, _memoryviewslice): if isinstance(memview, _memoryviewslice):
to_object_func = (<_memoryviewslice> memview).to_object_func to_object_func = (<_memoryviewslice> memview).to_object_func
......
...@@ -140,3 +140,26 @@ def test_ellipsis_memoryview(array): ...@@ -140,3 +140,26 @@ def test_ellipsis_memoryview(array):
e_obj = array[..., 5, 6] e_obj = array[..., 5, 6]
ae(e.shape[0], e_obj.shape[0]) ae(e.shape[0], e_obj.shape[0])
ae(e.strides[0], e_obj.strides[0]) ae(e.strides[0], e_obj.strides[0])
def test_transpose():
"""
>>> test_transpose()
3 4
(3, 4)
(3, 4)
11 11 11 11 11 11
"""
cdef dtype_t[:, :] a
numpy_obj = np.arange(4 * 3, dtype=np.int32).reshape(4, 3)
a = numpy_obj
a_obj = a
cdef dtype_t[:, :] b = a.T
print a.T.shape[0], a.T.shape[1]
print a_obj.T.shape
print numpy_obj.T.shape
print a[3, 2], a.T[2, 3], a_obj[3, 2], a_obj.T[2, 3], numpy_obj[3, 2], numpy_obj.T[2, 3]
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