TrieMap-3.0.0: Data/TrieSet.hs
{-# LANGUAGE UnboxedTuples #-}
module Data.TrieSet (
-- * Set type
TSet,
-- * Operators
(\\),
-- * Query
null,
size,
member,
notMember,
isSubsetOf,
isProperSubsetOf,
-- * Construction
empty,
singleton,
insert,
delete,
-- * Combine
union,
symmetricDifference,
intersection,
difference,
-- * Filter
filter,
partition,
split,
splitMember,
-- * Map
map,
mapMonotonic,
-- * Fold
foldl,
foldr,
-- * Min/Max
findMin,
findMax,
deleteMin,
deleteMax,
deleteFindMin,
deleteFindMax,
minView,
maxView,
-- * Conversion
-- ** Map
mapSet,
-- ** List
elems,
toList,
fromList,
-- ** Ordered lists
toAscList,
fromAscList,
fromDistinctAscList)
where
import Data.TrieMap.Class
import Data.TrieMap.Class.Instances ()
import Data.TrieMap.TrieKey
import Data.TrieMap.Representation.Class
import Data.TrieMap.Sized
import Data.TrieMap.Utils
import Control.Monad.Ends
import Data.Maybe
import qualified Data.Foldable as F
import Data.Monoid (Monoid (..))
import GHC.Exts
import Prelude hiding (foldr, foldl, map, filter, null)
instance TKey a => Eq (TSet a) where
s1 == s2 = size s1 == size s2 && s1 `isSubsetOf` s2
instance (TKey a, Ord a) => Ord (TSet a) where
s1 `compare` s2 = elems s1 `compare` elems s2
instance (TKey a, Show a) => Show (TSet a) where
show s = "fromList " ++ show (elems s)
instance TKey a => Monoid (TSet a) where
mempty = empty
mappend = union
-- | The empty 'TSet'.
empty :: TKey a => TSet a
empty = TSet emptyM
-- | Insert an element into the 'TSet'.
insert :: TKey a => a -> TSet a -> TSet a
insert a (TSet s) = TSet (insertWithM (const (Elem a)) (toRep a) (Elem a) s)
-- | Delete an element from the 'TSet'.
delete :: TKey a => a -> TSet a -> TSet a
delete a (TSet s) = TSet (searchMC (toRep a) s clearM (const clearM))
-- | /O(1)/. Create a singleton set.
singleton :: TKey a => a -> TSet a
singleton a = TSet (singletonM (toRep a) (Elem a))
-- | The union of two 'TSet's, preferring the first set when
-- equal elements are encountered.
union :: TKey a => TSet a -> TSet a -> TSet a
TSet s1 `union` TSet s2 = TSet (unionM (const . Just) s1 s2)
-- | The symmetric difference of two 'TSet's.
symmetricDifference :: TKey a => TSet a -> TSet a -> TSet a
TSet s1 `symmetricDifference` TSet s2 = TSet (unionM (\ _ _ -> Nothing) s1 s2)
-- | Difference of two 'TSet's.
difference :: TKey a => TSet a -> TSet a -> TSet a
TSet s1 `difference` TSet s2 = TSet (diffM (\ _ _ -> Nothing) s1 s2)
-- | Intersection of two 'TSet's. Elements of the result come from the first set.
intersection :: TKey a => TSet a -> TSet a -> TSet a
TSet s1 `intersection` TSet s2 = TSet (isectM (const . Just) s1 s2)
-- | Filter all elements that satisfy the predicate.
filter :: TKey a => (a -> Bool) -> TSet a -> TSet a
filter p (TSet s) = TSet (mapMaybeM (\ (Elem a) -> if p a then Just (Elem a) else Nothing) s)
-- | Partition the set into two sets, one with all elements that satisfy
-- the predicate and one with all elements that don't satisfy the predicate.
-- See also 'split'.
partition :: TKey a => (a -> Bool) -> TSet a -> (TSet a, TSet a)
partition p (TSet s) = case mapEitherM f s of
(# s1, s2 #) -> (TSet s1, TSet s2)
where f e@(Elem a)
| p a = (# Just e, Nothing #)
| otherwise = (# Nothing, Just e #)
-- | The expression (@'split' x set@) is a pair @(set1,set2)@
-- where @set1@ comprises the elements of @set@ less than @x@ and @set2@
-- comprises the elements of @set@ greater than @x@.
split :: TKey a => a -> TSet a -> (TSet a, TSet a)
split a s = case splitMember a s of
(sL, _, sR) -> (sL, sR)
-- | Performs a 'split' but also returns whether the pivot
-- element was found in the original set.
splitMember :: TKey a => a -> TSet a -> (TSet a, Bool, TSet a)
splitMember a (TSet s) = searchMC (toRep a) s nomatch match where
nomatch hole = (TSet (beforeM hole), False, TSet (afterM hole))
match _ hole = (TSet (beforeM hole), True, TSet (afterM hole))
-- |
-- @'map' f s@ is the set obtained by applying @f@ to each element of @s@.
--
-- It's worth noting that the size of the result may be smaller if,
-- for some @(x,y)@, @x \/= y && f x == f y@
map :: (TKey a, TKey b) => (a -> b) -> TSet a -> TSet b
map f s = fromList [f x | x <- elems s]
-- |
-- @'mapMonotonic' f s == 'map' f s@, but works only when @f@ is monotonic.
-- /The precondition is not checked./
-- Semi-formally, we have:
--
-- > and [x < y ==> f x < f y | x <- ls, y <- ls]
-- > ==> mapMonotonic f s == map f s
-- > where ls = toList s
mapMonotonic :: (TKey a, TKey b) => (a -> b) -> TSet a -> TSet b
mapMonotonic f s = fromAscList [f x | x <- toAscList s]
-- | Post-order fold.
foldr :: TKey a => (a -> b -> b) -> b -> TSet a -> b
foldr f z (TSet s) = F.foldr (flip $ F.foldr f) z s
-- | Pre-order fold.
foldl :: TKey b => (a -> b -> a) -> a -> TSet b -> a
foldl f z (TSet s) = F.foldl (F.foldl f) z s
-- | The minimal element of the set.
findMin :: TKey a => TSet a -> a
findMin = fst . deleteFindMin
-- | The maximal element of the set.
findMax :: TKey a => TSet a -> a
findMax = fst . deleteFindMax
-- | Delete the minimal element.
deleteMin :: TKey a => TSet a -> TSet a
deleteMin s = maybe s snd (minView s)
-- | Delete the maximal element.
deleteMax :: TKey a => TSet a -> TSet a
deleteMax s = maybe s snd (maxView s)
-- | Delete and find the minimal element.
--
-- > 'deleteFindMin' set = ('findMin' set, 'deleteMin' set)
deleteFindMin :: TKey a => TSet a -> (a, TSet a)
deleteFindMin = fromJust . minView
-- | Delete and find the maximal element.
--
-- > 'deleteFindMax' set = ('findMax' set, 'deleteMax' set)
deleteFindMax :: TKey a => TSet a -> (a, TSet a)
deleteFindMax = fromJust . maxView
-- | Retrieves the minimal key of the set, and the set
-- stripped of that element, or 'Nothing' if passed an empty set.
minView :: TKey a => TSet a -> Maybe (a, TSet a)
minView (TSet s) = case getFirst (extractHoleM s) of
Nothing -> Nothing
Just (Elem a, hole) -> Just (a, TSet (afterM hole))
-- | Retrieves the maximal key of the set, and the set
-- stripped of that element, or 'Nothing' if passed an empty set.
maxView :: TKey a => TSet a -> Maybe (a, TSet a)
maxView (TSet s) = case getLast (extractHoleM s) of
Nothing -> Nothing
Just (Elem a, hole) -> Just (a, TSet (beforeM hole))
{-# INLINE elems #-}
-- | See 'toAscList'.
elems :: TKey a => TSet a -> [a]
elems = toAscList
{-# INLINE toList #-}
-- | See 'toAscList'.
toList :: TKey a => TSet a -> [a]
toList = toAscList
{-# INLINE toAscList #-}
-- | Convert the set to an ascending list of elements.
toAscList :: TKey a => TSet a -> [a]
toAscList s = build (\ c n -> foldr c n s)
-- | Create a set from a list of elements.
fromList :: TKey a => [a] -> TSet a
fromList xs = TSet (fromListM const [(toRep x, Elem x) | x <- xs])
-- | Build a set from an ascending list in linear time.
-- /The precondition (input list is ascending) is not checked./
fromAscList :: TKey a => [a] -> TSet a
fromAscList xs = TSet (fromAscListM const [(toRep x, Elem x) | x <- xs])
-- | /O(n)/. Build a set from an ascending list of distinct elements in linear time.
-- /The precondition (input list is strictly ascending) is not checked./
fromDistinctAscList :: TKey a => [a] -> TSet a
fromDistinctAscList xs = TSet (fromDistAscListM [(toRep x, Elem x) | x <- xs])
-- | /O(1)/. Is this the empty set?
null :: TKey a => TSet a -> Bool
null (TSet s) = nullM s
-- | /O(1)/. The number of elements in the set.
size :: TKey a => TSet a -> Int
size (TSet s) = getSize s
-- | Is the element in the set?
member :: TKey a => a -> TSet a -> Bool
member a (TSet s) = option (lookupM (toRep a) s) False (const True)
-- | Is the element not in the set?
notMember :: TKey a => a -> TSet a -> Bool
notMember = not .: member
-- | Is this a subset? @(s1 `isSubsetOf` s2)@ tells whether @s1@ is a subset of @s2@.
isSubsetOf :: TKey a => TSet a -> TSet a -> Bool
TSet s1 `isSubsetOf` TSet s2 = isSubmapM (\ _ _ -> True) s1 s2
-- | Is this a proper subset? (ie. a subset but not equal).
isProperSubsetOf :: TKey a => TSet a -> TSet a -> Bool
s1 `isProperSubsetOf` s2 = size s1 < size s2 && s1 `isSubsetOf` s2
-- | See 'difference'.
(\\) :: TKey a => TSet a -> TSet a -> TSet a
(\\) = difference
{-# INLINE [1] mapSet #-}
-- | Generate a 'TMap' by mapping on the elements of a 'TSet'.
mapSet :: TKey a => (a -> b) -> TSet a -> TMap a b
mapSet f (TSet s) = TMap (fmapM (\ (Elem a) -> Assoc a (f a)) s)