我有一个2D矩阵存储在沿对角线的平缓冲区中.例如,4×4矩阵的索引分散如下:
0 2 5 9
1 4 8 12
3 7 11 14
6 10 13 15
使用此表示,在给定原始索引和X / Y偏移的情况下,计算相邻元素的索引的最有效方法是什么?例如:
// return the index of a neighbor given an offset
int getNGonalNeighbor(const size_t index,
const int x_offset,
const int y_offset){
//...
}
// for the array above:
getNGonalNeighbor(15,-1,-1); // should return 11
getNGonalNeighbor(15, 0,-1); // should return 14
getNGonalNeighbor(15,-1, 0); // should return 13
getNGonalNeighbor(11,-2,-1); // should return 1
我们假设溢出永远不会发生,并且没有环绕.
我有一个涉及很多triangular number和三角根计算的解决方案.它还包含很多分支,如果可能的话,我宁愿用代数替换它(这将在GPU上运行,其中分散的控制流是昂贵的).我的解决方案工作但非常冗长.我觉得必须有一个更简单,更少计算密集的方法.
如果有人可以在这个特定的问题/表示上加上名字,也许对我有帮助.
如果有人感兴趣的话,我可以发布我的完整解决方案,但正如我所说,对于这样一个简单的任务来说,这是非常漫长和相对复杂简而言之,我的解决方案:
>将原始索引转换为更大的三角形矩阵,以避免处理2个三角形(例如13将变为17)
对于4×4矩阵,这将是:
0 2 5 9 14 20 27
1 4 8 13 19 26
3 7 12 18 25
6 11 17 24
10 16 23
15 22
21
>使用偏移的曼哈顿距离和索引的三角根来计算该表示中邻居的对角线的索引.
>使用偏移量计算此对角线中邻居的位置
>通过删除填充来转换回原始表示.
出于某种原因,这是我能提出的最简单的解决方案.
编辑:
有循环来累积偏移量:
我意识到,考虑到三角形数字的属性,将矩阵分成两个三角形更容易(让我们称之为0到9’上三角’和10到15’下三角’)并且有一个带有测试的循环通过在上三角形中添加一个并在下三个中减去一个来累积偏移(如果这是有意义的).但是对于我的解决方案,必须不惜一切代价避免循环,尤其是具有不平衡跳闸计数的循环(同样,对于GPU来说非常糟糕).
因此,我正在寻找更多的代数解决方案而不是算法解决方案.
构建查找表:
同样,由于GPU,最好避免构建查找表并在其中进行随机访问(非常昂贵).代数解是优选的.
矩阵的属性:
>矩阵的大小是已知的.
>现在我只考虑方阵,但对于矩形矩阵的解决方案也会很好.
>正如我的例子中的函数名称所示,将解决方案扩展到N维体积(因此N-gonal flattening)也将是一个很大的优势.
最佳答案 表查找
#include <stdio.h>
#define SIZE 16
#define SIDE 4 //sqrt(SIZE)
int table[SIZE];
int rtable[100];// {x,y| x<=99, y<=99 }
void setup(){
int i, x, y, xy, index;//xy = x + y
x=y=xy=0;
for(i=0;i<SIZE;++i){
table[i]= index= x*10 + y;
rtable[x*10+y]=i;
x = x + 1; y = y - 1;//right up
if(y < 0 || x >= SIDE){
++xy;
x = 0;
y = xy;;
while(y>=SIDE){
++x;
--y;
}
}
}
}
int getNGonalNeighbor(int index, int offsetX, int offsetY){
int x,y;
x=table[index] / 10 + offsetX;
y=table[index] % 10 + offsetY;
if(x < 0 || x >= SIDE || y < 0 || y >= SIDE) return -1; //ERROR
return rtable[ x*10+y ];
}
int main() {
int i;
setup();
printf("%d\n", getNGonalNeighbor(15,-1,-1));
printf("%d\n", getNGonalNeighbor(15, 0,-1));
printf("%d\n", getNGonalNeighbor(15,-1, 0));
printf("%d\n", getNGonalNeighbor(11,-2,-1));
printf("%d\n", getNGonalNeighbor(0, -1,-1));
return 0;
}
不要使用表格版本.
#include <stdio.h>
#define SIZE 16
#define SIDE 4
void num2xy(int index, int *offsetX, int *offsetY){
int i, x, y, xy;//xy = x + y
x=y=xy=0;
for(i=0;i<SIZE;++i){
if(i == index){
*offsetX = x;
*offsetY = y;
return;
}
x = x + 1; y = y - 1;//right up
if(y < 0 || x >= SIDE){
++xy;
x = 0;
y = xy;;
while(y>=SIDE){
++x;
--y;
}
}
}
}
int xy2num(int offsetX, int offsetY){
int i, x, y, xy, index;//xy = x + y
x=y=xy=0;
for(i=0;i<SIZE;++i){
if(offsetX == x && offsetY == y) return i;
x = x + 1; y = y - 1;//right up
if(y < 0 || x >= SIDE){
++xy;
x = 0;
y = xy;;
while(y>=SIDE){
++x;
--y;
}
}
}
return -1;
}
int getNGonalNeighbor(int index, int offsetX, int offsetY){
int x,y;
num2xy(index, &x, &y);
return xy2num(x + offsetX, y + offsetY);
}
int main() {
printf("%d\n", getNGonalNeighbor(15,-1,-1));
printf("%d\n", getNGonalNeighbor(15, 0,-1));
printf("%d\n", getNGonalNeighbor(15,-1, 0));
printf("%d\n", getNGonalNeighbor(11,-2,-1));
printf("%d\n", getNGonalNeighbor(0, -1,-1));
return 0;
}