我正在编写自己的矩阵模块,以实现乐趣和实践(时间和空间的复杂性并不重要)。 现在我想实现矩阵乘法,我正在努力解决它。这可能就是我使用Haskell的原因,而且我对它没有多少经验。 这是我的数据类型:
data Matrix a =
M {
rows::Int,
cols::Int,
values::[a]
}
在数组中存储像这样的3x2矩阵:
1 2
3 4
5 6
= [1,2,3,4,5,6]
我有一个有点工作的转置功能
transpose::(Matrix a)->(Matrix a)
transpose (M rows cols values) = M cols rows (aux values 0 0 [])
where
aux::[a]->Int->Int->[a]->[a]
aux values row col transposed
| cols > col =
if rows > row then
aux values (row+1) col (transposed ++ [valueAtIndex (M rows cols values) (row,col)])
else aux values 0 (col+1) transposed
| otherwise = transposed
要索引数组中的元素,我正在使用此函数
valueAtIndex::(Matrix a)->(Int, Int)->a
valueAtIndex (M rows cols values) (row, col)
| rows <= row || cols <= col = error "indices too large for given Matrix"
| otherwise = values !! (cols * row + col)
根据我的理解,我必须为m1获取这样的元素:2x3和m2:3x2
m1(0,0)*m2(0,0)+m1(0,1)*m2(0,1)+m1(0,2)*m2(0,2)
m1(0,0)*m2(1,0)+m1(0,1)*m2(1,1)+m1(0,2)*m2(1,2)
m1(1,0)*m2(0,0)+m1(1,1)*m2(0,1)+m1(1,2)*m2(0,2)
m1(1,0)*m2(1,0)+m1(1,1)*m2(1,1)+m1(1,2)*m2(2,2)
现在我需要一个带有两个矩阵的函数,rows m1 == cols m2
,然后以某种方式递归计算正确的矩阵。
multiplyMatrix::Num a=>(Matrix a)->(Matrix a)->(Matrix a)
答案 0 :(得分:2)
首先,我并不是真的相信这样的线性列表是个好主意。 Haskell中的列表被建模为链表。这意味着通常访问 k -th元素将在 O(k)中运行。因此,对于 m×n - 矩阵,这意味着它需要 O(m n)才能访问最后一个元素。通过使用2d链表:包含链表的链表,我们将其缩小到 O(m + n),这通常更快。是的,由于您使用了更多“cons”数据构造函数,因此存在一些开销,但遍历量通常较低。如果你真的想要快速访问,你应该使用数组,向量等。但是还有其他的设计决策要做。
所以我建议我们将矩阵建模为:
data Matrix a = M {
rows :: Int,
cols :: Int,
values :: [[a]]
}
现在有了这个数据构造函数,我们可以将转置定义为:
transpose' :: Matrix a -> Matrix a
transpose' (M r c as) = M c r (trans as)
where trans [] = []
trans xs = map head xs : trans (map tail xs)
(这里我们假设列表列表总是矩形的)
现在对于矩阵乘法。如果 A 和 B 是两个矩阵,并且 C = A×B ,则基本上意味着 a i, j 是 i 第< A 行的点积, j < / em> B 的第列。或者 i 第< A 行,以及 B T <的 j 行/ em>( B 的转置)。因此,我们可以将点积定义为:
dot_prod :: Num a => [a] -> [a] -> a
dot_prod xs ys = sum (zipWith (*) xs ys)
现在只需迭代行和列,并将元素放在右侧列表中。像:
mat_mul :: Num a => Matrix a -> Matrix a -> Matrix a
mat_mul (M r ca xss) m2 | ca /= ra = error "Invalid matrix shapes"
| otherwise = M r c (matmul xss)
where (M c rb yss) = transpose m2
matmul [] = []
matmul (xs:xss) = generaterow yss xs : matmul xss
generaterow [] _ = []
generaterow (ys:yss) xs = dot_prod xs ys : generaterow yss xs