是否可以从数据文件中读取 add/subtract 数组?

Is it possible to add/subtract arrays read from a data file?

我想对从文件中读取的数据进行一些数学运算,例如addition/subtraction、均值等。数据是二维的,看起来像这样: 所以现在例如我想从第 3 行或第 4 行中减去第一行,在 python 中使用索引非常简单,但我不知道如何在 C++ 中执行。 这是我正在使用的代码。

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

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
    }
    std::cout << "\n End of file" << std::endl;
}

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]};
    //std::vector<hsize_t> strid{1, arr.shape()[0], arr.shape()[1]};
    // slice ohne stride:
    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;
    }
    std::string filename(argv[1]);
    print_array(read_frame(filename, 1));
    return 0; 
}

read_frame 函数采用参数文件名和 frame_no。该文件被分成多个帧,每个帧包含 (11214) 行,但了解这里并不重要。所以 read_frame returns 每一帧的二维数据。在 main() 函数中,我可以打印每一帧的数据,但现在假设我想从第二帧中减去第一帧,我该怎么做? 有谁知道ho

因此,文本形式的数据看起来如何是非常无关紧要的。相关的是,您必须对相同维度的数组进行元素级算术运算。

您可以使用适当的 Matrix 库(例如 Boost UBlas、Eigen、Armadillo 等)。

或者您可以为 Boost MultiArray 编写它们:How to execute mathematical operations between two boost::multi_arrays (C++)?

这是一个示例:

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

namespace ArrayOperators {
    template <typename Op> struct ArrayOp {
        Op op;
        constexpr explicit ArrayOp(Op op) : op(op) {}

        template <typename T, typename Scalar, size_t Dim> 
        constexpr inline auto operator()(
            boost::multi_array<T, Dim> const& l,
            Scalar const& v) const
        {
            std::array<int, Dim> shape;
            std::copy_n(l.shape(), Dim, shape.data());

            using R = boost::multi_array<decltype(op(T{}, v)), Dim>;
            R result(shape);
            
            std::transform(
               l.data(), l.data()+l.num_elements(),
               result.data(),
               [&op=op,v](auto const& el) { return op(el, v); });

            return result;
        }

        template <typename T, typename U, size_t Dim> 
        constexpr inline auto operator()(
            boost::multi_array<T, Dim> const& l,
            boost::multi_array<U, Dim> const& r) const
        {
            std::array<int, Dim> shape;
            std::copy_n(l.shape(), Dim, shape.data());
            assert(std::equal(shape.begin(), shape.end(), r.shape()));

            using R = boost::multi_array<decltype(op(T{}, U{})), Dim>;
            R result(shape);
            
            std::transform(
               l.data(), l.data()+l.num_elements(),
               r.data(), result.data(),
               [&op=op](auto const& v1, auto const& v2) { return op(v1, v2); });

            return result;
        }
    };

    template <typename L, typename R>
    static constexpr inline auto operator+(L const& l, R const& r) {
        return ArrayOp {std::plus<>{}} (l, r); }

    template <typename L, typename R>
    static constexpr inline auto operator-(L const& l, R const& r) {
        return ArrayOp {std::minus<>{}} (l, r); }

    template <typename L, typename R>
    static constexpr inline auto operator/(L const& l, R const& r) {
        return ArrayOp {std::divides<>{}} (l, r); }

    template <typename L, typename R>
    static constexpr inline auto operator*(L const& l, R const& r) {
        return ArrayOp {std::multiplies<>{}} (l, r); }
}

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

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
    }
    std::cout << "\n End of file" << std::endl;
}

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]};
    //std::vector<hsize_t> strid{1, arr.shape()[0], arr.shape()[1]};
    // slice ohne stride:
    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;
    }
    std::string filename(argv[1]);

    using namespace ArrayOperators;
    auto avg4 = //
        (read_frame(filename, 0) + read_frame(filename, 1) +
         read_frame(filename, 2) + read_frame(filename, 3)) /
        4.0;

    print_array(read_frame(filename, 4) - avg4);
    return 0; 
}

打印:

 -0.610001   0.410004  -0.150000 
  0.372501  -0.395000  -0.037500 
 -0.062500   0.027500  -0.122500 
  0.307503   0.184998  -0.212500 
  0.150000   0.009995   0.362500 
 -0.497500   0.197500   0.217500 
  0.405003  -0.185000   0.115000 
 -0.072500   0.247498   0.237500 
 -0.480000   0.034998   0.107500 
 -0.130000  -0.162499  -0.087500 
(...)
 -0.340000  -0.280001  -0.040000 
 -0.572502  -0.747505  -0.005000 
  0.392494   0.012500   0.045000 
  0.500000  -0.040000  -0.162500 
  0.355000   0.700000   0.065000 

 End of file