我正在try 为一个在C++中实现的函数构建python包装器,该函数接受2d vector并返回2d vector.我正在try 调整this的代码以满足我的需要.

Input matrix shape: (n*2)  
Output matrix shape: (n*2)

I think there is an issue with code.i file but not really sure what exactly is the issue.
If there are any other libraries which can achieve this that works as well. I just need to call the c++ function from python.
Here is complete reproducible example: Google Colab
My files:
code.cpp:

#include <vector>
#include "geomutils.h"
#include "code.h"

using namespace std;

vector< vector<double> > computeConvexHull(vector< vector<double> > i_matrix){
  Polygon custompts, customhull;
  for (int r = 0; r < i_matrix.size(); r++){
    custompts.push_back(Point(i_matrix[r][0], i_matrix[r][1]));
  }
  computeConvexHull(custompts, customhull);
  vector< vector<double> > res;
  for(int i = 0;i < customhull.size();i ++) {
        res[i][0] = customhull[i].x;
        res[i][1] = customhull[i].y;
  }
  return res;
}

geomutils.cpp:

#include "geomutils.h"

#include <iostream>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>

BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)


void computeConvexHull(Polygon &pts, Polygon &chull) {
    chull.clear();
    if(pts.size() == 1) {
        chull.push_back(pts[0]);
        chull.push_back(pts[0]);
        return;
    } else if(pts.size() == 2) {
        chull.push_back(pts[0]);
        chull.push_back(pts[1]);
        chull.push_back(pts[0]);
        return;
    }

    typedef boost::tuple<double, double> point;
    typedef boost::geometry::model::multi_point<point> mpoints;
    typedef boost::geometry::model::polygon<point> polygon;

    mpoints mpts;

    for(int i = 0;i < pts.size();i ++) {
        boost::geometry::append(mpts,point(pts[i].x,pts[i].y));
    }
    polygon hull;

    // Polygon is closed
    boost::geometry::convex_hull(mpts, hull);
    for(auto pt : hull.outer()) {
        chull.push_back(Point(pt.get<0>(), pt.get<1>()));
    }
}

geomutils.h:

#ifndef GEOMUTILS_H
#define GEOMUTILS_H

#include <vector>

struct Point {
    double x,y;

    Point(){}
    Point(double x, double y):x(x),y(y){}
};

typedef std::vector<Point> Polygon;

void computeConvexHull(Polygon &pts, Polygon &chull);

#endif // GEOMUTILS_H

code.i:

%module code
%{
#include "code.h"
#include "geomutils.h"
%}
%include "std_vector.i"
namespace std {

  /* On a side note, the names VecDouble and VecVecdouble can be changed, but the order of first the inner vector matters! */
  %template(VecDouble) vector< vector<double> >;
  %template(VecVecdouble) vector< vector<double> >;
}

%include "code.h"

代码使用一个名为boost的外部库.我try 生成包装器的方式如下:

g++ -c -fPIC code.cpp geomutils.cpp

swig -c++ -python code.i

g++ -c -fPIC code_wrap.cxx  -I/usr/include/python3.7 -I/usr/lib/python3.7

The first two commands run without giving any error but the third code gives me an error.
The Error is too long to post in the question. But the error can be reproduced using code link. Update 1:
After trying the changes suggested in answer 1 and running the following commands the code compiles but nothing happens when I try to run the c++ code from python. The code is updated in the same link. "test.py" is a simple python code that calls the computeConvexHull function.
Commands:

g++ -c -fPIC code.cpp geomutils.cpp
swig -c++ -python code.i
g++ -c -fPIC code_wrap.cxx  -I/usr/include/python3.7 -I/usr/lib/python3.7
g++ -shared -Wl,-soname,_code.so -o _code.so code.o geomutils.o code_wrap.o
python test.py

推荐答案

首先,我只想说,这是迄今为止我所看到的写作最精良的问题之一.谢谢你.

问题是,您正在为同一类型twice定义一个模板,而根据SWIG documentation:

不应使用%template指令在同一范围内多次包装同一模板实例化.这将产生一个错误.例如:

%template(intList) List<int>;
%template(Listint) List<int>;    // Error.   Template already wrapped.

导致此错误的原因是模板扩展导致两个同名的相同类.这会产生符号表冲突.此外,为了减少代码inflating 的可能性,只包装一次特定的实例化可能更有效.

因为类型系统知道如何处理typedef,所以通常不需要为等价的typename实例化模板的不同版本.例如,考虑以下代码:

%template(intList) vector<int>;
typedef int Integer;
...
void foo(vector<Integer> *x);

在这种情况下,vector与vector的类型完全相同.Vector的任何使用都会映射回之前创建的Vector的实例化.因此,没有必要为Integer类型实例化一个新类(这样做是多余的,只会导致代码inflating ).

正如您所怀疑的,这个问题出现在code.i中,您将VecDoubleVecVecDouble模板化为vector<vector<double>>.

根据this answer,我猜你想做的是:

  %template(VecDouble) vector<double>;
  %template(VecVecdouble) vector< vector<double> >;

它确实可以编译.

Python相关问答推荐

当测试字符串100%包含查询字符串时,为什么t fuzzywuzzy s Process.extractBests不给出100%分数?

如何使用PyTest根据self 模拟具有副作用的属性

在使用Guouti包的Python中运行MPP模型时内存不足

具有症状的分段函数:如何仅针对某些输入值定义函数?

如何通过多2多字段过滤查询集

分组数据并删除重复数据

Pandas 填充条件是另一列

如何在msgraph.GraphServiceClient上进行身份验证?

根据条件将新值添加到下面的行或下面新创建的行中

DataFrame groupby函数从列返回数组而不是值

点到面的Y距离

可变参数数量的重载类型(args或kwargs)

如何在Python中并行化以下搜索?

Pandas—合并数据帧,在公共列上保留非空值,在另一列上保留平均值

多指标不同顺序串联大Pandas 模型

计算分布的标准差

实现神经网络代码时的TypeError

旋转多边形而不改变内部空间关系

具有相同图例 colored颜色 和标签的堆叠子图

基于Scipy插值法的三次样条系数