packages feed

monoids 0.1.28 → 0.1.30

raw patch · 2 files changed

+173/−66 lines, 2 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.Ring.Semi.BitSet: instance Ord (BitSet a)
- Data.Ring.Semi.BitSet: instance Show (BitSet a)
+ Data.Ring.Semi.BitSet: instance (Enum a, Read a) => Read (BitSet a)
+ Data.Ring.Semi.BitSet: instance (Enum a, Show a) => Show (BitSet a)
+ Data.Ring.Semi.BitSet: intersection :: BitSet a -> BitSet a -> BitSet a
+ Data.Ring.Semi.BitSet: isComplemented :: BitSet a -> Bool
+ Data.Ring.Semi.BitSet: union :: BitSet a -> BitSet a -> BitSet a
- Data.Ring.Semi.BitSet: (\\) :: (Enum a, Bounded a) => BitSet a -> BitSet a -> BitSet a
+ Data.Ring.Semi.BitSet: (\\) :: (Enum a) => BitSet a -> BitSet a -> BitSet a

Files

Data/Ring/Semi/BitSet.hs view
@@ -1,20 +1,44 @@ {-# LANGUAGE FlexibleInstances, FlexibleContexts, MultiParamTypeClasses, DeriveDataTypeable, BangPatterns, PatternGuards, TypeFamilies #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Ring.Semi.BitSet+-- Copyright   :  (c) Edward Kmett 2009. +--                Based on Data.BitSet (c) Denis Bueno 2008-2009+-- License     :  BSD3+-- Maintainer  :  ekmett@gmail.com+-- Stability   :  experimental+-- Portability :  portable (instances use MPTCs)+--+-- Replacement for "Data.BitSet" extended to handle enumerations where fromEnum+-- can return negative values, support efficient intersection and union+-- and allow complementing of the set with respect to the bounds of the+-- enumeration+-------------------------------------------------------------------------------+ module Data.Ring.Semi.BitSet     ( module Data.Monoid.Reducer+    , module Data.Ring.Semi+    -- * BitSet     , BitSet+    -- * Manipulation     , empty     , singleton-    , null     , full+    , union+    , intersection     , complement     , insert     , delete+    , (\\)     , fromList     , fromDistinctAscList-    , toInteger-    , (\\)+    -- * Acessors     , member+    , null     , size+    , isComplemented+    , toInteger     ) where  import Prelude hiding ( null, exponent, toInteger )@@ -22,33 +46,33 @@ import qualified Data.Bits as Bits import Data.Data import Data.Ring.Semi.Natural+import Data.Ring.Semi import Data.Monoid.Reducer import Data.Generator import Data.Ring.Algebra+import Text.Read+import Text.Show  data BitSet a = BS -        { _countAtLeast  :: {-# UNPACK #-} !Int       -- ^ a conservative upper bound on the element count-        , _countAtMost   :: {-# UNPACK #-} !Int       -- ^ a conservative lower bound on the element count-        , _count         :: Int                       -- ^ the actual element count (lazy) used when the above two disagree-        , exponent       :: {-# UNPACK #-} !Int       -- ^ low water mark-        , _hwm           :: {-# UNPACK #-} !Int       -- ^ high water mark-        , mantissa       :: {-# UNPACK #-} !Integer   -- ^ the set of bits. TODO: negative mantissa = complement-        , _universe      :: (Int,Int)                 -- ^ invariant: mantissa < 0 => universe = (fromEnum minBound,fromEnum maxBound)-        } deriving (Data, Typeable,Show)--debug :: BitSet a -> (Int,Int,Int,Int,Int,Integer)-debug (BS a b c d e f _) = (a,b,c,d,e,f)+        { _countAtLeast  :: {-# UNPACK #-} !Int       -- ^ A conservative upper bound on the element count.+                                                      --   If negative, we are complemented with respect to the universe+        , _countAtMost   :: {-# UNPACK #-} !Int       -- ^ A conservative lower bound on the element count.+                                                      --   If negative, we are complemented with respect to the universe+        , _count         :: Int                       -- ^ Lazy element count used when the above two disagree. O(1) environment size+        , exponent       :: {-# UNPACK #-} !Int       -- ^ Low water mark. index of the least element potentially in the set.+        , _hwm           :: {-# UNPACK #-} !Int       -- ^ High water mark. index of the greatest element potentially in the set.+        , mantissa       :: {-# UNPACK #-} !Integer   -- ^ the set of bits starting from the exponent.+                                                      --   if negative, then we are complmenented with respect to universe+        , _universe      :: (Int,Int)                 -- ^ invariant: whenever mantissa < 0 => universe = (fromEnum minBound,fromEnum maxBound)+        } deriving (Data, Typeable) --- | internal smart constructor: makes sure the count is forced when known+-- | Internal smart constructor. Forces count whenever it is pigeonholed. bs :: Int -> Int -> Int -> Int -> Int -> Integer -> (Int,Int) -> BitSet a bs !a !b c !l !h !m u | a == b = BS a a a l h m u                       | otherwise = BS a b c l h m u {-# INLINE bs #-} --- instance (Enum a, Show a) => Show (BitSet a) where---    show s = "fromDistinctAscList " ++ show (toList s) ++ ---- | /O(d)/ where /d/ is absolute deviation in fromEnum from the least element in the set.+-- | /O(d)/ where /d/ is absolute deviation in fromEnum over the set toList :: Enum a => BitSet a -> [a] toList (BS _ _ _ l h m u)      | m < 0 = map toEnum [ul..max (pred l) ul] ++ toList' l (map toEnum [min (succ h) uh..uh])@@ -61,16 +85,18 @@                      | otherwise         = toList' (n+1) t {-# INLINE toList #-} --- | The empty bit set.+-- | /O(1)/ The empty set. Permits /O(1)/ null and size. empty :: BitSet a empty = BS 0 0 0 0 0 0 undefined {-# INLINE empty #-} +-- | /O(1)/ Construct a @BitSet@ with a single element. Permits /O(1)/ null and size singleton :: Enum a => a -> BitSet a  singleton x = BS 1 1 1 e e 1 undefined where e = fromEnum x {-# INLINE singleton #-} --- | Is the bit set empty? Asymptotically faster than checking if size == 0 in some cases.+-- | /O(1|d)/ Is the 'BitSet' empty? May be faster than checking if @'size' == 0@ after union.+--   Operations that require a recount are noted. null :: BitSet a -> Bool null (BS a b c _ _ _ _)      | a > 0     = False@@ -78,25 +104,42 @@     | otherwise = c == 0  {-# INLINE null #-} +-- | /O(1|d)/ The number of elements in the bit set.+size :: BitSet a -> Int+size (BS a b c _ _ m (ul,uh)) +    | a == b, m >= 0 = a+    | a == b         = uh - ul - a +    | m >= 0         = c+    | otherwise      = uh - ul - c +{-# INLINE size #-}++-- | /O(d)/ A 'BitSet' containing every member of the enumeration of @a@. full :: (Enum a, Bounded a) => BitSet a full = complement empty --universeOf :: (Bounded a, Enum a) => BitSet a -> (Int,Int)-universeOf x = (fromEnum (minBound `asArgTypeOf` x), fromEnum (maxBound `asArgTypeOf` x))+{-# INLINE full #-} --- ensures valid universe, may result in negative bitset, note recalculation of universe+-- | /O(d)/ Complements a 'BitSet' with respect to the bounds of @a@. Preserves order of 'null' and 'size' complement :: (Enum a, Bounded a) => BitSet a -> BitSet a -complement r@(BS a b c l h m _) = BS (Bits.complement b) (Bits.complement a) (Bits.complement c) l h (Bits.complement m) (universeOf r)+complement r@(BS a b c l h m _) = BS (Bits.complement b) (Bits.complement a) (Bits.complement c) l h (Bits.complement m) u where+    u = (fromEnum (minBound `asArgTypeOf` r), fromEnum (maxBound `asArgTypeOf` r))+{-# INLINE complement #-} --- proof obligation: either the value is already complemented or it is a complement-complement, note retention of u+-- | /O(d)/ unsafe internal method: complement a set that has already been complemented at least once. recomplement :: BitSet a -> BitSet a  recomplement (BS a b c l h m u) = BS (Bits.complement b) (Bits.complement a) (Bits.complement c) l h (Bits.complement m) u+{-# INLINE recomplement #-} --- | /O(d * n)/ Make a @BitSet@ from a list of items.+-- | /O(d)/ unsafe internal method: complement a set that has already been complemented at least once.+pseudoComplement :: BitSet a -> (Int,Int) -> BitSet a +pseudoComplement (BS a b c l h m _) u = BS (Bits.complement b) (Bits.complement a) (Bits.complement c) l h (Bits.complement m) u+{-# INLINE pseudoComplement #-}++-- | /O(d * n)/ Make a 'BitSet' from a list of items. fromList :: Enum a => [a] -> BitSet a fromList = foldr insert empty  {-# INLINE fromList #-} +-- | /O(d * n)/ Make a 'BitSet' from a distinct ascending list of items fromDistinctAscList :: Enum a => [a] -> BitSet a  fromDistinctAscList [] = empty fromDistinctAscList (c:cs) = fromDistinctAscList' cs 1 0 1 @@ -109,24 +152,24 @@                 h' = fromEnum c' {-# INLINE fromDistinctAscList #-} --- | /O(d)/ Insert an item into the bit set.+-- | /O(d)/ Insert a single element of type @a@ into the 'BitSet'. Preserves order of 'null' and 'size' insert :: Enum a => a -> BitSet a -> BitSet a insert x r@(BS a b c l h m u)      | m < 0, e < l = r      | m < 0, e > h = r-    | e < l = bs (a+1) (b+1) (c+1) e (h - e) (shiftL m (l - e) .|. 1) u+    | e < l = bs (a+1) (b+1) (c+1) e h (shiftL m (l - e) .|. 1) u     | e > h = bs (a+1) (b+1) (c+1) l p (setBit m p) u-    | testBit m (e - l) = r +    | testBit m p = r      | otherwise = bs (a+1) (b+1) (c+1) l h (setBit m p) u     where          e = fromEnum x         p = e - l  {-# INLINE insert #-} --- | /O(d)/ Delete an item from the bit set.+-- | /O(d)/ Delete a single item from the 'BitSet'. Preserves order of 'null' and 'size' delete :: Enum a => a -> BitSet a -> BitSet a delete x r@(BS a b c l h m u) -    | m < 0, e < l = bs (a+1) (b+1) (c+1) e (h - e) (shiftL m (l - e) .&. Bits.complement 1) u+    | m < 0, e < l = bs (a+1) (b+1) (c+1) e h (shiftL m (l - e) .&. Bits.complement 1) u     | m < 0, e > h = bs (a+1) (b+1) (c+1) l p (clearBit m p) u     | e < l       = r     | e > h       = r@@ -137,7 +180,7 @@         p = e - l {-# INLINE delete #-} --- | /O(testBit on Integer)/ Ask whether the item is in the bit set.+-- | /O(1)/ Test for membership in a 'BitSet' member :: Enum a => a -> BitSet a -> Bool member x (BS _ _ _ l h m _)      | e < l     = m < 0 @@ -147,33 +190,32 @@         e = fromEnum x {-# INLINE member #-} --- | /O(1)/ or /O(d)/ The number of elements in the bit set.-size :: BitSet a -> Int-size (BS a b c _ _ m (ul,uh)) -    | a == b, m >= 0 = a-    | a == b         = uh - ul - a -    | m >= 0         = c-    | otherwise      = uh - ul - c - -- | /O(d)/ convert to an Integer representation. Discards negative elements toInteger :: BitSet a -> Integer toInteger x = mantissa x `shift` exponent x +-- | /O(d)/. May force 'size' to take /O(d)/ if ranges overlap, preserves order of 'null' union :: BitSet a -> BitSet a -> BitSet a  union x@(BS a b c l h m u) y@(BS a' b' c' l' h' m' u')-    | l' < l    = union y x                                                         -- ensure left side has lower exponent-    | b == 0    = y                                                                 -- fast empty union-    | b' == 0   = x                                                                 -- fast empty union-    | a == -1   = BS (-1) (-1) (-1) 0 0 (-1) u                                      -- fast full union, recomplement obligation met by negative size-    | a' == -1  = BS (-1) (-1) (-1) 0 0 (-1) u'                                     -- fast full union, recomplement obligation met by negative size-    | m < 0, m' < 0 = recomplement (intersection (recomplement x) (recomplement y)) -- appeal to intersection, recomplement obligation met by 2s complement-    | m' < 0    = recomplement (pseudoDiff (recomplement y) x u')                      -- union with complement, recomplement obligation met by 2s complement -- THESE ARE WRONG FIX!-    | m < 0     = recomplement (pseudoDiff (recomplement x) y u)                      -- union with complement, recomplement obligation met by 2s complement -- THESE ARE WRONG FIX!-    | h < l'    = bs (a + a') (b + b') (c + c') l h' m'' u                          -- disjoint positive ranges-    | otherwise = bs (a `max` a') (b + b') (recount m'') l (h `max` h') m'' u       -- overlapped positives+    | l' < l        = union y x                                                         -- ensure left side has lower exponent+    | b == 0        = y                                                                 -- fast empty union+    | b' == 0       = x                                                                 -- fast empty union+    | a == -1       = entire u                                                          -- fast full union, recomplement obligation met by negative size+    | a' == -1      = entire u'                                                         -- fast full union, recomplement obligation met by negative size+    | m < 0, m' < 0 = recomplement (intersection (recomplement x) (recomplement y))     -- appeal to intersection, recomplement obligation met by 2s complement+    | m' < 0        = recomplement (pseudoDiff (recomplement y) x u')                   -- union with complement, recomplement obligation met by 2s complement+    | m < 0         = recomplement (pseudoDiff (recomplement x) y u)                    -- union with complement, recomplement obligation met by 2s complement+    | h < l'        = bs (a + a') (b + b') (c + c') l h' m'' u                          -- disjoint positive ranges+    | otherwise     = bs (a `max` a') (b + b') (recount m'') l (h `max` h') m'' u       -- overlapped positives     where          m'' = m .|. shiftL m' (l' - l)+        entire = BS (-1) (-1) (-1) 0 0 (-1) +-- | /O(1)/ check to see if we are represented as a complemented 'BitSet'. +isComplemented :: BitSet a -> Bool+isComplemented = (<0) . mantissa ++-- | /O(d)/. May force 'size' and 'null' both to take /O(d)/. intersection :: BitSet a -> BitSet a -> BitSet a  intersection x@(BS a b _ l h m u) y@(BS a' b' _ l' h' m' u')     | l' < l = intersection y x                                 @@ -190,24 +232,46 @@         l'' = max l l'         m'' = shift m (l'' - l) .&. shift m' (l'' - l') --- we know m >= 0, m' >= 0, a /= -1, a' /= -1, b /= 0, b' /= 0, u' is the universe of discourse+-- | Unsafe internal method for computing differences in a particular universe of discourse+-- preconditions:+--  m >= 0, m' >= 0, a /= -1, a' /= -1, b /= 0, b' /= 0, u'' is the universe of discourse pseudoDiff :: BitSet a -> BitSet a -> (Int,Int) -> BitSet a  pseudoDiff x@(BS a _ _ l h m _) (BS _ b' _ l' h' m' _) u''     | h < l' = x     | h' < l = x     | otherwise = bs (max (a - b') 0) a (recount m'') l h m'' u''-    where m'' = m .&. shift (Bits.complement m') (l' - l)+    where +        m'' = m .&. shift (Bits.complement m') (l' - l) -(\\) :: (Enum a, Bounded a) => BitSet a -> BitSet a -> BitSet a -x \\ y = x `intersection` complement y+-- | /O(d)/. Preserves order of 'null'. May force /O(d)/ 'size'.+difference :: Enum a => BitSet a -> BitSet a -> BitSet a +difference x@(BS a b _ _ _ m u)  y@(BS a' b' _ _ _ m' _) +   | a == -1       = pseudoComplement y u+   | a' == -1      = empty+   | b == 0        = empty+   | b' == 0       = x+   | m < 0, m' < 0 = pseudoDiff (recomplement y) (recomplement x) u+   | m < 0         = pseudoComplement (recomplement x `union` y) u+   | m' < 0        = x `union` recomplement y +   | otherwise     = pseudoDiff x y u+    +-- | /O(d)/. Preserves order of 'null'. May force /O(d)/ 'size'.+(\\) :: Enum a => BitSet a -> BitSet a -> BitSet a +(\\) = difference --- TODO: fix this so that it handles complements correctly instance Eq (BitSet a) where-    BS _ _ _ l _ m _ == BS _ _ _ l' _ m' _ = shift m (l'' - l) == shift m' (l'' - l) where l'' = min l l'-    BS _ _ _ l _ m _ /= BS _ _ _ l' _ m' _ = shift m (l'' - l) /= shift m' (l'' - l) where l'' = min l l'+    x@(BS _ _ _ l _ m u) == y@(BS _ _ _ l' _ m' _)+        | signum m == signum m' = shift m (l - l'') == shift m' (l - l'') +        | m' < 0 = y == x+        | otherwise = mask .&. shift m (l - ul) == shift m' (l - ul)+        where +            l'' = min l l'+            mask = setBit 0 (uh - ul + 1) - 1+            ul = fst u+            uh = snd u -instance Ord (BitSet a) where-    BS _ _ _ l _ m _ `compare` BS _ _ _ l' _ m' _ = shift m (l'' - l) `compare` shift m' (l'' - l) where l'' = min l l'+-- instance Ord (BitSet a) where+--    BS _ _ _ l _ m _ `compare` BS _ _ _ l' _ m' _ = shift m (l'' - l) `compare` shift m' (l'' - l) where l'' = min l l'  instance (Enum a, Bounded a) => Bounded (BitSet a) where     minBound = empty@@ -218,15 +282,58 @@         h = fromEnum (maxBound `asArgTypeOf` result)         m = setBit 0 n - 1 +-- | Utility function to avoid requiring ScopedTypeVariables asArgTypeOf :: a -> f a -> a asArgTypeOf = const {-# INLINE asArgTypeOf #-} +-- | /O(d)/ recount :: Integer -> Int-recount = recount' 0 where-    recount' :: Int -> Integer -> Int-    recount' !n 0 = n-    recount' !n !m = recount' (if testBit m 0 then n+1 else n) (shiftR m 1)+recount !n +    | n < 0     = Bits.complement (recount (Bits.complement n))+    | otherwise = recount' 0 0 +    where+        h = hwm n+        recount' !i !c+            | i > h = c+            | otherwise = recount' (i+1) (if testBit n i then c+1 else c)++-- | /O(d)/. Computes the equivalent of (truncate . logBase 2 . abs) extended with 0 at 0+hwm :: Integer -> Int+hwm !n +    | n < 0 = hwm (-n)+    | n > 1 = scan p (2*p) +    | otherwise = 0+    where+        p = probe 1+        -- incrementally compute 2^(2^(i+1)) until it exceeds n+        probe :: Int -> Int+        probe !i+            | bit (2*i) > n = i+            | otherwise     = probe (2*i)++        -- then scan the powers for the highest set bit+        scan :: Int -> Int -> Int+        scan !l !h+            | l == h = l+            | bit (m+1) > n = scan l m+            | otherwise = scan (m+1) h+            where m = l + (h - l) `div` 2+ +instance (Enum a, Show a) => Show (BitSet a) where+   showsPrec d x@(BS _ _ _ _ _ m u)+        | m < 0     = showParen (d > 10) $ showString "pseudoComplement " . showsPrec 11 (recomplement x) . showString " " . showsPrec 11 u+        | otherwise = showParen (d > 10) $ showString "fromDistinctAscList " . showsPrec 11 (toList x)++instance (Enum a, Read a) => Read (BitSet a) where+    readPrec = parens $ complemented +++ normal where+        complemented = prec 10 $ do +                Ident "pseudoComplement" <- lexP+                x <- step readPrec+                pseudoComplement x `fmap` step readPrec+        normal = prec 10 $ do+                Ident "fromDistinctAscList" <- lexP+                fromDistinctAscList `fmap` step readPrec  -- note that operations on values generated by toEnum are pretty slow because the bounds are suboptimal instance (Enum a, Bounded a) => Enum (BitSet a) where
monoids.cabal view
@@ -1,5 +1,5 @@ name:		    monoids-version:	    0.1.28+version:	    0.1.30 license:	    BSD3 license-file:   LICENSE author:		    Edward A. Kmett