Use the source's The outer list comprehension pairs corresponding rows; the inner one pairs corresponding entries. Checking both dimensions before using
type Matrix a = [[a]]. For its nonempty rectangular matrices, the number of rows and the first row's length determine the dimensions:dimensions :: Matrix a -> (Int,Int)
dimensions rows = (length rows, length (head rows))
addMat :: Num a => Matrix a -> Matrix a -> Matrix a
addMat a b
| dimensions a /= dimensions b = error "addMat: incompatible sizes"
| otherwise = [[x + y | (x,y) <- zip r s]
| (r,s) <- zip a b]zip prevents silent truncation. Thus the result has entries , the definition of matrix addition. The Num constraint supplies the addition operation.With The inner
dimensions as in part (i), the alternative definition isaddMat :: Num a => Matrix a -> Matrix a -> Matrix a
addMat a b
| dimensions a /= dimensions b = error "addMat: incompatible sizes"
| otherwise = zipWith (zipWith (+)) a bzipWith adds corresponding entries; the outer one applies that row operation to corresponding rows. This computes the same matrix addition, with the same rejection of unequal dimensions. Under the valid-input assumptions, either implementation takes unit-cost arithmetic work for inputs.A recursive transpose removes the first column, then transposes the remaining columns:The internal recursive calls eventually reach rows of length zero, even though the original input has positive dimensions; the second equation handles this terminating case. Rectangularity ensures that the rows become empty together, so no
transpose :: Matrix a -> Matrix a
transpose [] = []
transpose ([] : _) = []
transpose rows = map head rows : transpose (map tail rows)head or tail is applied to an empty row in the third equation. The output is an matrix with entry . The element type is unrestricted.Build columns by prepending the first row's entries to the columns obtained from the remaining rows:The singleton case turns each entry into a one-element column. In the recursive case,
transpose :: Matrix a -> Matrix a
transpose [] = []
transpose [row] = map (:[]) row
transpose (row : rows) = zipWith (:) row (transpose rows)transpose rows has exactly as many columns as row has entries, so zipWith (:) extends every column once. Structural induction on the number of rows proves that each output column contains the corresponding input entries in order. This uses list zip to implement the transpose, without requiring Num a.Reuse For of size and of size , every selected row and column has length . Their dot product isThe two list comprehensions place this entry in row , column of an result. The dimension guard checks exactly the compatibility condition for matrix multiplication. The shared
dimensions and either transpose definition above:multMat :: Num a => Matrix a -> Matrix a -> Matrix a
multMat a b
| colsA /= rowsB = error "multMat: incompatible sizes"
| otherwise = [[sum (zipWith (*) row col) | col <- columnsB]
| row <- a]
where
(_,colsA) = dimensions a
(rowsB,_) = dimensions b
columnsB = transpose bcolumnsB avoids recomputing the transpose for each row; the arithmetic cost is in the unit-cost model.Generate successive matrix powers and take cumulative sums using matrix addition:For the stipulated square matrix,
seriesMat :: Num a => Matrix a -> [Matrix a]
seriesMat m = scanl1 addMat (iterate (multMat m) m)iterate (multMat m) m produces m, m*m, m*(m*m), and so on. Associativity of exact matrix multiplication identifies these as . The left scan scanl1 addMat then returnsAll dimensions remain compatible. The infinite outer list is available a finite prefix at a time under lazy evaluation; no convergence of the matrix geometric series is needed. With floating-point entries, the expression specifies this particular multiplication and addition order, since machine arithmetic need not obey the exact algebraic laws. Articles by others on the same topic
There are currently no matching articles.