Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Speed up Data.Array row extraction and filtering

Tags:

arrays

haskell

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!

like image 525
bbtrb Avatar asked Oct 09 '22 10:10

bbtrb


1 Answers

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.

like image 166
Daniel Fischer Avatar answered Oct 13 '22 10:10

Daniel Fischer