Skip to content
Snippets Groups Projects
utils.py 2.52 KiB
Newer Older
markn92's avatar
markn92 committed
"""Holding the queue structure for unsettled Labels."""
markn92's avatar
markn92 committed
from typing import Any, Dict, List
markn92's avatar
markn92 committed

from evrouting.utils import PriorityQueue
markn92's avatar
markn92 committed
from evrouting.T import SoC, Time
markn92's avatar
markn92 committed
from evrouting.charge.T import Label, SoCFunction
from evrouting.charge.factories import SoCFunctionFactory
markn92's avatar
markn92 committed


class LabelPriorityQueue(PriorityQueue):
markn92's avatar
markn92 committed
    """
    Implementation of a variant of priority queue to store the
    ***unsettled*** labels of a vertex and efficiently extract
    the minimum label in the algorithm.

    The priority of a label is the minimum feasible time of it's
    according SoC Function. Tie breaker is the SoC at this time.

    It maintains the invariant:

        The queue is empty or the SoC Function of the minimum label
        is not dominated by any SoC Function of a ***settled*** label.

    """

markn92's avatar
markn92 committed
    def __init__(self, f_soc: SoCFunctionFactory, l_set: List[Label]):
markn92's avatar
markn92 committed
        """
        :param f_soc: SoC Function Factory to create SoC Functions of
            inserted labels for testing the invariant.
        :param l_set: Set of settled labels.
        """
markn92's avatar
markn92 committed
        super().__init__()
markn92's avatar
markn92 committed
        self.f_soc_factory: SoCFunctionFactory = f_soc
markn92's avatar
markn92 committed
        self.l_set: List[Label] = l_set
markn92's avatar
markn92 committed

    def insert(self, label: Label):
markn92's avatar
markn92 committed
        """Breaking ties with lowest soc at t_min."""
markn92's avatar
markn92 committed
        super().insert(item=label, **self.keys(self.f_soc_factory(label)))
markn92's avatar
markn92 committed

markn92's avatar
markn92 committed
        # If the minimum element has changed, check the invariant.
markn92's avatar
markn92 committed
        if self.peak_min() == label:
            self.dominance_check()

    def delete_min(self) -> Any:
markn92's avatar
markn92 committed
        """Delete and check the invariant."""
markn92's avatar
markn92 committed
        min_label = super().delete_min()
        self.dominance_check()
        return min_label

    def dominance_check(self):
markn92's avatar
markn92 committed
        """
        Compare the SoC Function of the minimum label with all
        SoC Functions of the already settled labels. If any settled label
        dominates the minimum label, the minimum label is removed, since
        it cannot lead to a better solution.
        """
markn92's avatar
markn92 committed
        try:
            label: Label = self.peak_min()
        except KeyError:
            return

        soc: SoCFunction = self.f_soc_factory(label)
markn92's avatar
markn92 committed

        # Remove item if it gets dominated by any label in l_set
        if any(self.f_soc_factory(label).dominates(soc) for label in self.l_set):
markn92's avatar
markn92 committed
            self.remove_item(label)
markn92's avatar
markn92 committed

markn92's avatar
markn92 committed
    @staticmethod
    def keys(f_soc: SoCFunction) -> Dict:
        """Return the keys for insertion. See class description."""
        t_min: Time = f_soc.minimum
        soc_min: SoC = f_soc(t_min)
        return {'priority': t_min, 'count': soc_min}