6

I am interfacing a C library with python. I have arrays in numpy that I pass to the library using the ctypes attribute of the array.

At some point I need to provide an array to the C library, that is expected to be the transposed of the numpy array a I have. (Another way of putting it is that the C library does not accept a stride for the inner-most dimension). However when I pass a.T instead of a, nothing happens.

Indeed it seems that numpy does some sort of lazy transposition by simply swapping the strides:

import ctypes
import numpy as np
a = np.zeros((2, 3))
a.ctypes.strides_as(ctypes.c_longlong)[:]
# returns [24, 8]
a.T.ctypes.strides_as(ctypes.c_longlong)[:]
# return [8, 24]

My question is, how to enforce this transposition to happen in memory?

EDIT

I noticed that

a.T + np.zeros(a.T.shape)

reorders the memory like I want, but if there is a more elegant and explicit solution, I would still like to hear it.

(Also, interestingly,

a.T + np.zeros_like(a.T)

seems to not reorder memory).

P-Gn
  • 23,115
  • 9
  • 87
  • 104

1 Answers1

4

a.T, like a.transpose(), just affect the header and return views. You can check them with : a.T.flags.owndata, wich is False.

To actually transpose the data, the simplest way to make a copy : a=a.T.copy().

Making it in place is a harder task. You can do it this way :

a=np.arange(6).reshape(2,3).copy()
print(a,a.flags,id(a),sep='\n')

a.ravel()[:]=a.T.ravel()
a.shape=a.T.shape

print(a,a.flags,id(a),sep=('\n'))

Output :

[[0 1 2]
 [3 4 5]]
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False
221212538640
[[0 3]
 [1 4]
 [2 5]]
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False
221212538640

But with no warranty, since you write on data you read. It can fails without warning on big arrays.

B. M.
  • 18,243
  • 2
  • 35
  • 54