F#中的生命游戏与加速器

Joh*_*mer 4 f# gpu accelerator conways-game-of-life

我试图用加速器V2写在F#的生活,但对于一些奇怪的原因,我的输出是不是尽管我所有的数组是方方 - 看起来一切,但一个矩形区域的矩阵的左上角被设置为假.我不知道这是怎么发生的,因为我的所有操作都应该平等对待整个阵列.有任何想法吗?

open Microsoft.ParallelArrays
open System.Windows.Forms
open System.Drawing
type IPA = IntParallelArray
type BPA = BoolParallelArray
type PAops = ParallelArrays
let RNG = new System.Random()
let size = 1024
let arrinit i = Array2D.init size size (fun x y -> i)
let target = new DX9Target()
let threearr = new IPA(arrinit 3)
let twoarr =   new IPA(arrinit 2)
let onearr =   new IPA(arrinit 1)
let zeroarr =  new IPA(arrinit 0)
let shifts = [|-1;-1|]::[|-1;0|]::[|-1;1|]::[|0;-1|]::[|0;1|]::[|1;-1|]::[|1;0|]::[|1;1|]::[]
let progress (arr:BPA) = let sums = shifts //adds up whether a neighbor is on or not
                                    |> List.fold (fun (state:IPA) t ->PAops.Add(PAops.Cond(PAops.Rotate(arr,t),onearr,zeroarr),state)) zeroarr
                         PAops.Or(PAops.CompareEqual(sums,threearr),PAops.And(PAops.CompareEqual(sums,twoarr),arr)) //rule for life
let initrandom () = Array2D.init size size (fun x y -> if RNG.NextDouble() > 0.5 then true else false)

type meform () as self= 
    inherit Form()
    let mutable array = new BoolParallelArray(initrandom())
    let timer = new System.Timers.Timer(1.0) //redrawing timer
    do base.DoubleBuffered <- true
    do base.Size <- Size(size,size)
    do timer.Elapsed.Add(fun _ -> self.Invalidate())
    do timer.Start()
    let draw (t:Graphics) = 
        array <- array |> progress
        let bmap = new System.Drawing.Bitmap(size,size)
        target.ToArray2D array
        |> Array2D.iteri (fun x y t ->
                 if not t then bmap.SetPixel(x,y,Color.Black))
        t.DrawImageUnscaled(bmap,0,0)

    do self.Paint.Add(fun t -> draw t.Graphics)

do Application.Run(new meform())
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 6

正如罗伯特所说,我写了一篇文章,展示了如何使用Accelerator v2 在F#中实现Game of Life,所以你可以看看它是否适合工作版本.我记得有类似的问题,但我不确切知道在什么情况下.

无论如何,如果你正在使用DX9Target那么问题可能是这个目标不应该支持整数运算(因为使用DX9精确地模拟GPU上的整数算术).我相信这也是我最终FloatParallelArray在我的实现中使用的原因.你有没有机会尝试X64MulticoreTarget看看是否有效?

编辑:我做了一些进一步的调查(除非我遗漏了一些重要的东西),这似乎是该CompareEqual方法的一个错误.这是一个更简单的示例,显示了该问题:

open Microsoft.ParallelArrays 

let target = new DX9Target() 
let zeros = new IntParallelArray(Array2D.create 4 4 0) 
let trues = target.ToArray2D(ParallelArrays.CompareEqual(zeros, zeros))

trues |> Array2D.iter (printfn "%A")
Run Code Online (Sandbox Code Playgroud)

预期的结果是true(几次),但如果你运行它,它只打印true4次然后打印12次false.我会问加速器团队的人并在这里发布答案.与此同时,你可以做我在我的例子中做的事情 - 也就是说,模拟布尔操作使用FPA和避免使用BPACompareEqual.

编辑2:以下是加速器团队成员的回复:

这与DX9 GPU上缺乏精确的整数计算有关.由于数值抖动,整数与其自身的布尔比较并不总是计算为完全相等.(......)

所以,总而言之,你不能真正依赖BPA.唯一的选择是按照我的建议 - 模拟布尔值使用FPA(并可能将数字与一些小的delta邻域进行比较,以避免GPU引起的抖动).然而,这个shoudl可以使用X86MulticoreTarget- 如果你能找到一些最小的repro,它可以显示库崩溃的情况,那将非常有用!