\section{Matrix}

 =======================================================================
 This file has been created entirely by Brian D. Moe (Summer 1990)
 It contains all the "include" statements for the sparse and dense
 matrix operations.
 Converted to Haskell by Ian R McLelland and Cordelia V Hall (Nov 1992)
 =======================================================================

\begin{code}

module Matrix
         (Matrix, Vector, Block , Vec ,
          Block_list , Row_pos, Col_pos,
          mmult, mvmult, svmult,
          madd, msub,
          vadd, vsub,
          vdot, vouter,
          mneg, vneg,
          norm,
          mkmatrix,
          mkvector,
          mergevectors,
          mupdate, vupdate,
          msubscript, vsubscript,
          getrow,
          getcol,
          numrows,
          msize, vsize,
          showmatrix, showvector) where


import AbsDensematrix
import Utils

\end{code}

 We have replaced include of "densematrix" with import of
 AbsDensematrix, which imports Densematrix and exports the
 named objects with the new names (excluding some). The original
 include appears in comments in AbsDensematrix (cvh).


 The beginning of Sparsematrix_kludge,
 textually inserted because Matrix and Sparsematrix_kludge
 are now mutually recursive, and it doesn't seem worth
 maintaining them separately for now (cvh).

  ================================================================
  ================ A SPARSE MATRIX IMPLEMENTATION ================

  Written by Brian D. Moe (Summer 1990)
  Note:
      mupdate and vupdate have been included by Kamini Shenoi

  ================================================================


     This is a matrix/vector abstract type implementation designed
     for sparse, block stuctured matrices.  Included are several
     functions specific to solving linear systems for oil reservoir
     modelling. (e.g. precond & uncondition)


Implementation of Types


\begin{code}

mmult   :: Matrix -> Matrix -> Matrix
madd    :: Matrix -> Matrix -> Matrix
msub    :: Matrix -> Matrix -> Matrix
mvmult  :: Matrix -> Vector -> Vector
vadd    :: Vector -> Vector -> Vector
vsub    :: Vector -> Vector -> Vector
vdot    :: Vector -> Vector -> Scalar
vouter  :: Vector -> Vector -> Matrix
norm    :: Vector -> Scalar
mneg    :: Matrix -> Matrix
vneg    :: Vector -> Vector
svmult  :: Scalar -> Vector -> Vector

mupdate :: Matrix -> (Int,Int) -> Block -> Matrix
vupdate :: Vector -> Int -> Vec -> Vector

msubscript  :: Int -> Int -> Matrix -> Block
msubscript' :: Int -> Int -> Matrix -> [Block]
vsubscript  :: Int -> Vector -> Vec
getrow      :: Int -> Matrix -> [Block_tuple]
getcol      :: Int -> Matrix -> [Block_tuple]
numrows     :: Matrix -> Int
msize       :: Matrix -> (Int,Int)
vsize       :: Vector -> Int

mkmatrix   :: [[(Int,Int,Block)]] -> Matrix
mkvector   :: [Vec] -> Vector
mergevectors :: Vector -> Vector -> Vector

showmatrix :: Matrix -> [Char]
showvector :: Vector -> [Char]

type Row_pos        = Int
type Col_pos        = Int
type Block_tuple    = (Row_pos, Col_pos, Block)
type Block_list     = [Block_tuple]

type Matrix = Matrix_type
type Vector = Vector_type

type Matrix_type = [Block_list]
type Vector_type = [Vec]

type Scalar = Float
sadd       = (+)

mmult m1 m2 = error "unsupported matrix operation"

madd m1 m2 = error "unsupported matrix operation"

msub m1 m2 = error "unsupported matrix operation"


mneg m = map (map negtuple) m
                    where
                       negtuple (r, c, b) = (r, c, bneg b)


vadd v1 v2   = map2 vecadd v1 v2

vsub v1 v2   = map2 vecsub v1 v2

vdot v1 v2   = foldl1 sadd (map2 vecdot v1 v2)

vouter v1 v2   = error "unsupported vector operation"

norm v   = foldl1 sadd (map vecnorm v)

vneg v   = map vecneg v

svmult s v = map (svecmult s) v

mupdate m (i,j) val
   = [getrow k m |k <- [0..i-1]] ++ [(f(m!!i))]
      ++ [getrow l m | l <- [(i+1) .. (numrows m)-1]]
     where
        f xs = (take j xs) ++ [(i, (j+1), val)] ++ (drop (j+1) xs)

	
vupdate v i vc = (take i v) ++ [vc] ++ (drop (i+1) v)


showmatrix m
   = concat [ (showrow i)++"\n" | i<-[0..length(m)-1] ]
     where
	showrow i = concat [status i j | j<-[0..length(m)-1]]
	status i j
	   = if exist i j then "#"
	     else "."
	exist i j = j `elem` (row i)
	row i = [ col | (r,col,b) <- (m!!i) ]

showvector vs =  concat (map showvec vs)



mkmatrix = id


mkvector = id

mergevectors = (++)

\end{code}




 ================================================
 ================ MISC FUNCTIONS ================
 ================================================



 Roger Wainwrights's mvmult:  (used in mvmult elsewhere)

      For multiplying a sparse matrix by its
      vector counterpart.  (a list of vectors)

	mvmult :: Matrix -> Vector -> Vector

\begin{code}

mvmult rows v
   =  if ok then [ rvdot row v | row <- rows ]
      else error "Incompatible operands to large mvmult"
     where
        ok = (length rows) == (length v)

rvdot row v
     = foldl1 vecadd [bvecmult b (vsubscript c v) | (r,c,b) <- row]

\end{code}

 Notes:

   okindex checks that the number given won't be out of range for the
   given list. WARNING:  WILL HANG IF LIST IS INFINITE.

   msubscript' gets the block at a given location in a sparse matrix.

   msubscript gets the block at a given location in s sparse matrix,
   even if it isn't present.

   getrow gets the list of block tuples from the given row of a matrix

   getcol gets the list of block tuples from the given column of a matrix

   numrows returns the number of rows of blocks in a sparse matrix.

   strip_block returns the block part of a block tuple.

   vsubscript gets a piece of one of those chopped up vectors.


\begin{code}

okindex :: Int -> [a] -> Bool
okindex n m = (0<=n) && (n<=((length m) - 1)) -- testing (irm)


iscol :: Int -> Block_tuple -> Bool
iscol k (r,c,b) = (k==c)


msubscript' r c m
   = map strip_block (filter (iscol c) (getrow r m))

msubscript r c m
   = if thingee /= [] then (head thingee)
    else zero_block r c m
     where
        thingee = msubscript' r c m


getrow n m
   = if okindex n m then m !! n
     else error "getrow: index out of bounds"



getcol n m
   = concat [ filter (iscol n) row | row <- m ]


numrows m = length m

msize m = (length m,length (head m))

vsize v = length v



strip_block :: Block_tuple -> Block
strip_block (r,c,b) = b


vsubscript n v
   = if okindex n v then v!!n
     else error "vsubscript in matrix"

\end{code}

========== end of Sparsematrix_kludge ========================

\begin{code}

zero_block :: Int -> Int -> Matrix -> Block
zero_block i j m
   = mkblock (rep nrows (rep ncols 0))
     where
       (nrows,junk1) = block_size (head (getrow i m))
       (junk2,ncols) = block_size (head (getcol j m))
       block_size (r,c,b) = bsize b

\end{code}
