def open(lower, upper): """ Creates a range excluding the endpoints (i.e. (lower, upper)) Parameters ---------- lower : comparable, of same type as or subclass of upper type The lower bound upper : comparable, of same type as or subclass of lower type The upper bound Raises ------ ValueError If type(s) are not comparable or compatible or if constructing a range of type (v,v), which is invalid Returns ------- A Range object (lower, upper) """ # Ensure cutpoints are of compatible, appropriate types Range._validate_cutpoints(lower, upper) theType = Range._get_type(lower,upper) if lower == upper: raise TypeError("Range of type (v,v) is not valid") return Range(Cut.aboveValue(lower, theType=theType), Cut.belowValue(upper, theType=theType))
def test_isGreaterThanInt(self): if debug: print("Testing isGreaterThan with integers") ptCut = Cut(int, point=2, below=False) belowAllCut = Cut(int, belowAll=True) aboveAllCut = Cut(int, aboveAll=True) self.assertFalse(ptCut.isGreaterThan(3)) self.assertTrue(ptCut.isGreaterThan(2)) self.assertTrue(ptCut.isGreaterThan(1)) self.assertFalse(belowAllCut.isGreaterThan(-999)) self.assertTrue(aboveAllCut.isGreaterThan(1000))
def test_aboveValue(self): if debug: print("Testing aboveValue") theCut = Cut.aboveValue(2) self.assertFalse(theCut.belowAll) self.assertFalse(theCut.aboveAll) self.assertEqual(theCut.point, 2) self.assertFalse(theCut.below)
def test_isLessThanInt(self): if debug: print("Testing isLessThan with integers") ptCut = Cut(int, point=2, below=False) belowAllCut = Cut(int, belowAll=True) aboveAllCut = Cut(int, aboveAll = True) self.assertTrue(ptCut.isLessThan(3)) self.assertFalse(ptCut.isLessThan(2)) self.assertFalse(ptCut.isLessThan(1)) self.assertTrue(belowAllCut.isLessThan(-999)) self.assertFalse(aboveAllCut.isLessThan(1000))
def atLeast(val): """ Makes range including all values greater than or equal to some value (i.e. [val, inf)) Parameters ---------- val : comparable The lower bound Raises ------ ValueError If type not comparable Returns ------- A Range object [val, inf) """ Range._validate_cutpoints(val) theType = Range._get_type(val) return Range(Cut.belowValue(val, theType=theType), Cut.aboveAll(theType=theType))
def atMost(val): """ Makes range including all values less than or equal to some value (i.e. (-inf, val]) Parameters ---------- val : comparable The upper bound Raises ------ ValueError If type not comparable Returns ------- A Range object (-inf, val] """ Range._validate_cutpoints(val) theType = Range._get_type(val) return Range(Cut.belowAll(theType=theType), Cut.aboveValue(val, theType=theType))
def openClosed(lower, upper): """ Creates a range including the upper (i.e. (lower, upper]) Parameters ---------- lower : comparable, of same type as or subclass of upper type The lower bound upper : comparable, of same type as or subclass of lower type The upper bound Raises ------ ValueError If type(s) are not comparable or compatible Returns ------- A Range object (lower, upper] """ # Ensure cutpoints are of compatible, appropriate types Range._validate_cutpoints(lower, upper) theType = Range._get_type(lower,upper) return Range(Cut.aboveValue(lower, theType=theType), Cut.aboveValue(upper, theType=theType))
def test_add(self): if debug: print("Testing add with integers") theSet = RangeSet() # Adding initial part theSet.add(Range.closed(3, 5)) self.assertEqual(theSet.lower_cuts[0], Cut.belowValue(3)) self.assertEqual(theSet.upper_cuts[0], Cut.aboveValue(5)) self.assertEqual(len(theSet), 1) # Adding distinct range above initial one theSet.add(Range.closed(7, 10)) self.assertEqual(len(theSet), 2) self.assertEqual(theSet.ranges[1], Range.closed(7, 10)) self.assertEqual(theSet.ranges[0], Range.closed(3, 5)) # Adding range below/overlapping with initial one theSet.add(Range.closed(2, 3)) self.assertEqual(len(theSet), 2) self.assertEqual(Range.closed(2, 5), theSet.ranges[0]) self.assertEqual(Cut.belowValue(2), theSet.lower_cuts[0]) self.assertEqual(Cut.aboveValue(5), theSet.upper_cuts[0]) self.assertEqual(Range.closed(7, 10), theSet.ranges[1]) self.assertEqual(Cut.belowValue(7), theSet.lower_cuts[1]) self.assertEqual(Cut.aboveValue(10), theSet.upper_cuts[1]) # Adding range above/overlapping second one theSet.add(Range.closed(9, 11)) self.assertEqual(len(theSet), 2) self.assertEqual(Range.closed(7, 11), theSet.ranges[1]) self.assertEqual(Cut.belowValue(7), theSet.lower_cuts[1]) self.assertEqual(Cut.aboveValue(11), theSet.upper_cuts[1]) # Adding range encompasing second one theSet.add(Range.closed(6, 12)) self.assertEqual(len(theSet), 2) self.assertEqual(Range.closed(6, 12), theSet.ranges[1]) self.assertEqual(Cut.belowValue(6), theSet.lower_cuts[1]) self.assertEqual(Cut.aboveValue(12), theSet.upper_cuts[1]) # Adding range encompassing all theSet.add(Range.closed(3, 11)) self.assertEqual(len(theSet), 1) self.assertEqual(len(theSet.lower_cuts), 1) self.assertEqual(len(theSet.upper_cuts), 1) self.assertEqual(Range.closed(2, 12), theSet.ranges[0]) self.assertEqual(Cut.belowValue(2), theSet.lower_cuts[0]) self.assertEqual(Cut.aboveValue(12), theSet.upper_cuts[0])
def range_all(theType): """Create a range than contains every value of the given type.""" return Range( Cut.belowAll(theType=theType), Cut.aboveAll(theType=theType))
def range_all(theType: Any) -> Range: """Create a range than contains every value of the given type.""" return Range(Cut.belowAll(theType=theType), Cut.aboveAll(theType=theType))
def test_add(self): if debug: print("Testing add with integers") theSet = RangeSet() # Adding initial part theSet.add(Range.closed(3,5)) self.assertEqual(theSet.lower_cuts[0], Cut.belowValue(3)) self.assertEqual(theSet.upper_cuts[0], Cut.aboveValue(5)) self.assertEqual(len(theSet),1) # Adding distinct range above initial one theSet.add(Range.closed(7,10)) self.assertEqual(len(theSet),2) self.assertEqual(theSet.ranges[1],Range.closed(7,10)) self.assertEqual(theSet.ranges[0],Range.closed(3,5)) # Adding range below/overlapping with initial one theSet.add(Range.closed(2,3)) self.assertEqual(len(theSet),2) self.assertEqual(Range.closed(2,5), theSet.ranges[0]) self.assertEqual(Cut.belowValue(2), theSet.lower_cuts[0]) self.assertEqual(Cut.aboveValue(5), theSet.upper_cuts[0]) self.assertEqual(Range.closed(7,10), theSet.ranges[1]) self.assertEqual(Cut.belowValue(7), theSet.lower_cuts[1]) self.assertEqual(Cut.aboveValue(10), theSet.upper_cuts[1]) # Adding range above/overlapping second one theSet.add(Range.closed(9,11)) self.assertEqual(len(theSet),2) self.assertEqual(Range.closed(7,11), theSet.ranges[1]) self.assertEqual(Cut.belowValue(7), theSet.lower_cuts[1]) self.assertEqual(Cut.aboveValue(11), theSet.upper_cuts[1]) # Adding range encompasing second one theSet.add(Range.closed(6,12)) self.assertEqual(len(theSet),2) self.assertEqual(Range.closed(6,12), theSet.ranges[1]) self.assertEqual(Cut.belowValue(6), theSet.lower_cuts[1]) self.assertEqual(Cut.aboveValue(12), theSet.upper_cuts[1]) # Adding range encompassing all theSet.add(Range.closed(3, 11)) self.assertEqual(len(theSet),1) self.assertEqual(len(theSet.lower_cuts),1) self.assertEqual(len(theSet.upper_cuts),1) self.assertEqual(Range.closed(2,12), theSet.ranges[0]) self.assertEqual(Cut.belowValue(2), theSet.lower_cuts[0]) self.assertEqual(Cut.aboveValue(12), theSet.upper_cuts[0])
def iteritems(self, start = None, end = None): """ Iterates over pairs of (Range, value) Parameters ---------- start : comparable, optional The starting point for iterating, inclusive end : comparable, optional The ending point for iterating, inclusive Returns ------- Generator of (Range intersecting [start,end], value), ordered by start point """ if start is None: start = self.lower_cuts[0] else: start = Cut.belowValue(start) if end is None: end = self.upper_cuts[-1] else: end = Cut.aboveValue(end) bounding_range = Range(start, end) # Get the bounding indices ovlapLowerInd = max(bisect_left(self.lower_cuts, start)-1,0) ovlapUpperInd = bisect_left(self.lower_cuts, end) # Create queue of values that need to be generated yield_vals = deque() # Create dictionary of values to be generated -> indices containing them vals_inds_dict = {} for i in range(ovlapLowerInd, ovlapUpperInd): # Check if anything can be released from the queue while len(yield_vals) > 0: if vals_inds_dict[yield_vals[0]][-1] < i-1: # Yield the full range, value. Remove value from queue val = yield_vals.popleft() yield Range(max(self.lower_cuts[vals_inds_dict[val][0]],start), min(self.upper_cuts[vals_inds_dict[val][-1]],end)), val # Remove value from dict del vals_inds_dict[val] else: break try: # Get intersection of the ranges intersect = bounding_range.intersection(self.ranges[i]) if not intersect.isEmpty(): # If overlapping with this range, put into queue for val in self.items[i]: if val not in vals_inds_dict: yield_vals.append(val) vals_inds_dict[val] = deque() vals_inds_dict[val].append(i) except ValueError: # Continue if no overlap with this range continue ## Yield remaining values while len(yield_vals) > 0: # Yield the full range, value. Remove value from queue val = yield_vals.popleft() yield Range(max(self.lower_cuts[vals_inds_dict[val][0]],start), min(self.upper_cuts[vals_inds_dict[val][-1]],end)), val # Remove value from dict del vals_inds_dict[val]
def test_aboveAll(self): if debug: print("Testing aboveAll") theCut = Cut.aboveAll(int) self.assertFalse(theCut.belowAll) self.assertTrue(theCut.aboveAll) self.assertIsNone(theCut.point)