-- Glasgow Haskell 0.403 : BLAS ( Basic Linear Algebra System )
-- **********************************************************************
-- *                                                                    *
-- * FILE NAME : vbmatrix.hs		DATE : 5-3-1991                 *
-- *                                                                    *
-- * CONTENTS : Variable bandwidth matrix data type and operations      *
-- *            implemented by using one-dimension array type.          *
-- **********************************************************************

module VBmatrix(Vbm, defvbmat, makevbmat, incrvbmat, updvbmat,
                vbmatsub, boundvbmat, addrvbmat, lengrvbmat, fstclvbmat,
                diagadrvbm, displayvbmati, displayvbmatr) where

import Basics
import Vector

data Vbm a = VBMAT Int (Vec Int) (Vec a)

defvbmat   :: Int -> Vec Int -> Vec a -> Vbm a

makevbmat  :: Int -> Vec Int -> ( (Int,Int) -> a ) -> Vbm a
	-- make a variable bandwidth matrix, by giving the diagonal
	-- element address vector and a element value generator.

updvbmat   :: Vbm a -> [((Int,Int),a)] -> Vbm a
	-- update matrix with the given index-value association list

incrvbmat  :: (Num a) => Vbm a -> [((Int,Int),a)] -> Vbm a
        -- increase matrix by the given index-value association list

vbmatsub   :: Vbm a -> (Int,Int) -> a
	-- Access to the given matrix element value

boundvbmat :: Vbm a -> Int
	-- Return the bounds of the variable bandwidth matrix

addrvbmat  :: Vbm a -> (Int,Int) -> Int
	-- Return the address of element [i,j]

lengrvbmat :: Vbm a -> Int -> Int
        -- Return the length (the number of non-zero elements) of row i

fstclvbmat :: Vbm a -> Int -> Int
        -- Return the first non-zero element's  coulmn number on at row i

diagadrvbm :: Vbm a -> Vec Int
	-- Return the diagonal element address vector

displayvbmati  ::  Vbm Int -> [Char]

displayvbmatr  ::  Vbm Float -> [Char]

lengrvbmat (VBMAT n addiag elems) i =
	if (i==1) then 1
	else (vecsub addiag i) - (vecsub addiag (i-1))

fstclvbmat (VBMAT n addiag elems) i =
	if (i==1) then 1
	else i - ( lengrvbmat (VBMAT n addiag elems) i ) + 1

addrvbmat vbm  (i,j) =
	vecsub addiag i + j -  i
	where
	(VBMAT n addiag elementlist) = vbm

boundvbmat (VBMAT bounds addiag elementlist) = bounds

diagadrvbm (VBMAT bounds addiag elementlist) = addiag

defvbmat bounds addiag elementlist =
	VBMAT bounds addiag elementlist

makevbmat n addiag generator =
	VBMAT n addiag (makevec (vecsub addiag n) f)
	where
	f i    = elemts !! (i - 1)
	elemts = foldl  irow []  [1..n]
	irow ls i = ls ++ [ generator (i,j) | j<- [(fstcl i)..i] ]
	fstcl i   = if (i==1) then 1
		    else i - vecsub addiag i + vecsub addiag (i-1) + 1

incrvbmat vbm updates =
	VBMAT n addiag new_elements
        where
	(VBMAT n addiag elements) = vbm
	new_elements = incrvec elements new_s
	new_s = map (\((i,j),x) -> (addrvbmat vbm (i,j),x) ) updates

updvbmat vbm updates =
        VBMAT n addiag new_elements
        where
        VBMAT n addiag elements = vbm
        new_elements = updvec elements new_s
        new_s = map (\((i,j),x) -> (addrvbmat vbm (i,j),x) ) updates

vbmatsub vbm (i,j) =
	vecsub elements (addrvbmat vbm (i,j))
        where
        VBMAT n addiag elements = vbm

displayvbmati vbm =
	"<  \n" ++
	concat (map displayvec rows) ++
	"> \n"
	where
	rows = [rowi vbm i | i <- [1..n]]
	n = boundvbmat vbm

displayvbmatr vbm =
        "<  \n" ++
        concat (map displayvec rows) ++
        "> \n"
        where
	rows = [rowr vbm i | i <- [1..n]]
        n = boundvbmat vbm

rowi vbm i =
	makevec n f
	where
	n = boundvbmat vbm
	f j = if ( (j >= (fstclvbmat vbm i)) && (j <= i) ) then
		vbmatsub vbm (i,j)
	      else 0

rowr vbm i =
        makevec n f
        where
        n = boundvbmat vbm
        f j = if ( (j >= (fstclvbmat vbm i)) && (j <= i) ) then
                vbmatsub vbm (i,j)
              else 0.0
