c - 尽可能高效地评估具有约 60,000 个短符号表达式的 vector (Matlab,C)

标签 c matlab benchmarking mex

我有一个符号 vector ,其中包含大约 60,000 个短符号表达式,每个单元格中有一个。 这样的表达式通常如下所示:

(81*A_1_1*W1)/(646*L) - (81*A_6_6*L)/(646*W1)

这些表达式中总共出现了大约 20 个不同的变量,我知道其中的值。

问题的中心是尽可能有效地评估这个符号矩阵。将来我需要执行数千次(此计算是优化问题中目标函数的一部分)。

我编写了一个 Matlab 函数,如下所示:

function [K_1_uniques]=K_1_computation(C1,W1,L)

%Define variables from elasticity tensor C1
A_1_1=C1(1,1);
A_1_2=C1(1,2);
A_1_6=C1(1,3);
A_2_2=C1(2,2);
A_2_6=C1(2,3);
A_6_6=C1(3,3);
D_1_1=C1(4,4);
D_1_2=C1(4,5);
D_1_6=C1(4,6);
D_2_2=C1(5,5);
D_2_6=C1(5,6);
D_6_6=C1(6,6);
A_4_4=C1(7,7);
A_4_5=C1(7,8);
A_5_5=C1(8,8);

%Initialize vector
K_1_uniques=zeros(65251,1);

%Populate vector
K_1_uniques(1)=(81*A_1_1*W1)/(646*L) - (81*A_6_6*L)/(646*W1);
K_1_uniques(2)=(63*A_4_5*L)/1427660 - (27*A_5_5*W1)/1427660;
K_1_uniques(3)=(63*A_4_4*L)/1427660 - (27*A_4_5*W1)/1427660;
...
K_1_uniques(65251)=- (2187*A_4_4*L)/62817040 - (2187*A_4_5*W1)/102077690;

第一次运行 MATLAB 大约需要 12.3 秒(用 tic-toc 计时),随后的运行需要 0.030158 秒,因为我猜它保留了编译?我是否正确地假设 Mex 预编译将消除这个漫长的首次运行(IMO 由于 JIT)。

所以我想知道是否可以通过将其作为 Mex 文件运行来进一步加快计算速度?我没有编码器包,所以我必须手动编写 C 代码(好吧,至少是语法,我显然会使用 Matlab 的 fprintf 来编写 65,000 个表达式)。

这是我第一次编写 C Mex 代码(我有一些基本的 C 经验)。我已经成功运行了“hello world”和一些基本的整数和 double 算术,所以我知道发生了什么。

如果我理解正确的话,Mex 文件是预编译的 C 代码,因此与 Matlab 中的 JIT 编译相比应该节省一些时间。

我想向 Mex 文件输入一个 8*8 double 矩阵(弹性张量 C1)以及两个 double 值(标量)W1 和 L。

程序应该像 Matlab 代码中那样赋值 A_1_1=C1(1,1), A_1_2=C1(1,2)...。然后,它应该填充一个新的矩阵数组,其中包含输出的 65,521 个条目。

我在下面有一个这样的代码的简单概述(仅 5 个条目),语法并不完全正确,但它是一个开始。它编译时没有错误,但如果我尝试运行它,Matlab 就会崩溃。我已将 A_1_1 和 A_1_2 指定为标量输入,因为我不确定如何从输入矩阵 C1 中提取它们。我也不确定如何写入矩阵数组,所以我使用了单元数组(这应该改变)。

#include "mex.h" /* Always include this */
void mexFunction(double nlhs, mxArray *plhs[], /* Output variables */
                double nrhs, mxArray *prhs[]) /* Input variables */
{
#define N 5
double A_1_1=*mxGetPr(prhs[0]);
double A_6_6=*mxGetPr(prhs[1]);

plhs[0]=mxCreateCellArray(1, N);
mxSetCell(plhs[0], 1, 2*A_1_1/84 + 3*A_6_6/92);
mxSetCell(plhs[0], 2, 5*A_1_1/120 + 7*A_6_6/11);
mxSetCell(plhs[0], 3, 2*A_1_1/56 + 4*A_6_6/82);
mxSetCell(plhs[0], 4, 12*A_1_1/7 + 3*A_6_6/48);
mxSetCell(plhs[0], 5, 2*A_1_1/74 + 8*A_6_6/92);

return;
}

任何帮助运行此代码的帮助都将不胜感激。另外,我不知道任何有关内存分配等的 C 技巧可以进一步加速此过程。在这方面的任何建议或评论,以及我在更广泛意义上的尝试,我们将不胜感激。

最佳答案

我倾向于信任this answer to your previous question 。就连接受答案的回答者也认为这是正确的。您可以再读一遍。

您的代码可以明显受益的一件事是 common subexpression elimination 。这个question/answer表明 Matlab 的 JIT 不执行此操作,尽管没有指出 Matlab 的版本。对于您的代码来说,这将需要大量繁琐的工作。

当您使用符号数学工具箱时,subexpr函数可能对此有所帮助。我不确定这会工作得如何,因为即使在具有大量内存的快速机器上,符号工具箱也会因大量输入而陷入困境,因此您可能需要解决问题。当然,只要你小心的话,查找和替换也是可以使用的。使用后一种方法,您可以首先查找并消除小的公共(public)子表达式,然后将它们组合起来。 Matlab 的编辑器在处理大文件时遇到麻烦,因为每次发生更改时它都会尝试对其进行着色并检查代码,因此您也可以切换到具有高级搜索和替换功能的全功能文本编辑器。只要使用标准优化级别进行编译,迁移到 mex 还应该消除许多常见的子表达式。但到那时,将其植入为更标准的循环会更有意义。

关于c - 尽可能高效地评估具有约 60,000 个短符号表达式的 vector (Matlab,C),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20596011/

相关文章:

PHP 垃圾收集和内存优化

linux - Linux 上的基准测试程序

c - 为什么我使用以下代码从 valgrind 获取 "invalid read"和 "invalid write"?

c - 有没有办法在 C 中巧妙地创建一个函数,使其在不同的参数值中执行不同的函数?

objective-c 检查 float 和 int 是否相等——2.0000 == 2

python - 如何在python中使用Matlab的imresize

c++ - 在Matlab中将固定长度的字节数组写入二进制文件

c - 当 scanf 需要一个 int 但接收到字符时如何防止菜单出现故障 (C)

matlab - Matlab 中的多行匿名函数?

programming-languages - 您对语言演变的预测