Skip to content

Add spec for new Interval / IntervalIndex methods: .overlaps(), .covers() #18975

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

Closed
wants to merge 12 commits into from
194 changes: 194 additions & 0 deletions pandas/tests/indexes/interval/test_interval_new.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,197 @@ def test_contains_method(self):

assert not index.contains(20)
assert not index.contains(-20)

def test_interval_covers_interval(self):

# class Interval:
# def covers(self, other: Interval) -> bool

assert Interval(1, 3).covers(Interval(1.5, 2.5))
Copy link
Member

Choose a reason for hiding this comment

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

I think Interval level tests would be more appropriate in pandas/tests/scalar/test_interval.py, which is where the other Interval specific tests are located.

assert Interval(1, 3).covers(Interval(1, 2))
assert Interval(1, 3).covers(Interval(2, 3))
assert not Interval(1, 3).covers(Interval(0.5, 2.5))
assert not Interval(1, 3).covers(Interval(1.5, 3.5))

assert Interval(1, 3, closed='right').covers(Interval(1, 3, closed='right'))
assert not Interval(1, 3, closed='right').covers(Interval(1, 3, closed='left'))
assert not Interval(1, 3, closed='right').covers(Interval(1, 3, closed='both'))

assert not Interval(1, 3, closed='left').covers(Interval(1, 3, closed='right'))
assert Interval(1, 3, closed='left').covers(Interval(1, 3, closed='left'))
assert not Interval(1, 3, closed='left').covers(Interval(1, 3, closed='both'))

assert Interval(1, 3, closed='both').covers(Interval(1, 3, closed='right'))
assert Interval(1, 3, closed='both').covers(Interval(1, 3, closed='left'))
assert Interval(1, 3, closed='both').covers(Interval(1, 3, closed='both'))

@pytest.mark.parametrize("idx_side", ['right', 'left', 'both', 'neither'])
def test_interval_covers_intervalIndex(self):

# class Interval:
# def covers(self, other: IntervalIndex) -> IntegerArray1D

idx = IntervalIndex.from_tuples([(0, 1), (2, 3), (1, 3)], closed='right')

tm.assert_numpy_array_equal(Interval(1, 3, closed='right').covers(idx), np.array([1, 2]))
tm.assert_numpy_array_equal(Interval(0, 3, closed='right').covers(idx), np.array([0, 1, 2]))
tm.assert_numpy_array_equal(Interval(0, 2, closed='right').covers(idx), np.array([0]))
tm.assert_numpy_array_equal(Interval(2, 4, closed='right').covers(idx), np.array([1]))

tm.assert_numpy_array_equal(Interval(1, 3, closed='left').covers(idx), np.array([]))
tm.assert_numpy_array_equal(Interval(0, 3, closed='left').covers(idx), np.array([0]))
tm.assert_numpy_array_equal(Interval(0, 2, closed='left').covers(idx), np.array([0]))
tm.assert_numpy_array_equal(Interval(2, 4, closed='left').covers(idx), np.array([1]))

tm.assert_numpy_array_equal(Interval(1, 3, closed='both').covers(idx), np.array([1, 2]))
tm.assert_numpy_array_equal(Interval(0, 5, closed='both').covers(idx), np.array([0, 1, 2]))
tm.assert_numpy_array_equal(Interval(0, 2, closed='both').covers(idx), np.array([0]))
tm.assert_numpy_array_equal(Interval(2, 4, closed='both').covers(idx), np.array([1]))

def test_interval_overlaps_interval(self):

# class Interval:
# def overlaps(self, other: Interval) -> bool

assert Interval(1, 3).overlaps(Interval(1.5, 2.5))
assert Interval(1, 3).overlaps(Interval(1, 2))
assert Interval(1, 3).overlaps(Interval(2, 3))
assert Interval(1, 3).overlaps(Interval(0.5, 2.5))
assert Interval(1, 3).overlaps(Interval(1.5, 3.5))

assert not Interval(1, 3).overlaps(Interval(-1, 1))
assert not Interval(1, 3).overlaps(Interval(3, 5))

# right
assert Interval(1, 3, closed='right').overlaps(Interval(1, 3, closed='right'))
assert Interval(1, 3, closed='right').overlaps(Interval(1, 3, closed='left'))
assert Interval(1, 3, closed='right').overlaps(Interval(1, 3, closed='both'))

assert not Interval(1, 3, closed='right').overlaps(Interval(-1, 1, closed='right'))
assert not Interval(1, 3, closed='right').overlaps(Interval(-1, 1, closed='left'))
assert not Interval(1, 3, closed='right').overlaps(Interval(-1, 1, closed='both'))

