如何正确地将numpy数组传递给Cython函数?

14 c++ python numpy 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()
Run Code Online (Sandbox Code Playgroud)

test.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]);
    }
    }
}
Run Code Online (Sandbox Code Playgroud)

test.h只有:

namespace mytest {
  void test(double *A, int m);
}
Run Code Online (Sandbox Code Playgroud)

这似乎有效,但何时np.ascontiguousarray需要?这样做是否足够:

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

或者你需要:

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

第二,更重要的是,这如何推广到二维阵列?

处理2d数组

这是我尝试将2d numpy数组传递给C++,但这不起作用:

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

被称为:

test(&a[0,0], a.shape[0], a.shape[1])
Run Code Online (Sandbox Code Playgroud)

在cpp代码中:

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

更新:正确的答案

正确的答案是对数组使用线性索引而不是[][]语法.打印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]);
    }
}
Run Code Online (Sandbox Code Playgroud)

nne*_*neo 6

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

cdef np.ndarray[double, mode="c", ndim=2]
Run Code Online (Sandbox Code Playgroud)

结果可能会也可能不会与原始内容共享内存.如果它与原始内存共享内存,则该阵列可能不是连续的,或者可能具有不寻常的跨步配置.在这种情况下,直接将缓冲区传递给C/C++将是灾难性的.

除非您的C/C++代码准备好处理非连续数据,否则您应该始终使用ascontiguousarray(在这种情况下,您需要将所有相关的步幅数据从Cython传递到C函数中).如果输入数组已连续,则不会进行任何复制.确保传递兼容dtype,ascontiguousarray以便您不会冒第二个副本的风险(例如,必须从连续float数组转换为连续double数组).

  • 在C中,你必须使用1D索引,是的.这在处理连续数据的缓冲区时是典型的.(在多维C数组上,如`double [] []`,C编译器基本上通过将数组维度与索引相乘来生成等效的1D索引操作. (2认同)