I have a very simple function in my application that does a lot of work and occupies the most computation time:
f :: Int -> Array (Int,Int) Int -> [Int]
f x arr = [v | v <- range (l,u), vv <- [g!(x,v)], vv /= 0]
where ((_,l), (_,u)) = bounds arr
What this does is: extract a row at index x
from the array arr
and return all the column indices with elements \= 0
. So, for instance, given the following matrix with bounds ((0,0),(2,2))
:
arr = [[0, 0, 5],
[4, 0, 3],
[0, 3, 1]] -- for simplicity in [[a]] notation
the expected output is
f 0 arr == [2]
f 1 arr == [0,2]
f 2 arr == [1,2]
How do I speed up f
and profile with more detail what actually takes most of the computation time in f (list construction, array access, etc)?
Thank you!
f x arr = [v | v <- range (l,u), vv <- [g!(x,v)], vv /= 0]
I suppose g
is a typo, it should be arr
.
Instead of range (l,u)
use [l .. u]
, the compiler may be able to optimise the former as well as the latter, but [l .. u]
is more idiomatic (and maybe the compiler can't optimise the former as well).
Don't create a pointless one-element list, you can use the direct test,
f x arr = [v | v <- [l .. u], arr!(x,v) /= 0]
The compiler may again be able to rewrite the former to the latter, but a) the latter is much clearer, and b) doesn't risk that the compiler can't.
To find out where time is spent, you can insert cost-centre annotations,
f x arr = [v | v <- {-# SCC "Range" #-} [l .. u], {-# SCC "ZeroTest" #-} (arr!(x,v) /= 0)]
but such annotations disable many optimisations (compiling for profiling always does), so the picture you get from profiling can be skewed and differ from what actually happens in the optimised programme.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With