2011-02-11 69 views
7

如果我想从两个列表list1list2找到所有可能的和,我用的是Outer[]功能与Plus说明书中作为合并算:在Mathematica中,如何为任意数量的参数编译函数Outer []?

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 [email protected]@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. "

的事情是,我上午用一根S支持的功能,即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 [email protected]@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."

所以我的问题是:有没有办法来规避这个错误,或者,一种方法来计算从编译函数中的任意数量的列表中拉出的元素的所有可能的总和?

(另外,我不知道,如果“汇编”是一个合适的标签。请指教。)

非常感谢。

+0

关于您期望使用多少个列表以及多长时间?根据答案,编译可能不是执行此操作的最快方法。 – joebolte 2011-02-12 00:14:59

回答

10

一种方法是使用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}]]]]; 

大概可以做到更漂亮,但它的作品。例如:

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}}} 

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}} 

在这种情况下,您面临着编译的开销,因为您每次都会重新创建一个编译函数。您可以使用记忆化而典雅打这方面的开销,使用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}} 
+0

但是我不需要重新编译所有可能数量的列表吗?我想要一个单一的编译函数,根据输入,它可以处理不同数量的列表。 – 2011-02-11 20:33:11

3

这是我的第一篇文章。我希望我得到这个权利。

如果你输入的整数列表,我是持怀疑态度编译该功能,至少在数学7

例如价值的:

f = Compile[{{a, _Integer, 1}, {b, _Integer, 1}, {c, _Integer, 1}, {d, _Integer, 1}, {e, _Integer, 1}}, 
     Outer[Plus, a, b, c, d, e] 
    ]; 

a = RandomInteger[{1, 99}, #] & /@ {12, 32, 19, 17, 43}; 

Do[f @@ a, {50}] // Timing 

Do[Outer[Plus, ##] & @@ a, {50}] // Timing 

两个定时不显著不同对我来说,但当然这只是一个样本。关键仅仅是Outer与编译版本相比已经相当快了。

如果除编译速度之外还有其他原因,您可能会在Tuples而不是Outer中找到一些用处,但您仍然有编译函数需要张量输入的限制。

f2 = Compile[{{array, _Integer, 2}}, 
     Plus @@@ [email protected] 
    ]; 

f2[{{1, 3, 7}, {13, 25, 41}}] 

如果您的输入很大,那么可能需要采用不同的方法。鉴于整数列表的列表,该函数将返回可能的和和的方式的数量来获得每个总和:

f3 = [email protected][Sum[x^i, {i, p}], {p, #}] &; 

f3[{{1, 3, 7}, {13, 25, 41}}] 

这应该被证明是在许多情况下,更高效的内存。

a2 = RandomInteger[{1, 999}, #] & /@ {50, 74, 55, 55, 90, 57, 47, 79, 87, 36}; 

f3[a2]; // Timing 

MaxMemoryUsed[] 

这花了3秒钟和最小的内存,但试图应用外部到a2终止内核与“没有更多的内存可用”。

相关问题