7

在 GNU Octave 中,这段代码 -

[e, ix] = min(X);

将返回最小元素及其位置。您如何在 repa 中为任意二进制函数执行此操作?

这就是我想出的:

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 的重点是使用数组,而不是列表!

在 repa 中,Array 类型有两个折叠(foldS 和 foldP) - 但它们只能具有类型 (a -> a -> a) 的功能 - 意思是,我不能将带有累加器的元组传递给它。还有 traverse,原则上可以将一维数组归约为标量数组:

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

但这也会将数组转换为列表,而不是对数组进行计算。

4

2 回答 2

3

我不是 Repa 方面的专家,但这似乎适用于一维数组。它可能适用于其他维度。

import Data.Array.Repa

indexed arr = traverse arr id (\src idx@(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 min@(valMin, iMin) x@(val, i) | val < valMin = x
                                    | otherwise = min
于 2012-11-29T20:04:15.977 回答
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 t@(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)
于 2016-06-29T21:55:22.597 回答