Beispiel #1
0
 def __init__(self, graph, start_vertex):
     self._edge_to = {}
     self._dist_to = dict(
         (vertex, 999999999) for vertex in graph.vertices())
     self._marked = defaultdict(bool)
     self._pq = IndexMinPQ(graph.vertices_size())
     self._dist_to[start_vertex] = 0
     self._pq.insert(start_vertex, 0.0)
     while len(self._pq) != 0:
         self.visit(graph, self._pq.delete_min())
    def __init__(self, graph, source):
        self._dist_to = dict(
            (v, INFINITE_POSITIVE_NUMBER) for v in graph.vertices())
        self._dist_to[source] = 0
        self._edge_to = {source: None}
        self._pq = IndexMinPQ(graph.vertices_size())
        self._pq.insert(source, 0)

        while not self._pq.is_empty():
            self.relax(graph, self._pq.delete_min())
class DijkstraSP(ShortestPath):
    """
      Dijkstra Shortest Path algorithm. First reach the source vertex, 'relax' all the adjacent
    edges of the source vertex, and then put all 'relaxed' edges into the priority queue or
    change the distance from the priority queue util the priority queue is empty. The cost of
    running time is proportional to O(ElogV), and the cost of the space is proportional to O(V).
    This algorithm is not applied to the graph with NEGATIVE edges. The worst case still has good
    performance.
    >>> test_data = ((4, 5, 0.35), (5, 4, 0.35), (4, 7, 0.37), (5, 7, 0.28), (7, 5, 0.28),
    ...              (5, 1, 0.32), (0, 4, 0.38), (0, 2, 0.26), (7, 3, 0.39), (1, 3, 0.29),
    ...              (2, 7, 0.34), (6, 2, 0.4), (3, 6, 0.52), (6, 0, 0.58), (6, 4, 0.93))
    >>> ewd = EdgeWeightedDigraph()
    >>> for a, b, weight in test_data:
    ...     edge = DirectedEdge(a, b, weight)
    ...     ewd.add_edge(edge)
    ...
    >>> sp = DijkstraSP(ewd, 0)
    >>> [sp.has_path_to(i) for i in range(1, 8)]
    [True, True, True, True, True, True, True]
    >>> [sp.dist_to(i) for i in range(1, 8)]
    [1.05, 0.26, 0.99, 0.38, 0.73, 1.51, 0.6]
    >>> pprint.pprint([[edge for edge in sp.path_to(i)] for i in range(1, 8)])
    [[0->4 0.38, 4->5 0.35, 5->1 0.32],
     [0->2 0.26],
     [0->2 0.26, 2->7 0.34, 7->3 0.39],
     [0->4 0.38],
     [0->4 0.38, 4->5 0.35],
     [0->2 0.26, 2->7 0.34, 7->3 0.39, 3->6 0.52],
     [0->2 0.26, 2->7 0.34]]
    """
    def __init__(self, graph, source):
        self._dist_to = dict(
            (v, INFINITE_POSITIVE_NUMBER) for v in graph.vertices())
        self._edge_to = {}
        self._pq = IndexMinPQ(graph.vertices_size())
        self._pq.insert(source, 0)
        self._edge_to[source] = None
        self._dist_to[source] = 0

        while not self._pq.is_empty():
            self.relax(graph, self._pq.delete_min())

    def relax(self, graph, vertex):
        for edge in graph.adjacent_edges(vertex):
            end = edge.end
            if self._dist_to[end] > self._dist_to[vertex] + edge.weight:
                self._dist_to[end] = round(self._dist_to[vertex] + edge.weight,
                                           2)
                self._edge_to[end] = edge

                if self._pq.contains(end):
                    self._pq.change_key(end, self._dist_to[end])
                else:
                    self._pq.insert(end, self._dist_to[end])
