{-# LANGUAGE CPP #-}
#ifdef __GLASGOW_HASKELL__
{-# LANGUAGE TypeFamilies #-}
#endif
module Data.PrioHeap
( PrioHeap
, empty, singleton
, fromHeap
, fromList
, insert
, union, unions
, map, mapWithKey
, traverseWithKey
, filter, filterWithKey
, partition, partitionWithKey
, mapMaybe, mapMaybeWithKey
, mapEither, mapEitherWithKey
, foldMapWithKey
, foldlWithKey, foldrWithKey
, foldlWithKey', foldrWithKey'
, foldMapOrd
, foldlOrd, foldrOrd
, foldlOrd', foldrOrd'
, foldMapWithKeyOrd
, foldlWithKeyOrd, foldrWithKeyOrd
, foldlWithKeyOrd', foldrWithKeyOrd'
, size
, member, notMember
, adjustMin, adjustMinWithKey
, lookupMin
, findMin
, deleteMin
, deleteFindMin
, updateMin, updateMinWithKey
, minView
, take
, drop
, splitAt
, takeWhile, takeWhileWithKey
, dropWhile, dropWhileWithKey
, span, spanWithKey
, break, breakWithKey
, nub
, keysHeap
, toList, toAscList, toDescList
) where
import Control.Exception (assert)
import Data.Foldable (foldl', foldr')
import Data.Functor.Classes
import Data.Maybe (fromMaybe)
#if !(MIN_VERSION_base(4,11,0))
import Data.Semigroup (Semigroup((<>)))
#endif
#ifdef __GLASGOW_HASKELL__
import GHC.Exts (IsList)
import qualified GHC.Exts as Exts
#endif
import Prelude hiding (break, drop, dropWhile, filter, map, reverse, span, splitAt, take, takeWhile, uncurry)
import Text.Read (Lexeme(Ident), lexP, parens, prec, readPrec)
import qualified Data.Heap.Internal as Heap
import Util.Internal.StrictList
data PrioHeap k a
= Empty
| Heap
{-# UNPACK #-} !Int
!k
a
!(Forest k a)
type Forest k a = List (Tree k a)
data Pair k a = Pair !k a
data Tree k a = Node
{ _rank :: {-# UNPACK #-} !Int
, _root :: !k
, _value :: a
, _elements :: !(List (Pair k a))
, _children :: !(Forest k a)
}
errorEmpty :: String -> a
errorEmpty s = error $ "PrioHeap." ++ s ++ ": empty heap"
uncurry :: (a -> b -> c) -> Pair a b -> c
uncurry f (Pair x y) = f x y
{-# INLINE uncurry #-}
link :: Ord k => Tree k a -> Tree k a -> Tree k a
link t1@(Node r1 key1 x1 xs1 c1) t2@(Node r2 key2 x2 xs2 c2) = assert (r1 == r2) $
if key1 <= key2
then Node (r1 + 1) key1 x1 xs1 (t2 `Cons` c1)
else Node (r2 + 1) key2 x2 xs2 (t1 `Cons` c2)
skewLink :: Ord k => k -> a -> Tree k a -> Tree k a -> Tree k a
skewLink kx x t1 t2 = let Node r ky y ys c = link t1 t2
in if kx <= ky
then Node r kx x (Pair ky y `Cons` ys) c
else Node r ky y (Pair kx x `Cons` ys) c
insTree :: Ord k => Tree k a -> Forest k a -> Forest k a
insTree t Nil = t `Cons` Nil
insTree t1 f@(t2 `Cons` ts)
| _rank t1 < _rank t2 = t1 `Cons` f
| otherwise = insTree (link t1 t2) ts
mergeTrees :: Ord k => Forest k a -> Forest k a -> Forest k a
mergeTrees f Nil = f
mergeTrees Nil f = f
mergeTrees f1@(t1 `Cons` ts1) f2@(t2 `Cons` ts2) = case _rank t1 `compare` _rank t2 of
LT -> t1 `Cons` mergeTrees ts1 f2
GT -> t2 `Cons` mergeTrees f1 ts2
EQ -> insTree (link t1 t2) (mergeTrees ts1 ts2)
merge :: Ord k => Forest k a -> Forest k a -> Forest k a
merge f1 f2 = mergeTrees (normalize f1) (normalize f2)
{-# INLINE merge #-}
normalize :: Ord k => Forest k a -> Forest k a
normalize Nil = Nil
normalize (t `Cons` ts) = insTree t ts
{-# INLiNE normalize #-}
ins :: Ord k => k -> a -> Forest k a -> Forest k a
ins key x (t1 `Cons` t2 `Cons` ts)
| _rank t1 == _rank t2 = key `seq` skewLink key x t1 t2 `Cons` ts
ins key x ts = key `seq` Node 0 key x Nil Nil `Cons` ts
fromForest :: Ord k => Int -> Forest k a -> PrioHeap k a
fromForest _ Nil = Empty
fromForest s f@(_ `Cons` _) =
let (Node _ key x xs ts1, ts2) = removeMinTree f
in Heap s key x (foldl' (\acc (Pair key x) -> ins key x acc) (merge (reverse ts1) ts2) xs)
removeMinTree :: Ord k => Forest k a -> (Tree k a, Forest k a)
removeMinTree Nil = error "removeMinTree: empty heap"
removeMinTree (t `Cons` Nil) = (t, Nil)
removeMinTree (t `Cons` ts) =
let (t', ts') = removeMinTree ts
in if _root t <= _root t'
then (t, ts)
else (t', t `Cons` ts')
instance Show2 PrioHeap where
liftShowsPrec2 spk slk spv slv p heap = showsUnaryWith (liftShowsPrec sp sl) "fromList" p (toList heap)
where
sp = liftShowsPrec2 spk slk spv slv
sl = liftShowList2 spk slk spv slv
instance Show k => Show1 (PrioHeap k) where
liftShowsPrec = liftShowsPrec2 showsPrec showList
{-# INLINE liftShowsPrec #-}
instance (Show k, Show a) => Show (PrioHeap k a) where
showsPrec = showsPrec2
{-# INLINE showsPrec #-}
instance (Ord k, Read k) => Read1 (PrioHeap k) where
liftReadsPrec rp rl = readsData $ readsUnaryWith (liftReadsPrec rp' rl') "fromList" fromList
where
rp' = liftReadsPrec rp rl
rl' = liftReadList rp rl
instance (Ord k, Read k, Read a) => Read (PrioHeap k a) where
#ifdef __GLASGOW_HASKELL__
readPrec = parens $ prec 10 $ do
Ident "fromList" <- lexP
xs <- readPrec
pure (fromList xs)
#else
readsPrec = readsPrec1
{-# INLINE readPrec #-}
#endif
instance Ord k => Eq1 (PrioHeap k) where
liftEq f heap1 heap2 = size heap1 == size heap2 && liftEq (liftEq f) (toAscList heap1) (toAscList heap2)
instance (Ord k, Eq a) => Eq (PrioHeap k a) where
(==) = eq1
{-# INLINE (==) #-}
instance Ord k => Ord1 (PrioHeap k) where
liftCompare f heap1 heap2 = liftCompare (liftCompare f) (toAscList heap1) (toAscList heap2)
instance (Ord k, Ord a) => Ord (PrioHeap k a) where
compare = compare1
{-# INLINE compare #-}
instance Ord k => Semigroup (PrioHeap k a) where
(<>) = union
{-# INLINE (<>) #-}
instance Ord k => Monoid (PrioHeap k a) where
mempty = empty
{-# INLINE mempty #-}
mappend = (<>)
{-# INLINE mappend #-}
instance Functor (PrioHeap k) where
fmap = map
{-# INLINE fmap #-}
instance Foldable (PrioHeap k) where
foldMap f = foldMapWithKey (const f)
{-# INLINE foldMap #-}
foldr f = foldrWithKey (const f)
{-# INLINE foldr #-}
foldl f = foldlWithKey (const . f)
{-# INLINE foldl #-}
foldr' f = foldrWithKey' (const f)
{-# INLINE foldr' #-}
foldl' f = foldlWithKey' (const . f)
{-# INLINE foldl' #-}
null Empty = True
null Heap{} = False
{-# INLINE null #-}
length = size
{-# INLINE length #-}
instance Traversable (PrioHeap k) where
traverse f = traverseWithKey (const f)
{-# INLINE traverse #-}
#ifdef __GLASGOW_HASKELL__
instance Ord k => IsList (PrioHeap k a) where
type Item (PrioHeap k a) = (k, a)
fromList = fromList
{-# INLINE fromList #-}
toList = toList
{-# INLINE toList #-}
#endif
empty :: PrioHeap k a
empty = Empty
{-# INLINE empty #-}
singleton :: k -> a -> PrioHeap k a
singleton k x = Heap 1 k x Nil
{-# INLINE singleton #-}
fromList :: Ord k => [(k, a)] -> PrioHeap k a
fromList = foldl' (\acc (key, x) -> insert key x acc) empty
{-# INLINE fromList #-}
insert :: Ord k => k -> a -> PrioHeap k a -> PrioHeap k a
insert key x Empty = singleton key x
insert kx x (Heap s ky y f)
| kx <= ky = Heap (s + 1) kx x (ins ky y f)
| otherwise = Heap (s + 1) ky y (ins kx x f)
union :: Ord k => PrioHeap k a -> PrioHeap k a -> PrioHeap k a
union heap Empty = heap
union Empty heap = heap
union (Heap s1 key1 x1 f1) (Heap s2 key2 x2 f2)
| key1 <= key2 = Heap (s1 + s2) key1 x1 (ins key2 x2 (merge f1 f2))
| otherwise = Heap (s1 + s2) key2 x2 (ins key1 x1 (merge f1 f2))
unions :: (Foldable f, Ord k) => f (PrioHeap k a) -> PrioHeap k a
unions = foldl' union empty
{-# INLINE unions #-}
map :: (a -> b) -> PrioHeap k a -> PrioHeap k b
map f = mapWithKey (const f)
{-# INLINE map #-}
mapWithKey :: (k -> a -> b) -> PrioHeap k a -> PrioHeap k b
mapWithKey _ Empty = Empty
mapWithKey f (Heap s key x forest) = Heap s key (f key x) (fmap mapTree forest)
where
mapTree (Node r key x xs c) = Node r key (f key x) (fmap mapPair xs) (fmap mapTree c)
mapPair (Pair key x) = Pair key (f key x)
{-# INLINE mapWithKey #-}
traverseWithKey :: Applicative f => (k -> a -> f b) -> PrioHeap k a -> f (PrioHeap k b)
traverseWithKey _ Empty = pure Empty
traverseWithKey f (Heap s key x forest) = Heap s key <$> f key x <*> traverse traverseTree forest
where
traverseTree (Node r key x xs c) = Node r key <$> f key x <*> traverse traversePair xs <*> traverse traverseTree c
traversePair (Pair key x) = Pair key <$> f key x
{-# INLINE traverseWithKey #-}
filter :: Ord k => (a -> Bool) -> PrioHeap k a -> PrioHeap k a
filter f = filterWithKey (const f)
{-# INLINE filter #-}
filterWithKey :: Ord k => (k -> a -> Bool) -> PrioHeap k a -> PrioHeap k a
filterWithKey f = foldrWithKey f' empty
where
f' key x heap
| f key x = insert key x heap
| otherwise = heap
{-# INLINE filterWithKey #-}
partition :: Ord k => (a -> Bool) -> PrioHeap k a -> (PrioHeap k a, PrioHeap k a)
partition f = partitionWithKey (const f)
{-# INLINE partition #-}
partitionWithKey :: Ord k => (k -> a -> Bool) -> PrioHeap k a -> (PrioHeap k a, PrioHeap k a)
partitionWithKey f = foldrWithKey f' (empty, empty)
where
f' key x (heap1, heap2)
| f key x = (insert key x heap1, heap2)
| otherwise = (heap1, insert key x heap2)
{-# INLINE partitionWithKey #-}
mapMaybe :: Ord k => (a -> Maybe b) -> PrioHeap k a -> PrioHeap k b
mapMaybe f = mapMaybeWithKey (const f)
{-# INLINE mapMaybe #-}
mapMaybeWithKey :: Ord k => (k -> a -> Maybe b) -> PrioHeap k a -> PrioHeap k b
mapMaybeWithKey f = foldrWithKey f' empty
where
f' key x heap = case f key x of
Just y -> insert key y heap
Nothing -> heap
{-# INLINE mapMaybeWithKey #-}
mapEither :: Ord k => (a -> Either b c) -> PrioHeap k a -> (PrioHeap k b, PrioHeap k c)
mapEither f = mapEitherWithKey (const f)
{-# INLINE mapEither #-}
mapEitherWithKey :: Ord k => (k -> a -> Either b c) -> PrioHeap k a -> (PrioHeap k b, PrioHeap k c)
mapEitherWithKey f = foldrWithKey f' (empty, empty)
where
f' key x (heap1, heap2) = case f key x of
Left y -> (insert key y heap1, heap2)
Right y -> (heap1, insert key y heap2)
{-# INLINE mapEitherWithKey #-}
foldMapWithKey :: Monoid m => (k -> a -> m) -> PrioHeap k a -> m
foldMapWithKey f = foldrWithKey (\key x acc -> f key x `mappend` acc) mempty
{-# INLINE foldMapWithKey #-}
foldrWithKey :: (k -> a -> b -> b) -> b -> PrioHeap k a -> b
foldrWithKey _ acc Empty = acc
foldrWithKey f acc (Heap _ key x forest) = f key x (foldr foldTree acc forest)
where
foldTree (Node _ key x xs c) acc = f key x (foldr (uncurry f) (foldr foldTree acc c) xs)
foldlWithKey :: (b -> k -> a -> b) -> b -> PrioHeap k a -> b
foldlWithKey _ acc Empty = acc
foldlWithKey f acc (Heap _ key x forest) = foldl foldTree (f acc key x) forest
where
foldTree acc (Node _ key x xs c) = foldl foldTree (foldl (uncurry . f) (f acc key x) xs) c
foldrWithKey' :: (k -> a -> b -> b) -> b -> PrioHeap k a -> b
foldrWithKey' f acc h = foldlWithKey f' id h acc
where
f' k key x z = k $! f key x z
{-# INLINE foldrWithKey' #-}
foldlWithKey' :: (b -> k -> a -> b) -> b -> PrioHeap k a -> b
foldlWithKey' f acc h = foldrWithKey f' id h acc
where
f' key x k z = k $! f z key x
{-# INLINE foldlWithKey' #-}
foldMapOrd :: (Ord k, Monoid m) => (a -> m) -> PrioHeap k a -> m
foldMapOrd f = foldMapWithKeyOrd (const f)
{-# INLINE foldMapOrd #-}
foldrOrd :: Ord k => (a -> b -> b) -> b -> PrioHeap k a -> b
foldrOrd f = foldrWithKeyOrd (const f)
{-# INLINE foldrOrd #-}
foldlOrd :: Ord k => (b -> a -> b) -> b -> PrioHeap k a -> b
foldlOrd f = foldlWithKeyOrd (const . f)
{-# INLINE foldlOrd #-}
foldrOrd' :: Ord k => (a -> b -> b) -> b -> PrioHeap k a -> b
foldrOrd' f = foldrWithKeyOrd' (const f)
{-# INLINE foldrOrd' #-}
foldlOrd' :: Ord k => (b -> a -> b) -> b -> PrioHeap k a -> b
foldlOrd' f = foldlWithKeyOrd' (const . f)
{-# INLINE foldlOrd' #-}
foldMapWithKeyOrd :: (Ord k, Monoid m) => (k -> a -> m) -> PrioHeap k a -> m
foldMapWithKeyOrd f = foldrWithKeyOrd (\key x acc -> f key x `mappend` acc) mempty
{-# INLINE foldMapWithKeyOrd #-}
foldrWithKeyOrd :: Ord k => (k -> a -> b -> b) -> b -> PrioHeap k a -> b
foldrWithKeyOrd f acc = go
where
go h = case minView h of
Nothing -> acc
Just ((key, x), h') -> f key x (go h')
{-# INLINE foldrWithKeyOrd #-}
foldlWithKeyOrd :: Ord k => (b -> k -> a -> b) -> b -> PrioHeap k a -> b
foldlWithKeyOrd f = go
where
go acc h = case minView h of
Nothing -> acc
Just ((key, x), h') -> go (f acc key x) h'
{-# INLINE foldlWithKeyOrd #-}
foldrWithKeyOrd' :: Ord k => (k -> a -> b -> b) -> b -> PrioHeap k a -> b
foldrWithKeyOrd' f acc h = foldlWithKeyOrd f' id h acc
where
f' k key x z = k $! f key x z
{-# INLINE foldrWithKeyOrd' #-}
foldlWithKeyOrd' :: Ord k => (b -> k -> a -> b) -> b -> PrioHeap k a -> b
foldlWithKeyOrd' f acc h = foldrWithKeyOrd f' id h acc
where
f' key x k z = k $! f z key x
{-# INLINE foldlWithKeyOrd' #-}
size :: PrioHeap k a -> Int
size Empty = 0
size (Heap s _ _ _) = s
{-# INLINE size #-}
member :: Ord k => k -> PrioHeap k a -> Bool
member _ Empty = False
member kx (Heap _ ky _ forest) = kx <= ky && any (kx `elemTree`) forest
where
kx `elemTree` (Node _ ky _ ys c) = kx <= ky && (any (\(Pair a _) -> kx == a) ys || any (kx `elemTree`) c)
notMember :: Ord k => k -> PrioHeap k a -> Bool
notMember key = not . member key
adjustMin :: (a -> a) -> PrioHeap k a -> PrioHeap k a
adjustMin f = adjustMinWithKey (const f)
{-# INLINE adjustMin #-}
adjustMinWithKey :: (k -> a -> a) -> PrioHeap k a -> PrioHeap k a
adjustMinWithKey _ Empty = Empty
adjustMinWithKey f (Heap s key x forest) = Heap s key (f key x) forest
lookupMin :: PrioHeap k a -> Maybe (k, a)
lookupMin Empty = Nothing
lookupMin (Heap _ key x _) = Just (key, x)
{-# INLINE lookupMin #-}
findMin :: PrioHeap k a -> (k, a)
findMin heap = fromMaybe (errorEmpty "findMin") (lookupMin heap)
{-# INLINE findMin #-}
deleteMin :: Ord k => PrioHeap k a -> PrioHeap k a
deleteMin Empty = Empty
deleteMin (Heap s _ _ f) = fromForest (s - 1) f
deleteFindMin :: Ord k => PrioHeap k a -> ((k, a), PrioHeap k a)
deleteFindMin heap = fromMaybe (errorEmpty "deleteFindMin") (minView heap)
{-# INLINE deleteFindMin #-}
updateMin :: Ord k => (a -> Maybe a) -> PrioHeap k a -> PrioHeap k a
updateMin f = updateMinWithKey (const f)
{-# INLINE updateMin #-}
updateMinWithKey :: Ord k => (k -> a -> Maybe a) -> PrioHeap k a -> PrioHeap k a
updateMinWithKey _ Empty = Empty
updateMinWithKey f (Heap s key x forest) = case f key x of
Nothing -> fromForest (s - 1) forest
Just x' -> Heap s key x' forest
minView :: Ord k => PrioHeap k a -> Maybe ((k, a), PrioHeap k a)
minView Empty = Nothing
minView (Heap s key x f) = Just ((key, x), fromForest (s - 1) f)
{-# INLINE minView #-}
take :: Ord k => Int -> PrioHeap k a -> [(k, a)]
take n h
| n <= 0 = []
| otherwise = case minView h of
Nothing -> []
Just (x, h') -> x : take (n - 1) h'
drop :: Ord k => Int -> PrioHeap k a -> PrioHeap k a
drop n h
| n <= 0 = h
| otherwise = drop (n - 1) (deleteMin h)
splitAt :: Ord k => Int -> PrioHeap k a -> ([(k, a)], PrioHeap k a)
splitAt n h
| n <= 0 = ([], h)
| otherwise = case minView h of
Nothing -> ([], h)
Just (x, h') -> let (xs, h'') = splitAt (n - 1) h' in (x : xs, h'')
takeWhile :: Ord k => (a -> Bool) -> PrioHeap k a -> [(k, a)]
takeWhile p = takeWhileWithKey (const p)
{-# INLINE takeWhile #-}
takeWhileWithKey :: Ord k => (k -> a -> Bool) -> PrioHeap k a -> [(k, a)]
takeWhileWithKey p = go
where
go h = case minView h of
Nothing -> []
Just ((key, x), h') -> if p key x then (key, x) : go h' else []
{-# INLINE takeWhileWithKey #-}
dropWhile :: Ord k => (a -> Bool) -> PrioHeap k a -> PrioHeap k a
dropWhile p = dropWhileWithKey (const p)
{-# INLINE dropWhile #-}
dropWhileWithKey :: Ord k => (k -> a -> Bool) -> PrioHeap k a -> PrioHeap k a
dropWhileWithKey p = go
where
go h = case minView h of
Nothing -> h
Just ((key, x), h') -> if p key x then go h' else h
{-# INLINE dropWhileWithKey #-}
span :: Ord k => (a -> Bool) -> PrioHeap k a -> ([(k, a)], PrioHeap k a)
span p = spanWithKey (const p)
{-# INLINE span #-}
spanWithKey :: Ord k => (k -> a -> Bool) -> PrioHeap k a -> ([(k, a)], PrioHeap k a)
spanWithKey p = go
where
go h = case minView h of
Nothing -> ([], h)
Just ((key, x), h') -> if p key x
then let (xs, h'') = go h' in ((key, x) : xs, h'')
else ([], h)
{-# INLINE spanWithKey #-}
break :: Ord k => (a -> Bool) -> PrioHeap k a -> ([(k, a)], PrioHeap k a)
break p = span (not . p)
{-# INLINE break #-}
breakWithKey :: Ord k => (k -> a -> Bool) -> PrioHeap k a -> ([(k, a)], PrioHeap k a)
breakWithKey p = spanWithKey (\key x -> not (p key x))
{-# INLINE breakWithKey #-}
nub :: Ord k => PrioHeap k a -> PrioHeap k a
nub h = case minView h of
Nothing -> Empty
Just ((key, x), h') -> insert key x (nub (dropWhileWithKey (const . (== key)) h'))
toList :: PrioHeap k a -> [(k, a)]
toList = foldrWithKey (\key x acc -> (key, x) : acc) []
toAscList :: Ord k => PrioHeap k a -> [(k, a)]
toAscList = foldrWithKeyOrd (\key x acc -> (key, x) : acc) []
toDescList :: Ord k => PrioHeap k a -> [(k, a)]
toDescList = foldlWithKeyOrd (\acc key x -> (key, x) : acc) []
fromHeap :: (k -> a) -> Heap.Heap k -> PrioHeap k a
fromHeap _ Heap.Empty = Empty
fromHeap f (Heap.Heap s key forest) = Heap s key (f key) (fmap fromTree forest)
where
fromTree (Heap.Node r key xs c) = Node r key (f key) (fmap (\key -> Pair key (f key)) xs) (fmap fromTree c)
keysHeap :: PrioHeap k a -> Heap.Heap k
keysHeap Empty = Heap.Empty
keysHeap (Heap s key _ forest) = Heap.Heap s key (fmap fromTree forest)
where
fromTree (Node r key _ xs c) = Heap.Node r key (fmap (\(Pair key _) -> key) xs) (fmap fromTree c)