简而言之,问题是如何传递
Eigen::Map<Eigen::MatrixXd>
对象需要一个
的函数Eigen::MatrixXd
对象。
更长的故事:
我有这个C ++函数声明
void npMatrix(const Eigen::MatrixXd &data, Eigen::MatrixXd &result);
与此实施一起
void npMatrix(const Eigen::MatrixXd &data, Eigen::MatrixXd &result)
{
//Just do s.th. with arguments
std::cout << data << std::endl;
result(1,1) = -5;
std::cout << result << std::endl;
}
我想使用numpy.array作为参数从python中调用此函数。为此,我使用了用c ++编写的包装函数
void pyMatrix(const double* p_data, const int dimData[],
double* p_result, const int dimResult[]);
它接受一个指向数据的指针,数据数组的大小,指向结果的指针以及结果数组的大小。数据指针指向内存的const补丁,因为在为结果保留的内存补丁是可写的时,不会更改数据。功能的实现
void pyMatrix(const double *p_data, const int dimData[], double *p_result, const int dimResult[])
{
Eigen::Map<const Eigen::MatrixXd> dataMap(p_data, dimData[0], dimData[1]);
Eigen::Map<Eigen::MatrixXd> resultMap(p_result, dimResult[0], dimResult[1]);
resultMap(0,0) = 100;
npMatrix(dataMap, resultMap);
}
分别为数据和结果定义Eigen :: Map。 Eigen :: Map允许将原始内存作为一种Eigen :: Matrix访问。 dataMap的类型为
<const Eigen::MatrixXd>
因为相关的存储器是只读的;相反,resultMap的类型为
<Eigen::MatrixXd>
因为它必须我们可写。这条线
resultMap(0,0) = 100;
表明,resultMap是可写的。在将dataMap传递给期望const Eigen :: MatrixXd的npMatrix()时,我无法找到以相同方式传递resultMap的方法。我确信,问题来自于这样一个事实:npMatrix的第一个参数是const,第二个参数不是。我找到的一个可能的解决方案是定义
Eigen::MatrixXd resultMatrix = resultMap;
并将此resutlMatrix传递给npMatrix()。但是,我想,这会创建一个副本,从而杀死Eigen :: Map的漂亮内存映射。所以我的问题是。
有没有办法将Eigen:Map传递给需要非const Eigen :: MatrixXd的函数?
作为旁注:我可以改变npMatrix以期待Eigen :: Map,但是因为在实际项目中,函数已经存在并经过测试,我宁愿不与它们发脾气。
要完成这个问题,这里是调用pyMatrix()
的python文件import ctypes as ct
import numpy as np
import matplotlib.pyplot as plt
# Load libfit and define input types
ct.cdll.LoadLibrary("/home/wmader/Methods/fdmb-refactor/build/pyinterface/libpyfit.so")
libfit = ct.CDLL("libpyfit.so")
libfit.pyMatrix.argtypes = [np.ctypeslib.ndpointer(dtype=np.float64, ndim=2),
np.ctypeslib.ndpointer(dtype=np.int32, ndim=1),
np.ctypeslib.ndpointer(dtype=np.float64, ndim=2, flags='WRITEABLE'),
np.ctypeslib.ndpointer(dtype=np.int32, ndim=1)
]
data = np.array(np.random.randn(10, 2), dtype=np.float64, order='F')
result = np.zeros_like(data, dtype=np.float64, order='F')
libfit.pyMatrix(data, np.array(data.shape, dtype=np.int32),
result, np.array(result.shape, dtype=np.int32))
答案 0 :(得分:2)
将它作为普通指针传递给数据,然后将Eigen :: Map映射到那里。或者,使用http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html中的template <typename Derived>
之类的内容
我个人的选择是第一个,因为最好让代码不暴露你使用的每个API的所有顽固性。此外,您不会失去与eigen的兼容性,也不会失去您(或其他任何人)以后可能使用的任何其他类型的库。
我发现了另一个技巧,可以在很多场合使用:
Eigen::MatrixXd a;
//lets assume a data pointer like double* DATA that we want to map
//Now we do
new (&a) Eigen::Map<Eigen::Matrix<Double,Eigen::Dynamic,Eigen::Dynamic>> (DATA,DATA rows,DATA cols);
这将按照你的要求行事,而不会浪费记忆力。我认为这是一个很酷的技巧,a
将表现为矩阵Xd,但我没有经常在每个场合进行测试。 没有内存副本。但是,在分配之前,您可能需要将a
调整为正确的大小。即使这样,编译器也不会在您请求resize
操作时立即分配所有内存,因此也不会有大的无用内存分配!
小心!调整操作大小可能重新分配特征矩阵使用的内存!因此,如果你::映射内存但是你执行一个调整矩阵大小的动作,它可能会映射到不同的放在记忆中。
答案 1 :(得分:0)
对于仍在将Eigen::Map
传递给具有签名Eigen::Matrix
或相反的函数的问题的人,发现Eigen::Matrix
到Eigen::Map
隐式转换技巧@Aperture Laboratories建议不起作用(在我的情况下,这给出了与尝试释放已释放的内存有关的运行时错误,[使用valgrind
运行时[不匹配的删除/无效的删除错误]),
我建议使用Eigen::Ref
类进行函数签名,如@ggael在此处给出的答案所建议:
Passing Eigen::Map<ArrayXd> to a function expecting ArrayXd&
并写在文档中: http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html#TopicUsingRefClass 在标题下:
如何编写通用但非模板化的函数?
例如,对于问题中指定的功能,将签名更改为
void npMatrix(const Eigen::Ref<const Eigen::MatrixXd> & data, Eigen::Ref< Eigen::MatrixXd> result);
意味着将Eigen::Map<Eigen::MatrixXd>
或Eigen::MatrixXd
对象传递给函数将无缝工作(有关在函数签名中使用Eigen :: Ref的不同方法,请参见@ggael对Correct usage of the Eigen::Ref<> class的回答)。 / p>
我很高兴OP表示他不想更改功能签名,但是就可以交替使用Eigen::Map
和Eigen::Matrix
而言,我发现这是最简单,最可靠的方法。