assert not Interval(1, 3, closed='right').overlaps(Interval(3, 5, closed='right'))
assert Interval(1, 3, closed='right').overlaps(Interval(3, 5, closed='left'))
assert Interval(1, 3, closed='right').overlaps(Interval(3, 5, closed='both'))

# left
assert Interval(1, 3, closed='left').overlaps(Interval(1, 3, closed='right'))
assert Interval(1, 3, closed='left').overlaps(Interval(1, 3, closed='left'))
assert Interval(1, 3, closed='left').overlaps(Interval(1, 3, closed='both'))

assert not Interval(1, 3, closed='left').overlaps(Interval(-1, 1, closed='right'))
assert not Interval(1, 3, closed='left').overlaps(Interval(-1, 1, closed='left'))
assert not Interval(1, 3, closed='left').overlaps(Interval(-1, 1, closed='both'))

assert not Interval(1, 3, closed='left').overlaps(Interval(3, 5, closed='right'))
assert Interval(1, 3, closed='left').overlaps(Interval(3, 5, closed='left'))
assert Interval(1, 3, closed='left').overlaps(Interval(3, 5, closed='both'))

# both
assert Interval(1, 3, closed='both').overlaps(Interval(1, 3, closed='right'))
assert Interval(1, 3, closed='both').overlaps(Interval(1, 3, closed='left'))
assert Interval(1, 3, closed='both').overlaps(Interval(1, 3, closed='both'))

assert Interval(1, 3, closed='both').overlaps(Interval(-1, 1, closed='right'))
assert not Interval(1, 3, closed='both').overlaps(Interval(-1, 1, closed='left'))
Copy link
Contributor

Choose a reason for hiding this comment

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

btw I would be very happy to have these in a different file, e.g.

pandas/tests/indexes/interval/test_overlap_covers.py or whatever (excluding @jschendel commet that the Interval tests need to go in the scalar tests); we can make a sub-dir there as well I think.

assert Interval(1, 3, closed='both').overlaps(Interval(-1, 1, closed='both'))

assert not Interval(1, 3, closed='both').overlaps(Interval(3, 5, closed='right'))
assert Interval(1, 3, closed='both').overlaps(Interval(3, 5, closed='left'))
assert Interval(1, 3, closed='both').overlaps(Interval(3, 5, closed='both'))

def test_interval_overlaps_intervalIndex(self):

# class Interval:
# def overlaps(self, other: IntervalIndex) -> IntegerArray1D

idx = IntervalIndex.from_tuples([(0, 1), (2, 3), (1, 3)], closed='right')

tm.assert_numpy_array_equal(Interval(1, 3, closed='right').overlaps(idx), np.array([1, 2]))
tm.assert_numpy_array_equal(Interval(1, 2, closed='right').overlaps(idx), np.array([2]))
tm.assert_numpy_array_equal(Interval(0, 2, closed='right').overlaps(idx), np.array([0, 2]))
tm.assert_numpy_array_equal(Interval(3, 4, closed='right').overlaps(idx), np.array([]))

tm.assert_numpy_array_equal(Interval(1, 3, closed='left').overlaps(idx), np.array([0, 1, 2]))
tm.assert_numpy_array_equal(Interval(1, 2, closed='left').overlaps(idx), np.array([0, 2]))
tm.assert_numpy_array_equal(Interval(0, 2, closed='left').overlaps(idx), np.array([0, 2]))
tm.assert_numpy_array_equal(Interval(3, 4, closed='left').overlaps(idx), np.array([3]))

tm.assert_numpy_array_equal(Interval(1, 3, closed='both').overlaps(idx), np.array([0, 1, 2]))
tm.assert_numpy_array_equal(Interval(1, 2, closed='both').overlaps(idx), np.array([0, 2]))
tm.assert_numpy_array_equal(Interval(0, 2, closed='both').overlaps(idx), np.array([0, 2]))
tm.assert_numpy_array_equal(Interval(3, 4, closed='both').overlaps(idx), np.array([3]))

def test_intervalIndex_covers_interval(self):

# class IntervalIndex:
# def covers(self, other: Interval) -> IntegerArray1D

idx = IntervalIndex.from_tuples([(0, 1), (2, 3), (1, 3)], closed='right')

tm.assert_numpy_array_equal(idx.covers(Interval(1, 3, closed='right')), np.array([1, 2]))
tm.assert_numpy_array_equal(idx.covers(Interval(0, 3, closed='right')), np.array([0, 1, 2]))
tm.assert_numpy_array_equal(idx.covers(Interval(0, 2, closed='right')), np.array([0]))
tm.assert_numpy_array_equal(idx.covers(Interval(2, 4, closed='right')), np.array([1]))

