\section{Densematrix} ============================================================+ ================== A MATRIX IMPLEMENTATION ================== ============================================================+ This is an implementation of the types "matrix" and "vector" and their associated operations. It is most appropriate for dense matrices and vectors. The operations involved are: mmult matvecmult vmmult Multiplication madd vadd Addition msub vsub Subtraction vdot vouter Vector outer and dot products minverse the inverse of a matrix. msize vsize Find size of data {(#rows,#cols) for matrices} norm Norm of a vector (vdot v v) swaprow swapcol swaprow a b m ==> swap ath and bth rows of matrix m droprow drop the first row of a matrix. getrow getcol getrow i m ==> get the ith row of a matrix svmult scalar-vector multiplication update vupdate update (i,j) x m vupdate i x v ==> update a singe element vhd vtl mergevectors treat vectors like [Float] mkvec mkrvec mkcvec vector creation from [Float]. mkmat mkrmat mkcmat matrix creation from [[Float]]. mkcmat assumes the arg is column major. \begin{code} module Densematrix(Matrix,Vector, mmult, madd, msub, vouter, vdot, norm ,mneg ,mxpose,mident, msize, mkmat, mkrmat, mkcmat, mkvec, mkrvec, mkcvec, vadd, vsub, vsize, vneg, swaprow, swapcol ,droprow, getrow, getcol, subscript, vsubscript, vecpart, update ,vupdate, update2, vhd, vtl,mergevectors, matvecmult, vmmult,svmult, showmatrix,displayvector, minverse, veclist, matlist ) where import List (transpose) import Utils type Matrix = [[Float]] type Vector = [Float] mmult :: Matrix -> Matrix -> Matrix madd :: Matrix -> Matrix -> Matrix msub :: Matrix -> Matrix -> Matrix vadd :: Vector -> Vector -> Vector vsub :: Vector -> Vector -> Vector vsize :: Vector -> Int vouter :: Vector -> Vector -> Matrix vdot :: Vector -> Vector -> Float norm :: Vector -> Float vneg :: Vector -> Vector mneg :: Matrix -> Matrix mxpose :: Matrix -> Matrix mident :: Int -> Matrix msize :: Matrix -> (Int,Int) mkmat :: [[Float]] -> Matrix mkrmat :: [[Float]] -> Matrix mkcmat :: [[Float]] -> Matrix mkvec :: [Float] -> Vector mkrvec :: [Float] -> Vector mkcvec :: [Float] -> Vector veclist :: Vector -> [Float] matlist :: Matrix -> [[Float]] swaprow :: Int -> Int -> Matrix -> Matrix swapcol :: Int -> Int -> Matrix -> Matrix droprow :: Matrix -> Matrix getrow :: Int -> Matrix -> Vector getcol :: Int -> Matrix -> Vector subscript :: Matrix -> (Int,Int) -> Float vsubscript :: Vector -> Int -> Float vecpart :: Int -> Int -> Vector -> Vector update :: Matrix -> (Int,Int) -> Float -> Matrix update2 :: Matrix -> (Int,Int,Int) -> (Float,Float) -> Matrix vupdate :: Vector -> Int -> Float -> Vector vhd :: Vector -> Float vtl :: Vector -> Vector mergevectors :: [Vector] -> Vector minverse :: Matrix -> Matrix lu_decomp :: Matrix -> Lu_factor apply_factor :: Lu_factor -> Matrix -> Matrix forward :: [[Float]] -> [Int] -> Matrix -> Matrix backward :: [[Float]] -> [Int] -> Matrix -> Matrix showmatrix :: Matrix -> [Char] displayvector :: Vector -> [Char] matvecmult :: Matrix -> Vector -> Vector vmmult :: Vector -> Matrix -> Vector svmult :: Float -> Vector -> Vector \end{code} Notes: vmmult implements an inner product vector matrix multiplication. \begin{code} mmult m n = if compatible then [row i | i <- [0..((length m)-1)]] else error errmsg where compatible = (snd (msize m)) == (fst (msize n)) row i = [item i j | j <- [0..length(head n)-1]] item i j = vdot (m!!i) (map (!!j) n) errmsg = "mmult in densematrix: incompatible matrices " ++ (show (msize m)) ++ "*" ++ (show (msize n)) matvecmult m v = map (vdot v) m vmmult v m = res where res' = mmult [v] m res = concat res' svmult s v = map (*s) v vdot u v = sum (map2 (*) u v) norm v = vdot v v vneg = map negate vouter u v = [ map (k*) u | k <- v] madd a b = map2 vadd a b vadd u v = map2 (+) u v msub a b = map2 vsub a b vsub u v = map2 (-) u v vsize = (length) mneg rs = map (map negate) rs mxpose = transpose mident n = [ row k | k <- [1..n] ] where row i = (rep (i-1) 0) ++ [1] ++ (rep (n-i) 0) msize m = (length m , length(head m)) mkmat = id mkrmat = id mkcmat = transpose matlist = id mkvec = id mkrvec = id mkcvec = id veclist = id swaprow a b m = swapitems a b m swapcol a b m = map (swapitems a b) m swapitems :: Int -> Int -> [a] -> [a] swapitems a b xs = if a< b then toa ++ [xs!!b] ++ atob ++ [xs!!a] ++ pastb else if a > b then swapitems b a xs else xs where toa = take a xs atob = take (b-a-1) (drop (a+1) xs) pastb = drop (b+1) xs droprow = tail getrow i m = m!!i getcol i m = map (!!i) m subscript m (i,j) = m !! i !! j vsubscript v n = v!!n vecpart start intber = (take intber) . (drop start) update m (i,j) val = (take i m) ++ [(f (m!!i))] ++ (drop (i+1) m) where f xs = (take j xs) ++ [val] ++ (drop (j+1) xs) update2 m (i1,i2,j) (val1,val2) = (take i1 m) ++ [(f1 (m!!i1))] ++ [(f2 (m!!i2))] ++ (drop (i1+2) m) where f1 xs = (take j xs) ++ [val1] ++ (drop (j+1) xs) f2 xs = (take j xs) ++ [val2] ++ (drop (j+1) xs) vupdate v i val = (take i v) ++ [val] ++ (drop (i+1) v) vhd = head vtl = tail mergevectors = concat showmatrix m = "\n" ++ showmat m ++ "\n" showmat :: [Vector] -> [Char] showmat m = concat (map show_row m) where show_row v = (displayvector v) ++ "\n" displayvector = concat . (map (rjustify 13)) . (map show) \end{code} ============================================================ ============== LU DECOMPOSITION ============== ============== (to do inverses) ============== ============================================================ An lu_factor is a rather contorted representation of an LU factorization. The first list of vectors represents the L matrix, the second represents the U part. The third list contains information about how the matrix was permuted as it was decomposed. About the only thing one can do with an Lu_factor is to use it as an argument to apply_factor. Notes: minverse returns the inverse of a matrix. apply_factor takes one of these lu_factors and applies it to a matrix. This has the effect of multiplying the inverse of the factorized matrix by the given matrix. forward and backward do the forward and backward substitution on the pieces of an lu_factor. lu_decomp a returns ( l-vectors, u-vectors, p-vector ) A baroque representation of an LU factorization. pivot m pivots the matrix m. It returns the pivoted matrix and the row on which the pivot was perfomed. pivoting preserves diagonal elements. two rows and two columns are swapped. findpivot m finds the row/column to pivot on in (square) matrix m. the pivot row/col is the one with the element of greatest absolulte value on the diagonal. \begin{code} data Lu_factor = Lu_fact [[Float]] [[Float]] [Int] minverse m = apply_factor (lu_decomp m) (mident (fst(msize m))) apply_factor factor m = ((backward uvecs ps) . (forward lvecs ps)) m where (Lu_fact lvecs uvecs ps) = factor forward [] p b = b forward (l:ls) (p:ps) b = y1 : (forward ls ps y') where y' = msub y (vouter y1 l) (y1:y) = swaprow 0 p b backward [[u]] p y = map (map (/u)) y backward ((u1:u):us) (p:ps) (y:ys) = x where x = swaprow 0 p (xk:nextx) xk = map (/u1) (vsub y (vmmult u nextx)) nextx = backward us ps ys lu_decomp a = if (fst(msize a) == 1) then Lu_fact [] [[only_one]] [1] else Lu_fact (l:ls) (u:us) (p:ps) where Lu_fact ls us ps = lu_decomp a11' (a',p) = pivot a u11 = head u u = getrow 0 a' m = getcol 0 a' l = if not(u11 == 0) then tail (map (/ u11) m) else error ("div by 0 in lu: block is\n "++(show a)) a11 = map tail (tail a') a11' = msub a11 (vouter (tail u) l) only_one = subscript a (0,0) pivot :: Matrix -> (Matrix,Int) pivot m = (swaprow 0 p (swapcol 0 p m), p) where p = findpivot m findpivot :: Matrix -> Int findpivot a = loc_of_max 0 diag where diag = [a `subscript` (i,i) | i <- [0..(fst(msize a))-1] ] absmax = maxlist (map absfloat diag) loc_of_max n (x:xs) = if (absfloat x) == absmax then n else loc_of_max (n+1) xs absfloat :: Float -> Float absfloat n = if n < 0 then -n else n maxlist :: [Float] -> Float maxlist xs = foldl1 max xs \end{code}