Para ser más específico, tengo el siguiente programa poco de aspecto inocuo Repa 3:¿Cuáles son las principales diferencias entre las API Repa 2 y 3?
{-# LANGUAGE QuasiQuotes #-}
import Prelude hiding (map, zipWith)
import System.Environment (getArgs)
import Data.Word (Word8)
import Data.Array.Repa
import Data.Array.Repa.IO.DevIL
import Data.Array.Repa.Stencil
import Data.Array.Repa.Stencil.Dim2
main = do
[s] <- getArgs
img <- runIL $ readImage s
let out = output x where RGB x = img
runIL . writeImage "out.bmp" . Grey =<< computeP out
output img = map cast . blur . blur $ blur grey
where
grey = traverse img to2D luminance
cast n = floor n :: Word8
to2D (Z:.i:.j:._) = Z:.i:.j
---------------------------------------------------------------
luminance f (Z:.i:.j) = 0.21*r + 0.71*g + 0.07*b :: Float
where
(r,g,b) = rgb (fromIntegral . f) i j
blur = map (/ 9) . convolve kernel
where
kernel = [stencil2| 1 1 1
1 1 1
1 1 1 |]
convolve = mapStencil2 BoundClamp
rgb f i j = (r,g,b)
where
r = f $ Z:.i:.j:.0
g = f $ Z:.i:.j:.1
b = f $ Z:.i:.j:.2
que toma tanto tiempo para procesar una imagen de 640x420 en mi 2 GHz Core 2 Duo portátil:
real 2m32.572s
user 4m57.324s
sys 0m1.870s
Sé que algo debe estar bastante mal, porque he obtenido un rendimiento mucho mejor en algoritmos mucho más complejos usando Repa 2. Bajo esa API, la gran mejora que encontré vino de agregar una llamada a 'fuerza' antes de cada transformación de matriz (que entender que significa cada llamada para mapear, convulsionar, atravesar, etc.). No puedo entender lo análogo a hacer en Repa 3, de hecho, pensé que los nuevos parámetros de tipo de manifestación deberían garantizar que no haya ambigüedad sobre cuándo se debe forzar una matriz. ¿Y cómo encaja la nueva interfaz monádica en este esquema? He leído el buen tutorial de Don S, pero hay algunas brechas clave entre las API Repa 2 y 3 que se discuten poco en línea AFAIK.
Más simplemente, ¿hay una forma mínimamente impactante de corregir la eficacia del programa anterior?
¡Esta es una gran respuesta! Entendí que computeP es el reemplazo de 'force', pero no había pensado usarlo con la mónada de identidad. Aprecio tu ayuda. – sacheie
Creo que la razón para usar tipos de retorno monádico es porque la idea de forzar algo está muy ligada a las fuerzas que ocurren secuencialmente. Hay una mejor explicación en http://www.cse.unsw.edu.au/~chak/papers/LCKP12.html – Axman6