使用Boost C++ uBLAS矩阵和向量类型进行逐元素操作

7
我希望对Boost矩阵和向量类型执行逐元素函数,例如取每个元素的对数、指数、应用特殊函数(如伽马函数和digamma函数)等(类似于Matlab对矩阵和向量应用这些函数的处理方式)。
我想写一个辅助函数来强制执行每个所需函数,但这似乎很浪费。
同样,Boost Wiki提供了一些代码来向量化标准函数,但这似乎相当复杂。
已经建议使用valarray,但我想避免在数据类型之间转换,因为我需要ublas数据类型进行其他操作(矩阵乘积、稀疏矩阵等)。
非常感谢任何帮助。
2个回答

10

使用begin1() / end1()无法正常工作,因为它只提供对位于默认列位置(0)的元素的访问:因此,您只能访问第一列中的所有元素。更好的方法(以获得预期的行为)是通过以下方式获得顺序访问:

std::transform(mat.data().begin(), mat.data().end(),
               mat.data().begin(), boost::math::tgamma) ;

我怀疑这可能是一种实现不够完整的情况。

享受!


3

警告

以下答案是不正确的。请查看底部的编辑。我保留原始答案以便了解错误的背景和贡献者。



我不是特别熟悉boost库,因此可能有更标准的方法来完成此操作,但我认为您可以使用迭代器和STL transform函数模板来实现所需功能。uBLAS库文档介绍中说其类被设计为与在STL中使用的相同迭代器行为兼容。boost矩阵和向量模板都 具有迭代器,可用于访问单个元素。向量具有begin()end(),矩阵具有begin1()end1()begin2()end2()1种是列迭代器,2种是行迭代器。有关更多信息,请参见boost VectorExpressionMatrixExpression文档。

使用STL transform算法,您可以将函数应用于可迭代序列的每个元素,并将结果分配给相同长度的不同可迭代序列或相同序列。因此,要在boost uBLAS向量上使用它,您可以这样做:

using namespace boost::numeric::ublas;

// Create a 30 element vector of doubles
vector<double> vec(30);

// Assign 8.0 to each element.
std::fill(vec.begin(), vec.end(), 8.0);

// Perform the "Gamma" function on each element and assign the result back
// to the original element in the vector.
std::transform(vec.begin(), vec.end(), vec.begin(), boost::math::tgamma);

对于矩阵而言,基本上是一样的,你需要使用12系列的迭代器。你选择使用哪个取决于你的矩阵的内存布局是行优先还是列优先。对uBLAS文档的初步扫描让我相信它可能是任意一个,因此你需要检查代码并确定正在使用哪个,以便选择最有效的迭代顺序。
matrix<double> mat(30, 30);
.
.
.

std::transform(mat.begin1(), mat.end1(), mat.begin1(), boost::math::tgamma);

你传递的最后一个参数可以是一个接受单个双精度参数并返回双精度值的函数。它也可以是一个函数对象
这不完全与你引用的向量化示例相同,但它似乎非常接近你想要的。

编辑

看起来在推荐之前我应该先测试一下。正如其他人所指出的那样,“1”和“2”迭代器只沿着矩阵的单行/单列进行迭代。Boost中的概述文档严重误导了用户。它声称begin1()“返回指向矩阵开头的iterator1”,而end1()“返回指向矩阵结尾的iterator1”。他们为什么不能说“矩阵的一列”而不是“矩阵”呢?我假设iterator1是一个按列迭代整个矩阵的迭代器。正确的方法,请参见Lantern Rouge的答案


begin1end1只遍历第一列,而不是整个矩阵。begin2end2对于第一行也是如此。请参考Lantern Rouge的答案,了解可能的解决方案。 - betabandido
好吧,这教会我一个教训,不要在自己都没有测试的情况下推荐一种方法!感谢你的发现,betabandido! - A. Levy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接