使用 boost c++ 进行逐元素运算 ublas 矩阵和向量类型

发布于 2024-07-18 16:42:00 字数 437 浏览 5 评论 0原文

我想对boost矩阵和向量类型执行逐元素函数,例如取每个元素的对数,对每个元素求幂,应用特殊函数,例如gamma和digamma等(类似于matlab对这些函数的处理应用矩阵和向量。)

我想编写一个辅助函数,为每个所需的函数强制执行此函数就足够了,但这似乎很浪费。

同样,boost wiki 提供了一些代码来矢量化标准函数,但这看起来相当复杂。

已建议使用 valarray,但我想避免在数据类型之间进行转换,因为我需要 ublas 数据类型进行其他操作(矩阵乘积、稀疏矩阵等),

非常感谢任何帮助。

i'd like to perform element-wise functions on boost matrix and vector types, e.g. take the logarithm of each element, exponentiate each element, apply special functions, such as gamma and digamma, etc. (similar to matlab's treatment of these functions applied to matrices and vectors.)

i suppose writing a helper function that brute-forced this for each desired function would suffice, but this seems wasteful.

likewise, the boost wiki offers some code to vectorize standard functions, but this seems quite complex.

valarray has been suggested, but i'd like to avoid converting between data types, as i need the ublas data types for other operations (matrix products, sparse matrices, etc.)

any help is greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

丶视觉 2024-07-25 16:42:00

使用 begin1() / end1() 不起作用,因为它提供了对默认列位置 (0) 中的元素的访问:因此,您只需访问所有第一列中的元素。 最好(从某种意义上说,您获得了预期的行为)通过以下方式获得顺序访问:

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

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

享受!

The use of begin1() / end1() won't work because it provides access to the element in the default column position (0): consequently, you just access all the elements in the first column. It is better (in the sense that you get the expected behavior) to get sequential access via:

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

I suspect this may be a case where the implementation is not quite complete.

Enjoy!

裂开嘴轻声笑有多痛 2024-07-25 16:42:00

警告

以下答案不正确。 请参阅底部的编辑。 我保留了原来的答案,以便为那些指出错误的人提供上下文和信任。


我对 boost 库不是特别熟悉,因此可能有更标准的方法来执行此操作,但我认为您可以使用迭代器和 STL transform 函数模板。 uBLAS 库文档简介 表示它的类被设计为与 STL 中使用的相同迭代器行为兼容。 boost 矩阵和向量模板都有迭代器可用于访问各个元素。 向量有 begin()end(),矩阵有 begin1()end1()begin2()end2()1 变体是按列迭代器,2 变体是按行迭代器。 请参阅 VectorExpression 和 MatrixExpression了解更多信息。

使用 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 的回答

WARNING

The following answer is incorrect. See Edit at the bottom. I've left the original answer as is to give context and credit to those who pointed out the error.


I'm not particularly familiar with the boost libraries, so there may be a more standard way to do this, but I think you can do what you want with iterators and the STL transform function template. The introduction to the uBLAS library documentation says its classes are designed to be compatible with the same iterator behavior that is used in the STL. The boost matrix and vector templates all have iterators which can be used to access the individual elements. The vector has begin() and end(), and the matrix has begin1(), end1(), begin2(), and end2(). The 1 varieties are column-wise iterators and the 2 varieties are row-wise iterators. See the boost documentation on VectorExpression and MatrixExpression for a little more info.

Using the STL transform algorithm, you can apply a function to each element of an iterable sequence and assign the result to a different iterable sequence of the same length, or the same sequence. So to use this on a boost uBLAS vector you could do this:

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);

For a matrix it would be basically the same thing, you would use either the 1 or 2 family of iterators. Which one you choose to use depends on whether the memory layout of your matrix is row major or column major. A cursory scan of the uBLAS documentation leads me to believe that it could be either one, so you will need to examine the code and determine which one is being used so you choose the most efficient iteration order.

matrix<double> mat(30, 30);
.
.
.

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

The function you pass as the last argument can be a function taking a single double argument and returning a double value. It can also be a functor.

This is not exactly the same as the vectorization example you cited, but it seems like it should be pretty close to what you want.


EDIT

Looks like I should have tested my recommendation before making it. As has been pointed out by others, the '1' and '2' iterators only iterate along a single row / column of the matrix. The overview documentation in Boost is seriously misleading on this. It claims that begin1() "Returns a iterator1 pointing to the beginning of the matrix" and that end1() "Returns a iterator1 pointing to the end of the matrix". Would it have killed them to say "a column of the matrix" instead of "matrix"? I assumed that an iterator1 was a column-wise iterator that would iterate over the whole matrix. For the correct way to do this, see Lantern Rouge's answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文