拆箱,(稀疏)矩阵和haskell矢量库

时间:2010-04-29 14:07:12

标签: arrays haskell vector unboxing

我想用haskell的矢量库有效地处理矩阵(完全或稀疏)。

这是矩阵类型

import qualified Data.Vector.Unboxed as U
import qualified Data.Vector as V

data Link a = Full (V.Vector (U.Vector a))
    | Sparse (V.Vector (U.Vector (Int,a)))

type Vector a = U.Vector a

如您所见,矩阵是未装箱矢量的矢量。现在,我想在矢量和矩阵之间做一个点积。通过组合sum,zip和map可以非常简单。

但是,如果我这样做,因为我正在通过矩阵的行进行映射,结果是一个盒装矢量,即使它可以是未装箱的。

propagateS output (Field src) (Full weights) = V.map (sum out) weights
    where out     = U.map output src
          sum s w = U.sum $ zipWithFull (*) w s

propagateS output (Field src) (Sparse weights) = V.map (sum out) weights
    where out     = U.map output src
          sum s w = U.sum $ zipWithSparse (*) w s

zipWithFull = U.zipWith

zipWithSparse f x y = U.map f' x
    where f' (i,v) = f v (y U.! i)

如何有效地获得未装箱的矢量?

1 个答案:

答案 0 :(得分:1)

我不知道您的Field类型是什么,所以我不太了解第二个代码段。

但是如果你将矩阵表示为一个盒装矢量,你的中间结果将是盒装矢量。如果您想要取消装箱结果,则需要使用U.fromList . V.toList显式转换类型。这是密集矩阵类型的一个例子(为简洁起见,我省略了稀疏的情况):

import qualified Data.Vector.Unboxed as U
import qualified Data.Vector as V

-- assuming row-major order
data Matrix a = Full (V.Vector (U.Vector a))

type Vector a = U.Vector a

-- matrix to vector dot product
dot :: (U.Unbox a, Num a) => (Matrix a) -> (Vector a) -> (Vector a)
(Full rows) `dot` x =
  let mx = V.map (vdot x) rows
  in U.fromList . V.toList $ mx  -- unboxing, O(n)

-- vector to vector dot product
vdot :: (U.Unbox a, Num a) => Vector a -> Vector a -> a
vdot x y = U.sum $ U.zipWith (*) x y

instance (Show a, U.Unbox a) => Show (Matrix a) where
  show (Full rows) = show $ V.toList $ V.map U.toList rows

showV = show . U.toList

main =
  let m = Full $ V.fromList $ map U.fromList ([[1,2],[3,4]] :: [[Int]])
      x = U.fromList ([5,6] :: [Int])
      mx = m `dot` x
  in putStrLn $ (show m) ++ " × " ++ (showV x) ++ " = " ++ (showV mx)

输出:

 [[1,2],[3,4]] × [5,6] = [17,39]

我不确定这种方法的表现。可能最好将整个矩阵存储为单个未装箱的矢量,并根据存储模型通过索引访问元素。这样你就不需要盒装载体了。

另请查看新的repa库及其index操作。