web-dev-qa-db-ja.com

numpy配列をC ++に渡す

Pythonで出力がnumpy配列であるコードを記述しました。次に、その出力をC++コードに送信します。ここで、計算の大部分が行われます。実行されました。

Cythonのpublic cdefを使用してみましたが、いくつかの問題が発生しています。よろしくお願いします!これが私のコードです:

pymodule.pyx

from pythonmodule import result # result is my numpy array
import numpy as np
cimport numpy as np
cimport cython

@cython.boundscheck(False)
@cython.wraparound(False)
cdef public void cfunc():
    print 'I am in here!!!'
    cdef np.ndarray[np.float64_t, ndim=2, mode='c'] res = result
    print res

これがcythonizedされたら、私は次のように呼びます。

pymain.c

#include <Python.h>
#include <numpy/arrayobject.h>
#include "pymodule.h"

int main() {
  Py_Initialize();
  initpymodule();
  test(2);
  Py_Finalize();
}

int test(int a)
{
    Py_Initialize();
    initpymodule();
    cfunc();
    return 0;
}

C++NameError変数のresultを取得しています。ポインタを使って定義し、他の関数から間接的に呼び出しようとしましたが、配列は表示されません。答えは非常に単純だと確信していますが、私にはわかりません。ご協力いただきありがとうございます!

12
user3225486

短い答え

NameErrorは、Pythonがモジュールを見つけることができず、作業ディレクトリが自動的に PYTHONPATH /に追加されない)という事実が原因でした。setenv を_C/C++_コードのsetenv("PYTHONPATH", ".", 1);とともに使用するとこれが修正されます。

長い答え

どうやら、これを行う簡単な方法があります。すでに作成された配列を含むpythonモジュール_pythonmodule.py_の場合:

_import numpy as np

result = np.arange(20, dtype=np.float).reshape((2, 10))
_

publicキーワードを使用して、_pymodule.pyx_を構造化してその配列をエクスポートできます。いくつかの補助関数を追加することで、通常、PythonにもNumpy _C-API_にも触れる必要がなくなります。

_from pythonmodule import result
from libc.stdlib cimport malloc
import numpy as np
cimport numpy as np


cdef public np.ndarray getNPArray():
    """ Return array from pythonmodule. """
    return <np.ndarray>result

cdef public int getShape(np.ndarray arr, int shape):
    """ Return Shape of the Array based on shape par value. """
    return <int>arr.shape[1] if shape else <int>arr.shape[0]

cdef public void copyData(float *** dst, np.ndarray src):
    """ Copy data from src numpy array to dst. """
    cdef float **tmp
    cdef int i, j, m = src.shape[0], n=src.shape[1];

    # Allocate initial pointer 
    tmp = <float **>malloc(m * sizeof(float *))
    if not tmp:
        raise MemoryError()

    # Allocate rows
    for j in range(m):
        tmp[j] = <float *>malloc(n * sizeof(float))
        if not tmp[j]:
            raise MemoryError()

    # Copy numpy Array
    for i in range(m):
        for j in range(n):
            tmp[i][j] = src[i, j]

    # Assign pointer to dst
    dst[0] = tmp
_

関数getNPArraygetShapeは、それぞれ配列とその形状を返します。 copyDataは、 _ndarray.data_ を抽出してコピーし、ファイナライズできるようにするために追加されましたPythonそしてインタプリタを初期化せずに動作します。

サンプルプログラム(Cでは、_C++_は同じように見えるはずです)は次のようになります。

_#include <Python.h>
#include "numpy/arrayobject.h"
#include "pyxmod.h"
#include <stdio.h>

void printArray(float **arr, int m, int n);
void getArray(float ***arr, int * m, int * n);

int main(int argc, char **argv){
    // Holds data and shapes.
    float **data = NULL;
    int m, n;

    // Gets array and then prints it.
    getArray(&data, &m, &n);
    printArray(data, m, n);

    return 0;
}

void getArray(float ***data, int * m, int * n){
    // setenv is important, makes python find 
    // modules in working directory
    setenv("PYTHONPATH", ".", 1);

    // Initialize interpreter and module
    Py_Initialize();
    initpyxmod();

    // Use Cython functions.
    PyArrayObject *arr = getNPArray();
    *m = getShape(arr, 0);
    *n = getShape(arr, 1);

    copyData(data, arr);

    if (data == NULL){  //really redundant.
        fprintf(stderr, "Data is NULL\n");
        return ;
    }

    Py_DECREF(arr);
    Py_Finalize();
}

void printArray(float **arr, int m, int n){
    int i, j;
    for(i=0; i < m; i++){
        for(j=0; j < n; j++)
            printf("%f ", arr[i][j]);

        printf("\n");
    }
}
_

常に設定することを忘れないでください:

_setenv("PYTHONPATH", ".", 1);
_

before_Py_Initialize_を呼び出すと、Pythonは作業ディレクトリでモジュールを見つけることができます。

残りはかなり簡単です。追加のエラーチェックが必要な場合があり、間違いなく割り当てられたメモリを解放する関数が必要です。

Cythonを使用しない代替方法:

あなたが試みている方法でそれを行うことは、それが価値があるよりもはるかに面倒です、あなたはおそらく _numpy.save_ を使用して配列をnpyバイナリファイルに保存し、次にいくつかを使用する方が良いでしょう そのファイルを読み取るC++ライブラリ