C++ 如何在OpenCL中最有效地映射厄米(对称)矩阵的内核范围?

C++ 如何在OpenCL中最有效地映射厄米(对称)矩阵的内核范围?,c++,matrix,opencl,C++,Matrix,Opencl,我正在进行一个OpenCL项目,以生成非常大的hermitian(对称)矩阵,并试图确定生成工作ID的最佳方法 厄米矩阵沿对角线对称,因此M(i,j)=M*(j,i) 以蛮力方式,for循环如下所示: for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) { complex<float> result = doSomeCalculation(); M(i,j) = resul

我正在进行一个OpenCL项目,以生成非常大的hermitian(对称)矩阵,并试图确定生成工作ID的最佳方法

厄米矩阵沿对角线对称,因此M(i,j)=M*(j,i)

以蛮力方式,for循环如下所示:

for(int i = 0; i < N; i++)
{
    for(int j = 0; j < N; j++)
    {
      complex<float> result = doSomeCalculation();
      M(i,j) = result;
    }
}
for(int i=0;i
然而,利用厄米特性质,通过仅计算矩阵的上三角部分并在下三角部分复制结果,可以使循环的效率提高一倍:

for(int i = 0; i < N; i++)
{
    for(int j = i; j < N; j++)
    {
      complex<float> result = doSomeCalculation();
      M(i,j) = result;
      M(j,i) = conj(result);
    }
}
for(int i=0;i
在这两个循环中,doSomeCalculation()是一个昂贵的操作,矩阵中的每个条目都与其他条目完全不相关(即问题是愚蠢的并行)

我的问题是:


如何将doSomeCalculation作为OpenCL内核来实现第二个循环,以使线程ID得到最有效的利用(即,线程在不必调用doSomeCalculation()两次的情况下同时计算M(I,j)和M(j,I)?

如果你的矩阵非常大,那么你可以将你的NxN矩阵切成(N/k)x(N/k)分片,每个分片的大小为kxk。只要您只需要一半的数据,就可以大致创建1DN大小范围
local\u group\u大小*(N/k)x(N/k)/2

矩阵的每个磁贴都由一个LocalGroup处理(LocalGroup的大小由您选择)。其思想是在主机端创建一个数组,其中包含矩阵中每个工作组的位置。内核存根应如下所示:

void __kernel myKernel(
    __global int* coords,
    ....)
{
    int2 WorkGroupPositionInMatrix = vload2(get_group_id(0), coords);
    ...
    DoCalculation();
    ...
    WriteResultTwice();
    ...
    return;
}

你需要手工做的是处理千个工作组,这些工作组将被放置在矩阵对角线上。如果矩阵大小较大,而本地组的开销较小,则放置在对角线上的工作组可以忽略不计。

一个直角三角形可以垂直切成两半,较小的部分旋转以适应较大的部分,形成一个相等的矩形a、 因此,很容易将三角形的全局工作区域变成一个适合OpenCL的矩形


请参见我的答案:

您需要使用线性索引,例如,您可以通过以下方式为矩阵的每个元素编制索引:

0  1  2   ...  N-1
* N-2     ...  2N-2
        ....
*  * 2N-1 ...  N(N+1)/2 -1
也就是说,指数K由下式给出:

 k=iN-i*(i+1)/2+j
其中N是矩阵的大小,(i,j)分别是行和列的基于0的索引

这种关系可以颠倒;请参见问题的答案,为了完整性,我在此报告:

i = floor( ( 2*N+1 - sqrt( (2N+1)*(2N+1) - 8*k ) ) / 2 ) ;
j = k - N*i + i*(i+1)/2 ;
因此,您需要将一个1D内核与N(N+1)/2个工作项排队,您可以自己决定工作组的大小(通常每个工作组64个项目是一个不错的选择)

然后,在OpenCL代码中,您可以使用以下方法检索索引K:

int k = get_group_id(0)*64 + get_local_id(0);
然后使用需要计算的矩阵元素索引上方的两个关系


此外,请注意,您还可以通过将厄米矩阵表示为具有N(N+1)/2个元素的线性向量来节省空间。

对于i==j的对角线,使用了什么公式?它是conj(result)吗?在我的例子中,对于i==j,它是标度恒等式(即标量)的特例但是,因为恒等式对角线在厄米矩阵中是纯实数,所以它是它自己的复共轭。谢谢,但是似乎有一个错误。在计算J之后,需要向它添加I以获得J的“正确”值。@stix。谢谢,修复了。