如何正确传递numpy数组到Cython函数?

时间:2021-10-22 21:22:13

This is described in many places but i simply cannot get it to work. I am calling a C++ function from Cython:

这在很多地方都有描述,但我根本无法让它发挥作用。我调用了一个来自Cython的c++函数:

cimport numpy as np
cdef extern from "test.h" namespace "mytest":
   void test(double *A, int m)

cdef int foo():
  cdef np.ndarray[double,mode="c"] a = np.array([1,2,3,4,5],dtype=float)
  # pass ptr to first element of 'a'
  test(&a[0], len(a))
  return 0

foo()

test.cpp is just:

测试。cpp是:

#include <stdio.h>
namespace mytest {
    void test(double *A, int m)
    {
    for (int i = 0; i < m; i++)
    {
        printf("%d is %f\n", i, A[i]);
    }
    }
}

test.h just has:

测试。h就有:

namespace mytest {
  void test(double *A, int m);
}

This seems to work but when is np.ascontiguousarray needed? Is it sufficient to do:

这似乎起作用,但什么时候是np。ascontiguousarray需要吗?这样做是否足够?

cdef np.ndarray[double,mode="c"] a = np.array([1,2,3,4,5],dtype=float)

or do you need:

或者你需要:

cdef np.ndarray[double,mode="c"] a = np.ascontiguousarray(np.array([1,2,3,4,5],dtype=float))

second and more importantly, how can this generalize to 2d arrays?

第二,更重要的是,如何将这个一般化到二维数组?

Handling 2d arrays

处理二维数组

Here is my attempt at passing 2d numpy arrays to C++ which does not work:

下面是我试图将2d numpy数组传递给c++的尝试:

cdef np.ndarray[double,mode="c",ndim=2] a = np.array([[1,2],[3,4]],dtype=float)

which is called as:

被称为:

test(&a[0,0], a.shape[0], a.shape[1])

in the cpp code:

在cpp代码:

void test(double *A, int m, int n) 
{ 
  printf("reference 0,0 element\n");
  printf("%f\n", A[0][0]);
}

UPDATE: The correct answer

更新:正确答案

The correct answer is to use linear indexing for the array and not the [][] syntax. The correct way to print the 2d array is:

正确的答案是对数组使用线性索引,而不是[][]语法。打印2d数组的正确方法是:

for (int i = 0; i < m; i++)
{
    for (int j = 0; j < n; j++)
    {
    printf("%d, %d is %f\n", i, j, A[i*m + j]);
    }
}

1 个解决方案

#1


5  

For 2D arrays, you just need the ndim keyword:

对于2D数组,只需要ndim关键字:

cdef np.ndarray[double, mode="c", ndim=2]

The result may or may not share memory with the original. If it shares memory with the original, then the array may not be contiguous, or may have an unusual striding configuration. In this case, passing the buffer to C/C++ directly will be disastrous.

结果可能会或不能与原始内存共享。如果它与原始内存共享内存,那么该数组可能不是连续的,或者可能有不寻常的条带配置。在这种情况下,直接将缓冲区传递给C/ c++将是灾难性的。

You should always use ascontiguousarray unless your C/C++ code is prepared to deal with non-contiguous data (in which case you will need to pass in all relevant stride data from Cython into the C function). If the input array is already contiguous, no copy will be made. Make sure to pass a compatible dtype to ascontiguousarray so that you don't risk a second copy (e.g. having to convert from a contiguous float array to a contiguous double array).

除非你的C/ c++代码准备好处理非连续数据(在这种情况下,你需要从Cython中传递所有相关的跨步数据到C函数中),否则你应该总是使用ascontiousarray。如果输入数组已经连续,则不会复制。确保将一个兼容的dtype传递给一个连续的数组,这样您就不会冒第二个副本的风险(例如,必须将一个连续的浮点数组转换成一个连续的双数组)。

#1


5  

For 2D arrays, you just need the ndim keyword:

对于2D数组,只需要ndim关键字:

cdef np.ndarray[double, mode="c", ndim=2]

The result may or may not share memory with the original. If it shares memory with the original, then the array may not be contiguous, or may have an unusual striding configuration. In this case, passing the buffer to C/C++ directly will be disastrous.

结果可能会或不能与原始内存共享。如果它与原始内存共享内存,那么该数组可能不是连续的,或者可能有不寻常的条带配置。在这种情况下,直接将缓冲区传递给C/ c++将是灾难性的。

You should always use ascontiguousarray unless your C/C++ code is prepared to deal with non-contiguous data (in which case you will need to pass in all relevant stride data from Cython into the C function). If the input array is already contiguous, no copy will be made. Make sure to pass a compatible dtype to ascontiguousarray so that you don't risk a second copy (e.g. having to convert from a contiguous float array to a contiguous double array).

除非你的C/ c++代码准备好处理非连续数据(在这种情况下,你需要从Cython中传递所有相关的跨步数据到C函数中),否则你应该总是使用ascontiousarray。如果输入数组已经连续,则不会复制。确保将一个兼容的dtype传递给一个连续的数组,这样您就不会冒第二个副本的风险(例如,必须将一个连续的浮点数组转换成一个连续的双数组)。