Wolfram mathematica Mathematica:使用simplify进行公共子表达式消除和强度缩减
所以最近我一直在玩弄Mathematica的模式匹配和术语重写如何在编译器优化中得到很好的应用……试图高度优化循环内部的短代码块。减少计算表达式所需工作量的两种常见方法是识别多次出现的子表达式并存储结果,然后在后续点使用存储的结果来保存工作量。另一种方法是尽可能使用更便宜的操作。例如,我的理解是,平方根比加法和乘法需要更多的时钟周期。明确地说,我感兴趣的是计算表达式所需的浮点运算成本,而不是Mathematica计算它所需的时间 我的第一个想法是,我将使用Mathematica函数来解决开发问题。可以指定一个复杂度函数来比较两个表达式的相对简单度。我将使用相关算术运算的权重创建一个表达式,并将表达式的LeafCount添加到其中,以说明所需的赋值操作。这解决了强度方面的降低问题,但正是消除了常见的子表达式使我绊倒了 我正在考虑将公共子表达式消除添加到可能的转换函数中,以简化使用。但是对于一个大的表达式,可能有许多可能的子表达式可以被替换,在看到表达式之前,不可能知道它们是什么。我已经编写了一个函数,它给出了可能的替换,但是您指定的转换函数似乎只需要返回一个可能的转换,至少从文档中的示例中是这样。你有没有想过如何绕过这个限制?对于simplify如何使用可能暗示前进方向的转换函数,有人有更好的想法吗 我想象Simplify的幕后工作是做一些动态编程,尝试对表达式的不同部分进行不同的简化,并返回复杂度最低的部分。我自己尝试使用常见的代数简化(如factor和collect)来做动态规划会更好吗 编辑:我添加了生成可能要删除的子表达式的代码Wolfram mathematica Mathematica:使用simplify进行公共子表达式消除和强度缩减,wolfram-mathematica,compiler-optimization,Wolfram Mathematica,Compiler Optimization,所以最近我一直在玩弄Mathematica的模式匹配和术语重写如何在编译器优化中得到很好的应用……试图高度优化循环内部的短代码块。减少计算表达式所需工作量的两种常见方法是识别多次出现的子表达式并存储结果,然后在后续点使用存储的结果来保存工作量。另一种方法是尽可能使用更便宜的操作。例如,我的理解是,平方根比加法和乘法需要更多的时钟周期。明确地说,我感兴趣的是计算表达式所需的浮点运算成本,而不是Mathematica计算它所需的时间 我的第一个想法是,我将使用Mathematica函数来解决开发问题
(*traverses entire expression tree storing each node*)
AllSubExpressions[x_, accum_] := Module[{result, i, len},
len = Length[x];
result = Append[accum, x];
If[LeafCount[x] > 1,
For[i = 1, i <= len, i++,
result = ToSubExpressions2[x[[i]], result];
];
];
Return[Sort[result, LeafCount[#1] > LeafCount[#2] &]]
]
CommonSubExpressions[statements_] := Module[{common, subexpressions},
subexpressions = AllSubExpressions[statements, {}];
(*get the unique set of sub expressions*)
common = DeleteDuplicates[subexpressions];
(*remove constants from the list*)
common = Select[common, LeafCount[#] > 1 &];
(*only keep subexpressions that occur more than once*)
common = Select[common, Count[subexpressions, #] > 1 &];
(*output the list of possible subexpressions to replace with the \
number of occurrences*)
Return[common];
]
冒着这个问题变得冗长的风险,我将给出一个小示例代码。我认为一个合适的表达式来尝试优化将是求解微分方程的经典方法
Input:
nextY=statements[y + 1/6 h (f[t, n] + 2 f[0.5 h + t, y + 0.5 h f[t, n]] +
2 f[0.5 h + t, y + 0.5 h f[0.5 h + t, y + 0.5 h f[t, n]]] +
f[h + t,
y + h f[0.5 h + t, y + 0.5 h f[0.5 h + t, y + 0.5 h f[t, n]]]])];
possibleTransformations=CommonSubExpressions[nextY]
transformed=eliminateCSE[nextY, First[possibleTransformations]]
Output:
{f[0.5 h + t, y + 0.5 h f[0.5 h + t, y + 0.5 h f[t, n]]],
y + 0.5 h f[0.5 h + t, y + 0.5 h f[t, n]],
0.5 h f[0.5 h + t, y + 0.5 h f[t, n]],
f[0.5 h + t, y + 0.5 h f[t, n]], y + 0.5 h f[t, n], 0.5 h f[t, n],
0.5 h + t, f[t, n], 0.5 h}
statements[r1[f[0.5 h + t, y + 0.5 h f[0.5 h + t, y + 0.5 h f[t, n]]]],
y + 1/6 h (2 r1 + f[t, n] + 2 f[0.5 h + t, y + 0.5 h f[t, n]] +
f[h + t, h r1 + y])]
最后,下面是判断不同表达式的相对成本的代码。在这一点上,权重是概念性的,因为这仍然是我正在研究的一个领域
Input:
cost[e_] :=
Total[MapThread[
Count[e, #1, Infinity, Heads -> True]*#2 &, {{Plus, Times, Sqrt,
f}, {1, 2, 5, 10}}]]
cost[transformed]
Output:
100
要识别重复的子表达式,可以使用如下内容
(*helper functions to add Dictionary-like functionality*)
index[downvalue_,
dict_] := (downvalue[[1]] /. HoldPattern[dict[x_]] -> x) //
ReleaseHold;
value[downvalue_] := downvalue[[-1]];
indices[dict_] :=
Map[#[[1]] /. {HoldPattern[dict[x_]] -> x} &, DownValues[dict]] //
ReleaseHold;
values[dict_] := Map[#[[-1]] &, DownValues[dict]];
items[dict_] := Map[{index[#, dict], value[#]} &, DownValues[dict]];
indexQ[dict_, index_] :=
If[MatchQ[dict[index], HoldPattern[dict[index]]], False, True];
(*count number of times each sub-expressions occurs *)
expr = Cos[x + Cos[Cos[x] + Sin[x]]] + Cos[Cos[x] + Sin[x]];
Map[(counts[#] = If[indexQ[counts, #], counts[#] + 1, 1]; #) &, expr,
Infinity];
items[counts] // Column
作者在这里还实现了一些例程: 我将它打包到一个*.M文件中,并修复了一个bug(如果表达式没有重复的子表达式,它就会消失),我正在尝试查找作者的联系信息,看看是否可以将其修改后的代码上载到pastebin或其他任何地方
编辑:我已获得作者的上传许可,并已将其粘贴到此处:我试图模仿此博客上出现的字典压缩功能: 这是我做的:
DictionaryCompress[expr_, count_, size_, func_] := Module[
{t, s, rule, rule1, rule2},
t = Tally@Level[expr, Depth[expr]];
s = Sort[
Select[{First@#, Last@#, Depth[First@#]} & /@
t, (#[[2]] > count && #[[3]] > size) &], #1[[2]]*#1[[3]] < #2[[
2]]*#2[[2]] &];
rule = MapIndexed[First[#1] -> func @@ #2 &, s];
rule = (# //. Cases[rule, Except[#]]) & /@ rule;
rule1 = Select[rule, ! FreeQ[#, Plus] &];
rule2 = Complement[rule, rule1];
rule = rule1 //. (Reverse /@ rule2);
rule = rule /. MapIndexed[ Last[#1] -> func @@ #2 &, rule];
{
expr //. rule,
Reverse /@ rule
}
];
poly = Sum[Subscript[c, k] x^k, {k, 0, 4}];
sol = Solve[poly == 0, x];
expr = x /. sol;
Column[{Column[
MapIndexed[
Style[TraditionalForm[Subscript[x, First[#2]] == #], 20] &, #[[
1]]], Spacings -> 1],
Column[Style[#, 20] & /@ #[[2]], Spacings -> 1, Frame -> All]
}] &@DictionaryCompress[expr, 1, 1,
Framed[#, Background -> LightYellow] &]
DictionaryCompress[expr\u,count\u,size\u,func\u]:=模块[
{t,s,规则,规则1,规则2},
t=Tally@Level[expr,Depth[expr]];
s=排序[
选择[{First@#、Last@#、Depth[First@#]}&/@
t、 (#[[2]]>计数和大小)&],#1[[2]]*#1[[3]]]<#2[[
2]]*#2[[2]] &];
rule=MapIndexed[First[#1]>func@@@2&,s];
规则=(#//.Cases[规则,除[#]]外])和/@rule;
规则1=选择[规则,!FreeQ[#,Plus]&];
规则2=补充[规则,规则1];
规则=规则1//(反向/@rule2);
rule=rule/.MapIndexed[Last[#1]>func@@@2&,rule];
{
expr/.规则,
反向/@规则
}
];
poly=Sum[下标[c,k]x^k,{k,0,4}];
sol=Solve[poly==0,x];
expr=x/。溶胶;
列[{列[
地图索引[
风格[传统形式[下标[x,第一个[#2]]==#2],20][[
1] ]],间距->1],
列[样式[#,20]和/#[[2]],间距->1,框架->全部]
}]&@DictionaryCompress[expr,1,1,
带边框[#,背景->浅黄色]&]
嗨!你介意分享你的功能,让可能的替代?Tnx!我找到了“实验性的表达”。。。这似乎消除了重复计算。不过,Simplify对我来说仍然不起作用。顺便说一句,Simplify更像是一种启发式搜索,它尝试使用不同的转换规则来缩短表达式。它的强大之处在于知道许多特殊的函数关系,但我经常遇到表达式只有exp、+、-、/,*,Simplify找不到最简单的形式,而一些自定义重写规则a->b做得很好!我想知道构建一个基本的优化器还剩下多少工作
DictionaryCompress[expr_, count_, size_, func_] := Module[
{t, s, rule, rule1, rule2},
t = Tally@Level[expr, Depth[expr]];
s = Sort[
Select[{First@#, Last@#, Depth[First@#]} & /@
t, (#[[2]] > count && #[[3]] > size) &], #1[[2]]*#1[[3]] < #2[[
2]]*#2[[2]] &];
rule = MapIndexed[First[#1] -> func @@ #2 &, s];
rule = (# //. Cases[rule, Except[#]]) & /@ rule;
rule1 = Select[rule, ! FreeQ[#, Plus] &];
rule2 = Complement[rule, rule1];
rule = rule1 //. (Reverse /@ rule2);
rule = rule /. MapIndexed[ Last[#1] -> func @@ #2 &, rule];
{
expr //. rule,
Reverse /@ rule
}
];
poly = Sum[Subscript[c, k] x^k, {k, 0, 4}];
sol = Solve[poly == 0, x];
expr = x /. sol;
Column[{Column[
MapIndexed[
Style[TraditionalForm[Subscript[x, First[#2]] == #], 20] &, #[[
1]]], Spacings -> 1],
Column[Style[#, 20] & /@ #[[2]], Spacings -> 1, Frame -> All]
}] &@DictionaryCompress[expr, 1, 1,
Framed[#, Background -> LightYellow] &]