packages feed

extrapolate-0.4.0: eg/redblack.hs

-- Copyright 2016--2017, Matt Might and Lee Pike.
--
-- Adapted from a SmartCheck example:
--   https://github.com/leepike/SmartCheck/tree/master/examples/RedBlackTreesh
-- which in turn was adapted from:
--   http://matt.might.net/articles/quick-quickcheck/
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}

 -- Note from Matt Might:
 -- Note: Benjamin Pierce's lecture notes are where I learned to 
 -- generate properly ordered binary search trees:

 -- http://www.seas.upenn.edu/~cis552/12fa/lectures/stub/BST.html

import RedBlackSet 

import Test.Extrapolate


instance (Ord a, Listable a) => Listable (RBSet a) where
  tiers = cons1 fromList

-- transforms a list into an RBSet.
fromList :: Ord a => [a] -> RBSet a
fromList = foldr insert empty

 -- Count the black depth of a red-black tree:
blackDepth :: RBSet a -> Maybe Int
blackDepth (E) = Just(1)
blackDepth (T R l _ r) = case (blackDepth(l),blackDepth(r)) of
  (Just(n),Just(m)) -> if n == m then Just(n) else Nothing
  (_,_) -> Nothing
blackDepth (T B l _ r) = case (blackDepth(l),blackDepth(r)) of
  (Just(n),Just(m)) -> if n == m then Just(1+n) else Nothing
  (_,_) -> Nothing
blackDepth _ = error "unhandled pattern"

 -- Check for red-red violations:
prop_NoRedRed :: RBSet Int -> Bool
prop_NoRedRed E = True
prop_NoRedRed (T R (T R _ _ _) _ _) = False
prop_NoRedRed (T R _ _ (T R _ _ _)) = False
prop_NoRedRed (T _ l x r) = (prop_NoRedRed l) && (prop_NoRedRed r)
prop_NoRedRed _ = error "unhandled pattern"


 -- Check for black-balanced violations:
prop_BlackBalanced :: RBSet Int -> Bool
prop_BlackBalanced t =
 case blackDepth(t) of
  Just _ -> True
  Nothing -> False


 -- Check for ordering violations:
prop_OrderedList :: Ord a => [a] -> Bool
prop_OrderedList [] = True
prop_OrderedList [x] = True
prop_OrderedList (x:y:tl) = (x < y) && (prop_OrderedList(y:tl))

prop_Ordered :: RBSet Int -> Bool
prop_Ordered t = prop_OrderedList (toAscList t) 

 -- Check for the validity of a red-black tree:
prop_RBValid :: RBSet Int -> Bool
prop_RBValid t = prop_NoRedRed t && prop_BlackBalanced t && prop_Ordered t


 -- Insertion properties:
prop_Create5 :: Int -> Int -> Int -> Int -> Int -> Bool
prop_Create5 a b c d e = 
  ((foldr insert empty) [a,b,c,d,e]) == 
  ((foldr insert empty) [b,c,d,e,a])

prop_InsertValid :: RBSet Int -> Int -> Bool
prop_InsertValid t x = prop_RBValid(insert x t)

prop_InsertMember :: RBSet Int -> Int -> Bool
prop_InsertMember t x = member x (insert x t)

prop_InsertSafe :: RBSet Int -> Int -> Int -> Bool
prop_InsertSafe t x y = member x t ==> (member x (insert y t))

prop_NoInsertPhantom :: RBSet Int -> Int -> Int -> Bool
prop_NoInsertPhantom t x y = 
 not (member x t) && x /= y ==> not (member x (insert y t))

 -- Deletion properties:
prop_InsertDeleteValid :: RBSet Int -> Int -> Bool
prop_InsertDeleteValid t x = prop_RBValid(delete x (insert x t))

prop_DeleteValid :: RBSet Int -> Int -> Bool
prop_DeleteValid t x = prop_RBValid(delete x t)

prop_MemberDelete :: RBSet Int -> Int -> Bool
prop_MemberDelete t x = member x t ==> not (member x (delete x t))

prop_DeletePreserve :: RBSet Int -> Int -> Int -> Bool
prop_DeletePreserve t x y = x /= y ==> (member y t) == (member y (delete x t))

main :: IO ()
main = do
  chk prop_BlackBalanced

  -- {-
  -- Insertion tests:
  chk prop_Create5
  chk prop_InsertValid
  chk prop_InsertSafe
  chk prop_NoInsertPhantom
  chk prop_InsertMember

  -- Deletion tests:
  chk prop_InsertDeleteValid
  chk prop_DeleteValid
  chk prop_MemberDelete
  chk prop_DeletePreserve
  -- -}
  where
  chk :: Testable a => a -> IO ()
  chk = check `for` 1080

instance Listable Color where
  tiers  =  [[R, B], [BB, NB]]

instance Name (RBSet a) where
  name _ = "h"

instance (Ord a, Express a) => Express (RBSet a) where
  expr t = value "fromList" (fromList ->: t) :$ expr (toAscList t)

instance (Ord a, Generalizable a) => Generalizable (RBSet a) where
  subInstances h  =  instances (toAscList h)

-- TODO: make LeanCheck find a counter-example to prop_BlackBalanced
--       when -DBALANCE_BUG is active or find out why it cannot find it.

-- TODO: somehow make "./eg/redblack-remove-bug" run faster.
--       (currently, it takes 2 minutes to run)