gpt4 book ai didi

python - Cython:从引用中获取时,Numpy 数组缺少两个第一个元素

转载 作者:行者123 更新时间:2023-11-30 05:05:36 27 4
gpt4 key购买 nike

这是最奇怪的错误,我正在尝试从返回一个 vector 的 reference 的 c++ 函数中获取一个 numpy 数组,整个数组使用 Cython 进行包装。

我可以让它工作返回一个 vector<int>而不是 vector<int>& ,但我想了解在使用引用时发生了什么。这是重现错误的一种方法:

cmy类.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <vector>
#include <string>

namespace vec {
class IntVector {
private:
std::vector<int> vec;
public:
IntVector();
virtual ~IntVector();
std::vector<int>& get_vec(); #return a reference !
};
}

#endif

cmyclass.cc

#include "cmyclass.h"
#include <iostream>

using namespace vec;

IntVector::IntVector(){
for(int i=10; i<20; ++i){
vec.push_back(i);
}
}

IntVector::~IntVector(){
}

std::vector<int>& IntVector::get_vec(){
std::vector<int> buff;
buff.reserve(vec.size());
for(int i=0; i<vec.size(); ++i){
buff.push_back(vec[i]);
}
return buff;
}

我的类.pyx

import numpy as np
cimport numpy as np

from libcpp.vector cimport vector

cdef extern from "cmyclass.h" namespace "vec":

cdef cppclass IntVector:
IntVector() except +
vector[int]& get_vec()

cdef class IntVec:

cdef IntVector* _thisptr

def __cinit__(self):
self._thisptr = new IntVector()

def __dealloc__(self):
del self._thisptr

def __init__(self):
pass

def get_vec(self):
cdef vector[int] buff;
buff = self._thisptr.get_vec();
return np.asarray(buff)

设置.py

from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension

sourcefiles = ['myclass.pyx', 'cmyclass.cc']
compile_opts = ['-std=c++11']
ext=[Extension('*',
sourcefiles,
extra_compile_args=compile_opts,
language='c++')]

setup(
ext_modules=cythonize(ext)
)

您可以使用 python setup.py build_ext --inplace 进行编译

用例

>>> import myclass
>>> vec = myclass.IntVec()
>>> vec.get_vec()
array([ 0, 0, 12, 13, 14, 15, 16, 17, 18, 19])

您可以看到前两个值设置为零(它们应该是 10 和 11)!如果我们返回一个 vector<int> 代码就可以正常工作而不是对 vector<int> 的引用.

知道为什么会这样吗?

编辑:最终解决方案

将 vector 作为参数传递。

cmy类.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <vector>
#include <string>

namespace vec {
class IntVector {
private:
std::vector<int> vec;
public:
IntVector();
virtual ~IntVector();
void get_vec(std::vector<int>&);
};
}

#endif

cmyclass.cc

#include "cmyclass.h"
#include <iostream>

using namespace vec;

IntVector::IntVector(){
for(int i=10; i<20; ++i){
vec.push_back(i);
}
}

IntVector::~IntVector(){
}

void IntVector::get_vec(std::vector<int>& buff){
buff.reserve(vec.size());
for(int i=0; i<vec.size(); ++i){
buff.push_back(vec[i]);
}
return buff;
}

我的类.pyx

import numpy as np
cimport numpy as np

from libcpp.vector cimport vector

cdef extern from "cmyclass.h" namespace "vec":

cdef cppclass IntVector:
IntVector() except +
void get_vec(vector[int]&)

cdef class IntVec:

cdef IntVector* _thisptr

def __cinit__(self):
self._thisptr = new IntVector()

def __dealloc__(self):
del self._thisptr

def __init__(self):
pass

def get_vec(self):
cdef vector[int] buff;
self._thisptr.get_vec(buff);
return np.asarray(buff)

设置.py

from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension

sourcefiles = ['myclass.pyx', 'cmyclass.cc']
compile_opts = ['-std=c++11']
ext=[Extension('*',
sourcefiles,
extra_compile_args=compile_opts,
language='c++')]

setup(
ext_modules=cythonize(ext)
)

最佳答案

您的主要目标似乎是让 numpy 使用在 C++ vector 中分配的内存。为此,您最好为 IntVec 实现缓冲协议(protocol)。 Cython 文档给出了 Matrix class based around a vector 的示例你可以简化(因为你的情况只是一维)。您真正需要做的就是创建函数 __getbuffer____releasebuffer__(后者可以为空,如示例文档中所示)。 (我不认为在此处复制/粘贴文档有很大的值(value))

这样做将允许您将 IntVec 直接传递给 np.asarray。生成的 numpy 数组将使用 IntVec 进行存储,并保留对 IntVec 的引用以确保它不会被删除。您还可以将 Cython 内存 View 与此类一起使用(如果有帮助的话)。

关于python - Cython:从引用中获取时,Numpy 数组缺少两个第一个元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48263108/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com