C语言中kronecker积的高效计算
我是C语言的新手,在我的大部分研究中都不需要比python更快的速度。然而,事实证明,我最近所做的工作需要计算相当大的向量/矩阵,因此C+MPI解决方案可能是合适的 从数学上讲,这项任务非常简单。我有很多维数为40k的向量,我希望计算这些向量的选定对的值,然后求这些kronecker积的和 问题是,如何有效地做到这一点?使用for循环或获得效果的以下代码结构是否有任何错误 下面描述的函数C语言中kronecker积的高效计算,c,linear-algebra,C,Linear Algebra,我是C语言的新手,在我的大部分研究中都不需要比python更快的速度。然而,事实证明,我最近所做的工作需要计算相当大的向量/矩阵,因此C+MPI解决方案可能是合适的 从数学上讲,这项任务非常简单。我有很多维数为40k的向量,我希望计算这些向量的选定对的值,然后求这些kronecker积的和 问题是,如何有效地做到这一点?使用for循环或获得效果的以下代码结构是否有任何错误 下面描述的函数kron传递长度vector\u size的向量A和B,并计算其kronecker乘积,该乘积存储在C、Ave
kron
传递长度vector\u size
的向量A
和B
,并计算其kronecker乘积,该乘积存储在C
、Avector\u size*vector\u size
矩阵中
void kron(int *A, int *B, int *C, int vector_size) {
int i,j;
for(i = 0; i < vector_size; i++) {
for (j = 0; j < vector_size; j++) {
C[i*vector_size+j] = A[i] * B[j];
}
}
return;
}
void kron(int*A,int*B,int*C,int向量大小){
int i,j;
对于(i=0;i
这对我来说似乎很好,当然(如果我没有犯一些愚蠢的语法错误的话)会产生正确的结果,但我有一种隐秘的怀疑,即嵌入式for循环不是最优的。如果我还有别的办法,请告诉我。欢迎提出建议
我感谢你的耐心和你的建议。再一次,我对C非常缺乏经验,但谷歌搜索给我带来了一点乐趣。对于双精度向量(单精度和复杂度相似),您可以使用BLAS例程
DGER
(排名一更新)或类似工具一次一个地完成产品,因为它们都是向量。你要乘多少向量?请记住,添加一组向量外积(您可以将Kronecker积视为)最终会得到矩阵乘法,BLAS的DGEMM
可以有效地处理这一问题。但是,如果您确实需要整数运算,您可能需要编写自己的例程。因为您的循环体都是完全独立的,所以肯定有一种方法可以加速这一过程。在考虑MPI之前,最简单的方法就是利用几个内核。OpenMP在这方面应该做得很好
#pragma omp parallel for
for(int i = 0; i < vector_size; i++) {
for (int j = 0; j < vector_size; j++) {
C[i][j] = A[i] * B[j];
}
}
#pragma omp parallel for
对于(int i=0;i
现在许多编译器都支持这一点
您也可以尝试将一些常见的表达式从内部循环中拖出,但一些像样的编译器(如gcc、icc或clang)应该可以自己完成这项工作:
#pragma omp parallel for
for(int i = 0; i < vector_size; ++i) {
int const x = A[i];
int * vec = &C[i][0];
for (int j = 0; j < vector_size; ++j) {
vec[j] = x * B[j];
}
}
#pragma omp parallel for
对于(int i=0;i
顺便说一句,使用
int
索引通常不是正确的做法size\t
对于与索引和对象大小有关的所有内容来说都是正确的typedef
。这是数值计算界一个常见的问题,最好的办法是使用一个调试良好的包,比如(或它的一个)
你甚至可以找到它的a,这样你就可以摆脱C
所有这些(可能)都将比严格用python编写的代码快。如果你需要更高的速度,我建议你做几件事:
如果编译器支持C99(并且你永远不会传递与<代码> A/<代码>和<代码> b>代码>相同的向量,请考虑在C99支持模式下编译并将函数签名更改为:
void kron(int * restrict A, int * restrict B, int * restrict C, int vector_size);
restrict
关键字向编译器保证由A
、B
和C
指向的数组不会别名(重叠)。在编写代码时,编译器必须在每次执行内部循环时重新加载A[i]
,因为它必须是保守的,并且假定存储到C[]
可以修改A[]
中的值。在restrict
下,编译器可以假设不会发生这种情况。找到了解决方案(感谢@Jeremiah Willcock):这似乎做得很好。如果我们逐步选择向量对A
和B
,并将它们添加到一些“运行总计”向量/矩阵C
,则上述kron函数的以下修改版本
void kronadd(int *A, int *B, int *C, int vector_size, int alpha) {
int i,j;
for(i = 0; i < vector_size; i++) {
for (j = 0; j < vector_size; j++) {
C[i*vector_size+j] = alpha * A[i] * B[j];
}
}
return;
}
void kronadd(int*A,int*B,int*C,int向量大小,int alpha){
int i,j;
对于(i=0;i
从功能上讲,精确地对应于BLAS DGER函数(可作为访问)。初始的kron
函数是DGER,其中alpha=0
和C
是具有正确维度的未初始化(归零)矩阵/向量
事实证明,最终简单地为这些库使用python绑定可能会更容易。然而,我想我在试图弄明白这件事的过程中学到了很多。在其他回答中有一些更有用的建议,如果你有同样的问题要处理,一定要查看它们。Tha
int i, j;
for(i = 0; i < vector_size; i++) {
int d = *A++;
int *e = B;
for (j = 0; j < vector_size; j++) {
*C++ = *e++ * d;
}
}