Как правильно передать массив numpy в функцию Cython?

Это описано во многих местах, но я просто не могу заставить его работать. Я вызываю функцию С++ из Cython:

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:

#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 просто имеет:

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

Вот моя попытка передать 2d массивы numpy на С++, который не работает:

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 element\n");
  printf("%f\n", A[0][0]);
}

ОБНОВЛЕНИЕ: правильный ответ

Правильный ответ - использовать линейную индексацию для массива, а не синтаксис [][]. Правильный способ печати массива 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

Для 2D-массивов вам нужно только ключевое слово ndim:

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

Результат может или не может обмениваться памятью с оригиналом. Если он разделяет память с оригиналом, то массив может не быть смежным или может иметь необычную конфигурацию шага. В этом случае передача буфера в C/С++ напрямую будет катастрофической.

Вы всегда должны использовать ascontiguousarray, если ваш код C/С++ не готов к обработке несмежных данных (в этом случае вам нужно будет передать все важные данные шага из Cython в функцию C). Если входной массив уже смежный, копия не будет выполнена. Обязательно передайте совместимый dtype в ascontiguousarray, чтобы не подвергать риску вторую копию (например, нужно преобразовать из смежного массива float в смежный массив double).