haskell中的查找表加速

时间:2015-11-05 19:00:23

标签: haskell gpgpu accelerate-haskell

我正在使用Haskell的加速库做一个有趣的副项目。我有一个我需要编写的函数,在纯Haskell中看起来像这样:

oddfac :: Int -> Int
oddfac n = product [1,3...n]

即。类似于阶乘函数,但只乘以奇数。我想在加速后端执行此功能,所以如果我理解正确,它需要成为Exp Int -> Exp Int类型。但是,出于性能原因,库不允许在Exp中评估任意表达式。幸运的是,我只需要为小值评估此函数,例如N'LT; = 7。我有想法定义一个预先计算的返回值的列表(或数组),以便简单地索引它将返回适当的值,并且每个评估将花费相同的时间量,这不是天真版本的情况。但是,我还没有找到办法做到这一点。我现在有两个问题:

1)有没有办法做到这一点,即定义一个硬编码数组,然后对其进行索引以在Exp a -> Exp b类型的函数中检索适当的值?

2)我是否以有效的方式处理事情?我如何思考这个问题是否有任何明显的缺陷?

更新

以下作品基于@ ErikR的回答及后续评论:

module Test where

import Data.Array.Accelerate as A
import Prelude as P

oddfac :: Exp Int -> Exp Int
oddfac n = (use $ A.fromList (Z :. 6) [1, 1, 3, 3, 15, 15]) A.! (index1 n)

alloddfac :: Acc (Vector Int)
alloddfac = A.map oddfac $ use $ A.fromList (Z :. 3) [1, 3, 5]

2 个答案:

答案 0 :(得分:2)

在我看来,您可以使用多种方法之一创建Acc (Array DIM1 Int),然后使用带有(!)函数的Accelerate index1来索引数组。

请注意,Vector aArray DIM1 a的别名。

以下是如何创建Acc (Vector Int)奇数阶乘(7个元素):

oddfacts :: Acc (Vector Int)
-- analogous to: take 7 $ scanl (*) 1 [3,5..]
oddfacts = A.scanl (*) (constant (1::Int)) $ A.enumFromStepN (A.index1 (constant (7::Int))) (constant (3::Int)) (constant (2::Int))

以及如何索引它:

foo :: Exp Int -> Exp Int
foo n = oddfacts A.! (A.index1 n)

以及如何使用条件:

bar :: Exp Int-> Exp Int
bar n = (n <=* (constant (7::Int))) ?
           ( oddfacts A.! (A.index1 n)
           , constant (0::Int)           -- return 0 if n > 7
           )

警告 - 我实际上并没有运行此代码,但它会进行类型检查。

accelerate-examples包中的示例包含许多使用数组生成函数(A.generate,A.scanl等)和索引函数(A.index1,A.index2等)的代码。)

答案 1 :(得分:1)

你可以从Haskell“扔过篱笆”进入Exp任意阵列到 (Shape sh, Elt e) => Lift Acc (Array sh e)个实例。因此,您可以在Haskell中创建查找表,然后只需lift

import Data.Array.Accelerate as A hiding (product)

oddfac :: Int -> Int
oddfac n = product [1,3..n]

oddfacs :: Vector Int
oddfacs = A.fromFunction (Z :. 7) (\(Z :. i) -> oddfac i)

lut :: Acc (Vector Int)
lut = A.lift oddfacs

然后通过索引到查找表lut来完成其余的@ ErikR答案。