【问题标题】:How to store values in the boost multi_array container?如何在 boost multi_array 容器中存储值?
【发布时间】:2021-12-15 05:34:02
【问题描述】:

我正在努力访问这些值并将它们存储在 boost multi_array 容器中。我尝试使用索引方法([] 和 .at())访问元素,但抛出 error: no matching function for call to 'boost::multi_array::data(int )',但是我可以打印数据(参见代码),但不知道如何存储它并再次访问它以进行进一步计算。数据是二维的(11214, 3),但与此同时,我只想将其展平并具有一系列值。所以我的问题是如何访问元素以及如何将它们存储在容器中?

#include <boost/multi_array.hpp>
#include <boost/timer/timer.hpp>
#include <boost/range/irange.hpp>
#include <h5xx/h5xx.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>

using array_2d_t = boost::multi_array<float, 2>;
//using array_2d_t = boost::multi_array<float, 3>;
template <typename T> 
void print_array(T const& array)
{
    for (auto const& row : array) 
        { for (auto v : row)
            printf("%10f ", v);
        printf("\n"); //prints a new line similar t0 \n
    }
}

h5xx::dataset open_dataset(std::string const& filename) {
    h5xx::file xaa(filename, h5xx::file::mode::in);
    h5xx::group g(xaa, "particles/lipids/box/positions");
    return h5xx::dataset(g, "value");
}

std::vector<float> cell_from_all_frames(h5xx::dataset& ds, size_t row, size_t col) {
    // determine dataset shape: frames, particle count, space dimension
    auto ds_shape = h5xx::dataspace(ds).extents<3>();
    std::vector<float> cells(ds_shape[0]); // number of frames

    std::vector<hsize_t> offsets{0, row, col};
    std::vector<hsize_t> counts{ds_shape[0], 1, 1};
    h5xx::slice slice(offsets, counts);

    h5xx::read_dataset(ds, cells, slice);
    return cells;
}

array_2d_t read_frame(std::string const& filename, unsigned frame_no) {
    //h5xx::file xaa("../../data/xaa.h5", h5xx::file::mode::in);
    h5xx::file xaa(filename, h5xx::file::mode::in);

    h5xx::group   g(xaa, "particles/lipids/box/positions");
    h5xx::dataset ds(g, "value");

    // determine dataset shape: frames, particle count, space dimension
    auto ds_shape = h5xx::dataspace(ds).extents<3>();
    array_2d_t arr(boost::extents[ds_shape[1]][ds_shape[2]]);

    std::vector<hsize_t> offsets{frame_no, 0, 0};
    std::vector<hsize_t> counts{1, arr.shape()[0], arr.shape()[1]};
    h5xx::slice slice(offsets, counts);

    h5xx::read_dataset(ds, arr, slice);
    return arr;
}

int main(int argc, char const* argv[])
{
    if (argc < 2) {
        std::cout << "Usage: " << argv[0] << " input.h5" << std::endl;
        return -1;
    }

    auto ds = open_dataset(argv[1]);
    std::vector<float> first_cells = cell_from_all_frames(ds, 0, 0);

    // set up multi-tau correlator for the computation of time correlation functions
    size_t nsamples = 10;            // FIXME obtain these parameters from HDF5 file. These 10 elements would be first element of first row, first element of 11214 row, first element of 11214*2 row, first element of 11214*3 row ,..., first element of 11214*10 row.
  return 0;
}

在 main() 中,我从函数 read_frame 读取数据并尝试将其传递给 nsamples。我已经尝试了一些东西,但它不起作用!

【问题讨论】:

  • 您的示例代码中有很多杂音。如果您删除了重现问题所不需要的部分,这个问题将更容易获得。一件显而易见的事情是h5xx——尽量减少使用的库的数量。由于这是一个 Boost 问题,因此代码应该只需要 Boost 和标准库。硬编码值而不是依赖命令行参数和文件。 如果我理解问题所在,为什么不只是一个支持 array_2d_t 定义的包装器、该类型的变量以及访问元素的尝试?
  • 是的。然后是int^,因为元素类型是“float”,所以没有意义。

标签: c++ boost boost-multi-array


【解决方案1】:

你可以选择。

存储它?

array_2d_t  frame = read_frame(filename, 1);

访问一个元素?

// access individual elements:
float ele = frame[0][3];

// or with index list:
std::array<int, 2> indices{0,3};
ele = frame(indices);

或者,如您所愿,提供阵列的平面视图:

boost::multi_array_ref<float, 1> sequence(frame.origin(), boost::extents[frame.num_elements()]);
fmt::print("Sum of all {} elements: {}\n",
        sequence.size(),
        std::accumulate(sequence.begin(), sequence.end(), 0.f));

事实上,你可能会就地重塑,但是你不能改变维度,所以你会得到所有单元格的 1“行”:

