Advertisement
jckuri

Matrix.hs (with Vectors instead of Lists, and Either monad)

Oct 18th, 2013
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- Matrix.hs (with Vectors instead of Lists, and Either monad)
  2. module Matrix where
  3.  
  4. import qualified Data.Vector as BV
  5. import qualified Data.Vector.Unboxed as UV
  6. import qualified System.Random as R
  7. import qualified Control.Monad as CM
  8.  
  9. isMatrixValid matrix =
  10.  if BV.length lengths == 0 then
  11.   False
  12.  else
  13.   (BV.all (== BV.head lengths) lengths)
  14.  where
  15.   lengths = BV.map UV.length matrix
  16.  
  17. newMatrix matrix =
  18.  if isMatrixValid matrix then Right matrix else Left "Matrix is not valid."  
  19.  
  20. fromListOfLists ll = newMatrix $ BV.fromList (map UV.fromList ll)
  21.  
  22. boxedToUnboxedVector boxed = UV.fromList $ BV.toList boxed
  23.  
  24. getMatrixSize matrix =
  25.  let
  26.   rows = BV.length matrix
  27.  in
  28.   if isMatrixValid matrix then
  29.    Right $ if rows == 0 then (0, 0) else (rows, UV.length $ BV.head matrix)
  30.   else
  31.    Left "Matrix cannot be measured because it is invalid."
  32.  
  33. at matrix (row,column) = (matrix BV.! row) UV.! column  
  34.  
  35. generateMatrixI (rows,columns) f =
  36.  BV.generate rows (generateRow columns)
  37.  where
  38.   generateRow columns row =
  39.    UV.generate columns (\column -> f (row,column))
  40.  
  41. transpose matrix =
  42.  getMatrixSize matrix >>= \(rows,columns) ->
  43.  Right $ generateMatrixI (columns,rows) (\(column,row) -> at matrix (row,column))
  44.  
  45. newRowVector vector =
  46.  let rowVector = BV.singleton vector
  47.  in newMatrix rowVector
  48.  
  49. newColumnVector vector =
  50.  Right $ generateMatrixI (UV.length vector,1) (\(r,c) -> vector UV.! r)
  51.  
  52. mapMatrix f matrix =
  53.  newMatrix matrix >>= \matrix0 ->
  54.  Right $ BV.map (UV.map f) matrix0
  55.  
  56. zipMatrixesWith f matrix0 matrix1 =
  57.  getMatrixSize matrix0 >>= \size0 ->
  58.  getMatrixSize matrix1 >>= \size1 ->
  59.  if size0 /= size1 then
  60.   Left "Matrixes cannot be zipped because their sizes don't match."
  61.  else
  62.   Right $ BV.zipWith (UV.zipWith f) matrix0 matrix1
  63.  
  64. mapMatrixWithIndexes f matrix =
  65.  getMatrixSize matrix >>= \(rows,columns) ->
  66.  Right $ generateMatrixI (rows,columns) (\p -> f p (at matrix p))
  67.    
  68. zipMatrixesWithIndexes f matrix0 matrix1 =
  69.  getMatrixSize matrix0 >>= \size0 ->
  70.  getMatrixSize matrix1 >>= \size1 ->
  71.  if size0 /= size1 then
  72.   Left "Matrixes cannot be zipped with indexes because their sizes don't match."
  73.  else
  74.   let (rows,columns) = size0
  75.   in Right $ generateMatrixI size0 (\p -> f p (at matrix0 p) (at matrix1 p))
  76.  
  77. sumMatrixes matrix0 matrix1 = zipMatrixesWith (+) matrix0 matrix1
  78.  
  79. subtractMatrixes matrix0 matrix1 = zipMatrixesWith (-) matrix0 matrix1
  80.  
  81. scaleMatrix value matrix = mapMatrix (* value) matrix
  82.  
  83. multiplyMatrixes matrix0 matrix1 =
  84.  getMatrixSize matrix0 >>= \size0 ->
  85.  getMatrixSize matrix1 >>= \size1 ->
  86.  let size = (fst size0,snd size1)
  87.  in
  88.   if snd size0 /= fst size1 then
  89.    Left "Matrixes cannot be multiplied because their dimensions don't match."
  90.   else
  91.    transpose matrix1 >>= \tMatrix1 ->
  92.    let
  93.     pointProduct v0 v1 = UV.sum $ UV.zipWith (*) v0 v1
  94.     generateValue (row,column) =
  95.      pointProduct (matrix0 BV.! row) (tMatrix1 BV.! column)
  96.    in Right $ generateMatrixI size (\p -> generateValue p)
  97.    
  98. newMatrixWithValue size value = generateMatrixI size (\p -> value)
  99.  
  100. pivot matrix (i,j) =
  101.  getMatrixSize matrix >>= \(rows,columns) ->
  102.  Right $ generateMatrixI (rows-1,columns-1) generateValue
  103.  where
  104.   generateValue (row,column) =
  105.    at matrix (r,c)
  106.    where
  107.     r = if row < i then row else row + 1
  108.     c = if column < j then column else column + 1
  109.  
  110. cofactorSign (i,j) = if (mod (i + j) 2) == 0 then 1.0 else -1.0    
  111.  
  112. determinant matrix =
  113.  getMatrixSize matrix >>= \(rows,columns) ->
  114.  if rows /= columns then
  115.   Left "Only square matrixes have determinant."
  116.  else
  117.   if rows == 1 then
  118.    Right $ at matrix (0,0)
  119.   else
  120.    if rows == 2 then
  121.     Right $ determinant2x2 matrix
  122.    else
  123.     determinantNxN rows matrix
  124.  where
  125.   determinant2x2 matrix =
  126.    (at matrix (0,0)) * (at matrix (1,1)) - (at matrix (0,1)) * (at matrix (1,0))
  127.      
  128. determinantNxN n matrix =
  129.  CM.foldM accum 0 (map detTerm [0..n-1])
  130.  where
  131.   accum acc term =
  132.    case term of
  133.     Left error -> Left error
  134.     Right value -> Right (acc + value)
  135.   detTerm j =
  136.    pivot matrix p >>= \detPivot ->
  137.    determinant detPivot >>= \det ->
  138.    Right ((cofactorSign p) * (at matrix p) * det)
  139.    where p = (0,j)
  140.  
  141. cofactorsMatrix matrix =
  142.  getMatrixSize matrix >>= \(rows,columns) ->
  143.  if rows /= columns then
  144.   Left "Only square matrixes have cofactors matrix."
  145.  else
  146.   Right $ generateMatrixI (rows,rows) generateValue
  147.  where
  148.   generateValue p =
  149.    case (pivot matrix p >>= \piv -> determinant piv) of
  150.     Left error -> 0
  151.     Right detValue -> (cofactorSign p) * detValue
  152.  
  153. inverse matrix =
  154.  cofactorsMatrix matrix >>= \cofactors ->
  155.  determinant matrix >>= \det ->
  156.  if det == 0.0 then
  157.   Left "This matrix cannot be inverted because its determinant is zero."
  158.  else
  159.   transpose cofactors >>= \transposedCofactors ->
  160.   scaleMatrix (1.0/det) transposedCofactors    
  161.  
  162. identity n one =
  163.  generateMatrixI (n,n) (\(i,j) -> if i == j then one else zero)
  164.  where zero = one - one
  165.  
  166. areNumbersAlmostEqual x0 x1 precision =
  167.  (abs (x0 - x1)) <= precision
  168.  
  169. areMatrixesAlmostEqual matrix0 matrix1 precision =
  170.  getMatrixSize matrix0 >>= \size0 ->
  171.  getMatrixSize matrix1 >>= \size1 ->
  172.  if size0 /= size1 then
  173.   Left "The matrixes cannot be compared because their dimensions don't match."
  174.  else
  175.   let
  176.    booleans = generateMatrixI size0 generateValue
  177.    generateValue p = areNumbersAlmostEqual (at matrix0 p) (at matrix1 p) precision
  178.   in Right $ BV.all (\row -> UV.all id row) booleans
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement