home *** CD-ROM | disk | FTP | other *** search
/ PSION CD 2 / PsionCDVol2.iso / Programs / 876 / hugs.sis / Matrix.hs < prev    next >
Encoding:
Text File  |  2000-09-21  |  3.5 KB  |  98 lines

  1. -- Some simple Hugs programs for manipulating matrices.
  2. --
  3.  
  4. module Matrix where
  5.  
  6. import List
  7.  
  8. type Matrix k = [Row k]          -- matrix represented by a list of its rows
  9. type Row k    = [k]              -- a row represented by a list of literals
  10.  
  11. -- General utility functions:
  12.  
  13. shapeMat    :: Matrix k -> (Int, Int)
  14. shapeMat mat = (rows mat, cols mat)
  15.  
  16. rows        :: Matrix k -> Int
  17. rows mat     = length mat
  18.  
  19. cols        :: Matrix k -> Int
  20. cols mat     = length (head mat)
  21.  
  22. idMat       :: Int -> Matrix Int
  23. idMat 0      = []
  24. idMat (n+1)  = [1:replicate n 0] ++ map (0:) (idMat n)
  25.  
  26. -- Matrix multiplication:
  27.  
  28. multiplyMat                     :: Matrix Int -> Matrix Int -> Matrix Int
  29. multiplyMat a b | cols a==rows b = [[row `dot` col | col<-b'] | row<-a]
  30.                 | otherwise      = error "incompatible matrices"
  31.                  where v `dot` w = sum (zipWith (*) v w)
  32.                        b'        = transpose b
  33.  
  34. -- An attempt to implement the standard algorithm for converting a matrix
  35. -- to echelon form...
  36.  
  37. echelon   :: Matrix Int -> Matrix Int
  38. echelon rs
  39.     | null rs || null (head rs) = rs
  40.     | null rs2                  = map (0:) (echelon (map tail rs))
  41.     | otherwise                 = piv : map (0:) (echelon rs')
  42.       where rs'            = map (adjust piv) (rs1++rs3)
  43.             (rs1,rs2)      = span leadZero rs
  44.             leadZero (n:_) = n==0
  45.             (piv:rs3)      = rs2
  46.  
  47. -- To find the echelon form of a matrix represented by a list of rows rs:
  48. -- 
  49. -- {first line in definition of echelon}:
  50. --  If either the number of rows or the number of columns in the matrix
  51. --  is zero (i.e. if null rs || null (head rs)), then the matrix is
  52. --  already in echelon form.
  53. -- 
  54. -- {definition of rs1, rs2, leadZero in where clause}:
  55. --  Otherwise, split the matrix into two submatrices rs1 and rs2 such that
  56. --  rs1 ++ rs2 == rs  and all of the rows in rs1 begin with a zero.
  57. --
  58. -- {second line in definition of echelon}:
  59. --  If rs2 is empty (i.e. if null rs2) then every row begins with a zero
  60. --  and the echelon form of rs can be found by adding a zero on to the
  61. --  front of each row in the echelon form of (map tail rs).
  62. --
  63. -- {Third line in definition of echelon, and definition of piv, rs3}:
  64. --  Otherwise, the first row of rs2 (denoted piv) contains a non-zero
  65. --  leading coefficient.  After moving this row to the top of the matrix
  66. --  the original matrix becomes  piv:(rs1++rs3).
  67. --  By subtracting suitable multiples of piv from (suitable multiples of)
  68. --  each row in (rs1++rs3) {see definition of adjust below}, we obtain a
  69. --  matrix of the form:
  70. --
  71. --          <----- piv ------>
  72. --          __________________
  73. --          0  |
  74. --          .  |
  75. --          .  |      rs'        where rs' = map (adjust piv) (rs1++rs3)
  76. --          .  |
  77. --          0  |
  78. --
  79. --  whose echelon form is  piv : map (0:) (echelon rs').
  80. --
  81.  
  82. adjust              :: Num a => Row a -> Row a -> Row a
  83. adjust (m:ms) (n:ns) = zipWith (-) (map (n*) ms) (map (m*) ns)
  84.  
  85. -- A more specialised version of this, for matrices of integers, uses the
  86. -- greatest common divisor function gcd in an attempt to try and avoid
  87. -- result matrices with very large coefficients:
  88. --
  89. -- (I'm not sure this is really worth the trouble!)
  90.  
  91. adjust'              :: Row Int -> Row Int -> Row Int
  92. adjust' (m:ms) (n:ns) = if g==0 then ns
  93.                                 else zipWith (\x y -> b*y - a*x) ms ns
  94.                         where g = gcd m n
  95.                               a = n `div` g
  96.                               b = m `div` g
  97. -- end!!
  98.