[Eigen中文文档] 存储顺序

简介: 矩阵和二维数组有两种不同的存储顺序:列优先和行优先。本节解释了这些存储顺序以及如何指定应该使用哪一种。

文档总目录

英文原文(Storage orders)

矩阵和二维数组有两种不同的存储顺序:列优先和行优先。本节解释了这些存储顺序以及如何指定应该使用哪一种。

列优先和行优先存储

矩阵的元素形成二维网格。然而,当矩阵存储在内存中时,元素必须以某种方式线性排列。有两种主要方法可以做到这一点,按行和按列。

如果一个矩阵是逐行存储的,我们说它是按行优先顺序存储。首先存储整个第一行,然后存储整个第二行,依此类推。例如考虑矩阵:

$$ A=\begin{bmatrix} 8&2&2&9 \\ 9&1&4&4 \\ 3&5&4&5 \end{bmatrix}. $$
如果该矩阵以行优先顺序存储,则元素在内存中的布局如下:

8 2 2 9 9 1 4 4 3 5 4 5

另一方面,如果一个矩阵是按列存储的,则它以列优先顺序存储,从整个第一列开始,然后是整个第二列,依此类推。如果上述矩阵按列优先顺序存储,则布局如下:

8 9 3 2 1 5 2 4 4 9 4 5

此示例由以下Eigen代码说明。它使用 PlainObjectBase::data() 函数,该函数返回指向矩阵第一个元素的指针。

Matrix<int, 3, 4, ColMajor> Acolmajor;
Acolmajor << 8, 2, 2, 9,
             9, 1, 4, 4,
             3, 5, 4, 5;
cout << "The matrix A:" << endl;
cout << Acolmajor << endl << endl; 

cout << "In memory (column-major):" << endl;
for (int i = 0; i < Acolmajor.size(); i++)
  cout << *(Acolmajor.data() + i) << "  ";
cout << endl << endl;

Matrix<int, 3, 4, RowMajor> Arowmajor = Acolmajor;
cout << "In memory (row-major):" << endl;
for (int i = 0; i < Arowmajor.size(); i++)
  cout << *(Arowmajor.data() + i) << "  ";
cout << endl;

输出:

The matrix A:
8 2 2 9
9 1 4 4
3 5 4 5

In memory (column-major):
8  9  3  2  1  5  2  4  4  9  4  5  

In memory (row-major):
8  2  2  9  9  1  4  4  3  5  4  5

Eigen中的存储顺序

可以通过为 MatrixArray 指定 Options 模板参数来设置矩阵或二维数组的存储顺序。Matrix 类模板有六个模板参数,其中三个是必需的(ScalarRowsAtCompileTimeColsAtCompileTime),三个是可选的(OptionsMaxRowsAtCompileTimeMaxColsAtCompileTime)。如果 Options 参数设置为 RowMajor,则矩阵或数组以行优先顺序存储;如果设置为 ColMajor,则以列优先顺序存储。上述Eigen程序中使用了这种机制来指定存储顺序。

如果未指定存储顺序,则 Eigen 默认以列优先顺序存储。使用一种存储顺序的矩阵和数组可以分配给使用另一种存储顺序的矩阵和数组,就像上面程序中使用矩阵 Acolmajor 初始化矩阵 Arowmajor 那样,Eigen 将自动重新排序元素。更一般地,行优先和列优先矩阵可以根据需要混合在一个表达式中。

选择哪种存储顺序?

那么,应该在程序中使用哪种存储顺序?这个问题没有统一的答案,这取决于应用程序。有以下几点请注意:

  • 编程时可能需要特定的存储顺序,或使用第三方库时,该库需要特定的存储顺序,这时使用该存储顺序是最好的选择。
  • 由于更好的数据局部性,当矩阵以行优先顺序存储时,逐行遍历矩阵的算法将运行得更快。同样,列优先矩阵的逐列遍历速度更快。
  • Eigen 中的默认值是列优先的。自然地,Eigen 库的大部分开发和测试都是通过列优先矩阵完成的。这意味着,尽管我们的目标是自由选择列优先或行优先存储顺序,但 Eigen 库可能最适合列优先矩阵。
相关文章
|
8月前
|
编译器 索引
[Eigen中文文档] 块操作
本文介绍了块操作。块是matrix或array的部分矩形元素。块表达式既可以用作右值也可以用作左值。与Eigen表达式一样,如果让编译器进行优化,则块操作的运行时间成本为零。
65 0
|
8月前
|
存储 编译器 C语言
[Eigen中文文档] 对未对齐数组断言的解释
本文将解释程序因断言失败而终止的问题。
74 0
|
8月前
|
并行计算 算法 测试技术
[Eigen中文文档] 稠密分解方法目录
本文介绍了 Eigen 提供的处理稠密矩阵分解方法的目录。
76 0
|
8月前
|
C++
[Eigen中文文档] 按值将Eigen对象传递给函数
对于 Eigen,这一点更为重要:按值传递固定大小的可向量化 Eigen 对象不仅效率低下,而且可能是非法的或使程序崩溃! 原因是这些 Eigen 对象具有对齐修饰符,在按值传递时会不遵守这些修饰符。
71 0
|
8月前
|
存储 算法 NoSQL
[Eigen中文文档] 稀疏矩阵操作
在许多应用中(例如,有限元方法),通常要处理非常大的矩阵,其中只有少数系数不为零。在这种情况下,可以通过使用仅存储非零系数的特殊表示来减少内存消耗并提高性能。这样的矩阵称为稀疏矩阵。
222 0
|
8月前
[Eigen中文文档] 编写以特征类型为参数的函数(一)
Eigen使用表达式模板的方式导致每个表达式的类型可能都不同。如果将这样的表达式传递给一个需要Matrix类型参数的函数,则表达式将隐式地被评估为一个临时Matrix,然后再传递给函数。这意味着失去了表达式模板的好处。
81 0
|
8月前
|
编译器 API 索引
[Eigen中文文档] 切片和索引
本文介绍了如何使用操作运算符operator()索引行和列的子集。该 API 在 Eigen 3.4 中引入。它支持 block API 提供的所有功能。特别是,它支持切片,即获取一组行、列或元素,以及等间隔的从矩阵或者数组中提取元素。
251 0
|
8月前
|
存储 数据建模 API
[Eigen中文文档] 稀疏矩阵快速参考指南
本页面简要介绍了类SparseMatrix中可用的主要操作。在处理稀疏矩阵时,重要的一点是要了解它们的存储方式:即行优先或列优先,Eigen默认为列优先。对稀疏矩阵进行的大多数算术操作都会默认它们具有相同的存储顺序。
114 0
|
8月前
[Eigen中文文档] 固定大小的可向量化Eigen对象
本文主要解释 固定大小可向量化 的含义。
52 0
|
8月前
|
存储 编译器 对象存储
[Eigen中文文档] 包含Eigen对象的结构体
如果定义的结构体包含固定大小的可向量化 Eigen 类型成员,则必须确保对其调用 operator new 来分配正确的对齐缓冲区。如果仅使用足够新的编译器(例如,GCC>=7、clang>=5、MSVC>=19.12)以 [c++17] 模式编译,那么编译器会自动处理所有事情,可以跳过本节。 否则,必须重载它的 operator new 以便它生成正确对齐的指针(例如,Vector4d 和 AVX 的 32 字节对齐)。幸运的是,Eigen 为提供了一个宏 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 来完成这项工作。
122 0