2011-02-11 26 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終止內核與「沒有更多的內存可用」。

相關問題