2011-08-30 58 views
1

我有以下問題。定義查詢速度:性能問題

我需要建立一個非常大的數字的定義(*),如

f[{1,0,0,0}] = 1 
f[{0,1,0,0}] = 2 
f[{0,0,1,0}] = 3 
f[{0,0,0,1}] = 2 
... 
f[{2,3,1,2}] = 4 
... 
f[{n1,n2,n3,n4}] = some integer 
... 

這僅僅是一個例子。參數列表的長度不一定是4,但可以是任何值。 我意識到,當參數列表的長度增加時,每個值的查找會以指數複雜度減慢。也許這並不奇怪,因爲很明顯,原則上Mathematica需要存儲多少定義的組合爆炸。儘管如此,我期望Mathematica很聰明,價值提取應該是不變的時間複雜度。顯然它不是。

有什麼辦法可以加快查找時間嗎?這可能與Mathematica內部處理符號定義查找的方式有關。它是否會在列表中找到匹配項?它似乎是這樣做的。

所有建議非常感謝。 祝你好運 卓然

(*)我正在研究隨機模擬軟件,它可以生成系統的所有配置,並且需要存儲每次配置發生的次數。在這個意義上,列表{n1,n2,...,nT}描述了系統的一個特定配置,表明有類型1的n1個粒子,類型2的n2個粒子,類型爲T的nT個粒子。可以是指數級的許多這樣的配置。

+8

無模式DownValue查找使用哈希,並分攤和適當的內存限制,恆定的時間。不管是什麼導致你的速度問題,它本身不可能是單獨的查找時間。 –

回答

9

您能否詳細說明您是如何計算查找時間的指數?

如果它確實是指數的,也許你可以加快速度通過在你的鑰匙(配置)使用Hash,然後存儲鍵值對像{{key1,value1},{key2,value2}}列表,不停地通過key排序,然後使用二進制搜索(這應該記錄時間)。這應該是非常快速的編碼,但在速度方面不是最佳的。

如果這還不夠快,可以考慮設置一個合適的哈希表實現(我認爲這是f[{0,1,0,1}]=3方法做的,沒有檢查)。

但放緩的一些玩具例子是進一步進行有益的......

編輯:我只是想

test[length_] := Block[{f}, 
    Do[ 
    f[RandomInteger[{0, 10}, 100]] = RandomInteger[0, 10];, 
    {i, 1, length} 
    ]; 
    f[{0, 0, 0, 0, 1, 7, 0, 3, 7, 8, 0, 4, 5, 8, 0, 8, 6, 7, 7, 0, 1, 6, 
     3, 9, 6, 9, 2, 7, 2, 8, 1, 1, 8, 4, 0, 5, 2, 9, 9, 10, 6, 3, 6, 
    8, 10, 0, 7, 1, 2, 8, 4, 4, 9, 5, 1, 10, 4, 1, 1, 3, 0, 3, 6, 5, 
    4, 0, 9, 5, 4, 6, 9, 6, 10, 6, 2, 4, 9, 2, 9, 8, 10, 0, 8, 4, 9, 
    5, 5, 9, 7, 2, 7, 4, 0, 2, 0, 10, 2, 4, 10, 1}] // timeIt 
    ] 

timeIt定義以準確的時間,即使短期運行如下:

timeIt::usage = "timeIt[expr] gives the time taken to execute expr, 
    repeating as many times as necessary to achieve a total time of \ 
1s"; 

SetAttributes[timeIt, HoldAll] 
timeIt[expr_] := Module[{t = Timing[expr;][[1]], tries = 1}, 
    While[t < 1., 
    tries *= 2; 
    t = Timing[Do[expr, {tries}];][[1]]; 
    ]; 
    Return[t/tries]] 

然後

out = {#, test[#]} & /@ {10, 100, 1000, 10000, 100000, 100000}; 
[email protected] 

enter image description here

(也適用於較大的運行)。所以在這裏似乎不變。

3

假設你輸入你的信息不喜歡

f[{1,0,0,0}] = 1 
f[{0,1,0,0}] = 2 

但到N1 N2 X N3 X N4 X矩陣m

m[[2,1,1,1]] = 1 
m[[1,2,1,1]] = 2 

(你甚至可以輸入值不是f[{1,0,0,0}]=1,而是f[{1,0,0,0},1]

f[li_List, i_Integer] := Part[m, Apply[Sequence, li + 1]] = i; 
    f[li_List] := Part[m, Apply[Sequence, li + 1]]; 

你必須初始化m例如通過m = ConstantArray[0, {4, 4, 4, 4}];

讓我們比較計時:

testf[z_] := 
    (
    Do[ f[{n1, n2, n3, n4}] = RandomInteger[{1,100}], {n1,z}, {n2,z}, {n3,z},{n4,z}]; 
    First[ Timing[ Do[ f[{n2, n4, n1, n3}], {n1, z}, {n2, z}, {n3, z}, {n4, z} ] ] ] 
); 
Framed[ 
    ListLinePlot[ 
     Table[{z, testf[z]}, {z, 22, 36, 2}], 
     PlotLabel -> Row[{"DownValue approach: ", 
          Round[MemoryInUse[]/1024.^2], 
          " MB needed" 
         }], 
     AxesLabel -> {"n1,n2,n3,n4", "time/s"},ImageSize -> 500 
    ] 
] 
Clear[f]; 
testf2[z_] := 
    (
    m = RandomInteger[{1, 100}, {z, z, z, z}]; 
    f2[ni__Integer] := m[[Sequence @@ ({ni} + 1)]]; 
    First[ Timing[ Do[ f2[{n2, n4, n1, n3}], {n1, z}, {n2, z}, {n3, z}, {n4, z}] ] ] 
) 
Framed[ 
    ListLinePlot[ 
     Table[{z, testf2[z]}, {z, 22, 36, 2}], 
     PlotLabel -> Row[{"Matrix approach: ", 
         Round[MemoryInUse[]/1024.^2], 
         " MB needed" 
         }], 
     AxesLabel -> {"n1,n2,n3,n4", "time/s"}, ImageSize -> 500 
    ] 
] 

DownValues approach Matrix approach

因此,對於較大的設置信息的矩陣方法似乎清楚preferrable。

當然,如果你有真正的大數據,比如說你的RAM有更多的GB,那麼你只需要 就必須使用數據庫和DatabaseLink。

+1

對於大型配置空間,這會產生問題:如果配置長度爲n,每個位置都有m個狀態,那麼預先分配的矩陣大小爲n^m;所以即使是1d經典的伊辛模型也只限於30個網站。如果配置空間是稀疏採樣的(我認爲這是首先進行隨機模擬的要點),那麼基於「基於DownValues」的方法是可以的。這可以通過使用稀疏矩陣的方法來處理,並且瞭解他們在速度方面的表現會很有趣。 – acl