Numpy.i отправляет фактические указатели на C ++ или создает копии памяти? - PullRequest
3 голосов
/ 19 июня 2019

Я изучаю C ++, swig и numpy для лаборатории, в которой я работаю. Было указано, что я должен использовать swig (без scypy), я должен использовать numpy массивы и не могу "вводить код C вмир python ", например, используя% import" std_vector "в моем файле интерфейса и просто заставляя пользователя python создать его для отправки. При этом я пытаюсь получить массив 1d numpy (если им нужно больше измерений, я будупросто сгладить его), чтобы он передавался в мой C-код исключительно по указателю - мой начальник не хочет тратить время на то, чтобы скопировать все, потому что эффективность очень важна.Я считаю, что мы используем c ++ 14, python 2.7 и последнюю версию swig, и я также использую numpy.i.

Я приведу нижеприведенный код, который я сейчас использую (просто пытаюсь добиться минимальной жизнеспособности), но я довольно новичок, и хотя он работает, я не уверен, что фактически передает указательи не копировать ничего, как я хотел бы.Может ли кто-нибудь, пожалуйста, подтвердить это или показать мне, как это сделать?Спасибо x10 ^ 99

//The C++ file I am wrapping: 
#ifndef _np_array_to_array_h
#define _np_array_to_array_h

using namespace std;
double getMid(double* myArray, int size){
    int half = size / 2;
    return myArray[half];
}
#endif

///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//\/\

//The interface file: 
%module np_array_to_array

%{
#define SWIG_FILE_WITH_INIT
#include "np_array_to_array.h"
#include <numpy/arrayobject.h>
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (double* IN_ARRAY1, int DIM1){(double* myArray, int size)};
%include "np_array_to_array.h"

//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

//How I compile on terminal: 
swig -python -c++ np_array_to_array.i
g++ -fpic -c np_array_to_array_wrap.cxx -I/usr/include/python2.7 
-I/home/sean/Desktop/SerangLab/Swig/numpy/numpy/core/include/ -I/home/sean/.local/lib/python2.7/site-packages/numpy/core/include/numpy/
 g++ -shared np_array_to_array_wrap.o -o _np_array_to_array.so

Это скомпилирует и запустит, и создаст успешно работающий модуль python, с которым я импортирую (находясь в той же директории) "из np_array_to_array import *", и я могу успешно запустить getMidметод, передавая в numpyArray и получая двойной обратно.Как указано выше, я просто не уверен, действительно ли это передается по указателю (не делает никаких копий) или нет, так как я не нашел ничего, что говорит так или иначе.Может ли кто-нибудь сказать мне, а если нет, объяснить, как можно это сделать?Я полагаю, что это должно быть возможно, поскольку я думаю, что массив numpy использует типы c и хранит память непрерывно, как c.

1 Ответ

1 голос
/ 21 июня 2019

Вы можете довольно легко исследовать это в коде, который генерирует SWIG.Это две части: файл .py и файл .cxx.В каждом из них есть некоторый код, сгенерированный для вашей функции getMid().Код Python просто напрямую передает все в код C ++, который в моей системе в итоге выглядел так:

SWIGINTERN PyObject *_wrap_getMid(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  double *arg1 = (double *) 0 ;
  int arg2 ;
  PyArrayObject *array1 = NULL ;
  int is_new_object1 = 0 ;
  PyObject * obj0 = 0 ;
  double result;

  if (!PyArg_ParseTuple(args,(char *)"O:getMid",&obj0)) SWIG_fail;
  {
    npy_intp size[1] = {
      -1 
    };
    array1 = obj_to_array_contiguous_force_conversion(obj0, NPY_DOUBLE,
      &is_new_object1);
    if (!array1 || !require_dimensions(array1, 1) ||
      !require_size(array1, size, 1)) SWIG_fail;
    arg1 = (double*) array_data(array1);
    arg2 = (int) array_size(array1,0);
  }
  result = (double)getMid(arg1,arg2);
  resultobj = SWIG_From_double(static_cast< double >(result));
  {
    if (is_new_object1 && array1)
    {
      Py_DECREF(array1); 
    }
  }
  return resultobj;
fail:
...

Он не сильно изменится между версиями SWIG и Python, хотя некоторые параметры SWIG будутизмените его немного.

Важным моментом с точки зрения вашего вопроса, похоже, является призыв к obj_to_array_contiguous_force_conversion.У него есть аргумент, который используется в качестве выходного параметра, чтобы указать, был ли выделен новый объект.Если для этого значения устанавливается значение true, то после вызова объект также освобождается.

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

Можно также с уверенностью предположить, что если вы используете какой-либо из типов numpy double, вы в конечном итоге выполните это требование и не будете делать копию, но для других типов данных это менее вероятно, если вы не приложите немного усилий.

...