Распаковка, (разреженные) матрицы и библиотека векторов haskell
Я хотел бы эффективно манипулировать матрицами (полными или разреженными) с векторной библиотекой 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
Как видите, матрица - это вектор неупакованных векторов. Теперь я хотел бы сделать точечное произведение между вектором и матрицей. Это довольно просто сделать, комбинируя сумму, почтовый индекс и карту.
Но если я сделаю это, поскольку я отображаю строки матрицы, результатом будет вектор в штучной упаковке, даже если он может быть распакован.
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 ответ
Я не знаю, что ты 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
операция.