Haskell中的逆矩阵

时间:2014-05-28 18:16:00

标签: haskell matrix inverse

我刚开始学习Haskell 我有一个问题。我试着写一个函数来找到逆矩阵 我的矩阵类型如下:

data Matrix a = M 
    { nrows :: !Int
    , ncols :: !Int
    , mvect :: V.Vector (V.Vector a)
    } deriving Eq

我也有fromLists功能 查找行列式的函数如下:

det :: Num a => Matrix a -> a
det (M 1 1 v) = V.head (V.head v)
det m =
    sum [ (-1)^(i-1) * m ! (i,1) * det (minorMatrix i 1 m) | i <- [1 .. nrows m] ]

所以,我的代码是找到逆矩阵:

coords :: Matrix a -> [[(Int, Int)]]
coords = zipWith (map . (,)) [0..] . map (zipWith const [0..])

delmatrix :: Int -> Int -> Matrix a -> Matrix a
delmatrix i j = dellist i . map (dellist j)
    where dellist i xs = take i xs ++ drop (i + 1) xs

mapMatrix :: (a -> a) -> Matrix a -> Matrix a
mapMatrix f = map (map f)

cofactor :: Num a => Int -> Int -> Matrix a -> a
cofactor i j m = ((-1) ** fromIntegral (i + j)) * det (delmatrix i j m)

cofactorM :: Matrix a -> Matrix a
cofactorM m = map (map (\(i,j) -> cofactor j i m)) $ coords m

inverse :: (Num a, Fractional a) => Matrix a -> Matrix a
inverse m = mapMatrix (* recip deter) $ cofactorM m
    where deter = det m

我在控制台上有什么:

Prelude> :r
[1 of 1] Compiling Matrixlab        ( Matrixlab.hs, interpreted )

Matrixlab.hs:120:38:
    Couldn't match expected type `Matrix a' with actual type `[a0]'
    Expected type: Matrix a -> [[Int]]
      Actual type: [a0] -> [b0]
    In the return type of a call of `map'
    In the second argument of `(.)', namely
      `map (zipWith const [0 .. ])'

Matrixlab.hs:123:17:
    Couldn't match expected type `Matrix a' with actual type `[a0]'
    Expected type: [a0] -> Matrix a
      Actual type: [a0] -> [a0]
    In the return type of a call of `dellist'
    In the first argument of `(.)', namely `dellist i'

Matrixlab.hs:127:15:
    Couldn't match expected type `Matrix a' with actual type `[a0]'
    Expected type: Matrix a -> Matrix a
      Actual type: [a0] -> [b0]
    In the return type of a call of `map'
    In the expression: map (map f)

Matrixlab.hs:130:24:
    Could not deduce (Floating a) arising from a use of `**'
    from the context (Num a)
      bound by the type signature for
                 cofactor :: Num a => Int -> Int -> Matrix a -> a
      at Matrixlab.hs:130:1-71
    Possible fix:
      add (Floating a) to the context of
        the type signature for
          cofactor :: Num a => Int -> Int -> Matrix a -> a
    In the first argument of `(*)', namely
      `((- 1) ** fromIntegral (i + j))'
    In the expression:
      ((- 1) ** fromIntegral (i + j)) * det (delmatrix i j m)
    In an equation for `cofactor':
        cofactor i j m
          = ((- 1) ** fromIntegral (i + j)) * det (delmatrix i j m)

Matrixlab.hs:133:15:
    Couldn't match expected type `Matrix a' with actual type `[[a]]'
    In the expression:
      map (map (\ (i, j) -> cofactor j i m)) $ coords m
    In an equation for `cofactorM':
        cofactorM m = map (map (\ (i, j) -> cofactor j i m)) $ coords m
Failed, modules loaded: none.

请帮帮我。

1 个答案:

答案 0 :(得分:3)

首先,如果你想使用矢量,你应该使用矢量。如果你要将它们一直转换回列表,你应该坚持使用列表。 vector包提供了Vector类型列表中的所有功能。所以你应该使用那些。事实上,使用Vector函数几乎总是更容易,因为它们为您提供了对项目索引的内置访问。 If you don't know what functions you have available, take a look at the docs.

您也不能假装您的Matrix等同于列表列表,并期望编译器知道您在说什么。你必须使用模式匹配从Matrix构造函数中取出向量,对它们进行操作,然后将它们放回去。例如:

import qualified Data.Vector as V

cofactorM :: Floating a => Matrix a -> Matrix a
cofactorM m@(M x y v) = M x y $ (V.imap $ \i -> V.imap $ \j -> const (cofactor i j m)) v 

cofactor :: Floating a => Int -> Int -> Matrix a -> a
cofactor ...

请注意,Vector为零索引,而您的det函数意味着您的列和行是一个索引。你将不得不弥补这一点。

最后,没有充分的理由用Vector (Vector a)打包行数和列数,因为获取向量的长度无论如何都是一个恒定的时间操作。