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))
T = ~T

A generic type to ensure type consistency for all the container classes.

class FringeContainer(abc.ABC, typing.Generic[~T]):
 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).

def is_empty(self) -> bool:
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.

@abc.abstractmethod
def push(self, item: ~T) -> None:
32    @abc.abstractmethod
33    def push(self, item: T) -> None:
34        """ Add an item to this container. """

Add an item to this container.

@abc.abstractmethod
def pop(self) -> ~T:
36    @abc.abstractmethod
37    def pop(self) -> T:
38        """ Remove the next item from this container. """

Remove the next item from this container.

class Stack(pacai.util.containers.FringeContainer[~T]):
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) .

def push(self, item: ~T) -> None:
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.

def pop(self) -> ~T:
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
FringeContainer
is_empty
class Queue(pacai.util.containers.FringeContainer[~T]):
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) .

def push(self, item: ~T) -> None:
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.

def pop(self) -> ~T:
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
FringeContainer
is_empty
class PriorityQueue(pacai.util.containers.FringeContainer[~T]):
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.

def push(self, item: ~T, priority: float) -> None:
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.

def pop(self) -> ~T:
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
FringeContainer
is_empty
@typing.runtime_checkable
class PriorityFunction(typing.Protocol):
 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.

PriorityFunction(*args, **kwargs)
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)
class PriorityQueueWithFunction(pacai.util.containers.PriorityQueue[~T]):
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.

PriorityQueueWithFunction(priority_func: PriorityFunction)
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. """
def push(self, item: ~T) -> None:
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