【问题标题】:exporting expressions to C, part 1 [wolfram-mathematica]将表达式导出到 C,第 1 部分 [wolfram-mathematica]
【发布时间】:2011-03-25 14:31:06
【问题描述】:

我有几个在 Mathematica 中生成的表达式,我想将它们导出到外部 C 程序的源代码中。 “CForm”几乎可以满足我的要求,只是求幂表示为对Power() 的调用。我的表达式只涉及小幂,所以我更喜欢 C 中的表达式使用内联乘法而不是调用 Power()

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

2*Power(hgt,2)*Power(k1inv,3)*mx0*Power(wid,2) + Power(hgt,2)*Power(k1inv,3)*Power(wid,3)

..而我想要生成的是:

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

我最初尝试选择表达式的内部 Power[..] 部分并使用 x_Symbol^y_Integer /; y > 1 :> Fold[Times, 1, Table[#1, {#2}]] 将其重新映射为乘法,但由于mathematica 立即将我精心生成的子表达式 a*a*a 重新转换回 Power[a,3] ; -) 我知道它只是想提供帮助,但我不知道如何让它停止,在这种情况下......

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

【问题讨论】:

    标签: wolfram-mathematica


    【解决方案1】:

    对于手头的情况,您可以使用以下内容:

    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:

    为了说明如何使用 SymbolicC 解决问题:

    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
    

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

    【讨论】:

    • 感谢您提供了一个很好的答案,我仍然对它的许多细微之处感到困惑(例如,为什么 HoldAll 用于 CForm? 整齐地使用 times 但随后在 @ 之外更改为 Times 987654333@。还有无证(?)使用HoldAll作为Apply的参数)
    • 我实际上删除了HoldAll,没有必要。另请参阅Block 的另一个解决方案。在Function 页面上记录了向纯函数添加属性的可能性,这是“更多信息”部分下的最后一项。如果我使用Function[Null,Hold[CForm[#]],HoldAll],则未记录的用途是。 IMO 最有趣的部分是 CFormHold 内部工作。所以,和其他形式一样,它不是常用的命令,而是表示输出的特殊模式。
    • 这是 CForm 的一个有趣行为;如果我复制输出然后粘贴到笔记本中,它似乎是 Hold 中的字符串值,例如Hold["2 hgt hgt k1inv k1inv k1inv mx0 wid wid + hgt hgt k1inv k1inv k1inv wid wid wid"] 并将相同的复制缓冲区粘贴到文本编辑器中或执行 Fullform 表明它正在被保留 Hold[CForm[2 hgt hgt k1inv k1inv k1inv mx0 wid wid + hgt hgt k1inv k1inv k1inv wid wid wid]];奇怪,但 CForm 的文档确实警告说它只是一个巧妙的语法糖衣。顺便说一句,非常感谢您的帮助,这解决了我的问题。
    • @Leonid Shifrin 我一直在研究 8 的“符号 C 生成”功能,但除了在 Mathematica 中表示 c 程序并可能以参数方式描述它的能力之外,以便您可以快速生成同一程序的多个版本,我不知道如何以合理的方式使用它。而且,回到问题上来,我看不出它如何用于替换 CForm。我可以想象您可以根据符号 C 概念编写 CForm 的替代品,但这是工作,我希望 Mathematica 为我做这件事。
    • @Sjoerd 坦率地说,我还没有使用太多。但是在这种特殊情况下,它并不太难并且代码大小大致相同(请参阅我的帖子的编辑),同时这也可以作为构建更大程序的构建块,因此可以积累自己的功能,例如最终将它们变成了一些小型 C 语言编译器,用于 Mathematica 的一小部分,适合个人需求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    • 2014-02-16
    • 1970-01-01
    相关资源
    最近更新 更多