Игра в жизнь в F # с ускорителем - PullRequest
4 голосов
/ 22 марта 2010

Я пытаюсь написать жизнь на F #, используя ускоритель v2, но по какой-то странной причине мой вывод не квадратный, несмотря на то, что все мои массивы квадратные - кажется, что все, кроме прямоугольной области в верхнем левом углу матрицы, устанавливается в ложь. Я понятия не имею, как это может происходить, поскольку все мои операции должны обрабатывать весь массив одинаково. Есть идеи?

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

Ответы [ 2 ]

6 голосов
/ 22 марта 2010

Как уже упоминал Роберт, я написал статью, в которой показано, как реализовать Game of Life в F # с использованием Accelerator v2, поэтому вы можете взглянуть на это для рабочей версии.Я помню, что у меня была похожая проблема, но я не знаю точно, по какому сценарию.

В любом случае, если вы используете 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 и избегать использования BPA и CompareEqual.

EDIT 2 : Вот ответ от членов команды акселератора:

Это связано с отсутствием точных целочисленных вычислений на графических процессорах DX9.Из-за числового джиттера булево сравнение целого числа с самим собой не всегда вычисляется как точно равное.(...)

Итак, в общем, вы не можете действительно полагаться на BPA.Единственный вариант - сделать то, что я предложил - имитировать логические значения, используя FPA (и, возможно, сравнить число с некоторой небольшой дельта-окрестностью, чтобы избежать дрожания, вызванного графическими процессорами).Однако этот шоудл работает с X86MulticoreTarget - если вы можете найти какое-то минимальное повторение, показывающее, в каких ситуациях происходит сбой библиотеки, это было бы действительно полезно!

2 голосов
/ 25 марта 2010

О проблемах точности: графические процессоры класса DX9 не имеют выделенного целочисленного оборудования, поэтому целочисленные потоки интерпретируются как потоки с плавающей запятой (с недостаточной точностью, с которой вы встречались).

Графические процессоры класса DX10 теперь поддерживают точные 32-битные целые числа со всеми побитовыми операциями Си. Но это не обязательно означает, что они имеют истинные 32-битные ALU. Например, в текущем DX10 целочисленная математика NVIDIA выполняется с 24-битными целочисленными единицами, таким образом, эмулируются 32-битные целочисленные операции. DX11 следующего поколения NVIDIA принесет истинные 32-разрядные целочисленные единицы.

...