我在Haskell中实现了一个kronecker产品功能用于学习,一切正常, 除了我还没有找到更高阶kroneckerProduct的正确实现 可以将sub-kroneckerProduct作为参数,这也促使我思考如何渲染 由kroneckerProduct生成的块矩阵。
{-# LANGUAGE RankNTypes #-}
import Data.List (intercalate, transpose)
import Data.List.Split (chunksOf)
import Control.Applicative (Applicative, pure, (<$>), (<*>))
newtype Matrix a = Matrix { getMatrix :: [[a]] }
instance Functor Matrix where
fmap f = Matrix . (fmap (fmap f)) . getMatrix
instance Applicative Matrix where
pure x = Matrix [[x]]
(Matrix as) <*> (Matrix bs) = Matrix $ zipWith (zipWith id) as bs
instance (Show a) => Show (Matrix a) where
show = (intercalate "\n") . fmap (unwords . fmap show) . getMatrix
scalarProduct :: (Num a) => a -> Matrix a -> Matrix a
scalarProduct scalar matrix = (* scalar) <$> matrix
hadamardProduct :: (Num a) => Matrix a -> Matrix a -> Matrix a
hadamardProduct matrix1 matrix2 = (*) <$> matrix1 <*> matrix2
-- The kronecker product M1 ⊗ M2, results in a block matrix.
-- It is a matrix that has elements that are also matrices,
-- this makes it somewhat multidimensional tensor.
-- The resulting block matrix has the same dimensions as M1.
-- Every resulting element M1M2ij is equal to M1ij × M2.
-- Assuming M1 contains scalars, this would mean every element
-- in the resulting matrix requires a further scalar multiplication.
-- But it could also be some other multiplication method.
-- This requires a RankNTypes
kroneckerProduct :: (a -> Matrix b -> Matrix b) -> Matrix a -> Matrix b -> Matrix (Matrix b)
kroneckerProduct f m1 m2 = (`f` m2) <$> m1
-- Flattening a block matrix produced by kroneckerProduct into a normal Matrix.
-- This works by assuming a quad layer matrix: [[[[...]]]].
-- We tranpose the middle 2,then concat the outside 2, and concat the inner 2.
-- This ends up bringing out the inner block matrices into the outside.
-- The resulting size of the new matrix is rowA*colA * rowB*colB,
-- where A is the outer Matrix, and B is the inner Matrix.
flattenBlock :: Matrix (Matrix a) -> Matrix a
flattenBlock blockMatrix = Matrix $ dilate $ getMatrix2 blockMatrix
where
dilate = (fmap concat) . concat . (fmap transpose)
getMatrix2 = getMatrix . fmap getMatrix
incrementingMatrix :: Int -> Int -> Matrix Int
incrementingMatrix rowSize colSize = Matrix $ chunksOf colSize [1..(rowSize * colSize)]
这样可行:
> let blockMatrix1 = kroneckerProduct scalarProduct (incrementingMatrix 2 2) (incrementingMatrix 2 2)
> putStrLn $ show $ flattenBlock blockMatrix1
> let blockMatrix2 = kroneckerProduct hadamardProduct blockMatrix1 (incrementingMatrix 2 2)
> putStrLn $ show $ flattenBlock blockMatrix2
但是我们无法编译(但数学上应该可以):
> let recursiveKro = kroneckerProduct (kroneckerProduct scalarProduct)
我最终得到一个&#34;发生检查&#34;:
Occurs check: cannot construct the infinite type: b ~ Matrix b
Expected type: Matrix b -> Matrix b -> Matrix b
Actual type: Matrix b -> Matrix b -> Matrix (Matrix b)
Relevant bindings include
recursiveKro :: Matrix (Matrix b) -> Matrix b -> Matrix (Matrix b)
(bound at <interactive>:240:5)
In the first argument of ‘kroneckerProduct’, namely
‘(kroneckerProduct scalarProduct)’
In the expression:
kroneckerProduct (kroneckerProduct scalarProduct)
那么我需要改变什么才能使上述表达成为可能?
此外,如果可以创建多层块矩阵,我们还需要将flattenBlock
函数扩展为递归。
我想它应该是这样的:
flattenBlockRecursive m = fmap flattenBlockRecursive $ Matrix $ (concat . (fmap transpose) . (fmap concat)) (getMatrix $ fmap getMatrix $ m)
并且需要使用某种类型类递归,但我尝试使用多参数类型类但不能理解它。
重申: