PrimitiveArray 0.0.4.0 → 0.1.1.2
raw patch · 6 files changed
+146/−233 lines, 6 filesdep +repadep +vectordep ~primitivePVP ok
version bump matches the API change (PVP)
Dependencies added: repa, vector
Dependency ranges changed: primitive
API changes (from Hackage documentation)
- Data.PrimitiveArray: amap :: (PrimArrayOps a b, PrimArrayOps a c) => (b -> c) -> PrimArray a b -> PrimArray a c
- Data.PrimitiveArray: checkBounds :: PrimArrayOps a b => PrimArray a b -> a -> Bool
- Data.PrimitiveArray: fromList :: PrimArrayOps a b => a -> a -> [b] -> PrimArray a b
- Data.PrimitiveArray: fromListM :: PrimArrayOpsM a b s => a -> a -> [b] -> s (PrimArrayM a b s)
- Data.PrimitiveArray: instance (Bounded a, Read a, Read b, PrimArrayOps a b) => Read (PrimArray a b)
- Data.PrimitiveArray: instance (Bounded a, Show a, Show b, PrimArrayOps a b) => Show (PrimArray a b)
- Data.PrimitiveArray: toList :: PrimArrayOps a b => PrimArray a b -> [b]
- Data.PrimitiveArray: toListM :: PrimArrayOpsM a b s => PrimArrayM a b s -> s [b]
- Data.PrimitiveArray.Internal: new :: Prim a => Int -> a -> ST s (MutableByteArray s)
- Data.PrimitiveArray.Internal: newWith :: Prim a => Int -> a -> ST s (MutableByteArray s)
- Data.PrimitiveArray.Ix: instance (Bounded a, Ix a, Prim b) => PrimArrayOps a b
- Data.PrimitiveArray.Ix: instance (Bounded a, Ix a, Prim b) => PrimArrayOpsM a b (ST s)
+ Data.PrimitiveArray: inBounds :: PrimArrayOps sh elm => PrimArray sh elm -> sh -> Bool
+ Data.PrimitiveArray: inBoundsM :: PrimArrayOpsM sh elm m => PrimArrayM sh elm m -> sh -> Bool
+ Data.PrimitiveArray.Unboxed: instance (Read elm, Read sh, Unbox elm) => Read (PrimArray sh elm)
+ Data.PrimitiveArray.Unboxed: instance (Show elm, Show sh, Unbox elm) => Show (PrimArray sh elm)
+ Data.PrimitiveArray.Unboxed: instance (Unbox elm, Shape sh) => PrimArrayOpsM sh elm (ST s)
+ Data.PrimitiveArray.Unboxed: instance (Unbox elm, Shape sh) => PrimArrayOpsM sh elm IO
+ Data.PrimitiveArray.Unboxed: instance (Unbox elm, Shape sh, Show elm, Show sh) => PrimArrayOps sh elm
- Data.PrimitiveArray: (!) :: PrimArrayOps a b => PrimArray a b -> a -> b
+ Data.PrimitiveArray: (!) :: PrimArrayOps sh elm => PrimArray sh elm -> sh -> elm
- Data.PrimitiveArray: assocs :: PrimArrayOps a b => PrimArray a b -> [(a, b)]
+ Data.PrimitiveArray: assocs :: PrimArrayOps sh elm => PrimArray sh elm -> [(sh, elm)]
- Data.PrimitiveArray: bounds :: PrimArrayOps a b => PrimArray a b -> (a, a)
+ Data.PrimitiveArray: bounds :: PrimArrayOps sh elm => PrimArray sh elm -> (sh, sh)
- Data.PrimitiveArray: boundsM :: PrimArrayOpsM a b s => PrimArrayM a b s -> s (a, a)
+ Data.PrimitiveArray: boundsM :: PrimArrayOpsM sh elm m => PrimArrayM sh elm m -> (sh, sh)
- Data.PrimitiveArray: class PrimArrayOps a b where { data family PrimArray a b :: *; }
+ Data.PrimitiveArray: class Shape sh => PrimArrayOps sh elm where { data family PrimArray sh elm :: *; }
- Data.PrimitiveArray: class PrimMonad s => PrimArrayOpsM a b s where { data family PrimArrayM a b s :: *; }
+ Data.PrimitiveArray: class (PrimMonad m, Shape sh) => PrimArrayOpsM sh elm m where { data family PrimArrayM sh elm m :: *; }
- Data.PrimitiveArray: fromAssocs :: PrimArrayOps a b => a -> a -> b -> [(a, b)] -> PrimArray a b
+ Data.PrimitiveArray: fromAssocs :: PrimArrayOps sh elm => sh -> sh -> elm -> [(sh, elm)] -> PrimArray sh elm
- Data.PrimitiveArray: fromAssocsM :: PrimArrayOpsM a b s => a -> a -> b -> [(a, b)] -> s (PrimArrayM a b s)
+ Data.PrimitiveArray: fromAssocsM :: PrimArrayOpsM sh elm m => sh -> sh -> elm -> [(sh, elm)] -> m (PrimArrayM sh elm m)
- Data.PrimitiveArray: readM :: PrimArrayOpsM a b s => PrimArrayM a b s -> a -> s b
+ Data.PrimitiveArray: readM :: PrimArrayOpsM sh elm m => PrimArrayM sh elm m -> sh -> m elm
- Data.PrimitiveArray: unsafeFreezeM :: PrimArrayOpsM a b s => PrimArrayM a b s -> s (PrimArray a b)
+ Data.PrimitiveArray: unsafeFreezeM :: PrimArrayOpsM sh elm m => PrimArrayM sh elm m -> m (PrimArray sh elm)
- Data.PrimitiveArray: unsafeIndex :: PrimArrayOps a b => PrimArray a b -> a -> b
+ Data.PrimitiveArray: unsafeIndex :: PrimArrayOps sh elm => PrimArray sh elm -> sh -> elm
- Data.PrimitiveArray: writeM :: PrimArrayOpsM a b s => PrimArrayM a b s -> a -> b -> s ()
+ Data.PrimitiveArray: writeM :: PrimArrayOpsM sh elm m => PrimArrayM sh elm m -> sh -> elm -> m ()
Files
- Benchmarks/Index.hs +0/−51
- Data/PrimitiveArray.hs +28/−76
- Data/PrimitiveArray/Internal.hs +0/−23
- Data/PrimitiveArray/Ix.hs +0/−68
- Data/PrimitiveArray/Unboxed.hs +97/−0
- PrimitiveArray.cabal +21/−15
− Benchmarks/Index.hs
@@ -1,51 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE ScopedTypeVariables #-}---- | Benchmark the folding functions. As these functions need several tables to--- read data from, we have to initialize some stuff. The benchmarks test access--- and calculation patterns that are common in bioinformatics.------ For best results, compile with "-Odph -fllvm" (6.13) or "-Odph" (6.12). This--- is for the unboxed vectors. Both benchmarks should clock at about 10us.--module Main where--import Criterion.Main-import Control.DeepSeq-import System.Random-import qualified Data.Vector.Unboxed as VU--import Data.PrimitiveArray-import Data.PrimitiveArray.Ix-import Data.Primitive.Types----hi = 999--main = do- rng <- getStdGen- let (table :: PrimArray (Int,Int) Int) = fromAssocs (0,0) (hi,hi) 0 $ zip- [ (i,j)- | i<-[0..hi]- , j<-[0..hi]- ] $ randomRs (0,hi) rng- print $ table ! (0,0)- print $ table ! (hi,hi)- defaultMain- [ bgroup "compare"- [ bench "unsafeIndex" $- whnf (\k -> {-# CORE "sum/unsafeIndex" #-}- VU.foldl' min 999999 $- VU.map (\ij -> table ! ij) $- VU.generate k (\z -> (z,z))- ) hi- , bench "twiceIndex" $- whnf (\k -> {-# CORE "sum/twiceIndex" #-}- VU.foldl' min 999999 $- VU.map (\(i,j) -> (table ! (i,0)) + (table ! (0,j))) $- VU.generate k (\z -> (z,z))- ) hi- ]- ]
Data/PrimitiveArray.hs view
@@ -1,94 +1,46 @@-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE RankNTypes #-} --- | Unboxed, primitive, multidimensional tables. In instance for 'Ix'-type--- keys comes with the package. This package trades safety for speed. The index--- operator (!) is basically the only function that does bounds-checking and--- only with an assertion. This, however, is by design. The only way to get an--- immutable table from a mutable one is by the 'unsafeFreezeM' operation.--- Again, it is by design that both data structures share the same memory--- pointer internally.+-- | Primitive arrays with a small set of operations. Modelled after repa+-- arrays and indexing. ----- TODO We kind-of lost all but the ST monad for monadic operations.+-- Array indexing is between [i..j] per dimension.+--+-- All operations are UNSAFE. In interpreted code, "assert" provides a safety+-- net. module Data.PrimitiveArray where import Control.Monad.Primitive (PrimMonad)+import Data.Array.Repa.Shape (Shape) import Control.Exception (assert)-import Text.Read.Lex as L-import Text.Read-import Text.ParserCombinators.ReadP --- * The PrimArray class. -class PrimArrayOps a b where- -- | PrimArray data type- data PrimArray a b :: *- unsafeIndex :: PrimArray a b -> a -> b -- ^ Index an array without bounds-checking- assocs :: PrimArray a b -> [(a,b)] -- ^ All associations of (key,value)- fromAssocs :: a -> a -> b -> [(a,b)] -> PrimArray a b -- ^ Pure build function- bounds :: PrimArray a b -> (a,a) -- ^ Min- and maxbound of all dimensions- checkBounds :: PrimArray a b -> a -> Bool -- ^ Check if index is within bounds- fromList :: a -> a -> [b] -> PrimArray a b -- ^ Build the /complete/ table from a list- toList :: PrimArray a b -> [b] -- ^ Read the complete table as a list +class Shape sh => PrimArrayOps sh elm where+ data PrimArray sh elm :: *+ unsafeIndex :: PrimArray sh elm -> sh -> elm+ bounds :: PrimArray sh elm -> (sh,sh)+ inBounds :: PrimArray sh elm -> sh -> Bool+ fromAssocs :: sh -> sh -> elm -> [(sh,elm)] -> PrimArray sh elm+ assocs :: PrimArray sh elm -> [(sh,elm)] -class (PrimMonad s) => PrimArrayOpsM a b s where- -- | Monadic data type- data PrimArrayM a b s :: *- readM :: PrimArrayM a b s -> a -> s b -- ^ Monadic read- writeM :: PrimArrayM a b s -> a -> b -> s () -- ^ Monadic write- boundsM :: PrimArrayM a b s -> s (a,a) -- ^ Monadic bounds- fromAssocsM :: a -> a -> b -> [(a,b)] -> s (PrimArrayM a b s) -- ^ Build monadic array from assocs- unsafeFreezeM :: PrimArrayM a b s -> s (PrimArray a b) -- ^ UNSAFE freezing of array.- fromListM :: a -> a -> [b] -> s (PrimArrayM a b s) -- ^ Build the /complete/ monadic table from a list- toListM :: PrimArrayM a b s -> s [b] -- ^ Read the complete monadic table as a list+class (PrimMonad m, Shape sh) => PrimArrayOpsM sh elm m where+ data PrimArrayM sh elm m :: *+ readM :: PrimArrayM sh elm m -> sh -> m elm+ writeM :: PrimArrayM sh elm m -> sh -> elm -> m ()+ -- | Create a monadic array from a list of associations+ fromAssocsM :: sh -> sh -> elm -> [(sh,elm)] -> m (PrimArrayM sh elm m)+ unsafeFreezeM :: PrimArrayM sh elm m -> m (PrimArray sh elm)+ boundsM :: PrimArrayM sh elm m -> (sh,sh)+ inBoundsM :: PrimArrayM sh elm m -> sh -> Bool --- * Helper functions.---- | Asserting 'unsafeIndex'. Debug-code is checked for out-of-bounds--- occurances while production code uses unsafeIndex directly.+-- * Helper functions -(!) :: (PrimArrayOps a b) => PrimArray a b -> a -> b-(!) pa idx = assert (checkBounds pa idx) $ unsafeIndex pa idx+(!) :: PrimArrayOps sh elm => PrimArray sh elm -> sh -> elm+(!) pa idx = assert (inBounds pa idx) $ unsafeIndex pa idx {-# INLINE (!) #-} --- | Create a new array from an old one, mapping a function over all values.--amap :: (PrimArrayOps a b, PrimArrayOps a c) => (b -> c) -> PrimArray a b -> PrimArray a c-amap f pa = fromList lb ub $ map f $ toList pa where- (lb,ub) = bounds pa------ * Read and show instances---- | The Show instance looks a bit like Show for Data.Vector.Unboxed--instance (Bounded a, Show a, Show b, PrimArrayOps a b) => Show (PrimArray a b) where- show pa = "fromList " ++ show l ++ " " ++ show u ++ " " ++ (show $ toList pa) ++ " :: Data.PrimitiveArray.PrimitiveArray" where- (l,u) = bounds pa---- | The Read instance follows Read for Data.Vector.Unboxed--instance (Bounded a, Read a, Read b, PrimArrayOps a b) => Read (PrimArray a b) where- readPrec =- parens $ do- lift $ skipSpaces- L.Ident "fromList" <- lexP- lift $ skipSpaces- (l :: a) <- readPrec- lift $ skipSpaces- (u :: a) <- readPrec- (vals :: [b]) <- readPrec- lift $ skipSpaces- lift $ string "::"- lift $ skipSpaces- lift $ string "Data.PrimitiveArray.PrimitiveArray"- lift $ skipSpaces- return $ fromList l u vals- readListPrec = readListPrecDefault- readList = readListDefault
− Data/PrimitiveArray/Internal.hs
@@ -1,23 +0,0 @@---- | Helper functions for creating new arrays.--module Data.PrimitiveArray.Internal where--import Data.Primitive-import Control.Monad.ST-import Control.Monad (forM_)---- | Create a new m-array with a default value.--newWith :: (Prim a) => Int -> a -> ST s (MutableByteArray s)-newWith l z = do- marr <- new l z- forM_ [0..l-1] $ \k -> (writeByteArray marr k z)- return marr---- | In 'new', 'z' is not used.--new :: (Prim a) => Int -> a -> ST s (MutableByteArray s)-new l z = do- marr <- newByteArray (l * sizeOf z)- return marr
− Data/PrimitiveArray/Ix.hs
@@ -1,68 +0,0 @@--{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE MultiParamTypeClasses #-}---- | PrimitiveArray with 'Ix' keys.--module Data.PrimitiveArray.Ix where--import Data.Primitive-import Control.Monad.ST-import Control.Monad (liftM, forM_, zipWithM_, forM)-import Data.Primitive.Types-import qualified GHC.Arr as A--import Data.PrimitiveArray-import Data.PrimitiveArray.Internal----instance (Bounded a, A.Ix a, Prim b) => PrimArrayOps a b where- data PrimArray a b = PaIxP !a !a {-# UNPACK #-} !ByteArray- unsafeIndex (PaIxP lb ub arr) i = indexByteArray arr (A.unsafeIndex (lb,ub) i)- assocs (pa@(PaIxP lb ub _)) = [(i, unsafeIndex pa i) | i<-A.range(lb,ub) ]- fromAssocs l u z xs = runST $ do- pam <- fromAssocsM l u z xs- unsafeFreezeM pam- bounds (PaIxP lb ub _) = (lb,ub)- checkBounds (PaIxP lb ub _) i = A.inRange (lb,ub) i- fromList l u xs = runST $ do- pam <- fromListM l u xs- unsafeFreezeM pam- toList pa@(PaIxP lb ub _) = [unsafeIndex pa i | i <- A.range(lb,ub)]- {-# INLINE unsafeIndex #-}- {-# INLINE assocs #-}- {-# INLINE fromAssocs #-}- {-# INLINE bounds #-}- {-# INLINE checkBounds #-}- {-# INLINE fromList #-}- {-# INLINE toList #-}--instance (Bounded a, A.Ix a, Prim b) => PrimArrayOpsM a b (ST s) where- data PrimArrayM a b (ST s) = PaIxPM !a !a {-# UNPACK #-} !(MutableByteArray s)- readM (PaIxPM lb ub marr) i = readByteArray marr (A.unsafeIndex (lb,ub) i)- writeM (PaIxPM lb ub marr) i val = writeByteArray marr (A.unsafeIndex (lb,ub) i) val- boundsM (PaIxPM lb ub _) = return (lb,ub)- fromAssocsM lb ub z xs = do- let l = A.rangeSize (lb,ub)- pam <- PaIxPM lb ub `liftM` newWith l z- forM_ xs $ uncurry (writeM pam)- return pam- unsafeFreezeM (PaIxPM lb ub marr) = do- arr <- unsafeFreezeByteArray marr- return $ PaIxP lb ub arr- fromListM lb ub xs = do- let l = A.rangeSize (lb,ub)- pam <- PaIxPM lb ub `liftM` new l (undefined `asTypeOf` head xs)- zipWithM_ (writeM pam) (A.range (lb,ub)) xs- return pam- toListM pam@(PaIxPM lb ub _) = forM (A.range (lb,ub)) (readM pam)- {-# INLINE readM #-}- {-# INLINE writeM #-}- {-# INLINE boundsM #-}- {-# INLINE fromAssocsM #-}- {-# INLINE unsafeFreezeM #-}- {-# INLINE fromListM #-}- {-# INLINE toListM #-}-
+ Data/PrimitiveArray/Unboxed.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}++module Data.PrimitiveArray.Unboxed where++import qualified Data.Vector.Unboxed.Mutable as VUM+import qualified Data.Vector.Unboxed as VU+import Control.Monad.ST+import Control.Monad+import Data.Array.Repa.Shape+import Control.Exception (assert)++import Data.PrimitiveArray++import Data.Array.Repa.Index++++instance (VU.Unbox elm, Shape sh, Show elm, Show sh) => PrimArrayOps sh elm where+ -- | An immutable PrimArray has a lower bound (lsh), and upper bound (ush)+ -- and an upper bound minus unitDim (ush'), returned by bounds+ data PrimArray sh elm = PrimArray sh sh sh (VU.Vector elm)+ unsafeIndex (PrimArray lsh ush ush' v) idx = assert (inShapeRange lsh ush idx)+ $ v `VU.unsafeIndex` (toIndex ush idx - toIndex ush lsh)+ bounds (PrimArray lsh ush ush' _) = (lsh,ush')+ inBounds (PrimArray lsh ush ush' _) idx = inShapeRange lsh ush idx+ fromAssocs lsh ush' def xs =+ let ush = ush' `addDim` unitDim+ in PrimArray lsh ush ush'+ $ VU.replicate (size ush - size lsh) def+ VU.// map (\(k,v) -> if (inShapeRange lsh ush k)+ then (toIndex ush k - toIndex ush lsh,v)+ else error $ show (lsh,ush,k,v)+ ) xs+ assocs (PrimArray lsh ush ush' v) = map (\(k,v) -> (fromIndex ush $ k + toIndex ush lsh, v))+ . VU.toList+ . VU.indexed+ $ v+ {-# INLINE unsafeIndex #-}+ {-# INLINE bounds #-}+ {-# INLINE inBounds #-}+ {-# INLINE fromAssocs #-}++deriving instance (Show elm, Show sh, VU.Unbox elm) => Show (PrimArray sh elm)++deriving instance (Read elm, Read sh, VU.Unbox elm) => Read (PrimArray sh elm)++++instance (VUM.Unbox elm, Shape sh) => PrimArrayOpsM sh elm (ST s) where+ data PrimArrayM sh elm (ST s) = PrimArrayST sh sh sh (VUM.STVector s elm)+ readM (PrimArrayST lsh ush ush' v) sh = VUM.unsafeRead v (toIndex ush sh - toIndex ush lsh)+ writeM (PrimArrayST lsh ush suh' v) sh e = VUM.unsafeWrite v (toIndex ush sh - toIndex ush lsh) e+ fromAssocsM lsh ush' def xs = do+ let ush = ush' `addDim` unitDim+ v <- VUM.new (size ush - size lsh)+ VUM.set v def+ forM_ xs $ \(k,e) -> assert (inShapeRange lsh ush k)+ $ VUM.unsafeWrite v (toIndex ush k - toIndex ush lsh) e+ return $ PrimArrayST lsh ush ush' v+ unsafeFreezeM (PrimArrayST lsh ush ush' v) = do+ v' <- VU.unsafeFreeze v+ return $ PrimArray lsh ush ush' v'+ boundsM (PrimArrayST lsh ush ush' _) = (lsh,ush')+ inBoundsM (PrimArrayST lsh ush ush' _) idx = inShapeRange lsh ush idx+ {-# INLINE readM #-}+ {-# INLINE writeM #-}+ {-# INLINE fromAssocsM #-}+ {-# INLINE unsafeFreezeM #-}+ {-# INLINE boundsM #-}+ {-# INLINE inBoundsM #-}++instance (VUM.Unbox elm, Shape sh) => PrimArrayOpsM sh elm IO where+ data PrimArrayM sh elm IO = PrimArrayIO sh sh sh (VUM.IOVector elm)+ readM (PrimArrayIO lsh ush ush' v) sh = VUM.unsafeRead v (toIndex ush sh - toIndex ush lsh)+ writeM (PrimArrayIO lsh ush suh' v) sh e = VUM.unsafeWrite v (toIndex ush sh - toIndex ush lsh) e+ fromAssocsM lsh ush' def xs = do+ let ush = ush' `addDim` unitDim+ v <- VUM.new (size ush - size lsh)+ VUM.set v def+ forM_ xs $ \(k,e) -> assert (inShapeRange lsh ush k)+ $ VUM.unsafeWrite v (toIndex ush k - toIndex ush lsh) e+ return $ PrimArrayIO lsh ush ush' v+ unsafeFreezeM (PrimArrayIO lsh ush ush' v) = do+ v' <- VU.unsafeFreeze v+ return $ PrimArray lsh ush ush' v'+ boundsM (PrimArrayIO lsh ush ush' _) = (lsh,ush')+ inBoundsM (PrimArrayIO lsh ush ush' _) idx = inShapeRange lsh ush idx+ {-# INLINE readM #-}+ {-# INLINE writeM #-}+ {-# INLINE fromAssocsM #-}+ {-# INLINE unsafeFreezeM #-}+ {-# INLINE boundsM #-}+ {-# INLINE inBoundsM #-}+
PrimitiveArray.cabal view
@@ -1,34 +1,40 @@ Name: PrimitiveArray-Version: 0.0.4.0+Version: 0.1.1.2 License: BSD3 License-file: LICENSE Author: Christian Hoener zu Siederdissen Maintainer: choener@tbi.univie.ac.at-Copyright: Christian Hoener zu Siederdissen, 2010-2011+Copyright: Christian Hoener zu Siederdissen, 2010-2012 Homepage: http://www.tbi.univie.ac.at/~choener/ Stability: Experimental Category: Data Build-type: Simple-Cabal-version: >=1.2+Cabal-version: >=1.6 Synopsis:- Unboxed, multidimensional arrays based on the primitive- package.+ Efficient multidimensional arrays Description:- Provides unboxed multidimensional tables with a small- interface. Comes with an instance for Ix keys. Read and Show- instances are provided for serialization.--extra-source-files:- Benchmarks/Index.hs+ This library provides efficient multidimensional arrays. All+ arrays are 0-based and indexed using repa-shapes.+ .+ Please note that this version only has the name (and author) in+ common with the previous 0.0.4.0 version. The basic idea of the+ library remains the same: provide efficient access to immutable+ arrays. Library Exposed-modules: Data.PrimitiveArray- Data.PrimitiveArray.Ix- Data.PrimitiveArray.Internal+ Data.PrimitiveArray.Unboxed Build-depends: base >= 4 && <5,- primitive >= 0.4.0.1 && < 0.5+ primitive >= 0.4,+ vector >= 0.9,+ repa >= 2.0 ghc-options:- -O2+ -Odph+ -funbox-strict-fields++source-repository head+ type: git+ location: git://github.com/choener/PrimitiveArray