0

I am using C-contiguous memoryviews in my Python code and I would like to use dgemm which needs Fortran-contiguous memoryviews. I would like to use the function PyMemoryView_GetContiguous found here but I don't know how to access it.

Does someone know which import I have to do ?

I don't want to use the function copy_fortran() as it really slows down my code.

14thibea
  • 5
  • 2
  • A comment as this is a bit of a guess: It looks as though you currently have the matrices stored in row major order, which is the transpose of what you think you want. But can you use C(T)=(AB)(T)=B(T)A(T) with the transpose options in dgemm to avoid having to change the memory layout? (Where (T) means take the transpose) – Ian Bush Jul 18 '17 at 08:44
  • This is finally how I solved my problem. Thanks ! – 14thibea Jul 19 '17 at 07:53

1 Answers1

0

PyMemoryView_GetContiguous doesn't look to be exposed as part of the Cython standard includes unfortunately. It should be reasonably easy to wrap though:

from cpython.buffer cimport PyBUF_READ # we'll need this later

cdef extern from "Python.h":
    # copy the signature replacing PyObject* with object to let Cython
    # handle the reference counting
    object PyMemoryView_GetContiguous(object, int, char)

def test(double[:,::1] c_contig):
   f_contig = PyMemoryView_GetContiguous(c_contig, PyBuf_READ,'F')
   # .... do something useful

Be aware that this will still involve copying all the memory (this is absolutely unavoidable!) so is unlikely to be significantly faster than copy_fortran.


There's a problem though - PyMemoryView_GetContiguous won't return a writeable memoryview unless it does not have to make a copy, and Cython requires things assigned to a typed memoryview be writeable, so you can only use it as a Python object.

You can get a pointer to the first element though - the underlying object that created is a bytes/str object, so you can get a char* then cast that to whatever pointer you need. This should be enough to call your Fortran functions:

cdef char* as_bytes = f_contig.obj
some_function(<double*>as_bytes)
DavidW
  • 29,336
  • 6
  • 55
  • 86