def pythagorean_triples(n=None): """Generate n Pythagorean triples ordered by the value of c ascending. If n is None or not given, generate infinitly. Default is None. Examples: >>> list(pythagorean_triples(5)) [(3, 4, 5), (5, 12, 13), (15, 8, 17), (7, 24, 25), (21, 20, 29)] """ iterator = _count() if n is None else range(n) iterator = iter(iterator) base_mat = ((1, 2, 2), (2, 1, 2), (2, 2, 3)) multiplier = ((1, -1, 1), (1, 1, 1), (-1, 1, 1)) matrices = [] for multip in multiplier: mat = [] for row, elem in zip(base_mat, multip): mat.append(tuple(map(lambda e: e * elem, row))) matrices.append(tuple(mat)) matrices = tuple(matrices) heap = [(5, (3, 4, 5))] for i in iterator: _, triple = _heappop(heap) yield triple for matrix in matrices: next_triple = tuple(map(lambda col: sum(_starmap(_mul, zip(triple, col))), zip(*matrix))) _heappush(heap, (next_triple[2], next_triple))
def schedule_interval_soft(self, func, interval, *args, **kwargs): """Schedule a function to be called every ``interval`` seconds. This method is similar to `schedule_interval`, except that the clock will move the interval out of phase with other scheduled functions so as to distribute CPU more load evenly over time. This is useful for functions that need to be called regularly, but not relative to the initial start time. :py:mod:`pyglet.media` does this for scheduling audio buffer updates, which need to occur regularly -- if all audio updates are scheduled at the same time (for example, mixing several tracks of a music score, or playing multiple videos back simultaneously), the resulting load on the CPU is excessive for those intervals but idle outside. Using the soft interval scheduling, the load is more evenly distributed. Soft interval scheduling can also be used as an easy way to schedule graphics animations out of phase; for example, multiple flags waving in the wind. .. versionadded:: 1.1 :Parameters: `func` : callable The function to call when the timer lapses. `interval` : float The number of seconds to wait between each call. """ next_ts = self._get_soft_next_ts(self._get_nearest_ts(), interval) last_ts = next_ts - interval item = _ScheduledIntervalItem(func, interval, last_ts, next_ts, args, kwargs) _heappush(self._schedule_interval_items, item)
def _n_nearest_items(self, n: int, point: _Point) -> _List[_Item]: candidates = [] # type: _List[_Tuple[_Scalar, _Item]] queue = [self._root] push, pop = queue.append, queue.pop while queue: node = pop() # type: _Node distance_to_point = node.distance_to_point(point) candidate = -distance_to_point, node.item if len(candidates) < n: _heappush(candidates, candidate) elif distance_to_point < -candidates[0][0]: _heapreplace(candidates, candidate) coordinate = node.projector(point) point_is_on_the_left = coordinate < node.projection if point_is_on_the_left: if node.left is not _NIL: push(node.left) elif node.right is not _NIL: push(node.right) if (len(candidates) < n or (node.distance_to_coordinate(coordinate) < -candidates[0][0])): if point_is_on_the_left: if node.right is not _NIL: push(node.right) elif node.left is not _NIL: push(node.left) return [item for _, item in candidates]
def _n_nearest_items(self, n: int, point: _Point) -> _Iterator[_Item]: queue = [(0, 0, self._root)] while n and queue: _, _, node = _heappop(queue) for child in node.children: _heappush(queue, (child.distance_to_point(point), -child.index - 1 if child.is_leaf else child.index, child)) while n and queue and queue[0][1] < 0: _, _, node = _heappop(queue) yield node.item n -= 1
def schedule_once(self, func, delay, *args, **kwargs): """Schedule a function to be called once after `delay` seconds. The callback function prototype is the same as for `schedule`. :Parameters: `func` : callable The function to call when the timer lapses. `delay` : float The number of seconds to wait before the timer lapses. """ last_ts = self._get_nearest_ts() next_ts = last_ts + delay item = _ScheduledIntervalItem(func, 0, last_ts, next_ts, args, kwargs) _heappush(self._schedule_interval_items, item)
def nearest_item(self, point: _Point) -> _Item: """ Searches for index with box in the tree the nearest to the given point. Time complexity: ``O(max_children * log size)`` Memory complexity: ``O(max_children * log size)`` where ``size = len(self.boxes)``, ``max_children = self.max_children``. :param point: input point. :returns: index with box in the tree the nearest to the input point. >>> from ground.base import get_context >>> context = get_context() >>> Box, Point = context.box_cls, context.point_cls >>> boxes = [Box(-index, index, 0, index) for index in range(1, 11)] >>> tree = Tree(boxes) >>> tree.nearest_item(Point(0, 0)) == (9, Box(-10, 10, 0, 10)) True >>> tree.nearest_item(Point(-10, 0)) == (9, Box(-10, 10, 0, 10)) True >>> tree.nearest_item(Point(-10, 10)) == (9, Box(-10, 10, 0, 10)) True >>> tree.nearest_item(Point(10, 0)) == (9, Box(-10, 10, 0, 10)) True >>> tree.nearest_item(Point(10, 10)) == (9, Box(-10, 10, 0, 10)) True """ queue = [(0, 0, self._root)] while queue: _, _, node = _heappop(queue) for child in node.children: _heappush(queue, (child.distance_to_point(point), -child.index - 1 if child.is_leaf else child.index, child)) if queue and queue[0][1] < 0: _, _, node = _heappop(queue) return node.item
def schedule_interval(self, func, interval, *args, **kwargs): """Schedule a function to be called every `interval` seconds. Specifying an interval of 0 prevents the function from being called again (see `schedule` to call a function as often as possible). The callback function prototype is the same as for `schedule`. :Parameters: `func` : callable The function to call when the timer lapses. `interval` : float The number of seconds to wait between each call. """ last_ts = self._get_nearest_ts() next_ts = last_ts + interval item = _ScheduledIntervalItem(func, interval, last_ts, next_ts, args, kwargs) _heappush(self._schedule_interval_items, item)
def nearest_to_point_item(self, point: _Point) -> _Item: """ Searches for index with segment in the tree the nearest to the given point. Time complexity: ``O(max_children * log size)`` Memory complexity: ``O(max_children * log size)`` where ``size = len(self.segments)``, ``max_children = self.max_children``. :param point: input point. :returns: index with segment in the tree the nearest to the input point. >>> from ground.base import get_context >>> context = get_context() >>> Point, Segment = context.point_cls, context.segment_cls >>> segments = [Segment(Point(0, index), Point(index, index)) ... for index in range(1, 11)] >>> tree = Tree(segments) >>> (tree.nearest_to_point_item(Point(0, 0)) ... == (0, Segment(Point(0, 1), Point(1, 1)))) True """ queue = [(0, 0, self._root)] while queue: _, _, node = _heappop(queue) for child in node.children: _heappush(queue, (child.distance_to_point(point), child.index if child.is_leaf else -child.index - 1, child)) if queue and queue[0][1] >= 0: _, _, node = _heappop(queue) return node.item
def _put(self, item): _heappush(self.queue, item)
def call_scheduled_functions(self, dt): """Call scheduled functions that elapsed on the last `update_time`. .. versionadded:: 1.2 :Parameters: dt : float The elapsed time since the last update to pass to each scheduled function. This is *not* used to calculate which functions have elapsed. :rtype: bool :return: True if any functions were called, otherwise False. """ now = self.last_ts result = False # flag indicates if any function was called # handle items scheduled for every tick if self._schedule_items: result = True # duplicate list in case event unschedules itself for item in list(self._schedule_items): item.func(dt, *item.args, **item.kwargs) # check the next scheduled item that is not called each tick # if it is scheduled in the future, then exit interval_items = self._schedule_interval_items try: if interval_items[0].next_ts > now: return result # raised when the interval_items list is empty except IndexError: return result # NOTE: there is no special handling required to manage things # that are scheduled during this loop, due to the heap self._current_interval_item = item = None get_soft_next_ts = self._get_soft_next_ts while interval_items: # the scheduler will hold onto a reference to an item in # case it needs to be rescheduled. it is more efficient # to push and pop the heap at once rather than two operations if item is None: item = _heappop(interval_items) else: item = _heappushpop(interval_items, item) # a scheduled function may try and unschedule itself # so we need to keep a reference to the current # item no longer on heap to be able to check self._current_interval_item = item # if next item is scheduled in the future then break if item.next_ts > now: break # execute the callback try: item.func(now - item.last_ts, *item.args, **item.kwargs) except ReferenceError: pass # weakly-referenced object no longer exists. if item.interval: # Try to keep timing regular, even if overslept this time; # but don't schedule in the past (which could lead to # infinitely-worsening error). item.next_ts = item.last_ts + item.interval item.last_ts = now # test the schedule for the next execution if item.next_ts <= now: # the scheduled time of this item has already passed # so it must be rescheduled if now - item.next_ts < 0.05: # missed execution time by 'reasonable' amount, so # reschedule at normal interval item.next_ts = now + item.interval else: # missed by significant amount, now many events have # likely missed execution. do a soft reschedule to # avoid lumping many events together. # in this case, the next dt will not be accurate item.next_ts = get_soft_next_ts(now, item.interval) item.last_ts = item.next_ts - item.interval else: # not an interval, so this item will not be rescheduled self._current_interval_item = item = None if item is not None: _heappush(interval_items, item) return True