pra*_*nak 9 haskell data-parallel-haskell
我试图使用DPH实现nqueens问题,但我最终得到了无法向量化GHC.Prim.Int#错误.当我搜索错误时,我发现了一个GHC Bug,它讨论了用于模式匹配的矢量化文字(http://haskell.1045720.n5.nabble.com/GHC-5702-Can-t-vectorise-pattern-matching-on -numeric-文字-td5076659.html).我不确定这是不是同一个bug.我的代码如下,
{-# LANGUAGE ParallelArrays #-}
{-# OPTIONS_GHC -fvectorise #-}
module NQueensP (nqueens_wrapper)
where
import qualified Prelude
import Data.Array.Parallel
import Data.Array.Parallel.Prelude
import Data.Array.Parallel.Prelude.Int as I
import qualified Data.Array.Parallel.PArray as P
isSafe i q n = isSafeHelper i (Prelude.zip (P.toList (toPArrayP q)) [n, n I.- 1..1])
where isSafeHelper i [] = True
isSafeHelper i (x:xs) = (i I.== Prelude.fst x) && I.abs(i I.-
(Prelude.fst x)) I./= I.abs(n I.- (Prelude.snd x)) &&
isSafeHelper i xs
nqueens_wrapper::Int -> PArray (PArray Int)
nqueens_wrapper n = toPArrayP (mapP toPArrayP (nqueens n 0))
nqueens::Int -> Int -> [:[:Int:]:]
nqueens n 1 = [:[:i:] | i <- (enumFromToP 1 n) :]
nqueens n k = [: [:i:] +:+ q | i <- oneton, q <- boards, isSafe i q k:]
where boards = nqueens n (k I.- 1)
oneton = (enumFromToP 1 n)
Run Code Online (Sandbox Code Playgroud)
如果我做错了,请告诉我.我正在使用GHC 7.4.1.
提前致谢.
小智 1
是的,这似乎与您提到的错误有关。您得到的错误源于这一行:
nqueens n 1 = [:[:i:] | i <- (enumFromToP 1 n) :]
Run Code Online (Sandbox Code Playgroud)
显然,您不能在-fvectorise启用的情况下使用 n 模式。让我们手动对该行进行脱糖以删除 n 模式:
nqueens n w | w I.== 1 = [:[:i:] | i <- (enumFromToP 1 n) :]
Run Code Online (Sandbox Code Playgroud)
我们现在已经处理了一条神秘的错误消息。这并不意味着我们已经完成了,因为下一条错误消息似乎同样神秘:
*** Vectorisation error ***
Tycon not vectorised: []
Run Code Online (Sandbox Code Playgroud)
(我认为)的问题isSafe是您使用了大量未使用-fvectorise. 这意味着您不能只使用链表 ( Tycon not vectorised: [])、Prelude.fst、Prelude.snd或Prelude.zip,除非您在模块中重新定义这些结构。(令人烦恼的是,如果不重新定义它,我什至无法使用(.)它。)
我们将不得不重写isSafe。我们看一下它的第一行:
isSafe i q n = isSafeHelper i (Prelude.zip (P.toList (toPArrayP q)) [n, n I.- 1..1])
Run Code Online (Sandbox Code Playgroud)
我们不能使用Prelude.zip,但我们可以使用zipP,这意味着我们不再需要转换q。然而,我们的递减列表应该使用 DPH 组合器重写。足够愚蠢的是,enumFromThenToP不存在,所以相反,我们会说mapP (n I.-) (enumFromToP 0 (n I.- 1))获得 的并行等价物[n, n I.- 1..1]。所以这一行变成:
isSafe i q n = isSafeHelper i (zipP q (mapP (n I.-) (enumFromToP 0 (n I.- 1))))
Run Code Online (Sandbox Code Playgroud)
现在isSafeHelper:
isSafeHelper i [] = True
isSafeHelper i (x:xs)
= (i I.== Prelude.fst x)
&& I.abs(i I.- (Prelude.fst x)) I./= I.abs(n I.- (Prelude.snd x))
&& isSafeHelper i xs
Run Code Online (Sandbox Code Playgroud)
因为Prelude.fst和Prelude.snd不可用,您可以通过在模式本身中提取元组的这些部分来解决此问题:
isSafeHelper i [] = True
isSafeHelper i ((x1,x2):xs)
= (i I.== x1)
&& I.abs(i I.- x) I./= I.abs(n I.- x2)
&& isSafeHelper i xs
Run Code Online (Sandbox Code Playgroud)
但是,当然,它仍然无法编译:您的参数将是一个并行列表,而不是 Prelude 样式的链表。为了解决这个问题,我们将使用函数以更实用的方式重写它all:
isSafeHelper i xs = all (isSafePredicate i) xs
isSafePredicate i (x1,x2)
= (i I.== x1)
&& I.abs(i I.- x) I./= I.abs(n I.- x2)
Run Code Online (Sandbox Code Playgroud)
all仍然适用于链接列表,但请注意,您不会在自己的函数中手动解构列表。allP如果有一个for 并行列表不是很好吗?会有,但是没有。不过写起来并不难:
allP :: (a -> Bool) -> [: a :] -> Bool
allP p arr = andP (mapP p arr)
Run Code Online (Sandbox Code Playgroud)
把它们放在一起,你可以写isSafe如下:
isSafe i q n = allP (isSafePredicate i n) (zipP q ntoone)
where
isSafePredicate i n (x1, x2)
= (i I.== x1)
&& I.abs(i I.- x1) I./= I.abs(n I.- x2)
ntoone = mapP (n I.-) (enumFromToP 0 (n I.- 1))
Run Code Online (Sandbox Code Playgroud)
nqueens_wrapper看起来不错。您的代码现在应该可以编译了。
一些注意事项:
*** Exception: crossMapP: not implemented,并且不知道如何修复它),但看起来应该有效。isSafe反过来重写是行不通的。如果您尝试使用列表Prelude中的数字Prelude,您最终会再次收到投诉Int#。我认为这是因为isSafe至少被一个矢量化函数使用nqueens。不包括Data.Array.Parallel.Prelude. 模块描述是这样说的:
该模块不应再在用户代码中显式导入。用户代码应仅导入 Parallel,并且在矢量化器支持类型类之前,还应导入特定于类型的模块。
不要为本地定义而疯狂。isSafeHelper在您的版本中缺少其n参数。