I am going to send a c++
array to a python function as numpy array
and get back another numpy array
. After consulting with numpy
documentation and some other threads and tweaking the code, finally the code is working but I would like to know if this code is written optimally considering the:
我将把一个c++数组作为numpy数组发送给python函数,然后返回另一个numpy数组。在查阅了numpy文档和其他一些线程并对代码进行了调整之后,代码终于开始工作了,但是我想知道,考虑到:
- Unnecessary copying of the array between
c++
andnumpy (python)
. - 在c++和numpy (python)之间不必要地复制数组。
- Correct dereferencing of the variables.
- 正确取消变量的引用。
- Easy straight-forward approach.
- 简单直接的方法。
C++ code:
c++代码:
// python_embed.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "Python.h"
#include "numpy/arrayobject.h"
#include<iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
Py_SetProgramName(argv[0]);
Py_Initialize();
import_array()
// Build the 2D array
PyObject *pArgs, *pReturn, *pModule, *pFunc;
PyArrayObject *np_ret, *np_arg;
const int SIZE{ 10 };
npy_intp dims[2]{SIZE, SIZE};
const int ND{ 2 };
long double(*c_arr)[SIZE]{ new long double[SIZE][SIZE] };
long double* c_out;
for (int i{}; i < SIZE; i++)
for (int j{}; j < SIZE; j++)
c_arr[i][j] = i * SIZE + j;
np_arg = reinterpret_cast<PyArrayObject*>(PyArray_SimpleNewFromData(ND, dims, NPY_LONGDOUBLE,
reinterpret_cast<void*>(c_arr)));
// Calling array_tutorial from mymodule
PyObject *pName = PyUnicode_FromString("mymodule");
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (!pModule){
cout << "mymodule can not be imported" << endl;
Py_DECREF(np_arg);
delete[] c_arr;
return 1;
}
pFunc = PyObject_GetAttrString(pModule, "array_tutorial");
if (!pFunc || !PyCallable_Check(pFunc)){
Py_DECREF(pModule);
Py_XDECREF(pFunc);
Py_DECREF(np_arg);
delete[] c_arr;
cout << "array_tutorial is null or not callable" << endl;
return 1;
}
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, reinterpret_cast<PyObject*>(np_arg));
pReturn = PyObject_CallObject(pFunc, pArgs);
np_ret = reinterpret_cast<PyArrayObject*>(pReturn);
if (PyArray_NDIM(np_ret) != ND - 1){ // row[0] is returned
cout << "Function returned with wrong dimension" << endl;
Py_DECREF(pFunc);
Py_DECREF(pModule);
Py_DECREF(np_arg);
Py_DECREF(np_ret);
delete[] c_arr;
return 1;
}
int len{ PyArray_SHAPE(np_ret)[0] };
c_out = reinterpret_cast<long double*>(PyArray_DATA(np_ret));
cout << "Printing output array" << endl;
for (int i{}; i < len; i++)
cout << c_out[i] << ' ';
cout << endl;
// Finalizing
Py_DECREF(pFunc);
Py_DECREF(pModule);
Py_DECREF(np_arg);
Py_DECREF(np_ret);
delete[] c_arr;
Py_Finalize();
return 0;
}
In CodeReview, there is a fantastic answer: Link...
在CodeReview中,有一个奇妙的答案:Link…
3 个解决方案
#1
3
From my experience that seems to be pretty efficient. To get even more efficiency out of it try this : http://ubuntuforums.org/showthread.php?t=1266059
根据我的经验,这似乎很有效。为了提高效率,可以尝试以下方法:http://ubuntuforums.org/showthread.php?
Using weave you can inline C/C++ code in Python so that could be useful.
使用weave,你可以在Python中内联C/ c++代码,这很有用。
http://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.weave.inline.html
http://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.weave.inline.html
Here's a link on how Python can be used to interface between many different languages along with examples.
这里有一个关于如何使用Python与许多不同语言之间进行接口的链接以及示例。
http://docs.scipy.org/doc/numpy/user/c-info.python-as-glue.html
http://docs.scipy.org/doc/numpy/user/c-info.python-as-glue.html
This is a quick and easy example of how to pass numpy arrays to c++ using Cython:
这是一个使用Cython将numpy数组传递给c++的快速简单示例:
http://www.birving.com/blog/2014/05/13/passing-numpy-arrays-between-python-and/
http://www.birving.com/blog/2014/05/13/passing-numpy-arrays-between-python-and/
#2
2
Try out xtensor and the xtensor-python python bindings.
xtensor is a C++ library meant for numerical analysis with multi-dimensional array expressions.
x张量是一个c++库,用于使用多维数组表达式进行数值分析。
xtensor provides
xtensor提供
- an extensible expression system enabling numpy-style broadcasting (see the numpy to xtensor cheat sheet).
- 一个可扩展的表达式系统,支持numpy样式的广播(参见numpy到x张量备忘单)。
- an API following the idioms of the C++ standard library.
- 遵循c++标准库的习惯用法的API。
- tools to manipulate array expressions and build upon xtensor.
- 用于操作数组表达式和构建x张量的工具。
- bindings for Python, but also R and Julia.
- Python的绑定,还有R和Julia。
Example of usage
Initialize a 2-D array and compute the sum of one of its rows and a 1-D array.
初始化一个二维数组并计算其中一行和一个一维数组的和。
#include <iostream>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
xt::xarray<double> arr1
{{1.0, 2.0, 3.0},
{2.0, 5.0, 7.0},
{2.0, 5.0, 7.0}};
xt::xarray<double> arr2
{5.0, 6.0, 7.0};
xt::xarray<double> res = xt::view(arr1, 1) + arr2;
std::cout << res;
Outputs
输出
{7, 11, 14}
Creating a Numpy-style universal function in C++.
#include "pybind11/pybind11.h"
#include "xtensor-python/pyvectorize.hpp"
#include <numeric>
#include <cmath>
namespace py = pybind11;
double scalar_func(double i, double j)
{
return std::sin(i) - std::cos(j);
}
PYBIND11_PLUGIN(xtensor_python_test)
{
py::module m("xtensor_python_test", "Test module for xtensor python bindings");
m.def("vectorized_func", xt::pyvectorize(scalar_func), "");
return m.ptr();
}
Python code:
Python代码:
import numpy as np
import xtensor_python_test as xt
x = np.arange(15).reshape(3, 5)
y = [1, 2, 3, 4, 5]
z = xt.vectorized_func(x, y)
z
Outputs
输出
[[-0.540302, 1.257618, 1.89929 , 0.794764, -1.040465],
[-1.499227, 0.136731, 1.646979, 1.643002, 0.128456],
[-1.084323, -0.583843, 0.45342 , 1.073811, 0.706945]]
#3
2
As an additional way, without touching directly to the Python C API, it is possible to use pybind11 ( header-only library) :
另外,如果不直接接触Python C API,就可以使用pybind11 (header-only库):
CPP :
CPP:
#include <pybind11/embed.h> // everything needed for embedding
#include <iostream>
#include <Eigen/Dense>
#include<pybind11/eigen.h>
using Eigen::MatrixXd;
namespace py = pybind11;
int main()
{
try
{
Py_SetProgramName("PYTHON");
py::scoped_interpreter guard{};
py::module py_test = py::module::import("py_test");
MatrixXd m(2,2);
m(0,0) = 1;
m(1,0) = 2;
m(0,1) = 3;
m(1,1) = 4;
py::object result = py_test.attr("test_mat")(m);
MatrixXd res = result.cast<MatrixXd>();
std::cout << "In c++ \n" << res << std::endl;
}
catch (std::exception ex)
{
std::cout << "ERROR : " << ex.what() << std::endl;
}
return 1;
}
In py_test.py
:
在py_test。py:
def test_mat(m):
print ("Inside python m = \n ",m )
m[0,0] = 10
m[1,1] = 99
return m
Output :
输出:
Inside python m =
[[ 1. 3.]
[ 2. 4.]]
In c++
10 3
2 99
See the official documentation.
看官方文档。
ps: I'm using Eigen for the C++ Matrix.
我用特征表示c++矩阵。
#1
3
From my experience that seems to be pretty efficient. To get even more efficiency out of it try this : http://ubuntuforums.org/showthread.php?t=1266059
根据我的经验,这似乎很有效。为了提高效率,可以尝试以下方法:http://ubuntuforums.org/showthread.php?
Using weave you can inline C/C++ code in Python so that could be useful.
使用weave,你可以在Python中内联C/ c++代码,这很有用。
http://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.weave.inline.html
http://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.weave.inline.html
Here's a link on how Python can be used to interface between many different languages along with examples.
这里有一个关于如何使用Python与许多不同语言之间进行接口的链接以及示例。
http://docs.scipy.org/doc/numpy/user/c-info.python-as-glue.html
http://docs.scipy.org/doc/numpy/user/c-info.python-as-glue.html
This is a quick and easy example of how to pass numpy arrays to c++ using Cython:
这是一个使用Cython将numpy数组传递给c++的快速简单示例:
http://www.birving.com/blog/2014/05/13/passing-numpy-arrays-between-python-and/
http://www.birving.com/blog/2014/05/13/passing-numpy-arrays-between-python-and/
#2
2
Try out xtensor and the xtensor-python python bindings.
xtensor is a C++ library meant for numerical analysis with multi-dimensional array expressions.
x张量是一个c++库,用于使用多维数组表达式进行数值分析。
xtensor provides
xtensor提供
- an extensible expression system enabling numpy-style broadcasting (see the numpy to xtensor cheat sheet).
- 一个可扩展的表达式系统,支持numpy样式的广播(参见numpy到x张量备忘单)。
- an API following the idioms of the C++ standard library.
- 遵循c++标准库的习惯用法的API。
- tools to manipulate array expressions and build upon xtensor.
- 用于操作数组表达式和构建x张量的工具。
- bindings for Python, but also R and Julia.
- Python的绑定,还有R和Julia。
Example of usage
Initialize a 2-D array and compute the sum of one of its rows and a 1-D array.
初始化一个二维数组并计算其中一行和一个一维数组的和。
#include <iostream>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
xt::xarray<double> arr1
{{1.0, 2.0, 3.0},
{2.0, 5.0, 7.0},
{2.0, 5.0, 7.0}};
xt::xarray<double> arr2
{5.0, 6.0, 7.0};
xt::xarray<double> res = xt::view(arr1, 1) + arr2;
std::cout << res;
Outputs
输出
{7, 11, 14}
Creating a Numpy-style universal function in C++.
#include "pybind11/pybind11.h"
#include "xtensor-python/pyvectorize.hpp"
#include <numeric>
#include <cmath>
namespace py = pybind11;
double scalar_func(double i, double j)
{
return std::sin(i) - std::cos(j);
}
PYBIND11_PLUGIN(xtensor_python_test)
{
py::module m("xtensor_python_test", "Test module for xtensor python bindings");
m.def("vectorized_func", xt::pyvectorize(scalar_func), "");
return m.ptr();
}
Python code:
Python代码:
import numpy as np
import xtensor_python_test as xt
x = np.arange(15).reshape(3, 5)
y = [1, 2, 3, 4, 5]
z = xt.vectorized_func(x, y)
z
Outputs
输出
[[-0.540302, 1.257618, 1.89929 , 0.794764, -1.040465],
[-1.499227, 0.136731, 1.646979, 1.643002, 0.128456],
[-1.084323, -0.583843, 0.45342 , 1.073811, 0.706945]]
#3
2
As an additional way, without touching directly to the Python C API, it is possible to use pybind11 ( header-only library) :
另外,如果不直接接触Python C API,就可以使用pybind11 (header-only库):
CPP :
CPP:
#include <pybind11/embed.h> // everything needed for embedding
#include <iostream>
#include <Eigen/Dense>
#include<pybind11/eigen.h>
using Eigen::MatrixXd;
namespace py = pybind11;
int main()
{
try
{
Py_SetProgramName("PYTHON");
py::scoped_interpreter guard{};
py::module py_test = py::module::import("py_test");
MatrixXd m(2,2);
m(0,0) = 1;
m(1,0) = 2;
m(0,1) = 3;
m(1,1) = 4;
py::object result = py_test.attr("test_mat")(m);
MatrixXd res = result.cast<MatrixXd>();
std::cout << "In c++ \n" << res << std::endl;
}
catch (std::exception ex)
{
std::cout << "ERROR : " << ex.what() << std::endl;
}
return 1;
}
In py_test.py
:
在py_test。py:
def test_mat(m):
print ("Inside python m = \n ",m )
m[0,0] = 10
m[1,1] = 99
return m
Output :
输出:
Inside python m =
[[ 1. 3.]
[ 2. 4.]]
In c++
10 3
2 99
See the official documentation.
看官方文档。
ps: I'm using Eigen for the C++ Matrix.
我用特征表示c++矩阵。