在Mathematica中,如何为任意数量的参数编译函数Outer []?

Jes*_*del 8 wolfram-mathematica compilation

如果我想从两个列表中找到所有可能的和list1list2,我用的是Outer[]函数的规格Plus为合并算:

In[1]= list1 = {a, b}; list2 = {c, d}; Outer[Plus, list1, list2]

Out[1]= {{a + c, a + d}, {b + c, b + d}}

如果我希望能够处理任意数量的列表,请列出列表,

In[2]= listOfLists={list1, list2};

那么我知道如何找到所有可能的总和的唯一方法是使用Apply[]函数(有简写@@)以及Join:

In[3]= argumentsToPass=Join[{Plus},listOfLists]

Out[3]= {Plus, {a, b}, {c, d}}

In[4]= Outer @@ argumentsToPass

Out[4]= {{a + c, a + d}, {b + c, b + d}}

或者干脆

In[5]= Outer @@ Join[{Plus},listOfLists]

Out[5]= {{a + c, a + d}, {b + c, b + d}}

当我尝试编译时出现问题:

In[6]= Compile[ ..... Outer @@ Join[{Plus},listOfLists] .... ]

Compile::cpapot: "Compilation of Outer@@Join[{Plus},listOfLists]] is not supported for the function argument Outer. The only function arguments supported are Times, Plus, or List. Evaluation will use the uncompiled function. "

问题是,我正在使用支持的功能,即Plus.问题似乎完全在于Apply[]功能.因为如果我给外部加一个固定数量的列表,它可以正常工作

In[7]= Compile[{{bob, _Integer, 1}, {joe, _Integer, 1}}, Outer[Plus, bob, joe]]

Out[7]= CompiledFunction[{bob, joe}, Outer[Plus, bob, joe],-CompiledCode-]

但是一旦我使用Apply,它就会破裂

In[8]= Compile[{{bob, _Integer, 1}, {joe, _Integer, 1}}, Outer @@ Join[{Plus}, {bob, joe}]]

Out[8]= Compile::cpapot: "Compilation of Outer@@Join[{Plus},{bob,joe}] is not supported for the function argument Outer. The only function arguments supported are Times, Plus, or List. Evaluation will use the uncompiled function."

所以我的问题是:有没有办法绕过这个错误,或者,有办法计算从编译函数中任意数量的列表中提取的所有可能的元素总和?

(另外,我不确定"编译"是否是合适的标签.请告知.)

非常感谢.

Leo*_*rin 12

使用它的一种方法是以With编程方式创建编译函数:

Clear[makeCompiled];
makeCompiled[lnum_Integer] :=
 With[{listNames = Table[Unique["list"], {lnum}]},
   With[{compileArgs = {#, _Integer, 1} & /@ listNames},
      Compile @@ Join[Hold[compileArgs],
        Replace[Hold[Outer[Plus, listNames]], 
          Hold[Outer[Plus, {x__}]] :> Hold[Outer[Plus, x]], {0}]]]];
Run Code Online (Sandbox Code Playgroud)

它可以做得更漂亮,但它的工作原理.例如:

In[22]:= p2 = makeCompiled[2]
Out[22]= CompiledFunction[{list13,list14},Outer[Plus,list13,list14],-CompiledCode-]

In[23]:= p2[{1,2,3},{4,5}]
Out[23]= {{5,6},{6,7},{7,8}}

In[24]:= p3 = makeCompiled[3]
Out[24]= CompiledFunction[{list15,list16,list17},Outer[Plus,list15,list16,list17],-CompiledCode-]

In[25]:= p3[{1,2},{3,4},{5,6}]
Out[25]= {{{9,10},{10,11}},{{10,11},{11,12}}}
Run Code Online (Sandbox Code Playgroud)

HTH

编辑:

您可以将已编译的函数隐藏在另一个函数后面,以便它在运行时创建,而您实际上并未看到它:

In[33]:= 
Clear[computeSums]
computeSums[lists : {__?NumberQ} ..] := makeCompiled[Length[{lists}]][lists];

In[35]:= computeSums[{1, 2, 3}, {4, 5}]

Out[35]= {{5, 6}, {6, 7}, {7, 8}}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您将面临编译的开销,因为您每次都会重新创建编译函数.你可以通过memoization,使用Module变量进行持久化来优化地控制这个开销,来本地化你的memoized定义:

In[44]:= 
Clear[computeSumsMemoized];
Module[{compiled},
  compiled[n_] := compiled[n] = makeCompiled[n];
  computeSumsMemoized[lists : {__?NumberQ} ..] := compiled[Length[{lists}]][lists]];

In[46]:= computeSumsMemoized[{1, 2, 3}, {4, 5}]

Out[46]= {{5, 6}, {6, 7}, {7, 8}}
Run Code Online (Sandbox Code Playgroud)

  • 问题实际上并非如此简单.在一个过程语言中,它需要具有许多循环的嵌套循环,这取决于许多输入参数 - 我不知道如何在C或Java中执行此操作,确切地给出了这个公式(没有递归或其他技巧允许). (3认同)
  • 好的,对不起,我错过了一点.事实上,这不是处理任何列表组合的单个编译函数.相反,这是编译函数的集合(哈希表),可根据需要自动创建.对于单个编译函数,你确实遇到了"Apply"和"Outer"的问题,而且我不知道如何解决这个问题.但是,在实践中,它是否会产生很大的影响?每次提供新数量的列表时,由于编译,您将面临小的性能命中,但对于给定数量的列表,这只会发生一次. (2认同)