He estado aprendiendo un poco de Haskell mediante la implementación de un algoritmo de selección de características.
Me he metido en el rendimiento a partir de los 20 años en un punto de referencia del conjunto de datos hacia 5s, donde el programa de C maneja el mismo conjunto de datos en 0.5 seg. El conjunto de datos se puede encontrar aquí. Para ejecutar, llamada el binario compilado así: ./Mrmr 10 test_nci9_s3.csv
.
El código está aquí, y estoy interesado en la optimización de mutualInfoInnerLoop:
mutualInfoInnerLoop :: Double -> Data.Vector.Unboxed.Vector (Int, Int) -> Double -> (Int, Int, Double) -> Double
mutualInfoInnerLoop n xys !acc (!i, !j, !px_py)
| n == 0 || px_py == 0 || pxy == 0 = acc
| otherwise = pxy * logBase 2 ( pxy / px_py ) + acc
where
pxy = ( fromIntegral . U.foldl' accumEq2 0 $ xys ) / n
accumEq2 :: Int -> (Int, Int) -> Int
accumEq2 !acc (!i', !j')
| i' == i && j' == j = acc + 1
| otherwise = acc
El analizador dice:
COST CENTRE MODULE %time %alloc
mutualInfoInnerLoop Main 75.0 47.9
mutualInfo Main 14.7 32.1
parseCsv Main 5.9 13.1
CAF GHC.Float 1.5 0.0
readInt Main 1.5 1.2
doMrmr Main 1.5 4.0
Que muestra mutualInfoInnerLoop como hacer el 50% de los créditos, con el 75% del tiempo de ejecución en el programa. Las asignaciones son desconcertantes.
También, el Núcleo, para que la función tiene una firma:
mutualInfoInnerLoop_rXG
:: GHC.Types.Double
-> Data.Vector.Unboxed.Base.Vector (GHC.Types.Int, GHC.Types.Int)
-> GHC.Types.Double
-> (GHC.Types.Int, GHC.Types.Int, GHC.Types.Double)
-> GHC.Types.Double
[GblId,
Arity=4,
Caf=NoCafRefs,
Str=DmdType U(L)LU(L)U(U(L)U(L)U(L))m]
Mostrando la mayoría de los parámetros como ser Constantemente evaluados y en caja (en contraposición a la estricta y sin caja).
He intentado BangPatterns, he tratado de MagicHash, y me parece que no puede hacer que vaya más rápido.
Alguien tiene alguna sugerencia?