packages feed

vpq-0.1.0.0: Data/PriorityQueue.hs

module Data.PriorityQueue (PQ, singleton, insert, minView, minViewWithKey, minAlterWithKeyF,
                           toOrdList, foldMapWithKey,
                           foldrWithKey, foldlWithKey, foldrWithKeyM, foldlWithKeyM) where

import Control.Applicative
import Control.Monad
import Control.Monad.Primitive
import Data.Bits
import Data.Bool
import Data.Filtrable
import Data.Function (on)
import Data.Functor.Classes
import Data.Tuple (swap)
import Data.Vector.Generic ((!?), Vector)
import qualified Data.Vector.Generic as V
import Data.Vector.Generic.Mutable (MVector)
import qualified Data.Vector.Generic.Mutable as MV
import Util.Vector as V
import Util.Vector.Mutable as MV
import Util

newtype PQ v k a = PQ (v (k, a))

foldMapWithKey :: (Ord k, Vector v (k, a)) => Monoid b => (k -> a -> b) -> PQ v k a -> b
foldMapWithKey f = foldrWithKey ((<>) ∘∘ f) mempty

foldrWithKey :: (Ord k, Vector v (k, a)) => (k -> a -> b -> b) -> b -> PQ v k a -> b
foldrWithKey f z = minViewWithKey & \ case Nothing -> z
                                           Just (k, a, pq) -> f k a $ foldrWithKey f z pq

foldlWithKey :: (Ord k, Vector v (k, a)) => (k -> b -> a -> b) -> b -> PQ v k a -> b
foldlWithKey f z xs = foldrWithKey (\ k a c x -> c (f k x a)) id xs z

foldrWithKeyM :: (Ord k, Vector v (k, a)) => Monad m => (k -> a -> b -> m b) -> b -> PQ v k a -> m b
foldrWithKeyM f z xs = foldlWithKey f' pure xs z where f' k c x z = f k x z >>= c

foldlWithKeyM :: (Ord k, Vector v (k, a)) => Monad m => (k -> b -> a -> m b) -> b -> PQ v k a -> m b
foldlWithKeyM f z xs = foldrWithKey f' pure xs z where f' k x c z = f k z x >>= c

toOrdList :: (Ord k, Vector v (k, a)) => PQ v k a -> [(k, a)]
toOrdList = foldrWithKey (curry (:)) []

singleton :: Vector v (k, a) => k -> a -> PQ v k a
singleton = curry $ PQ . V.singleton

insert :: (Ord k, Vector v (k, a)) => k -> a -> PQ v k a -> PQ v k a
insert k a (PQ xs) = PQ $ V.modify go xs
  where go xs = do
            let l = MV.length xs
            xs <- MV.unsafeGrow xs 1
            MV.unsafeWrite xs l (k, a)
            siftUpBy (compare `on` fst) xs l

minAlterWithKeyF :: (Ord k, Vector v (k, a), Functor f)
                 => (Maybe (k, a) -> f (Maybe (k, a))) -> PQ v k a -> f (PQ v k a)
minAlterWithKeyF f (PQ xs) = PQ . bool (uncurry id . \ a -> V.modify' (go a) xs) (maybe xs V.singleton) (V.null xs) <$> f (xs !? 0)
  where go Nothing xs = do
            MV.unsafeSwap xs 0 (MV.length xs - 1)
            V.init <$ siftDownBy (compare `on` fst) (MV.init xs)
        go (Just (k, a)) xs = do
            MV.unsafeWrite xs 0 (k, a)
            id     <$ siftDownBy (compare `on` fst) xs

minView :: (Ord k, Vector v (k, a)) => PQ v k a -> Maybe (a, PQ v k a)
minView = minViewWithKey & fmap (\ (_, a, pq) -> (a, pq))

minViewWithKey :: (Ord k, Vector v (k, a)) => PQ v k a -> Maybe (k, a, PQ v k a)
minViewWithKey = minAlterWithKeyF (join (,)) & swap & sequenceA & fmap (\ (pq, (k, a)) -> (k, a, pq))

siftUpBy :: (MVector v a, PrimMonad m) => (a -> a -> Ordering) -> v (PrimState m) a -> Int -> m ()
siftUpBy cmp xs = go
  where go 0 = pure ()
        go n = do
            let m = n `shiftR` 1
            i <- MV.unsafeRead xs m
            j <- MV.unsafeRead xs n
            when (GT == cmp i j) $ MV.unsafeSwap xs m n >> go m

siftDownBy :: (MVector v a, PrimMonad m) => (a -> a -> Ordering) -> v (PrimState m) a -> m ()
siftDownBy cmp xs = go 0
  where go m = (liftA2 (minBy cmp') `on` \ n ->
                fmap ((,) n) <$> MV.readMaybe xs n) (m + m) (m + m + 1) >>= \ case
            Nothing -> pure ()
            Just (n, j) -> do
                i <- MV.unsafeRead xs m
                when (GT == cmp i j) $ MV.unsafeSwap xs m n >> go n
        cmp' = flip $ liftCompare (flip cmp `on` snd)

minBy :: (a -> a -> Ordering) -> a -> a -> a
minBy cmp x y | GT <- cmp x y = y | otherwise = x