一种残膜回收机防缠绕挑膜装置的制 一种秧草收获机用电力驱动行走机构

一种基于Coq的矩阵代码生成技术的形式化描述方法与流程

2022-03-09 00:30:43 来源:中国专利 TAG:

一种基于coq的矩阵代码生成技术的形式化描述方法
技术领域
1.本发明涉及形式化描述技术领域,特别是涉及一种基于coq的矩阵代码生成技术的形式化描述方法。


背景技术:

2.来自智能计算的需求增加了矩阵计算的复杂性,并行硬件为矩阵计算的性能带来了很大的提升,高性能的矩阵代码都是命令式代码,但是函数式矩阵描述适合于矩阵数学性质的证明以及矩阵表达式的优化,但函数式语言的矩阵代码效率不高。atkey等人中提出了一种把函数式矩阵描述转换到命令式代码的方法data parallel idealised algol(dpia)(atkey r,steuwer m,lindley s,et al.strategy preserving compilation for parallel functional code[j].2017),该技术是对syntactic control ofinference revisited(o'hearn p w,power a j,takeyama m,et al.syntactic control of interference revisited[j].1997.)的扩展,它描述了一种从带有并行策略的高级函数式代码到并行命令式代码的转换,但是该方法抽象度高,直观性差,可靠性不易令人信服,实现中尚有各种问题需要解决,详细分析如下:
[0003]
其一,dpia技术缺少对代码转换规则的形式化验证,难以保证代码转换过程中的正确性问题。当代定理证明工具(比如coq)可以进行数学定理的证明验证,也能够支持程序的正确性问题。但是,为了把数学形式的规则系统在coq中进行形式化描述,还需要解决一系列问题。
[0004]
其二,为了在coq定理证明器中对dpia转换规则进行形式化验证,需要将这些规则在coq中实现。为此,需要描述dpia引入的函数常量的类型,并保证函数定义和转换规则定义都能够通过类型检查。
[0005]
其三,在dpia技术中缺少了为新变量自动生成新名字的具体方案。在函数式代码转c代码的过程中,往往需要引入新变量,典型的情景有:并行运算中的局部变量,循环体中的循环变量,这些变量相互之间不能有冲突,否则代码不能正确运行。
[0006]
其四,由于dpia技术所处理的程序主要是矩阵程序,因此首先需要在coq中对矩阵进行形式化。虽然在定理证明领域已经存在一些矩阵的形式化方法,但是,这些形式化技术有的比较繁琐,有的不适合表达关于矩阵的函数式程序。dpia本身所提供的原语和规则并不足以支持矩阵部分函数式程序的翻译,因此无法生成比较复杂的矩阵代码,如矩阵转置,分块矩阵运算等。
[0007]
为解决上述问题,本发明提出一种基于coq的矩阵代码生成技术的形式化描述方法。


技术实现要素:

[0008]
有鉴于此,本发明的目的在于提供一种基于coq的矩阵代码生成技术的形式化描述方法,该方法基于dpia(data parallel idealised algol)技术原理在coq定理证明器内
对矩阵代码生成技术进行形式化描述,用于高效矩阵命令式代码(c)的生成,解决了该技术中存在的新变量声明命名重复的问题,并对该技术中的原语和规则进行扩展以实现更多函数式矩阵程序的转换。
[0009]
为了实现上述目的,本发明采用如下技术方案:
[0010]
一种基于coq的矩阵代码生成技术的形式化描述方法,所述方法包括如下步骤:
[0011]
步骤s1、对数据类型、功能原语、命令原语进行形式化描述;
[0012]
步骤s2、对代码转换规则进行形式化描述,其中,所述代码转换规则包括:从高级功能原语到高级命令式宏的转换、从高级命令式宏到低级for循环的转换、命令和接收器以及与表达式之间的显示转换;
[0013]
步骤s3、利用coq中的重写功能编写自动化重写策略以实现矩阵代码生成;
[0014]
步骤s4、构建变量名自动生成函数,并设立和证明了不同的命令中变量声明个数引理,再将引理引入命令的显示翻译规则中,实现在对命令显示翻译时新变量命名无重复声明;
[0015]
步骤s5、进行原句和规则的扩展,以实现更多矩阵代码的生成,其中,所述原句包括:矩阵赋值、倒置、转置、标量功能原语以及索引功能原语。
[0016]
进一步的,在所述步骤s1中,所述数据类型包括:数值、索引、数组、对偶以及相应的接受器和表达式;所述功能原语包括:标量功能原语、数组功能原语以及对偶功能原语;所述命令原语包括:空命令、顺序执行、赋值、新变量声明、顺序for循环以及并行for循环。
[0017]
进一步的,对数据类型进行形式化描述,具体包括:
[0018]
利用coq中常用大类type实现数据类型和短语类型所属类型kind、短语类型phrase;数据类型包括:数值类型num、接受一个自然数作为参数的索引类型idx、接受一个自然数和一个数据类型作为参数的数组类型ary、接受两个数据类型作为参数的对偶类型tensor;接收器类型与表达式类型接受一个数据类型作为输入参数返回短语类型。
[0019]
进一步的,对所述标量功能原语进行形式化描述,具体包括:
[0020]
取负函数neg接受一个数值表达式参数,再输出一个数值表达式;加法函数add、乘法函数mul、除法函数div以及减法函数sub接受两个数值表达式参数,再输出一个数值表达式;对所述数组功能原语进行形式化描述,具体包括:映射函数map接受一个自然数n、数据类型s和t、映射函数、长度为n且元素类型为s的表达式的数组作为参数,输出类型为长度为n且数据类型为t的数组表达式,其中,映射函数map接受的映射函数,其接受数据以数据类型为s的表达式为参数,以数据类型为t的表达式为输出;规定顺序映射函数mapseq与并行映射函数mappar同映射函数map的类型相同;规约函数reduce接受一个自然数、数据类型s和t、计算函数、初始值、长度为n且元素类型为s的表达式的数组作为参数,输出类型为t的表达式类型,其中,该计算函数接受s的表达式类型和t的表达式类型,并且以t的表达式类型作为输出类型,该初始值为t的表达式类型;顺序执行的规约函数reduceseq的类型同规约函数reduce的类型相同;组合函数zip接受一个自然数、数据类型s和t、长度为n且元素类型为s的表达式的数组、长度为n且数据类型为t的表达式的数组作为参数,输出类型为长度为n且元素类型为s与t的对偶的数组表达式;查询函数fun_idx接受一个自然数n、数据类型t、长度为n且数据类型为t的数组表达式,并且以小于n的索引表达式作为参数,输出类型为t的表达式;接收器组合左分量函数zipacc1接受一个自然数n、数据类型s和t,长度为n且数
据类型为s和t的对偶类型的接收器作为输入,输出为长度为n且数据类型为s的接收器;接收器组合右分量函数zipacc2接受一个自然数n、数据类型s和t,长度为n且数据类型为s和t的对偶类型的接收器作为输入,输出为长度为n且数据类型为t的接收器;接收器查询函数idxacc接受自然数n、数据类型t、长度为n且数据类型为t的数组接收器、小于n的索引表达式作为参数,输出为数据类型为t的接收器。
[0021]
进一步的,对对偶功能原语进行形式化描述,具体包括:
[0022]
对偶函数pair接受数据类型s和t、数据类型为s的表达式、数据类型为t的表达式作为参数,输出为数据类型为s和t的对偶的表达式;左分量函数fst接受数据类型s和t、数据类型为s和t的对偶的表达式作为参数,输出为数据类型为s的表达式;右分量函数snd接受数据类型s和t、数据类型为s和t的对偶的表达式作为参数,输出为数据类型为t的表达式;接收器对偶左分量函数pairacc1接受数据类型s和t、数据类型为s和t的对偶的接收器作为参数,输出类型为数据类型为s的接收器;接收器对偶右分量函数pairacc2接受数据类型s和t、数据类型为s和t的对偶的接收器作为参数,输出类型为数据类型为t的接收器;
[0023]
其中,对命令原语进行形式化描述,具体包括:
[0024]
顺序语句seq接受命令类型组成的对偶作为参数,输出类型为命令类型;空语句skip为命令类型;赋值语句assign接受一个数据类型d以及d的接收器与表达式的对偶作为参数,输出类型为命令类型;新变量声明语句接受一个数据类型t、以及一个函数作为参数,输出类型为命令,其中,所述新变量声明语句接受的函数,其以接受参数为t的接收器和表达式的对偶作为参数,其输出类型为命令类型;顺序循环seqfor接受自然数n、一个函数作为参数,输出类型为命令,其中,所述顺序循环seqfor接受的函数,其以接受小于n的索引表达式作为输入,其输出类型为命令类型;并行循环parfor接受自然数n、数据类型t、一个函数作为参数,输出类型为命令类型,其中,所述并行循环parfor接受的函数,其以接受一个长度为n数据类型为t的数组接受器、小于n的索引表达式以及数据类型为t的接收器作为输入,其输出类型为命令。
[0025]
进一步的,所述步骤s2中,所述从高级功能原语到高级命令式宏的转换,其通过acceptor-passing翻译器、continuation-passing翻译器实现;
[0026]
所述命令和接收器以和表达式之间的显示转换,其通过命令翻译器、接收器翻译器和表达式翻译器实现;
[0027]
其中,acceptor-passing翻译器的形式化描述,具体包括:
[0028]
翻译器a接受数据类型d、数据类型为d的表达式和接收器作为参数,输出类型为命令类型;acceptor-passing规则的形式化描述,具体包括:数值类型的表达式e和接收器a经过翻译器a的转换规则;数组类型的表达式e和接收器a经过翻译器a的转换规则;对偶类型的表达式和接收器经过翻译器a的转换规则;数值类型的表达式取负经过翻译器a的转换规则;数值类型的表达式e1和e2相加经过翻译器a的转换规则;数值类型的表达式e1和e2相乘经过翻译器a的转换规则;经过顺序映射mapseq的数组表达式经过翻译器a的转换规则;并行映射mappar作用的数组表达式经过翻译器a的转换规则;顺序规约reduceseql作用的数组表达式经过翻译器a的转换规则;组合函数zip作用的数组表达式经过翻译器a的转换规则;对偶函数pair作用的表达式经过翻译器a的转换规则;左分量函数fst作用的表达式经过翻译器a的转换规则;右分量函数snd作用的表达式经过翻译器a的转换规则;
[0029]
continuation-passing翻译器的形式化描述,具体包括:
[0030]
翻译器c接受一个数据类型d、数据类型为d的表达式和一个函数作为参数,输出类型为命令类型,其中,该翻译器c接受的一个函数,其输入参数为数据类型为d的表达式,输出类型为命令类型;
[0031]
continuation-passing规则的形式化描述,具体包括:
[0032]
数据类型为d的表达式和后续调用操作c经过翻译器c的转换规则;数值类型的表达式取负经过翻译器c的转换规则;数值类型的表达式e1和e2相加经过翻译器c的转换规则;数值类型的表达式e1和e2相乘经过翻译器c的转换规则;并行映射mappar作用的数组表达式经过翻译器c的转换规则;经过顺序映射mapseq的数组表达式经过翻译器c的转换规则;顺序规约reduceseql作用的数组表达式经过翻译器c的转换规则;组合函数zip作用的数组表达式经过翻译器c的转换规则;对偶函数pair作用的表达式经过翻译器c的转换规则;
[0033]
所述从高级命令式宏到低级for循环的转换,其形式化描述,具体包括:
[0034]
并行映射mapparl接受自然数n、数据类型s和t、一个函数、长度为n且数据类型为s的数组表达式xs、长度为n且数据类型为t的接收器out作为参数,使用并行循环parfor将映射函数f作用于xs的每个元素之上,并将结果存储于out中,其中,所述并行映射mapparl接受的一个函数,其输入参数为数据类型为s的表达式和数据类型为y的接收器;
[0035]
顺序映射mapseql接受自然数n、数据类型s和t、一个函数、长度为n且数据类型为s的数组表达式xs、长度为n且数据类型为t的接收器out作为参数,使用顺序循环seqfor将映射函数f作用于xs和out的每个对应元素之上,其中,所述顺序映射mapseql接受的一个函数,其输入参数为数据类型为s的表达式和数据类型为t的接收器;
[0036]
顺序规约reduceseql接受自然数n、数据类型的d1和d2、一个函数、初始值、长度为n且数据类型为d1的数组表达式xs、后续处理函数c,实现为新生命一个临时变量,将初始值赋值于该变量,然后通过顺序循环seqfor将f作用于数组内的每个元素与该临时变量之上,最后将后续处理函数作用于该临时变量之上,其中,所述顺序规约reduceseql接受的一个函数,其输入参数为数据类型为d1和d2的表达式和数据类型为d2的接收器,所述顺序规约reduceseql接受的初始值,其为数据类型为d2的表达式,所述顺序规约reduceseql接受的后续处理函数c,其以接受数据类型为d2为参数,其输出为命令类型。
[0037]
进一步的,命令和接收器以及与表达式之间的显示转换,其形式化描述包括:命令的翻译规则在coq中的形式化、接收器的翻译规则在coq中的形式化以及表达式的翻译规则在coq中的形式化,其中,
[0038]
所述命令的翻译规则在coq中的形式化,具体包括:
[0039]
空语句skip的显示翻译规则;顺序执行语句seq的显示翻译规则;赋值语句assign的显示翻译规则;新变量生成语句new的显示翻译规则;顺序循环语句seqfor的显示翻译规则;并行循环语句parfor的显示翻译规则;所述接收器的翻译规则在coq中的形式化,具体包括:数据类型为d的接收器与环境和路径的显示翻译规则;接收器查询函数idxacc作用的数组接收器的显示翻译规则;接收器对偶左分量函数pairacc1作用的接收器的显示翻译规则;接收器对偶右分量函数pairacc2作用的接收器的显示翻译规则;接收器组合左分量函数zipacc1作用的接收器的显示翻译规则;接收器组合右分量函数zipacc2作用的接收器的
显示翻译规则;
[0040]
所述表达式的翻译规则在coq中的形式化,具体包括:
[0041]
数据类型为d的表达式与环境和路径的显示翻译规则;取负表达式的显示翻译规则;相加表达式的显示翻译规则;相乘表达式的显示翻译规则;组合函数zip作用的表达式的显示翻译规则;对偶函数pair作用的表达式的显示翻译规则;对偶左分量函数fst作用的表达式的显示翻译规则;对偶右分量snd作用的表达式的显示翻译规则;查询函数fun_idx作用的表达式的显示翻译规则。
[0042]
进一步的,所述步骤s3具体包括:
[0043]
定义高级功能原语与翻译器a的重写规则于自动化重写策略asimpl1中;
[0044]
定义其余关于翻译器a的重写规则于自动化重写策略asimpl2中;
[0045]
定义高级功能原语与翻译器c的重写规则于自动化重写策略csimpl1中;
[0046]
定义其余关于翻译器c的重写规则于自动化重写策略csimpl2中;
[0047]
定义命令、左值、右值显示翻译规则于自动化重写策略cgsimpl中;
[0048]
将asimpl1、asimpl2、csimpl1、csimpl2、cgsimpl封装于自动化重写策略allsimpl中;
[0049]
定义字符串到自然数的重写规则strnat_simpl。
[0050]
进一步的,所述步骤s4具体包括:
[0051]
定义变量名生成函数vstr、istr,根据输入的自然数编号自动生成相应的变量名字符串,其中,vstr为临时变量,istr为循环变量;
[0052]
定义不同命令中临时变量生成个数,其中空语句skip命令生成0个,顺序执行语句seq生成的个数为其中顺序执行的语句p1、p2中生成变量数之和,赋值语句assign生成0个;
[0053]
新变量生成语句new生成的个数为带参命令体p生成的个数加1;
[0054]
顺序循环语句seqfor生成的个数为循环体p生成的个数加1;
[0055]
并行循环语句parfor生成的个数为循环体p生成的个数加1;
[0056]
将变量名命名规则于命令显示翻译相结合,其中为命令的显示翻译器增加一个自然数作为编号参数,接着定义针对skip、seq、assign、new、seqfor、parfor的带有变量名自动生成的命令显示翻译规则。
[0057]
进一步的,所述步骤s5包括对原语扩展进行扩展和对规则进行扩展;
[0058]
其中,对原语扩展进行扩展具体包括:
[0059]
定义数值类型表达式的求根函数sqrt;定义数值表达式的绝对值函数abs;定义索引表达式减1函数idxpred;定义索引表达式的求和函数addidx、相减函数subidx、相乘函数mulidx、相除函数dividx;定义数组表达式的逆置函数reverse;定义数组表达式的顺序逆置函数reverseseq;定义数组表达式的复制函数copy;定义数组表达式的顺序复制函数copyseq;定义二维数组表达式的并行转置函数transpar;定义顺序for循环实现的顺序逆置函数reverseseql;定义顺序循环实现的顺序复制函数copyseql;定义并行循环实现的并行转置函数transparl;
[0060]
对规则进行扩展具体包括:
[0061]
定义求根函数sqrt与翻译器a的转换规则;定义求绝对值函数abs与翻译器a的转换规则;定义顺序逆置函数reverseseq与翻译器a的转换规则;定义顺序复制函数copyseq
与翻译器a的转换规则;定义并行转置函数transpar与翻译器a的转换规则;定义求根函数sqrt与翻译器c的转换规则;定义绝对值函数abs与翻译器c的转换规则;定义顺序逆置函数reverseseq与翻译器c的转换规则;定义顺序复制函数copyseq与翻译器c的转换规则;定义并行转置函数transpar与翻译器c的转换规则;定义求根函数sqrt作用的数值表达式显示翻译规则;定义求绝对值函数abs作用的数值表达式显示翻译规则;定义索引表达式减1函数idxpred作用的索引表达式的显示翻译规则;定义索引表达式的求和函数addidx作用的索引表达式的显示翻译规则;定义索引表达式的相减函数subidx作用的索引表达式的显示翻译规则;定义索引表达式的相乘函数mulidx作用的索引表达式的显示翻译规则;定义数组赋值语句的显示翻译规则。
[0062]
本发明的有益效果是:
[0063]
本发明的一方面将形式化技术应用于矩阵代码生成技术,在coq定理证明器内实现了将带有执行策略的函数式代码转换为可执行高效并行的命令式代码的矩阵代码生成技术,在coq中该技术的形式化描述具有严格的定义,并且能够通过类型检查,为未来规则正确性验证打下基础。另一方面提出了一种变量自动命名的方法,解决了矩阵代码生成技术中存在的临时变量命名重名问题,并对该技术进行一定的扩展以实现更多矩阵代码的生成。
附图说明
[0064]
图1为实施例1中提供的一种基于coq的矩阵代码生成技术的形式化描述方法的框架示意图;
[0065]
图2为实施例1中提供的dpia大类型kind的示意图;
[0066]
图3为实施例1中提供的dpia数据类型data的示意图;
[0067]
图4为实施例1中提供的dpia短语类型phrase的示意图;
[0068]
图5为实施例1中提供的dpia代码转换过程的示意图;
[0069]
图6为实施例1中提供的函数式矩阵程序的表格;
[0070]
图7为实施例1中提供的基于4核的测试结果图;
[0071]
图8为实施例1中提供的基于8核的测试结果图。
具体实施方式
[0072]
为使本发明实施例的目的、技术方案和优点更加清楚,下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本发明保护的范围。
[0073]
实施例1
[0074]
参见图1-图8,本实施例中提供一种基于coq的矩阵代码生成技术的形式化描述方法,该方法的逻辑框图如图1所示,该方法具体包括:
[0075]
1)对数据类型、功能原语、命令原语进行形式化描述,具体实现如下:
[0076]

