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

how to pass numpy array to Cython function correctly?

本文关键字:Cython 函数 numpy 数组      更新时间:2023-10-16

这在很多地方都有描述,但我根本无法让它工作。我正在调用来自 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()

测试.cpp只是:

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

Test.h 只有:

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

这似乎有效,但什么时候需要np.ascontiguousarray?是否足以做到:

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

或者您需要:

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

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

处理 2D 数组

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

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

这被称为:

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

在 CPP 代码中:

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

更新:正确答案

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

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

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

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

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

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