module Data.IndexedPriorityQueue
(
PriorityQueue
, Value
, Index
, newPriorityQueue
, newPriorityQueueBy
, NewFifo (..)
, getElems
, clear
, clone
, Enqueue (..)
, Dequeue (..)
, QueueSize (..)
, member
, update
, getHeapArray
) where
import Control.Monad
import Data.Ix
import qualified Data.Array.Base as A
import qualified Data.Array.IO as A
import Data.IORef
import Data.Queue.Classes
type Index = Int
type Value = Int
data PriorityQueue
= PriorityQueue
{ lt :: !(Value -> Value -> IO Bool)
, heap :: !(IORef (Int, A.IOUArray Index Value))
, table :: !(IORef (A.IOUArray Value Index))
}
newPriorityQueue :: IO PriorityQueue
newPriorityQueue = newPriorityQueueBy (\a b -> return (a < b))
newPriorityQueueBy :: (Value -> Value -> IO Bool) -> IO (PriorityQueue)
newPriorityQueueBy cmp = do
h <- A.newArray_ (0,1)
ref <- newIORef (0,h)
idx <- A.newArray_ (0,1)
ref2 <- newIORef idx
return $ PriorityQueue{ lt = cmp, heap = ref, table =ref2 }
getElems :: PriorityQueue -> IO [Value]
getElems q = do
(n,arr) <- readIORef (heap q)
forM [0..n1] $ \i -> A.readArray arr i
clear :: PriorityQueue -> IO ()
clear q = do
(_,arr) <- readIORef (heap q)
writeIORef (heap q) (0,arr)
idx <- readIORef (table q)
(!lb,!ub) <- A.getBounds idx
let go i
| i > ub = return ()
| otherwise = A.unsafeWrite idx i (1) >> go (i+1)
go lb
clone :: PriorityQueue -> IO PriorityQueue
clone q = do
(n,arr) <- readIORef (heap q)
arr' <- cloneArray arr
ref <- newIORef (n,arr')
idx <- readIORef (table q)
idx' <- cloneArray idx
ref2 <- newIORef idx'
return $ PriorityQueue{ lt = lt q, heap = ref, table = ref2 }
instance Enqueue (PriorityQueue) IO Value where
enqueue q val = do
m <- member q val
unless m $ do
(n,arr) <- readIORef (heap q)
c <- liftM rangeSize $ A.getBounds arr
if (n+1 < c)
then do
A.unsafeWrite arr n val
writeIORef (heap q) (n+1,arr)
else do
let c' = max 2 (c * 3 `div` 2)
arr' <- A.newArray_ (0, c'1)
copyTo arr arr' (0, n1)
A.unsafeWrite arr' n val
writeIORef (heap q) (n+1,arr')
idx <- readIORef (table q)
c2 <- liftM rangeSize $ A.getBounds idx
if val < c2
then A.unsafeWrite idx val n
else do
let c2' = max 2 (c2 * 3 `div` 2)
idx' <- A.newArray_ (0, c2'1)
copyTo idx idx' (0, c21)
forM_ [c2..c2'1] $ \i -> A.unsafeWrite idx' i (1)
A.unsafeWrite idx' val n
writeIORef (table q) idx'
up q n
instance Dequeue (PriorityQueue) IO Value where
dequeue q = do
(n,arr) <- readIORef (heap q)
idx <- readIORef (table q)
case n of
0 -> do
return Nothing
_ -> do
val <- A.readArray arr 0
A.unsafeWrite idx val (1)
writeIORef (heap q) (n1, arr)
when (n > 1) $ do
val1 <- A.readArray arr (n1)
A.unsafeWrite arr 0 val1
A.unsafeWrite idx val1 0
down q 0
return (Just val)
dequeueBatch q = go []
where
go xs = do
r <- dequeue q
case r of
Nothing -> return (reverse xs)
Just x -> go (x:xs)
instance QueueSize (PriorityQueue) IO where
queueSize q = do
(n,_) <- readIORef (heap q)
return n
member :: PriorityQueue -> Value -> IO Bool
member q v = do
idx <- readIORef (table q)
r <- A.getBounds idx
if not (inRange r v) then
return False
else do
i <- A.unsafeRead idx v
return $! i /= 1
update :: PriorityQueue -> Value -> IO ()
update q v = do
idx <- readIORef (table q)
i <- A.readArray idx v
unless (i == 1) $ do
up q i
down q i
up :: PriorityQueue -> Index -> IO ()
up q !i = do
(_,arr) <- readIORef (heap q)
idx <- readIORef (table q)
val <- A.readArray arr i
let loop 0 = return 0
loop j = do
let p = parent j
val_p <- A.readArray arr p
b <- lt q val val_p
if b
then do
A.unsafeWrite arr j val_p
A.unsafeWrite idx val_p j
loop p
else return j
j <- loop i
A.unsafeWrite arr j val
A.unsafeWrite idx val j
down :: PriorityQueue -> Index -> IO ()
down q !i = do
(!n,arr) <- readIORef (heap q)
idx <- readIORef (table q)
val <- A.readArray arr i
let loop !j = do
let !l = left j
!r = right j
if l >= n
then return j
else do
child <- do
if r >= n
then return l
else do
val_l <- A.readArray arr l
val_r <- A.readArray arr r
b <- lt q val_r val_l
if b
then return r
else return l
val_child <- A.readArray arr child
b <- lt q val_child val
if not b
then return j
else do
A.unsafeWrite arr j val_child
A.unsafeWrite idx val_child j
loop child
j <- loop i
A.unsafeWrite arr j val
A.unsafeWrite idx val j
getHeapArray :: PriorityQueue -> IO (A.IOUArray Index Value)
getHeapArray q = liftM snd $ readIORef (heap q)
left :: Index -> Index
left i = i*2 + 1
right :: Index -> Index
right i = (i+1)*2;
parent :: Index -> Index
parent i = (i1) `div` 2
cloneArray :: (A.MArray a e m) => a Index e -> m (a Index e)
cloneArray arr = do
b <- A.getBounds arr
arr' <- A.newArray_ b
copyTo arr arr' b
return arr'
copyTo :: (A.MArray a e m) => a Index e -> a Index e -> (Index,Index) -> m ()
copyTo fromArr toArr b = do
forM_ (range b) $ \i -> do
val_i <- A.readArray fromArr i
A.unsafeWrite toArr i val_i