{-# LANGUAGE BangPatterns #-}
import Test.QuickCheck
import Data.Word
import Data.Monoid
import Data.DisjointSet (DisjointSet)
import Data.DisjointMap (DisjointMap)
import Data.Set (Set)
import Data.Foldable (toList)
import qualified Data.Foldable as F
import qualified Data.DisjointSet as DS
import qualified Data.DisjointMap as DM
import qualified GHC.OldList as L
main :: IO ()
main = do
putStrLn "\nBeginning QuickCheck Tests"
quickCheck propUnionAll
quickCheck propUnionAppend
quickCheck propSingletons
quickCheck propMapUnionAppend
propUnionAll :: [Word] -> Bool
propUnionAll xs =
let pairs = zip xs (drop 1 xs)
ds = L.foldl' (\s (a,b) -> DS.union a b s) DS.empty pairs
roots = mapM (\x -> DS.representative x ds) xs
in case roots of
Nothing -> L.length xs == 1
Just [] -> L.null xs
Just (y : ys) -> L.all (== y) ys
propUnionAppend :: [(Word,Word)] -> Bool
propUnionAppend xs =
let r1 = unionPairs xs
(xs1,xs2) = splitList xs
r2 = unionPairs xs1 <> unionPairs xs2
in r1 == r2
propMapUnionAppend :: [(Word,Word)] -> [(Word,Sum Word)] -> Bool
propMapUnionAppend xs ys =
let r1 = unionMapPairs xs <> mapFromPairs ys
(xs1,xs2) = splitList xs
(ys1,ys2) = splitList ys
r2 = unionMapPairs xs1 <> mapFromPairs ys1 <> unionMapPairs xs2 <> mapFromPairs ys2
in r1 == r2
propSingletons :: [Set Word] -> Bool
propSingletons xs = foldMap unionFoldable xs == foldMap DS.singletons xs
splitList :: [a] -> ([a],[a])
splitList xs =
let halfLen = div (L.length xs) 2
xs1 = L.drop halfLen xs
xs2 = L.take halfLen xs
in (xs1,xs2)
unionFoldable :: Ord a => Foldable t => t a -> DisjointSet a
unionFoldable xs =
let ys = toList xs
pairs = zip ys (drop 1 ys)
in case ys of
[] -> DS.empty
z : _ -> unionPairsGo pairs (DS.singleton z)
mapFromPairs :: (Ord k, Monoid v) => Foldable t => t (k,v) -> DisjointMap k v
mapFromPairs = F.foldl' (\dm (k,v) -> DM.insert k v dm) DM.empty
unionPairs :: Ord a => [(a,a)] -> DisjointSet a
unionPairs xs = unionPairsGo xs DS.empty
unionPairsGo :: Ord a => [(a,a)] -> DisjointSet a -> DisjointSet a
unionPairsGo [] !ds = ds
unionPairsGo ((a,b):xs) !ds = unionPairsGo xs (DS.union a b ds)
unionMapPairs :: (Ord k, Monoid v) => [(k,k)] -> DisjointMap k v
unionMapPairs xs = unionMapPairsGo xs DM.empty
unionMapPairsGo :: (Ord k, Monoid v) => [(k,k)] -> DisjointMap k v -> DisjointMap k v
unionMapPairsGo [] !ds = ds
unionMapPairsGo ((a,b):xs) !ds = unionMapPairsGo xs (DM.union a b ds)