Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
302 views
in Technique[技术] by (71.8m points)

Matrix division in Haskell

What is wrong? This code is supposed to do matrix division by finding a times b inverse. I try to understand what its errors are but I fail to see how to link it.

import List
import Ratio

inverse :: [[Rational]] -> [[Rational]]
inverse mat = sweep ([], zipWith (++) mat unit) where
    unit = map (take (length mat)) $ iterate (0 :) (1 : [0,0..])
    sweep (xss, []) = xss
    sweep (xss, yss) = sweep (xss' ++ [ws], filter (any (/= 0)) yss') where
        Just (x : xs) = find ((/= 0) . head) yss
        ws = map (/ x) xs
        [xss', yss'] = map (map f) [xss, yss]
        f (y : ys) = zipWith (d e -> e - d * y) ws ys

How can I link it with

import Data.Array

mmult :: (Ix i, Num a) => Array (i, i) a -> Array (i, i) a -> Array (i, i) a 
mmult x y 
    | x1 /= y0 || x1' /= y0'  = error "range mismatch"
    | otherwise               = array ((x0, y1), (x0', y1')) l where
        ((x0, x1), (x0', x1')) = bounds x
        ((y0, y1), (y0', y1')) = bounds y
        ir = range (x0, x0')
        jr = range (y1, y1')
        kr = range (x1, x1')
        l  = [((i, j), sum [x ! (i, k) * y ! (k, j) | k <- kr

to do matrix division by multiplying a and b's inverse.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There seem to be a couple problems here. First of all, the definition of l in mmult seems to be incomplete. You start a list and start a pair, but never close them. Perhaps you meant:

l = [((i, j), sum [x ! (i, k) * y ! (k, j) | k <- kr]) | i <- ir, j <- jr]

The other problem that is inherent in, as you put it, linking those two modules, is that you are using different types for matricies in the two modules. The first one, where you invert a matrix, treats it as a list of lists. The second one, which multiplies two matricies, uses arrays. To combine the two, you need to be able to convert between the representations. Essentially, you need two operations:

fromListMatrix :: [[Rational]] -> Array (Int, Int) Rational
toListMatrix :: Array (Int, Int) Rational -> [[Rational]]

Once you have these, you can implement matrix division pretty easily.

divideMatrix :: Array (Int, Int) Rational -> Array (Int, Int) Rational -> Array (Int, Int) Rational
divideMatrix a b = mmult a (fromListMatrix (invert (toListMatrix b)))

On the implementation front, let's start with toListMatrix, as it is easier.

toListMatrix mat =

Now, we're going to need the bounds of the array, so

toListMatrix mat = let ((x0, x1), (x0', x1')) = bounds mat in

We will construct it row by row:

toListMatrix mat = let ((x0, x1), (x0', x1')) = bounds mat in
    [row | rowNum <- range (x1, x1')]

Each row is simply the elements of the matrix with a fixed row number:

toListMatrix mat = let ((x0, x1), (x0', x1')) = bounds mat in
    [[mat ! (pos, rowNum) | pos <- range (x0, x0')] | rowNum <- range (x1, x1')]

Moving on to fromlistMatrix:

fromListMatrix mat =

We want to associate each element with a position, and then feed the result to array, so:

fromListMatrix mat = array ((1, 1), (length (head mat), length mat)) indexedElems where
    indexedElems =

First we need to get the row numbers in place, so:

fromListMatrix mat = array (length (head mat), length mat) indexedElems where
    indexedElems = someFunction (zip [1..] mat)

Then we put in the position numbers:

fromListMatrix mat = array (length (head mat), length mat) indexedElems where
    indexedElems = someFunction (map addPositions (zip [1..] mat))
    addPositions (rowNum, elems) = zip [(pos, rowNum) | pos <- [1..]] elems

Now we have a list of rows of the indexed elements. We need to concatenate this into a single list:

fromListMatrix mat = array (length (head mat), length mat) indexedElems where
    indexedElems = concat (map addPositions (zip [1..] mat))
    addPositions (rowNum, elems) = zip [(pos, rowNum) | pos <- [1..]] elems

Finally, we clean up the code by changing map addPositions (zip [1..] mat) into a simpler form with zipWith:

fromListMatrix mat = array (length (head mat), length mat) indexedElems where
    indexedElems = concat (zipWith addPositions [1..] mat)
    addPositions rowNum elems = zip [(pos, rowNum) | pos <- [1..]] elems

You're done!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...