建立数据类型的coq归纳定义:dpia原理中的数据类型包括数值类型、索引类型、数组类型、对偶类型以及相应的接收器和表达式类型,如图2、3、4所示。本实施例构建了
这些类型的coq形式化定义:
[0077]
definition kinds:type:=type.
[0078]
inductive data:kinds:=
[0079]
|num:data(*数值类型*)
[0080]
|idx:nat-》data(*索引类型*)
[0081]
|ary:nat-》data-》data(*数组类型*)
[0082]
|tensor:data-》data-》data.(*对偶类型*)
[0083]
definition phrase:kinds:=type.
[0084]
本实施例构建了接收器和表达式类型的高阶类型声明:
[0085]
接收器类型acc:data-》phrase.
[0086]
表达式类型exp:data-》phrase.
[0087]
接受器和表达式类型分别为变量的可写域(左值)和可读域(右值),接受器类型可以被某个表达式赋值,表达式类型则直接参与计算。
[0088]

建立功能原语的coq类型声明:dpia包含一组基本函数原语(仅包含名字、类型和功能描述),本发明建立了这组函数的coq类型描述。这些基本函数原语分为四类,第一类是标量操作原语,主要用于对标量的计算;第二类是不带执行策略的高级功能原语,用于处理数组数据;第三类是带有执行策略的高级功能原语,用于处理数组数据;第四类是对数据布局的功能原语,zip将两个长度相等的向量转换为元素为对偶的数组,pair构造对偶,fst和snd解构一对,fun_idx在数组中查找一个值。
[0089]
标量原语
[0090]
neg:(exp num)-》(exp num).
[0091]
add mul div sub:(exp num)-》(exp num)-》(exp num).
[0092]
zero one:exp num.
[0093]
数组功能原语
[0094]
map:forall[n:nat][s t:data],((exp s)-》(exp t))-》(exp(ary n s))-》(exp(ary n t)).
[0095]
mapseq:forall[n:nat][s t:data],((exp s)-》(exp t))-》(exp(ary n s))-》(exp(ary n t)).
[0096]
mappar:forall[n:nat][s t:data],((exp s)-》(exp t))-》(exp(ary n s))-》(exp(ary n t)).
[0097]
reduce:forall[n:nat][s t:data],((exp s)-》(exp t)-》(exp t))-》(exp t)-》(exp(ary n s))-》(exp t).
[0098]
reduceseq:forall[n:nat][s t:data],((exp s)-》(exp t)-》(exp t))-》(exp t)-》(exp(ary n s))-》(expt).
[0099]
zip:forall[n:nat][s t:data],(exp(ary n s))-》(exp(ary n t))-》(exp(ary n(tensor s t))).
[0100]
fun_idx:forall[n:nat][t:data],(exp(ary n t))-》(exp(idx n))-》(exp t).
[0101]
zipacc1:forall[n:nat][s t:data],(acc(ary n(tensor s t)))-》acc(ary n s).
[0102]
zipacc2:forall[n:nat][s t:data],(acc(ary n(tensor s t)))-》acc(ary n t).
[0103]
pairacc1:forall[s t:data],(acc(tensor s t))-》(acc s).
[0104]
pairacc2:forall[s t:data],(acc(tensor s t))-》(acc t).
[0105]
idxacc:forall[n:nat][t:data],(acc(ary n t))-》(exp(idx n))-》(acc t).
[0106]
对偶原语
[0107]
pair:forall[s t:data],(exp s)-》(exp t)-》(exp(tensor s t)).
[0108]
fst:forall[s t:data],(exp(tensor s t))-》(exp s).
[0109]
snd:forall[s t:data],(exp(tensor s t))-》(exp t).
[0110]

