packages feed

PrimitiveArray 0.5.4.0 → 0.6.0.0

raw patch · 26 files changed

+1757/−1188 lines, 26 filesdep +OrderedBitsdep +PrimitiveArraydep +aesondep −repadep ~QuickCheckdep ~basedep ~deepseq

Dependencies added: OrderedBits, PrimitiveArray, aeson, binary, bits, cereal, test-framework, test-framework-quickcheck2, test-framework-th, vector-binary-instances

Dependencies removed: repa

Dependency ranges changed: QuickCheck, base, deepseq, primitive, vector, vector-th-unbox

Files

− Data/Array/Repa/ExtShape.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeOperators #-}---- | Additional functions on shapes--module Data.Array.Repa.ExtShape where--import Data.Array.Repa.Index-import Data.Array.Repa.Shape------ | A number of additional operations that are useful together with--- 'PrimitiveArray's.--class ExtShape sh where--  -- | subtract the right coordinates from the left. Does not check if the-  -- resulting shape make sense.--  subDim :: sh -> sh -> sh--  -- | Given an index and an extend, return a list of all indices. For-  -- @rangeList (Z:.3) (Z:.2)@ this returns @[(Z:.3), (Z:.4), (Z:.5)]@.--  rangeList :: sh -> sh -> [sh]----instance ExtShape Z where-  subDim _ _ = Z-  {-# INLINE subDim #-}-  rangeList _ _ = [Z]-  {-# INLINE rangeList #-}--instance ExtShape sh => ExtShape (sh:.Int) where-  subDim (sh1:.n1) (sh2:.n2) = subDim sh1 sh2 :. (n1-n2)-  {-# INLINE subDim #-}-  rangeList (sh1:.n1) (sh2:.n2) = [sh:.n | sh <- rangeList sh1 sh2, n <- [n1 .. (n1+n2) ] ]-  {-# INLINE rangeList #-}-
− Data/Array/Repa/Index/Outside.hs
@@ -1,173 +0,0 @@-{-# 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           Data.Vector.Unboxed.Deriving-import           GHC.Base (quotInt, remInt)-import qualified Data.Vector.Generic.Base-import qualified Data.Vector.Generic.Mutable-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 hiding (upperTri, subwordIndex, subwordFromIndex,stage)-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/Point.hs
@@ -1,115 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeOperators #-}---- | A Repa-compatible index of points in multi-dimensional space. A point--- represents the index of a left- or right-linear grammar.--module Data.Array.Repa.Index.Point 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 Data.Array.Repa.ExtShape----stage = "Data.Array.Repa.Index.Point"---- |--newtype Point = Point Int-  deriving (Eq,Ord,Show)---- |--instance Shape sh => Shape (sh :. Point) where-  {-# INLINE [1] rank #-}-  rank   (sh  :. _)-    = rank sh + 1--  {-# INLINE [1] zeroDim #-}-  zeroDim = zeroDim :. Point 0--  {-# INLINE [1] unitDim #-}-  unitDim = unitDim :. Point 1--  {-# INLINE [1] intersectDim #-}-  intersectDim (sh1 :. Point n1) (sh2 :. Point n2)-    = (intersectDim sh1 sh2 :. Point (min n1 n2))--  {-# INLINE [1] addDim #-}-  addDim (sh1 :. Point n1) (sh2 :. Point n2)-    = addDim sh1 sh2 :. Point (n1 + n2)--  {-# INLINE [1] size #-}-  size  (sh1 :. Point n)-    = size sh1 * n--  {-# INLINE [1] sizeIsValid #-}-  sizeIsValid (sh1 :. Point n)-    | size sh1 > 0-    = n <= maxBound `div` size sh1--    | otherwise-    = False--  {-# INLINE [1] toIndex #-}-  toIndex (sh1 :. Point sh2) (sh1' :. Point sh2')-    = toIndex sh1 sh1' * sh2 + sh2'--  {-# INLINE [1] fromIndex #-}-  fromIndex (ds :. Point d) n-          = fromIndex ds (n `quotInt` d) :. Point r-          where-          -- 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--  {-# INLINE [1] inShapeRange #-}-  inShapeRange (zs :. Point z) (sh1 :. Point n1) (sh2 :. Point n2)-    = (n2 >= z) && (n2 < n1) && (inShapeRange zs sh1 sh2)--  {-# NOINLINE listOfShape #-}-  listOfShape (sh :. Point n)-   = n : listOfShape sh--  {-# NOINLINE shapeOfList #-}-  shapeOfList xx-   = case xx of-    []  -> error $ stage ++ ".toList: empty list when converting to  (_ :. Point)"-    x:xs  -> shapeOfList xs :. Point x--  {-# INLINE deepSeq #-}-  deepSeq (sh :. Point n) x = deepSeq sh (n `seq` x)---- |--instance ExtShape sh => ExtShape (sh:.Point) where-  subDim (sh1:.Point n1) (sh2:.Point n2) = subDim sh1 sh2 :. Point (n1-n2)-  {-# INLINE subDim #-}-  rangeList (sh1:.Point n1) (sh2:.Point n2) = [sh:.Point n | sh <- rangeList sh1 sh2, n <- [n1 .. (n1+n2) ] ]-  {-# INLINE rangeList #-}--instance NFData Point where-  rnf (Point i) = rnf i---- |--instance Arbitrary Point where-  arbitrary = Point <$> choose (0,100)-  shrink (Point i)-    | i>0       = [Point (i-1)]-    | otherwise = []--instance Arbitrary z => Arbitrary (z:.Point) where-  arbitrary = (:.) <$> arbitrary <*> arbitrary-  shrink (z:.s) = (:.) <$> shrink z <*> shrink s-
− Data/Array/Repa/Index/Points.hs
@@ -1,239 +0,0 @@-{-# 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.Generic.Base-import qualified Data.Vector.Generic.Mutable-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)-  deriving (Eq,Read,Show)--pointR :: Int -> Int -> PointR-pointR i j = PointR (i:.j)-{-# INLINE pointR #-}------ * Instances: PointL--derivingUnbox "PointL"-  [t| PointL -> (Int,Int) |]-  [| \ (PointL (i:.j)) -> (i,j) |]-  [| \ (i,j) -> PointL (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------ * Instances: PointR--derivingUnbox "PointR"-  [t| PointR -> (Int,Int) |]-  [| \ (PointR (i:.j)) -> (i,j) |]-  [| \ (i,j) -> PointR (i:.j) |]--instance Shape sh => Shape (sh :. PointR) where-  {-# INLINE [1] rank #-}-  rank   (sh  :. _)-    = rank sh + 1--  {-# INLINE [1] zeroDim #-}-  zeroDim = zeroDim :. PointR (0:.0)--  {-# INLINE [1] unitDim #-}-  unitDim = unitDim :. PointR (0:.1)--  {-# INLINE [1] intersectDim #-}-  intersectDim (sh1 :. PointR (i:.j)) (sh2 :. PointR (k:.l))-    = (intersectDim sh1 sh2 :. PointR (max i k :. min j l))--  {-# INLINE [1] addDim #-}-  addDim (sh1 :. PointR (i:.j)) (sh2 :. PointR (k:.l))-    = addDim sh1 sh2 :. PointR (i+k:.j+l)--  -- NOTE size is calculated NOT as upper-triangular, but linear!-  {-# INLINE [1] size #-}-  size  (sh1 :. PointR (i:.j)) = size sh1 * (j-i)--  {-# INLINE [1] sizeIsValid #-}-  sizeIsValid (sh1 :. PointR (i:.j))-    | size sh1 > 0-    = i>=0 && i<=j && j <= maxBound `div` size sh1-    | otherwise-    = False--  -- NOTE only the @i@ coordinate is used for indexing NTs, @j@ is just for-  -- convenience. @l@ however restricts the NT to some value @>0@ if desired.-  {-# INLINE [1] toIndex #-}-  toIndex (sh1 :. PointR(l:.r)) (sh1' :. PointR(i:.j))-    = toIndex sh1 sh1' * (r-l) + i--  {-# 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 :. PointR (_:._)) (sh1 :. PointR (l:.n)) (sh2 :. PointR (i:.j))-    = i<=j && l<=i && j<n && (inShapeRange zs sh1 sh2)--  {-# NOINLINE listOfShape #-}-  listOfShape (sh :. PointR (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 :. PointR (i:.j)--  {-# INLINE deepSeq #-}-  deepSeq (sh :. n) x = deepSeq sh (n `seq` x)--instance ExtShape sh => ExtShape (sh:.PointR) where-  {-# INLINE [1] subDim #-}-  subDim (sh1:.PointR (i:.j)) (sh2:.PointR (k:.l)) = subDim sh1 sh2 :. PointR (i-k:.j-l)-  {-# INLINE [1] rangeList #-}-  rangeList _ _ = error "PointR:rangeList not implemented"--instance NFData PointR where-  rnf (PointR (i:.j)) = i `seq` rnf j-  {-# INLINE rnf #-}--instance Arbitrary PointR where-  arbitrary = do-    b <- choose (0,100)-    return $ pointR b 100-  shrink (PointR (i:.j))-    | i<j = [pointR (i+1) $ j]-    | otherwise = []--instance Arbitrary z => Arbitrary (z:.PointR) where-  arbitrary = (:.) <$> arbitrary <*> arbitrary-  shrink (z:.s) = (:.) <$> shrink z <*> shrink s-
− Data/Array/Repa/Index/Subword.hs
@@ -1,188 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeOperators #-}---- | Subwords span upper triangular tables. A subword (i,j) is legal iff i<=j.------ NOTE Using more complicated shapes has a number of benefits. We don't need--- to specify triangular or rectangular tables anymore. A rectangular--- one-dimensional table with a subword as shape actually /does/ create space--- as required for subwords.------ TODO subword indexing is currently hardcoded to be zero-based. See--- 'subwordIndex'.------ TODO consider replacing (`quot` 2) with (`shiftR` 1)------ TODO all the QuickCheck stuff is missing--module Data.Array.Repa.Index.Subword 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.Generic.Base-import qualified Data.Vector.Generic.Mutable-import qualified Data.Vector.Unboxed as VU-import           Test.QuickCheck-import           Test.QuickCheck.All--import           Data.Array.Repa.ExtShape----stage = "Data.Array.Repa.Index.Subword"---- | A subword wraps a simple pair.------ Subwords always yield the upper-triangular part of a rect-angular array.--- This gives the quite curious effect that (0,N) points to the ``largest''--- index, while (0,0) and (N,N) both point to the smallest. We do, however, use--- (0,0) as the smallest as (0,k) gives successively smaller upper triangular--- parts.--newtype Subword = Subword (Int:.Int)-  deriving (Eq,Ord,Show)--derivingUnbox "Subword"-  [t| Subword -> (Int,Int) |]-  [| \ (Subword (i:.j)) -> (i,j) |]-  [| \ (i,j) -> Subword (i:.j) |]--subword :: Int -> Int -> Subword-subword i j = Subword (i:.j)-{-# INLINE subword #-}---- | triangular numbers------ A000217--triangularNumber :: Int -> Int-triangularNumber x = (x * (x+1)) `quot` 2-{-# INLINE triangularNumber #-}---- | Size of an upper triangle starting at 'i' and ending at 'j'. "(0,N)" what--- be the normal thing to use.--upperTri :: Subword -> Int-upperTri (Subword (i:.j)) = triangularNumber $ j-i-{-# INLINE upperTri #-}---- | Subword 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 :: Subword -> Subword -> Int-subwordIndex (Subword (l:.n)) (Subword (i:.j)) = adr n (i,j) -- - adr n (l,n)-  where-    adr n (i,j) = n*i - triangularNumber i + j-{-# INLINE subwordIndex #-}--subwordFromIndex :: Subword -> Int -> Subword-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 :. Subword) where-  {-# INLINE [1] rank #-}-  rank   (sh  :. _)-    = rank sh + 1--  {-# INLINE [1] zeroDim #-}-  zeroDim = zeroDim :. Subword (0:.0)--  {-# INLINE [1] unitDim #-}-  unitDim = unitDim :. Subword (0:.1)--  {-# INLINE [1] intersectDim #-}-  intersectDim (sh1 :. Subword (i:.j)) (sh2 :. Subword (k:.l))-    = (intersectDim sh1 sh2 :. Subword (max i k :. min j l))--  {-# INLINE [1] addDim #-}-  addDim (sh1 :. Subword (i:.j)) (sh2 :. Subword (k:.l))-    = addDim sh1 sh2 :. Subword (i+k:.j+l)--  {-# INLINE [1] size #-}-  size  (sh1 :. sw) = size sh1 * upperTri sw--  {-# INLINE [1] sizeIsValid #-}-  sizeIsValid (sh1 :. Subword (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 :. Subword (_:._)) (sh1 :. Subword (l:.n)) (sh2 :. Subword (i:.j))-    = i<=j && l<=i && j<n && (inShapeRange zs sh1 sh2)--  {-# NOINLINE listOfShape #-}-  listOfShape (sh :. Subword (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 :. Subword (i:.j)--  {-# INLINE deepSeq #-}-  deepSeq (sh :. n) x = deepSeq sh (n `seq` x)---- |--instance ExtShape sh => ExtShape (sh:.Subword) where-  subDim (sh1:.Subword (i:.j)) (sh2:.Subword (k:.l)) = subDim sh1 sh2 :. Subword (i-k:.j-l)-  {-# INLINE subDim #-}-  rangeList (sh1:.Subword (i:.j)) (sh2:.Subword (k:.l)) = error "not implemented" -- [sh:.Subword (m,n) | sh <- rangeList sh1 sh2, m <- [i .. [i+k], n <- [ n <- [n1 .. (n1+n2) ] ]-  {-# INLINE rangeList #-}---- |--instance NFData Subword where-  rnf (Subword (i:.j)) = i `seq` rnf j---- |--instance Arbitrary Subword where-  arbitrary = do-    a <- choose (0,100)-    b <- choose (0,100)-    return $ Subword (min a b :. max a b)-  shrink (Subword (i:.j))-    | i<j       = [Subword (i:.j-1)]-    | otherwise = []--instance Arbitrary z => Arbitrary (z:.Subword) where-  arbitrary = (:.) <$> arbitrary <*> arbitrary-  shrink (z:.s) = (:.) <$> shrink z <*> shrink s-
Data/PrimitiveArray.hs view
@@ -1,166 +1,13 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-} --- | Vastly extended primitive arrays. Some basic ideas are now modeled after--- the vector package, especially the monadic mutable / pure immutable array--- system.------ NOTE all operations in MPrimArrayOps and PrimArrayOps are highly unsafe. No--- bounds-checking is performed at all.--module Data.PrimitiveArray where--import Control.Exception (assert)-import Control.Monad-import Control.Monad.Primitive-import Control.Monad.ST-import Data.Array.Repa.Index-import Data.Array.Repa.Shape-import Data.Primitive-import Data.Primitive.Types-import Prelude as P-import System.IO.Unsafe--import Data.Array.Repa.ExtShape------ | Mutable version of an array.--data family MutArr (m :: * -> *) (arr :: *) :: *----- | The core set of operations for monadic arrays.-class (Shape sh, ExtShape sh) => MPrimArrayOps arr sh elm where--  -- | Return the bounds of the array. All bounds are inclusive, as in-  -- @[lb..ub]@--  boundsM :: MutArr m (arr sh elm) -> (sh,sh)--  -- | Given lower and upper bounds and a list of /all/ elements, produce a-  -- mutable array.--  fromListM :: PrimMonad m => sh -> sh -> [elm] -> m (MutArr m (arr sh elm))--  -- | Creates a new array with the given bounds with each element within the-  -- array being in an undefined state.--  newM :: PrimMonad m => sh -> sh -> m (MutArr m (arr sh elm))--  -- | Creates a new array with all elements being equal to 'elm'.--  newWithM :: PrimMonad m => sh -> sh -> elm -> m (MutArr m (arr sh elm))--  -- | Reads a single element in the array.--  readM :: PrimMonad m => MutArr m (arr sh elm) -> sh -> m elm--  -- | Writes a single element in the array.--  writeM :: PrimMonad m => MutArr m (arr sh elm) -> sh -> elm -> m ()------ | The core set of functions on immutable arrays.--class (Shape sh, ExtShape sh) => PrimArrayOps arr sh elm where--  -- | Returns the bounds of an immutable array, again inclusive bounds: @ [lb..ub] @.--  bounds :: arr sh elm -> (sh,sh)--  -- | Freezes a mutable array an returns its immutable version. This operation-  -- is /O(1)/ and both arrays share the same memory. Do not use the mutable-  -- array afterwards.--  freeze :: PrimMonad m => MutArr m (arr sh elm) -> m (arr sh elm)--  -- | Extract a single element from the array. Generally unsafe as not-  -- bounds-checking is performed.--  index :: arr sh elm -> sh -> elm--class (Shape sh, ExtShape sh) => PrimArrayMap arr sh e e' where--  -- | Map a function over each element, keeping the shape intact.--  map :: (e -> e') -> arr sh e -> arr sh e'------ | Infix index operator. Performs minimal bounds-checking using assert in--- non-optimized code.--(!) :: PrimArrayOps arr sh elm => arr sh elm -> sh -> elm-(!) arr idx = assert (inBounds arr idx) $ index arr idx-{-# INLINE (!) #-}---- | Returns true if the index is valid for the array.--inBoundsM :: (Monad m, MPrimArrayOps arr sh elm) => MutArr m (arr sh elm) -> sh -> Bool-inBoundsM marr idx = let (lb,ub) = boundsM marr in inShapeRange lb ub idx-{-# INLINE inBoundsM #-}---- | Given two arrays with the same dimensionality, their respective starting--- index, and how many steps to go in each dimension (in terms of a dimension--- again), determine if the multidimensional slices have the same value at--- all positions------ TODO specialize for DIM1 (and maybe higher dim's) to use memcmp--sliceEq :: (Eq elm, PrimArrayOps arr sh elm) => arr sh elm -> sh -> arr sh elm -> sh -> sh -> Bool-sliceEq arr1 k1 arr2 k2 xtnd = assert ((inBounds arr1 k1) && (inBounds arr2 k2) && (inBounds arr1 $ k1 `addDim` xtnd) && (inBounds arr2 $ k2 `addDim` xtnd)) $ and res where-  res = zipWith (==) xs ys-  xs = P.map (index arr1) $ rangeList k1 xtnd-  ys = P.map (index arr2) $ rangeList k2 xtnd-{-# INLINE sliceEq #-}---- | Construct a mutable primitive array from a lower and an upper bound, a--- default element, and a list of associations.--fromAssocsM-  :: (PrimMonad m, MPrimArrayOps arr sh elm)-  => sh -> sh -> elm -> [(sh,elm)] -> m (MutArr m (arr sh elm))-fromAssocsM lb ub def xs = do-  ma <- newWithM lb ub def-  forM_ xs $ \(k,v) -> writeM ma k v-  return ma-{-# INLINE fromAssocsM #-}---- | Return all associations from an array.--assocs :: PrimArrayOps arr sh elm => arr sh elm -> [(sh,elm)]-assocs arr = P.map (\k -> (k,index arr k)) $ rangeList lb (ub `subDim` lb) where-  (lb,ub) = bounds arr-{-# INLINE assocs #-}---- | Creates an immutable array from lower and upper bounds and a complete list--- of elements.--fromList :: (PrimArrayOps arr sh elm, MPrimArrayOps arr sh elm) => sh -> sh -> [elm] -> arr sh elm-fromList lb ub xs = runST $ fromListM lb ub xs >>= freeze-{-# INLINE fromList #-}---- | Creates an immutable array from lower and upper bounds, a default element,--- and a list of associations.--fromAssocs :: (PrimArrayOps arr sh elm, MPrimArrayOps arr sh elm) => sh -> sh -> elm -> [(sh,elm)] -> arr sh elm-fromAssocs lb ub def xs = runST $ fromAssocsM lb ub def xs >>= freeze-{-# INLINE fromAssocs #-}---- | Determines if an index is valid for a given immutable array.--inBounds :: PrimArrayOps arr sh elm => arr sh elm -> sh -> Bool-inBounds arr idx = let (lb,ub) = bounds arr in inShapeRange lb (ub `addDim` unitDim) idx-{-# INLINE inBounds #-}---- | Returns all elements of an immutable array as a list.+module Data.PrimitiveArray +  ( module Data.PrimitiveArray.Class+  , module Data.PrimitiveArray.Dense+  , module Data.PrimitiveArray.FillTables+  , module Data.PrimitiveArray.Index+  ) where -toList :: PrimArrayOps arr sh elm =>  arr sh elm -> [elm]-toList arr = let (lb,ub) = bounds arr in P.map ((!) arr) $ rangeList lb $ ub `subDim` lb-{-# INLINE toList #-}+import Data.PrimitiveArray.Class+import Data.PrimitiveArray.Dense+import Data.PrimitiveArray.FillTables+import Data.PrimitiveArray.Index 
+ Data/PrimitiveArray/Class.hs view
@@ -0,0 +1,188 @@++-- | Vastly extended primitive arrays. Some basic ideas are now modeled after+-- the vector package, especially the monadic mutable / pure immutable array+-- system.+--+-- NOTE all operations in MPrimArrayOps and PrimArrayOps are highly unsafe. No+-- bounds-checking is performed at all.++module Data.PrimitiveArray.Class where++import           Control.Applicative (Applicative, pure, (<$>), (<*>))+import           Control.Exception (assert)+import           Control.Monad (forM_)+import           Control.Monad.Primitive (PrimMonad)+import           Control.Monad.ST (runST)+import           Prelude as P+import qualified Data.Vector.Fusion.Stream as S++import Data.PrimitiveArray.Index++++-- | Mutable version of an array.++data family MutArr (m :: * -> *) (arr :: *) :: *+++-- | The core set of operations for monadic arrays.++class (Index sh) => MPrimArrayOps arr sh elm where++  -- | Return the bounds of the array. All bounds are inclusive, as in+  -- @[lb..ub]@++  boundsM :: MutArr m (arr sh elm) -> (sh,sh)++  -- | Given lower and upper bounds and a list of /all/ elements, produce a+  -- mutable array.++  fromListM :: PrimMonad m => sh -> sh -> [elm] -> m (MutArr m (arr sh elm))++  -- | Creates a new array with the given bounds with each element within the+  -- array being in an undefined state.++  newM :: PrimMonad m => sh -> sh -> m (MutArr m (arr sh elm))++  -- | Creates a new array with all elements being equal to 'elm'.++  newWithM :: PrimMonad m => sh -> sh -> elm -> m (MutArr m (arr sh elm))++  -- | Reads a single element in the array.++  readM :: PrimMonad m => MutArr m (arr sh elm) -> sh -> m elm++  -- | Writes a single element in the array.++  writeM :: PrimMonad m => MutArr m (arr sh elm) -> sh -> elm -> m ()++++-- | The core set of functions on immutable arrays.++class (Index sh) => PrimArrayOps arr sh elm where++  -- | Returns the bounds of an immutable array, again inclusive bounds: @ [lb..ub] @.++  bounds :: arr sh elm -> (sh,sh)++  -- | Freezes a mutable array an returns its immutable version. This operation+  -- is /O(1)/ and both arrays share the same memory. Do not use the mutable+  -- array afterwards.++  unsafeFreeze :: PrimMonad m => MutArr m (arr sh elm) -> m (arr sh elm)++  -- | Thaw an immutable array into a mutable one. Both versions share+  -- memory.++  unsafeThaw :: PrimMonad m => arr sh elm -> m (MutArr m (arr sh elm))++  -- | Extract a single element from the array. Generally unsafe as not+  -- bounds-checking is performed.++  unsafeIndex :: arr sh elm -> sh -> elm++  -- | Savely transform the shape space of a table.++  transformShape :: (Index sh') => (sh -> sh') -> arr sh elm -> arr sh' elm++class (Index sh) => PrimArrayMap arr sh e e' where++  -- | Map a function over each element, keeping the shape intact.++  map :: (e -> e') -> arr sh e -> arr sh e'++++-- | Infix index operator. Performs minimal bounds-checking using assert in+-- non-optimized code.++(!) :: PrimArrayOps arr sh elm => arr sh elm -> sh -> elm+(!) arr idx = assert (uncurry inBounds (bounds arr) idx) $ unsafeIndex arr idx+{-# INLINE (!) #-}++-- | Returns true if the index is valid for the array.++inBoundsM :: (Monad m, MPrimArrayOps arr sh elm) => MutArr m (arr sh elm) -> sh -> Bool+inBoundsM marr idx = let (lb,ub) = boundsM marr in inBounds lb ub idx+{-# INLINE inBoundsM #-}++-- -- | Given two arrays with the same dimensionality, their respective starting+-- -- index, and how many steps to go in each dimension (in terms of a dimension+-- -- again), determine if the multidimensional slices have the same value at+-- -- all positions+-- --+-- -- TODO specialize for DIM1 (and maybe higher dim's) to use memcmp+-- +-- sliceEq :: (Eq elm, PrimArrayOps arr sh elm) => arr sh elm -> sh -> arr sh elm -> sh -> sh -> Bool+-- sliceEq arr1 k1 arr2 k2 xtnd = assert ((inBounds arr1 k1) && (inBounds arr2 k2) && (inBounds arr1 $ k1 `addDim` xtnd) && (inBounds arr2 $ k2 `addDim` xtnd)) $ and res where+--   res = zipWith (==) xs ys+--   xs = P.map (unsafeIndex arr1) $ rangeList k1 xtnd+--   ys = P.map (unsafeIndex arr2) $ rangeList k2 xtnd+-- {-# INLINE sliceEq #-}++-- | Construct a mutable primitive array from a lower and an upper bound, a+-- default element, and a list of associations.++fromAssocsM+  :: (PrimMonad m, MPrimArrayOps arr sh elm)+  => sh -> sh -> elm -> [(sh,elm)] -> m (MutArr m (arr sh elm))+fromAssocsM lb ub def xs = do+  ma <- newWithM lb ub def+  forM_ xs $ \(k,v) -> writeM ma k v+  return ma+{-# INLINE fromAssocsM #-}++-- | Return all associations from an array.++assocs :: (IndexStream sh, PrimArrayOps arr sh elm) => arr sh elm -> [(sh,elm)]+assocs arr = P.map (\k -> (k,unsafeIndex arr k)) . S.toList $ streamUp lb ub where+  (lb,ub) = bounds arr+{-# INLINE assocs #-}++-- | Creates an immutable array from lower and upper bounds and a complete list+-- of elements.++fromList :: (PrimArrayOps arr sh elm, MPrimArrayOps arr sh elm) => sh -> sh -> [elm] -> arr sh elm+fromList lb ub xs = runST $ fromListM lb ub xs >>= unsafeFreeze+{-# INLINE fromList #-}++-- | Creates an immutable array from lower and upper bounds, a default element,+-- and a list of associations.++fromAssocs :: (PrimArrayOps arr sh elm, MPrimArrayOps arr sh elm) => sh -> sh -> elm -> [(sh,elm)] -> arr sh elm+fromAssocs lb ub def xs = runST $ fromAssocsM lb ub def xs >>= unsafeFreeze+{-# INLINE fromAssocs #-}++-- -- | Determines if an index is valid for a given immutable array.+-- +-- inBounds :: PrimArrayOps arr sh elm => arr sh elm -> sh -> Bool+-- inBounds arr idx = let (lb,ub) = bounds arr in inShapeRange lb (ub `addDim` unitDim) idx+-- {-# INLINE inBounds #-}++-- | Returns all elements of an immutable array as a list.++toList :: (IndexStream sh, PrimArrayOps arr sh elm) => arr sh elm -> [elm]+toList arr = let (lb,ub) = bounds arr in P.map ((!) arr) . S.toList $ streamUp lb ub+{-# INLINE toList #-}++++-- * Freeze an inductive stack of tables with a 'Z' at the bottom.++-- | 'freezeTables' freezes a stack of tables.++class FreezeTables m t where+    type Frozen t :: *+    freezeTables :: t -> m (Frozen t)++instance Applicative m => FreezeTables m Z where+    type Frozen Z = Z+    freezeTables Z = pure Z+    {-# INLINE freezeTables #-}++instance (Functor m, Applicative m, Monad m, PrimMonad m, FreezeTables m ts, PrimArrayOps arr sh elm) => FreezeTables m (ts:.MutArr m (arr sh elm)) where+    type Frozen (ts:.MutArr m (arr sh elm)) = Frozen ts :. arr sh elm+    freezeTables (ts:.t) = (:.) <$> freezeTables ts <*> unsafeFreeze t+    {-# INLINE freezeTables #-}+
+ Data/PrimitiveArray/Dense.hs view
@@ -0,0 +1,178 @@++-- | Dense primitive arrays where the lower index is zero (or the+-- equivalent of zero for newtypes and enumerations).+--+-- Actual @write@s to data structures use a more safe @write@ instead of+-- the unsafe @unsafeWrite@. Writes also tend to occur much less in DP+-- algorithms (say, N^2 writes for an N^3 time algorithm -- mostly reads+-- are being executed).+--+-- TODO consider if we want to force the lower index to be zero, or allow+-- non-zero lower indices. Will have to be considered together with the+-- @Index.Class@ module!++module Data.PrimitiveArray.Dense where++import           Control.DeepSeq+import           Control.Exception (assert)+import           Control.Monad (liftM, forM_, zipWithM_)+import           Control.Monad.Primitive (PrimState)+import           Data.Aeson (ToJSON,FromJSON)+import           Data.Binary (Binary)+import           Data.Serialize (Serialize)+import           Data.Vector.Binary+import           Data.Vector.Cereal+import           Data.Vector.Generic.Mutable as GM hiding (length)+import           Data.Vector.Unboxed.Mutable (Unbox)+import           GHC.Generics (Generic)+import qualified Data.Vector as V hiding (forM_, length, zipWithM_)+import qualified Data.Vector.Generic as G+import qualified Data.Vector.Unboxed as VU hiding (forM_, length, zipWithM_)+++import           Data.PrimitiveArray.Class+import           Data.PrimitiveArray.Index++++-- * Unboxed, multidimensional arrays.++data Unboxed sh e = Unboxed !sh !sh !(VU.Vector e)+  deriving (Read,Show,Eq,Generic)++instance (Binary    sh, Binary    e, Unbox e) => Binary    (Unboxed sh e)+instance (Serialize sh, Serialize e, Unbox e) => Serialize (Unboxed sh e)+instance (ToJSON    sh, ToJSON    e, Unbox e) => ToJSON    (Unboxed sh e)+instance (FromJSON  sh, FromJSON  e, Unbox e) => FromJSON  (Unboxed sh e)++instance NFData (Unboxed sh e) where+  rnf !_ = ()++data instance MutArr m (Unboxed sh e) = MUnboxed !sh !sh !(VU.MVector (PrimState m) e)++instance NFData (MutArr m (Unboxed sh e)) where+  rnf !_ = ()++instance (Index sh, Unbox elm) => MPrimArrayOps Unboxed sh elm where+  boundsM (MUnboxed l h _) = (l,h)+  fromListM l h xs = do+    ma <- newM l h+    let (MUnboxed _ _ mba) = ma+    zipWithM_ (\k x -> assert (length xs == size l h) $ unsafeWrite mba k x) [0.. size l h -1] xs+    return ma+  newM l h = MUnboxed l h `liftM` new (size l h)+  newWithM l h def = do+    ma <- newM l h+    let (MUnboxed _ _ mba) = ma+    forM_ [0 .. size l h -1] $ \k -> unsafeWrite mba k def+    return ma+  readM  (MUnboxed l h mba) idx     = assert (inBounds l h idx) $ unsafeRead  mba (linearIndex l h idx)+  writeM (MUnboxed l h mba) idx elm = write mba (linearIndex l h idx) elm+  {-# INLINE boundsM #-}+  {-# INLINE fromListM #-}+  {-# INLINE newM #-}+  {-# INLINE newWithM #-}+  {-# INLINE readM #-}+  {-# INLINE writeM #-}++instance (Index sh, Unbox elm) => PrimArrayOps Unboxed sh elm where+  bounds (Unboxed l h _) = (l,h)+  unsafeFreeze (MUnboxed l h mba) = Unboxed l h `liftM` G.unsafeFreeze mba+  unsafeThaw   (Unboxed  l h ba) = MUnboxed l h `liftM` G.unsafeThaw ba+  unsafeIndex  (Unboxed  l h ba) idx = {- assert (inShape exUb idx) $ -} G.unsafeIndex ba (linearIndex l h idx)+  transformShape tr (Unboxed l h ba) = Unboxed (tr l) (tr h) ba+  {-# INLINE bounds #-}+  {-# INLINE unsafeFreeze #-}+  {-# INLINE unsafeThaw #-}+  {-# INLINE unsafeIndex #-}+  {-# INLINE transformShape #-}++instance (Index sh, Unbox e, Unbox e') => PrimArrayMap Unboxed sh e e' where+  map f (Unboxed l h xs) = Unboxed l h (VU.map f xs)+  {-# INLINE map #-}++++-- * Boxed, multidimensional arrays.++data Boxed sh e = Boxed !sh !sh !(V.Vector e)+  deriving (Read,Show,Eq,Generic)++instance (Binary    sh, Binary    e)  => Binary    (Boxed sh e)+instance (Serialize sh, Serialize e)  => Serialize (Boxed sh e)+instance (ToJSON    sh, ToJSON    e)  => ToJSON    (Boxed sh e)+instance (FromJSON  sh, FromJSON  e)  => FromJSON  (Boxed sh e)++instance NFData (Boxed sh e) where+  rnf !_ = ()++data instance MutArr m (Boxed sh e) = MBoxed !sh !sh !(V.MVector (PrimState m) e)++instance NFData (MutArr m (Boxed sh e)) where+  rnf !_ = ()++instance (Index sh) => MPrimArrayOps Boxed sh elm where+  boundsM (MBoxed l h _) = (l,h)+  fromListM l h xs = do+    ma <- newM l h+    let (MBoxed _ _ mba) = ma+    zipWithM_ (\k x -> assert (length xs == size l h) $ unsafeWrite mba k x) [0 .. size l h - 1] xs+    return ma+  newM l h =+    MBoxed l h `liftM` new (size l h)+  newWithM l h def = do+    ma <- newM l h+    let (MBoxed _ _ mba) = ma+    forM_ [0 .. size l h -1] $ \k -> unsafeWrite mba k def+    return ma+  readM  (MBoxed l h mba) idx     = assert (inBounds l h idx) $ GM.unsafeRead mba (linearIndex l h idx)+  writeM (MBoxed l h mba) idx elm = assert (inBounds l h idx) $ GM.write mba (linearIndex l h idx) elm+  {-# INLINE boundsM #-}+  {-# INLINE fromListM #-}+  {-# INLINE newM #-}+  {-# INLINE newWithM #-}+  {-# INLINE readM #-}+  {-# INLINE writeM #-}++instance (Index sh, Unbox elm) => PrimArrayOps Boxed sh elm where+  bounds (Boxed l h _) = (l,h)+  unsafeFreeze (MBoxed l h mba) = Boxed l h `liftM` G.unsafeFreeze mba+  unsafeThaw   (Boxed l h ba) = MBoxed l h `liftM` G.unsafeThaw ba+  unsafeIndex (Boxed l h ba) idx = {- assert (inShape exUb idx) $ -} G.unsafeIndex ba (linearIndex l h idx)+  transformShape tr (Boxed l h ba) = Boxed (tr l) (tr h) ba+  {-# INLINE bounds #-}+  {-# INLINE unsafeFreeze #-}+  {-# INLINE unsafeThaw #-}+  {-# INLINE unsafeIndex #-}+  {-# INLINE transformShape #-}++instance (Index sh) => PrimArrayMap Boxed sh e e' where+  map f (Boxed l h xs) = Boxed l h (V.map f xs)+  {-# INLINE map #-}++++{-+ -+ - This stuff tells us how to write efficient generics on large data+ - constructors like the Turner and Vienna ctors.+ -++import qualified Data.Generics.TH as T++data Unboxed sh e = Unboxed !sh !(VU.Vector e)+  deriving (Show,Eq,Ord)++data X e = X (Unboxed DIM1 e) (Unboxed DIM1 e)+  deriving (Show,Eq,Ord)++x :: X Int+x = X z z where z = (Unboxed (Z:.10) (VU.fromList [ 0 .. 10] ))++pot :: X Int -> X Double+pot = $( T.thmapT (T.mkTs ['f]) [t| X Int |] ) where+  f :: Unboxed DIM1 Int -> Unboxed DIM1 Double+  f (Unboxed sh xs) = Unboxed sh (VU.map fromIntegral xs)++-}+
Data/PrimitiveArray/FillTables.hs view
@@ -1,103 +1,64 @@-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeOperators #-} --- | Operations to fill primitive arrays. Arrays are combined just like indices--- using 'Z' and '(:.)'. This allows filling an unlimited number of tables.------ TODO make explicit in which order the tables are filled.+-- | Operations to fill primitive arrays. Arrays are combined just like+-- indices using 'Z' and '(:.)'. This allows filling an unlimited number of+-- tables. 'ExtShape' provides the 'rangeStream' function with generates+-- a stream of indices in (generally) the right order.  module Data.PrimitiveArray.FillTables where  import Control.Monad.Primitive-import Data.Array.Repa.Index-import Data.Array.Repa.Shape-import Data.Vector.Fusion.Stream.Monadic as S+import Control.Monad (when)+import Data.Vector.Fusion.Stream as S+import Data.Vector.Fusion.Stream.Monadic as M+import Data.Vector.Fusion.Stream.Size -import Data.PrimitiveArray-import Data.Array.Repa.Index.Subword+import Data.PrimitiveArray.Class+import Data.PrimitiveArray.Index   --- * Driver classes for table filling system.+-- * High-level table filling system. --- Upper triangular table filling. Right now, only a serial option 'upperTriS'--- is available.+-- | Run the forward phase of algorithms. Is *really* unsafe for now if+-- tables have different sizes, as in its broken. ----- TODO Using Repa, 'upperTriP' will soon become available.--class UpperTriS m stack where-  upperTriS :: stack -> m ()+-- TODO Need to run min/max on the bounds for all tables, not just the last+-- table. Otherwise we don't really need the distinction between save and+-- unsafe. This will have to be in @runFillTables@. --- | Defines how a single index in a stack of arrays + evaluation functions is--- handled. The instances *should* work for any index @ix@.+unsafeRunFillTables+  :: ( Index sh, IndexStream sh+     , WriteCell m (tail :. (MutArr m (arr sh elm), t)) sh+     , MPrimArrayOps arr sh elm+     , Monad m+     , PrimMonad m+     )+  => (tail :. (MutArr m (arr sh elm), t)) -> m () -class Stack m sh xs where-  writeStack :: xs -> sh -> m ()+unsafeRunFillTables (ts:.(t,f)) = M.mapM_ (unsafeWriteCell (ts:.(t,f))) $ streamUp from to where -- generateIndices from to where+  (from,to) = boundsM t -- TODO min/max over all tables [for the safe version, the unsafe version *always* assumes equal-size tables; we still should check this during runtime]+{-# INLINE unsafeRunFillTables #-}   --- * Instances---- ** 1-tape grammars with 'Subword' indices.---- TODO Insert check that all extends are the same!--instance-  ( Monad m-  , 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 (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-      -- filled left to right in the stack order '(Z:.first:.next:.last)'-      go xs (i,j) = writeStack xs (Subword (i:.j))-      {-# INLINE go #-}-      -- the unfolder steps through the diagonals from the main toward the-      -- upper-right. It starts a the main-diagonal column and goes to the-      -- right in each big step '(i==u)' and increases the row by one in each-      -- small step.-      unfolder l u = S.unfoldr step (l,l) where-        step (j,i)-          | j> u      = Nothing-          | i==u      = Just ((i,j),(j+1,l))-          | otherwise = Just ((i,j),(j,i+1))-        {-# INLINE step #-}-      {-# INLINE unfolder #-}-  {-# INLINE upperTriS #-}--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 #-}---- ** Multi-tape indices.--instance (Monad m) => Stack m sh Z where-  writeStack _ _ = return ()-  {-# INLINE writeStack #-}--instance-  ( PrimMonad m-  , 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 #-}+-- * Write to individuel cells. +-- | 'WriteCell' provides methods to fill all cells with a specific index+-- @sh@ in a stack of non-terminal tables @c@. +class (Monad m) => WriteCell m c sh where+    unsafeWriteCell :: c -> sh -> m ()+    writeCell       :: c -> sh -> m () --- Wrap non-terminal symbol type, corresponding rule type.+instance (Monad m) => WriteCell m Z sh where+    unsafeWriteCell _ _ = return ()+    writeCell _ _ = return ()+    {-# INLINE unsafeWriteCell #-}+    {-# INLINE writeCell #-} -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)+instance (WriteCell m cs sh, Monad m, MPrimArrayOps arr sh a, PrimMonad m) => WriteCell m (cs:.(MutArr m (arr sh a), sh -> m a)) sh where+    unsafeWriteCell (cs:.(t,f)) sh = unsafeWriteCell cs sh >> (f sh >>= writeM t sh)+    writeCell (cs:.(t,f)) sh = writeCell cs sh >> (when (inBoundsM t sh) (f sh >>= writeM t sh))+    {-# INLINE unsafeWriteCell #-}+    {-# INLINE writeCell #-} 
+ Data/PrimitiveArray/Index.hs view
@@ -0,0 +1,19 @@++module Data.PrimitiveArray.Index+  ( module Data.PrimitiveArray.Index.Class+  , module Data.PrimitiveArray.Index.Complement+  , module Data.PrimitiveArray.Index.Int+  , module Data.PrimitiveArray.Index.Outside+  , module Data.PrimitiveArray.Index.Point+  , module Data.PrimitiveArray.Index.Set+  , module Data.PrimitiveArray.Index.Subword+  ) where++import Data.PrimitiveArray.Index.Class+import Data.PrimitiveArray.Index.Complement+import Data.PrimitiveArray.Index.Int+import Data.PrimitiveArray.Index.Outside+import Data.PrimitiveArray.Index.Point+import Data.PrimitiveArray.Index.Set+import Data.PrimitiveArray.Index.Subword+
+ Data/PrimitiveArray/Index/Class.hs view
@@ -0,0 +1,204 @@++module Data.PrimitiveArray.Index.Class where++import           Control.Applicative+import           Control.DeepSeq (NFData(..))+import           Control.Monad (liftM2)+import           Data.Aeson+import           Data.Binary+import           Data.Serialize+import           Data.Vector.Fusion.Stream.Monadic (Stream)+import           Data.Vector.Unboxed.Deriving+import           Data.Vector.Unboxed (Unbox(..))+import           GHC.Generics+import qualified Data.Vector.Fusion.Stream.Monadic as SM+import           Test.QuickCheck++++infixl 3 :.++-- | Strict pairs -- as in @repa@.++data a :. b = !a :. !b+  deriving (Eq,Ord,Show,Generic)++derivingUnbox "StrictPair"+  [t| forall a b . (Unbox a, Unbox b) => (a:.b) -> (a,b) |]+  [| \(a:.b) -> (a, b) |]+  [| \(a,b)  -> (a:.b) |]++instance (Binary    a, Binary    b) => Binary    (a:.b)+instance (Serialize a, Serialize b) => Serialize (a:.b)+instance (ToJSON    a, ToJSON    b) => ToJSON    (a:.b)+instance (FromJSON  a, FromJSON  b) => FromJSON  (a:.b)++deriving instance (Read a, Read b) => Read (a:.b)++instance (NFData a, NFData b) => NFData (a:.b) where+  rnf (a:.b) = rnf a `seq` rnf b+  {-# Inline rnf #-}++instance (Arbitrary a, Arbitrary b) => Arbitrary (a :. b) where+  arbitrary     = liftM2 (:.) arbitrary arbitrary+  shrink (a:.b) = [ (a':.b) | a' <- shrink a ] ++ [ (a:.b') | b' <- shrink b ]++++infixl 3 :>++-- | A different version of strict pairs. Makes for simpler type inference in+-- multi-tape grammars. We use @:>@ when we have special needs, like+-- non-recursive instances on inductives tuples, as used for set indices.++data a :> b = !a :> !b+  deriving (Eq,Ord,Show,Generic)++derivingUnbox "StrictIxPair"+  [t| forall a b . (Unbox a, Unbox b) => (a:>b) -> (a,b) |]+  [| \(a:>b) -> (a, b) |]+  [| \(a,b)  -> (a:>b) |]++instance (Binary    a, Binary    b) => Binary    (a:>b)+instance (Serialize a, Serialize b) => Serialize (a:>b)+instance (ToJSON    a, ToJSON    b) => ToJSON    (a:>b)+instance (FromJSON  a, FromJSON  b) => FromJSON  (a:>b)++deriving instance (Read a, Read b) => Read (a:>b)++instance (NFData a, NFData b) => NFData (a:>b) where+  rnf (a:>b) = rnf a `seq` rnf b+  {-# Inline rnf #-}++--instance (Arbitrary a, Arbitrary b) => Arbitrary (a :> b) where+--  arbitrary = (:>) <$> arbitrary <*> arbitrary+--  shrink (a:>b) = (:>) <$> shrink a <*> shrink b++++-- | Base data constructor for multi-dimensional indices.++data Z = Z+  deriving (Eq,Ord,Read,Show,Generic)++derivingUnbox "Z"+  [t| Z -> () |]+  [| const () |]+  [| const Z  |]++instance Binary    Z+instance Serialize Z+instance ToJSON    Z+instance FromJSON  Z++instance Arbitrary Z where+  arbitrary = return Z++instance NFData Z where+  rnf Z = ()+  {-# Inline rnf #-}++++-- | Index structures for complex, heterogeneous indexing. Mostly designed for+-- indexing in DP grammars, where the indices work for linear and context-free+-- grammars on one or more tapes, for strings, sets, later on tree structures.++class Index i where++  -- | Given a minimal size, a maximal size, and a current index, calculate+  -- the linear index.++  linearIndex :: i -> i -> i -> Int++  -- | Given an index element from the smallest subset, calculate the+  -- highest linear index that is *not* stored.++  smallestLinearIndex :: i -> Int -- LH i++  -- | Given an index element from the largest subset, calculate the+  -- highest linear index that *is* stored.++  largestLinearIndex :: i -> Int -- LH i++  -- | Given smallest and largest index, return the number of cells+  -- required for storage.++  size :: i -> i -> Int++  -- | Check if an index is within the bounds.++  inBounds :: i -> i -> i -> Bool++++-- | Generate a stream of indices in correct order for dynamic programming.+-- Since the stream generators require @concatMap@ / @flatten@ we have to+-- write more specialized code for @(z:.IX)@ stuff.++class IndexStream i where++  -- | This generates an index stream suitable for @forward@ structure filling.+  -- The first index is the smallest (or the first indices considered are all+  -- equally small in partially ordered sets). Larger indices follow up until+  -- the largest one.++  streamUp   :: Monad m => i -> i -> Stream m i+  default streamUp :: (Monad m, IndexStream (Z:.i)) => i -> i -> Stream m i+  streamUp l h = SM.map (\(Z:.i) -> i) $ streamUp (Z:.l) (Z:.h)+  {-# INLINE streamUp #-}++  -- | If 'streamUp' generates indices from smallest to largest, then+  -- 'streamDown' generates indices from largest to smallest. Outside grammars+  -- make implicit use of this. Asking for an axiom in backtracking requests+  -- the first element from this stream.++  streamDown :: Monad m => i -> i -> Stream m i+  default streamDown :: (Monad m, IndexStream (Z:.i)) => i -> i -> Stream m i+  streamDown l h = SM.map (\(Z:.i) -> i) $ streamDown (Z:.l) (Z:.h)+  {-# INLINE streamDown #-}++++instance Index Z where+  linearIndex _ _ _ = 0+  {-# INLINE linearIndex #-}+  smallestLinearIndex _ = 0+  {-# INLINE smallestLinearIndex #-}+  largestLinearIndex _ = 0+  {-# INLINE largestLinearIndex #-}+  size _ _ = 1+  {-# INLINE size #-}+  inBounds _ _ _ = True+  {-# INLINE inBounds #-}++instance IndexStream Z where+  streamUp   Z Z = SM.singleton Z+  {-# INLINE streamUp #-}+  streamDown Z Z = SM.singleton Z+  {-# INLINE streamDown #-}++instance (Index zs, Index z) => Index (zs:.z) where+  linearIndex (ls:.l) (hs:.h) (zs:.z) = linearIndex ls hs zs * (largestLinearIndex h + 1) + linearIndex l h z+  {-# INLINE linearIndex #-}+  smallestLinearIndex (ls:.l) = smallestLinearIndex ls * smallestLinearIndex l+  {-# INLINE smallestLinearIndex #-}+  largestLinearIndex (hs:.h) = largestLinearIndex hs * largestLinearIndex h+  {-# INLINE largestLinearIndex #-}+  size (ls:.l) (hs:.h) = size ls hs * (size l h)+  {-# INLINE size #-}+  inBounds (ls:.l) (hs:.h) (zs:.z) = inBounds ls hs zs && inBounds l h z+  {-# INLINE inBounds #-}++instance (Index zs, Index z) => Index (zs:>z) where+  linearIndex (ls:>l) (hs:>h) (zs:>z) = linearIndex ls hs zs * (largestLinearIndex h + 1) + linearIndex l h z+  {-# INLINE linearIndex #-}+  smallestLinearIndex (ls:>l) = smallestLinearIndex ls * smallestLinearIndex l+  {-# INLINE smallestLinearIndex #-}+  largestLinearIndex (hs:>h) = largestLinearIndex hs * largestLinearIndex h+  {-# INLINE largestLinearIndex #-}+  size (ls:>l) (hs:>h) = size ls hs * (size l h)+  {-# INLINE size #-}+  inBounds (ls:>l) (hs:>h) (zs:>z) = inBounds ls hs zs && inBounds l h z+  {-# INLINE inBounds #-}+
+ Data/PrimitiveArray/Index/Complement.hs view
@@ -0,0 +1,60 @@++module Data.PrimitiveArray.Index.Complement where++import Control.Applicative+import Control.DeepSeq (NFData(..))+import Data.Aeson+import Data.Binary+import Data.Serialize+import Data.Vector.Unboxed.Deriving+import Data.Vector.Unboxed (Unbox(..))+import GHC.Generics+import Test.QuickCheck++import Data.PrimitiveArray.Index.Class++++-- | A special index wrapper -- like @Outside@. @Complement@ allows combining+-- inside and outside symbols which complement each other. This then yields+-- ensemble results for each index (you need @ADPfusion@ for this).++newtype Complement z = C { unC :: z }+  deriving (Eq,Ord,Read,Show,Generic)++derivingUnbox "Complement"+  [t| forall z . Unbox z => Complement z -> z |]+  [| unC |]+  [| C   |]++instance Binary    z => Binary    (Complement z)+instance Serialize z => Serialize (Complement z)+instance ToJSON    z => ToJSON    (Complement z)+instance FromJSON  z => FromJSON  (Complement z)++instance NFData z => NFData (Complement z) where+  rnf (C z) = rnf z+  {-# Inline rnf #-}++instance Index i => Index (Complement i) where+  linearIndex (C l) (C h) (C i) = linearIndex l h i+  {-# INLINE linearIndex #-}+  smallestLinearIndex (C i) = smallestLinearIndex i+  {-# INLINE smallestLinearIndex #-}+  largestLinearIndex (C i) = largestLinearIndex i+  {-# INLINE largestLinearIndex #-}+  size (C l) (C h) = size l h+  {-# INLINE size #-}+  inBounds (C l) (C h) (C z) = inBounds l h z+  {-# INLINE inBounds #-}++instance IndexStream i => IndexStream (Complement i) where+  streamUp   (C l) (C h) = fmap C $ streamUp l h+  {-# INLINE streamUp #-}+  streamDown (C l) (C h) = fmap C $ streamDown l h+  {-# INLINE streamDown #-}++instance Arbitrary z => Arbitrary (Complement z) where+  arbitrary    = C <$> arbitrary+  shrink (C z) = C <$> shrink z+
+ Data/PrimitiveArray/Index/Int.hs view
@@ -0,0 +1,47 @@++module Data.PrimitiveArray.Index.Int where++import Data.Vector.Fusion.Stream.Monadic (flatten,map,Step(..))+import Data.Vector.Fusion.Stream.Size+import Prelude hiding (map)++import Data.PrimitiveArray.Index.Class++++instance Index Int where+  linearIndex _ _ k = k+  {-# Inline linearIndex #-}+  smallestLinearIndex _ = error "still needed?"+  {-# Inline smallestLinearIndex #-}+  largestLinearIndex h = h+  {-# Inline largestLinearIndex #-}+  size _ h = h+1+  {-# Inline size #-}+  inBounds l h k = l <= k && k <= h+  {-# Inline inBounds #-}++instance IndexStream z => IndexStream (z:.Int) where+  streamUp (ls:.l) (hs:.h) = flatten mk step Unknown $ streamUp ls hs+    where mk z = return (z,l)+          step (z,k)+            | k > h     = return $ Done+            | otherwise = return $ Yield (z:.k) (z,k+1)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamUp #-}+  streamDown (ls:.l) (hs:.h) = flatten mk step Unknown $ streamDown ls hs+    where mk z = return (z,h)+          step (z,k)+            | k < l     = return $ Done+            | otherwise = return $ Yield (z:.k) (z,k-1)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamDown #-}++instance IndexStream Int where+  streamUp l h = map (\(Z:.k) -> k) $ streamUp (Z:.l) (Z:.h)+  {-# Inline streamUp #-}+  streamDown l h = map (\(Z:.k) -> k) $ streamDown (Z:.l) (Z:.h)+  {-# Inline streamDown #-}+
+ Data/PrimitiveArray/Index/Outside.hs view
@@ -0,0 +1,62 @@++module Data.PrimitiveArray.Index.Outside where++import Control.Applicative+import Control.DeepSeq (NFData(..))+import Data.Aeson+import Data.Binary+import Data.Serialize+import Data.Vector.Unboxed.Deriving+import Data.Vector.Unboxed (Unbox(..))+import GHC.Generics+import Test.QuickCheck++import Data.PrimitiveArray.Index.Class++++-- | The 'Outside' wrapper takes an index structure, and provides+-- 'IndexStream' functions 'streamUp' and 'streamDown' that work the other+-- way around. In particular, for @Outside z@ @streamUp (Outside z) = fmap+-- Outside $ streamDown z@ and vice versa. @Index@ functions are unwrapped+-- but otherwise work as before.++newtype Outside z = O { unO :: z }+  deriving (Eq,Ord,Read,Show,Generic)++derivingUnbox "Outside"+  [t| forall z . Unbox z => Outside z -> z |]+  [| unO |]+  [| O   |]++instance Binary    z => Binary    (Outside z)+instance Serialize z => Serialize (Outside z)+instance ToJSON    z => ToJSON    (Outside z)+instance FromJSON  z => FromJSON  (Outside z)++instance NFData z => NFData (Outside z) where+  rnf (O z) = rnf z+  {-# Inline rnf #-}++instance Index i => Index (Outside i) where+  linearIndex (O l) (O h) (O i) = linearIndex l h i+  {-# INLINE linearIndex #-}+  smallestLinearIndex (O i) = smallestLinearIndex i+  {-# INLINE smallestLinearIndex #-}+  largestLinearIndex (O i) = largestLinearIndex i+  {-# INLINE largestLinearIndex #-}+  size (O l) (O h) = size l h+  {-# INLINE size #-}+  inBounds (O l) (O h) (O z) = inBounds l h z+  {-# INLINE inBounds #-}++instance IndexStream i => IndexStream (Outside i) where+  streamUp (O l) (O h) = fmap O $ streamDown l h+  {-# INLINE streamUp #-}+  streamDown (O l) (O h) = fmap O $ streamUp l h+  {-# INLINE streamDown #-}++instance Arbitrary z => Arbitrary (Outside z) where+  arbitrary = O <$> arbitrary+  shrink (O z) = O <$> shrink z+
+ Data/PrimitiveArray/Index/Point.hs view
@@ -0,0 +1,119 @@++-- | @Point@ index structures are used for left- and right-linear grammars.+-- Such grammars have at most one syntactic symbol on each r.h.s. of a rule.+-- The syntactic symbol needs to be in an outermost position.++module Data.PrimitiveArray.Index.Point where++import           Control.Applicative+import           Control.DeepSeq (NFData(..))+import           Data.Aeson+import           Data.Binary+import           Data.Bits+import           Data.Bits.Extras (Ranked)+import           Data.Serialize+import           Data.Vector.Fusion.Stream.Size+import           Data.Vector.Unboxed.Deriving+import           Data.Vector.Unboxed (Unbox(..))+import           GHC.Generics+import qualified Data.Vector.Fusion.Stream.Monadic as SM+import qualified Data.Vector.Unboxed as VU+import           Test.QuickCheck++import           Data.PrimitiveArray.Index.Class++++-- | A point in a left-linear grammar. The syntactic symbol is in left-most+-- position.++newtype PointL = PointL {fromPointL :: Int}+  deriving (Eq,Read,Show,Generic)++-- | A point in a right-linear grammars.++newtype PointR = PointR {fromPointR :: Int}+  deriving (Eq,Read,Show,Generic)++++derivingUnbox "PointL"+  [t| PointL -> Int    |]+  [| \ (PointL i) -> i |]+  [| \ i -> PointL i   |]++instance Binary    PointL+instance Serialize PointL+instance FromJSON  PointL+instance ToJSON    PointL++instance NFData PointL where+  rnf (PointL l) = rnf l+  {-# Inline rnf #-}++instance Index PointL where+  linearIndex _ _ (PointL z) = z+  {-# INLINE linearIndex #-}+  smallestLinearIndex (PointL l) = error "still needed?"+  {-# INLINE smallestLinearIndex #-}+  largestLinearIndex (PointL h) = h+  {-# INLINE largestLinearIndex #-}+  size (_) (PointL h) = h + 1+  {-# INLINE size #-}+  inBounds (_) (PointL h) (PointL x) = 0<=x && x<=h+  {-# INLINE inBounds #-}++instance IndexStream z => IndexStream (z:.PointL) where+  streamUp (ls:.PointL lf) (hs:.PointL ht) = SM.flatten mk step Unknown $ streamUp ls hs+    where mk z = return (z,lf)+          step (z,k)+            | k > ht    = return $ SM.Done+            | otherwise = return $ SM.Yield (z:.PointL k) (z,k+1)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamUp #-}+  streamDown (ls:.PointL lf) (hs:.PointL ht) = SM.flatten mk step Unknown $ streamDown ls hs+    where mk z = return (z,ht)+          step (z,k)+            | k < lf    = return $ SM.Done+            | otherwise = return $ SM.Yield (z:.PointL k) (z,k-1)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamDown #-}++instance IndexStream PointL++instance Arbitrary PointL where+  arbitrary = do+    b <- choose (0,100)+    return $ PointL b+  shrink (PointL j)+    | 0<j = [PointL $ j-1]+    | otherwise = []++++derivingUnbox "PointR"+  [t| PointR -> Int    |]+  [| \ (PointR i) -> i |]+  [| \ i -> PointR i   |]++instance Binary    PointR+instance Serialize PointR+instance FromJSON  PointR+instance ToJSON    PointR++instance NFData PointR where+  rnf (PointR l) = rnf l+  {-# Inline rnf #-}++instance Index PointR where+  linearIndex l _ (PointR z) = undefined+  {-# INLINE linearIndex #-}+  smallestLinearIndex = undefined+  {-# INLINE smallestLinearIndex #-}+  largestLinearIndex = undefined+  {-# INLINE largestLinearIndex #-}+  size = undefined+  {-# INLINE size #-}+
+ Data/PrimitiveArray/Index/Set.hs view
@@ -0,0 +1,508 @@++-- | Set with and without interfaces. We provide instances for sets, and+-- sets with one or two interfaces. The @First@ and @Last@ annotation is+-- purely cosmetical (apart from introducing type safety).++module Data.PrimitiveArray.Index.Set where++import           Control.Applicative ((<$>),(<*>))+import           Control.DeepSeq (NFData(..))+import           Data.Aeson (FromJSON,ToJSON)+import           Data.Binary (Binary)+import           Data.Bits+import           Data.Bits.Extras+import           Data.Serialize (Serialize)+import           Data.Vector.Fusion.Stream.Size+import           Data.Vector.Unboxed.Deriving+import           Data.Vector.Unboxed (Unbox(..))+import           Debug.Trace+import           GHC.Generics+import qualified Data.Vector.Fusion.Stream.Monadic as SM+import qualified Data.Vector.Unboxed as VU+import           Test.QuickCheck (Arbitrary(..), choose, elements)++import           Data.Bits.Ordered+import           Data.PrimitiveArray.Index.Class++++-- * @newtype@s, @data@ types, @class@es.++++-- | Certain sets have an interface, a particular element with special+-- meaning. In this module, certain ``meanings'' are already provided.+-- These include a @First@ element and a @Last@ element. We phantom-type+-- these to reduce programming overhead.++newtype Interface t = Iter { getIter :: Int }+  deriving (Eq,Ord,Read,Show,Generic,Num)++-- | Declare the interface to be the start of a path.++data First++-- | Declare the interface to be the end of a path.++data Last++-- | Declare the interface to match anything.+--+-- TODO needed? want to use later in ADPfusion++data Any++-- | Newtype for a bitset. We'd use @Word@s but that requires more shape+-- instances.+--+-- TODO can we use @Word@s now?++newtype BitSet = BitSet { getBitSet :: Int }+  deriving (Eq,Ord,Read,Generic,FiniteBits,Ranked,Num,Bits)++-- | A bitset with one interface.++type BS1I i = BitSet:>Interface i++-- | A bitset with two interfaces.++type BS2I i j = BitSet:>Interface i:>Interface j++-- | Successor and Predecessor for sets. Designed as a class to accomodate+-- sets with interfaces and without interfaces with one function.+--+-- The functions are not written recursively, as we currently only have+-- three cases, and we do not want to "reset" while generating successors+-- and predecessors.+--+-- Note that sets have a partial order. Within the group of element with+-- the same @popCount@, we use @popPermutation@ which has the same stepping+-- order for both, @setSucc@ and @setPred@.++class SetPredSucc s where+  -- | Set successor. The first argument is the lower set limit, the second+  -- the upper set limit, the third the current set.+  setSucc :: s -> s -> s -> Maybe s+  -- | Set predecessor. The first argument is the lower set limit, the+  -- second the upper set limit, the third the current set.+  setPred :: s -> s -> s -> Maybe s++-- | Masks are used quite often for different types of bitsets. We liberate+-- them as a type family.++type family Mask s :: *++-- | @Fixed@ allows us to fix some or all bits of a bitset, thereby+-- providing @succ/pred@ operations which are only partially free.+--+-- The mask is lazy, this allows us to have @undefined@ for @l@ and @h@.+--+-- @f = getFixedMask .&. getFixed@ are the fixed bits.+-- @n = getFixed .&. complement getFixedMask@ are the free bits.+-- @to = complement getFixed@ is the to move mask+-- @n' = popShiftR to n@ yields the population after the move+-- @p = popPermutation undefined n'@ yields the new population permutation+-- @p' = popShiftL to p@ yields the population moved back+-- @final = p' .|. f@++data Fixed t = Fixed { getFixedMask :: (Mask t) , getFixed :: !t }++-- | Assuming a bitset on bits @[0 .. highbit]@, we can apply a mask that+-- stretches out those bits over @[0 .. higherBit]@ with @highbit <=+-- higherBit@. Any active interfaces are correctly set as well.++class ApplyMask s where+  applyMask :: Mask s -> s -> s++++-- * Instances++++derivingUnbox "Interface"+  [t| forall t . Interface t -> Int |]+  [| \(Iter i) -> i            |]+  [| Iter                      |]++instance Binary    (Interface t)+instance Serialize (Interface t)+instance ToJSON    (Interface t)+instance FromJSON  (Interface t)++instance NFData (Interface t) where+  rnf (Iter i) = rnf i+  {-# Inline rnf #-}++instance Index (Interface i) where+  linearIndex l _ (Iter z) = z - smallestLinearIndex l+  {-# INLINE linearIndex #-}+  smallestLinearIndex (Iter l) = l+  {-# INLINE smallestLinearIndex #-}+  largestLinearIndex (Iter h) = h+  {-# INLINE largestLinearIndex #-}+  size (Iter l) (Iter h) = h - l + 1+  {-# INLINE size #-}+  inBounds l h z = l <= z && z <= h+  {-# INLINE inBounds #-}++++derivingUnbox "BitSet"+  [t| BitSet     -> Int |]+  [| \(BitSet s) -> s   |]+  [| BitSet             |]++instance Show BitSet where+  show (BitSet s) = "<" ++ (show $ activeBitsL s) ++ ">(" ++ show s ++ ")"++instance Binary    BitSet+instance Serialize BitSet+instance ToJSON    BitSet+instance FromJSON  BitSet++instance NFData BitSet where+  rnf (BitSet s) = rnf s+  {-# Inline rnf #-}++instance Index BitSet where+  linearIndex l _ (BitSet z) = z - smallestLinearIndex l -- (2 ^ popCount l - 1)+  {-# INLINE linearIndex #-}+  smallestLinearIndex l = 2 ^ popCount l - 1+  {-# INLINE smallestLinearIndex #-}+  largestLinearIndex h = 2 ^ popCount h - 1+  {-# INLINE largestLinearIndex #-}+  size l h = 2 ^ popCount h - 2 ^ popCount l + 1+  {-# INLINE size #-}+  inBounds l h z = popCount l <= popCount z && popCount z <= popCount h+  {-# INLINE inBounds #-}++++instance IndexStream z => IndexStream (z:.BitSet) where+  streamUp (ls:.l) (hs:.h) = SM.flatten mk step Unknown $ streamUp ls hs+    where mk z = return (z , (if l <= h then Just l else Nothing))+          step (z , Nothing) = return $ SM.Done+          step (z , Just t ) = return $ SM.Yield (z:.t) (z , setSucc l h t)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamUp   #-}+  streamDown (ls:.l) (hs:.h) = SM.flatten mk step Unknown $ streamDown ls hs+    where mk z = return (z :. (if l <= h then Just h else Nothing))+          step (z :. Nothing) = return $ SM.Done+          step (z :. Just t ) = return $ SM.Yield (z:.t) (z :. setPred l h t)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamDown #-}++instance IndexStream z => IndexStream (z:.(BitSet:>Interface i)) where+  streamUp (ls:.l@(sl:>_)) (hs:.h@(sh:>_)) = SM.flatten mk step Unknown $ streamUp ls hs+    where mk z = return (z, (if sl<=sh then Just (sl:>(Iter . max 0 $ lsbZ sl)) else Nothing))+          step (z , Nothing) = return $ SM.Done+          step (z,  Just t ) = return $ SM.Yield (z:.t) (z , setSucc l h t)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamUp #-}+  streamDown (ls:.l@(sl:>_)) (hs:.h@(sh:>_)) = SM.flatten mk step Unknown $ streamDown ls hs+    where mk z = return (z, (if sl<=sh then Just (sh:>(Iter . max 0 $ lsbZ sh)) else Nothing))+          step (z , Nothing) = return $ SM.Done+          step (z , Just t ) = return $ SM.Yield (z:.t) (z , setPred l h t)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamDown #-}++instance IndexStream z => IndexStream (z:.(BitSet:>Interface i:>Interface j)) where+  streamUp (ls:.l@(sl:>_:>_)) (hs:.h@(sh:>_:>_)) = SM.flatten mk step Unknown $ streamUp ls hs+    where mk z | sl > sh   = return (z , Nothing)+               | cl == 0   = return (z , Just (0:>0:>0))+               | cl == 1   = let i = lsbZ sl+                             in  return (z , Just (sl :> Iter i :> Iter i))+               | otherwise = let i = lsbZ sl; j = lsbZ (sl `clearBit` i)+                             in  return (z , Just (sl :> Iter i :> Iter j))+               where cl = popCount sl+          step (z , Nothing) = return $ SM.Done+          step (z , Just t ) = return $ SM.Yield (z:.t) (z , setSucc l h t)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamUp #-}+  streamDown (ls:.l@(sl:>_:>_)) (hs:.h@(sh:>_:>_)) = SM.flatten mk step Unknown $ streamDown ls hs+    where mk z | sl > sh   = return (z , Nothing)+               | ch == 0   = return (z , Just (0:>0:>0))+               | ch == 1   = let i = lsbZ sh+                             in  return (z , Just (sh :> Iter i :> Iter i))+               | otherwise = let i = lsbZ sh; j = lsbZ sh+                             in  return (z , Just (sh :> Iter i :> Iter j))+               where ch = popCount sh+          step (z , Nothing) = return $ SM.Done+          step (z , Just t ) = return $ SM.Yield (z:.t) (z , setPred l h t)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamDown #-}++++instance SetPredSucc BitSet where+  setSucc l h s+    | cs > ch                        = Nothing+    | Just s' <- popPermutation ch s = Just s'+    | cs >= ch                       = Nothing+    | cs < ch                        = Just . BitSet $ 2^(cs+1) -1+    where ch = popCount h+          cs = popCount s+  {-# Inline setSucc #-}+  setPred l h s+    | cs < cl                        = Nothing+    | Just s' <- popPermutation ch s = Just s'+    | cs <= cl                       = Nothing+    | cs > cl                        = Just . BitSet $ 2^(cs-1) -1+    where cl = popCount l+          ch = popCount h+          cs = popCount s+  {-# Inline setPred #-}++instance SetPredSucc (BitSet:>Interface i) where+  setSucc (l:>il) (h:>ih) (s:>Iter is)+    | cs > ch                         = Nothing+    | Just is' <- maybeNextActive is s     = Just (s:>Iter is')+    | Just s'  <- popPermutation ch s = Just (s':>Iter (lsbZ s'))+    | cs >= ch                        = Nothing+    | cs < ch                         = let s' = BitSet $ 2^(cs+1)-1 in Just (s' :> Iter (lsbZ s'))+    where ch = popCount h+          cs = popCount s+  {-# Inline setSucc #-}+  setPred (l:>il) (h:>ih) (s:>Iter is)+    | cs < cl                         = Nothing+    | Just is' <- maybeNextActive is s     = Just (s:>Iter is')+    | Just s'  <- popPermutation ch s = Just (s':>Iter (lsbZ s'))+    | cs <= cl                        = Nothing+    | cs > cl                         = let s' = BitSet $ 2^(cs-1)-1 in Just (s' :> Iter (max 0 $ lsbZ s'))+    where cl = popCount l+          ch = popCount h+          cs = popCount s+  {-# Inline setPred #-}++instance SetPredSucc (BitSet:>Interface i:>Interface j) where+  setSucc (l:>il:>jl) (h:>ih:>jh) (s:>Iter is:>Iter js)+    -- early termination+    | cs > ch                         = Nothing+    -- in case nothing was set, set initial set @1@ with both interfaces+    -- pointing to the same element+    | cs == 0                         = Just (1:>0:>0)+    -- when only a single element is set, we just permute the population+    -- and set the single interface+    | cs == 1+    , Just s'  <- popPermutation ch s+    , let is' = lsbZ s'          = Just (s':>Iter is':>Iter is')+    -- try advancing only one of the interfaces, doesn't collide with @is@+    | Just js' <- maybeNextActive js (s `clearBit` is) = Just (s:>Iter is:>Iter js')+    -- advance other interface, +    | Just is' <- maybeNextActive is s+    , let js' = lsbZ (s `clearBit` is')      = Just (s:>Iter is':>Iter js')+    -- find another permutation of the population+    | Just s'  <- popPermutation ch s+    , let is' = lsbZ s'+    , Just js' <- maybeNextActive is' s'   = Just (s':>Iter is':>Iter js')+    -- increasing the population forbidden by upper limit+    | cs >= ch                        = Nothing+    -- increase population+    | cs < ch+    , let s' = BitSet $ 2^(cs+1)-1+    , let is' = lsbZ s'+    , Just js' <- maybeNextActive is' s'   = Just (s':>Iter is':>Iter js')+    where ch = popCount h+          cs = popCount s+  {-# Inline setSucc #-}+  setPred (l:>il:>jl) (h:>ih:>jh) (s:>Iter is:>Iter js)+    -- early termination+    | cs < cl                         = Nothing+    -- in case nothing was set, set initial set @1@ with both interfaces+    -- pointing to the same element+    | cs == 0                         = Nothing+    -- when only a single element is set, we just permute the population+    -- and set the single interface+    | cs == 1+    , Just s'  <- popPermutation ch s+    , let is' = lsbZ s'          = Just (s':>Iter is':>Iter is')+    -- return the single @0@ set+    | cs == 1                         = Just (0:>0:>0)+    -- try advancing only one of the interfaces, doesn't collide with @is@+    | Just js' <- maybeNextActive js (s `clearBit` is) = Just (s:>Iter is:>Iter js')+    -- advance other interface, +    | Just is' <- maybeNextActive is s+    , let js' = lsbZ (s `clearBit` is')      = Just (s:>Iter is':>Iter js')+    -- find another permutation of the population+    | Just s'  <- popPermutation ch s+    , let is' = lsbZ s'+    , Just js' <- maybeNextActive is' s'   = Just (s':>Iter is':>Iter js')+    -- decreasing the population forbidden by upper limit+    | cs <= cl                        = Nothing+    -- decrease population+    | cs > cl && cs > 2+    , let s' = BitSet $ 2^(cs-1)-1+    , let is' = lsbZ s'+    , Just js' <- maybeNextActive is' s'   = Just (s':>Iter is':>Iter js')+    -- decrease population to single-element sets+    | cs > cl && cs == 2              = Just (1:>0:>0)+    where cl = popCount l+          ch = popCount h+          cs = popCount s+  {-# Inline setPred #-}++++type instance Mask BitSet = BitSet++type instance Mask (BitSet :> Interface i) = BitSet++type instance Mask (BitSet :> Interface i :> Interface j) = BitSet++++derivingUnbox "Fixed"+  [t| forall t . (Unbox t, Unbox (Mask t)) => Fixed t -> (Mask t, t) |]+  [| \(Fixed m s) -> (m,s)              |]+  [| uncurry Fixed                      |]++deriving instance (Eq t     , Eq      (Mask t)) => Eq      (Fixed t)+deriving instance (Ord t    , Ord     (Mask t)) => Ord     (Fixed t)+deriving instance (Read t   , Read    (Mask t)) => Read    (Fixed t)+deriving instance (Show t   , Show    (Mask t)) => Show    (Fixed t)+deriving instance (Generic t, Generic (Mask t)) => Generic (Fixed t)++instance (Generic t, Generic (Mask t), Binary t   , Binary    (Mask t)) => Binary    (Fixed t)+instance (Generic t, Generic (Mask t), Serialize t, Serialize (Mask t)) => Serialize (Fixed t)+{- -- TODO do json instances work automatically here?+instance ToJSON    (Interface t)+instance FromJSON  (Interface t)+-}++instance NFData (Fixed t) where+  rnf (Fixed m s) = m `seq` s `seq` ()++-- TODO we need to be careful here, that we actually fix all bits that are+-- fixed AND that during permutations / increases in popCount we do not set+-- an already fixed bit -- as otherwise we lose one in popCount.++testBsS :: BitSet -> Maybe (Fixed BitSet)+testBsS k = setSucc (Fixed 0 0) (Fixed 0 7) (Fixed 4 k)+{-# NoInline testBsS #-}++instance SetPredSucc (Fixed BitSet) where+  setPred (Fixed _ l) (Fixed _ h) (Fixed !m s) = Fixed m <$> setPred l h (s .&. complement m)+  {-# Inline setPred #-}+  --setSucc (Fixed _ l) (Fixed _ h) (Fixed !m s) = Fixed m <$> setSucc l h (s .&. complement m)+  --setSucc (Fixed _ l) (Fixed _ h) (Fixed !m' s) = (Fixed m . (.|. f)) <$> p -- return population, now again including the fixed part @f@+  --  where m = m' .&. h            -- constrain the mask to just the bits until @h@+  --        f = s .&. m             -- these bits are fixed to @1@+  --        n = s .&. complement m  -- these bits are free to be @0@ or @1@ and may move around; this means that @n `subset` complement m@+  --        to = complement m       -- once we have calculated our permutation, we move it to the correct places via @to@+  --        n' = popShiftR to n     -- population without holes. all primes denote that we are in hole-free space.+  --        p' = popPermutation (popCount $ h .&. to) n'  -- permutate the shifted population+  --        p  = popShiftL to <$> p'  -- undo the shift+  setSucc (Fixed _ l) (Fixed _ h) (Fixed !m' s) = traceShow (h,m,s,' ',fb0,fb1,' ',p',p'',p) $ (Fixed m . (.|. fb1)) <$> p+    where m   = m' .&. h+          fb0 = m  .&. complement s+          fb1 = m  .&. s+          p'  = popShiftR m s+          p'' = setSucc (popShiftR m l) (popShiftR m h) p'+          p   = popShiftL m <$> p''+  {-# Inline setSucc #-}++instance SetPredSucc (Fixed (BitSet:>Interface i)) where+  setPred (Fixed _ (l:>li)) (Fixed _ (h:>hi)) (Fixed !m (s:>i))+    | s `testBit` getIter i = (Fixed m . (:> i) . ( `setBit` getIter i)) <$> setPred l h (s .&. complement m)+    | otherwise             = (Fixed m) <$> setPred (l:>li) (h:>hi) ((s .&. complement m):>i)+  {-# Inline setPred #-}+  setSucc (Fixed _ (l:>li)) (Fixed _ (h:>hi)) (Fixed !m (s:>i))+    | s `testBit` getIter i = (Fixed m . (:> i) . ( `setBit` getIter i)) <$> setSucc l h (s .&. complement m)+    | otherwise             = (Fixed m) <$> setSucc (l:>li) (h:>hi) ((s .&. complement m):>i)+  {-# Inline setSucc #-}++instance SetPredSucc (Fixed (BitSet:>Interface i:>Interface j)) where+  setPred (Fixed _ (l:>li:>lj)) (Fixed _ (h:>hi:>hj)) (Fixed !m (s:>i:>j))+    | s `testBit` getIter i && s `testBit` getIter j+    = (Fixed m . (\z       -> (z `setBit` getIter i `setBit` getIter j:>i:>j ))) <$> setPred l h (s .&. complement m)+    | s `testBit` getIter i+    = (Fixed m . (\(z:>j') -> (z `setBit` getIter i                   :>i:>j'))) <$> setPred (l:>lj) (h:>hj) (s .&. complement m :>j)+    | s `testBit` getIter j+    = (Fixed m . (\(z:>i') -> (z `setBit` getIter j                   :>i':>j))) <$> setPred (l:>li) (h:>hi) (s .&. complement m :>i)+  {-# Inline setPred #-}+  setSucc (Fixed _ (l:>li:>lj)) (Fixed _ (h:>hi:>hj)) (Fixed !m (s:>i:>j))+    | s `testBit` getIter i && s `testBit` getIter j+    = (Fixed m . (\z       -> (z `setBit` getIter i `setBit` getIter j:>i:>j ))) <$> setSucc l h (s .&. complement m)+    | s `testBit` getIter i+    = (Fixed m . (\(z:>j') -> (z `setBit` getIter i                   :>i:>j'))) <$> setSucc (l:>lj) (h:>hj) (s .&. complement m :>j)+    | s `testBit` getIter j+    = (Fixed m . (\(z:>i') -> (z `setBit` getIter j                   :>i':>j))) <$> setSucc (l:>li) (h:>hi) (s .&. complement m :>i)+  {-# Inline setSucc #-}++++instance ApplyMask BitSet where+  applyMask = popShiftL+  {-# Inline applyMask #-}++instance ApplyMask (BitSet :> Interface i) where+  applyMask m (s:>i)+    | popCount s == 0 = 0:>0+    | otherwise       = popShiftL m s :> (Iter . getBitSet . popShiftL m . BitSet $ 2 ^ getIter i)+  {-# Inline applyMask #-}++instance ApplyMask (BitSet :> Interface i :> Interface j) where+  applyMask m (s:>i:>j)+    | popCount s == 0 = 0:>0:>0+    | popCount s == 1 = s' :> i' :> Iter (getIter i')+    | otherwise       = s' :> i' :> j'+    where s' = popShiftL m s+          i' = Iter . getBitSet . popShiftL m . BitSet $ 2 ^ getIter i+          j' = Iter . getBitSet . popShiftL m . BitSet $ 2 ^ getIter j+  {-# Inline applyMask #-}++++arbitraryBitSetMax = 6++instance (Arbitrary t, Arbitrary (Mask t)) => Arbitrary (Fixed t) where+  arbitrary = Fixed <$> arbitrary <*> arbitrary+  shrink (Fixed m s) = [ Fixed m' s' | m' <- shrink m, s' <- shrink s ]++instance Arbitrary BitSet where+  arbitrary = BitSet <$> choose (0,2^arbitraryBitSetMax-1)+  shrink s = let s' = [ s `clearBit` a | a <- activeBitsL s ]+             in  s' ++ concatMap shrink s'++instance Arbitrary (BitSet:>Interface i) where+  arbitrary = do+    s <- arbitrary+    if s==0+      then return (s:>Iter 0)+      else do i <- elements $ activeBitsL s+              return (s:>Iter i)+  shrink (s:>i) =+    let s' = [ (s `clearBit` a:>i)+             | a <- activeBitsL s+             , Iter a /= i ]+             ++ [ 0 :> Iter 0 | popCount s == 1 ]+    in  s' ++ concatMap shrink s'++instance Arbitrary (BitSet:>Interface i:>Interface j) where+  arbitrary = do+    s <- arbitrary+    case (popCount s) of+      0 -> return (s:>Iter 0:>Iter 0)+      1 -> do i <- elements $ activeBitsL s+              return (s:>Iter i:>Iter i)+      _ -> do i <- elements $ activeBitsL s+              j <- elements $ activeBitsL (s `clearBit` i)+              return (s:>Iter i:>Iter j)+  shrink (s:>i:>j) =+    let s' = [ (s `clearBit` a:>i:>j)+             | a <- activeBitsL s+             , Iter a /= i, Iter a /= j ]+             ++ [ 0 `setBit` a :> Iter a :> Iter a+                | popCount s == 2+                , a <- activeBitsL s ]+             ++ [ 0 :> Iter 0 :> Iter 0+                | popCount s == 1 ]+    in  s' ++ concatMap shrink s'+
+ Data/PrimitiveArray/Index/Subword.hs view
@@ -0,0 +1,132 @@++-- | Index structure for context-free grammars on strings. A @Subword@ captures+-- a pair @(i,j)@ with @i<=j@.++module Data.PrimitiveArray.Index.Subword where++import Control.DeepSeq (NFData(..))+import Data.Aeson (FromJSON,ToJSON)+import Data.Binary (Binary)+import Data.Serialize (Serialize)+import Data.Vector.Fusion.Stream.Monadic (Step(..), flatten, map)+import Data.Vector.Fusion.Stream.Size+import Data.Vector.Unboxed.Deriving+import GHC.Generics (Generic)+import Test.QuickCheck (Arbitrary(..), choose)+import Prelude hiding (map)++import Data.PrimitiveArray.Index.Class++++-- | A subword wraps a pair of @Int@ indices @i,j@ with @i<=j@.+--+-- Subwords always yield the upper-triangular part of a rect-angular array.+-- This gives the quite curious effect that @(0,N)@ points to the+-- ``largest'' index, while @(0,0) ... (1,1) ... (k,k) ... (N,N)@ point to+-- the smallest. We do, however, use (0,0) as the smallest as (0,k) gives+-- successively smaller upper triangular parts.++newtype Subword = Subword {fromSubword :: (Int:.Int)}+  deriving (Eq,Ord,Show,Generic,Read)++derivingUnbox "Subword"+  [t| Subword -> (Int,Int) |]+  [| \ (Subword (i:.j)) -> (i,j) |]+  [| \ (i,j) -> Subword (i:.j) |]++instance Binary    Subword+instance Serialize Subword+instance FromJSON  Subword+instance ToJSON    Subword++instance NFData Subword where+  rnf (Subword (i:.j)) = i `seq` rnf j+  {-# Inline rnf #-}++subword :: Int -> Int -> Subword+subword i j = Subword (i:.j)+{-# INLINE subword #-}++-- | triangular numbers+--+-- A000217++triangularNumber :: Int -> Int+triangularNumber x = (x * (x+1)) `quot` 2+{-# INLINE triangularNumber #-}++-- | Size of an upper triangle starting at 'i' and ending at 'j'. "(0,N)" what+-- be the normal thing to use.++upperTri :: Subword -> Int+upperTri (Subword (i:.j)) = triangularNumber $ j-i+1+{-# INLINE upperTri #-}++-- | Subword 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 :: Subword -> Subword -> Int+subwordIndex (Subword (l:.n)) (Subword (i:.j)) = adr n (i,j) -- - adr n (l,n)+  where+    adr n (i,j) = (n+1)*i - triangularNumber i + j+{-# INLINE subwordIndex #-}++subwordFromIndex :: Subword -> Int -> Subword+subwordFromIndex = error "subwordFromIndex not implemented"+{-# INLINE subwordFromIndex #-}++++instance Index Subword where+  linearIndex _ h i = subwordIndex h i+  {-# Inline linearIndex #-}+  smallestLinearIndex _ = error "still needed?"+  {-# Inline smallestLinearIndex #-}+  largestLinearIndex = upperTri+  {-# Inline largestLinearIndex #-}+  size _ h = upperTri h+  {-# Inline size #-}+  inBounds _ (Subword (_:.h)) (Subword (i:.j)) = 0<=i && i<=j && j<=h+  {-# Inline inBounds #-}++instance IndexStream z => IndexStream (z:.Subword) where+  streamUp (ls:.Subword (l:._)) (hs:.Subword (_:.h)) = flatten mk step Unknown $ streamUp ls hs+    where mk z = return (z,h,h)+          step (z,i,j)+            | i < l     = return $ Done+            | j > h     = return $ Skip (z,i-1,i-1)+            | otherwise = return $ Yield (z:.subword i j) (z,i,j+1)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamUp #-}+  streamDown (ls:.Subword (l:._)) (hs:.Subword (_:.h)) = flatten mk step Unknown $ streamDown ls hs+    where mk z = return (z,l,h)+          step (z,i,j)+            | i > h     = return $ Done+            | j < i     = return $ Skip (z,i+1,h)+            | otherwise = return $ Yield (z:.subword i j) (z,i,j-1)+          {-# Inline [0] mk   #-}+          {-# Inline [0] step #-}+  {-# Inline streamDown #-}++-- Default methods don't inline in a good way!++instance IndexStream Subword where+  streamUp l h = map (\(Z:.i) -> i) $ streamUp (Z:.l) (Z:.h)+  {-# INLINE streamUp #-}+  streamDown l h = map (\(Z:.i) -> i) $ streamDown (Z:.l) (Z:.h)+  {-# INLINE streamDown #-}++instance Arbitrary Subword where+  arbitrary = do+    a <- choose (0,100)+    b <- choose (0,100)+    return $ Subword (min a b :. max a b)+  shrink (Subword (i:.j))+    | i<j       = [Subword (i:.j-1), Subword (i+1:.j)]+    | otherwise = []+
− Data/PrimitiveArray/QuickCheck.hs
@@ -1,5 +0,0 @@--module Data.PrimitiveArray.QuickCheck where---
+ Data/PrimitiveArray/QuickCheck/Index/Set.hs view
@@ -0,0 +1,31 @@++module Data.PrimitiveArray.QuickCheck.Index.Set where++import Control.Applicative+import Data.Bits+import Data.Word (Word)+import Debug.Trace+import Test.QuickCheck hiding (Fixed(..), (.&.))++import Data.PrimitiveArray.Index.Set++++-- TODO what exactly does the mask fix? Only bits already @1@, or every bit+-- as it is? The mask should actually freeze-fix those bits, where we are+-- set to @1@!++prop_Fixed_BitSet_setSucc (u :: Word, Fixed m s :: Fixed BitSet) = traceShow (tgo, tsu) $ tgo == tsu+  where tgo = go s+        tsu = (getFixed <$> setSucc (Fixed 0 0) (Fixed 0 h) (Fixed m s))+        fb1 = m .&. s -- fixed bits to 1+        fb0 = m .&. complement s  -- fixed bits to 0+        h   = bit (fromIntegral $ u `mod` 8) - 1+        go x -- continue creating successors, until the mask criterion is met (again).+          | Nothing <- ssx = Nothing+          | Just x' <- ssx+          , fb0 == m .&. complement x'+          , fb1 == m .&. x' = traceShow ('j',fb0,fb1,m,x,x') $ Just x'+          | Just x' <- ssx  = traceShow ('g',fb0,fb1,m,x,x') $ go x'+          where ssx = setSucc 0 h x+
− Data/PrimitiveArray/Zero.hs
@@ -1,147 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}---- | Primitive arrays where the lower index is zero (or the equivalent of zero--- for newtypes and enumerations).--module Data.PrimitiveArray.Zero where--import           Control.Exception (assert)-import           Control.Monad-import           Control.Monad.Primitive (PrimState)-import           Data.Array.Repa.Index-import           Data.Array.Repa.Shape-import           Data.Vector.Generic as G hiding (forM_, length, zipWithM_, new)-import           Data.Vector.Generic.Mutable as GM hiding (length)-import qualified Data.Vector as V hiding (forM_, length, zipWithM_)-import qualified Data.Vector.Unboxed as VU hiding (forM_, length, zipWithM_)-import qualified Data.Vector.Unboxed.Mutable as VUM hiding (length)--import Data.Array.Repa.ExtShape-import Data.PrimitiveArray------ * Unboxed, multidimensional arrays.--data Unboxed sh e = Unboxed !sh !(VU.Vector e)-  deriving (Read,Show,Eq)--data instance MutArr m (Unboxed sh e) = MUnboxed !sh !(VU.MVector (PrimState m) e)--instance (Shape sh, ExtShape sh, VUM.Unbox elm) => MPrimArrayOps Unboxed sh elm where-  boundsM (MUnboxed exUb _) = (zeroDim,exUb `subDim` unitDim)-  fromListM inLb inUb xs = do-    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.. size exUb -1] xs-    return ma-  newM inLb inUb = let exUb = inUb `addDim` unitDim in-    unless (inLb == zeroDim) (error "MArr0 lb/=zeroDim") >>-    MUnboxed exUb `liftM` new (size exUb)-  newWithM inLb inUb def = do-    let exUb = inUb `addDim` unitDim-    ma <- newM inLb inUb-    let (MUnboxed _ mba) = ma-    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-  {-# INLINE boundsM #-}-  {-# INLINE fromListM #-}-  {-# INLINE newM #-}-  {-# INLINE newWithM #-}-  {-# INLINE readM #-}-  {-# INLINE writeM #-}--instance (Shape sh, ExtShape sh, VUM.Unbox elm) => PrimArrayOps Unboxed sh elm where-  bounds (Unboxed exUb _) = (zeroDim,exUb `subDim` unitDim)-  freeze (MUnboxed exUb mba) = Unboxed exUb `liftM` unsafeFreeze mba-  index (Unboxed exUb ba) idx = assert (inShape exUb idx) $ unsafeIndex ba (toIndex exUb idx)-  {-# INLINE bounds #-}-  {-# INLINE freeze #-}-  {-# INLINE index #-}--instance (Shape sh, ExtShape sh, VUM.Unbox e, VUM.Unbox e') => PrimArrayMap Unboxed sh e e' where-  map f (Unboxed sh xs) = Unboxed sh (VU.map f xs)-  {-# INLINE map #-}------ * Boxed, multidimensional arrays.--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 #-}---{-- -- - This stuff tells us how to write efficient generics on large data- - constructors like the Turner and Vienna ctors.- ---import qualified Data.Generics.TH as T--data Unboxed sh e = Unboxed !sh !(VU.Vector e)-  deriving (Show,Eq,Ord)--data X e = X (Unboxed DIM1 e) (Unboxed DIM1 e)-  deriving (Show,Eq,Ord)--x :: X Int-x = X z z where z = (Unboxed (Z:.10) (VU.fromList [ 0 .. 10] ))--pot :: X Int -> X Double-pot = $( T.thmapT (T.mkTs ['f]) [t| X Int |] ) where-  f :: Unboxed DIM1 Int -> Unboxed DIM1 Double-  f (Unboxed sh xs) = Unboxed sh (VU.map fromIntegral xs)---}-
LICENSE view
@@ -1,4 +1,4 @@-Copyright Christian Hoener zu Siederdissen 2010-2013+Copyright Christian Hoener zu Siederdissen 2010-2015  All rights reserved. 
PrimitiveArray.cabal view
@@ -1,49 +1,109 @@ Name:           PrimitiveArray-Version:        0.5.4.0+Version:        0.6.0.0 License:        BSD3 License-file:   LICENSE-Author:         Christian Hoener zu Siederdissen-Maintainer:     choener@tbi.univie.ac.at-Copyright:      Christian Hoener zu Siederdissen, 2010-2014-Homepage:       http://www.tbi.univie.ac.at/~choener/+Maintainer:     choener@bioinf.uni-leipzig.de+author:         Christian Hoener zu Siederdissen, 2011-2015+copyright:      Christian Hoener zu Siederdissen, 2011-2015+homepage:       http://www.bioinf.uni-leipzig.de/Software/gADP/ Stability:      Experimental Category:       Data Build-type:     Simple-Cabal-version:  >=1.6-Synopsis:-                Efficient multidimensional arrays+Cabal-version:  >=1.10.0+tested-with:    GHC == 7.8.4, GHC == 7.10.1+Synopsis:       Efficient multidimensional arrays Description:-                This library provides efficient multidimensional arrays.+                This library provides efficient multidimensional arrays. Import+                @Data.PrimitiveArray@ for indices, lenses, and arrays.                 .+                For ADPfusion users, the library also provides the machinary to+                fill tables in the correct order required by usual CYK-style+                parsers, or regular grammars (used e.g. in alignment+                algorithms). This means that unless your grammar require a+                strange order in which parsing is to be performed, it will+                mostly "just work".+                .                 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. ++ extra-source-files:-  changelog+  README.md+  changelog.md ++ 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.Class+    Data.PrimitiveArray.Dense     Data.PrimitiveArray.FillTables-    Data.PrimitiveArray.QuickCheck-    Data.PrimitiveArray.Zero-  Build-depends:-    base            >= 4 && <5  ,-    deepseq         >= 1.3      ,-    primitive       >= 0.5.0.1  ,-    vector          >= 0.10.0.1 ,-    vector-th-unbox >= 0.2      ,-    repa            >= 3.2.3    ,-    QuickCheck      >= 2.5+    Data.PrimitiveArray.Index+    Data.PrimitiveArray.Index.Class+    Data.PrimitiveArray.Index.Complement+    Data.PrimitiveArray.Index.Int+    Data.PrimitiveArray.Index.Outside+    Data.PrimitiveArray.Index.Point+    Data.PrimitiveArray.Index.Set+    Data.PrimitiveArray.Index.Subword+    Data.PrimitiveArray.QuickCheck.Index.Set+  build-depends: base                     >= 4.7      && < 4.9+               , aeson                    == 0.8.*+               , binary                   == 0.7.*+               , bits                     == 0.4.*+               , cereal                   == 0.4.*+               , deepseq                  >= 1.3      && < 1.5+               , OrderedBits              == 0.0.0.*+               , primitive                >= 0.5.4    && < 0.7+               , QuickCheck               >= 2.7      && < 2.9+               , vector                   == 0.10.*+               , vector-binary-instances  == 0.2.*+               , vector-th-unbox          == 0.2.*+  default-extensions: BangPatterns+                    , DefaultSignatures+                    , DeriveGeneric+                    , FlexibleContexts+                    , FlexibleInstances+                    , GeneralizedNewtypeDeriving+                    , MultiParamTypeClasses+                    , RankNTypes+                    , ScopedTypeVariables+                    , StandaloneDeriving+                    , TemplateHaskell+                    , TypeFamilies+                    , TypeOperators+                    , UndecidableInstances+  default-language:+    Haskell2010   ghc-options:     -O2     -funbox-strict-fields++++test-suite properties+  type:+    exitcode-stdio-1.0+  main-is:+    properties.hs+  ghc-options:+    -threaded -rtsopts -with-rtsopts=-N+  hs-source-dirs:+    tests+  default-language:+    Haskell2010+  default-extensions: TemplateHaskell+  build-depends: base+               , PrimitiveArray+               , QuickCheck+               , test-framework               >= 0.8  && < 0.9+               , test-framework-quickcheck2   >= 0.3  && < 0.4+               , test-framework-th            >= 0.2  && < 0.3++  source-repository head   type: git
+ README.md view
@@ -0,0 +1,18 @@+# PrimitiveArray++[![Build Status](https://travis-ci.org/choener/PrimitiveArray.svg?branch=master)](https://travis-ci.org/choener/PrimitiveArray)++PrimitiveArray provides operations on multi-dimensional arrays. Internally, the+representation is based on the vector library, while the multi-dimensional+indexing follows repa.++Primitive arrays are designed to be used together with ADPfusion.++++#### Contact++Christian Hoener zu Siederdissen+choener@bioinf.uni-leipzig.de+http://www.bioinf.uni-leipzig.de/~choener/+
− changelog
@@ -1,9 +0,0 @@-0.5.4.0--- actually implemented PointR--- added the rather important strictness annotation for mutable arrays in .Zero--0.5.3.0--- fixed vector-th-unbox problem
+ changelog.md view
@@ -0,0 +1,37 @@+0.6.0.0+-------++- moved primitive array classes to Data.PrimitiveArray.Class+- added _from / _to lenses+- Field1 .. Field6 lenses for indices (Z:.a:.b...) (with Z being Field0)+  - lens stuff currently commented out; aiming to have an extra package [lens+    is fairly heavy]+- FillTables should work now (with PointL, Subword)+- freezing of whole stacks of (Z:.mutarr:.mutarr:. ...) tables+- explicit 'Shape Subword'; this allows for simpler code in a number of places+  and is especially useful for CYK-style algorithms that have a+  single-dimensional upper-triangular matrix.+- rangeStream of Extshape is new and used by the FillTables module+- Binary, Cereal, Aeson instances for indices and immutable tables+- orphan instances of Binary, Cereal, Aeson for Z, and (:.)+- topmostIndex returns the final index position for CYK-style (bottom to top)+  parsing+- removed Data.Array.Repa.Index.Point (we have PointL, PointR in Points.hs)+- added   Data.Array.Repa.Index.Set (for sets with an interface, used by+  Hamiltonian path problems)+- Data.Array.Repa.Index.Outside is now just a newtype wrapped around other+  Index types. We want to be able to say "a Subword, but for Outside+  algorithms"+- travis-ci integration++0.5.4.0+-------++- actually implemented PointR++- added the rather important strictness annotation for mutable arrays in .Zero++0.5.3.0+-------++- fixed vector-th-unbox problem
+ tests/properties.hs view
@@ -0,0 +1,15 @@++module Main where++import           Test.Framework.Providers.QuickCheck2+import           Test.Framework.TH++-- import qualified Data.Bits.Ordered.QuickCheck as QC++++-- prop_PopCountSet = QC.prop_PopCountSet++main :: IO ()+main = $(defaultMainGenerator)+