J Fritsch
J Fritsch

Reputation: 3358

Translation of nested for loops into Haskell

I am struggling to translate this piece of a matrix multiplication in F# into Haskell (pls forget the parallel component):

Parallel.For(0, rowsA, (fun i->
        for j = 0 to colsB - 1 do
           for k = 0 to colsA - 1 do
              result.[i,j] <- result.[i,j] + a.[i,k] * b.[k,j]))  
    |> ignore

All I managed to put together is

sum (map (\(i, j, k) -> (my.read (a,i,k)) * (my.read (b, k, j))) [ (i, j, k) | i <- [0..rowsA], j <- [0..colsB], k <- [0..colsA] ]) 

--my.read reads the values of the respective cells from 'my' database

The intention is to read the cells of matrix a and matrix b from my database and do a matrix multiplication that eventually can be carried out in portions by different agents. This is controlled by setting the boundaries for i , j and k but is not relevant here.

I have tried to translate the above F# sample into haskell. The issue I am struggling with is that the result is not the sum over everything but there should be a list of results at the position i, j(F# result.[i,j] - the cell is the result matrix). I do not see how I could emit the right result (i,j). Maybe I must further take this apart?

Upvotes: 2

Views: 466

Answers (2)

wit
wit

Reputation: 1622

Try to divide

a :: [(a,a,a)]
a = [ (i, j, k) | i <- [0..rowsA], j <- [0..colsB], k <- [0..colsA] ]

into

b :: [[(a,a,a)]]
b = [ [ (i, j, k) | k <- [0..colsA]] | i <- [0..rowsA], j <- [0..colsB] ]

And you have a list of "lines" - matrix

And the list of sum is

m = [ [ (i, j, k) | k <- [0..colsA]] | i <- [0..rowsA], j <- [0..colsB] ]
listSum = map sum $ map (map (\(i,j,k) -> my_read (a,i,k) * my_read(b,k,j))) m

Upvotes: 3

bheklilr
bheklilr

Reputation: 54058

What exactly is the original code doing? Also, what is the type signature of my.read? I assume it would have a signature similar to Num b => (a, Int, Int) -> IO b, in which case this code will not even compile. If my . read is in the IO monad, then you could write it as:

myfunc = do
    let indices = [(i, j, k) | i <- [0..rowsA],
                               j <- [0..colsB],
                               k <- [0..colsA]]

    -- Since `my . read` returns a value in the IO monad,
    -- we can't just multiply the values returned.
    r1 <- mapM (\(i, j, k) -> (my . read) (a, i, k)) indices
    r2 <- mapM (\(i, j, k) -> (my . read) (b, k, j)) indices

    -- We can multiply r1 and r2 together though,
    -- since they are values extracted from the IO monad
    return $ sum $ zipWith (*) r1 r2

The best advice I can give you right now is to use ghci to figure out your types.

Upvotes: 3

Related Questions