tm.assert_numpy_array_equal(idx.covers(Interval(1, 3, closed='left')), np.array([]))
tm.assert_numpy_array_equal(idx.covers(Interval(0, 3, closed='left')), np.array([0]))
tm.assert_numpy_array_equal(idx.covers(Interval(0, 2, closed='left')), np.array([0]))
tm.assert_numpy_array_equal(idx.covers(Interval(2, 4, closed='left')), np.array([1]))

tm.assert_numpy_array_equal(idx.covers(Interval(1, 3, closed='both')), np.array([1, 2]))
tm.assert_numpy_array_equal(idx.covers(Interval(0, 5, closed='both')), np.array([0, 1, 2]))
tm.assert_numpy_array_equal(idx.covers(Interval(0, 2, closed='both')), np.array([0]))
tm.assert_numpy_array_equal(idx.covers(Interval(2, 4, closed='both')), np.array([1]))

def test_intervalIndex_covers_intervalIndex(self):

# class IntervalIndex:
# def covers(self, other: IntervalIndex) -> Tuple[IntegerArray1D, IntegerArray1D]

idx1 = IntervalIndex.from_tuples([(0, 1), (2, 3), (1, 3)], closed='right')
idx2 = IntervalIndex.from_tuples([(0, 1), (2, 3), (1, 3)], closed='left')
idx3 = IntervalIndex.from_tuples([(0, 1), (2, 3), (1, 3)], closed='both')

self._compare_tuple_of_numpy_array(idx.covers(idx1), (np.array([0,1,2,2]), np.array([0,1,1,2])))
self._compare_tuple_of_numpy_array(idx.covers(idx2), (np.array([2]), np.array([1])))
self._compare_tuple_of_numpy_array(idx.covers(idx3), (np.array([0,1,2,2]), np.array([0,1,1,2])))

def test_intervalIndex_overlaps_interval(self):

# class IntervalIndex:
# def overlaps(self, other: Interval) -> IntegerArray1D

idx = IntervalIndex.from_tuples([(0, 1), (2, 3), (1, 3)], closed='right')

tm.assert_numpy_array_equal(idx.overlaps(Interval(1, 3, closed='right')), np.array([1, 2]))
tm.assert_numpy_array_equal(idx.overlaps(Interval(1, 2, closed='right')), np.array([2]))
tm.assert_numpy_array_equal(idx.overlaps(Interval(0, 2, closed='right')), np.array([0, 2]))
tm.assert_numpy_array_equal(idx.overlaps(Interval(3, 4, closed='right')), np.array([]))

tm.assert_numpy_array_equal(idx.overlaps(Interval(1, 3, closed='left')), np.array([0, 1, 2]))
tm.assert_numpy_array_equal(idx.overlaps(Interval(1, 2, closed='left')), np.array([0, 2]))
tm.assert_numpy_array_equal(idx.overlaps(Interval(0, 2, closed='left')), np.array([0, 2]))
tm.assert_numpy_array_equal(idx.overlaps(Interval(3, 4, closed='left')), np.array([3]))

tm.assert_numpy_array_equal(idx.overlaps(Interval(1, 3, closed='both')), np.array([0, 1, 2]))
tm.assert_numpy_array_equal(idx.overlaps(Interval(1, 2, closed='both')), np.array([0, 2]))
tm.assert_numpy_array_equal(idx.overlaps(Interval(0, 2, closed='both')), np.array([0, 2]))
tm.assert_numpy_array_equal(idx.overlaps(Interval(3, 4, closed='both')), np.array([3]))

def test_intervalIndex_overlaps_intervalIndex(self):

# class IntervalIndex:
# def overlaps(self, other: IntervalIndex) -> Tuple[IntegerArray1D, IntegerArray1D]

idx1 = IntervalIndex.from_tuples([(0, 1), (2, 3), (1, 3)], closed='right')
idx2 = IntervalIndex.from_tuples([(0, 1), (2, 3), (1, 3)], closed='left')
idx3 = IntervalIndex.from_tuples([(0, 1), (2, 3), (1, 3)], closed='both')

self._compare_tuple_of_numpy_array(idx.overlaps(idx1), (np.array([0,1,2,2]), np.array([0,1,1,2])))
self._compare_tuple_of_numpy_array(idx.overlaps(idx2), (np.array([0,0,1,1,2,2]), np.array([0,2,1,2,1,2])))
self._compare_tuple_of_numpy_array(idx.overlaps(idx3), (np.array([0,0,1,1,2,2]), np.array([0,2,1,2,1,2])))