2010-03-22 47 views
4

我想用F#編寫生活中使用加速器V2,但由於一些奇怪的原因,我的輸出是不是正方形,儘管我的所有數組是正方形 - 看起來,除了矩形區域矩陣的左上角被設置爲false。我不知道這是如何發生的,因爲我所有的操作都應該平等地對待整個陣列。有任何想法嗎?加速器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()) 
+0

在這篇博文中有一個GPU上的生命遊戲實現:http://tomasp.net/blog/accelerator-life-game。aspx – Robert

回答

6

正如羅伯特提到的,我寫了一篇文章,介紹瞭如何使用加速器V2實現Game of Life in F#,所以你可以看一看,對於一個工作版本。我記得有類似的問題,但我不知道在什麼情況下。

無論如何,如果你正在使用DX9Target那麼問題可能是,這個目標是不應該支持的操作與整數(因爲模擬GPU的整數算術使用DX9恰恰僅僅是不可能的)。我相信這也是爲什麼我在我的實現中使用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") 

預期的結果將是true(多次),但如果你運行它,它打印true只有4次,然後打印12倍false。我會要求加速器團隊的成員在此發佈答案。同時,您可以像我在示例中那樣做同樣的事情 - 即使用FPA來模擬布爾操作,並避免使用BPACompareEqual

編輯2:下面是來自加速器團隊成員的答覆:

這與缺乏對DX9的GPU精確整數計算的。由於數字抖動,整數與自身的布爾比較並不總是完全相等。 (...)

因此,總之,你不能真正依靠BPA。唯一的選擇就是按照我的建議來做 - 使用FPA來模擬布爾值(也可以將數字與一些小的delta-neighborhood進行比較,以避免由GPU引起的抖動)。然而,這個shoudl與X86MulticoreTarget一起工作 - 如果你可以找到一些最小的repro來顯示庫在哪種情況下崩潰,這將非常有用!

+0

使用x64目標只是導致崩潰 FloatParallelArrays具有相同的問題,只使用廣場的左側四分之一 –

+0

它看起來像真的有一些錯誤 - 請參閱編輯答案。 –

+0

添加了加速器團隊的答案 - 這確實是一個錯誤(或者更具體地說,是當前GPU技術無法解決的技術限制)。 –

2

關於精度問題:DX9級GPU沒有專用的整數硬件,因此整數流被解釋爲浮點流(因爲您遇到了缺乏精度)。

DX10級別的GPU現在支持所有C位操作的精確32位整數。但這並不意味着它們具有真正的32位整數ALU。例如,在當前的DX10 NVIDIA Gen整數數學是用24位整數單位完成的,因此32位整數操作被仿真。下一代DX11 NVIDIA將帶來真正的32位整數單位。