Pregunta

Estoy tratando de escribir la vida en F # utilizando acelerador v2, pero por alguna extraña razón mi salida no es cuadrada a pesar de todas mis matrices ser cuadrado - Parece que todo, excepto un área rectangular en la parte superior izquierda de la matriz es se establece en false. No tengo idea de cómo esto podría estar ocurriendo ya que todas mis operaciones deben tratar a toda la serie igualmente. ¿Alguna idea?

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())
¿Fue útil?

Solución

Como se ha mencionado Robert, escribí un artículo que muestra cómo implementar juego de la vida en F # utilizando Acelerador v2, para que pueda echar un vistazo a que para una versión de trabajo. Recuerdo haber tenido un problema similar, pero no sé exactamente en qué escenario.

De todos modos, si usted está utilizando DX9Target entonces el problema puede ser que este objetivo no se supone para apoyar las operaciones con números enteros (debido a la emulación de la aritmética de enteros en la GPU, precisamente, no sólo es posible utilizando DX9). Creo que esto también es una razón por la que terminé usando FloatParallelArray en mi aplicación. ¿Tiene alguna oportunidad de probar el X64MulticoreTarget para ver si eso funcionaría?

Editar : Hice algunas investigaciones adicionales y (a menos que me falta algo importante) que parece ser un error con el método CompareEqual. Aquí es un ejemplo mucho más simple que muestra el problema:

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

El resultado esperado sería true (varias veces), pero si lo ejecuta, se imprime true sólo 4 veces y luego imprime 12 veces false. Le preguntaré a alguien del equipo de acelerador y publicar una respuesta aquí. Mientras tanto, se puede hacer lo mismo que hice en mi ejemplo -., Es decir, simular operaciones booleanas utilizando FPA y evitar el uso BPA y CompareEqual

EDIT 2 : Aquí es una respuesta de los miembros del equipo del acelerador:

  

Esto está relacionado con la falta de los cálculos de enteros precisas sobre las GPU DX9. Debido a la fluctuación numérica, una comparación de Boole de un entero con ella misma no siempre se calcula como exactamente iguales. (...)

Así, en resumen, realmente no se puede confiar en BPA. La única opción es hacer lo que le sugerí - Simular booleanos utilizando FPA (y posiblemente comparar el número con algún pequeño delta-barrio para evitar la trepidación causada por GPU). Este shoudl sin embargo trabajar con el X86MulticoreTarget - si se puede encontrar un poco de repro mínima que muestra situaciones en las que los choques de la biblioteca, que sería realmente útil

Otros consejos

Sobre cuestiones de precisión:. GPU de clase DX9 no tienen el hardware entero dedicado, por lo que las corrientes enteros se interpretan como corrientes de punto flotante (con la falta de precisión que has conocido)

GPU de clase DX10 hacen ahora exactos de apoyo 32 bits enteros con todas las operaciones de C bit a bit. Pero esto significa que no es necesario que tengan verdaderos números enteros de 32 bits ALU. Por ejemplo en DX10 actual NVIDIA gen matemáticas número entero se realiza con unidades de enteros de 24 bits, ops enteros de este modo de 32 bits se emulan. Próxima generación de NVIDIA DX11 traerá verdaderas unidades de enteros de 32 bits.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top