使用 Eigen::Map<Eigen::MatrixXd> 作为 Eigen::MatrixXd 类型的函数参数

Ree*_*ood 10 c++ numpy eigen3

简而言之,问题是如何通过

Eigen::Map<Eigen::MatrixXd>
Run Code Online (Sandbox Code Playgroud)

一个函数的对象,它期望一个

Eigen::MatrixXd
Run Code Online (Sandbox Code Playgroud)

目的。


更长的故事:

我有这个 C++ 函数声明

void npMatrix(const Eigen::MatrixXd &data, Eigen::MatrixXd &result);
Run Code Online (Sandbox Code Playgroud)

连同这个实现

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;
}
Run Code Online (Sandbox Code Playgroud)

我想使用 numpy.array 作为参数从 python 调用这个函数。为此,我使用了一个用 c++ 编写的包装函数

void pyMatrix(const double* p_data, const int dimData[],
                              double* p_result, const int dimResult[]);
Run Code Online (Sandbox Code Playgroud)

它需要一个指向数据的指针、数据数组的大小、一个指向结果的指针以及结果数组的大小。数据指针指向内存的常量补丁,因为当为结果保留的内存补丁可写时,数据不会被更改。函数的实现

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);
}
Run Code Online (Sandbox Code Playgroud)

分别为数据和结果定义了一个 Eigen::Map。Eigen::Map 允许访问原始内存作为一种 Eigen::Matrix。dataMap 是类型

<const Eigen::MatrixXd>
Run Code Online (Sandbox Code Playgroud)

因为关联的内存是只读的;相比之下,resultMap 是类型

<Eigen::MatrixXd>
Run Code Online (Sandbox Code Playgroud)

因为它必须是可写的。线

resultMap(0,0) = 100;
Run Code Online (Sandbox Code Playgroud)

显示, resultMap 实际上是可写的。在将 dataMap 传递给需要 const Eigen::MatrixXd 的 npMatrix() 时,我找不到以相同方式传递 resultMap 的方法。我敢肯定,问题来自这样一个事实,即 npMatrix 的第一个参数是 const,而第二个不是。我发现的一个可能的解决方案是定义

Eigen::MatrixXd resultMatrix = resultMap;
Run Code Online (Sandbox Code Playgroud)

并将这个 resutlMatrix 传递给 npMatrix()。但是,我想,这会创建一个副本,因此会破坏 Eigen::Map 的良好内存映射。所以我的问题是。

有没有办法将 Eigen:Map 传递给需要非常量 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))
Run Code Online (Sandbox Code Playgroud)

小智 3

将其作为指向数据的普通指针传递,然后 Eigen::Map 将其映射到那里。或者,使用http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.htmltemplate <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);
Run Code Online (Sandbox Code Playgroud)

这将执行您所要求的操作,而不会浪费内存。我认为这是一个很酷的技巧,并且a将表现为矩阵Xd,但我还没有测试每种情况。它没有内存副本。但是,您可能需要a在分配之前将其调整为正确的大小。即使如此,编译器也不会在您请求操作时立即分配所有内存resize,因此也不会有大量无用的内存分配!

当心!调整大小操作可能会重新分配特征矩阵使用的内存!因此,如果您 ::Map 内存,但随后执行调整矩阵大小的操作,则它可能会映射到内存中的不同位置。