Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add function to check if two IntSets are disjoint. #377

Merged
merged 2 commits into from Jan 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Data/IntSet.hs
Expand Up @@ -74,6 +74,7 @@ module Data.IntSet (
, lookupGE
, isSubsetOf
, isProperSubsetOf
, disjoint

-- * Construction
, empty
Expand Down
49 changes: 49 additions & 0 deletions Data/IntSet/Internal.hs
Expand Up @@ -118,6 +118,7 @@ module Data.IntSet.Internal (
, lookupGE
, isSubsetOf
, isProperSubsetOf
, disjoint

-- * Construction
, empty
Expand Down Expand Up @@ -659,6 +660,54 @@ isSubsetOf (Tip _ _) Nil = False
isSubsetOf Nil _ = True


{--------------------------------------------------------------------
Disjoint
--------------------------------------------------------------------}
-- | /O(n+m)/. Check whether two sets are disjoint (i.e. their intersection
-- is empty).
Copy link
Contributor

@m-renaud m-renaud Jan 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some example invocations of the function and an @since 0.5.11 annotation? Thanks!

--
-- > disjoint (fromList [2,4,6]) (fromList [1,3]) == True
-- > disjoint (fromList [2,4,6,8]) (fromList [2,3,5,7]) == False
-- > disjoint (fromList [1,2]) (fromList [1,2,3,4]) == False
-- > disjoint (fromList []) (fromList []) == True
--
-- @since 0.5.11
disjoint :: IntSet -> IntSet -> Bool
disjoint t1@(Bin p1 m1 l1 r1) t2@(Bin p2 m2 l2 r2)
| shorter m1 m2 = disjoint1
| shorter m2 m1 = disjoint2
| p1 == p2 = disjoint l1 l2 && disjoint r1 r2
| otherwise = True
where
disjoint1 | nomatch p2 p1 m1 = True
| zero p2 m1 = disjoint l1 t2
| otherwise = disjoint r1 t2

disjoint2 | nomatch p1 p2 m2 = True
| zero p1 m2 = disjoint t1 l2
| otherwise = disjoint t1 r2

disjoint t1@(Bin _ _ _ _) (Tip kx2 bm2) = disjointBM t1
where disjointBM (Bin p1 m1 l1 r1) | nomatch kx2 p1 m1 = True
| zero kx2 m1 = disjointBM l1
| otherwise = disjointBM r1
disjointBM (Tip kx1 bm1) | kx1 == kx2 = (bm1 .&. bm2) == 0
| otherwise = True
disjointBM Nil = True

disjoint (Bin _ _ _ _) Nil = True

disjoint (Tip kx1 bm1) t2 = disjointBM t2
where disjointBM (Bin p2 m2 l2 r2) | nomatch kx1 p2 m2 = True
| zero kx1 m2 = disjointBM l2
| otherwise = disjointBM r2
disjointBM (Tip kx2 bm2) | kx1 == kx2 = (bm1 .&. bm2) == 0
| otherwise = True
disjointBM Nil = True

disjoint Nil _ = True


{--------------------------------------------------------------------
Filter
--------------------------------------------------------------------}
Expand Down
1 change: 1 addition & 0 deletions Data/Set.hs
Expand Up @@ -74,6 +74,7 @@ module Data.Set (
, lookupGE
, isSubsetOf
, isProperSubsetOf
, disjoint

-- * Construction
, empty
Expand Down
22 changes: 22 additions & 0 deletions Data/Set/Internal.hs
Expand Up @@ -141,6 +141,7 @@ module Data.Set.Internal (
, lookupGE
, isSubsetOf
, isProperSubsetOf
, disjoint

-- * Construction
, empty
Expand Down Expand Up @@ -622,6 +623,27 @@ isSubsetOfX (Bin _ x l r) t
{-# INLINABLE isSubsetOfX #-}
#endif

{--------------------------------------------------------------------
Disjoint
--------------------------------------------------------------------}
-- | /O(n+m)/. Check whether two sets are disjoint (i.e. their intersection
-- is empty).
--
-- > disjoint (fromList [2,4,6]) (fromList [1,3]) == True
-- > disjoint (fromList [2,4,6,8]) (fromList [2,3,5,7]) == False
-- > disjoint (fromList [1,2]) (fromList [1,2,3,4]) == False
-- > disjoint (fromList []) (fromList []) == True
--
-- @since 0.5.11

disjoint :: Ord a => Set a -> Set a -> Bool
disjoint Tip _ = True
disjoint _ Tip = True
disjoint (Bin _ x l r) t
-- Analogous implementation to `subsetOfX`
= not found && disjoint l lt && disjoint r gt
where
(lt,found,gt) = splitMember x t

{--------------------------------------------------------------------
Minimal, Maximal
Expand Down
4 changes: 4 additions & 0 deletions benchmarks/IntSet.hs
Expand Up @@ -32,6 +32,10 @@ main = do
, bench "fromList" $ whnf S.fromList elems
, bench "fromAscList" $ whnf S.fromAscList elems
, bench "fromDistinctAscList" $ whnf S.fromDistinctAscList elems
, bench "disjoint:false" $ whnf (S.disjoint s) s_even
, bench "disjoint:true" $ whnf (S.disjoint s_odd) s_even
, bench "null.intersection:false" $ whnf (S.null. S.intersection s) s_even
, bench "null.intersection:true" $ whnf (S.null. S.intersection s_odd) s_even
]
where
elems = [1..2^12]
Expand Down
4 changes: 4 additions & 0 deletions benchmarks/Set.hs
Expand Up @@ -33,6 +33,10 @@ main = do
, bench "fromList-desc" $ whnf S.fromList (reverse elems)
, bench "fromAscList" $ whnf S.fromAscList elems
, bench "fromDistinctAscList" $ whnf S.fromDistinctAscList elems
, bench "disjoint:false" $ whnf (S.disjoint s) s_even
, bench "disjoint:true" $ whnf (S.disjoint s_odd) s_even
, bench "null.intersection:false" $ whnf (S.null. S.intersection s) s_even
, bench "null.intersection:true" $ whnf (S.null. S.intersection s_odd) s_even
]
where
elems = [1..2^12]
Expand Down
7 changes: 6 additions & 1 deletion tests/intset-properties.hs
Expand Up @@ -54,6 +54,7 @@ main = defaultMain [ testCase "lookupLT" test_lookupLT
, testProperty "prop_isProperSubsetOf2" prop_isProperSubsetOf2
, testProperty "prop_isSubsetOf" prop_isSubsetOf
, testProperty "prop_isSubsetOf2" prop_isSubsetOf2
, testProperty "prop_disjoint" prop_disjoint
, testProperty "prop_size" prop_size
, testProperty "prop_findMax" prop_findMax
, testProperty "prop_findMin" prop_findMin
Expand Down Expand Up @@ -202,7 +203,7 @@ prop_MemberFromList xs
t = fromList abs_xs

{--------------------------------------------------------------------
Union
Union, Difference and Intersection
--------------------------------------------------------------------}
prop_UnionInsert :: Int -> IntSet -> Property
prop_UnionInsert x t =
Expand Down Expand Up @@ -233,6 +234,9 @@ prop_Int xs ys =
valid t .&&.
toAscList t === List.sort (nub ((List.intersect) (xs) (ys)))

prop_disjoint :: IntSet -> IntSet -> Bool
prop_disjoint a b = a `disjoint` b == null (a `intersection` b)

{--------------------------------------------------------------------
Lists
--------------------------------------------------------------------}
Expand Down Expand Up @@ -402,3 +406,4 @@ prop_bitcount a w = bitcount_orig a w == bitcount_new a w
go a x = go (a + 1) (x .&. (x-1))
bitcount_new a x = a + popCount x
#endif

4 changes: 4 additions & 0 deletions tests/set-properties.hs
Expand Up @@ -67,6 +67,7 @@ main = defaultMain [ testCase "lookupLT" test_lookupLT
, testProperty "prop_isProperSubsetOf2" prop_isProperSubsetOf2
, testProperty "prop_isSubsetOf" prop_isSubsetOf
, testProperty "prop_isSubsetOf2" prop_isSubsetOf2
, testProperty "prop_disjoint" prop_disjoint
, testProperty "prop_size" prop_size
, testProperty "prop_lookupMax" prop_lookupMax
, testProperty "prop_lookupMin" prop_lookupMin
Expand Down Expand Up @@ -426,6 +427,9 @@ prop_Int :: [Int] -> [Int] -> Bool
prop_Int xs ys = toAscList (intersection (fromList xs) (fromList ys))
== List.sort (nub ((List.intersect) (xs) (ys)))

prop_disjoint :: Set Int -> Set Int -> Bool
prop_disjoint a b = a `disjoint` b == null (a `intersection` b)

{--------------------------------------------------------------------
Lists
--------------------------------------------------------------------}
Expand Down