Przekazywanie tablic Numpy do funkcji C dla wejścia i wyjścia
O rany, jestem głupcem. Po prostu pomijałem drugi i trzeci argument podczas wywoływania funkcji. Jak głupiec. Bo tym właśnie jestem. Oryginalne głupie pytanie:
Wydaje się, że to musi być bardzo powszechna rzecz do zrobienia, ale nie mogę znaleźć odpowiedniego tutoriala, i jestem zbyt nieświadomy o Numpy
i ctypes
, aby sam to rozgryźć.
Mam funkcję C w pliku ctest.c
.
#include <stdio.h>
void cfun(const void * indatav, int rowcount, int colcount, void * outdatav) {
//void cfun(const double * indata, int rowcount, int colcount, double * outdata) {
const double * indata = (double *) indatav;
double * outdata = (double *) outdatav;
int i;
puts("Here we go!");
for (i = 0; i < rowcount * colcount; ++i) {
outdata[i] = indata[i] * 2;
}
puts("Done!");
}
(Jak można się domyślać, początkowo miałem argumenty jako podwójne * raczej niż void *, ale nie mogłem wymyślić, co zrobić po stronie Pythona. Z pewnością chciałbym je zmienić, ale nie jestem wybredny, dopóki to działa.)
Robię z tego wspólną bibliotekę. gcc-fPIC-shared-o ctest.so ctest.c
Następnie w Pythonie mam kilka tablic numpy i chciałbym przekazać je do funkcji C, jedna jako wejście, a druga jako wyjście.
indata = numpy.ones((5,6), dtype=numpy.double)
outdata = numpy.zeros((5,6), dtype=numpy.double)
lib = ctypes.cdll.LoadLibrary('./ctest.so')
fun = lib.cfun
# Here comes the fool part.
fun(ctypes.c_void_p(indata.ctypes.data), ctypes.c_void_p(outdata.ctypes.data))
print 'indata: %s' % indata
print 'outdata: %s' % outdata
To nie zgłasza żadnych błędów, ale wypisuje
>>> Here we go!
Done!
indata: [[ 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1.]]
outdata: [[ 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]]
Tablica outdata nie jest modyfikowana. I w fakt, jeśli ponownie wywołam tę funkcję, dostaję segfault. Co mnie nie dziwi ... naprawdę Nie wiem, co tu robię. Czy ktoś może wskazać mi właściwy kierunek?
2 answers
Wystarczy przekazać wszystkie cztery argumenty do funkcji C. Zmień kod Pythona z:
fun(ctypes.c_void_p(indata.ctypes.data), ctypes.c_void_p(outdata.ctypes.data))
Do:
fun(ctypes.c_void_p(indata.ctypes.data), ctypes.c_int(5), ctypes.c_int(6),
ctypes.c_void_p(outdata.ctypes.data))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-02 23:21:17
Chociaż nie jest to bezpośrednia odpowiedź na oryginalne pytanie, oto o wiele wygodniejszy sposób na wywołanie funkcji. Po pierwsze, zrób prototyp swojej funkcji C dokładnie tak, jak byś to zrobił w zwykłym C. Ponieważ nie potrzebujesz rowcount
i colcount
osobno, zwinę je w jeden parametr size
:
void cfun(const double *indatav, size_t size, double *outdatav)
{
size_t i;
for (i = 0; i < size; ++i)
outdatav[i] = indatav[i] * 2.0;
}
Teraz zdefiniuj prototyp ctypes w następujący sposób:
import ctypes
from numpy.ctypeslib import ndpointer
lib = ctypes.cdll.LoadLibrary("./ctest.so")
fun = lib.cfun
fun.restype = None
fun.argtypes = [ndpointer(ctypes.c_double, flags="C_CONTIGUOUS"),
ctypes.c_size_t,
ndpointer(ctypes.c_double, flags="C_CONTIGUOUS")]
Teraz wywołania twojej funkcji będą naprawdę wygodne:
indata = numpy.ones((5,6))
outdata = numpy.empty((5,6))
fun(indata, indata.size, outdata)
Można również zdefiniować wrapper aby było to jeszcze wygodniejsze:
def wrap_fun(indata, outdata):
assert indata.size == outdata.size
fun(indata, indata.size, outdata)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 11:13:10