def end_update(self, domain): if domain.is_empty or self._end_update_interval.is_superset_of(domain): return self._end_update_interval = Interval.union( [self._end_update_interval, domain]) if not self._end_update_interval.is_superset_of( self._begin_update_interval): # Keep collecting updates return # Updates complete update_interval = self._end_update_interval self._begin_update_interval = Interval.empty() self._end_update_interval = Interval.empty() self.set_needs_interval_update() for token in list(self._ordered_observer_tokens): _, callback_interval, _, callback, _, callback_with_interval = self._observer_data[ token] if callback_interval is None or update_interval.intersects( callback_interval): if callback is not None: if callback_with_interval: callback(update_interval) else: callback()
def test_inequalities(): assert Interval(1, 3) == (1, 3) assert (1, 3) == Interval(1, 3) assert Interval(1, 3) < (4, 6) assert not Interval(1, 3) < (3, 6) assert not Interval(1, 3) < (-3, -1) assert Interval(1, 3) <= (3, 6) assert Interval(1, 3) <= (2, 6) assert Interval(1, 3) <= (1, 6) assert Interval(3, 5) <= (1, 6) assert not Interval(1, 3) <= (-3, -1) assert not Interval(3, 6) <= Interval.open(1, 6) assert Interval(1, 3) < Interval.empty() assert Interval(1, 3) <= Interval.empty() assert Interval(7, 9) > (4, 6) assert not Interval(7, 9) > (4, 7) assert not Interval(7, 9) > (10, 12) assert Interval(7, 9) >= (4, 7) assert Interval(7, 9) >= (4, 8) assert Interval(7, 9) >= (4, 9) assert not Interval(7, 9) >= (10, 12) assert not Interval(4, 10) >= Interval.open(4, 9) assert Interval(7, 9) > Interval.empty() assert Interval(7, 9) >= Interval.empty()
def test_round(): assert Interval(1.2, 3.4).round() == (1, 3) assert Interval(1.2, 3.4).round(method=math.floor) == (1, 3) assert Interval(1.2, 3.4).round(method=math.ceil) == (2, 4) assert Interval.open_closed(1.2, 3.4).round() == Interval.open_closed(1, 3) assert Interval.closed_open(1.2, 3.4).round() == Interval.closed_open(1, 3) assert Interval.empty().round() == Interval.empty()
def __init__(self, min_step=None): self.name = None self._domain = None self._observer_data = {} self._ordered_observer_tokens = [] self._begin_update_interval = Interval.empty() self._end_update_interval = Interval.empty() self.min_step = min_step
def test_equals(): d = Interval(1, 3) assert d.equals((1, 3)) assert not d.equals(None) assert not d.equals(Interval.closed_open(1, 3)) assert Interval.empty().equals(Interval.empty()) # Empty intervals are always equal assert Interval.open(1, 1).equals(Interval.open(2, 2)) assert Interval.infinite().equals(Interval.infinite())
def __init__(self, min_width, is_upper_trend=True, min_points=None, min_point_distance=0, search_length_rel=None, search_length_int_rel=None, x_tol_rel=None, x_tol_abs=None, y_tol_rel=None, y_tol_abs=None): self.min_width = min_width self.is_upper_trend = is_upper_trend self.min_points = min_points self.min_point_distance = min_point_distance self.search_length_rel = search_length_rel self.search_length_int_rel = search_length_int_rel self.x_tol_rel = x_tol_rel self.x_tol_abs = x_tol_abs self.y_tol_rel = y_tol_rel self.y_tol_abs = y_tol_abs """A list of points through which the trend line is formed.""" self.trend_points = [] """An unfiltered list of points from which trend points are derived.""" self._boundary_points = [] """A list of points which touch the trend line without the underlying trend crossing the trend.""" self.tangent_points = [] self._line = None self.search_interval = Interval.empty() self.reset_points_of_interest() self.reset_prediction()
def span_interval(self, interval, start_open=False) -> Interval: """ Returns the time interval which fully contains the specified interval. """ interval = Interval.parse(interval, default_inf=True) if interval.is_empty: return Interval.empty() elif interval.start == interval.end: return self.span_date(interval.start, start_open=start_open) end_open = not start_open if interval.is_negative_infinite: start = -math.inf else: # Move outward if interval is closed but should be open o = not interval.start_open and start_open span = self.span_date(interval.start, start_open=o) start = span.start if interval.is_positive_infinite: end = math.inf else: # Move outward if interval is closed but should be open o = not interval.end_open and end_open span = self.span_date(interval.end, start_open=not o) end = span.end return Interval(start, end, start_open=start_open, end_open=not start_open)
def test_intersects(): assert Interval.closed(1, 3).intersects(Interval.closed(2, 3)) assert Interval.closed(1, 3).intersects((2, 3)) assert Interval.closed(1, 3).intersects((1, 3)) assert Interval.closed(1, 3).intersects(Interval.open(1, 3)) assert Interval.closed(1, 3).intersects(Interval.closed(3, 4)) assert not Interval.closed(1, 3).intersects(Interval.open(3, 4)) assert not Interval.open(1, 3).intersects(Interval.closed(3, 4)) assert Interval.point(3).intersects(Interval.closed(3, 4)) assert Interval.point(3).intersects(Interval.closed(1, 3)) assert not Interval.point(3).intersects(Interval.open(3, 4)) assert not Interval.point(3).intersects(Interval.open(1, 3)) assert Interval.closed(1, 3).intersects(Interval.closed(0, 1)) assert not Interval.closed(1, 3).intersects(Interval.open(0, 1)) assert not Interval.open(1, 3).intersects(Interval.closed(0, 1)) assert not Interval.closed(1, 3).intersects(Interval.closed(4, 5)) assert not Interval.closed(1, 3).intersects(Interval.closed(-2, 0)) assert not Interval.closed(1, 3).intersects(Interval.empty()) assert Interval.closed(1, 3).intersects(Interval.infinite()) assert not Interval.point(1).intersects(Interval.open_closed(1, 2))
def __init__(self, func, start=True, end=True, uniform=True, raise_on_empty=False, min_step=MIN_STEP): super().__init__(min_step=min_step) self.curve = Curve.parse(func) if self.curve.domain.is_negative_infinite: start = False if self.curve.domain.is_positive_infinite: end = False self.start = start self.end = end self.start_valid = True self.end_valid = True self.uniform = uniform self.raise_on_empty = raise_on_empty self.extension_interval = Interval.empty() self._extension_stale = True self._extension_interval_stale = True self.curve.add_observer(begin=self.begin_extension_update, end=self.end_extension_update, prioritize=True) self.start_func = None self.end_func = None if self.start: self.start_func = self.create_extension_func(start=True) self.start_func.add_observer(self, begin=self.begin_update, end=self.end_update) if self.end: self.end_func = self.create_extension_func(start=False) self.end_func.add_observer(self, begin=self.begin_update, end=self.end_update)
def get_domain(self): if len(self._points) == 0: return Interval.empty() return Interval(self._points[0][0], self._points[-1][0], start_open=False, end_open=False)
def _did_update_extremas(self): self.possible_extrema = None self.possible_extrema_phase = None if len(self.extremas) == 0: self.extrema_interval = Interval.empty() else: self.extrema_interval = Interval(self.extrema_xs[0], self.extrema_xs[-1], start_open=False, end_open=False)
def get_range(self, domain=None, **kwargs): points = self.sample_points(domain=domain, **kwargs) low = None high = None for p in points: if low is None or p[1] < low: low = p[1] if high is None or p[1] > high: high = p[1] if low is None or high is None: return Interval.empty() return Interval(low, high)
def __init__(self, func, ref_func, min_deviation=0, min_step=MIN_STEP): self.ref_func = Curve.parse(ref_func) self.min_deviation = abs(min_deviation) self.extremas = [] self.extrema_xs = [] self.extrema_interval = Interval.empty() self.possible_extrema = None self.possible_extrema_phase = None self._did_update_extremas() super().__init__(func, self._extrema_scan, min_step=min_step) self._ref_observer_token = self.ref_func.add_observer( begin=self.begin_update, end=self.end_update)
def get_domain(self): d = self.curve.domain if d.is_empty: return Interval.empty() if self.period is not None: x = self.curve.x_previous(d.start + self.period, min_step=self.min_step) if x is None: p = self.period else: p = x - d.start elif self.degree is not None: x = d.start for _ in range(self.degree - 1): x = self.curve.x_next(x, min_step=self.min_step) if x is None: return Interval.empty() p = x - d.start else: raise Exception('Bad SMA configuration') d_start = d.start + p if math.isnan(d_start) or d_start > d.end: return Interval.empty() return Interval.closed(d_start, d.end)
def update_interval(self): len_trend_points = len(self.trend_points) if self._line is None: if len_trend_points == 1: self.search_interval = Interval.point(self.trend_points[0][0]) else: self.search_interval = Interval.empty() return p0, p1 = self._line if p0[0] == p1[0]: # vertical line self.search_interval = Interval.point(p0[0]) return if self.search_length_rel <= 0: self.search_interval = Interval.closed(p0[0], p1[0]) return x_min = p0[0] x_max = p1[0] intersection = self.intersections[0] if len( self.intersections) != 0 else None if intersection is not None and intersection[0] <= x_min: intersection = None if intersection is None or len_trend_points >= self.min_points: # search ahead x_length = (x_max - x_min) * self.search_length_rel else: # not enought points to go through intersection x_length = intersection[0] - x_min # if intersection is None: # # search ahead # x_length = (x_max - x_min) * self.search_length_rel # elif len_trend_points >= self.min_points: # # search ahead of intersection # x_length = (intersection[0] - x_min) * self.search_length_int_rel # else: # # not enought points to go through intersection # x_length = intersection[0] - x_min x_max = x_min + x_length self.search_interval = Interval.closed_open(x_min, x_max)
def pad(self, interval, start=0, end=0, start_open=False) -> Interval: """ Appends calendar lengths to the start and end of a interval. """ interval = self.span_interval(interval, start_open=start_open) if interval.is_empty: return Interval.empty() l = interval.start if not interval.is_negative_infinite: l = self.step(l, count=start, backward=True) h = interval.end if not interval.is_positive_infinite: h = self.step(h, count=end) return Interval(l, h, start_open=start_open, end_open=not start_open)
def test_extensions(): d = Interval(1, 3) assert d.get_lte().equals(Interval.lte(3)) assert d.get_gte().equals(Interval.gte(1)) assert d.get_lt().equals(Interval.lt(1)) assert d.get_gt().equals(Interval.gt(3)) d = Interval.open(1, 3) assert d.get_lte().equals(Interval.lt(3)) assert d.get_gte().equals(Interval.gt(1)) assert d.get_lt().equals(Interval.lte(1)) assert d.get_gt().equals(Interval.gte(3)) d = Interval.empty() assert d.get_lte().is_empty assert d.get_gte().is_empty assert d.get_lt().is_empty assert d.get_gt().is_empty
def _update_extension_interval(self): if not self._extension_interval_stale: return self._extension_interval_stale = False if self._extension_stale: self._update_extension_if_needed() if self.start and self.start_valid and self.end and self.end_valid: self.extension_interval = Interval.union([self.start_func.domain, self.end_func.domain]) elif self.start and self.start_valid: self.extension_interval = Interval.intersection([self.start_func.domain, self.curve.domain.get_lt()]) elif self.end and self.end_valid: self.extension_interval = Interval.intersection([self.end_func.domain, self.curve.domain.get_gt()]) else: self.extension_interval = Interval.empty() self.update_extension_interval() if (self.start and not self.extension_interval.is_negative_infinite) or (self.end and not self.extension_interval.is_positive_infinite): if self.raise_on_empty: raise Exception('Unable to extend func')
def _offset_interval(self, domain, floor=False): start = self._offset_x(domain.start, floor=floor) end = self._offset_x(domain.end, floor=floor) if start is None and end is None: return Interval.empty() elif start is None: return Interval(start, end, start_open=False, end_open=domain.end_open) elif end is None: return Interval(start, end, start_open=domain.start_open, end_open=False) else: return Interval(start, end, start_open=domain.start_open, end_open=domain.end_open)
def test_cast(): assert bool(Interval.empty()) is False assert bool(Interval(0, 0)) is True assert list(Interval.empty()) == [] assert list(Interval(0, 0)) == [0, 0] assert list(Interval.open(1, 20)) == [1, 20]
def get_domain(self): return Interval.empty()
def list_domain(cls, quotes): if len(quotes) == 0: return Interval.empty() return Interval.union([quotes[0].domain, quotes[-1].domain])
def test_intersection_inf(): assert Interval.intersection([Interval.gte(100), (98, 101)]) == (100, 101) assert Interval.intersection([Interval.point(100), Interval.open_closed(100, 101)]) == Interval.empty()
def test_intersection(): # closed, closed d1 = Interval(0, 2, start_open=False, end_open=False) d2 = Interval(1, 3, start_open=False, end_open=False) assert d1.contains(0) assert d1.contains(1) assert d1.contains(2) d = Interval.intersection([d1, d2]) assert d.start == 1 assert d.end == 2 assert not d.start_open assert not d.end_open d = Interval.union([d1, d2]) assert d.start == 0 assert d.end == 3 assert not d.start_open assert not d.end_open # closed, open d1 = Interval(0, 2, start_open=False, end_open=False) d2 = Interval(1, 3, start_open=True, end_open=True) d = Interval.intersection([d1, d2]) assert d.start == 1 assert d.end == 2 assert d.start_open assert not d.end_open d = Interval.union([d1, d2]) assert d.start == 0 assert d.end == 3 assert not d.start_open assert d.end_open # open, open d1 = Interval(0, 2, start_open=True, end_open=True) d2 = Interval(1, 3, start_open=True, end_open=True) assert not d1.contains(0) assert d1.contains(1) assert not d1.contains(2) d = Interval.intersection([d1, d2]) assert d.start == 1 assert d.end == 2 assert d.start_open assert d.end_open d = Interval.union([d1, d2]) assert d.start == 0 assert d.end == 3 assert d.start_open assert d.end_open d = Interval.intersection([Interval(0, 1), Interval(2, 3)]) assert d.is_empty d = Interval.intersection([Interval(0, 1, end_open=True), Interval(1, 3, start_open=True)]) assert d.is_empty d = Interval.intersection([Interval(0, 1), Interval.empty()]) assert d.is_empty d = Interval.union([Interval.empty(), 1]) assert d.start == 1 assert d.end == 1