class DijkstraSP(ShortestPath):

    """
      Dijkstra Shortest Path algorithm. First reach the source vertex, 'relax' all the adjacent
    edges of the source vertex, and then put all 'relaxed' edges into the priority queue or
    change the distance from the priority queue util the priority queue is empty. The cost of
    running time is proportional to O(ElogV), and the cost of the space is proportional to O(V).
    This algorithm is not applied to the graph with NEGATIVE edges. The worst case still has good
    performance.
    >>> test_data = ((4, 5, 0.35), (5, 4, 0.35), (4, 7, 0.37), (5, 7, 0.28), (7, 5, 0.28),
    ...              (5, 1, 0.32), (0, 4, 0.38), (0, 2, 0.26), (7, 3, 0.39), (1, 3, 0.29),
    ...              (2, 7, 0.34), (6, 2, 0.4), (3, 6, 0.52), (6, 0, 0.58), (6, 4, 0.93))
    >>> ewd = EdgeWeightedDigraph()
    >>> for a, b, weight in test_data:
    ...     edge = DirectedEdge(a, b, weight)
    ...     ewd.add_edge(edge)
    ...
    >>> sp = DijkstraSP(ewd, 0)
    >>> [sp.has_path_to(i) for i in range(1, 8)]
    [True, True, True, True, True, True, True]
    >>> [sp.dist_to(i) for i in range(1, 8)]
    [1.05, 0.26, 0.99, 0.38, 0.73, 1.51, 0.6]
    >>> pprint.pprint([[edge for edge in sp.path_to(i)] for i in range(1, 8)])
    [[0->4 0.38, 4->5 0.35, 5->1 0.32],
     [0->2 0.26],
     [0->2 0.26, 2->7 0.34, 7->3 0.39],
     [0->4 0.38],
     [0->4 0.38, 4->5 0.35],
     [0->2 0.26, 2->7 0.34, 7->3 0.39, 3->6 0.52],
     [0->2 0.26, 2->7 0.34]]
    """

    def __init__(self, graph, source):
        self._dist_to = dict((v, INFINITE_POSITIVE_NUMBER) for v in graph.vertices())
        self._edge_to = {}
        self._pq = IndexMinPQ(graph.vertices_size())
        self._pq.insert(source, 0)
        self._edge_to[source] = None
        self._dist_to[source] = 0

        while not self._pq.is_empty():
            self.relax(graph, self._pq.delete_min())

    def relax(self, graph, vertex):
        for edge in graph.adjacent_edges(vertex):
            end = edge.end
            if self._dist_to[end] > self._dist_to[vertex] + edge.weight:
                self._dist_to[end] = round(self._dist_to[vertex] + edge.weight, 2)
                self._edge_to[end] = edge

                if self._pq.contains(end):
                    self._pq.change_key(end, self._dist_to[end])
                else:
                    self._pq.insert(end, self._dist_to[end])
    def __init__(self, graph, sources):
        tmp = EdgeWeightedDigraph(graph)
        for v in sources:
            tmp.add_edge(DirectedEdge(-1, v, 0))

        self._dist_to = dict(
            (v, INFINITE_POSITIVE_NUMBER) for v in tmp.vertices())
        self._edge_to = {}
        self._pq = IndexMinPQ(tmp.vertices_size())
        self._pq.insert(-1, 0)
        self._edge_to[-1] = None
        self._dist_to[-1] = 0
        self._sources = (i for i in sources)

        while not self._pq.is_empty():
            self.relax(tmp, self._pq.delete_min())
