module Relations where
import FiniteMap(emptyFM,addListToFM_C,lookupWithDefaultFM)
import Sets
type Rel a b = Set (a,b)
listToRel :: (Ord a,Ord b) => [(a,b)] -> Rel a b
listToRel xs = mkSet xs
relToList :: Rel a b -> [(a,b)]
relToList r = setToList r
emptyRel :: Rel a b
emptyRel = emptySet
restrictDom :: (Ord a, Ord b) =>
(a -> Bool) -> Rel a b -> Rel a b
restrictDom p r = listToRel [(x,y) | (x,y) <- relToList r, p x]
restrictRng :: (Ord a, Ord b) =>
(b -> Bool) -> Rel a b -> Rel a b
restrictRng p r = listToRel [(x,y) | (x,y) <- relToList r, p y]
--dom :: Ord a => Rel a b -> Set a
dom r = mapSet fst r
--rng :: Ord b => Rel a b -> Set b
rng r = mapSet snd r
--mapDom :: (Ord b, Ord x) =>
-- (a -> x) -> Rel a b -> Rel x b
mapDom f = mapSet (\(x,y) -> (f x, y))
--mapRng :: (Ord a, Ord x) =>
-- (b -> x) -> Rel a b -> Rel a x
mapRng f = mapSet (\(x,y) -> (x, f y))
intersectRel :: (Ord a, Ord b) =>
Rel a b -> Rel a b -> Rel a b
r `intersectRel` s = r `intersect` s
unionRels :: (Ord a, Ord b) => [Rel a b] -> Rel a b
unionRels rs = unionManySets rs
minusRel :: (Ord a, Ord b) =>
Rel a b -> Rel a b -> Rel a b
r `minusRel` s = r `minusSet` s
partitionDom :: (Ord a, Ord b) =>
(a -> Bool) -> Rel a b -> (Rel a b, Rel a b)
partitionDom p r = (restrictDom p r, restrictDom (not . p) r)
applyRel :: (Ord a, Ord b) => Rel a b -> a -> [b]
--applyRel r a = setToList (rng (restrictDom (== a) r))
--applyRel r a = [b|(a',b)<-setToList r,a'==a] -- not faster...
applyRel r = lookupWithDefaultFM fm []
where fm = addListToFM_C (++) emptyFM [(a,[b])|(a,b)<-setToList r]
unionMapSet :: Ord b => (a -> Set b) -> (Set a -> Set b)
unionMapSet f = unionManySets . map f . setToList