注意:我已经根据Keith Randall和Chiyou的有用反馈编辑了这个问题。
我有一个想法,使用 1D 数组在特定处理上下文中缓存最常用的 2D NxM 矩阵条目。问题是,是否已经有大量的工作可以从中获得洞察力,或者是否只有知道的人。我将首先概述腿部工作,然后再提出问题。作为补充说明,Chiyou已经提出了空间填充曲线,它在概念上看起来是我所追求的东西,但不会轻易回答我的具体问题(即我找不到可以做我所追求的曲线) .
腿部工作:
目前最常用的条目被定义为循环和特殊的组合pointer_array
(见下面的代码),它们组合产生最常用矩阵元素的索引。pointer_array 包含范围 [0, max(N, M)]中的数字(参见上面定义为 NxM 的矩阵维度)。
代码的目的是产生一个合适的(在程序的上下文中)索引组合来处理一些矩阵条目。有可能N = M,即方阵。遍历矩阵的代码 (C++) 如下所示
for(int i = 0; i < N; i++)
{
for(int j = i + 1; j < M; j++)
{
auto pointer1 = pointer_array[i];
auto pointer2 = pointer_array[i + 1];
auto pointer3 = pointer_array[j];
auto pointer4 = pointer_array[j + 1];
auto entry1 = some_matrix[pointer1][pointer3];
auto entry2 = some_matrix[pointer2][pointer4];
auto entry3 = some_matrix[pointer3][pointer4];
auto entry4 = some_matrix[pointer1][pointer2];
//Computing with the entries...
}
}
一些值得单独注意的事情:
为了使这种缓存有价值,我认为它应该是密集的。也就是说,可以随机访问并在内存中连续布局的东西。即没有空间“浪费”(除非有许多单独的块)并且复杂性在 O(1) 中。这意味着缓存不能是与 1D 行/列主要有序数组完全排序的相同 2D 矩阵。我觉得它应该适合长度为max(N, M)的数组(参见上面的矩阵维度定义)。
some_matrix
在循环期间将忽略其中的许多条目。pointer_array 排序记录了通过矩阵的路线,因此它也用于其他地方。
我在各种场合都遇到过这种需求,但这次我编写了一个2-opt算法,我正在寻求改进它的内存访问模式。我知道还有其他方法可以编写算法(但请参阅我遇到的其他设置,现在想知道是否有通用解决方案)。
跳出框框的想法是产生一种类似的索引组合,在概念上类似于访问 2D 矩阵,但更智能。一种选择是在循环期间缓存矩阵行/列。
由于条目将被大量使用,因此
pointer_array
通过缓存 some_matrix 调用来替换间接会更理想,这样获取entry*
循环中的值会更快,即从预加载的缓存而不是可能相当大的矩阵。这里的另一点是它会节省存储空间,这反过来意味着经常使用的值可以很好地适应更快的缓存。
问题:是否可以设计一种索引方案,使矩阵索引本质上变成
//Load the 2D matrix entries to some_1d_cache using the pointer_array
//so that the loop indices can be used directly...
for (int i = 0; i < N; i++)
{
for (int j = i + 1; j < M; j++)
{
//The some_1d_cache((x, y) call will calculate an index to the 1D cache array...
auto entry1 = some_1d_cache(i, j);
auto entry2 = some_1d_cache(i + 1, j + 1);
auto entry3 = some_1d_cache(j, j + 1);
auto entry4 = some_1d_cache(i, i + 1);
//Computing with the entries...
}
}
或者也许像下面这样的东西也可以
for (int i = 0; i < N; i++)
{
for (int j = i + 1; j < M; j++)
{
auto pointer1 = pointer_array[i];
auto pointer2 = pointer_array[i + 1];
auto pointer3 = pointer_array[j];
auto pointer4 = pointer_array[j + 1];
//The some_1d_cache((x, y) call will calculate an index to the 1D cache array...
auto entry1 = some_1d_cache(pointer1, pointer3);
auto entry2 = some_1d_cache(pointer2, pointer4);
auto entry3 = some_1d_cache(pointer3, pointer4);
auto entry4 = some_1d_cache(pointer1, pointer2);
//Computing with the entries...
}
}