Wolfram mathematica 将表达式导出到C,第1部分[wolfram mathematica]

Wolfram mathematica 将表达式导出到C,第1部分[wolfram mathematica],wolfram-mathematica,Wolfram Mathematica,我有几个用Mathematica生成的表达式,我想导出到外部C程序的源代码中。“CForm”几乎实现了我想要的功能,除了求幂表示为调用Power()。我的表达式只涉及小的幂,因此我更希望C中的表达式使用内联乘法,而不是调用Power() 例如,CForm[2 hgt^2 k1inv^3 mx0 wid^2+hgt^2 k1inv^3 wid^3] 2*功率(hgt,2)*功率(k1inv,3)*mx0*功率(wid,2)+ 功率(hgt,2)*功率(k1inv,3)*功率(wid,3) …而我想

我有几个用Mathematica生成的表达式,我想导出到外部C程序的源代码中。“CForm”几乎实现了我想要的功能,除了求幂表示为调用
Power()
。我的表达式只涉及小的幂,因此我更希望C中的表达式使用内联乘法,而不是调用
Power()

例如,
CForm[2 hgt^2 k1inv^3 mx0 wid^2+hgt^2 k1inv^3 wid^3]

2*功率(hgt,2)*功率(k1inv,3)*mx0*功率(wid,2)+
功率(hgt,2)*功率(k1inv,3)*功率(wid,3)

…而我想产生的是:

2*hgt*hgt*k1inv*k1inv*mx0*wid*wid+
hgt*hgt*k1inv*k1inv*k1inv*wid*wid*wid

我最初尝试选择表达式的内部
幂[..]
部分,并使用
x\u符号^y\u整数/,将其重新映射到乘法;y>1:>Fold[Times,1,Table[#1,{#2}]
被mathematica立即将我精心生成的子表达式
a*a*a
右转为
幂[a,3]
;-)我知道它只是想帮忙,但我不知道如何让它停下来,在这种情况下


在我写这个问题时,我突然想到,我可以将
CForm
的输出捕获到一个字符串中,然后对其执行字符串模式匹配和操作,但这是一个好方法吗?我想我更喜欢将其作为Mathematica表达式进行处理,因为我需要重新映射,然后输出..?

对于手头的案例,您可以使用以下内容:

Clear[getCFormNoPowers];
getCFormNoPowers[expr_] :=
  Module[{times},      
   Apply[Function[code, Hold[CForm[code]], HoldAll],
     Hold[#] &[expr /. x_Symbol^y_Integer /; y > 1 :> 
         times @@ Table[x, {y}]] /. times -> Times]];
比如说,

In[52]:= getCFormNoPowers[2 hgt^2 k1inv^3 mx0 wid^2+hgt^2 k1inv^3 wid^3]

Out[52]= Hold[2*mx0*(hgt*hgt)*(wid*wid)*(k1inv*k1inv*k1inv) + 
hgt*hgt*(k1inv*k1inv*k1inv)* (wid*wid*wid)]
结果被包装在
Hold
中,以防止其计算返回到
Power
-s。您可以将其转换为 使用类似于
ToString[HoldForm@@result]
的内容,可以随时创建字符串。或者你可以进一步操纵

编辑:

作为替代方案,您可以执行以下操作:

Clear[getCFormNoPowers];
getCFormNoPowers[expr_] :=
 Block[{Times},
   SetAttributes[Times, {Flat, OneIdentity}];
   Apply[Function[code, Hold[CForm[code]], HoldAll],
   Hold[#] &[expr /. x_Symbol^y_Integer /; y > 1 :> Times @@ Table[x, {y}]]]];
这也将保持术语的原始顺序,并消除不必要的括号,因此这一个似乎与您的规格完全对应

通常,您可能希望了解版本8的新“符号C生成”功能。将代码映射到符号C表达式可能是一种更健壮的方法。这样,您就不必一直担心计算问题,并且您可以在最后使用新功能生成整个C程序

编辑2:

要说明如何使用SymbolicCC解决问题,请执行以下操作:

Needs["SymbolicC`"];

Clear[getCFormNoPowersSymC];
getCFormNoPowersSymC[expr_] :=
  Block[{Times},
   SetAttributes[Times, {Flat, Orderless}];
   ToCCodeString[
     expr /. x_Symbol^y_Integer /; y > 1 :> Times @@ Table[x, {y}] //.     
       HoldPattern[(op : (Times | Plus))[args__]] :>  COperator[op, {args}]]];

In[53]:= getCFormNoPowersSymC[2 hgt^2 k1inv^3 mx0 wid^2+hgt^2 k1inv^3 wid^3]

Out[53]= 2 * hgt * hgt * k1inv * k1inv * k1inv * mx0 * wid * wid + 
    hgt * hgt * k1inv * k1inv * k1inv * wid * wid * wid

这种方法有几个优点。也许这两个主要因素是可组合性(人们可以将这些表达式嵌套在它们的符号形式中,从较小的代码块中构建较大的代码块),以及一个不需要考虑太多计算的事实(我不需要在这里使用
Hold
的任何技巧)。

感谢您给出了一个很好的答案,我仍然对它的许多微妙之处感到困惑(例如,为什么
HoldAll
用于
CForm?
巧妙地使用
时间
,但随后在
Hold
之外改为
时间
。以及未记录的(?)使用
HoldAll
作为
应用
的参数),我实际上删除了
HoldAll
,这是不必要的。另请参见另一个带有
块的解决方案。将属性添加到纯函数的可能性记录在
函数
页面中,这是“更多信息”部分下的最后一项。如果我使用了
函数[Null,Hold[CForm[#]和HoldAll]
,则会使用未记录的用法。这里最有趣的是,
CForm
Hold
内部工作。因此,与其他形式一样,它不是通常的命令,而是表示输出的特殊模式;如果我复制输出,然后粘贴到笔记本中,它似乎是Hold中的一个字符串值,例如
Hold[“2 hgt hgt hgt hgt k1inv k1inv k1inv mx0 wid wid+hgt hgt hgt k1inv k1inv k1inv wid wid”]
但将相同的复制缓冲区粘贴到文本编辑器中或执行
Fullform
显示它正在被保存
Hold[CForm][2 hgt hgt k1inv k1inv k1inv mx0 wid wid+hgt hgt hgt k1inv k1inv k1inv wid wid wid]
;奇怪,但CForm的文档确实警告说它只是一个巧妙的语法糖衣。顺便说一句,非常感谢您的帮助,这解决了我的问题。@Leonid Shifrin我一直在研究“符号C代”8的功能,但除了用Mathematica表示c程序,或者用参数化方法描述它,以便您可以快速生成同一程序的多个版本之外,我还不知道如何以合理的方式使用它。回到问题上来,我不知道如何用它来代替CForm。我可以想象你可以用符号C的概念来代替CForm,但这是工作,我希望Mathematica能帮我这么做。@Sjoerd坦白地说,我还没有太多地使用它。但在这种情况下,它并不太难,代码大小也差不多(见我文章的编辑部分),而这也可以作为构建更大程序的构建块,因此可以像这样累积自己的函数,最终将它们转换为Mathematica的一小部分C的迷你编译器,以满足个人需要。