PrimitiveArray 0.5.0.0 → 0.5.2.0
raw patch · 6 files changed
+412/−25 lines, 6 files
Files
- Data/Array/Repa/Index/Outside.hs +171/−0
- Data/Array/Repa/Index/Points.hs +151/−0
- Data/PrimitiveArray/FillTables.hs +37/−16
- Data/PrimitiveArray/QuickCheck.hs +5/−0
- Data/PrimitiveArray/Zero.hs +44/−3
- PrimitiveArray.cabal +4/−6
+ Data/Array/Repa/Index/Outside.hs view
@@ -0,0 +1,171 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeOperators #-}++-- | 'Outside' covers subwords for outside calculations. These types of+-- calculations requires quite "weird" index movements if you want to stay with+-- usual grammars. This remains true if grammars are transformed to Chomsky+-- normal form, only that in said form it is easier to write down the+-- recursions.+--+-- TODO basically untested!++module Data.Array.Repa.Index.Outside where++import Control.Applicative+import Control.DeepSeq+import Data.Array.Repa.Index+import Data.Array.Repa.Shape+import GHC.Base (quotInt, remInt)+import Test.QuickCheck+import Test.QuickCheck.All+import qualified Data.Vector.Unboxed as VU+import Data.Vector.Unboxed.Deriving++import Data.Array.Repa.ExtShape+import Data.Array.Repa.Index.Subword hiding (upperTri, subwordIndex, subwordFromIndex)+import qualified Data.Array.Repa.Index.Subword as SW++++stage = "Data.Array.Repa.Index.Outside"++-- | 'Outside' inverts the usual subword (i,j) system.+--+-- TODO do I need to store N ?++newtype Outside = Outside (Int:.Int)+ deriving (Eq,Ord,Show)++derivingUnbox "Outside"+ [t| Outside -> (Int,Int) |]+ [| \ (Outside (i:.j)) -> (i,j) |]+ [| \ (i,j) -> Outside (i:.j) |]++outside :: Int -> Int -> Outside+outside i j = Outside (i:.j)+{-# INLINE outside #-}++-- | Size of an upper triangle starting at 'i' and ending at 'j'. "(0,N)" what+-- be the normal thing to use. Internally, we stell upper triangular matrices.++upperTri :: Outside -> Int+upperTri (Outside (i:.j)) = triangularNumber $ j-i+{-# INLINE upperTri #-}++-- | Outside indexing. Given the longest subword and the current subword,+-- calculate a linear index "[0,..]". "(l,n)" in this case means "l"ower bound,+-- length "n". And "(i,j)" is the normal index.+--+-- TODO probably doesn't work right with non-zero base ?!++subwordIndex :: Outside -> Outside -> Int+subwordIndex (Outside (l:.n)) (Outside (i:.j)) = adr n (i,j) -- - adr n (l,n)+ where+ adr n (i,j) = n*i - triangularNumber i + j+{-# INLINE subwordIndex #-}++subwordFromIndex :: Outside -> Int -> Outside+subwordFromIndex = error "not implemented"+{-# INLINE subwordFromIndex #-}++++-- | Some weird things are going on here. Adding subwords (i,j) and (k,l)+-- yields (i+k,j+l). Normally i==k==0 when calculating space requirements. If+-- you have a subword (3,10) and want the next outer one add (-1,1) and you get+-- what you want. We make NO(!) check that the final subword contains only+-- non-negative indices.++instance Shape sh => Shape (sh :. Outside) where+ {-# INLINE [1] rank #-}+ rank (sh :. _)+ = rank sh + 1+ {-# INLINE [1] zeroDim #-}+ zeroDim = zeroDim :. Outside (0:.0)++ {-# INLINE [1] unitDim #-}+ unitDim = unitDim :. Outside (0:.1)++ {-# INLINE [1] intersectDim #-}+ intersectDim (sh1 :. Outside (i:.j)) (sh2 :. Outside (k:.l))+ = (intersectDim sh1 sh2 :. Outside (max i k :. min j l))++ {-# INLINE [1] addDim #-}+ addDim (sh1 :. Outside (i:.j)) (sh2 :. Outside (k:.l))+ = addDim sh1 sh2 :. Outside (i+k:.j+l)++ {-# INLINE [1] size #-}+ size (sh1 :. sw) = size sh1 * upperTri sw++ {-# INLINE [1] sizeIsValid #-}+ sizeIsValid (sh1 :. Outside (i:.j))+ | size sh1 > 0+ = i>=0 && i<=j && j <= maxBound `div` size sh1+ | otherwise+ = False++ {-# INLINE [1] toIndex #-}+ toIndex (sh1 :. sh2) (sh1' :. sh2')+ = toIndex sh1 sh1' * upperTri sh2 + subwordIndex sh2 sh2'++ {-# INLINE [1] fromIndex #-}+ fromIndex (ds :. d) n = undefined -- fromIndex ds (n `quotInt` d) :. r+ where+ r = subwordFromIndex d n+ -- If we assume that the index is in range, there is no point+ -- in computing the remainder for the highest dimension since+ -- n < d must hold. This saves one remInt per element access which+ -- is quite a big deal.+ {-+ r | rank ds == 0 = n+ | otherwise = n `remInt` d -}++ -- | TODO fix for lower bounds check!+ {-# INLINE [1] inShapeRange #-}+ inShapeRange (zs :. Outside (_:._)) (sh1 :. Outside (l:.n)) (sh2 :. Outside (i:.j))+ = i<=j && l<=i && j<n && (inShapeRange zs sh1 sh2)++ {-# NOINLINE listOfShape #-}+ listOfShape (sh :. Outside (i:.j)) = i : j : listOfShape sh++ {-# NOINLINE shapeOfList #-}+ shapeOfList xx+ = case xx of+ [] -> error $ stage ++ ".toList: empty list when converting to (_ :. Int)"+ [x] -> error $ stage ++ ".toList: only single element remaining!"+ i:j:xs -> shapeOfList xs :. Outside (i:.j)++ {-# INLINE deepSeq #-}+ deepSeq (sh :. n) x = deepSeq sh (n `seq` x)++-- |++instance ExtShape sh => ExtShape (sh:.Outside) where+ subDim (sh1:.Outside (i:.j)) (sh2:.Outside (k:.l)) = subDim sh1 sh2 :. Outside (i-k:.j-l)+ {-# INLINE subDim #-}+ rangeList (sh1:.Outside (i:.j)) (sh2:.Outside (k:.l)) = error "not implemented" -- [sh:.Outside (m,n) | sh <- rangeList sh1 sh2, m <- [i .. [i+k], n <- [ n <- [n1 .. (n1+n2) ] ]+ {-# INLINE rangeList #-}++-- |++instance NFData Outside where+ rnf (Outside (i:.j)) = i `seq` rnf j++-- |++instance Arbitrary Outside where+ arbitrary = do+ a <- choose (0,100)+ b <- choose (0,100)+ return $ Outside (min a b :. max a b)+ shrink (Outside (i:.j))+ | i<j = [Outside (i:.j-1)]+ | otherwise = []++instance Arbitrary z => Arbitrary (z:.Outside) where+ arbitrary = (:.) <$> arbitrary <*> arbitrary+ shrink (z:.s) = (:.) <$> shrink z <*> shrink s+
+ Data/Array/Repa/Index/Points.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}++-- | Index structures for left- and right-linear grammars. Do not use this+-- index for general linear- or context-free grammars.+--+-- Internally, both 'PointL' and 'PointR' work a lot like 'Subword's, but in+-- non-terminals we only store the left- or right part.++module Data.Array.Repa.Index.Points where++import Control.Applicative+import Control.DeepSeq+import Data.Array.Repa.Index+import Data.Array.Repa.Shape+import Data.Vector.Unboxed.Deriving+import GHC.Base (quotInt, remInt)+import qualified Data.Vector.Unboxed as VU+import Test.QuickCheck+import Test.QuickCheck.All++import Data.Array.Repa.ExtShape+import Data.Array.Repa.Index.Subword++++-- | A point in left-linear grammars. In @(i:.j)@, @j@ is the non-terminal+-- storage point, @i==0@ always for the non-terminal, while @i>=0@ for+-- terminals, which are on the right of the non-terminal. (This is why+-- left-linear grammars are called left-linear: they recurse on the left).+--+-- PS: all this left/right talk deals with the RHS of a production rule, the+-- LHS is always a non-terminal ;-)++newtype PointL = PointL (Int:.Int)+ deriving (Eq,Read,Show)++pointL :: Int -> Int -> PointL+pointL i j = PointL (i:.j)+{-# INLINE pointL #-}++-- | A point in right-linear grammars.++newtype PointR = PointR (Int:.Int)++pointR :: Int -> Int -> PointR+pointR i j = PointR (i:.j)+{-# INLINE pointR #-}++++-- * Instances++derivingUnbox "PointL"+ [t| PointL -> (Int,Int) |]+ [| \ (PointL (i:.j)) -> (i,j) |]+ [| \ (i,j) -> PointL (i:.j) |]++derivingUnbox "PointR"+ [t| PointR -> (Int,Int) |]+ [| \ (PointR (i:.j)) -> (i,j) |]+ [| \ (i,j) -> PointR (i:.j) |]++instance Shape sh => Shape (sh :. PointL) where+ {-# INLINE [1] rank #-}+ rank (sh :. _)+ = rank sh + 1++ {-# INLINE [1] zeroDim #-}+ zeroDim = zeroDim :. PointL (0:.0)++ {-# INLINE [1] unitDim #-}+ unitDim = unitDim :. PointL (0:.1)++ {-# INLINE [1] intersectDim #-}+ intersectDim (sh1 :. PointL (i:.j)) (sh2 :. PointL (k:.l))+ = (intersectDim sh1 sh2 :. PointL (max i k :. min j l))++ {-# INLINE [1] addDim #-}+ addDim (sh1 :. PointL (i:.j)) (sh2 :. PointL (k:.l))+ = addDim sh1 sh2 :. PointL (i+k:.j+l)++ -- NOTE size is calculated NOT as upper-triangular, but linear!+ {-# INLINE [1] size #-}+ size (sh1 :. PointL (i:.j)) = size sh1 * (j-i)++ {-# INLINE [1] sizeIsValid #-}+ sizeIsValid (sh1 :. PointL (i:.j))+ | size sh1 > 0+ = i>=0 && i<=j && j <= maxBound `div` size sh1+ | otherwise+ = False++ -- NOTE only the @j@ coordinate is used for indexing NTs, @i@ is just for+ -- convenience. @l@ however restricts the NT to some value @>0@ if desired.+ {-# INLINE [1] toIndex #-}+ toIndex (sh1 :. PointL(l:.r)) (sh1' :. PointL(i:.j))+ = toIndex sh1 sh1' * (r-l) + (j-l)++ {-# INLINE [1] fromIndex #-}+ fromIndex (ds :. d) n = undefined -- fromIndex ds (n `quotInt` d) :. r+ where+ r = undefined++ -- | TODO fix for lower bounds check!+ {-# INLINE [1] inShapeRange #-}+ inShapeRange (zs :. PointL (_:._)) (sh1 :. PointL (l:.n)) (sh2 :. PointL (i:.j))+ = i<=j && l<=i && j<n && (inShapeRange zs sh1 sh2)++ {-# NOINLINE listOfShape #-}+ listOfShape (sh :. PointL (i:.j)) = i : j : listOfShape sh++ {-# NOINLINE shapeOfList #-}+ shapeOfList xx+ = case xx of+ [] -> error $ stage ++ ".toList: empty list when converting to (_ :. Int)"+ [x] -> error $ stage ++ ".toList: only single element remaining!"+ i:j:xs -> shapeOfList xs :. PointL (i:.j)++ {-# INLINE deepSeq #-}+ deepSeq (sh :. n) x = deepSeq sh (n `seq` x)++instance ExtShape sh => ExtShape (sh:.PointL) where+ {-# INLINE [1] subDim #-}+ subDim (sh1:.PointL (i:.j)) (sh2:.PointL (k:.l)) = subDim sh1 sh2 :. PointL (i-k:.j-l)+ {-# INLINE [1] rangeList #-}+ rangeList _ _ = error "PointL:rangeList not implemented"++instance NFData PointL where+ rnf (PointL (i:.j)) = i `seq` rnf j+ {-# INLINE rnf #-}++-- TODO maybe vary the left border, too? Since this invalidates that @i==0@ in+-- @PointL (i:.j)@, we would need to make sure that the memoizers for NTs get+-- notified ...++instance Arbitrary PointL where+ arbitrary = do+ b <- choose (0,100)+ return $ pointL 0 b+ shrink (PointL (i:.j))+ | i<j = [pointL i $ j-1]+ | otherwise = []++instance Arbitrary z => Arbitrary (z:.PointL) where+ arbitrary = (:.) <$> arbitrary <*> arbitrary+ shrink (z:.s) = (:.) <$> shrink z <*> shrink s+
Data/PrimitiveArray/FillTables.hs view
@@ -21,6 +21,8 @@ +-- * Driver classes for table filling system.+ -- Upper triangular table filling. Right now, only a serial option 'upperTriS' -- is available. --@@ -29,18 +31,28 @@ class UpperTriS m stack where upperTriS :: stack -> m () --- |---+-- | Defines how a single index in a stack of arrays + evaluation functions is+-- handled. The instances *should* work for any index @ix@.++class Stack m sh xs where+ writeStack :: xs -> sh -> m ()++++-- * Instances++-- ** 1-tape grammars with 'Subword' indices.+ -- TODO Insert check that all extends are the same! instance ( Monad m- , MPrimArrayOps arr Subword e- , Stack m Subword (xs:.MutArr m (arr Subword e))- ) => UpperTriS m (xs:.MutArr m (arr Subword e)) where- upperTriS xs@(_:.x) = do+ , MPrimArrayOps arr (Z:.Subword) e+ , Stack m Subword (xs :. SubwordNonTerminal m arr e)+ ) => UpperTriS m (xs :. SubwordNonTerminal m arr e) where+ upperTriS xs@(_:.(x,f)) = do -- TODO missing extends check- let (Subword (l:._),Subword (u:._)) = boundsM x+ let (Z:.Subword (l:._),Z:.Subword (u:._)) = boundsM x S.mapM_ (go xs) $ unfolder l u where -- Write all table values at a certain subword. Note that tables are@@ -60,13 +72,15 @@ {-# INLINE unfolder #-} {-# INLINE upperTriS #-} ----- | Defines how a single index in a stack of arrays + evaluation functions is--- handled.+instance+ ( PrimMonad m+ , Stack m Subword xs+ , MPrimArrayOps arr (Z:.Subword) e+ ) => Stack m Subword (xs :. SubwordNonTerminal m arr e) where+ writeStack (xs:.(x,f)) i = writeStack xs i >> f i >>= writeM x (Z:.i)+ {-# INLINE writeStack #-} -class Stack m sh xs where- writeStack :: xs -> sh -> m ()+-- ** Multi-tape indices. instance (Monad m) => Stack m sh Z where writeStack _ _ = return ()@@ -74,9 +88,16 @@ instance ( PrimMonad m- , Stack m Subword xs- , MPrimArrayOps arr Subword e- ) => Stack m Subword (xs:.(MutArr m (arr Subword e),(Subword -> m e))) where+ , Stack m ix xs+ , MPrimArrayOps arr ix e+ ) => Stack m ix (xs :. GeneralNonTerminal m arr ix e) where writeStack (xs:.(x,f)) i = writeStack xs i >> f i >>= writeM x i {-# INLINE writeStack #-}++++-- Wrap non-terminal symbol type, corresponding rule type.++type SubwordNonTerminal m arr e = (MutArr m (arr (Z:.Subword) e), Subword -> m e)+type GeneralNonTerminal m arr ix e = (MutArr m (arr ix e), ix -> m e)
+ Data/PrimitiveArray/QuickCheck.hs view
@@ -0,0 +1,5 @@++module Data.PrimitiveArray.QuickCheck where+++
Data/PrimitiveArray/Zero.hs view
@@ -41,7 +41,7 @@ ma <- newM inLb inUb let exUb = inUb `addDim` unitDim let (MUnboxed _ mba) = ma- zipWithM_ (\k x -> assert (length xs == size exUb) $ unsafeWrite mba k x) [0.. toIndex exUb inUb] xs+ zipWithM_ (\k x -> assert (length xs == size exUb) $ unsafeWrite mba k x) [0.. size exUb -1] xs return ma newM inLb inUb = let exUb = inUb `addDim` unitDim in unless (inLb == zeroDim) (error "MArr0 lb/=zeroDim") >>@@ -50,7 +50,7 @@ let exUb = inUb `addDim` unitDim ma <- newM inLb inUb let (MUnboxed _ mba) = ma- forM_ [0 .. toIndex exUb inUb] $ \k -> unsafeWrite mba k def+ forM_ [0 .. size exUb -1] $ \k -> unsafeWrite mba k def return ma readM (MUnboxed exUb mba) idx = assert (inShape exUb idx) $ unsafeRead mba (toIndex exUb idx) writeM (MUnboxed exUb mba) idx elm = assert (inShape exUb idx) $ unsafeWrite mba (toIndex exUb idx) elm@@ -77,7 +77,48 @@ -- * Boxed, multidimensional arrays. --- data Boxed sh e = Boxed !sh !(V.Vector e)+data Boxed sh e = Boxed !sh !(V.Vector e)+ deriving (Read,Show,Eq)++data instance MutArr m (Boxed sh e) = MBoxed !sh (V.MVector (PrimState m) e)++instance (Shape sh, ExtShape sh, VUM.Unbox elm) => MPrimArrayOps Boxed sh elm where+ boundsM (MBoxed exUb _) = (zeroDim,exUb `subDim` unitDim)+ fromListM inLb inUb xs = do+ ma <- newM inLb inUb+ let exUb = inUb `addDim` unitDim+ let (MBoxed _ mba) = ma+ zipWithM_ (\k x -> assert (length xs == size exUb) $ unsafeWrite mba k x) [0 .. size exUb - 1] xs -- [0.. toIndex exUb inUb] xs+ return ma+ newM inLb inUb = let exUb = inUb `addDim` unitDim in+ unless (inLb == zeroDim) (error "MArr0 lb/=zeroDim") >>+ MBoxed exUb `liftM` new (size exUb)+ newWithM inLb inUb def = do+ let exUb = inUb `addDim` unitDim+ ma <- newM inLb inUb+ let (MBoxed _ mba) = ma+ forM_ [0 .. size exUb -1] $ \k -> unsafeWrite mba k def+ return ma+ readM (MBoxed exUb mba) idx = assert (inShape exUb idx) $ unsafeRead mba (toIndex exUb idx)+ writeM (MBoxed exUb mba) idx elm = assert (inShape exUb idx) $ unsafeWrite mba (toIndex exUb idx) elm+ {-# INLINE boundsM #-}+ {-# INLINE fromListM #-}+ {-# INLINE newM #-}+ {-# INLINE newWithM #-}+ {-# INLINE readM #-}+ {-# INLINE writeM #-}++instance (Shape sh, ExtShape sh, VUM.Unbox elm) => PrimArrayOps Boxed sh elm where+ bounds (Boxed exUb _) = (zeroDim,exUb `subDim` unitDim)+ freeze (MBoxed exUb mba) = Boxed exUb `liftM` unsafeFreeze mba+ index (Boxed exUb ba) idx = assert (inShape exUb idx) $ unsafeIndex ba (toIndex exUb idx)+ {-# INLINE bounds #-}+ {-# INLINE freeze #-}+ {-# INLINE index #-}++instance (Shape sh, ExtShape sh) => PrimArrayMap Boxed sh e e' where+ map f (Boxed sh xs) = Boxed sh (V.map f xs)+ {-# INLINE map #-} {-
PrimitiveArray.cabal view
@@ -1,5 +1,5 @@ Name: PrimitiveArray-Version: 0.5.0.0+Version: 0.5.2.0 License: BSD3 License-file: LICENSE Author: Christian Hoener zu Siederdissen@@ -18,19 +18,17 @@ In general all operations are (highly) unsafe, no bounds-checking or other sanity-checking is performed. Operations are aimed toward efficiency as much as possible.- Goals of the library are to have arrays according to three- ideas: immutable/mutable arrays, strict/lazy arrays,- zero-based/lower-bound arrays. Zero-based arrays save one- addition on each access if the lower bound or the array is- always zero. Library Exposed-modules: Data.Array.Repa.ExtShape+ Data.Array.Repa.Index.Outside Data.Array.Repa.Index.Point+ Data.Array.Repa.Index.Points Data.Array.Repa.Index.Subword Data.PrimitiveArray Data.PrimitiveArray.FillTables+ Data.PrimitiveArray.QuickCheck Data.PrimitiveArray.Zero Build-depends: base >= 4 && <5 ,