Beispiel #6
0
class PrimMST(object):
    """
      Prim-Minimum-Spanning-Tree instant version. Put the start_vertex and 0 weight into the
    index minimum priority queue. Then check all adjacent vertices, if the adjacent vertex is
    checked before, ignore it; otherwise update the distance between the current vertex and the
    start vertex. The cost of space is proportional to O(V), and the cost of running time is
    proportional to O(ElogV)
    >>> test_data = ((4, 5, 0.35), (4, 7, 0.37), (5, 7, 0.28), (0, 7, 0.16), (1, 5, 0.32),
    ...              (0, 4, 0.38), (2, 3, 0.17), (1, 7, 0.19), (0, 2, 0.26), (1, 2, 0.36),
    ...              (1, 3, 0.29), (2, 7, 0.34), (6, 2, 0.4), (3, 6, 0.52), (6, 0, 0.58),
    ...              (6, 4, 0.93))
    >>> ewg = EdgeWeightedGraph()
    >>> for a, b, weight in test_data:
    ...    edge = Edge(a, b, weight)
    ...    ewg.add_edge(edge)
    ...
    >>> prim_mst = PrimMST(ewg, 0)
    >>> prim_mst.weight()
    1.81
    >>> [edge for edge in prim_mst.edges()]
    [1-7 0.19, 0-2 0.26, 2-3 0.17, 4-5 0.35, 5-7 0.28, 6-2 0.4, 0-7 0.16]
    """
    def __init__(self, graph, start_vertex):
        self._edge_to = {}
        self._dist_to = dict(
            (vertex, 999999999) for vertex in graph.vertices())
        self._marked = defaultdict(bool)
        self._pq = IndexMinPQ(graph.vertices_size())
        self._dist_to[start_vertex] = 0
        self._pq.insert(start_vertex, 0.0)
        while len(self._pq) != 0:
            self.visit(graph, self._pq.delete_min())

    def visit(self, graph, vertex):
        self._marked[vertex] = True
        for edge in graph.adjacent_edges(vertex):
            other_vertex = edge.other(vertex)
            if self._marked[other_vertex]:
                continue
            if edge.weight < self._dist_to[other_vertex]:
                self._edge_to[other_vertex] = edge
                self._dist_to[other_vertex] = edge.weight

                if self._pq.contains(other_vertex):
                    self._pq.change_key(other_vertex,
                                        self._dist_to[other_vertex])
                else:
                    self._pq.insert(other_vertex, self._dist_to[other_vertex])

    # 4.3.21 practice, the code is given in the book.
    def edges(self):
        return self._edge_to.values()

    # 4.3.31 practice
    def weight(self):
        return round(sum(val for val in self._dist_to.values()), 2)
class PrimMST(object):

    """
      Prim-Minimum-Spanning-Tree instant version. Put the start_vertex and 0 weight into the
    index minimum priority queue. Then check all adjacent vertices, if the adjacent vertex is
    checked before, ignore it; otherwise update the distance between the current vertex and the
    start vertex. The cost of space is proportional to O(V), and the cost of running time is
    proportional to O(ElogV)
    >>> test_data = ((4, 5, 0.35), (4, 7, 0.37), (5, 7, 0.28), (0, 7, 0.16), (1, 5, 0.32),
    ...              (0, 4, 0.38), (2, 3, 0.17), (1, 7, 0.19), (0, 2, 0.26), (1, 2, 0.36),
    ...              (1, 3, 0.29), (2, 7, 0.34), (6, 2, 0.4), (3, 6, 0.52), (6, 0, 0.58),
    ...              (6, 4, 0.93))
    >>> ewg = EdgeWeightedGraph()
    >>> for a, b, weight in test_data:
    ...    edge = Edge(a, b, weight)
    ...    ewg.add_edge(edge)
    ...
    >>> prim_mst = PrimMST(ewg, 0)
    >>> prim_mst.weight()
    1.81
    >>> [edge for edge in prim_mst.edges()]
    [1-7 0.19, 0-2 0.26, 2-3 0.17, 4-5 0.35, 5-7 0.28, 6-2 0.4, 0-7 0.16]
    """

    def __init__(self, graph, start_vertex):
        self._edge_to = {}
        self._dist_to = dict((vertex, 999999999) for vertex in graph.vertices())
        self._marked = defaultdict(bool)
        self._pq = IndexMinPQ(graph.vertices_size())
        self._dist_to[start_vertex] = 0
        self._pq.insert(start_vertex, 0.0)
        while len(self._pq) != 0:
            self.visit(graph, self._pq.delete_min())

    def visit(self, graph, vertex):
        self._marked[vertex] = True
        for edge in graph.adjacent_edges(vertex):
            other_vertex = edge.other(vertex)
            if self._marked[other_vertex]:
                continue
            if edge.weight < self._dist_to[other_vertex]:
                self._edge_to[other_vertex] = edge
                self._dist_to[other_vertex] = edge.weight

                if self._pq.contains(other_vertex):
                    self._pq.change_key(other_vertex, self._dist_to[other_vertex])
                else:
                    self._pq.insert(other_vertex, self._dist_to[other_vertex])

    # 4.3.21 practice, the code is given in the book.
    def edges(self):
        return self._edge_to.values()

    # 4.3.31 practice
    def weight(self):
        return round(sum(val for val in self._dist_to.values()), 2)
