拆箱,(稀疏)矩阵,和Haskell矢量库 [英] unboxing, (sparse) matrices, and haskell vector library
问题描述
我想操纵矩阵(全部或稀疏的)有效地与Haskell的向量库。
I would like to manipulate matrices (full or sparse) efficiently with haskell's vector library.
下面是一个矩阵型
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
正如你所看到的,矩阵向量拆箱的向量。现在,我愿做一个向量和矩阵之间的点积。这是相当简单的结合的总和,拉链和地图做的。
As you can see, the matrix is a vector of unboxed vectors. Now, I would like to do a dot product between a vector and a matrix. It is fairly simple to do by combining a sum, zip and map.
但是,如果我这样做,因为我通过矩阵的行映射,结果是盒装载体,即使它可以拆箱。
But if I do that, because I'm mapping through the rows of the matrix, the result is a boxed vector, even though it could be unboxed.
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)
我怎样才能得到一个装箱矢量结果有效?
How can I get an unboxed vector as a result efficiently ?
推荐答案
我不知道你的字段
的类型是什么,所以我不太了解第二片段。
I don't know what your Field
type is, so I don't quite understand the second snippet.
但是,如果你再present你的矩阵作为盒装载体,你的中间结果将被装箱的载体。如果你想有一个未装箱的结果,你需要类型的 U.fromList显式转换。 V.toList
。这就为您的密集矩阵型为例(我省略了稀疏的情况下,为简便起见):
But if you represent your matrix as a boxed vector, your intermediate results will be boxed vectors. If you want to have an unboxed result, you need to convert types explicitly with U.fromList . V.toList
. This an example for your dense matrix type (I omitted the sparse case for brevity):
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]
我不知道这种方法的性能。也许这是更好的根据存储模型对整个矩阵存储为通过索引单个装箱载体和接入元素。这样,您就不需要盒装载体。
I am not sure about performance of this approach. Probably it is much better to store the whole matrix as a single unboxed vector and access elements by index according to storage model. This way you don't need boxed vectors.
看看还新 repa 库及其指数
操作。
这篇关于拆箱,(稀疏)矩阵,和Haskell矢量库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!