module Simulation.Aivika.Trans.PriorityQueue
(PriorityQueue,
queueNull,
queueCount,
newQueue,
enqueue,
dequeue,
queueFront) where
import Control.Monad
import Simulation.Aivika.Trans.Session
import Simulation.Aivika.Trans.ProtoRef
import Simulation.Aivika.Trans.Comp
import qualified Simulation.Aivika.Trans.ProtoArray as A
import qualified Simulation.Aivika.Trans.ProtoArray.Unboxed as UA
data PriorityQueue m a =
PriorityQueue { pqSession :: Session m,
pqKeys :: ProtoRef m (UA.ProtoArray m Double),
pqVals :: ProtoRef m (A.ProtoArray m a),
pqSize :: ProtoRef m Int,
pqCapacity :: ProtoRef m Int }
increase :: ProtoMonadComp m => PriorityQueue m a -> m ()
increase pq =
do let s = pqSession pq
keyRef = pqKeys pq
valRef = pqVals pq
capacityRef = pqCapacity pq
keys <- readProtoRef keyRef
vals <- readProtoRef valRef
len <- readProtoRef capacityRef
let capacity' | len < 64 = 2 * len
| otherwise = (len `div` 2) * 3
keys' <- UA.newProtoArray_ s capacity'
vals' <- A.newProtoArray_ s capacity'
mapM_ (\i -> do { k <- UA.readProtoArray keys i; UA.writeProtoArray keys' i k }) [0 .. len 1]
mapM_ (\i -> do { v <- A.readProtoArray vals i; A.writeProtoArray vals' i v }) [0 .. len 1]
writeProtoRef keyRef keys'
writeProtoRef valRef vals'
writeProtoRef capacityRef capacity'
siftUp :: ProtoMonadComp m
=> UA.ProtoArray m Double
-> A.ProtoArray m a
-> Int
-> Double
-> a
-> m ()
siftUp keys vals i k v =
if i == 0
then do UA.writeProtoArray keys i k
A.writeProtoArray vals i v
else do let n = (i 1) `div` 2
kn <- UA.readProtoArray keys n
if k >= kn
then do UA.writeProtoArray keys i k
A.writeProtoArray vals i v
else do vn <- A.readProtoArray vals n
UA.writeProtoArray keys i kn
A.writeProtoArray vals i vn
siftUp keys vals n k v
siftDown :: ProtoMonadComp m
=> UA.ProtoArray m Double
-> A.ProtoArray m a
-> Int
-> Int
-> Double
-> a
-> m ()
siftDown keys vals size i k v =
if i >= (size `div` 2)
then do UA.writeProtoArray keys i k
A.writeProtoArray vals i v
else do let n = 2 * i + 1
n' = n + 1
kn <- UA.readProtoArray keys n
if n' >= size
then if k <= kn
then do UA.writeProtoArray keys i k
A.writeProtoArray vals i v
else do vn <- A.readProtoArray vals n
UA.writeProtoArray keys i kn
A.writeProtoArray vals i vn
siftDown keys vals size n k v
else do kn' <- UA.readProtoArray keys n'
let n'' = if kn > kn' then n' else n
kn'' = min kn' kn
if k <= kn''
then do UA.writeProtoArray keys i k
A.writeProtoArray vals i v
else do vn'' <- A.readProtoArray vals n''
UA.writeProtoArray keys i kn''
A.writeProtoArray vals i vn''
siftDown keys vals size n'' k v
queueNull :: ProtoMonadComp m => PriorityQueue m a -> m Bool
queueNull pq =
do size <- readProtoRef (pqSize pq)
return $ size == 0
queueCount :: ProtoMonadComp m => PriorityQueue m a -> m Int
queueCount pq = readProtoRef (pqSize pq)
newQueue :: ProtoMonadComp m => Session m -> m (PriorityQueue m a)
newQueue session =
do keys <- UA.newProtoArray_ session 11
vals <- A.newProtoArray_ session 11
keyRef <- newProtoRef session keys
valRef <- newProtoRef session vals
sizeRef <- newProtoRef session 0
capacityRef <- newProtoRef session 11
return PriorityQueue { pqSession = session,
pqKeys = keyRef,
pqVals = valRef,
pqSize = sizeRef,
pqCapacity = capacityRef }
enqueue :: ProtoMonadComp m => PriorityQueue m a -> Double -> a -> m ()
enqueue pq k v =
do i <- readProtoRef (pqSize pq)
n <- readProtoRef (pqCapacity pq)
when (i >= n 1) $ increase pq
writeProtoRef (pqSize pq) (i + 1)
keys <- readProtoRef (pqKeys pq)
vals <- readProtoRef (pqVals pq)
siftUp keys vals i k v
dequeue :: ProtoMonadComp m => PriorityQueue m a -> m ()
dequeue pq =
do size <- readProtoRef (pqSize pq)
when (size == 0) $ error "Empty priority queue: dequeue"
let i = size 1
writeProtoRef (pqSize pq) i
keys <- readProtoRef (pqKeys pq)
vals <- readProtoRef (pqVals pq)
k <- UA.readProtoArray keys i
v <- A.readProtoArray vals i
let k0 = 0.0
v0 = undefined
UA.writeProtoArray keys i k0
A.writeProtoArray vals i v0
siftDown keys vals i 0 k v
queueFront :: ProtoMonadComp m => PriorityQueue m a -> m (Double, a)
queueFront pq =
do size <- readProtoRef (pqSize pq)
when (size == 0) $ error "Empty priority queue: queueFront"
keys <- readProtoRef (pqKeys pq)
vals <- readProtoRef (pqVals pq)
k <- UA.readProtoArray keys 0
v <- A.readProtoArray vals 0
return (k, v)