The game of life in F # with the accelerator

I am trying to write life in F # using the v2 accelerator, but for some odd reason, my output is not square, despite the fact that all my arrays are square. It looks like everything except the rectangular area in the upper left corner of the matrix is ​​false. I have no idea how this can happen, since all my operations should process the entire array in the same way. Any ideas?

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 xy -> 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 xy -> 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 xyt -> 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()) 
+4
source share
2 answers

As Robert mentioned, I wrote an article that showed how to implement Game of Life in F # using Accelerator v2, so you can take a look at the working version. I remember that I had a similar problem, but I don’t know exactly what scenario.

In any case, if you are using DX9Target , the problem may be that this goal should not support integer operations (since emulating integer arithmetic on the GPU is definitely not possible using DX9). I believe this is also the reason why I ended up using FloatParallelArray in my implementation. Do you have a chance to try X64MulticoreTarget see if this works?

EDIT . I did some further research and (unless I missed something important), this seems to be a bug with the CompareEqual method. Here is a much simpler example that shows the problem:

 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") 

The expected result will be true (several times), but if you run it, it prints true only 4 times, and then prints 12 times false . I will ask someone from the Accelerator team and post the answer here. In the meantime, you can do the same as in my example, that is, simulate logical operations using FPA and avoid using BPA and CompareEqual .

EDIT 2 . Here is the response from the Accelerator team members:

This is due to the lack of accurate whole calculations on DX9 GPUs. Due to numerical jitter, the logical comparison of the whole with itself is not always calculated as exactly equal. (...)

So, in general, you cannot rely on BPA . The only option is to do what I suggested - to model logical values ​​using FPA (and possibly compare the number with some small delta neighborhood to avoid jitter caused by GPUs). However, this shoudl works with the X86MulticoreTarget - if you can find minimal repro showing what situations the library crashes in, it would be really useful!

+6
source

About accuracy issues: DX9-class GPUs do not have specialized integer hardware, so whole threads are interpreted as floating point streams (with the lack of precision that you handled).

DX10-class GPUs now support accurate 32-bit integers with all C bitwise operations. But this does not necessarily mean that they have true 32-bit integers. For example, in the current DX10 NVIDIA gen, integer math is performed with 24-bit integer units, thus 32-bit integer ops are emulated. The next NVIDIA DX11 gene will bring true 32-bit integers.

+2
source

Source: https://habr.com/ru/post/1304748/


All Articles