使用 Eigen::Map<Eigen::MatrixXd> 作为 Eigen::MatrixXd 类型的函数参数
Using Eigen::Map<Eigen::MatrixXd> as function argument of type Eigen::MatrixXd
简而言之,问题是如何通过
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 传递给需要非常量 Eigen::MatrixXd 的函数?
附带说明:我可以将 npMatrix 更改为期望 Eigen::Map,但由于在实际项目中,功能已经存在并经过测试,我不想对它们进行调整。
为了完成问题,这里是 python 文件调用 pyMatrix()
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))
将其作为指向数据的普通指针传递,然后 Eigen::Map 将其传递到那里。或者,使用 template <typename Derived>
等,在 http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html 中找到
不过,我个人的选择是第一个,因为最好不要暴露您使用过的每个 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
将表现为 matrixXd,但我没有在所有场合都进行过测试。 它没有内存副本。但是,您可能需要在分配之前将 a
的大小调整到正确的大小。即便如此,编译器不会在您请求 resize
操作时立即分配所有内存,因此也不会有大量无用的内存分配!
Be careful! Resizing operations might reallocate the memory used by an eigen matrix! So, if you ::Map a memory but then you perform an action that resizes the matrix, it might be mapped to a different place in memory.
对于仍在努力解决将 Eigen::Map
传递给具有签名 Eigen::Matrix
的函数或反之亦然的问题并发现 Eigen::Matrix
到 Eigen::Map
隐式转换的任何人@Aperture Laboratories 建议的技巧不起作用(在我的例子中,这给出了与尝试释放已经释放的内存相关的运行时错误,[当 运行 和 valgrind
] 时不匹配的删除/无效删除错误],
我建议使用 Eigen::Ref
class 作为函数签名,正如 @ggael 在此处给出的答案中所建议的那样:
Passing Eigen::Map<ArrayXd> to a function expecting ArrayXd&
并在文档中写道:
http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html#TopicUsingRefClass
标题下:
How to write generic, but non-templated function?
比如题中指定的函数,将签名改成
void npMatrix(const Eigen::Ref<const Eigen::MatrixXd> & data, Eigen::Ref< Eigen::MatrixXd> result);
意味着将 Eigen::Map<Eigen::MatrixXd>
或 Eigen::MatrixXd
objects 传递给函数将无缝工作(请参阅@ggael 对 Correct usage of the Eigen::Ref<> class 的不同使用方式 Eigen::Ref 在函数签名中)。
我感谢 OP 说他不想更改函数签名,但就交替使用 Eigen::Map
和 Eigen::Matrix
而言,我发现这是最简单和最可靠的方法。
简而言之,问题是如何通过
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 传递给需要非常量 Eigen::MatrixXd 的函数?
附带说明:我可以将 npMatrix 更改为期望 Eigen::Map,但由于在实际项目中,功能已经存在并经过测试,我不想对它们进行调整。
为了完成问题,这里是 python 文件调用 pyMatrix()
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))
将其作为指向数据的普通指针传递,然后 Eigen::Map 将其传递到那里。或者,使用 template <typename Derived>
等,在 http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html 中找到
不过,我个人的选择是第一个,因为最好不要暴露您使用过的每个 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
将表现为 matrixXd,但我没有在所有场合都进行过测试。 它没有内存副本。但是,您可能需要在分配之前将 a
的大小调整到正确的大小。即便如此,编译器不会在您请求 resize
操作时立即分配所有内存,因此也不会有大量无用的内存分配!
Be careful! Resizing operations might reallocate the memory used by an eigen matrix! So, if you ::Map a memory but then you perform an action that resizes the matrix, it might be mapped to a different place in memory.
对于仍在努力解决将 Eigen::Map
传递给具有签名 Eigen::Matrix
的函数或反之亦然的问题并发现 Eigen::Matrix
到 Eigen::Map
隐式转换的任何人@Aperture Laboratories 建议的技巧不起作用(在我的例子中,这给出了与尝试释放已经释放的内存相关的运行时错误,[当 运行 和 valgrind
] 时不匹配的删除/无效删除错误],
我建议使用 Eigen::Ref
class 作为函数签名,正如 @ggael 在此处给出的答案中所建议的那样:
Passing Eigen::Map<ArrayXd> to a function expecting ArrayXd&
并在文档中写道: http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html#TopicUsingRefClass 标题下:
How to write generic, but non-templated function?
比如题中指定的函数,将签名改成
void npMatrix(const Eigen::Ref<const Eigen::MatrixXd> & data, Eigen::Ref< Eigen::MatrixXd> result);
意味着将 Eigen::Map<Eigen::MatrixXd>
或 Eigen::MatrixXd
objects 传递给函数将无缝工作(请参阅@ggael 对 Correct usage of the Eigen::Ref<> class 的不同使用方式 Eigen::Ref 在函数签名中)。
我感谢 OP 说他不想更改函数签名,但就交替使用 Eigen::Map
和 Eigen::Matrix
而言,我发现这是最简单和最可靠的方法。