summaryrefslogtreecommitdiff
path: root/lib/Data/Packed
diff options
context:
space:
mode:
authorBen Gamari <bgamari.foss@gmail.com>2013-08-15 14:19:57 -0400
committerBen Gamari <bgamari.foss@gmail.com>2013-08-15 14:19:57 -0400
commit83453a970491fc764a9e490e1f9791a289e9b571 (patch)
tree33ba6a9eb93129cb98e6ad4aef06e39977fc21d5 /lib/Data/Packed
parent955d569823230f871fba8c4492b5ad4a4a2def31 (diff)
parent374194ee454622e66c931dce8f315c68167c7ac9 (diff)
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'lib/Data/Packed')
-rw-r--r--lib/Data/Packed/Foreign.hs99
-rw-r--r--lib/Data/Packed/Internal/Matrix.hs21
-rw-r--r--lib/Data/Packed/Internal/Vector.hs59
-rw-r--r--lib/Data/Packed/Matrix.hs44
-rw-r--r--lib/Data/Packed/Random.hs21
5 files changed, 149 insertions, 95 deletions
diff --git a/lib/Data/Packed/Foreign.hs b/lib/Data/Packed/Foreign.hs
new file mode 100644
index 0000000..efa51ca
--- /dev/null
+++ b/lib/Data/Packed/Foreign.hs
@@ -0,0 +1,99 @@
1{-# LANGUAGE MagicHash, UnboxedTuples #-}
2-- | FFI and hmatrix helpers.
3--
4-- Sample usage, to upload a perspective matrix to a shader.
5--
6-- @ glUniformMatrix4fv 0 1 (fromIntegral gl_TRUE) \`appMatrix\` perspective 0.01 100 (pi\/2) (4\/3)
7-- @
8--
9module Data.Packed.Foreign
10 ( app
11 , appVector, appVectorLen
12 , appMatrix, appMatrixLen, appMatrixRaw, appMatrixRawLen
13 , unsafeMatrixToVector, unsafeMatrixToForeignPtr
14 ) where
15import Data.Packed.Internal
16import qualified Data.Vector.Storable as S
17import Foreign (Ptr, ForeignPtr, Storable)
18import Foreign.C.Types (CInt)
19import GHC.Base (IO(..), realWorld#)
20
21{-# INLINE unsafeInlinePerformIO #-}
22-- | If we use unsafePerformIO, it may not get inlined, so in a function that returns IO (which are all safe uses of app* in this module), there would be
23-- unecessary calls to unsafePerformIO or its internals.
24unsafeInlinePerformIO :: IO a -> a
25unsafeInlinePerformIO (IO f) = case f realWorld# of
26 (# _, x #) -> x
27
28{-# INLINE app #-}
29-- | Only useful since it is left associated with a precedence of 1, unlike 'Prelude.$', which is right associative.
30-- e.g.
31--
32-- @
33-- someFunction
34-- \`appMatrixLen\` m
35-- \`appVectorLen\` v
36-- \`app\` other
37-- \`app\` arguments
38-- \`app\` go here
39-- @
40--
41-- One could also write:
42--
43-- @
44-- (someFunction
45-- \`appMatrixLen\` m
46-- \`appVectorLen\` v)
47-- other
48-- arguments
49-- (go here)
50-- @
51--
52app :: (a -> b) -> a -> b
53app f = f
54
55{-# INLINE appVector #-}
56appVector :: Storable a => (Ptr a -> b) -> Vector a -> b
57appVector f x = unsafeInlinePerformIO (S.unsafeWith x (return . f))
58
59{-# INLINE appVectorLen #-}
60appVectorLen :: Storable a => (CInt -> Ptr a -> b) -> Vector a -> b
61appVectorLen f x = unsafeInlinePerformIO (S.unsafeWith x (return . f (fromIntegral (S.length x))))
62
63{-# INLINE appMatrix #-}
64appMatrix :: Element a => (Ptr a -> b) -> Matrix a -> b
65appMatrix f x = unsafeInlinePerformIO (S.unsafeWith (flatten x) (return . f))
66
67{-# INLINE appMatrixLen #-}
68appMatrixLen :: Element a => (CInt -> CInt -> Ptr a -> b) -> Matrix a -> b
69appMatrixLen f x = unsafeInlinePerformIO (S.unsafeWith (flatten x) (return . f r c))
70 where
71 r = fromIntegral (rows x)
72 c = fromIntegral (cols x)
73
74{-# INLINE appMatrixRaw #-}
75appMatrixRaw :: Storable a => (Ptr a -> b) -> Matrix a -> b
76appMatrixRaw f x = unsafeInlinePerformIO (S.unsafeWith (xdat x) (return . f))
77
78{-# INLINE appMatrixRawLen #-}
79appMatrixRawLen :: Element a => (CInt -> CInt -> Ptr a -> b) -> Matrix a -> b
80appMatrixRawLen f x = unsafeInlinePerformIO (S.unsafeWith (xdat x) (return . f r c))
81 where
82 r = fromIntegral (rows x)
83 c = fromIntegral (cols x)
84
85infixl 1 `app`
86infixl 1 `appVector`
87infixl 1 `appMatrix`
88infixl 1 `appMatrixRaw`
89
90{-# INLINE unsafeMatrixToVector #-}
91-- | This will disregard the order of the matrix, and simply return it as-is.
92-- If the order of the matrix is RowMajor, this function is identical to 'flatten'.
93unsafeMatrixToVector :: Matrix a -> Vector a
94unsafeMatrixToVector = xdat
95
96{-# INLINE unsafeMatrixToForeignPtr #-}
97unsafeMatrixToForeignPtr :: Storable a => Matrix a -> (ForeignPtr a, Int)
98unsafeMatrixToForeignPtr m = S.unsafeToForeignPtr0 (xdat m)
99
diff --git a/lib/Data/Packed/Internal/Matrix.hs b/lib/Data/Packed/Internal/Matrix.hs
index b8ed18d..255009c 100644
--- a/lib/Data/Packed/Internal/Matrix.hs
+++ b/lib/Data/Packed/Internal/Matrix.hs
@@ -47,6 +47,7 @@ import Data.Complex(Complex)
47import Foreign.C.Types 47import Foreign.C.Types
48import Foreign.C.String(newCString) 48import Foreign.C.String(newCString)
49import System.IO.Unsafe(unsafePerformIO) 49import System.IO.Unsafe(unsafePerformIO)
50import Control.DeepSeq
50 51
51----------------------------------------------------------------- 52-----------------------------------------------------------------
52 53
@@ -131,12 +132,10 @@ mat a f =
131 let m g = do 132 let m g = do
132 g (fi (rows a)) (fi (cols a)) p 133 g (fi (rows a)) (fi (cols a)) p
133 f m 134 f m
134 135-- | Creates a vector by concatenation of rows. If the matrix is ColumnMajor, this operation requires a transpose.
135{- | Creates a vector by concatenation of rows 136--
136 137-- @\> flatten ('ident' 3)
137@\> flatten ('ident' 3) 138-- 9 |> [1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0]@
1389 |> [1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0]@
139-}
140flatten :: Element t => Matrix t -> Vector t 139flatten :: Element t => Matrix t -> Vector t
141flatten = xdat . cmat 140flatten = xdat . cmat
142 141
@@ -459,3 +458,13 @@ size m = (rows m, cols m)
459 458
460shSize m = "(" ++ show (rows m) ++"><"++ show (cols m)++")" 459shSize m = "(" ++ show (rows m) ++"><"++ show (cols m)++")"
461 460
461----------------------------------------------------------------------
462
463instance (Storable t, NFData t) => NFData (Matrix t)
464 where
465 rnf m | d > 0 = rnf (v @> 0)
466 | otherwise = ()
467 where
468 d = dim v
469 v = xdat m
470
diff --git a/lib/Data/Packed/Internal/Vector.hs b/lib/Data/Packed/Internal/Vector.hs
index d3b80ff..5892e67 100644
--- a/lib/Data/Packed/Internal/Vector.hs
+++ b/lib/Data/Packed/Internal/Vector.hs
@@ -55,48 +55,17 @@ import GHC.Base
55import GHC.IOBase hiding (liftIO) 55import GHC.IOBase hiding (liftIO)
56#endif 56#endif
57 57
58#ifdef VECTOR
59import qualified Data.Vector.Storable as Vector 58import qualified Data.Vector.Storable as Vector
60import Data.Vector.Storable(Vector, 59import Data.Vector.Storable(Vector,
61 unsafeToForeignPtr, 60 unsafeToForeignPtr,
62 unsafeFromForeignPtr, 61 unsafeFromForeignPtr,
63 unsafeWith) 62 unsafeWith)
64#else
65import Foreign.ForeignPtr(withForeignPtr)
66#endif
67 63
68#ifdef VECTOR
69 64
70-- | Number of elements 65-- | Number of elements
71dim :: (Storable t) => Vector t -> Int 66dim :: (Storable t) => Vector t -> Int
72dim = Vector.length 67dim = Vector.length
73 68
74#else
75
76-- | One-dimensional array of objects stored in a contiguous memory block.
77data Vector t =
78 V { ioff :: {-# UNPACK #-} !Int -- ^ offset of first element
79 , idim :: {-# UNPACK #-} !Int -- ^ number of elements
80 , fptr :: {-# UNPACK #-} !(ForeignPtr t) -- ^ foreign pointer to the memory block
81 }
82
83unsafeToForeignPtr :: Storable a => Vector a -> (ForeignPtr a, Int, Int)
84unsafeToForeignPtr v = (fptr v, ioff v, idim v)
85
86-- | Same convention as in Roman Leshchinskiy's vector package.
87unsafeFromForeignPtr :: Storable a => ForeignPtr a -> Int -> Int -> Vector a
88unsafeFromForeignPtr fp i n | n > 0 = V {ioff = i, idim = n, fptr = fp}
89 | otherwise = error "unsafeFromForeignPtr with dim < 1"
90
91unsafeWith (V i _ fp) m = withForeignPtr fp $ \p -> m (p `advancePtr` i)
92{-# INLINE unsafeWith #-}
93
94-- | Number of elements
95dim :: (Storable t) => Vector t -> Int
96dim = idim
97
98#endif
99
100 69
101-- C-Haskell vector adapter 70-- C-Haskell vector adapter
102-- vec :: Adapt (CInt -> Ptr t -> r) (Vector t) r 71-- vec :: Adapt (CInt -> Ptr t -> r) (Vector t) r
@@ -204,36 +173,8 @@ subVector :: Storable t => Int -- ^ index of the starting element
204 -> Int -- ^ number of elements to extract 173 -> Int -- ^ number of elements to extract
205 -> Vector t -- ^ source 174 -> Vector t -- ^ source
206 -> Vector t -- ^ result 175 -> Vector t -- ^ result
207
208#ifdef VECTOR
209
210subVector = Vector.slice 176subVector = Vector.slice
211 177
212{-
213subVector k l v
214 | k<0 || k >= n || k+l > n || l < 0 = error "subVector out of range"
215 | otherwise = unsafeFromForeignPtr fp (i+k) l
216 where
217 (fp, i, n) = unsafeToForeignPtr v
218-}
219
220#else
221
222subVector k l v@V{idim = n, ioff = i}
223 | k<0 || k >= n || k+l > n || l < 0 = error "subVector out of range"
224 | otherwise = v {idim = l, ioff = i+k}
225
226{-
227subVectorCopy k l (v@V {idim=n})
228 | k<0 || k >= n || k+l > n || l < 0 = error "subVector out of range"
229 | otherwise = unsafePerformIO $ do
230 r <- createVector l
231 let f _ s _ d = copyArray d (advancePtr s k) l >> return 0
232 app2 f vec v vec r "subVector"
233 return r
234-}
235
236#endif
237 178
238{- | Reads a vector position: 179{- | Reads a vector position:
239 180
diff --git a/lib/Data/Packed/Matrix.hs b/lib/Data/Packed/Matrix.hs
index c1a9b24..1b67820 100644
--- a/lib/Data/Packed/Matrix.hs
+++ b/lib/Data/Packed/Matrix.hs
@@ -30,7 +30,7 @@ module Data.Packed.Matrix (
30 (@@>), 30 (@@>),
31 asRow, asColumn, 31 asRow, asColumn,
32 fromRows, toRows, fromColumns, toColumns, 32 fromRows, toRows, fromColumns, toColumns,
33 fromBlocks, toBlocks, toBlocksEvery, 33 fromBlocks, diagBlock, toBlocks, toBlocksEvery,
34 repmat, 34 repmat,
35 flipud, fliprl, 35 flipud, fliprl,
36 subMatrix, takeRows, dropRows, takeColumns, dropColumns, 36 subMatrix, takeRows, dropRows, takeColumns, dropColumns,
@@ -46,6 +46,7 @@ import Data.Array
46 46
47import Data.List(transpose,intersperse) 47import Data.List(transpose,intersperse)
48import Foreign.Storable(Storable) 48import Foreign.Storable(Storable)
49import Control.Monad(liftM)
49 50
50------------------------------------------------------------------- 51-------------------------------------------------------------------
51 52
@@ -155,7 +156,19 @@ adaptBlocks ms = ms' where
155 x = m@@>(0,0) 156 x = m@@>(0,0)
156 g _ _ = error "inconsistent dimensions in fromBlocks" 157 g _ _ = error "inconsistent dimensions in fromBlocks"
157 158
158----------------------------------------------------------- 159
160--------------------------------------------------------------------------------
161
162-- | create a block diagonal matrix
163diagBlock :: (Element t, Num t) => [Matrix t] -> Matrix t
164diagBlock ms = fromBlocks $ zipWith f ms [0..]
165 where
166 f m k = take n $ replicate k z ++ m : repeat z
167 n = length ms
168 z = (1><1) [0]
169
170--------------------------------------------------------------------------------
171
159 172
160-- | Reverse rows 173-- | Reverse rows
161flipud :: Element t => Matrix t -> Matrix t 174flipud :: Element t => Matrix t -> Matrix t
@@ -351,7 +364,11 @@ toBlocksEvery r c m = toBlocks rs cs m where
351 364
352------------------------------------------------------------------- 365-------------------------------------------------------------------
353 366
354mk c g = \k v -> g (divMod k c) v 367-- Given a column number and a function taking matrix indexes, returns
368-- a function which takes vector indexes (that can be used on the
369-- flattened matrix).
370mk :: Int -> ((Int, Int) -> t) -> (Int -> t)
371mk c g = \k -> g (divMod k c)
355 372
356{- | 373{- |
357 374
@@ -364,9 +381,8 @@ m[1,1] = 5
364m[1,2] = 6@ 381m[1,2] = 6@
365-} 382-}
366mapMatrixWithIndexM_ 383mapMatrixWithIndexM_
367 :: (Element a, Num a, 384 :: (Element a, Num a, Monad m) =>
368 Functor f, Monad f) => 385 ((Int, Int) -> a -> m ()) -> Matrix a -> m ()
369 ((Int, Int) -> a -> f ()) -> Matrix a -> f ()
370mapMatrixWithIndexM_ g m = mapVectorWithIndexM_ (mk c g) . flatten $ m 386mapMatrixWithIndexM_ g m = mapVectorWithIndexM_ (mk c g) . flatten $ m
371 where 387 where
372 c = cols m 388 c = cols m
@@ -380,11 +396,9 @@ Just (3><3)
380 , 20.0, 21.0, 122.0 ]@ 396 , 20.0, 21.0, 122.0 ]@
381-} 397-}
382mapMatrixWithIndexM 398mapMatrixWithIndexM
383 :: (Foreign.Storable.Storable t, 399 :: (Element a, Storable b, Monad m) =>
384 Element a, Num a, 400 ((Int, Int) -> a -> m b) -> Matrix a -> m (Matrix b)
385 Functor f, Monad f) => 401mapMatrixWithIndexM g m = liftM (reshape c) . mapVectorWithIndexM (mk c g) . flatten $ m
386 ((Int, Int) -> a -> f t) -> Matrix a -> f (Matrix t)
387mapMatrixWithIndexM g m = fmap (reshape c) . mapVectorWithIndexM (mk c g) . flatten $ m
388 where 402 where
389 c = cols m 403 c = cols m
390 404
@@ -395,10 +409,10 @@ mapMatrixWithIndexM g m = fmap (reshape c) . mapVectorWithIndexM (mk c g) . flat
395 , 10.0, 111.0, 12.0 409 , 10.0, 111.0, 12.0
396 , 20.0, 21.0, 122.0 ]@ 410 , 20.0, 21.0, 122.0 ]@
397 -} 411 -}
398mapMatrixWithIndex :: (Foreign.Storable.Storable t, 412mapMatrixWithIndex
399 Element a, Num a) => 413 :: (Element a, Storable b) =>
400 ((Int, Int) -> a -> t) -> Matrix a -> Matrix t 414 ((Int, Int) -> a -> b) -> Matrix a -> Matrix b
401mapMatrixWithIndex g m = reshape c $ mapVectorWithIndex (mk c g) $ flatten m 415mapMatrixWithIndex g m = reshape c . mapVectorWithIndex (mk c g) . flatten $ m
402 where 416 where
403 c = cols m 417 c = cols m
404 418
diff --git a/lib/Data/Packed/Random.hs b/lib/Data/Packed/Random.hs
index 4b229f0..dabb17d 100644
--- a/lib/Data/Packed/Random.hs
+++ b/lib/Data/Packed/Random.hs
@@ -12,11 +12,11 @@
12----------------------------------------------------------------------------- 12-----------------------------------------------------------------------------
13 13
14module Data.Packed.Random ( 14module Data.Packed.Random (
15 Seed,
15 RandDist(..), 16 RandDist(..),
16 randomVector, 17 randomVector,
17 gaussianSample, 18 gaussianSample,
18 uniformSample, 19 uniformSample
19 meanCov,
20) where 20) where
21 21
22import Numeric.GSL.Vector 22import Numeric.GSL.Vector
@@ -25,9 +25,11 @@ import Numeric.ContainerBoot
25import Numeric.LinearAlgebra.Algorithms 25import Numeric.LinearAlgebra.Algorithms
26 26
27 27
28type Seed = Int
29
28-- | Obtains a matrix whose rows are pseudorandom samples from a multivariate 30-- | Obtains a matrix whose rows are pseudorandom samples from a multivariate
29-- Gaussian distribution. 31-- Gaussian distribution.
30gaussianSample :: Int -- ^ seed 32gaussianSample :: Seed
31 -> Int -- ^ number of rows 33 -> Int -- ^ number of rows
32 -> Vector Double -- ^ mean vector 34 -> Vector Double -- ^ mean vector
33 -> Matrix Double -- ^ covariance matrix 35 -> Matrix Double -- ^ covariance matrix
@@ -40,7 +42,7 @@ gaussianSample seed n med cov = m where
40 42
41-- | Obtains a matrix whose rows are pseudorandom samples from a multivariate 43-- | Obtains a matrix whose rows are pseudorandom samples from a multivariate
42-- uniform distribution. 44-- uniform distribution.
43uniformSample :: Int -- ^ seed 45uniformSample :: Seed
44 -> Int -- ^ number of rows 46 -> Int -- ^ number of rows
45 -> [(Double,Double)] -- ^ ranges for each column 47 -> [(Double,Double)] -- ^ ranges for each column
46 -> Matrix Double -- ^ result 48 -> Matrix Double -- ^ result
@@ -53,14 +55,3 @@ uniformSample seed n rgs = m where
53 am = konst 1 n `outer` a 55 am = konst 1 n `outer` a
54 m = fromColumns (zipWith scale cs dat) `add` am 56 m = fromColumns (zipWith scale cs dat) `add` am
55 57
56------------ utilities -------------------------------
57
58-- | Compute mean vector and covariance matrix of the rows of a matrix.
59meanCov :: Matrix Double -> (Vector Double, Matrix Double)
60meanCov x = (med,cov) where
61 r = rows x
62 k = 1 / fromIntegral r
63 med = konst k r `vXm` x
64 meds = konst 1 r `outer` med
65 xc = x `sub` meds
66 cov = scale (recip (fromIntegral (r-1))) (trans xc `mXm` xc)