diff options
author | Ben Gamari <bgamari.foss@gmail.com> | 2013-08-15 14:19:57 -0400 |
---|---|---|
committer | Ben Gamari <bgamari.foss@gmail.com> | 2013-08-15 14:19:57 -0400 |
commit | 83453a970491fc764a9e490e1f9791a289e9b571 (patch) | |
tree | 33ba6a9eb93129cb98e6ad4aef06e39977fc21d5 /lib/Data/Packed | |
parent | 955d569823230f871fba8c4492b5ad4a4a2def31 (diff) | |
parent | 374194ee454622e66c931dce8f315c68167c7ac9 (diff) |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'lib/Data/Packed')
-rw-r--r-- | lib/Data/Packed/Foreign.hs | 99 | ||||
-rw-r--r-- | lib/Data/Packed/Internal/Matrix.hs | 21 | ||||
-rw-r--r-- | lib/Data/Packed/Internal/Vector.hs | 59 | ||||
-rw-r--r-- | lib/Data/Packed/Matrix.hs | 44 | ||||
-rw-r--r-- | lib/Data/Packed/Random.hs | 21 |
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 | -- | ||
9 | module Data.Packed.Foreign | ||
10 | ( app | ||
11 | , appVector, appVectorLen | ||
12 | , appMatrix, appMatrixLen, appMatrixRaw, appMatrixRawLen | ||
13 | , unsafeMatrixToVector, unsafeMatrixToForeignPtr | ||
14 | ) where | ||
15 | import Data.Packed.Internal | ||
16 | import qualified Data.Vector.Storable as S | ||
17 | import Foreign (Ptr, ForeignPtr, Storable) | ||
18 | import Foreign.C.Types (CInt) | ||
19 | import 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. | ||
24 | unsafeInlinePerformIO :: IO a -> a | ||
25 | unsafeInlinePerformIO (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 | -- | ||
52 | app :: (a -> b) -> a -> b | ||
53 | app f = f | ||
54 | |||
55 | {-# INLINE appVector #-} | ||
56 | appVector :: Storable a => (Ptr a -> b) -> Vector a -> b | ||
57 | appVector f x = unsafeInlinePerformIO (S.unsafeWith x (return . f)) | ||
58 | |||
59 | {-# INLINE appVectorLen #-} | ||
60 | appVectorLen :: Storable a => (CInt -> Ptr a -> b) -> Vector a -> b | ||
61 | appVectorLen f x = unsafeInlinePerformIO (S.unsafeWith x (return . f (fromIntegral (S.length x)))) | ||
62 | |||
63 | {-# INLINE appMatrix #-} | ||
64 | appMatrix :: Element a => (Ptr a -> b) -> Matrix a -> b | ||
65 | appMatrix f x = unsafeInlinePerformIO (S.unsafeWith (flatten x) (return . f)) | ||
66 | |||
67 | {-# INLINE appMatrixLen #-} | ||
68 | appMatrixLen :: Element a => (CInt -> CInt -> Ptr a -> b) -> Matrix a -> b | ||
69 | appMatrixLen 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 #-} | ||
75 | appMatrixRaw :: Storable a => (Ptr a -> b) -> Matrix a -> b | ||
76 | appMatrixRaw f x = unsafeInlinePerformIO (S.unsafeWith (xdat x) (return . f)) | ||
77 | |||
78 | {-# INLINE appMatrixRawLen #-} | ||
79 | appMatrixRawLen :: Element a => (CInt -> CInt -> Ptr a -> b) -> Matrix a -> b | ||
80 | appMatrixRawLen f x = unsafeInlinePerformIO (S.unsafeWith (xdat x) (return . f r c)) | ||
81 | where | ||
82 | r = fromIntegral (rows x) | ||
83 | c = fromIntegral (cols x) | ||
84 | |||
85 | infixl 1 `app` | ||
86 | infixl 1 `appVector` | ||
87 | infixl 1 `appMatrix` | ||
88 | infixl 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'. | ||
93 | unsafeMatrixToVector :: Matrix a -> Vector a | ||
94 | unsafeMatrixToVector = xdat | ||
95 | |||
96 | {-# INLINE unsafeMatrixToForeignPtr #-} | ||
97 | unsafeMatrixToForeignPtr :: Storable a => Matrix a -> (ForeignPtr a, Int) | ||
98 | unsafeMatrixToForeignPtr 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) | |||
47 | import Foreign.C.Types | 47 | import Foreign.C.Types |
48 | import Foreign.C.String(newCString) | 48 | import Foreign.C.String(newCString) |
49 | import System.IO.Unsafe(unsafePerformIO) | 49 | import System.IO.Unsafe(unsafePerformIO) |
50 | import 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]@ |
138 | 9 |> [1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0]@ | ||
139 | -} | ||
140 | flatten :: Element t => Matrix t -> Vector t | 139 | flatten :: Element t => Matrix t -> Vector t |
141 | flatten = xdat . cmat | 140 | flatten = xdat . cmat |
142 | 141 | ||
@@ -459,3 +458,13 @@ size m = (rows m, cols m) | |||
459 | 458 | ||
460 | shSize m = "(" ++ show (rows m) ++"><"++ show (cols m)++")" | 459 | shSize m = "(" ++ show (rows m) ++"><"++ show (cols m)++")" |
461 | 460 | ||
461 | ---------------------------------------------------------------------- | ||
462 | |||
463 | instance (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 | |||
55 | import GHC.IOBase hiding (liftIO) | 55 | import GHC.IOBase hiding (liftIO) |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | #ifdef VECTOR | ||
59 | import qualified Data.Vector.Storable as Vector | 58 | import qualified Data.Vector.Storable as Vector |
60 | import Data.Vector.Storable(Vector, | 59 | import Data.Vector.Storable(Vector, |
61 | unsafeToForeignPtr, | 60 | unsafeToForeignPtr, |
62 | unsafeFromForeignPtr, | 61 | unsafeFromForeignPtr, |
63 | unsafeWith) | 62 | unsafeWith) |
64 | #else | ||
65 | import Foreign.ForeignPtr(withForeignPtr) | ||
66 | #endif | ||
67 | 63 | ||
68 | #ifdef VECTOR | ||
69 | 64 | ||
70 | -- | Number of elements | 65 | -- | Number of elements |
71 | dim :: (Storable t) => Vector t -> Int | 66 | dim :: (Storable t) => Vector t -> Int |
72 | dim = Vector.length | 67 | dim = Vector.length |
73 | 68 | ||
74 | #else | ||
75 | |||
76 | -- | One-dimensional array of objects stored in a contiguous memory block. | ||
77 | data 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 | |||
83 | unsafeToForeignPtr :: Storable a => Vector a -> (ForeignPtr a, Int, Int) | ||
84 | unsafeToForeignPtr v = (fptr v, ioff v, idim v) | ||
85 | |||
86 | -- | Same convention as in Roman Leshchinskiy's vector package. | ||
87 | unsafeFromForeignPtr :: Storable a => ForeignPtr a -> Int -> Int -> Vector a | ||
88 | unsafeFromForeignPtr fp i n | n > 0 = V {ioff = i, idim = n, fptr = fp} | ||
89 | | otherwise = error "unsafeFromForeignPtr with dim < 1" | ||
90 | |||
91 | unsafeWith (V i _ fp) m = withForeignPtr fp $ \p -> m (p `advancePtr` i) | ||
92 | {-# INLINE unsafeWith #-} | ||
93 | |||
94 | -- | Number of elements | ||
95 | dim :: (Storable t) => Vector t -> Int | ||
96 | dim = 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 | |||
210 | subVector = Vector.slice | 176 | subVector = Vector.slice |
211 | 177 | ||
212 | {- | ||
213 | subVector 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 | |||
222 | subVector 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 | {- | ||
227 | subVectorCopy 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 | ||
47 | import Data.List(transpose,intersperse) | 47 | import Data.List(transpose,intersperse) |
48 | import Foreign.Storable(Storable) | 48 | import Foreign.Storable(Storable) |
49 | import 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 | ||
163 | diagBlock :: (Element t, Num t) => [Matrix t] -> Matrix t | ||
164 | diagBlock 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 |
161 | flipud :: Element t => Matrix t -> Matrix t | 174 | flipud :: 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 | ||
354 | mk 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). | ||
370 | mk :: Int -> ((Int, Int) -> t) -> (Int -> t) | ||
371 | mk c g = \k -> g (divMod k c) | ||
355 | 372 | ||
356 | {- | | 373 | {- | |
357 | 374 | ||
@@ -364,9 +381,8 @@ m[1,1] = 5 | |||
364 | m[1,2] = 6@ | 381 | m[1,2] = 6@ |
365 | -} | 382 | -} |
366 | mapMatrixWithIndexM_ | 383 | mapMatrixWithIndexM_ |
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 () | ||
370 | mapMatrixWithIndexM_ g m = mapVectorWithIndexM_ (mk c g) . flatten $ m | 386 | mapMatrixWithIndexM_ 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 | -} |
382 | mapMatrixWithIndexM | 398 | mapMatrixWithIndexM |
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) => | 401 | mapMatrixWithIndexM g m = liftM (reshape c) . mapVectorWithIndexM (mk c g) . flatten $ m |
386 | ((Int, Int) -> a -> f t) -> Matrix a -> f (Matrix t) | ||
387 | mapMatrixWithIndexM 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 | -} |
398 | mapMatrixWithIndex :: (Foreign.Storable.Storable t, | 412 | mapMatrixWithIndex |
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 |
401 | mapMatrixWithIndex g m = reshape c $ mapVectorWithIndex (mk c g) $ flatten m | 415 | mapMatrixWithIndex 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 | ||
14 | module Data.Packed.Random ( | 14 | module 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 | ||
22 | import Numeric.GSL.Vector | 22 | import Numeric.GSL.Vector |
@@ -25,9 +25,11 @@ import Numeric.ContainerBoot | |||
25 | import Numeric.LinearAlgebra.Algorithms | 25 | import Numeric.LinearAlgebra.Algorithms |
26 | 26 | ||
27 | 27 | ||
28 | type 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. |
30 | gaussianSample :: Int -- ^ seed | 32 | gaussianSample :: 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. |
43 | uniformSample :: Int -- ^ seed | 45 | uniformSample :: 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. | ||
59 | meanCov :: Matrix Double -> (Vector Double, Matrix Double) | ||
60 | meanCov 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) | ||