packages feed

fitspec-0.4.4: bench/heaps.hs

{-# Language DeriveDataTypeable, NoMonomorphismRestriction #-}
import Test.FitSpec
import Prelude hiding (null)
import qualified Data.List as L
import Data.Maybe (listToMaybe)
import Heap
import Control.Monad (unless)

instance (Ord a, Listable a) => Listable (Heap a) where
  tiers = bagCons fromList

-- a good property to assure that the above does not leave out elements is:
--
-- \xs ys =  xs `permutation` ys  <==>  fromList xs == fromList ys
--                                          `asTypeOf` (undefined :: Heap a)

instance (Ord a, Listable a) => Mutable (Heap a) where
  mutiers = mutiersEq 

instance (Ord a, Show a, Listable a) => ShowMutable (Heap a) where
  mutantS = mutantSEq

-- Alias for type (they are repeated a lot)
type Insert a    = a -> Heap a -> Heap a
type DeleteMin a = Heap a -> Heap a
type Merge a     = Heap a -> Heap a -> Heap a
type Ty a        = (Insert a, DeleteMin a, Merge a)

properties :: (Ord a, Show a, Listable a)
           => Insert a
           -> DeleteMin a
           -> Merge a
           -> [Property]
properties insert' deleteMin' merge' =
  [ property $ \x y h ->      insert' x (insert' y h) == insert' y (insert' x h) --  1
  , property $ \h x ->             null (insert' x h) == False                   --  2
  , property $ \x h ->          L.insert x (toList h) == toList (insert' x h)    --  3

  , property $ \h h1 ->                   merge' h h1 == merge' h1 h             --  4
  , property $ \h ->                     merge' h Nil == h                       --  5
  , property $ \h h1 h2 ->    merge' h (merge' h1 h2) == merge' h1 (merge' h h2) --  6
  , property $ \h -> not (null h) ==> findMin (merge' h h) == findMin h          --  7
  , property $ \h ->                null (merge' h h) == null h                  --  8
  , property $ \h h1 ->           (null h && null h1) == null (merge' h h1)      --  9

  , property $ \h h1 x ->     merge' h (insert' x h1) == insert' x (merge' h h1) -- 10
  , property $ \h -> not (null h) ==> merge' h (deleteMin' h) == deleteMin' (merge' h h) -- 11
  , property $ \x ->       deleteMin' (insert' x Nil) == Nil                     -- 12
  ]

sargs = args
  { timeout  = 0
  , nMutants = 500
  , nTests   = 500
  , names    = ["insert x h","deleteMin h","merge h h'"]
--, extraMutants = take 0 [(uncurry maxInsert,maxDeleteMin,uncurry maxMerge)] }
  }

fns :: Ord a => Ty a
fns = (insert, deleteMin, merge)

em :: (Bounded a, Ord a) => [Ty a]
em = take 3
  [ (maxInsert, maxDeleteMin, maxMerge)
  , (insert, deleteMin, crazyMerge)
  , (\i h -> Nil, deleteMin, merge)
  ]

main :: IO ()
main = do 
  as <- getArgsWith sargs
  let run f = reportWithExtra em as f (uncurry3 properties)
  case concat (extra as) of
--  "bool"  -> run (fns :: Ty Bool)
--  "bools" -> run (fns :: Ty [Bool])
    "i"     -> run (fns :: Ty Int)
    "i1"    -> run (fns :: Ty Int1)
    "i2"    -> run (fns :: Ty Int2)
    "i3"    -> run (fns :: Ty Int3)
    "w1"    -> run (fns :: Ty Word1)
    "w2"    -> run (fns :: Ty Word2)
    "w3"    -> run (fns :: Ty Word3)
    "unit"  -> run (fns :: Ty ())
    ""      -> run (fns :: Ty Word2)


maxInsert :: Ord a => a -> Heap a -> Heap a
maxInsert x h = maxMerge h (branch x Nil Nil)

maxDeleteMin :: Ord a => Heap a -> Heap a
maxDeleteMin (Branch _ _ l r) = maxMerge l r
maxDeleteMin Nil              = Nil

maxMerge :: Ord a => Heap a -> Heap a -> Heap a
maxMerge Nil h = h
maxMerge h Nil = h
maxMerge h1@(Branch _ x1 l1 r1) h2@(Branch _ x2 l2 r2)
 | x1 >= x2 = branch x1 (maxMerge l1 h2) r1
 | otherwise = maxMerge h2 h1

uncurry3 :: (a->b->c->d) -> (a,b,c) -> d
uncurry3 f (x,y,z) = f x y z

crazyMerge :: (Bounded a, Ord a) => Heap a -> Heap a -> Heap a
crazyMerge Nil Nil = Nil
crazyMerge Nil h = h
crazyMerge h Nil = h
crazyMerge h h1 = insert maxBound $ merge h h1