建立命令原语以及翻译器的coq定义:dpia命令原语分为两类,第一类是命令其中seq(记作';)为顺序执行命令;skip不做任何操作;new用于变量声明;assign(记作|:=)是赋值语句。for循环由for和parfor组合子构建而成,其中并行for循环parfor与通常的for循环不同在于它需要声明一个数组型变量,该变量用于每次迭代的输出,这能够保证parfor的实现是安全的,本实施例构建了这些命令原语的coq定义:
[0111]
inductive comm:type:=
[0112]
|seq:comm*comm-》com
[0113]
|skip:comm
[0114]
|assign:forall{d:data},(acc d)*(exp d)-》comm
[0115]
|new:forall{t:data},((acc t)*(exp t)-》comm)-》comm
[0116]
|seqfor:forall(n:nat),((exp(idx n))-》comm)-》comm
[0117]
|parfor:forall(n:nat)(t:data),(acc(ary n t))-》((exp(idx n))-》(acc t)-》comm)-》comm.
[0118]
2)对翻译器和代码转换规则进行形式化描述。dpia翻译规则主要分为三类,第一类为由acceptor-passing和continuation-passing相互定义的转换规则,该部分的规则需要通过acceptor-passing翻译器(a)、continuation-passing翻译器(c)来实现,这些规则能够将功能表达式转换为命令式代码,第二类利用低级for循环实现高级命令式宏,第三类是命令式程序生成的翻译规则,这部分的规则需要通过命令翻译器(codegen
comm
)、接收器翻译器(codegen
acc
)、表达式翻译器(codegen
exp
)和数据类型翻译器(codegen
data
),主要用于第三步骤的翻译,具体如图5所示。
[0119]
下面是第一类的翻译规则在coq中的形式化描述。acceptor-passing翻译器a(e)δ(a)等价于一个赋值语句,其中a和e分别为赋值的接收器和表达式。下面是这部分的翻译器以及翻译规则在coq内的形式化定义:
[0120]
acceptor-passing翻译器的形式化描述:a:forall[d:data],(exp d)-》(acc d)-》comm.记作a(?)|(?)。
[0121]
a翻译器接受一个接受器和表达式作为参数,其等价于赋值命令。
[0122]
acceptor-passing规则的形式化描述:
[0123]
规则:a(e)
num
(a)=a:=
num e
[0124]
coq实现:forall(a:acc num)(x:exp num),a(x)|(a)=a|:=x.
[0125]
规则:a(e)
n.δ
(a)=mapparl
nδδ
(λx a.a:=
δ
x)e a
[0126]
coq实现:forall(n:nat)(d:data)(a:acc(ary n d))(x:exp(ary n d)),a(x)|(a)=mapparl(fun x a=》a|:=x)x a.
[0127]
规则:a(e)
δ1
×
δ2
(a)=pairacc1 a:=
δ1
fst e;pairacc2 a:=
δ2
snd e
[0128]
coq实现:forall(n:nat)(d1 d2:data)(a:acc(tensor d1 d2))(x:exp(tensor d1 d2)),a(x)|(a)=(a.x1|:=fst x)';a.x2|:=snd x.
[0129]
规则:a(neg e)
num
(a)=c(e)
num
(λx.a:=
num
(neg x))
[0130]
coq实现:forall(a:acc num)(e:exp num),a(neg e)|(a)=c(e)|(fun(x:exp num)=》a|:=neg x)
[0131]
规则:a(add e1e2)
num
(a)=c(e1)
num
(λx.c(e2)
num
(λy.a:=
num
(add x y))
[0132]
coq实现:forall(a:acc num)(e1 e2:exp num),a(add e1 e2)|(a)=c(e1)|(fun x=》c(e2)|(fun y=》a|:=add e1 e2)).
[0133]
规则:a(mul e1 e2)
num
(a)=c(e1)
num
(λx.c(e2)
num
(λy.a:=
num
(mul x y))
[0134]
coq实现:forall(a:acc num)(e1 e2:exp num),a(mul e1 e2)|(a)=c(e1)|(fun x=》c(e2)|(fun y=》a|:=mul e1 e2)).
[0135]
规则:a(mapseq
n,δ1,δ2
fe)
n.δ2
(a)=c(e)
n.δ1
(λx.mapseql
n,δ1,δ2
(λy.(λo.a(fy)
δ2
))x a)
[0136]
coq实现:forall(n:nat)(d1 d2:data)(f:exp d1-》exp d2)(e:exp(ary n d1))(a:acc(ary n d2)),a(mapseq f e)|(a)=c(e)|(fun(x:exp(ary n d1))=》mapseql(fun y=》(fun o=》a(fy)|(o)))xa).
[0137]
规则:a(mappar
n,δ1,δ2
fe)
n.δ2
(a)=c(e)
n.δ1
(λx.mapseql
n,δ1,δ2
(λy.(λo.a(fy)
δ2
))x a)
[0138]
coq实现:forall(n:nat)(d1 d2:data)(f:exp d1-》exp d2)(e:exp(ary n d1))(a:acc(ary n d2)),a(mappar fe)|(a)=c(e)|(fun(x:exp(ary n d1))=》mapparl(fun y=》(fun o=》a(fy)|(o)))x a).
[0139]
规则:a(reduceseq
n,δ1,δ2
f i e)
n.δ2
(a)
[0140]
=c(e)
n.δ1
(λx.c(i)(λy.reduceseql
n,δ1,δ2
(λx’.(λy’.(λo.a(fx’y’)δ2
)))y x(λr.a(r)
δ2
(a)))
[0141]
coq实现:forall(n:nat)(d1 d2:data)(f:exp d1-》exp d2-》exp d2)(i:exp d2)(e:exp(ary n d1))(a:acc d2),a(reduceseq f i e)|(a)=c(e)|(fun(x:exp(ary n d1))=》c(i)|(fun y=》reduceseql(fun x'=》(fun y'=》(fun o=》a(fx'y')|(o))))y x(fun r=》a(r)|(a)))).
[0142]
规则:a(zip e1 e2)
n,δ1,δ2
(a)=a(e1)
n.δ1
(zipacc1 a);a(e2)
n.δ1
(zipacc2 a)
[0143]
coq实现:forall(n:nat)(d1 d2:data)(e1:exp(ary n d1))(e2:exp(ary n d2))(a:acc(ary n(tensor d1 d2))),a(zip e1 e2)|(a)=a(e1)|(zipacc1 a)';a(e2)|(zipacc2 a).
[0144]
规则:a(pair
δ1,δ2
e1 e2)δ1
×
δ2(a)=a(e1)
δ1
(pairacc1
δ1,δ2
a);a(e2)
δ2
(pairacc2
δ1,δ2
a)
[0145]
coq实现:forall(d1 d2:data)(e1:exp d1)(e2:exp d2)(a:acc(tensor d1 d2)),a(pair e1 e2)|(a)=a(e1)|(pairacc1 a)';a(e2)|(pairacc2 a).
[0146]
规则:a(fst
δ1,δ2
e)δ1(a)=c(e)
δ1
×
δ2
(λx.a:=
δ1
fst
δ1,δ2
x)
[0147]
coq实现:forall(d1 d2:data)(e:exp(tensor d1 d2))(a:acc d1),a(fst e)|(a)=c(e)|(fun x=》a|:=fst x).
[0148]
规则:a(snd
δ1,δ2
e)
δ2
(a)=c(e)
δ1
×
δ2
(λx.a:=
δ2
snd
δ1,δ2
x)
[0149]
coq实现:forall(d1 d2:data)(e:exp(tensor d1 d2))(a:acc d2),a(snd e)|(a)=c(e)|(fun x=》a|:=snd x).
[0150]
continuation-passing翻译器的形式化描述:c:forall[d:data],(exp d)-》((exp d)-》comm)-》comm.记作c(?)|(?)。
[0151]
c翻译器接受一个表达式和一个以该表达式为参数的函数作为参数,其等价于将后者作用于前者的操作。
[0152]
continuation-passing规则的形式化描述:
[0153]
规则:c(e)
δ
(c)=c e
[0154]
coq实现:forall(d:data)(e:exp d)(c:exp d-》comm),c(e)|(c)=c e.
[0155]
规则:c(neg e)
num c=c(e)
num
(λx.c(neg x))
[0156]
coq实现:forall(e:exp num)(c:exp num-》comm),c(nege)|(c)=c(e)|(fun x=》c(neg x)).
[0157]
规则:c(add e1e2)
num c=c(e1)
num
(λx.c(e2)
num
(λy.c(add x y))))
[0158]
coq实现:forall(e1 e2:exp num)(c:exp num-》comm),c(add e1 e2)|(c)=c(e1)|(fun x=》c(e2)|(fun y=》c(add x y))).
[0159]
规则:c(mul e1 e2)
num c=c(e1)
num
(λx.c(e2)
num
(λy.c(mul x y))))
[0160]
coq实现:forall(e1 e2:exp num)(c:exp num-》comm),c(mul e1 e2)|(c)=c(e1)|(fun x=》c(e2)|(fun y=》c(mul x y))).
[0161]
规则:c(mappar
n,δ1,δ2
f e)n.δ2(c)=new
n.δ2
(λtmp.a(mappar
n,δ1,δ2
f e)
n.δ2
(fst tmp);c(snd tmp)))
[0162]
coq实现:forall(n:nat)(d1 d2:data)(f:exp d1-》exp d2)(e:exp(ary n d1))(c:exp(ary n d2)-》comm),c(mappar fe)|(c)=new(fun tmp=》a(mappar fe)|(fst tmp)';c(sndtmp)).
[0163]
规则:c(mapseq
n,δ1,δ2
fe)n.δ2(c)=new
n.δ2
(λtmp.a(mapseq
n,δ1,δ2
fe)
n.δ2
(fst tmp);c(snd tmp)))
[0164]
coq实现:forall(n:nat)(d1 d2:data)(f:exp d1-》exp d2)(e:exp(ary n d1))(c:exp(ary n d2)-》comm),c(mapseq fe)|(c)=new(fun tmp=》a(mapseq fe)|(fst tmp)';c(sndtmp)).
[0165]
规则:c(reduceseq
n,δ1,δ2
f i e)
δ2
(c)
[0166]
=c(e1)
n.δ1
(λx.c(i)
δ2
(λy.reduceseql
n,δ1,δ2
(λx’y’o.a(fx’y’)
δ2
(o))y x c))
[0167]
coq实现:forall(n:nat)(d1 d2:data)(f:exp d1-》exp d2-》exp d2)(i:exp d2)(e:exp(ary n d1))(c:exp d2-》comm),c(reduceseq f i e)|(c)=c(e)|(fun x=》c(i)|(fun y=》reduceseql(fun x'y'o=》a(fx'y')|(o))y x c)).
[0168]
规则:c(zip
n,δ1,δ2
e1 e2)
n.δ1
×
δ2
(c)=c(e1)
n.δ1
(λx.c(e2)
n.δ2
(λy.c(zip
n,δ1,δ2
x y)))
[0169]
coq实现:forall(n:nat)(d1 d2:data)(e1:exp(ary n d1))(e2:exp(ary n d2))(c:exp(ary n(tensor d1 d2))-》comm),c(zip e1 e2)|(c)=c(e1)|(fun x=》c(e2)|(fun y=》c(zip x y))).
[0170]
规则:c(pair
n,δ1,δ2
e1 e2)
δ1
×
δ2
(c)=c(e1)
n.δ1
(λx.c(e2)
n.δ1
(λy.c(pair
n,δ1,δ2
x y)))
[0171]
coq实现:forall(d1 d2:data)(e1:exp d1)(e2:exp d2)(c:exp(tensor d1 d2)-》comm),c(@pair d1 d2 e1 e2)|(c)=c(e1)|(fun x=》c(e2)|(fun y=》c(@pair d1 d2 x y))).
[0172]
规则:c(fst
δ1
×
δ2
e)
δ2
(c)=c(e)
δ1
×
δ2
(λx.c(fst
δ1
×
δ2
x))
[0173]
coq实现:forall(d1 d2:data)(e:exp(tensor d1 d2))(c:exp d1-》comm),c(@fst d1 d2 e)|(c)=c(e)|(fun x=》c(@fst d1 d2 x)).
[0174]
规则:c(snd
δ1
×
δ2
e)
δ2
(c)=c(e)
δ1
×
δ2
(λx.c(snd
δ1
×
δ2
x))
[0175]
coq实现:forall(d1 d2:data)(e:exp(tensor d1 d2))(c:exp d2-》comm),c(@snd d1 d2 e)|(c)=c(e)|(fun x=》c(@snd d1 d2 x)).
[0176]
第二类是高级命令式宏的低级for循环实现在coq中的形式化,主要有3个分别是mapparl,mapseql和reduceseql,具体如下:
[0177]
definition mapparl(n:nat)(s t:data)(f:(exp s)-》(acc t)-》comm)
[0178]
(xs:(exp(ary n s)))(out:(acc(ary n t))):=
[0179]
parfor n t out(fun i=》fun o=》f(fun_idx n s xs i)o).
[0180]
definition mapseql(n:nat)(s t:data)(f:(exp s)-》(acc t)-》comm)
[0181]
(xs:(exp(ary n s)))(out:(acc(ary n t))):=
[0182]
seqfor n(fun i=》f(fun_idx n s xs i)(idxacc n t out i)).
[0183]
definition reduceseql(n:nat)(d1 d2:data)(f:(exp d1)-》(exp d2)-》(acc d2)-》comm)
[0184]
(init:exp d2)(xs:exp(ary n d1))(c:exp d2-》comm):=
[0185]
new d2(fun ac=》
[0186]
let(vw,vr):=ac in
[0187]
seq(assign d2(vw,init),
[0188]
seq(seqfor n(fun i=》f(fun_idx n d1 xs i)vr vw),
[0189]
c vr))).
[0190]
第三类的转换规则主要用于将命令、左值、右值转换成相应的命令式代码。
[0191]
在代码显示翻译中需要通过环境映射将dpia标识符转换为输出程序的标识符,本发明对存储该映射的环境类型以及相应的翻译函数在coq中形式化定义如下:
[0192]
definition env:=list(string*string).
[0193]
fixpoint getvar(s:string)(eta:env):string:=
[0194]
match eta with
[0195]
|(x,y)::tl=》ifstring_dec s x then y else getvar s tl
[0196]
|nil=》""
[0197]
end.
[0198]
例如getvar"a"["a","a"]="a",即将dpia中的标识符"a"翻译为"a"。
[0199]
代码显示翻译中对于接受器和表达式变量的显示翻译,需要通过其相应的访问路径以及变量名进行翻译,本发明对该需求构建了访问路径类型以及表达式变量的显示翻译函数,在coq中对访问路径的形式化定义如下:
[0200]
inductive path:=aidx(i:nat)|sacc(p:string).
[0201]
definition pslist:=listpath.
[0202]
pslist为表达式的访问路径,表达式变量的显示翻译需要通过该表达式变量名以及相应的访问路径来实现,本发明在coq中构建该函数如下:
[0203]
fixpoint applyps(v:string)(ps:pslist):string:=
[0204]
matchps with
[0205]
|nil=》v
[0206]
|(aidx i)::tl=》applyps(v)tl "[" (writenat i) "]"
[0207]
|(sacc p)::tl=》applyps(v p)tl
[0208]
end.
[0209]
例如apply“x”[aidx 3]=“x[3]”表示为访问x数组中的第三个元素。
[0210]
下面是命令、接收器、表达式翻译器在coq中的形式化定义:
[0211]
codegen
comm
:env-》comm-》string.
[0212]
codegen
acc
:forall(p:phrase),env-》pslist-》p-》string.
[0213]
codegen
exp
:forall(p:phrase),env-》pslist-》p-》string.
[0214]
codegen
data
:data-》string-》string.
[0215]
codegen
comm
翻译器接受一个命令作为参数并将其显示翻译以字符串输出,env为dpia标识符与翻译后的生成代码标识符对应关系的参数。codegen
acc
翻译器接受一个接受器为参数并将其显示翻译以字串串输出。codegen
exp
翻译器接受一个表达式为参数并将其显示翻译以字符串输出。codegen
data
翻译器接受一个数据类型和变量名,返回该变量的声明,主要用于临时变量的声明部分。本实施例在coq中构建codegen
data
的具体实现的形式化定义如下:
[0216]
fixpoint codegen_data(d:data)(s:string):string:=
[0217]
match dwith
[0218]
|num=》"float" s
[0219]
|idx n=》"int"
[0220]
|ary n d=》(codegen_data d(s "[" (writenat n) "]"))
[0221]
|tensor d1 d2=》"
[0222]
struct{
[0223]
" (codegen_data d1 s) "x1;
[0224]
" (codegen_data d2 s) "x2;
[0225]
}"
[0226]
end.
[0227]
下面是命令的翻译规则在coq中的形式化:
[0228]
规则:codegen
comm
(skip,η)=/*skip*/
[0229]
coq实现:codegen_comm eta skip="/*skip*/".
[0230]
规则:codegen
comm
(p1;p2,η)=codegen
comm
(p1,η)codegen
comm
(p2,)
[0231]
coq实现:forall(p1 p2:comm),codegen_comm eta(p1';p2)cnt=(codegen_comm etap1) (codegen_comm etap2)
[0232]
规则:codegen
comm
(a:=
num e)=codegen
acc
(a,η,[])“=”codegen
exp
(e,η,[]);
[0233]
coq实现:forall(a:acc num)(e:exp num),codegen_comm eta(a|:=e)=(codegen_acc(acc num)eta[]a) "=" (codegen_exp(exp num)eta[]e) ";".
[0234]
规则:codegen
comm
(new
δ
(λv.p),η)=codegen
data
[δ](v);codegen
comm
(p(v,v),v::η)
[0235]
coq实现:forall(d:data)(p:acc d*exp d-》comm),codegen_comm eta(new p)=(codegen_data d)"v" ";" (codegen_comm(("v","v")::eta)(p(vwt"v",vrd"v"))).
[0236]
规则:codegen
comm
(for n(λi.p),η)=for(int i=0;i《n;i =1){codegen
comm
(p,i::η)}
[0237]
coq实现:forall(n:nat)(p:exp(idx n)-》comm),codegen_comm eta(seqfor n p)="for(int i=0;i《n;i =1){" (codegen_comm(("i","i")::eta)(p(vrd"i"))) "}".
[0238]
规则:codegen
comm
(parforn,δa(λi o.p),η)=
[0239]
#pragma omp parallel for
[0240]
for(int i=0;i《n;i =1){codegen
comm
(p[idxacc a i o],i::η,)}
[0241]
coq实现:forall(n:nat)(d:data)(a:acc(ary n d))(p:exp(idx n)-》acc d-》comm),codegen_comm eta(parfor n d ap)=
[0242]
"#pragma omp parallel for
[0243]
for(int i=0;i《n;i =1){" (codegen_comm(("i","i")::eta)(p(vrd"i")(a'[(vrd"i"]))) "}".
[0244]
下面是左值的翻译规则在coq中的形式化:
[0245]
规则:codegen
acc[δ]
(x,η,p)=η(x)(rev p)
[0246]
coq实现:forall(d:data)(x:string)(ps:pslist),codegen_acc(acc d)eta ps(vwt x)=applyps(getvar x eta)(rev ps).
[0247]
codegen
acc[δ]
(idxacc
n,δ1
a i,η,p)=codegen
acc
[n.δ](a,η,codegen
exp
[idx[n]](i,η,[])::ps))
[0248]
coq实现:forall(d:data)(n:nat)(a:acc(ary n d))(i:exp(idx n))(ps:pslist),codegen_acc(acc d)etaps(a'[i])=codegen_acc(acc(ary n d))eta(aidx(codegen_exp(exp(idx n))eta[]i)::ps)a.
[0249]
规则:codegen
acc[δ1]
(pairacc1
δ1,δ2
a,η,p)=codegen
acc[δ1
×
δ2]
(a,η,.x1::ps)
[0250]
coq实现:forall(d1 d2:data)(a:acc(tensor d1 d2))(ps:pslist),codegen_acc(acc d1)eta ps(a.x1)=codegen_acc(acc(tensor d1 d2))eta(sacc".x1"::ps)a.
[0251]
规则:codegen
acc[δ2]
(pairacc2
δ1,δ2
a,η,p)=codegen
acc[δ1
×
δ2]
(a,η,.x2::ps)
[0252]
coq实现:forall(d1 d2:data)(a:acc(tensor d1 d2))(ps:pslist),codegen_acc(acc d2)eta ps(a.x2)=codegen_acc(acc(tensor d1 d2))eta(sacc".x2"::ps)a.
[0253]
规则:codegen
acc[δ1]
(zipacc1
δ1,δ2
a,η,i::p)=codegen
acc[n.(δ1
×
δ2)]
(a,η,i::.x1::ps)
[0254]
coq实现:forall(n:nat)(d1 d2:data)(a:acc(ary n(tensor d1 d2)))(ps:pslist)(i:nat),codegen_acc(acc(ary n d1))eta(aidx i::ps)(zipacc1 a)=codegen_acc(acc(ary n(tensor d1 d2)))eta(aidx i::sacc".x1"::ps)a.
[0255]
规则:codegen
acc[δ2]
(zipacc2
δ1,δ2
a,η,i::p)=codegen
acc[n.(δ1
×
δ2)]
(a,η,i::.x2::ps)
[0256]
coq实现:forall(n:nat)(d1 d2:data)(a:acc(ary n(tensor d1 d2)))(ps:pslist)(i:nat),codegen_acc(acc(ary n d2))eta(aidx i::ps)(zipacc2 a)=codegen_acc(acc(ary n(tensor d1 d2)))eta(aidx i::sacc".x2"::ps)a.
[0257]
下面是右值的翻译规则在coq中的形式化:
[0258]
规则:codegen
exp[δ]
(x,η,p)=η(x)(rev p)
[0259]
coq实现:forall(d:data)(x:string)(ps:pslist),codegen_exp(exp d)eta ps(vrd x)=applyps(getvar x eta)(rev ps).
[0260]
规则:codegen
exp[num]
(neg e,η,[])=(-codegen
exp[num]
(e,η,[]))
[0261]
coq实现:forall(e:exp num),codegen_exp(exp num)eta[](negate e)="(-" (codegen_exp(exp num)eta[]e) ")".
[0262]
规则:codegen
exp[num]
(e1 e2,η,[])=(codegen
exp[num]
(e1,η,[]) codegen
exp[num]
(e2,η,[]))
[0263]
coq实现:forall(e1 e2:exp num),codegen_exp(exp num)eta[](add e1 e2)="(" (codegen_exp(exp num)eta[]e1) " " (codegen_exp(exp num)eta[]e2) ")".
[0264]
规则:codegen
exp[n.(δ1
×
δ2)]
(zip
n,δ1,δ2
e1 e2,η,i::.x1::p)=codegen
exp[n.δ1]
(zip
n,δ1,δ2
e1 e2,η,i::p)
[0265]
coq实现:forall(e1 e2:exp num),codegen_exp(exp num)eta[](mul e1 e2)="(" (codegen_exp(exp num)eta[]e1) "*" (codegen_exp(exp num)eta[]e2) ")".
[0266]
规则:codegen
exp[n.(δ1
×
δ2)]
(zip n,δ1,δ2
e1 e2,η,i::.x1::p)=codegen
exp[n.δ1]
(zip n,δ1,δ2
e1 e2,η,i::p)
[0267]
coq实现:forall(n:nat)(d1 d2:data)(e1:exp(ary n d1))(e2:exp(ary n d2))(i:nat)(ps:pslist),codegen_exp(exp(ary n(tensor d1 d2)))eta(aidx i::sacc".x1"::ps)(zip e1 e2)=codegen_exp(exp(ary n d1))eta(aidx i::ps)e1.
[0268]
规则:codegen
exp[n.(δ1
×
δ2)]
(zip
n,δ1,δ2
e1 e2,η,i::.x2::p)=codegen
exp[n.δ2]
(zip
n,δ1,δ2
e1 e2,η,i::p)
[0269]
coq实现:forall(n:nat)(d1 d2:data)(e1:exp(ary n d1))(e2:exp(ary n d2))(i:nat)(ps:pslist),codegen_exp(exp(ary n(tensor d1 d2)))eta(aidx i::sacc".x2"::ps)(zip e1 e2)=codegen_exp(exp(ary n d2))eta(aidx i::ps)e2.
[0270]
规则:codegen
exp[δ1
×
δ2]
(pair
δ1,δ2
e1 e2,η,.x1::p)=codegen
exp[δ1]
(e1,η,p)
[0271]
coq实现:forall(n m:nat)(d1 d2:data)(e1:exp d1)(e2:exp d2)(ps:pslist),codegen_exp(exp(tensor d1 d2))eta(sacc".x1"::ps)(pair e1 e2)=codegen_exp(exp d1)etaps e1.
[0272]
规则:codegen
exp[δ1
×
δ2]
(pair
δ1,δ2
e1 e2,η,.x2::p)=codegen
exp[δ2]
(e2,η,p)
[0273]
coq实现:forall(n m:nat)(d1 d2:data)(e1:exp d1)(e2:exp d2)(ps:pslist),codegen_exp(exp(tensor d1 d2))eta(sacc".x2"::ps)(pair e1 e2)=codegen_exp(exp d2)etaps e2.
[0274]
规则:codegen
exp[δ1]
(fst
δ1,δ2
e,η,p)=codegen
exp[δ1
×
δ2]
(e,η,.x1::p)
[0275]
coq实现:forall(d1 d2:data)(e:exp(tensor d1 d2))(ps:pslist),codegen_exp(exp d1)eta ps(fst e)=codegen_exp(exp(tensor d1 d2))eta(sacc".x1"::ps)e.
[0276]
规则:codegen
exp[δ2]
(snd
δ1,δ2
e,η,p)=codegen
exp[δ1
×
δ2]
(e,η,.x2::p)
[0277]
coq实现:forall(d1 d2:data)(e:exp(tensor d1 d2))(ps:pslist),codegen_exp(exp d2)eta ps(snd e)=codegen_exp(exp(tensor d1 d2))eta(sacc".x2"::ps)e.
[0278]
规则:codegen
exp[δ]
(fun_idx n,δ
e i,η,p)=codegen
exp[n.δ]
(e,η,codegen
exp[idx[n]]
(i,η,[])::p)
[0279]
coq实现:forall(d:data)(n:nat)(e:exp(ary n d))(i:exp(idx n))(ps:pslist),codegen_exp(expd)eta ps(e|[i])=codegen_exp(exp(ary n d))eta(aidx(codegen_exp(exp(idx n))eta[]i)::ps)e.
[0280]
3)利用重写技术实现代码转换。在coq中通过自定义重写策略利用重写技术来实现矩阵代码生成。
[0281]
ltacasimpl1:=
[0282]
rewrite?amapseq,?amappar,?areduceseq,?areverseseq,?acopyseq,?atranspar.
[0283]
ltacasimpl2:=
[0284]
rewrite?azip,?afst,?asnd;
[0285]
rewrite?aadd,?amul,?asqrt,?aabs,?avar_ary,?avar_tensor,?avar_num.
[0286]
ltac csimpl1:=
[0287]
repeat(rewrite?cmappar,?cmapseq,?creduceseq,?creverseseq,?ccopyseq,?atranspar);
[0288]
try unfold mapparl,mapseql,reduceseql,reverseseql,copyseql,transparl.
[0289]
ltac csimpl2:=rewrite?czip,?cfst,?csnd;rewrite?cmul,?cadd,?csqrt,?cabs,?cvar.
[0290]
ltac cgsimpl:=
[0291]
rewrite?cgskip,?cgseq,?cgassign,?cgassign_ary,?cgnew,?cgfor,?cgparfor;
[0292]
repeat cnt_simpl;rewrite?cgzip1,?cgzip2,?cgfst,?cgsnd;
[0293]
rewrite?cgidxacc,?cgidx,?cgmul,?cgadd,?cgsqrt,?cgabs,
[0294]
?cgaddidx,?cgmulidx,?cgsubidx,?cgidxpred,?cgaccvar,?cgexpvar.
[0295]
ltacallsimpl:=asimpl1;asimpl2;csimpl1;csimpl2;cgsimpl.
[0296]
ltac strnat_simpl:=simpl;rewrite?wtstrnat;simpl.
[0297]
阶段二:矩阵代码生成技术的完善和扩充:
[0298]
1)解决变量命名重复问题:
[0299]
变量名生成函数在coq中的定义如下:
[0300]
definition vstr(cnt:nat):string:="v" (writenat cnt).
[0301]
definition istr(cnt:nat):string:="i" (writenat cnt).
[0302]
其中vstr为临时变量的变量名,istr为循环中循环变量的变量名,两者都是通过一个自然数产生相应的变量名,该自然数取决于程序中变量声明的个数,例如在最初输入函数式矩阵代码时该自然数为0,随着命令的主句翻译该自然数逐渐增加为已翻译的命令中临时变量声明的个数。对于不同命令中临时变量的声明个数不同,因此定义了计算变量声明个数的函数,该函数以命令作为输入,以临时变量声明个数作为输出,skip命令不做任何操作因此无临时变量声明,seq命令临时变量个数为顺序执行的两个命令中临时变量声明个数之和,assign为赋值语句无临时变量声明,new命令声明了一个新变量,seqfor和parfor中都含有循环变量的声明。
[0303]
fixpoint cnt_var(c:comm):=
[0304]
match c with
[0305]
|skip=》0
[0306]
|seq(c1,c2)=》cnt_var c1 cnt_var c2
[0307]
|assign ac=》0
[0308]
|@new tp=》1 cnt_var(p(vwt"",vrd""))
[0309]
|seqfor n p=》1 cnt_var(p(vrd""))
[0310]
|parfor n t ap=》1 cnt_var(p(vrd"")(vwt""))
[0311]
end.
[0312]
利用上述定义将变量命名规则与命令显示翻译相结合,具体如下:
[0313]
codegen
comm
:env-》comm-》nat-》string.
[0314]
codegen
comm
(skip,η,cnt)=/*skip*/
[0315]
codegen
comm
(p1;p2,η,cnt)=codegen
comm
(p1,η,cnt)codegen
comm
(p2,η,cnt_varp1 cnt)
[0316]
codegen
comm
(a:=
num e,η,cnt)=codegen
acc
(a,η,[])“=”codegen
exp
(e,η,[]);
[0317]
codegen
comm
(new
δ
(λv.p),η,cnt)=let v:=vstr cnt in
[0318]
codegen
data[δ]
(v);codegen
comm
(p(vwtδv,vrdδv),v::η),(cnt 1))
[0319]
codegen
comm
(forn(λi.p),η,cnt)=let i:=istr cnt in
[0320]
for(int i=0;i《n;i =1){codegen
comm
(p,i::η,cnt 1)}
[0321]
codegen
comm
(parfor
n,δ
a(λi o.p),η,cnt)=let i:=istr cnt in
[0322]
#pragma omp parallel for
[0323]
for(int i=0;i《n;i =1){codegen
comm
(p[idxacc a i o],i::η,cnt 1)}
[0324]
2)对原语和规则进行扩展:
[0325]
我们能够通过该编译技术产生矩阵运算的相应代码,同时该规则具有良好的扩展性,通过扩展规则可以实现不同向量和矩阵表达式的重写。下面是我们根据向量运算函数(向量范数、向量绝对值求和、向量赋值、向量逆转、向量赋值和矩阵转置)进行的相应扩展。
[0326]
原语扩展:
[0327]
idxpred:forall(n:nat),exp(idx n).
[0328]
addidx subidx mulidx dividx:forall(n:nat),(exp(idx n))-》(exp(idx n))-》(exp(idx n)).
[0329]
reverse:forall[n:nat][s:data],(exp(ary n s))-》(exp(ary n s)).
[0330]
reverseseq:forall[n:nat][s:data],(exp(ary n s))-》(exp(ary n s)).
[0331]
copy:forall[n:nat][s:data],(exp(ary n s))-》(exp(ary n s)).
[0332]
copyseq:forall[n:nat][s:data],(exp(ary n s))-》(exp(ary n s)).
[0333]
transpar:forall[m n:nat][s:data],(exp(ary m(ary n s)))-》(exp(ary n(ary m s))).
[0334]
reverseseql[n:nat][d1:data](xs:exp(ary n d1))(out:acc(ary n d1)):=
[0335]
seqfor n(fun i=》assign d1(idxacc out i,fun_idx xs(subidx n(idxpredn)i))).
[0336]
copyseql[n:nat][d1:data](xs:exp(ary n d1))(out:acc(ary n d1)):=
[0337]
seqfor n(fun i=》assign d1(idxacc out i,fun_idx xs i)).
[0338]
transparl[m n:nat][d1:data](xs:exp(ary m(ary n d1)))(out:acc(ary n(ary m d1))):=
[0339]
parfor n(ary m d1)out(fun i=》fun o=》seqfor m(funj=》
[0340]
assign d1(idxacc(idxacc out i)j,fun_idx(fun_idx xsj)i))).
[0341]
规则扩展
[0342]
a(sqrt e)
num
(a)=c(e)
num
(λx.a:=
num
(sqrt x))(根号)
[0343]
a(abs e)
num
(a)=c(e)
num
(λx.a:=
num
(abs x))(绝对值)
[0344]
a(reverseseq
n,δ
e)
n.δ
(a)=c(e)
n.δ
(λx.reverseseql
n,δ
x a)
[0345]
a(copyseq
n,δ
e)
n.δ
(a)=c(e)
n.δ
(λx.copyseql
n,δ
x a)
[0346]
a(transpar
m,n,δ
e)
n.δ
(a)=c(e)
n,m.δ
(λx.transparl
n,m,δ
x a)
[0347]
c(sqrt e)
num c=c(e)
num
(λx.c(sqrt x))
[0348]
c(abs e)
num c=c(e)
num
(λx.c(abs x))
[0349]
c(reverseseq
n,δ
e)
n.δ
(c)=new
n.δ2
(λtmp.a(reverseseq
n,δ
fe)
n.δ2
(fst tmp);c(sndtmp)))
[0350]
c(copyseq
n,δ
e)
n.δ2
(c)=new
n.δ
(λtmp.a(copyseq
n,δ
e)
n.δ
(fst tmp);c(snd tmp)))
[0351]
c(transpar
m,n,δ
e)
m.n.δ2
(c)=new m.n.δ(λtmp.a(transpar
m,n,δ
e)
m.n.δ
(fst tmp);c(sndtmp)))
[0352]
codegen
exp[num]
(sqrt e,η,[])=(sqrt codegen
exp[num]
(e,η,[]))
[0353]
codegen
exp[num]
(abs e,η,[])=(abs codegen
exp[num]
(e,η,[]))
[0354]
codegen
exp[idx[n]]
(idxpred n,η,[])=(n-1)
[0355]
codegen
exp[idx[n]]
(addidx e1 e2,η,[])=(codegen
exp[idx[n]]
(e1,η,[]) codegen
exp[idx[n]]
(e2,η,[]))
[0356]
codegen
exp[idx[n]]]
(subidx e1 e2,η,[])=(codegen
exp[idx[n]]
(e1,η,[])-codegen
exp[idx[n]]
(e2,η,[]))
[0357]
codegen
exp[idx[n]]
(mulidx e1 e2,η,[])=(codegen
exp[idx[n]]
(e1,η,[])*codegen
exp[idx[n]]
(e2,η,[]))
[0358]
原dpia无法实现分块矩阵的代码生成无法实现,原因是在reduceseql需要对初始值进行赋值赋值,在向量运算中为num类型。但分块矩阵在使用reduceseql时是对小矩阵进行初始赋值,而在赋值命令assign的翻译规则中,只存在对num类型的规则,为此我们新添加了关于数组类型的规则。
[0359]
codegen
comm
(a:=n.δe,η,cnt)=codegen
comm
(for n(λi.idxacc a i:=δfun_idx e i),η,cnt)
[0360]
这条规则是对数组类型的赋值命令的显示翻译,将对于数组类型的赋值转换为顺序执行的for循环,其循环体表示为“a[i]=e[i];”,语义为依次对数组的元素依次赋值。
[0361]
添加这条规则之后,就可以完成分块矩阵的乘法代码生成,其中两个矩阵的大小分别为m1*n1与p1*n1,内部分块为m*n与p*n。
[0362]
#pragma omp parallel for
[0363]
for(int i0=0;i0《m1;i0 =1)
[0364]
{#pragma omp parallel for
[0365]
for(int i1=0;i1《p1;i1 =1)
[0366]
{float v2[n1][m2][p2];
[0367]
for(int i3=0;i3《n1;i3 =1)
[0368]
{for(int i4=0;i4《m2;i4 =1)
[0369]
{for(int i5=0;i5《p2;i5 =1)
[0370]
{float v6[n2];
[0371]
for(int i7=0;i7《n2;i7 =1)
[0372]
{v6[i7]=(a1[i0][i3][i4][i7]*b1[i1][i3][i5][i7]);}
[0373]
float v8;
[0374]
v8=0;
[0375]
for(int i9=0;i9《n2;i9 =1)
[0376]
{v8=(v6[i9] v8);}
[0377]
v2[i3][i4][i5]=v8;}}}
[0378]
float v10[m2][p2];
[0379]
for(int i11=0;i11《m2;i11 =1)
[0380]
{for(int i12=0;i12《p2;i12 =1)
[0381]
{v10[i11][i12]=mzero[i11][i12];}}
[0382]
for(int i11=0;i11《n1;i11 =1)
[0383]
{#pragma omp parallel for
[0384]
for(int i12=0;i12《m2;i12 =1)
[0385]
{for(int i13=0;i13《p2;i13 =1)
[0386]
{v10[i12][i13]=(v2[i11][i12][i13] v10[i12][i13]);}}}
[0387]
#pragma omp parallel for
[0388]
for(int i14=0;i14《m2;i14 =1)
[0389]
{for(int i15=0;i15《p2;i15 =1)
[0390]
{out[i0][i1][i14][i15]=v10[i14][i15];}}}}
[0391]
这样一个复杂的命令式程序的正确性很难直接判断,因此需要对这样的代码的生成过程进行形式化验证,以保证生成矩阵代码的可靠性。其中,图6表示为能够生成命令式代码的一些基本函数式矩阵程序。对生成的矩阵c程序进行了相应的速度测试,本次测试使用的处理器为英特尔i7-8565u(4核、8核)。本次测试主要分为生成的顺序执行的c代码和带openmp并行的c代码,主要测试结果如图7和图8所示。
[0392]
本发明未详述之处,均为本领域技术人员的公知技术。以上详细描述了本发明的较佳具体实施例。应当理解,本领域的普通技术人员无需创造性劳动就可以根据本发明的构思作出诸多修改和变化。因此,凡本技术领域中技术人员依本发明的构思在现有技术的基础上通过逻辑分析、推理或者有限的实验可以得到的技术方案,皆应在由权利要求书所确定的保护范围内。
再多了解一些

本文用于企业家、创业者技术爱好者查询,结果仅供参考。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

相关文献