Haskell:递归矩阵Kronecker乘积和多维块矩阵的递归展平渲染

时间:2015-12-30 07:22:01

标签: haskell recursion matrix matrix-multiplication typeclass

我在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)

并且需要使用某种类型类递归,但我尝试使用多参数类型类但不能理解它。

重申:

  1. 如何更改kroneckerProduct函数以允许更大的灵活性来接受sub-kroneckerProduct函数?
  2. 我如何展平多层块矩阵并渲染它?

0 个答案:

没有答案