【问题标题】:Variable dimension dynamic array in C++C ++中的可变维度动态数组
【发布时间】:2017-11-19 01:31:04
【问题描述】:

我想在 C++ 中实现一个类似 STL 的张量模板,它需要重载 operator[] 来访问它的元素,它可能看起来像这样:

Tensor<double,2> tensor2
{
    {1,2,3},
    {4,5,6}
};
std::cout<< tensor2[1][2]<<'\n';

对于低维度,使用类似的东西可能很容易

std::vector<std::vector<int>>

但这对于更高的维度并不容易使用。 我还想在一个张量中实现张量之间的乘积和维度之间的收缩。

【问题讨论】:

  • 对不起,你能解释一下嵌套向量有什么问题吗?
  • 如果嵌套太难以辨认/不灵活,请实现多维向量类型。
  • 没有这样的东西,但是您可以使用具有复杂索引的普通一维数组,例如std::size_t plain_index(std::size_t i, std::size_t j, std::size_t k, ...)
  • 没有简单的解决方案。可以参考github上Tensorflow源码中shape类和IndexUtil::MultidimensionalIndexToLinearIndex函数的实现。
  • 我会为此建议一个库。 BoostEigenTensorflow。不要重新发明轮子,除非有一些功能或性能目标无法实现。

标签: c++ multidimensional-array tensor


【解决方案1】:

我用一些非常基本的操作实现了多维数组。由于 Boost.MultiArray 提供了更好的解决方案,我的实现只是为了演示。

namespace DataStructures
{
    struct ExtentList   //Discribe extents of dimensions for MultiArray
    {
        std::vector<size_t> dimensions;
        ExtentList() = default;
        template<typename Iterator, typename SFINAE = std::enable_if_t<std::_Is_iterator_v<Iterator>>>
        ExtentList(Iterator begin, Iterator end) : dimensions(begin, end) {}
        //operator[] used to initialize the extents
        ExtentList& operator[](size_t n) { dimensions.push_back(n); return *this; }
        ExtentList after_front() const { return ExtentList(++dimensions.cbegin(), dimensions.cend()); }
        //at() used to access extents
        size_t at(size_t n) const { return dimensions.at(n); }
    };

    static ExtentList Extents;

    template<
        typename ElemType,                                                  //Underlying Type
        size_t Dimension,                                                   //Dimension of MultiArray
        typename ElementAllocator = std::allocator<ElemType>,               //Allocator for elements
        template<typename, typename> typename ContainerType = std::vector,  //Underlying container type
        template<typename> typename ContainerAllocator = std::allocator>    //Allocator for container
    class MultiArray
    {
        //Necessary for contructor with ExtentList
        friend class MultiArray<ElemType, Dimension + 1U, ElementAllocator, ContainerType, ContainerAllocator>;

        using value_type = typename
            std::conditional_t<
            Dimension == 1U, 
            ElemType,
            MultiArray<ElemType, Dimension - 1U, ElementAllocator, ContainerType, ContainerAllocator>>;
        using allocator_type = typename
            std::conditional_t<
            Dimension == 1U,
            ElementAllocator,
            ContainerAllocator<value_type>>;
        ContainerType<value_type, allocator_type> data;


    public:
        MultiArray() = default;
        MultiArray(size_t n, const value_type& val) : data(n, val) {}

        template<typename SFINAE = std::enable_if_t<(Dimension == 1U)>>
            MultiArray(ExtentList extents, const ElemType& elem) : data(extents.at(0), elem) {}
        template<typename SFINAE = std::enable_if_t<(Dimension >= 2U)>, typename SFINAE2 = SFINAE>
            MultiArray(ExtentList extents, const ElemType& elem) : data(extents.at(0), value_type(extents.after_front(), elem)) {}

        MultiArray(std::initializer_list<value_type> ilist) : data(ilist) {}


        template<typename ... SizeType>
        MultiArray(size_t N, SizeType... args) : data(N, value_type(args...)) {}

        value_type& operator[](size_t n) { return data[n]; }
        void push_back(const value_type& elem) { data.push_back(elem); }
    };
}

思路是用递归模板实现多维数组,所以允许订阅和列表初始化操作。

namespace DS = DataStructures;

DS::MultiArray<int, 2> matrix_2d
{
    { 1,2,3 },
    { 4,5,6 },
    { 7,8,9 }
};
for (size_t i = 0; i != 3; ++i)
    for (size_t j = 0; j != 3; ++j)
        std::cout << matrix_2d[i][j] << ' ';

DS::MultiArray<int, 3> matrix_3d(DS::Extents[10][10][10], 0);
size_t sum = 0;
for (size_t i = 0; i != DS::Extents.at(0); ++i)
    for (size_t j = 0; j != DS::Extents.at(1); ++j)
        for (size_t k = 0; k != DS::Extents.at(2); ++k)
            sum += (matrix_3d[i][j][k] = i * 100 + j * 10 + k);
std::cout << sum << '\n' << matrix_3d[9][9][9] << '\n';

ExtentList 的想法来自于 Boost。它比可变函数参数列表或可变模板更好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-11
    相关资源
    最近更新 更多