Page 83 - 《软件学报》2021年第6期
P. 83
苏卓 等:基于分支标记的数据流模型的代码生成方法 1657
支情况的模型实例,然后将这些实例按照本文提出的算法最终转化为 C 语言代码.实验所构建的 Ptolemy-II 模
型如表 2 中的第 1 列所示,对应生成的代码如第 2 列所示.这 3 个模型都使用离散事件指示器(DE director)和离
散时钟(DiscreteClock)来驱动,模型的仿真时间为 50 个单位时间,离散时钟的采样时间为 1 个单位时间,所以整
个模型会反复执行 51 次.模型中的 BooleanSwitch 组件为二分支的分支组件,它会根据它最下面的端口数据的
逻辑值选择将左边输入数据传递到右边的哪个端口.Ramp 组件可以产生等差数列,这里我们设置的等差数列首
项为−25,公差为 1,该组件每次输出的结构会从−25 开始依次加 1.Expression 为表达式组件,可以把输入数据代
入表达式求解,再将结果传递到输出端口.Scale 组件可以将输入数值缩放后输出.SequencePlotter 示波器组件可
以将每次输入的数据以折线的形式绘制出来.Counter 组件的输出从 1 开始,之后每次执行输出会增加 1.Display
组件可以将输入数据以文本的形式输出出来.表 2 中第 2 列显示的代码只是完整代码的一部分,这里只把组件
的调度及计算逻辑相关的代码呈现了出来,其他的比如主函数封装、局部变量的声明等和调度无关的代码在这
里不加以展示.另外,我们以标准输出“printf”作为各种输出组件对应的生成代码;并且在由 CGLT 转化为代码的
过程中,以 BooleanSwitch 组件为数据源的组件,直接跨过 BooleanSwitch 组件向前寻找数据源.通过这种方式,可
以生成更精简的代码.
Table 2 Model examples for three different branch situations
表 2 3 种不同分支情况的模型实例
模型 对应的 C 代码
1. Ramp_output+=1;
2. Expression_output=Ramp_output>0;
3. if (Expression_output){
4. printf(“%f\n”,Ramp_output);
5. } else {
6. Scale_out=Ramp_output*0.1;
(a) 分支合并情况的模型 7. printf(“%f\n”,Scale_out);
8. }
1. Ramp_output+=1;
2. Expression_output=Ramp_output>0;
3. Expression2_output=Ramp_output>−10;
4. if (Expression_output){
5. Expression3_output=Ramp_output*5+1;
6. printf(“%f\n”,Expression3_output);
7. } else {
8. if (Expression2_output){
9. Expression4_output=Ramp_output*−4+1;
10. printf(“%f\n”,Expression4_output);
11. } else {
(b) 分支嵌套情况的模型
12. Expression5_output=Ramp_output*5+91;
13. printf(“%f\n”,Expression5_output);
14. }
15. }
1. Counter_output+=1;
2. Expression_output=Counter_output%7==0;
3. Expression2_output=Counter_output%3==0;
4. if (Expression_output && Expression2_output){
5. printf(“%d%d\n”,Counter_output,Counter_output);
6. } else if (Expression_output){
7. printf(“%d\n”,Counter_output);
8. } else if (Expression2_output){
9. printf(“%d\n”,Counter_output);
(c) 分支交叉情况的模型
10. }
表 2(a)模型显示了一个在深度学习领域中常用的激活函数 LeakyRelu 函数的图像:当 Ramp 组件的输出大
于 0 时,SequencePlotter 显示 Ramp 组件本来的输出值;当 Ramp 组件的输出小于等于 0 时,SequencePlotter 显示
Ramp 组件输出值乘以 0.1.模型中的 BooleanSwitch 组件生成了 if-else 语句(第 3 行和第 5 行);SequencePlotter
组件合并了 BooleanSwitch 组件的两个分支,由于 SequencePlotter 组件在两个分支下的数据源不同,所以在 if 和
else 控制的语句块下各生成了一行代码(第 4 行和第 7 行);Scale 组件仅在 BooleanSwitch 的 False 分支中,所以