c++ - 使用嵌套 std::vector 在 C++ 中实现 3D 矩阵

标签 c++ c++11 matrix

我有一个包含 MxNxL 元素的 3D 矩阵。 M 和 N 在编译时都是已知的。而 L 是可变的,取决于用户的输入。但它将在程序开始时提供,并且在程序的生命周期内永远不会改变。我想在 C++11 中实现这个矩阵,我想让用户灵活地沿着矩阵的第一维和第二维旋转 3D 矩阵。

我想知道实现此矩阵的最佳和最有效的设计选项是什么?

我看到了以下使用 std::vector 的解决方案。使用 std::vector,用户可以使用 std::rotate 旋转任何维度。解决方案取自此 thread .然而,vsoftco提到使用嵌套 vector 并不好,而是使其线性化。但是由于我有跨维度旋转的需求,使用线阵会增加处理难度。

#include <vector>

#define M_SIZE 360
#define N_SIZE 180 

template<typename T>
using vec = std::vector<T>;

int main()
{
    uint16_t L;
    std::cin << L;
    vec<vec<vec<double>>> v{M_SIZE, vec<vec<double>>{N_SIZE, vec<double>{L}}};
}

同样,使用动态 c 数组是一种可能的解决方案,但 std::rotate 仅适用于 3D 矩阵的最后一个维度。

注意:我更愿意在不依赖第三方库的情况下执行此操作。

最佳答案

我不知道这是否会帮助您实现您所追求的目标,但这是我已经开始使用现代 C++ 功能构建的 Matrix 类;例如 可变参数模板。 Matrix 类自包含在单个头文件中。

#ifndef MATRIX_H
#define MATRIX_H

#include <cstddef>  // std::size_t
#include <numeric>  // std::accumulate
#include <vector>

namespace /*Your namespace name here*/ {

template<typename Type, std::size_t... Dims>
class Matrix {
public:
    static const std::size_t numDims_ = sizeof...(Dims);

private:
    std::size_t numElements_;

    std::vector<Type> elements_;
    std::vector<std::size_t> strides_;

public:
    Matrix() noexcept;

    template<typename... Args>
    Matrix(Args&&... args) noexcept;

    const Type& operator[](std::size_t idx) const;

    std::size_t numElements() const { return elements_.size(); }

    const std::vector<std::size_t>& strides() const { return strides_; }
    const std::vector<Type>& elements() const { return elements_; }
};

template<typename Type, std::size_t... Dims>
Matrix<Type, Dims...>::Matrix() noexcept :
    strides_({ Dims... }) {
    using std::begin;
    using std::end;
    auto mult = std::accumulate(begin(strides_), end(strides_), 1, std::multiplies<>());
    numElements_ = mult;
    elements_.resize(numElements_);
}

template<typename Type, std::size_t... Dims>
template<typename... Args>
Matrix<Type, Dims...>::Matrix(Args&&... args) noexcept :
    elements_({ args... }),
    strides_({ Dims... }) {
    numElements_ = elements_.size();
}

template<typename T, std::size_t... d>
const T& Matrix<T, d...>::operator[](std::size_t idx) const {
    if (idx > numElements_)
        throw std::runtime_error("Invalid index");
    return elements_[idx];
}

} // Your namespace name here
#endif MATRIX_H

还有一个使用它的小示例程序:

#include <iostream>
#include <exception>

#include "Matrix.h"

int main() {    
    try {
        using /*your namespace name here*/;
        Matrix<double, 2, 2, 2> mat( 1.0 ,1.1, 1.2, 1.3,
                                     1.4, 1.5, 1.6, 1.7 );

        // Print the elements from the use of getting the vector
        for (auto& e : mat.elements()) {
            std::cout << e << " ";
        }
        std::cout << '\n';

        // Print the elements from the use of using operator[]
        for ( std::size_t n = 0; n < mat.numElements(); n++ ) {
            std::cout << mat[n] << " ";
        }
        std::cout << '\n';

        // Print out the strides
        std::cout << "Number of strides: " << mat.numDims_ << '\n';
        for (auto& s : mat.strides()) {
            std::cout << s << " ";
        }
        std::cout << '\n';

    } catch ( std::exception& e ) {
        std::cerr << e.what();
        return EXIT_FAILURE;
    }    
    return EXIT_SUCCESS;
}

-输出-

 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7
 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7
 Number of strides: 3
 2 2 2

这个类远未完成,因为它只是包含任何 MxNx...Zx... 矩阵的任意维度大小的外壳。在模板参数列表中,它需要一个 Type:intfloatcharuser defined Type 之后的tempale 参数的可变参数决定了这个矩阵有多少维度,以及每个维度的维度大小。示例:

Matrix<type,1> = a 1 matrix which in essence would be a scalar
Matrix<type,1,2> = a 1x2 matrix and would be considered a vector
Matrix<type,3,1> = a 3x1 matrix and would be considered a vector
Matrix<type,2,2> = a 2x2 matrix
Matrix<type,3,4> = a 3x4 matrix
Matrix<type,3,3,3> = a 3x3x3 Matrix (3D-Matrix) and has 27 elements
Matrix<type,3,4,5,3,2> = a 3x4x5x3x2 (5D - Matrix) and has 360 elements

// The number of elements will always equal the product of all of the strides.
// When creating an arbitrary matrix size; careful consideration needs to be taken
// when it comes to how many dimensions and the size of that dimension. Even lower
// dimensional matrices can explode in the amount of elements...
Matrix<type, 128, 356, 242> = a 128x356x242 (3D - Matrix) but has 11,027,456 elements

// It is the Matrix's user defined variadic constructor that the number of arguments 
// in the parameter list that has to equal the total amount of elements defined by 
// the product of all of its strides.

当处理高维矩阵时,很难将它们可视化,但可以使用 strides vector 轻松管理它们。我们可以使用它们进行适当的索引。

这种设计方法的挑战性在于能够实现实际的算术计算运算符。为此,如果我们有两个具有不同步幅的不同矩阵,它们将被视为不同类型......这只是简单的矩阵运算;当谈到矩阵乘法时,事情变得更加困难,因为矩阵 A 和矩阵 B 的边必须具有相同的大小。例如:4x2 * 2x3 会得到一个 4x3 矩阵。这只是一个 2D 矩阵问题,当进入 3D、4D、...ND 矩阵时,符号甚至变得更难。然而,这种模板方法确实允许代码更加通用和可读,可以自包含到一个类中,而不是为各种矩阵大小使用许多不同的矩阵类......

关于c++ - 使用嵌套 std::vector 在 C++ 中实现 3D 矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53639591/

相关文章:

c++ - 返回基于参数类的模板迭代器

c++ - 在 C 或 C++ 中定义结构的宏

c++ - V8引擎中的隐藏类是如何实现的?

c++ - 在 C++11 中创建并返回包含 lambda 成员变量的类

c++ - 无法解析类型 'uint32_t'

c - FLOPS Intel 内核并使用 C(内积)对其进行测试

python - 如何迭代行索引并从Python数据集中找到具有最大行列式的组?

c++ - GLSL 照明作为平面 - 法线问题?

C++ 模板在模板函数实例化时类型未知

javascript - 如何从矩阵SVG中提取位置、旋转和缩放