class DijkstraMatrixSP(ShortestPath):

    """
    >>> test_data = ((4, 5, 0.35), (5, 4, 0.35), (4, 7, 0.37), (5, 7, 0.28), (7, 5, 0.28),
    ...              (5, 1, 0.32), (0, 4, 0.38), (0, 2, 0.26), (7, 3, 0.39), (1, 3, 0.29),
    ...              (2, 7, 0.34), (6, 2, 0.4), (3, 6, 0.52), (6, 0, 0.58), (6, 4, 0.93))
    >>> ewm = EdgeWeightedMatrix()
    >>> for a, b, weight in test_data:
    ...     ewm.add_edge(a, b, weight)
    ...
    >>> sp = DijkstraMatrixSP(ewm, 0)
    >>> [sp.has_path_to(i) for i in range(1, 8)]
    [True, True, True, True, True, True, True]
    >>> [sp.dist_to(i) for i in range(1, 8)]
    [1.05, 0.26, 0.99, 0.38, 0.73, 1.51, 0.6]
    >>> [e for e in sp.path_to(7)]
    [(0, 2, 0.26), (2, 7, 0.34)]
    >>> [e for e in sp.path_to(6)]
    [(0, 2, 0.26), (2, 7, 0.34), (7, 3, 0.39), (3, 6, 0.52)]
    """

    def __init__(self, graph, source):
        self._dist_to = dict((v, INFINITE_POSITIVE_NUMBER) for v in graph.vertices())
        self._dist_to[source] = 0
        self._edge_to = {source: None}
        self._pq = IndexMinPQ(graph.vertices_size())
        self._pq.insert(source, 0)

        while not self._pq.is_empty():
            self.relax(graph, self._pq.delete_min())

    def relax(self, graph, vertex):
        for v, weight in graph.adjacent_edges(vertex).items():
            if self._dist_to[v] > self._dist_to[vertex] + weight:
                self._dist_to[v] = round(self._dist_to[vertex] + weight, 2)
                self._edge_to[v] = (vertex, v, weight)

                if self._pq.contains(v):
                    self._pq.change_key(v, self._dist_to[v])
                else:
                    self._pq.insert(v, self._dist_to[v])

    def path_to(self, vertex):
        if not self.has_path_to(vertex):
            return None
        path = Stack()
        edge = self._edge_to[vertex]
        while edge:
            path.push(edge)
            edge = self._edge_to[edge[0]]
        return path