frame.reshape(std::array<size_t, 2> {1, frame.num_elements()});
// now the first "row" is the full sequence:
auto&& sequence = frame[0];
fmt::print("Sum of all {} elements: {}\n",
        sequence.size(),
        std::accumulate(sequence.begin(), sequence.end(), 0.f));

有大量的切片/重新索引选项,有或没有跨步,但我refer to the Boost documentation 以防止在这里不必要地复杂化。

现场演示

#include <boost/multi_array.hpp>
#include <fmt/ranges.h>
#include <h5xx/h5xx.hpp>
#include <iostream>
#include <iterator>

using array_2d_t = boost::multi_array<float, 2>;

h5xx::dataset open_dataset(std::string const& filename) {
    h5xx::file xaa(filename, h5xx::file::mode::in);
    h5xx::group g(xaa, "particles/lipids/box/positions");
    return h5xx::dataset(g, "value");
}

array_2d_t read_frame(h5xx::dataset& ds, unsigned frame_no) {
    auto ds_shape = h5xx::dataspace(ds).extents<3>();
    array_2d_t arr(boost::extents[ds_shape[1]][ds_shape[2]]);

    std::vector<hsize_t> offsets{frame_no, 0, 0};
    std::vector<hsize_t> counts{1, arr.shape()[0], arr.shape()[1]};
    h5xx::slice slice(offsets, counts);

    h5xx::read_dataset(ds, arr, slice);
    return arr;
}

std::vector<float> cell_from_all_frames(h5xx::dataset& ds, size_t row, size_t col) {
    // determine dataset shape: frames, particle count, space dimension
    auto ds_shape = h5xx::dataspace(ds).extents<3>();
    std::vector<float> cells(ds_shape[0]); // number of frames

    std::vector<hsize_t> offsets{0, row, col};
    std::vector<hsize_t> counts{ds_shape[0], 1, 1};
    h5xx::slice slice(offsets, counts);

    h5xx::read_dataset(ds, cells, slice);
    return cells;
}

int main(int argc, char const* argv[])
{
    if (argc < 2) {
        std::cout << "Usage: " << argv[0] << " input.h5" << std::endl;
        return -1;
    }

    auto ds = open_dataset(argv[1]);
    array_2d_t  frame = read_frame(ds, 1);

    // access individual elements:
    [[maybe_unused]] float ele = frame[0][2];

    // or with index list:
    std::array<int, 2> indices{0,2};
    ele = frame(indices);

    {
        boost::multi_array_ref<float, 1> sequence(frame.origin(), boost::extents[frame.num_elements()]);
        fmt::print("Sum of all {} elements: {}\n",
                sequence.size(),
                std::accumulate(sequence.begin(), sequence.end(), 0.f));
    }

    {
        // in fact yuou might reshape in-place, but then you cannot change dimensiaonality
        frame.reshape(std::array<size_t, 2> {1, frame.num_elements()});
        // now the first "row" is the full sequence:
        auto&& sequence = frame[0];
        fmt::print("Sum of all {} elements: {}\n",
                sequence.size(),
                std::accumulate(sequence.begin(), sequence.end(), 0.f));
    }

    {
        std::vector<float> first_cells = cell_from_all_frames(ds, 0, 0);

        fmt::print("Sum of all {} first cells: {}\n",
                first_cells.size(),
                std::accumulate(first_cells.begin(), first_cells.end(), 0.f));
    }
}

不久前使用您的 xaa.h5:

Sum of all 33642 elements: 737589.1
Sum of all 33642 elements: 737589.1
Sum of all 75 first cells: 6053.3496

【讨论】:

  • 谢谢!!还有一件事!假设如果我只想从所有帧(共 10 个)中提取第一个元素,是否可以使用 read_frame 函数或者必须先读取所有帧然后提取元素?因为该元素在第一帧的索引 0 处出现,然后在 11214 处,依此类推!
  • 有很多方法。 h5xx 和 multi_array 都支持跨步。我只是添加了read_frame 的最简单修改来完成您所说的:cell_from_all_frames。还进行了一些重构,以避免每次读取都重新打开数据集。
  • (顺便说一句,没有什么新东西)
  • 我不明白您是如何获得所有 75 个第一个单元格的总和:6053..!我猜你把每一帧的第一行加起来
  • 也许我把你弄糊涂了!!如果您查看问题中已编辑的代码,我需要将这些元素传递给 nsamples(现在是 10)。数据集是连续的(一行接一行),但参考我们的模拟,一帧由 11214 行组成,每一行代表一个粒子在 3 维中的位置。因此,11214 行之后的第一行属于该特定粒子。目前我不需要所有三个维度,而是每个帧中的一个值。那么,10 帧有 10 个值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
  • 1970-01-01
相关资源
最近更新 更多