Игра жизни на F# с акселератором

Я пытаюсь написать жизнь на 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())

person John Palmer    schedule 22.03.2010    source источник
comment
В этом сообщении блога есть реализация игры в жизнь на GPU: tomasp.net/ блог/accelerator-life-game.aspx   -  person Robert    schedule 22.03.2010


Ответы (2)


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

В любом случае, если вы используете DX9Target, проблема может заключаться в том, что эта цель не должна поддерживать операции с целыми числами (поскольку точная эмуляция целочисленной арифметики на GPU просто невозможна с использованием DX9). Я считаю, что это также причина, по которой я использовал FloatParallelArray в своей реализации. У вас есть шанс попробовать X64MulticoreTarget, чтобы убедиться, что это сработает?

EDIT: я провел дополнительные исследования и (если я не упустил что-то важное) похоже, что это ошибка с методом 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.

РЕДАКТИРОВАНИЕ 2. Вот ответ членов команды акселератора:

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

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

person Tomas Petricek    schedule 22.03.2010
comment
использование цели x64 просто вызывает сбой FloatParallelArrays имеет ту же проблему, используя только левую четверть квадрата - person John Palmer; 23.03.2010
comment
Похоже, действительно есть какая-то ошибка - см. отредактированный ответ. - person Tomas Petricek; 23.03.2010
comment
Добавлен ответ от команды Accelerator - это действительно ошибка (или, точнее, техническое ограничение, которое невозможно решить для текущих технологий GPU). - person Tomas Petricek; 23.03.2010

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

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

person Stringer    schedule 25.03.2010