pacai.util.containers
1import abc 2import heapq 3import typing 4 5T = typing.TypeVar('T') 6""" A generic type to ensure type consistency for all the container classes. """ 7 8class FringeContainer(abc.ABC, typing.Generic[T]): 9 """ 10 A generic container base class that is useful for a search fringe 11 (but can be used for any sort of storage). 12 """ 13 14 def __init__(self) -> None: 15 self._items: list[T] = [] 16 """ 17 The underlying storage for our container's items. 18 We can just use a normal list as long as we are careful about how we work with it. 19 """ 20 21 def is_empty(self) -> bool: 22 """ Returns True if the container is empty. """ 23 24 return (len(self._items) == 0) 25 26 def __len__(self) -> int: 27 """ Override the len() operator to get the size of the container. """ 28 29 return len(self._items) 30 31 @abc.abstractmethod 32 def push(self, item: T) -> None: 33 """ Add an item to this container. """ 34 35 @abc.abstractmethod 36 def pop(self) -> T: 37 """ Remove the next item from this container. """ 38 39class Stack(FringeContainer[T]): 40 """ 41 A container with a last-in-first-out (LIFO) queuing policy. 42 See https://en.wikipedia.org/wiki/Stack_(abstract_data_type) . 43 """ 44 45 def push(self, item: T) -> None: 46 """ Push an item onto the stack. """ 47 48 self._items.append(item) 49 50 def pop(self) -> T: 51 """ Pop the most recently pushed item from the stack. """ 52 53 return self._items.pop() 54 55class Queue(FringeContainer[T]): 56 """ 57 A container with a first-in-first-out (FIFO) queuing policy. 58 See: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) . 59 """ 60 61 def push(self, item: T) -> None: 62 """ Enqueue the item into the queue. """ 63 64 self._items.insert(0, item) 65 66 def pop(self) -> T: 67 """ Dequeue the earliest enqueued item still in the queue. """ 68 69 return self._items.pop() 70 71class PriorityQueue(FringeContainer[T]): 72 """ 73 A container with a queuing policy that prioritizes objects with lower priority.. 74 See: https://en.wikipedia.org/wiki/Priority_queue . 75 76 Each inserted item has a priority associated with it, 77 and the user is usually interested in quick retrieval of the lowest-priority item in the queue. 78 This data structure allows O(1) access to the lowest-priority item. 79 80 Note that this PriorityQueue does not allow you to change the priority of an item. 81 However, you may insert the same item multiple times with different priorities. 82 """ 83 84 def push(self, item: T, priority: float) -> None: # type: ignore # pylint: disable=arguments-differ 85 """ Enqueue the item into the priority queue. """ 86 87 pair = (priority, item) 88 heapq.heappush(self._items, pair) # type: ignore 89 90 def pop(self) -> T: 91 """ Dequeue the earliest enqueued item still in the priority queue. """ 92 93 (_, item) = heapq.heappop(self._items) # type: ignore 94 return item # type: ignore 95 96@typing.runtime_checkable 97class PriorityFunction(typing.Protocol): 98 """ 99 A function that assigns a priority value to an object being inserted into the priority queue. 100 """ 101 102 def __call__(self, item: typing.Any) -> float: 103 ... 104 105class PriorityQueueWithFunction(PriorityQueue[T]): 106 """ 107 Implements a priority queue with the same push/pop signature of the Queue and the Stack classes. 108 This is designed for drop-in replacement for those two classes. 109 The caller has to provide a priority function, which extracts each item's priority. 110 """ 111 112 def __init__(self, priority_func: PriorityFunction) -> None: 113 super().__init__() 114 115 self._priority_func: PriorityFunction = priority_func 116 """ The function to get a priority for each item in this container. """ 117 118 def push(self, item: T) -> None: # type: ignore # pylint: disable=arguments-differ 119 """ 120 Adds an item to the queue with priority from the priority function 121 """ 122 123 super().push(item, self._priority_func(item))
A generic type to ensure type consistency for all the container classes.
9class FringeContainer(abc.ABC, typing.Generic[T]): 10 """ 11 A generic container base class that is useful for a search fringe 12 (but can be used for any sort of storage). 13 """ 14 15 def __init__(self) -> None: 16 self._items: list[T] = [] 17 """ 18 The underlying storage for our container's items. 19 We can just use a normal list as long as we are careful about how we work with it. 20 """ 21 22 def is_empty(self) -> bool: 23 """ Returns True if the container is empty. """ 24 25 return (len(self._items) == 0) 26 27 def __len__(self) -> int: 28 """ Override the len() operator to get the size of the container. """ 29 30 return len(self._items) 31 32 @abc.abstractmethod 33 def push(self, item: T) -> None: 34 """ Add an item to this container. """ 35 36 @abc.abstractmethod 37 def pop(self) -> T: 38 """ Remove the next item from this container. """
A generic container base class that is useful for a search fringe (but can be used for any sort of storage).
22 def is_empty(self) -> bool: 23 """ Returns True if the container is empty. """ 24 25 return (len(self._items) == 0)
Returns True if the container is empty.
40class Stack(FringeContainer[T]): 41 """ 42 A container with a last-in-first-out (LIFO) queuing policy. 43 See https://en.wikipedia.org/wiki/Stack_(abstract_data_type) . 44 """ 45 46 def push(self, item: T) -> None: 47 """ Push an item onto the stack. """ 48 49 self._items.append(item) 50 51 def pop(self) -> T: 52 """ Pop the most recently pushed item from the stack. """ 53 54 return self._items.pop()
A container with a last-in-first-out (LIFO) queuing policy. See https://en.wikipedia.org/wiki/Stack_(abstract_data_type) .
46 def push(self, item: T) -> None: 47 """ Push an item onto the stack. """ 48 49 self._items.append(item)
Push an item onto the stack.
51 def pop(self) -> T: 52 """ Pop the most recently pushed item from the stack. """ 53 54 return self._items.pop()
Pop the most recently pushed item from the stack.
Inherited Members
56class Queue(FringeContainer[T]): 57 """ 58 A container with a first-in-first-out (FIFO) queuing policy. 59 See: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) . 60 """ 61 62 def push(self, item: T) -> None: 63 """ Enqueue the item into the queue. """ 64 65 self._items.insert(0, item) 66 67 def pop(self) -> T: 68 """ Dequeue the earliest enqueued item still in the queue. """ 69 70 return self._items.pop()
A container with a first-in-first-out (FIFO) queuing policy. See: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) .
62 def push(self, item: T) -> None: 63 """ Enqueue the item into the queue. """ 64 65 self._items.insert(0, item)
Enqueue the item into the queue.
67 def pop(self) -> T: 68 """ Dequeue the earliest enqueued item still in the queue. """ 69 70 return self._items.pop()
Dequeue the earliest enqueued item still in the queue.
Inherited Members
72class PriorityQueue(FringeContainer[T]): 73 """ 74 A container with a queuing policy that prioritizes objects with lower priority.. 75 See: https://en.wikipedia.org/wiki/Priority_queue . 76 77 Each inserted item has a priority associated with it, 78 and the user is usually interested in quick retrieval of the lowest-priority item in the queue. 79 This data structure allows O(1) access to the lowest-priority item. 80 81 Note that this PriorityQueue does not allow you to change the priority of an item. 82 However, you may insert the same item multiple times with different priorities. 83 """ 84 85 def push(self, item: T, priority: float) -> None: # type: ignore # pylint: disable=arguments-differ 86 """ Enqueue the item into the priority queue. """ 87 88 pair = (priority, item) 89 heapq.heappush(self._items, pair) # type: ignore 90 91 def pop(self) -> T: 92 """ Dequeue the earliest enqueued item still in the priority queue. """ 93 94 (_, item) = heapq.heappop(self._items) # type: ignore 95 return item # type: ignore
A container with a queuing policy that prioritizes objects with lower priority.. See: https://en.wikipedia.org/wiki/Priority_queue .
Each inserted item has a priority associated with it, and the user is usually interested in quick retrieval of the lowest-priority item in the queue. This data structure allows O(1) access to the lowest-priority item.
Note that this PriorityQueue does not allow you to change the priority of an item. However, you may insert the same item multiple times with different priorities.
85 def push(self, item: T, priority: float) -> None: # type: ignore # pylint: disable=arguments-differ 86 """ Enqueue the item into the priority queue. """ 87 88 pair = (priority, item) 89 heapq.heappush(self._items, pair) # type: ignore
Enqueue the item into the priority queue.
91 def pop(self) -> T: 92 """ Dequeue the earliest enqueued item still in the priority queue. """ 93 94 (_, item) = heapq.heappop(self._items) # type: ignore 95 return item # type: ignore
Dequeue the earliest enqueued item still in the priority queue.
Inherited Members
97@typing.runtime_checkable 98class PriorityFunction(typing.Protocol): 99 """ 100 A function that assigns a priority value to an object being inserted into the priority queue. 101 """ 102 103 def __call__(self, item: typing.Any) -> float: 104 ...
A function that assigns a priority value to an object being inserted into the priority queue.
1953def _no_init_or_replace_init(self, *args, **kwargs): 1954 cls = type(self) 1955 1956 if cls._is_protocol: 1957 raise TypeError('Protocols cannot be instantiated') 1958 1959 # Already using a custom `__init__`. No need to calculate correct 1960 # `__init__` to call. This can lead to RecursionError. See bpo-45121. 1961 if cls.__init__ is not _no_init_or_replace_init: 1962 return 1963 1964 # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`. 1965 # The first instantiation of the subclass will call `_no_init_or_replace_init` which 1966 # searches for a proper new `__init__` in the MRO. The new `__init__` 1967 # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent 1968 # instantiation of the protocol subclass will thus use the new 1969 # `__init__` and no longer call `_no_init_or_replace_init`. 1970 for base in cls.__mro__: 1971 init = base.__dict__.get('__init__', _no_init_or_replace_init) 1972 if init is not _no_init_or_replace_init: 1973 cls.__init__ = init 1974 break 1975 else: 1976 # should not happen 1977 cls.__init__ = object.__init__ 1978 1979 cls.__init__(self, *args, **kwargs)
106class PriorityQueueWithFunction(PriorityQueue[T]): 107 """ 108 Implements a priority queue with the same push/pop signature of the Queue and the Stack classes. 109 This is designed for drop-in replacement for those two classes. 110 The caller has to provide a priority function, which extracts each item's priority. 111 """ 112 113 def __init__(self, priority_func: PriorityFunction) -> None: 114 super().__init__() 115 116 self._priority_func: PriorityFunction = priority_func 117 """ The function to get a priority for each item in this container. """ 118 119 def push(self, item: T) -> None: # type: ignore # pylint: disable=arguments-differ 120 """ 121 Adds an item to the queue with priority from the priority function 122 """ 123 124 super().push(item, self._priority_func(item))
Implements a priority queue with the same push/pop signature of the Queue and the Stack classes. This is designed for drop-in replacement for those two classes. The caller has to provide a priority function, which extracts each item's priority.
119 def push(self, item: T) -> None: # type: ignore # pylint: disable=arguments-differ 120 """ 121 Adds an item to the queue with priority from the priority function 122 """ 123 124 super().push(item, self._priority_func(item))
Adds an item to the queue with priority from the priority function