class DijkstraMatrixSP(ShortestPath):
    """
    >>> test_data = ((4, 5, 0.35), (5, 4, 0.35), (4, 7, 0.37), (5, 7, 0.28), (7, 5, 0.28),
    ...              (5, 1, 0.32), (0, 4, 0.38), (0, 2, 0.26), (7, 3, 0.39), (1, 3, 0.29),
    ...              (2, 7, 0.34), (6, 2, 0.4), (3, 6, 0.52), (6, 0, 0.58), (6, 4, 0.93))
    >>> ewm = EdgeWeightedMatrix()
    >>> for a, b, weight in test_data:
    ...     ewm.add_edge(a, b, weight)
    ...
    >>> sp = DijkstraMatrixSP(ewm, 0)
    >>> [sp.has_path_to(i) for i in range(1, 8)]
    [True, True, True, True, True, True, True]
    >>> [sp.dist_to(i) for i in range(1, 8)]
    [1.05, 0.26, 0.99, 0.38, 0.73, 1.51, 0.6]
    >>> [e for e in sp.path_to(7)]
    [(0, 2, 0.26), (2, 7, 0.34)]
    >>> [e for e in sp.path_to(6)]
    [(0, 2, 0.26), (2, 7, 0.34), (7, 3, 0.39), (3, 6, 0.52)]
    """
    def __init__(self, graph, source):
        self._dist_to = dict(
            (v, INFINITE_POSITIVE_NUMBER) for v in graph.vertices())
        self._dist_to[source] = 0
        self._edge_to = {source: None}
        self._pq = IndexMinPQ(graph.vertices_size())
        self._pq.insert(source, 0)

        while not self._pq.is_empty():
            self.relax(graph, self._pq.delete_min())

    def relax(self, graph, vertex):
        for v, weight in graph.adjacent_edges(vertex).items():
            if self._dist_to[v] > self._dist_to[vertex] + weight:
                self._dist_to[v] = round(self._dist_to[vertex] + weight, 2)
                self._edge_to[v] = (vertex, v, weight)

                if self._pq.contains(v):
                    self._pq.change_key(v, self._dist_to[v])
                else:
                    self._pq.insert(v, self._dist_to[v])

    def path_to(self, vertex):
        if not self.has_path_to(vertex):
            return None
        path = Stack()
        edge = self._edge_to[vertex]
        while edge:
            path.push(edge)
            edge = self._edge_to[edge[0]]
        return path
 def __init__(self, graph, start_vertex):
     self._edge_to = {}
     self._dist_to = dict((vertex, 999999999) for vertex in graph.vertices())
     self._marked = defaultdict(bool)
     self._pq = IndexMinPQ(graph.vertices_size())
     self._dist_to[start_vertex] = 0
     self._pq.insert(start_vertex, 0.0)
     while len(self._pq) != 0:
         self.visit(graph, self._pq.delete_min())
    def __init__(self, graph, source):
        self._dist_to = dict((v, INFINITE_POSITIVE_NUMBER) for v in graph.vertices())
        self._dist_to[source] = 0
        self._edge_to = {source: None}
        self._pq = IndexMinPQ(graph.vertices_size())
        self._pq.insert(source, 0)

        while not self._pq.is_empty():
            self.relax(graph, self._pq.delete_min())
