2011-11-21 21 views
5

我在我的應用程序,做了很多工作,並佔據了大部分的計算時間一個很簡單的功能:加快Data.Array行提取和過濾

f :: Int -> Array (Int,Int) Int -> [Int] 
f x arr = [v | v <- range (l,u), vv <- [g!(x,v)], vv /= 0] 
      where ((_,l), (_,u)) = bounds arr 

這樣做是:提取一行索引x來自數組arr並返回所有列索引與元素\= 0。所以,舉例來說,給出界限((0,0),(2,2))以下矩陣:

arr = [[0, 0, 5], 
     [4, 0, 3], 
     [0, 3, 1]] -- for simplicity in [[a]] notation 

預期的輸出是

f 0 arr == [2] 
f 1 arr == [0,2] 
f 2 arr == [1,2] 

如何加快f和更詳細的個人資料究竟需要大部分的計算時間在f(列表構造,數組訪問等)?

謝謝!

回答

2
f x arr = [v | v <- range (l,u), vv <- [g!(x,v)], vv /= 0] 

我想g是筆誤,應該是arr
而不是range (l,u)使用[l .. u],編譯器可能能夠優化前者和後者,但[l .. u]是更習慣(也許編譯器也不能優化前者)。
不要創建一個毫無意義的一個元素的列表,你可以使用直接測試,

f x arr = [v | v <- [l .. u], arr!(x,v) /= 0] 

編譯器可能會再次能夠前者重寫後者,但一),後者表現得更加明顯,和b)不會冒編譯器無法做到的風險。

要找出時間花費在哪裏,你可以將成本中心的註解,

f x arr = [v | v <- {-# SCC "Range" #-} [l .. u], {-# SCC "ZeroTest" #-} (arr!(x,v) /= 0)] 

但這樣的標註禁用許多的優化(編譯建檔總是這樣),所以你從分析得到的圖片可以偏斜並且與優化程序中實際發生的不同。

+0

我剛剛檢查了庫的源代碼,'range'應該和'[..]'一樣。 – sclv

+0

@sclv是的,它是一樣的。然而,編譯器必須剝離更多層。 「Int」應該沒有問題,但可能適用於其他類型。 –

+0

感謝您的評論。這確實有助於很多,我認爲問題在於列表的構建。我最終需要的是對列表的摺疊,所以最好直接在調用者中對數組進行摺疊。 – bbtrb