#if __GLASGOW_HASKELL__ >= 707
#endif
module Data.Heap
(
Heap
, Entry(..)
, empty
, null
, size
, singleton
, insert
, minimum
, deleteMin
, union
, uncons, viewMin
, mapMonotonic
, map
, toUnsortedList
, fromList
, sort
, traverse
, mapM
, concatMap
, filter
, partition
, split
, break
, span
, take
, drop
, splitAt
, takeWhile
, dropWhile
, group
, groupBy
, nub
, intersect
, intersectWith
, replicate
) where
import Prelude hiding
( map
, span, dropWhile, takeWhile, break, filter, take, drop, splitAt
, foldr, minimum, replicate, mapM
, concatMap
#if __GLASGOW_HASKELL__ < 710
, null
#else
, traverse
#endif
)
#if MIN_VERSION_base(4,8,0)
import Data.Bifunctor
#endif
import qualified Data.List as L
import Control.Applicative (Applicative(pure))
import Control.Monad (liftM)
#if MIN_VERSION_base(4,9,0)
import Data.Semigroup (Semigroup(..))
#endif
import Data.Monoid (Monoid(mappend, mempty))
import Data.Foldable hiding (minimum, concatMap)
import Data.Function (on)
import Data.Data (DataType, Constr, mkConstr, mkDataType, Fixity(Prefix), Data(..), constrIndex)
import Data.Typeable (Typeable)
import Text.Read
import Text.Show
import qualified Data.Traversable as Traversable
import Data.Traversable (Traversable)
data Heap a
= Empty
| Heap !Int (a -> a -> Bool) !(Tree a)
deriving Typeable
#if __GLASGOW_HASKELL__ >= 707
type role Heap nominal
#endif
instance Show a => Show (Heap a) where
showsPrec _ Empty = showString "fromList []"
showsPrec d (Heap _ _ t) = showParen (d > 10) $
showString "fromList " . showsPrec 11 (toList t)
instance (Ord a, Read a) => Read (Heap a) where
readPrec = parens $ prec 10 $ do
Ident "fromList" <- lexP
fromList `fmap` step readPrec
instance (Ord a, Data a) => Data (Heap a) where
gfoldl k z h = z fromList `k` toUnsortedList h
toConstr _ = fromListConstr
dataTypeOf _ = heapDataType
gunfold k z c = case constrIndex c of
1 -> k (z fromList)
_ -> error "gunfold"
heapDataType :: DataType
heapDataType = mkDataType "Data.Heap.Heap" [fromListConstr]
fromListConstr :: Constr
fromListConstr = mkConstr heapDataType "fromList" [] Prefix
instance Eq (Heap a) where
Empty == Empty = True
Empty == Heap{} = False
Heap{} == Empty = False
a@(Heap s1 leq _) == b@(Heap s2 _ _) = s1 == s2 && go leq (toList a) (toList b)
where
go f (x:xs) (y:ys) = f x y && f y x && go f xs ys
go _ [] [] = True
go _ _ _ = False
instance Ord (Heap a) where
Empty `compare` Empty = EQ
Empty `compare` Heap{} = LT
Heap{} `compare` Empty = GT
a@(Heap _ leq _) `compare` b = go leq (toList a) (toList b)
where
go f (x:xs) (y:ys) =
if f x y
then if f y x
then go f xs ys
else LT
else GT
go f [] [] = EQ
go f [] (_:_) = LT
go f (_:_) [] = GT
empty :: Heap a
empty = Empty
singleton :: Ord a => a -> Heap a
singleton = singletonWith (<=)
singletonWith :: (a -> a -> Bool) -> a -> Heap a
singletonWith f a = Heap 1 f (Node 0 a Nil)
insert :: Ord a => a -> Heap a -> Heap a
insert = insertWith (<=)
insertWith :: (a -> a -> Bool) -> a -> Heap a -> Heap a
insertWith leq x Empty = singletonWith leq x
insertWith leq x (Heap s _ t@(Node _ y f))
| leq x y = Heap (s+1) leq (Node 0 x (t `Cons` Nil))
| otherwise = Heap (s+1) leq (Node 0 y (skewInsert leq (Node 0 x Nil) f))
union :: Heap a -> Heap a -> Heap a
union Empty q = q
union q Empty = q
union (Heap s1 leq t1@(Node _ x1 f1)) (Heap s2 _ t2@(Node _ x2 f2))
| leq x1 x2 = Heap (s1 + s2) leq (Node 0 x1 (skewInsert leq t2 f1))
| otherwise = Heap (s1 + s2) leq (Node 0 x2 (skewInsert leq t1 f2))
replicate :: Ord a => a -> Int -> Heap a
replicate x0 y0
| y0 < 0 = error "Heap.replicate: negative length"
| y0 == 0 = mempty
| otherwise = f (singleton x0) y0
where
f x y
| even y = f (union x x) (quot y 2)
| y == 1 = x
| otherwise = g (union x x) (quot (y 1) 2) x
g x y z
| even y = g (union x x) (quot y 2) z
| y == 1 = union x z
| otherwise = g (union x x) (quot (y 1) 2) (union x z)
uncons :: Heap a -> Maybe (a, Heap a)
uncons Empty = Nothing
uncons l@(Heap _ _ t) = Just (root t, deleteMin l)
viewMin :: Heap a -> Maybe (a, Heap a)
viewMin = uncons
minimum :: Heap a -> a
minimum Empty = error "Heap.minimum: empty heap"
minimum (Heap _ _ t) = root t
trees :: Forest a -> [Tree a]
trees (a `Cons` as) = a : trees as
trees Nil = []
deleteMin :: Heap a -> Heap a
deleteMin Empty = Empty
deleteMin (Heap _ _ (Node _ _ Nil)) = Empty
deleteMin (Heap s leq (Node _ _ f0)) = Heap (s 1) leq (Node 0 x f3)
where
(Node r x cf, ts2) = getMin leq f0
(zs, ts1, f1) = splitForest r Nil Nil cf
f2 = skewMeld leq (skewMeld leq ts1 ts2) f1
f3 = foldr (skewInsert leq) f2 (trees zs)
adjustMin :: (a -> a) -> Heap a -> Heap a
adjustMin _ Empty = Empty
adjustMin f (Heap s leq (Node r x xs)) = Heap s leq (heapify leq (Node r (f x) xs))
type ForestZipper a = (Forest a, Forest a)
zipper :: Forest a -> ForestZipper a
zipper xs = (Nil, xs)
emptyZ :: ForestZipper a
emptyZ = (Nil, Nil)
rightZ :: ForestZipper a -> ForestZipper a
rightZ (path, x `Cons` xs) = (x `Cons` path, xs)
adjustZ :: (Tree a -> Tree a) -> ForestZipper a -> ForestZipper a
adjustZ f (path, x `Cons` xs) = (path, f x `Cons` xs)
adjustZ _ z = z
rezip :: ForestZipper a -> Forest a
rezip (Nil, xs) = xs
rezip (x `Cons` path, xs) = rezip (path, x `Cons` xs)
rootZ :: ForestZipper a -> a
rootZ (_ , x `Cons` _) = root x
rootZ _ = error "Heap.rootZ: empty zipper"
minZ :: (a -> a -> Bool) -> Forest a -> ForestZipper a
minZ _ Nil = emptyZ
minZ f xs = minZ' f z z
where z = zipper xs
minZ' :: (a -> a -> Bool) -> ForestZipper a -> ForestZipper a -> ForestZipper a
minZ' _ lo (_, Nil) = lo
minZ' leq lo z = minZ' leq (if leq (rootZ lo) (rootZ z) then lo else z) (rightZ z)
heapify :: (a -> a -> Bool) -> Tree a -> Tree a
heapify _ n@(Node _ _ Nil) = n
heapify leq n@(Node r a as)
| leq a a' = n
| otherwise = Node r a' (rezip (left, heapify leq (Node r' a as') `Cons` right))
where
(left, Node r' a' as' `Cons` right) = minZ leq as
fromList :: Ord a => [a] -> Heap a
fromList = foldr insert mempty
fromListWith :: (a -> a -> Bool) -> [a] -> Heap a
fromListWith f = foldr (insertWith f) mempty
sort :: Ord a => [a] -> [a]
sort = toList . fromList
#if MIN_VERSION_base(4,9,0)
instance Semigroup (Heap a) where
(<>) = union
#endif
instance Monoid (Heap a) where
mempty = empty
#if !(MIN_VERSION_base(4,11,0))
mappend = union
#endif
toUnsortedList :: Heap a -> [a]
toUnsortedList Empty = []
toUnsortedList (Heap _ _ t) = foldMap return t
instance Foldable Heap where
foldMap _ Empty = mempty
foldMap f l@(Heap _ _ t) = f (root t) `mappend` foldMap f (deleteMin l)
#if __GLASGOW_HASKELL__ >= 710
null Empty = True
null _ = False
length = size
#else
null :: Heap a -> Bool
null Empty = True
null _ = False
#endif
size :: Heap a -> Int
size Empty = 0
size (Heap s _ _) = s
map :: Ord b => (a -> b) -> Heap a -> Heap b
map _ Empty = Empty
map f (Heap _ _ t) = foldMap (singleton . f) t
mapMonotonic :: Ord b => (a -> b) -> Heap a -> Heap b
mapMonotonic _ Empty = Empty
mapMonotonic f (Heap s _ t) = Heap s (<=) (fmap f t)
filter :: (a -> Bool) -> Heap a -> Heap a
filter _ Empty = Empty
filter p (Heap _ leq t) = foldMap f t
where
f x | p x = singletonWith leq x
| otherwise = Empty
partition :: (a -> Bool) -> Heap a -> (Heap a, Heap a)
partition _ Empty = (Empty, Empty)
partition p (Heap _ leq t) = foldMap f t
where
f x | p x = (singletonWith leq x, mempty)
| otherwise = (mempty, singletonWith leq x)
split :: a -> Heap a -> (Heap a, Heap a, Heap a)
split a Empty = (Empty, Empty, Empty)
split a (Heap s leq t) = foldMap f t
where
f x = if leq x a
then if leq a x
then (mempty, singletonWith leq x, mempty)
else (singletonWith leq x, mempty, mempty)
else (mempty, mempty, singletonWith leq x)
take :: Int -> Heap a -> Heap a
take = withList . L.take
drop :: Int -> Heap a -> Heap a
drop = withList . L.drop
splitAt :: Int -> Heap a -> (Heap a, Heap a)
splitAt = splitWithList . L.splitAt
break :: (a -> Bool) -> Heap a -> (Heap a, Heap a)
break = splitWithList . L.break
span :: (a -> Bool) -> Heap a -> (Heap a, Heap a)
span = splitWithList . L.span
takeWhile :: (a -> Bool) -> Heap a -> Heap a
takeWhile = withList . L.takeWhile
dropWhile :: (a -> Bool) -> Heap a -> Heap a
dropWhile = withList . L.dropWhile
nub :: Heap a -> Heap a
nub Empty = Empty
nub h@(Heap _ leq t) = insertWith leq x (nub zs)
where
x = root t
xs = deleteMin h
zs = dropWhile (`leq` x) xs
concatMap :: (a -> Heap b) -> Heap a -> Heap b
concatMap _ Empty = Empty
concatMap f h@(Heap _ _ t) = foldMap f t
group :: Heap a -> Heap (Heap a)
group Empty = Empty
group h@(Heap _ leq _) = groupBy (flip leq) h
groupBy :: (a -> a -> Bool) -> Heap a -> Heap (Heap a)
groupBy f Empty = Empty
groupBy f h@(Heap _ leq t) = insert (insertWith leq x ys) (groupBy f zs)
where
x = root t
xs = deleteMin h
(ys,zs) = span (f x) xs
intersect :: Heap a -> Heap a -> Heap a
intersect Empty _ = Empty
intersect _ Empty = Empty
intersect a@(Heap _ leq _) b = go leq (toList a) (toList b)
where
go leq' xxs@(x:xs) yys@(y:ys) =
if leq' x y
then if leq' y x
then insertWith leq' x (go leq' xs ys)
else go leq' xs yys
else go leq' xxs ys
go _ [] _ = empty
go _ _ [] = empty
intersectWith :: Ord b => (a -> a -> b) -> Heap a -> Heap a -> Heap b
intersectWith _ Empty _ = Empty
intersectWith _ _ Empty = Empty
intersectWith f a@(Heap _ leq _) b = go leq f (toList a) (toList b)
where
go :: Ord b => (a -> a -> Bool) -> (a -> a -> b) -> [a] -> [a] -> Heap b
go leq' f' xxs@(x:xs) yys@(y:ys)
| leq' x y =
if leq' y x
then insert (f' x y) (go leq' f' xs ys)
else go leq' f' xs yys
| otherwise = go leq' f' xxs ys
go _ _ [] _ = empty
go _ _ _ [] = empty
traverse :: (Applicative t, Ord b) => (a -> t b) -> Heap a -> t (Heap b)
traverse f = fmap fromList . Traversable.traverse f . toList
mapM :: (Monad m, Ord b) => (a -> m b) -> Heap a -> m (Heap b)
mapM f = liftM fromList . Traversable.mapM f . toList
both :: (a -> b) -> (a, a) -> (b, b)
both f (a,b) = (f a, f b)
data Tree a = Node
{ rank :: !Int
, root :: a
, _forest :: !(Forest a)
} deriving (Show,Read,Typeable)
data Forest a = !(Tree a) `Cons` !(Forest a) | Nil
deriving (Show,Read,Typeable)
infixr 5 `Cons`
instance Functor Tree where
fmap f (Node r a as) = Node r (f a) (fmap f as)
instance Functor Forest where
fmap f (a `Cons` as) = fmap f a `Cons` fmap f as
fmap _ Nil = Nil
instance Foldable Tree where
foldMap f (Node _ a as) = f a `mappend` foldMap f as
instance Foldable Forest where
foldMap f (a `Cons` as) = foldMap f a `mappend` foldMap f as
foldMap _ Nil = mempty
link :: (a -> a -> Bool) -> Tree a -> Tree a -> Tree a
link f t1@(Node r1 x1 cf1) t2@(Node r2 x2 cf2)
| f x1 x2 = Node (r1+1) x1 (t2 `Cons` cf1)
| otherwise = Node (r2+1) x2 (t1 `Cons` cf2)
skewLink :: (a -> a -> Bool) -> Tree a -> Tree a -> Tree a -> Tree a
skewLink f t0@(Node _ x0 cf0) t1@(Node r1 x1 cf1) t2@(Node r2 x2 cf2)
| f x1 x0 && f x1 x2 = Node (r1+1) x1 (t0 `Cons` t2 `Cons` cf1)
| f x2 x0 && f x2 x1 = Node (r2+1) x2 (t0 `Cons` t1 `Cons` cf2)
| otherwise = Node (r1+1) x0 (t1 `Cons` t2 `Cons` cf0)
ins :: (a -> a -> Bool) -> Tree a -> Forest a -> Forest a
ins _ t Nil = t `Cons` Nil
ins f t (t' `Cons` ts)
| rank t < rank t' = t `Cons` t' `Cons` ts
| otherwise = ins f (link f t t') ts
uniqify :: (a -> a -> Bool) -> Forest a -> Forest a
uniqify _ Nil = Nil
uniqify f (t `Cons` ts) = ins f t ts
unionUniq :: (a -> a -> Bool) -> Forest a -> Forest a -> Forest a
unionUniq _ Nil ts = ts
unionUniq _ ts Nil = ts
unionUniq f tts1@(t1 `Cons` ts1) tts2@(t2 `Cons` ts2) = case compare (rank t1) (rank t2) of
LT -> t1 `Cons` unionUniq f ts1 tts2
EQ -> ins f (link f t1 t2) (unionUniq f ts1 ts2)
GT -> t2 `Cons` unionUniq f tts1 ts2
skewInsert :: (a -> a -> Bool) -> Tree a -> Forest a -> Forest a
skewInsert f t ts@(t1 `Cons` t2 `Cons`rest)
| rank t1 == rank t2 = skewLink f t t1 t2 `Cons` rest
| otherwise = t `Cons` ts
skewInsert _ t ts = t `Cons` ts
skewMeld :: (a -> a -> Bool) -> Forest a -> Forest a -> Forest a
skewMeld f ts ts' = unionUniq f (uniqify f ts) (uniqify f ts')
getMin :: (a -> a -> Bool) -> Forest a -> (Tree a, Forest a)
getMin _ (t `Cons` Nil) = (t, Nil)
getMin f (t `Cons` ts)
| f (root t) (root t') = (t, ts)
| otherwise = (t', t `Cons` ts')
where (t',ts') = getMin f ts
getMin _ Nil = error "Heap.getMin: empty forest"
splitForest :: Int -> Forest a -> Forest a -> Forest a -> (Forest a, Forest a, Forest a)
splitForest a b c d | a `seq` b `seq` c `seq` d `seq` False = undefined
splitForest 0 zs ts f = (zs, ts, f)
splitForest 1 zs ts (t `Cons` Nil) = (zs, t `Cons` ts, Nil)
splitForest 1 zs ts (t1 `Cons` t2 `Cons` f)
| rank t2 == 0 = (t1 `Cons` zs, t2 `Cons` ts, f)
| otherwise = (zs, t1 `Cons` ts, t2 `Cons` f)
splitForest r zs ts (t1 `Cons` t2 `Cons` cf)
| r1 == r2 = (zs, t1 `Cons` t2 `Cons` ts, cf)
| r1 == 0 = splitForest (r1) (t1 `Cons` zs) (t2 `Cons` ts) cf
| otherwise = splitForest (r1) zs (t1 `Cons` ts) (t2 `Cons` cf)
where
r1 = rank t1
r2 = rank t2
splitForest _ _ _ _ = error "Heap.splitForest: invalid arguments"
withList :: ([a] -> [a]) -> Heap a -> Heap a
withList _ Empty = Empty
withList f hp@(Heap _ leq _) = fromListWith leq (f (toList hp))
splitWithList :: ([a] -> ([a],[a])) -> Heap a -> (Heap a, Heap a)
splitWithList _ Empty = (Empty, Empty)
splitWithList f hp@(Heap _ leq _) = both (fromListWith leq) (f (toList hp))
data Entry p a = Entry { priority :: p, payload :: a }
deriving (Read,Show,Data,Typeable)
instance Functor (Entry p) where
fmap f (Entry p a) = Entry p (f a)
#if MIN_VERSION_base(4,8,0)
instance Bifunctor Entry where
bimap f g (Entry p a) = Entry (f p) (g a)
#endif
instance Foldable (Entry p) where
foldMap f (Entry _ a) = f a
instance Traversable (Entry p) where
traverse f (Entry p a) = Entry p `fmap` f a
instance Eq p => Eq (Entry p a) where
(==) = (==) `on` priority
instance Ord p => Ord (Entry p a) where
compare = compare `on` priority