class DijkstraMultipleSourcesSP(ShortestPath):
    """
    >>> test_data = ((4, 5, 0.35), (5, 4, 0.35), (4, 7, 0.37), (5, 7, 0.28), (7, 5, 0.28),
    ...              (5, 1, 0.32), (0, 4, 0.38), (0, 2, 0.26), (7, 3, 0.39), (1, 3, 0.29),
    ...              (2, 7, 0.34), (6, 2, 0.4), (3, 6, 0.52), (6, 0, 0.58), (6, 4, 0.93))
    >>> ewd = EdgeWeightedDigraph()
    >>> for a, b, weight in test_data:
    ...     edge = DirectedEdge(a, b, weight)
    ...     ewd.add_edge(edge)
    ...
    >>> sp = DijkstraMultipleSourcesSP(ewd, (0, 6))
    >>> [sp.has_path_to(i) for i in range(1, 8)]
    [True, True, True, True, True, True, True]
    """
    def __init__(self, graph, sources):
        tmp = EdgeWeightedDigraph(graph)
        for v in sources:
            tmp.add_edge(DirectedEdge(-1, v, 0))

        self._dist_to = dict(
            (v, INFINITE_POSITIVE_NUMBER) for v in tmp.vertices())
        self._edge_to = {}
        self._pq = IndexMinPQ(tmp.vertices_size())
        self._pq.insert(-1, 0)
        self._edge_to[-1] = None
        self._dist_to[-1] = 0
        self._sources = (i for i in sources)

        while not self._pq.is_empty():
            self.relax(tmp, self._pq.delete_min())

    def relax(self, graph, vertex):
        for edge in graph.adjacent_edges(vertex):
            end = edge.end
            if self._dist_to[end] > self._dist_to[vertex] + edge.weight:
                self._dist_to[end] = round(self._dist_to[vertex] + edge.weight,
                                           2)
                self._edge_to[end] = edge

                if self._pq.contains(end):
                    self._pq.change_key(end, self._dist_to[end])
                else:
                    self._pq.insert(end, self._dist_to[end])

    def dist(self, source, dist):
        if source not in self._sources:
            return None
        return self.dist_to(dist)
class DijkstraMultipleSourcesSP(ShortestPath):

    """
    >>> test_data = ((4, 5, 0.35), (5, 4, 0.35), (4, 7, 0.37), (5, 7, 0.28), (7, 5, 0.28),
    ...              (5, 1, 0.32), (0, 4, 0.38), (0, 2, 0.26), (7, 3, 0.39), (1, 3, 0.29),
    ...              (2, 7, 0.34), (6, 2, 0.4), (3, 6, 0.52), (6, 0, 0.58), (6, 4, 0.93))
    >>> ewd = EdgeWeightedDigraph()
    >>> for a, b, weight in test_data:
    ...     edge = DirectedEdge(a, b, weight)
    ...     ewd.add_edge(edge)
    ...
    >>> sp = DijkstraMultipleSourcesSP(ewd, (0, 6))
    >>> [sp.has_path_to(i) for i in range(1, 8)]
    [True, True, True, True, True, True, True]
    """

    def __init__(self, graph, sources):
        tmp = EdgeWeightedDigraph(graph)
        for v in sources:
            tmp.add_edge(DirectedEdge(-1, v, 0))

        self._dist_to = dict((v, INFINITE_POSITIVE_NUMBER) for v in tmp.vertices())
        self._edge_to = {}
        self._pq = IndexMinPQ(tmp.vertices_size())
        self._pq.insert(-1, 0)
        self._edge_to[-1] = None
        self._dist_to[-1] = 0
        self._sources = (i for i in sources)

        while not self._pq.is_empty():
            self.relax(tmp, self._pq.delete_min())

    def relax(self, graph, vertex):
        for edge in graph.adjacent_edges(vertex):
            end = edge.end
            if self._dist_to[end] > self._dist_to[vertex] + edge.weight:
                self._dist_to[end] = round(self._dist_to[vertex] + edge.weight, 2)
                self._edge_to[end] = edge

                if self._pq.contains(end):
                    self._pq.change_key(end, self._dist_to[end])
                else:
                    self._pq.insert(end, self._dist_to[end])

    def dist(self, source, dist):
        if source not in self._sources:
            return None
        return self.dist_to(dist)
    def __init__(self, graph, sources):
        tmp = EdgeWeightedDigraph(graph)
        for v in sources:
            tmp.add_edge(DirectedEdge(-1, v, 0))

        self._dist_to = dict((v, INFINITE_POSITIVE_NUMBER) for v in tmp.vertices())
        self._edge_to = {}
        self._pq = IndexMinPQ(tmp.vertices_size())
        self._pq.insert(-1, 0)
        self._edge_to[-1] = None
        self._dist_to[-1] = 0
        self._sources = (i for i in sources)

        while not self._pq.is_empty():
            self.relax(tmp, self._pq.delete_min())