[Solved] Write this Scala Matrix multiplication in Haskell [duplicate]


It’ll be perfectly safe with a smart constructor and stored dimensions. Of course there are no natural implementations for the operations signum and fromIntegral (or maybe a diagonal matrix would be fine for the latter).

module Matrix (Matrix(),matrix,matrixTranspose) where

import Data.List (transpose)

data Matrix a = Matrix {matrixN :: Int, 
                        matrixM :: Int,
                        matrixElems :: [[a]]}
                deriving (Show, Eq)

matrix :: Int -> Int -> [[a]] -> Matrix a
matrix n m vals
  | length vals /= m            = error "Wrong number of rows"
  | any (/=n) $ map length vals = error "Column length mismatch"
  | otherwise = Matrix n m vals

matrixTranspose (Matrix m n vals) = matrix n m (transpose vals)

instance Num a => Num (Matrix a) where

  (+) (Matrix m n vals) (Matrix m' n' vals')
    | m/=m' = error "Row number mismatch"
    | n/=n' = error "Column number mismatch"
    | otherwise = Matrix m n (zipWith (zipWith (+)) vals vals')

  abs (Matrix m n vals) = Matrix m n (map (map abs) vals)

  negate (Matrix m n vals) = Matrix m n (map (map negate) vals)

  (*) (Matrix m n vals) (Matrix n' p vals')
    | n/=n' = error "Matrix dimension mismatch in multiplication"
    | otherwise = let tvals' = transpose vals'
                      dot x y = sum $ zipWith (*) x y
                      result = map (\col -> map (dot col) tvals') vals
                  in Matrix m p result

Test it in ghci:

*Matrix> let a = matrix 3 2 [[1,0,2],[-1,3,1]]
*Matrix> let b = matrix 2 3 [[3,1],[2,1],[1,0]]
*Matrix> a*b
Matrix {matrixN = 3, matrixM = 3, matrixElems = [[5,1],[4,2]]}

Since my Num instance is generic, it even works for complex matrices out of the box:

Prelude Data.Complex Matrix> let c = matrix 2 2 [[0:+1,1:+0],[5:+2,4:+3]]
Prelude Data.Complex Matrix> let a = matrix 2 2 [[0:+1,1:+0],[5:+2,4:+3]]
Prelude Data.Complex Matrix> let b = matrix 2 3 [[3:+0,1],[2,1],[1,0]]
Prelude Data.Complex Matrix> a
Matrix {matrixN = 2, matrixM = 2, matrixElems = [[0.0 :+ 1.0,1.0 :+ 0.0],[5.0 :+ 2.0,4.0 :+ 3.0]]}
Prelude Data.Complex Matrix> b
Matrix {matrixN = 2, matrixM = 3, matrixElems = [[3.0 :+ 0.0,1.0 :+ 0.0],[2.0 :+ 0.0,1.0 :+ 0.0],[1.0 :+ 0.0,0.0 :+ 0.0]]}
Prelude Data.Complex Matrix> a*b
Matrix {matrixN = 2, matrixM = 3, matrixElems = [[2.0 :+ 3.0,1.0 :+ 1.0],[23.0 :+ 12.0,9.0 :+ 5.0]]}

EDIT: new material

Oh, you want to just override the (*) function without any Num stuff. That’s possible to o but you’ll have to remember that the Haskell standard library has reserved (*) for use in the Num class.

module Matrix where

import qualified Prelude as P
import Prelude hiding ((*))
import Data.List (transpose)

class Multiply a where
  (*) :: a -> a -> a

data Matrix a = Matrix {matrixN :: Int, 
                        matrixM :: Int,
                        matrixElems :: [[a]]}
                deriving (Show, Eq)

matrix :: Int -> Int -> [[a]] -> Matrix a
matrix n m vals
  | length vals /= m            = error "Wrong number of rows"
  | any (/=n) $ map length vals = error "Column length mismatch"
  | otherwise = Matrix n m vals

matrixTranspose (Matrix m n vals) = matrix n m (transpose vals)

instance P.Num a => Multiply (Matrix a) where
  (*) (Matrix m n vals) (Matrix n' p vals')
    | n/=n' = error "Matrix dimension mismatch in multiplication"
    | otherwise = let tvals' = transpose vals'
                      dot x y = sum $ zipWith (P.*) x y
                      result = map (\col -> map (dot col) tvals') vals
                  in Matrix m p result


a = matrix 3 2 [[1,2,3],[4,5,6]]
b = a * matrixTranspose

Testing in ghci:

*Matrix> b
Matrix {matrixN = 3, matrixM = 3, matrixElems = [[14,32],[32,77]]}

There. Now if a third module wants to use both the Matrix version of (*) and the Prelude version of (*) it’ll have to of course import one or the other qualified. But that’s just business as usual.

I could’ve done all of this without the Multiply type class but this implementation leaves our new shiny (*) open for extension in other modules.

8

solved Write this Scala Matrix multiplication in Haskell [duplicate]