关于 c :遍历任何 boost::multi_array 的除第 d 维之外的所有维度
Iterate over all but d-th dimension of any boost::multi_array
很多时候,人们想要沿着
我能想到的最好的方法是实现一个
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
#include"boost/multi_array.hpp"
#include <ostream> using namespace boost; typedef multi_array_types::index index_t; template <template <typename, std::size_t, typename...> class Array, template <template <typename, std::size_t, typename...> class Array, typename T> template <template <typename, std::size_t, typename...> class Array, // collapse dimensions [0,d) and (d,Ndims) // reshape to collapsed dimensions // call f for each slice [i,:,k] template <template <typename, std::size_t, typename...> class Array, |
这是测试程序
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include"f.hpp"
int main() { int i = 0; std::cout <<"work on boost::multi_array_ref" << std::endl; std::cout <<"work on boost::multi_array" << std::endl; std::cout <<"work on boost::detail::multi_array:sub_array" << std::endl; std::cout <<"work on boost::detail::multi_array:sub_array" << std::endl; //f(A[1]); // fails: rvalue A[1] is boost::multi_array_ref<double, 3ul>::reference |
显然,这种方法存在问题,即当将切片传递给
似乎更好(更像 C)的方法是从 boost 类型提供的迭代器中构造一个聚合迭代器,因为这会自动处理沿给定维度的非统一步幅。
注意:
SO 上已经有类似的问题,但没有一个让我很满意。我对
更新:
这相当于我在 Python 中想要的:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
def idx_iterator(s, d, idx):
if len(s) == 0: yield idx else: ii = (slice(None),) if d == 0 else xrange(s[0]) for i in ii: for new_idx in idx_iterator(s[1:], d - 1, idx + [i]): yield new_idx def iterator(A, d=0): def f(A): import numpy as np print"Work on flattened array" print"Work on array" print"Work on contiguous slice" print"Work on discontiguous slice" |
使用
相关讨论
- 你看到 MultiArray Concept 下的解释了吗?特别是。 " 例如,如果 indices 是 index_gen 类型的对象,则以下示例:
indices[index_range(0,5)][2][index_range(0,4)] ; 具有退化的第二维。从上述规范生成的视图将具有 2 个维度,形状为 5 x 4" - 我注意到。请注意我 5 分钟前是如何删除该评论的 🙂
-
@sehe:是的,我读过这个。假设我得到这样一个
5 x 4 视图对象。然后我需要首先迭代5 维度,沿4 维度的所有切片应用f() ,反之亦然。在这种情况下,我的方法失败了,因为内存不是连续的。这就是为什么我认为我必须以某种方式利用视图对象提供的迭代器。 - 您可以使用迭代器迭代视图。如果内存实际上是连续的很重要,那么无论如何您都将不得不复制数据
-
@sehe:如果工作维度为
d ,则将这些迭代器用于 ND 数组会变得复杂。如果内存是连续的,我的方法已经奏效了。如果任何/部分/所有维度不连续,我也希望它能够工作。 - 你说的很明显。你想要更复杂的东西,所以你不能使用简单的方法。您宁愿编写复杂的迭代,还是使用已实现的库?
-
我不清楚如何使用"图书馆"。我怀疑
index_gen 是相关的,但我还没有弄清楚如何使用它来实现我想要的。
好的,在花了大量时间研究
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
#include"boost/multi_array.hpp"
template <template <typename, std::size_t, typename...> class Array, array_type& A; SliceIterator(array_type& A, long d) : A(A), shape(A.shape()), d(d) { SliceIterator& operator++() { slice_type operator*() { // fakes for iterator protocol (actual implementations would be expensive) SliceIterator begin() {return *this;} template <template <typename, std::size_t, typename...> class Array, // overload for rvalue references |
可以作为
|
1
2 3 |
for (auto S : make_slice_iterator(A, d)) {
f(S); } |
适用于我的问题中的所有示例。
我必须说,
总之,我发现
的"放手"
-
我在网络上的任何地方都找不到
boost::multi_array 的任何严重用例 - 发展似乎在 2002 年基本停止
- StackOverflow 上的这个(和类似的)问题几乎没有引起任何兴趣 😉