Per essere più precisi, ho il seguente piccolo programma innocua Repa 3:Quali sono le differenze chiave tra le API Repa 2 e 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
che prende così tanto tempo per elaborare un'immagine di 640x420 sul mio nucleo 2Ghz 2 Duo per notebook:
real 2m32.572s
user 4m57.324s
sys 0m1.870s
So che qualcosa deve essere sbagliato, perché ho ottenuto prestazioni molto migliori su algoritmi molto più complessi usando Repa 2. Sotto quell'API, il grande miglioramento che ho trovato è venuto dall'aggiungere una chiamata a "force" prima di ogni array transform (che ho capire per significare ogni chiamata per mappare, convogliare, attraversare ecc.). Non riesco a distinguere la cosa analoga da fare in Repa 3 - in effetti ho pensato che i nuovi parametri del tipo manifest dovrebbero garantire che non ci sia ambiguità su quando un array deve essere forzato? E come si inserisce la nuova interfaccia monadica in questo schema? Ho letto il bel tutorial di Don S, ma ci sono alcune lacune chiave tra le API di Repa 2 e 3 che sono poco discusse in AFAIK online.
Più semplicemente, c'è un modo minimo di impatto per correggere l'efficienza del programma di cui sopra?
Questa è un'ottima risposta! Avevo capito che computeP è il sostituto di "force", ma non avevo pensato di usarlo con la monade dell'identità. Apprezzo il vostro aiuto. – sacheie
Credo che la ragione per cui si usano i tipi di ritorno monadici sia perché l'idea di forzare qualcosa è strettamente legata alle forzature che avvengono in sequenza. C'è una spiegazione migliore in http://www.cse.unsw.edu.au/~chak/papers/LCKP12.html – Axman6