packages feed

fitspec-0.4.3: bench/Set.hs

-- A list-based library for programming with sets.
-- Colin Runciman, June 2007 to April 2008.

module Set (Set, elemList, set, emptyS, singleS, pairS, insertS, deleteS, 
            sizeS, sizeAtMostS, sizeExactlyS, sizeAtLeastS,
            isEmptyS, nonEmptyS, minS, choiceS, (<~),
            (\/), (/\), (\\), unionS, interS, subS, disjointS,
            elemSubsetsOf, powerS, partitionsS, subsetPartitionsS,
            (<|), allS, anyS, exactly, forAll, thereExists, forExactly,
            minimalS, mapS, mapMonoS, unionMapS, regular) where

import Data.List (nub, sort, intersperse)

infixl 7 /\
infixl 6 \/
infixr 5 `elemSubsetsOf`, `subsetPartitionsS`, <|
infix  4 <~, `subS`

data Set a = S {elemList :: [a]}

instance (Ord a, Eq a) => Eq (Set a)
  where
  S xs == S ys = xs == ys

instance Ord a => Ord (Set a)
  where
  compare (S xs) (S ys) = compare xs ys

instance (Ord a, Show a) => Show (Set a)
  where
  show (S xs) =
    "{"++concat (intersperse "," (map show xs))++"}"

set :: Ord a => [a] -> Set a
set = S . nub . sort

emptyS :: Ord a => Set a
emptyS = S []

singleS :: Ord a => a -> Set a
singleS e = S [e]

pairS :: Ord a => a -> a -> Set a
pairS e1 e2 = set [e1,e2]

