packages feed

creditmonad-1.0.0: src/Test/Credit/Heap/Binomial.hs

{-# LANGUAGE TypeFamilies #-}

module Test.Credit.Heap.Binomial where

import Prettyprinter (Pretty)
import Control.Monad.Credit
import Test.Credit
import Test.Credit.Heap.Base

data Tree a = Node Int a [Tree a]
  deriving (Eq, Ord, Show)

rank :: Tree a -> Int
rank (Node r _ _) = r

root :: Tree a -> a
root (Node _ x _) = x

rev :: MonadCredit m => [a] -> [a] -> m [a]
rev [] acc = pure acc
rev (x : xs) acc = tick >> rev xs (x : acc)

link :: Ord a => Tree a -> Tree a -> Tree a
link t1@(Node r x1 c1) t2@(Node _ x2 c2)
  | x1 <= x2 = Node (r+1) x1 (t2:c1)
  | otherwise = Node (r+1) x2 (t1:c2)

insTree :: MonadCredit m => Ord a => Tree a -> [Tree a] -> m [Tree a]
insTree t [] = pure [t]
insTree t ts@(t':ts')
  | rank t < rank t' = pure $ t:ts
  | otherwise = tick >> insTree (link t t') ts'

mrg :: MonadCredit m => Ord a => [Tree a] -> [Tree a] -> m [Tree a]
mrg ts1 [] = pure ts1
mrg [] ts2 = pure ts2
mrg ts1@(t1:ts1') ts2@(t2:ts2')
  | rank t1 < rank t2 = tick >> (t1 :) <$> mrg ts1' ts2
  | rank t2 < rank t1 = tick >> (t2 :) <$> mrg ts1 ts2'
  | otherwise = tick >> do
    insTree (link t1 t2) =<< mrg ts1' ts2'

removeMinTree :: MonadCredit m => Ord a => [Tree a] -> m (Tree a, [Tree a])
removeMinTree [] = error "removeMinTree"
removeMinTree [t] = pure (t, [])
removeMinTree (t:ts) = tick >> do
  (t', ts') <- removeMinTree ts
  pure $ if root t <= root t' then (t, ts) else (t', t:ts')

data Binomial a m = Binomial Size (Thunk m (Lazy m) [Tree a])

allZeros :: Size -> Credit
allZeros 0 = 0
allZeros n = (fromIntegral $ (n + 1) `mod` 2) + allZeros (n `div` 2)

instance Heap Binomial where
  empty = do
    t <- delay $ Lazy $ pure []
    pure $ Binomial 0 t
  insert x (Binomial n h) = do
    ts <- delay $ Lazy $ do 
      creditWith h (allZeros n)
      h' <- force h
      insTree (Node 0 x []) h'
    creditWith ts 2
    pure $ Binomial (n + 1) ts
  merge (Binomial n1 t1) (Binomial n2 t2) = do
    t1 `creditWith` (allZeros n1)
    ts1 <- force t1
    t2 `creditWith` (allZeros n2)
    ts2 <- force t2
    ts <- delay $ Lazy $ mrg ts1 ts2
    ts `creditWith` (log2 (n1 + n2))
    pure $ Binomial (n1 + n2) ts
  splitMin (Binomial n t) = do
    creditWith t (log2 n)
    ts <- force t
    case ts of
      [] -> pure Nothing
      _ -> do
        (Node _ x ts1, ts2) <- removeMinTree ts
        t' <- delay $ Lazy $ do
          rts1 <- rev ts1 []
          mrg rts1 ts2
        creditWith t' (2 * log2 n)
        pure $ Just (x, Binomial (max 0 (n - 1)) t')

instance BoundedHeap Binomial where
  hcost _ (Insert _) = 2
  hcost n Merge = 3 * log2 n
  hcost n SplitMin = 4 * log2 n

instance MemoryCell m a => MemoryCell m (Tree a) where
  prettyCell (Node r x c) = do
    r' <- prettyCell r
    x' <- prettyCell x
    c' <- mapM prettyCell c
    pure $ mkMCell "Node" [r', x', mkMList c' Nothing]

instance (MonadMemory m, MemoryCell m a) => MemoryCell m (Binomial a m) where
  prettyCell (Binomial _ t) = do
    t' <- prettyCell t
    pure $ mkMCell "Binomial" [t']

instance Pretty a => MemoryStructure (Binomial (PrettyCell a)) where
  prettyStructure = prettyCell