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