2012-11-26 42 views
7

在GNU八度的代碼 -Haskell repa - 如何減少數組和返回索引?

[e, ix] = min(X); 

將返回最小元素,它的位置。 你如何在修復任意二進制函數?

這是我想出了:

min x = z $ foldl' f (e,0,0) es 
    where 
    (e:es) = toList x 
    f (a,ix,r) b = let ix' = ix+1 in if a < b then (a,ix',r) else (b,ix',ix') 
    z (a,ix,r) = (a,r) 

在上面的例子中,我們轉換repA的1D矩陣列表,然後使用與foldl」(從Data.List模塊)與兩個累加器 - 一個用於計算迭代(IX )和其他保存最小元素(r)的位置。但使用repa的全部重點是使用數組,而不是列表!

在修復中,數組類型(foldS和foldP)有兩個摺疊 - 但它們只能使用類型的函數(a - > a - > a) - 意思是說,我不能將具有累加器的元組傳遞給它。還有遍歷,它可以在原則上,一維數組減少對標量數組:

min x = traverse x to0D min 
    where 
    to0D (Z:.i) = Z 
    min f (Z) = ??? -- how to get elements for comparison? 

,想到的第一件事是

[f (Z:.i) | i <- [1..n]], where n = (\(Z:.i) -> i) $ extent x 

但是,這也將轉換數組列表,而不是在數組上進行計算。

+2

對於repa還不是很熟悉,但是在使用'foldP?'之前,不能將每個項目映射到一個元組。例如,可以使用最小元素的元組,最小元素的索引和子數組的長度來描述子數組。所以你把每個元素'x'映射到'(x,0,1)',然後使用'f(x,i,n)(y,j,m)=並行摺疊如果x hammar

+0

對不起,那當然應該是'maxBound'。 – hammar

+0

爲了在一個元組中使用foldP,你必須有這些元組的數組。它可以完成,但是這對圖像處理(數百萬個元素)是一種浪費。 – EvgenijM86

回答

3

我不是Repa專家,但這似乎適用於一維陣列。它可能可以適用於其他維度。

import Data.Array.Repa 

indexed arr = traverse arr id (\src [email protected](Z :. i) -> (src idx, i)) 

minimize arr = foldP f h t 
    where 
    (Z :. n) = extent arr 
    arr' = indexed arr 
    h = arr' ! (Z :. 0) 
    t = extract (Z :. 1) (Z :. (n-1)) arr' 
    f [email protected](valMin, iMin) [email protected](val, i) | val < valMin = x 
            | otherwise = min 
+0

我面臨同樣的問題,沒有找到其他解決方案。 – olek

0

重振殭屍後的風險,這裏是一個任意維解決方案,我摸索出(其中,審查意見,是@hammar建議到底是什麼)。由於foldAllP的怪異本質,我在合併元組時使用它作爲標識元素,因此還需要爲您正在尋找的數組的最小值提供上限。

import Data.Array.Repa 
import Data.Array.Repa.Eval 
import Data.Array.Repa.Repr.Unboxed 

minimize :: (Shape sh, Source r a, Elt a, Unbox a, Monad m, Ord a) => Array r sh a -> a -> m (a,sh) 
minimize arr upperBound = do 
     -- Zip the array with its (Int representation of) indices 
     let zippedWithIndex = Data.Array.Repa.traverse arr id (\f idx -> (f idx, toIndex (extent arr) idx)) 

     -- Define a function that compares two tuple of (a,Int) on the value of the first entry 
     let minimumIndex [email protected](v,_) t'@(v',_) = if v < v' then t else t' 

     -- Do a parallel fold of all elements in the array 
     (min,idx) <- foldAllP minimumIndex (upperBound, error "Empty array") zippedWithIndex 

     -- convert the indice back from its Int representation 
     return (min, fromIndex (extent arr) idx) 

當然,如果您的數組包含有Bounded實例的類型,你可以更方便的功能

minimize' arr = minimize arr maxBound 

一些測試,你可以在提示符下執行:

λ> let x = fromListUnboxed (ix2 2 2) [20, 30, 10, 40] :: Array U DIM2 Int 
λ> minimize' x 
(10,(Z :. 1) :. 0)