insertS :: Ord a => a -> Set a -> Set a
insertS e = S . insertList e . elemList
  where
  insertList e []         = [e]
  insertList e xs@(x:xs') = case compare e x of
                            LT -> e : xs
                            EQ -> xs
                            GT -> x : insertList e xs'

deleteS :: Ord a => a -> Set a -> Set a
deleteS e = S . deleteList e . elemList
  where
  deleteList e []         = []
  deleteList e xs@(x:xs') = case compare e x of
                            LT -> xs
                            EQ -> xs'
                            GT -> x : deleteList e xs'

sizeS :: Ord a => Set a -> Int
sizeS = length . elemList

sizeExactlyS :: Ord a => Int -> Set a -> Bool
sizeExactlyS n = lengthExactly n . elemList
  where
  lengthExactly 0 xs     = null xs
  lengthExactly n []     = False
  lengthExactly n (x:xs) = lengthExactly (n-1) xs

sizeAtLeastS :: Ord a => Int -> Set a -> Bool
sizeAtLeastS n = lengthAtLeast n . elemList
  where
  lengthAtLeast 0 xs     = True
  lengthAtLeast n []     = False
  lengthAtLeast n (x:xs) = lengthAtLeast (n-1) xs

sizeAtMostS :: Ord a => Int -> Set a -> Bool
sizeAtMostS n = lengthAtMost n . elemList
  where
  lengthAtMost 0 xs     = null xs
  lengthAtMost n []     = True
  lengthAtMost n (x:xs) = lengthAtMost (n-1) xs

isEmptyS :: Ord a => Set a -> Bool
isEmptyS = null . elemList

nonEmptyS :: Ord a => Set a -> Bool
nonEmptyS = not . isEmptyS

minS :: Ord a => Set a -> a
minS = head . elemList

choiceS :: Ord a => Set a -> Set (a, Set a)
choiceS = S . choice . elemList
  where
  choice xs = [(x, S (xs1++xs2)) | (xs1,x:xs2) <- splits xs]  

splits :: [a] -> [([a],[a])]
splits []     = [([],[])]
splits (x:xs) = ([],x:xs) : [(x:xs1, xs2) | (xs1,xs2) <- splits xs]

(<~) :: Ord a => a -> Set a -> Bool
(<~) e = ordElem e . elemList
  where
  ordElem e []     = False
  ordElem e (x:xs) = case compare e x of
                     LT -> False
                     EQ -> True
                     GT -> ordElem e xs

(\/) :: Ord a => Set a -> Set a -> Set a
S xs \/ S ys = S (join xs ys)
  where
  join [] ys = ys
  join xs [] = xs
  join xs@(x:xs') ys@(y:ys') =
    case compare x y of
    LT -> x : join xs' ys
    EQ -> x : join xs' ys'
    GT -> y : join xs  ys'

(/\) :: Ord a => Set a -> Set a -> Set a
S xs /\ S ys = S (meet xs ys)

meet [] _  = []
meet _  [] = []
meet xs@(x:xs') ys@(y:ys') =
  case compare x y of
  LT ->     meet xs' ys
  EQ -> x : meet xs' ys'
  GT ->     meet xs  ys'

(\\) :: Ord a => Set a -> Set a -> Set a
S xs \\ S ys = S (diff xs ys)

diff [] _  = []
diff xs [] = xs
diff xs@(x:xs') ys@(y:ys') =
  case compare x y of
  LT -> x : diff xs' ys
  EQ ->     diff xs' ys'
  GT ->     diff xs  ys'

unionS :: Ord a => Set (Set a) -> Set a
unionS = foldr (\/) emptyS . elemList

interS :: Ord a => Set (Set a) -> Set a
interS = foldr1 (/\) . elemList

disjointS :: Ord a => Set a -> Set a -> Bool
disjointS (S xs) (S ys) = null (meet xs ys)

subS :: Ord a => Set a -> Set a -> Bool
subS (S xs) (S ys) = null (diff xs ys)

elemSubsetsOf :: Ord a => Int -> Set a -> Set (Set a)
elemSubsetsOf n =
  S . map S . sublistsOf n . elemList
  where
  sublistsOf 0 _      = [[]]
  sublistsOf _ []     = []
  sublistsOf n (x:xs) =
    map (x:) (sublistsOf (n-1) xs) ++ sublistsOf n xs

powerS :: Ord a => Set a -> Set (Set a)
powerS = 
  S . map S . ([]:) . nonEmptySublists . elemList
  where
  nonEmptySublists [] = []
  nonEmptySublists (x:xs) =
    [x] : map (x:) ss ++ ss
    where
    ss = nonEmptySublists xs

-- outer 'set' used to be 'S' but then ordering between
-- partitions can be wrong
-- TO DO: instead reorder partitionsList computation?
partitionsS :: Ord a => Set a -> Set (Set (Set a))
partitionsS = set . map (S . map S) . partitionsList . elemList
  where
  partitionsList []     = [[]]
  partitionsList (x:xs) =
    [[x] : p | p <- ps] ++
    [(x:xs') : xss ++ xss' | p <- ps, (xss,xs':xss') <- splits p]
    where
    ps = partitionsList xs

subsetPartitionsS :: Ord a => Int -> Set a -> Set (Set (Set a))
subsetPartitionsS n = S . map (S . map S) . sublistPartitionsList n . elemList
  where
  sublistPartitionsList n []  = [[] | n == 0]
  sublistPartitionsList n (x:xs) =
    [ [x] : p
    | n > 0, p <- sublistPartitionsList (n-1) xs ] ++
    [ (x:xs') : xss ++ xss'
    | n > 0, p <- sublistPartitionsList n xs, (xss,xs':xss') <- splits p ]

(<|) :: Ord a => (a -> Bool) -> Set a -> Set a
(<|) p = S . filter p . elemList

allS, anyS :: Ord a => (a -> Bool) -> Set a -> Bool
allS p = all p . elemList
anyS p = any p . elemList

exactly ::
  Ord a => Int -> (a->Bool) -> Set a -> Bool
exactly n p =
  exactlyList n p . elemList
  where
  exactlyList 0 p xs     = not (any p xs)
  exactlyList n p []     = False
  exactlyList n p (x:xs) = exactlyList 
                             (if p x then n-1 else n) p xs

forAll, thereExists :: Ord a => Set a -> (a->Bool) -> Bool
forAll s p = allS p s
thereExists s p = anyS p s

forExactly :: Ord a => Int -> Set a -> (a->Bool) -> Bool
forExactly n s p = exactly n p s

mapS :: (Ord a, Ord b) => (a -> b) -> Set a -> Set b
mapS f = set . map f . elemList

-- more efficient variant when f is monotonic
mapMonoS :: (Ord a, Ord b) => (a -> b) -> Set a -> Set b
mapMonoS f = S . map f . elemList

unionMapS :: (Ord a, Ord b) => (a -> Set b) -> Set a -> Set b
unionMapS f = foldr (\/) emptyS . map f . elemList

minimalS :: Ord a => (Set a -> Bool) -> Set a -> Bool
minimalS p s = (p <| powerS s) == set [s]

regular :: Ord a => Int -> Set (Set a) -> Bool
regular d ss =
  -- every element occurs in exactly d sets
  forAll (unionS ss) $ \e ->
    forExactly d ss $ \s -> e <~ s