def del_edge(self, graph, edge):

        if edge not in set(self._mst):
            return self._mst

        # init disjoint set with iterable object
        uf = GenericUnionFind([(e.either(), e.other(e.either()))
                               for e in self._mst if e is not edge])

        pq = MinPQ()
        for e in graph.edges():
            if e is not edge:
                pq.insert(e)

        tmp = Queue([e for e in self._mst if e is not edge])

        # find the minimum edge with both vertices is not connected
        while not pq.is_empty():
            min_edge = pq.del_min()
            vertx_a = min_edge.either()
            vertx_b = min_edge.other(vertx_a)

            if uf.connected(vertx_a, vertx_b):
                continue
            # only need one edge
            tmp.enqueue(min_edge)
            break

        self._mst = tmp
        return self._mst
Exemplo n.º 2
0
    def del_edge(self, graph, edge):

        if edge not in set(self._mst):
            return self._mst

        # init disjoint set with iterable object
        uf = GenericUnionFind([(e.either(), e.other(e.either()))
                               for e in self._mst if e is not edge])

        pq = MinPQ()
        for e in graph.edges():
            if e is not edge:
                pq.insert(e)

        tmp = Queue([e for e in self._mst if e is not edge])

        # find the minimum edge with both vertices is not connected
        while not pq.is_empty():
            min_edge = pq.del_min()
            vertx_a = min_edge.either()
            vertx_b = min_edge.other(vertx_a)

            if uf.connected(vertx_a, vertx_b):
                continue
            # only need one edge
            tmp.enqueue(min_edge)
            break

        self._mst = tmp
        return self._mst
class DepthFirstOrder(object):

    def __init__(self, graph):
        self._pre = Queue()
        self._post = Queue()
        self._reverse_post = Stack()
        self._marked = defaultdict(bool)

        for v in graph.vertices():
            if not self._marked[v]:
                self.dfs(graph, v)

    def dfs(self, graph, vertex):
        self._pre.enqueue(vertex)
        self._marked[vertex] = True
        for v in graph.get_adjacent_vertices(vertex):
            if not self._marked[v]:
                self.dfs(graph, v)

        self._post.enqueue(vertex)
        self._reverse_post.push(vertex)

    def prefix(self):
        return self._pre

    def postfix(self):
        return self._post

    def reverse_postfix(self):
        return self._reverse_post
    def __init__(self, graph):
        self._pre = Queue()
        self._post = Queue()
        self._reverse_post = Stack()
        self._marked = defaultdict(bool)

        for v in graph.vertices():
            if not self._marked[v]:
                self.dfs(graph, v)
Exemplo n.º 5
0
 def __init__(self, graph):
     deleted_edges = set()
     max_pq = MaxPQ(graph.edges())
     self._mst = Queue()
     while not max_pq.is_empty():
         edge = max_pq.del_max()
         if self._graph_connected(graph, edge, deleted_edges):
             deleted_edges.add(edge)
         else:
             self._mst.enqueue(edge)
class LazyPrimMST(object):

    """
      Lazy version Prim-Minimum-Spanning-Tree. This algorithm is a greedy strategy.
    First input a start vertex, then visit all the adjacent edges, if the other side
    of the vertex is not marked, put the edge into a priority queue. The result queue
    only enqueue those edges with small weight and either vertex is not marked.
    The cost of space is proportional to number of edges, and the worst case of running time
    is proportional to O(ElogE) (E is the number of edges).
    >>> 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)
    ...
    >>> lazy_prim_mst = LazyPrimMST(ewg, 0)
    >>> lazy_prim_mst.weight()
    1.81
    >>> [edge for edge in lazy_prim_mst.edges()]
    [0-7 0.16, 1-7 0.19, 0-2 0.26, 2-3 0.17, 5-7 0.28, 4-5 0.35, 6-2 0.4]
    """

    def __init__(self, graph, start_vertex):
        self._pq = MinPQ()
        self._marked = defaultdict(bool)
        self._mst = Queue()
        self.visit(graph, start_vertex)
        while not self._pq.is_empty():
            edge = self._pq.del_min()
            a = edge.either()
            b = edge.other(a)
            if self._marked[a] and self._marked[b]:
                continue
            self._mst.enqueue(edge)
            if not self._marked[a]:
                self.visit(graph, a)
            if not self._marked[b]:
                self.visit(graph, b)

    def visit(self, graph, vertex):
        self._marked[vertex] = True
        for edge in graph.adjacent_edges(vertex):
            if not self._marked[edge.other(vertex)]:
                self._pq.insert(edge)

    def edges(self):
        return self._mst

    # 4.3.31 practice, lazy weight implementation
    def weight(self):
        return sum(i.weight for i in self._mst)
 def keys_with_prefix(self, prefix):
     '''
     Return all the keys starts with the given prefix in the trie tree.
     '''
     q = Queue()
     node = self.get(prefix)
     if not node:
         return q
     if node.val:
         q.enqueue(prefix)
     self._collect(node.mid, prefix, q)
     return q
Exemplo n.º 8
0
 def keys_with_prefix(self, prefix):
     '''
     Return all the keys starts with the given prefix in the trie tree.
     '''
     q = Queue()
     node = self.get(prefix)
     if not node:
         return q
     if node.val:
         q.enqueue(prefix)
     self._collect(node.mid, prefix, q)
     return q
class KruskalMST(object):

    """
      Kruskal-Minimum-Spanning-Tree algorithm. This is a greedy stategy algorithm. First
    put all edges into the priority queue, then delete the minimum-weight edge in the
    priority queue. Check if those vertices on the both side of the edge is connected.
    If connected, ignore the edge, if not, then use a disjoint set to connect two vertices
    and put the edge into the result. This algorithm is a little bit slower than Prim's algorithm,
    because the cost of connect operation is expensive. The running time of this algorithm
    is proportional to O(ElogE) (E is the number of the edges). And the cost of the space
    is proportional to E.
    >>> 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)
    ...
    >>> kruskal_mst = KruskalMST(ewg)
    >>> [edge for edge in kruskal_mst.edges()]
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 4-5 0.35, 6-2 0.4]
    >>> kruskal_mst.weight()
    1.81
    """

    def __init__(self, graph):
        self._mst = Queue()
        pq = self._init_priority_queue(graph)
        uf = GenericUnionFind()

        while not pq.is_empty() and self._mst.size() < graph.vertices_size() - 1:
            edge = pq.del_min()
            a = edge.either()
            b = edge.other(a)
            if uf.connected(a, b):
                continue
            uf.union(a, b)
            self._mst.enqueue(edge)

    def _init_priority_queue(self, graph):
        pq = MinPQ()
        for edge in graph.edges():
            pq.insert(edge)
        return pq

    def edges(self):
        return self._mst

    def weight(self):
        return sum(i.weight for i in self._mst)
Exemplo n.º 10
0
class LazyPrimMST(object):
    """
      Lazy version Prim-Minimum-Spanning-Tree. This algorithm is a greedy strategy.
    First input a start vertex, then visit all the adjacent edges, if the other side
    of the vertex is not marked, put the edge into a priority queue. The result queue
    only enqueue those edges with small weight and either vertex is not marked.
    The cost of space is proportional to number of edges, and the worst case of running time
    is proportional to O(ElogE) (E is the number of edges).
    >>> 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)
    ...
    >>> lazy_prim_mst = LazyPrimMST(ewg, 0)
    >>> lazy_prim_mst.weight()
    1.81
    >>> [edge for edge in lazy_prim_mst.edges()]
    [0-7 0.16, 1-7 0.19, 0-2 0.26, 2-3 0.17, 5-7 0.28, 4-5 0.35, 6-2 0.4]
    """
    def __init__(self, graph, start_vertex):
        self._pq = MinPQ()
        self._marked = defaultdict(bool)
        self._mst = Queue()
        self.visit(graph, start_vertex)
        while not self._pq.is_empty():
            edge = self._pq.del_min()
            a = edge.either()
            b = edge.other(a)
            if self._marked[a] and self._marked[b]:
                continue
            self._mst.enqueue(edge)
            if not self._marked[a]:
                self.visit(graph, a)
            if not self._marked[b]:
                self.visit(graph, b)

    def visit(self, graph, vertex):
        self._marked[vertex] = True
        for edge in graph.adjacent_edges(vertex):
            if not self._marked[edge.other(vertex)]:
                self._pq.insert(edge)

    def edges(self):
        return self._mst

    # 4.3.31 practice, lazy weight implementation
    def weight(self):
        return sum(i.weight for i in self._mst)
Exemplo n.º 11
0
class KruskalMST(object):
    """
      Kruskal-Minimum-Spanning-Tree algorithm. This is a greedy stategy algorithm. First
    put all edges into the priority queue, then delete the minimum-weight edge in the
    priority queue. Check if those vertices on the both side of the edge is connected.
    If connected, ignore the edge, if not, then use a disjoint set to connect two vertices
    and put the edge into the result. This algorithm is a little bit slower than Prim's algorithm,
    because the cost of connect operation is expensive. The running time of this algorithm
    is proportional to O(ElogE) (E is the number of the edges). And the cost of the space
    is proportional to E.
    >>> 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)
    ...
    >>> kruskal_mst = KruskalMST(ewg)
    >>> [edge for edge in kruskal_mst.edges()]
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 4-5 0.35, 6-2 0.4]
    >>> kruskal_mst.weight()
    1.81
    """
    def __init__(self, graph):
        self._mst = Queue()
        pq = self._init_priority_queue(graph)
        uf = GenericUnionFind()

        while not pq.is_empty(
        ) and self._mst.size() < graph.vertices_size() - 1:
            edge = pq.del_min()
            a = edge.either()
            b = edge.other(a)
            if uf.connected(a, b):
                continue
            uf.union(a, b)
            self._mst.enqueue(edge)

    def _init_priority_queue(self, graph):
        pq = MinPQ()
        for edge in graph.edges():
            pq.insert(edge)
        return pq

    def edges(self):
        return self._mst

    def weight(self):
        return sum(i.weight for i in self._mst)
class KruskalMSF(object):

    """
    >>> 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), (8, 12, 0.61), (8, 11, 0.77), (11, 12, 0.12), (8, 9, 0.99),
    ...              (9, 11, 0.36), (9, 10, 0.39), (8, 10, 0.04), (10, 12, 0.14))
    >>> ewg = EdgeWeightedGraph()
    >>> for a, b, weight in test_data:
    ...    edge = Edge(a, b, weight)
    ...    ewg.add_edge(edge)
    ...
    >>> kmsf = KruskalMSF(ewg)
    >>> sorted([[e for e in mst] for mst in kmsf.edges()])
    [[8-10 0.04, 11-12 0.12, 10-12 0.14, 9-11 0.36], [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 4-5 0.35, 6-2 0.4]]
    """

    def __init__(self, forest):
        ecc = EdgeConnectedComponent(forest)
        self._msf = Queue()

        for vertices in ecc.get_components():
            pq = self._init_priority_queue(vertices, forest)
            uf = GenericUnionFind()
            mst = Queue()
            while not pq.is_empty() and mst.size() < len(vertices) - 1:
                edge = pq.del_min()
                a = edge.either()
                b = edge.other(a)
                if uf.connected(a, b):
                    continue
                uf.union(a, b)
                mst.enqueue(edge)
            self._msf.enqueue(mst)

    def _init_priority_queue(self, vertices, forest):
        dup_set = set()
        pq = MinPQ()
        for v in vertices:
            for edge in forest.adjacent_edges(v):
                if edge not in dup_set:
                    pq.insert(edge)
                    dup_set.add(edge)
        return pq

    def edges(self):
        return self._msf

    def weight(self):
        return sum(i.weight for i in self._mst)
Exemplo n.º 13
0
    def __init__(self, graph):
        self._mst = Queue()
        pq = self._init_priority_queue(graph)
        uf = GenericUnionFind()

        while not pq.is_empty(
        ) and self._mst.size() < graph.vertices_size() - 1:
            edge = pq.del_min()
            a = edge.either()
            b = edge.other(a)
            if uf.connected(a, b):
                continue
            uf.union(a, b)
            self._mst.enqueue(edge)
Exemplo n.º 14
0
 def __init__(self, graph, start_vertex):
     self._marked = defaultdict(bool)
     self._mst = Queue()
     self.pq = MinPQ()
     self.visit(graph, start_vertex)
     while not self.pq.is_empty():
         edge = self.pq.del_min()
         if self._marked[edge[1]] and self._marked[edge[2]]:
             continue
         self._mst.enqueue(edge)
         if not self._marked[edge[1]]:
             self.visit(graph, edge[1])
         if not self._marked[edge[2]]:
             self.visit(graph, edge[2])
    def __init__(self, graph):
        indegree = defaultdict(int)
        self._order = Queue()
        self._rank = defaultdict(int)
        count = 0
        for v in graph.vertices():
            for adj in graph.get_adjacent_vertices(v):
                indegree[adj] += 1
        queue = Queue()
        for v in graph.vertices():
            if indegree[v] == 0:
                queue.enqueue(v)

        while not queue.is_empty():
            vertex = queue.dequeue()
            self._order.enqueue(vertex)
            self._rank[vertex] = count
            count += 1
            for v in graph.get_adjacent_vertices(vertex):
                indegree[v] -= 1
                if indegree[v] == 0:
                    queue.enqueue(v)

        if count != graph.vertices_size():
            self._order = None

        assert self.check(graph)
Exemplo n.º 16
0
class KruskalMSF(object):
    """
    >>> 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), (8, 12, 0.61), (8, 11, 0.77), (11, 12, 0.12), (8, 9, 0.99),
    ...              (9, 11, 0.36), (9, 10, 0.39), (8, 10, 0.04), (10, 12, 0.14))
    >>> ewg = EdgeWeightedGraph()
    >>> for a, b, weight in test_data:
    ...    edge = Edge(a, b, weight)
    ...    ewg.add_edge(edge)
    ...
    >>> kmsf = KruskalMSF(ewg)
    >>> sorted([[e for e in mst] for mst in kmsf.edges()])
    [[8-10 0.04, 11-12 0.12, 10-12 0.14, 9-11 0.36], [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 4-5 0.35, 6-2 0.4]]
    """
    def __init__(self, forest):
        ecc = EdgeConnectedComponent(forest)
        self._msf = Queue()

        for vertices in ecc.get_components():
            pq = self._init_priority_queue(vertices, forest)
            uf = GenericUnionFind()
            mst = Queue()
            while not pq.is_empty() and mst.size() < len(vertices) - 1:
                edge = pq.del_min()
                a = edge.either()
                b = edge.other(a)
                if uf.connected(a, b):
                    continue
                uf.union(a, b)
                mst.enqueue(edge)
            self._msf.enqueue(mst)

    def _init_priority_queue(self, vertices, forest):
        dup_set = set()
        pq = MinPQ()
        for v in vertices:
            for edge in forest.adjacent_edges(v):
                if edge not in dup_set:
                    pq.insert(edge)
                    dup_set.add(edge)
        return pq

    def edges(self):
        return self._msf

    def weight(self):
        return sum(i.weight for i in self._mst)
Exemplo n.º 17
0
class ReverseDeleteMST(object):
    """
    >>> 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)
    ...
    >>> rd_mst = ReverseDeleteMST(ewg)
    >>> sorted([edge for edge in rd_mst.edges()])
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 4-5 0.35, 6-2 0.4]
    """
    def __init__(self, graph):
        deleted_edges = set()
        max_pq = MaxPQ(graph.edges())
        self._mst = Queue()
        while not max_pq.is_empty():
            edge = max_pq.del_max()
            if self._graph_connected(graph, edge, deleted_edges):
                deleted_edges.add(edge)
            else:
                self._mst.enqueue(edge)

    def _graph_connected(self, graph, canidate_edge, deleted_edges):
        self._marked = defaultdict(bool)
        start_vertex = canidate_edge.either()
        self._marked[start_vertex] = True
        for edge in graph.adjacent_edges(start_vertex):
            a = edge.other(start_vertex)
            if edge is not canidate_edge and edge not in deleted_edges and not self._marked[
                    a]:
                self._dfs(graph, a, canidate_edge, deleted_edges)
        connected_vertices = len([v for v in self._marked if self._marked[v]])
        return graph.vertices_size() == connected_vertices

    def _dfs(self, graph, vertex, canidate_edge, deleted_edges):
        self._marked[vertex] = True
        for edge in graph.adjacent_edges(vertex):
            v = edge.other(vertex)
            if edge is not canidate_edge and edge not in deleted_edges and not self._marked[
                    v]:
                self._dfs(graph, v, canidate_edge, deleted_edges)

    def edges(self):
        return self._mst
class ReverseDeleteMST(object):

    """
    >>> 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)
    ...
    >>> rd_mst = ReverseDeleteMST(ewg)
    >>> sorted([edge for edge in rd_mst.edges()])
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 4-5 0.35, 6-2 0.4]
    """

    def __init__(self, graph):
        deleted_edges = set()
        max_pq = MaxPQ(graph.edges())
        self._mst = Queue()
        while not max_pq.is_empty():
            edge = max_pq.del_max()
            if self._graph_connected(graph, edge, deleted_edges):
                deleted_edges.add(edge)
            else:
                self._mst.enqueue(edge)

    def _graph_connected(self, graph, canidate_edge, deleted_edges):
        self._marked = defaultdict(bool)
        start_vertex = canidate_edge.either()
        self._marked[start_vertex] = True
        for edge in graph.adjacent_edges(start_vertex):
            a = edge.other(start_vertex)
            if edge is not canidate_edge and edge not in deleted_edges and not self._marked[a]:
                self._dfs(graph, a, canidate_edge, deleted_edges)
        connected_vertices = len([v for v in self._marked if self._marked[v]])
        return graph.vertices_size() == connected_vertices

    def _dfs(self, graph, vertex, canidate_edge, deleted_edges):
        self._marked[vertex] = True
        for edge in graph.adjacent_edges(vertex):
            v = edge.other(vertex)
            if edge is not canidate_edge and edge not in deleted_edges and not self._marked[v]:
                self._dfs(graph, v, canidate_edge, deleted_edges)

    def edges(self):
        return self._mst
Exemplo n.º 19
0
 def keys_that_match(self, pattern):
     '''
     Return all the keys match the given pattern in the trie tree.
     '''
     q = Queue()
     self._keys_collect(self._root, '', pattern, q)
     return q
Exemplo n.º 20
0
 def __init__(self, graph, start_vertex):
     self._pq = MinPQ()
     self._marked = defaultdict(bool)
     self._mst = Queue()
     self.visit(graph, start_vertex)
     while not self._pq.is_empty():
         edge = self._pq.del_min()
         a = edge.either()
         b = edge.other(a)
         if self._marked[a] and self._marked[b]:
             continue
         self._mst.enqueue(edge)
         if not self._marked[a]:
             self.visit(graph, a)
         if not self._marked[b]:
             self.visit(graph, b)
class EdgeSetMST(object):

    """
    >>> 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)
    ...
    >>> contain_edges = set(edge for edge in ewg.adjacent_edges(6))
    >>> mst = EdgeSetMST(ewg, contain_edges)
    >>> [edge for edge in mst.edges()]
    [6-4 0.93, 3-6 0.52, 6-2 0.4, 6-0 0.58, 0-7 0.16, 1-7 0.19, 5-7 0.28]
    """

    def __init__(self, graph, contain_edges):
        self._mst = Queue([edge for edge in contain_edges])
        pq = self._init_priority_queue(graph, contain_edges)
        uf = GenericUnionFind()
        for edge in contain_edges:
            uf.union(edge.either(), edge.other(edge.either()))

        while not pq.is_empty() and self._mst.size() < graph.vertices_size() - 1:
            edge = pq.del_min()
            a = edge.either()
            b = edge.other(a)
            if uf.connected(a, b):
                continue
            uf.union(a, b)
            self._mst.enqueue(edge)

    def _init_priority_queue(self, graph, contain_edges):
        pq = MinPQ()
        for edge in graph.edges():
            if edge not in contain_edges:
                pq.insert(edge)
        return pq

    def edges(self):
        return self._mst

    def weight(self):
        return sum(i.weight for i in self._mst)
    def __init__(self, forest):
        ecc = EdgeConnectedComponent(forest)
        self._msf = Queue()

        for vertices in ecc.get_components():
            pq = self._init_priority_queue(vertices, forest)
            uf = GenericUnionFind()
            mst = Queue()
            while not pq.is_empty() and mst.size() < len(vertices) - 1:
                edge = pq.del_min()
                a = edge.either()
                b = edge.other(a)
                if uf.connected(a, b):
                    continue
                uf.union(a, b)
                mst.enqueue(edge)
            self._msf.enqueue(mst)
Exemplo n.º 23
0
class EdgeSetMST(object):
    """
    >>> 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)
    ...
    >>> contain_edges = set(edge for edge in ewg.adjacent_edges(6))
    >>> mst = EdgeSetMST(ewg, contain_edges)
    >>> [edge for edge in mst.edges()]
    [6-4 0.93, 3-6 0.52, 6-2 0.4, 6-0 0.58, 0-7 0.16, 1-7 0.19, 5-7 0.28]
    """
    def __init__(self, graph, contain_edges):
        self._mst = Queue([edge for edge in contain_edges])
        pq = self._init_priority_queue(graph, contain_edges)
        uf = GenericUnionFind()
        for edge in contain_edges:
            uf.union(edge.either(), edge.other(edge.either()))

        while not pq.is_empty(
        ) and self._mst.size() < graph.vertices_size() - 1:
            edge = pq.del_min()
            a = edge.either()
            b = edge.other(a)
            if uf.connected(a, b):
                continue
            uf.union(a, b)
            self._mst.enqueue(edge)

    def _init_priority_queue(self, graph, contain_edges):
        pq = MinPQ()
        for edge in graph.edges():
            if edge not in contain_edges:
                pq.insert(edge)
        return pq

    def edges(self):
        return self._mst

    def weight(self):
        return sum(i.weight for i in self._mst)
class PrimitiveLazyPrimMST(object):

    """
    >>> test_data = ((0.35, 4, 5), (0.37, 4, 7), (0.28, 5, 7), (0.16, 0, 7), (0.32, 1, 5),
    ...              (0.38, 0, 4), (0.17, 2, 3), (0.19, 1, 7), (0.26, 0, 2), (0.36, 1, 2),
    ...              (0.29, 1, 3), (0.34, 2, 7), (0.4, 6, 2), (0.52, 3, 6), (0.58, 6, 0),
    ...              (0.93, 6, 4))
    >>> wg = WeightedGraph()
    >>> for edge in test_data:
    ...     wg.add_edge(edge)
    ...
    >>> primitive_mst = PrimitiveLazyPrimMST(wg, 0)
    >>> [edge for edge in primitive_mst.edges()]
    [(0.16, 0, 7), (0.19, 1, 7), (0.26, 0, 2), (0.17, 2, 3), (0.28, 5, 7), (0.35, 4, 5), (0.4, 6, 2)]
    """

    def __init__(self, graph, start_vertex):
        self._marked = defaultdict(bool)
        self._mst = Queue()
        self.pq = MinPQ()
        self.visit(graph, start_vertex)
        while not self.pq.is_empty():
            edge = self.pq.del_min()
            if self._marked[edge[1]] and self._marked[edge[2]]:
                continue
            self._mst.enqueue(edge)
            if not self._marked[edge[1]]:
                self.visit(graph, edge[1])
            if not self._marked[edge[2]]:
                self.visit(graph, edge[2])

    def visit(self, graph, vertex):
        self._marked[vertex] = True
        for edge in graph.adjacent_edges(vertex):
            if edge[1] == vertex and not self._marked[edge[2]]:
                self.pq.insert(edge)
            elif edge[2] == vertex and not self._marked[edge[1]]:
                self.pq.insert(edge)

    def edges(self):
        return self._mst

    def weight(self):
        return sum(edge[0] for edge in self._mst)
 def bfs(self, graph, vertex):
     queue = Queue()
     self._marked[vertex] = True
     queue.enqueue(vertex)
     while not queue.is_empty():
         tmp = queue.dequeue()
         for v in graph.get_adjacent_vertices(tmp):
             if not self._marked[v]:
                 self._edge_to[v] = tmp
                 self._dist[v] = self._dist[tmp] + 1
                 self._marked[v] = True
                 queue.enqueue(v)
 def __init__(self, graph):
     deleted_edges = set()
     max_pq = MaxPQ(graph.edges())
     self._mst = Queue()
     while not max_pq.is_empty():
         edge = max_pq.del_max()
         if self._graph_connected(graph, edge, deleted_edges):
             deleted_edges.add(edge)
         else:
             self._mst.enqueue(edge)
Exemplo n.º 27
0
class PrimitiveLazyPrimMST(object):
    """
    >>> test_data = ((0.35, 4, 5), (0.37, 4, 7), (0.28, 5, 7), (0.16, 0, 7), (0.32, 1, 5),
    ...              (0.38, 0, 4), (0.17, 2, 3), (0.19, 1, 7), (0.26, 0, 2), (0.36, 1, 2),
    ...              (0.29, 1, 3), (0.34, 2, 7), (0.4, 6, 2), (0.52, 3, 6), (0.58, 6, 0),
    ...              (0.93, 6, 4))
    >>> wg = WeightedGraph()
    >>> for edge in test_data:
    ...     wg.add_edge(edge)
    ...
    >>> primitive_mst = PrimitiveLazyPrimMST(wg, 0)
    >>> [edge for edge in primitive_mst.edges()]
    [(0.16, 0, 7), (0.19, 1, 7), (0.26, 0, 2), (0.17, 2, 3), (0.28, 5, 7), (0.35, 4, 5), (0.4, 6, 2)]
    """
    def __init__(self, graph, start_vertex):
        self._marked = defaultdict(bool)
        self._mst = Queue()
        self.pq = MinPQ()
        self.visit(graph, start_vertex)
        while not self.pq.is_empty():
            edge = self.pq.del_min()
            if self._marked[edge[1]] and self._marked[edge[2]]:
                continue
            self._mst.enqueue(edge)
            if not self._marked[edge[1]]:
                self.visit(graph, edge[1])
            if not self._marked[edge[2]]:
                self.visit(graph, edge[2])

    def visit(self, graph, vertex):
        self._marked[vertex] = True
        for edge in graph.adjacent_edges(vertex):
            if edge[1] == vertex and not self._marked[edge[2]]:
                self.pq.insert(edge)
            elif edge[2] == vertex and not self._marked[edge[1]]:
                self.pq.insert(edge)

    def edges(self):
        return self._mst

    def weight(self):
        return sum(edge[0] for edge in self._mst)
Exemplo n.º 28
0
 def keys_with_prefix(self, prefix):
     '''
     Return all the keys starts with the given prefix in the trie tree.
     '''
     q = Queue()
     if prefix == '':
         self._collect(self._root, prefix, q)
     else:
         start_node = self.get(prefix)
         self._collect(start_node, prefix, q)
     return q
    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._queue = Queue()
        self._queue.enqueue(source)
        self._on_queue = defaultdict(bool)
        self._on_queue[source] = True

        self._cost = 0
        self._cycle = None

        while not self._queue.is_empty() and not self._has_negative_cycle():
            vertex = self._queue.dequeue()
            self._on_queue[vertex] = False
            self.relax(graph, vertex)

        assert self.check(graph, source)
    def __init__(self, graph):
        self._mst = Queue()
        pq = self._init_priority_queue(graph)
        uf = GenericUnionFind()

        while not pq.is_empty() and self._mst.size() < graph.vertices_size() - 1:
            edge = pq.del_min()
            a = edge.either()
            b = edge.other(a)
            if uf.connected(a, b):
                continue
            uf.union(a, b)
            self._mst.enqueue(edge)
    def _get_max_cycle_edge(self, graph, new_edge):
        # put the new edge into the mst creates a unique cycle
        tmp = Queue(self._mst)
        tmp.enqueue(new_edge)
        mst_query_set = set(tmp)
        cycle = Queue()
        cycle.enqueue([new_edge])

        start_vertex = new_edge.either()
        end_vertex = new_edge.other(start_vertex)

        while start_vertex != end_vertex:
            path = cycle.dequeue()
            last_edge = path[-1]
            a, b = last_edge.either(), last_edge.other(last_edge.either())
            start_vertex = b if a == start_vertex else a
            for edge in graph.adjacent_edges(start_vertex):
                if edge is not new_edge and edge in mst_query_set:
                    path.append(edge)
                    cycle.enqueue(path)
        max_edge = max(cycle.dequeue())
        return max_edge
 def bfs(self, graph, vertex):
     queue = Queue()
     self._marked[vertex] = True
     queue.enqueue(vertex)
     while not queue.is_empty():
         tmp = queue.dequeue()
         for v in graph.get_adjacent_vertices(tmp):
             if not self._marked[v]:
                 self._edge_to[v] = tmp
                 self._dist[v] = self._dist[tmp] + 1
                 self._marked[v] = True
                 queue.enqueue(v)
 def __init__(self, graph, start_vertex):
     self._marked = defaultdict(bool)
     self._mst = Queue()
     self.pq = MinPQ()
     self.visit(graph, start_vertex)
     while not self.pq.is_empty():
         edge = self.pq.del_min()
         if self._marked[edge[1]] and self._marked[edge[2]]:
             continue
         self._mst.enqueue(edge)
         if not self._marked[edge[1]]:
             self.visit(graph, edge[1])
         if not self._marked[edge[2]]:
             self.visit(graph, edge[2])
 def __init__(self, graph, start_vertex):
     self._pq = MinPQ()
     self._marked = defaultdict(bool)
     self._mst = Queue()
     self.visit(graph, start_vertex)
     while not self._pq.is_empty():
         edge = self._pq.del_min()
         a = edge.either()
         b = edge.other(a)
         if self._marked[a] and self._marked[b]:
             continue
         self._mst.enqueue(edge)
         if not self._marked[a]:
             self.visit(graph, a)
         if not self._marked[b]:
             self.visit(graph, b)
Exemplo n.º 35
0
    def __init__(self, forest):
        ecc = EdgeConnectedComponent(forest)
        self._msf = Queue()

        for vertices in ecc.get_components():
            pq = self._init_priority_queue(vertices, forest)
            uf = GenericUnionFind()
            mst = Queue()
            while not pq.is_empty() and mst.size() < len(vertices) - 1:
                edge = pq.del_min()
                a = edge.either()
                b = edge.other(a)
                if uf.connected(a, b):
                    continue
                uf.union(a, b)
                mst.enqueue(edge)
            self._msf.enqueue(mst)
    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._queue = Queue()
        self._queue.enqueue(source)
        self._on_queue = defaultdict(bool)
        self._on_queue[source] = True

        self._cost = 0
        self._cycle = None

        while not self._queue.is_empty() and not self._has_negative_cycle():
            vertex = self._queue.dequeue()
            self._on_queue[vertex] = False
            self.relax(graph, vertex)

        assert self.check(graph, source)
Exemplo n.º 37
0
 def keys_that_match(self, pattern):
     q = Queue()
     self._keys_collect(self._root, '', 0, pattern, q)
     return q
class BellmanFordSP(ShortestPath):

    """
      BellmanFord Shortest Path algorithm. This version is not a traditional one,
    it's a queue-based version. First enqueue the source vertex, and dequeue the vertex,
    'relax' all adjacent edges and put the adjacent vertices into the queue until the queue
    is empty or find the negative cycle. A negative cycle check is nessesary every V times
    relaxtion.The cost of running time is proportional to O(V + E), the worst case is VE.
    This is a universal algorithm for Shortest Path algorithm.
    >>> 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, -1.2), (3, 6, 0.52), (6, 0, -1.4), (6, 4, -1.25))
    >>> ewd = EdgeWeightedDigraph()
    >>> for a, b, weight in test_data:
    ...     edge = DirectedEdge(a, b, weight)
    ...     ewd.add_edge(edge)
    ...
    >>> sp = BellmanFordSP(ewd, 0)
    >>> [sp.has_path_to(i) for i in range(8)]
    [True, True, True, True, True, True, True, True]
    >>> sp._has_negative_cycle()
    False
    >>> [edge for edge in sp.path_to(7)]
    [0->2 0.26, 2->7 0.34]
    >>> [edge for edge in sp.path_to(4)]
    [0->2 0.26, 2->7 0.34, 7->3 0.39, 3->6 0.52, 6->4 -1.25]
    """

    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._queue = Queue()
        self._queue.enqueue(source)
        self._on_queue = defaultdict(bool)
        self._on_queue[source] = True

        self._cost = 0
        self._cycle = None

        while not self._queue.is_empty() and not self._has_negative_cycle():
            vertex = self._queue.dequeue()
            self._on_queue[vertex] = False
            self.relax(graph, vertex)

        assert self.check(graph, source)

    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 not self._on_queue[end]:
                    self._queue.enqueue(end)
                    self._on_queue[end] = True

            if self._cost % graph.vertices_size() == 0:
                self._find_negative_cycle(graph)
            self._cost += 1

    def _find_negative_cycle(self, graph):
        spt = EdgeWeightedDigraph()
        for v in graph.vertices():
            if self._edge_to.get(v, None):
                spt.add_edge(self._edge_to[v])

        cf = EdgeWeightedDirectedCycle(spt)
        self._cycle = cf.cycle()

    def _has_negative_cycle(self):
        return self._cycle is not None

    def negative_cycle(self):
        return self._cycle

    def check(self, graph, source):
        # if negative cycle exists, check the total weight of the negative cycle is negative.
        if self._has_negative_cycle():
            if sum(e.weight for e in self.negative_cycle()) >= 0:
                print('positive weight from negative cycle')
                return False
        # no negative cycle
        else:
            # check vertex self._dist_to[v] and self._edge_to[v] are consistent
            if self._dist_to[source] != 0 or self._edge_to[source] is not None:
                print('the distance and edge_to of source vertex inconsistent')
                return False

            for v in graph.vertices():
                if v == source:
                    continue
                if self._edge_to[v] is None and self._dist_to[v] != INFINITE_POSITIVE_NUMBER:
                    print('the distance and edge_to of {} inconsistent'.format(v))
                    return False

            # check each edge is relaxed
            for v in graph.vertices():
                for e in graph.adjacent_edges(v):
                    if round(self._dist_to[v] + e.weight, 2) < self._dist_to[e.end]:
                        print('edge {} is not relaxed'.format(e))
                        return False

            # check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight()
            for v in graph.vertices():
                if self._edge_to[v] is None:
                    continue
                edge = self._edge_to[v]
                if v != edge.end:
                    print('here')
                    return False
                if round(self._dist_to[edge.start] + edge.weight, 2) != self._dist_to[v]:
                    print('edge {} on shortest path not tight'.format(edge))
                    return False

        return True
class DynamicMST(object):

    """
    >>> 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)
    ...
    >>> dmst = DynamicMST(ewg)
    >>> new_edge = Edge(1, 6, 0.65) # add a new edge that doesn't change the mst result
    >>> ewg.add_edge(new_edge)
    >>> [e for e in dmst.incr_edge(ewg, new_edge)]
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 4-5 0.35, 6-2 0.4]
    >>> new_edge2 = Edge(3, 4, 0.3)
    >>> ewg.add_edge(new_edge2)
    >>> # add a new edge that change the mst result
    >>> # and if the new edge is in the mst, then it must be in the end of the queue.
    >>> [e for e in dmst.incr_edge(ewg, new_edge2)]
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 6-2 0.4, 3-4 0.3]
    >>> # delete edge operation, the edge is not actually deleted
    >>> # delete a edge that is out of the mst
    >>> [e for e in dmst.del_edge(ewg, new_edge)]
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 6-2 0.4, 3-4 0.3]
    >>> # really sad that the order of the edges is not weight-increased
    >>> [e for e in dmst.del_edge(ewg, new_edge2)]
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 6-2 0.4, 4-5 0.35]
    >>> 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))
    >>> ewg2 = EdgeWeightedGraph()
    >>> for a, b, weight in test_data:
    ...    edge = Edge(a, b, weight)
    ...    ewg2.add_edge(edge)
    ...
    >>> dmst2 = DynamicMST(ewg2)
    >>> dmst2.edge_add_to_mst(ewg, Edge(1, 6, 0.41))
    False
    >>> dmst2.edge_add_to_mst(ewg, Edge(1, 6, 0.29))
    True
    >>> dmst2.edge_add_to_mst(ewg, Edge(4, 2, 0.3))
    True
    """

    def __init__(self, graph):
        self._mst = Queue()
        pq = self._init_priority_queue(graph)
        uf = GenericUnionFind()

        while not pq.is_empty() and self._mst.size() < graph.vertices_size() - 1:
            edge = pq.del_min()
            a = edge.either()
            b = edge.other(a)
            if uf.connected(a, b):
                continue
            uf.union(a, b)
            self._mst.enqueue(edge)

    def _init_priority_queue(self, graph):
        pq = MinPQ()
        for edge in graph.edges():
            pq.insert(edge)
        return pq

    def _get_max_cycle_edge(self, graph, new_edge):
        # put the new edge into the mst creates a unique cycle
        tmp = Queue(self._mst)
        tmp.enqueue(new_edge)
        mst_query_set = set(tmp)
        cycle = Queue()
        cycle.enqueue([new_edge])

        start_vertex = new_edge.either()
        end_vertex = new_edge.other(start_vertex)

        while start_vertex != end_vertex:
            path = cycle.dequeue()
            last_edge = path[-1]
            a, b = last_edge.either(), last_edge.other(last_edge.either())
            start_vertex = b if a == start_vertex else a
            for edge in graph.adjacent_edges(start_vertex):
                if edge is not new_edge and edge in mst_query_set:
                    path.append(edge)
                    cycle.enqueue(path)
        max_edge = max(cycle.dequeue())
        return max_edge

    # 4.3.16 practice, the solution is similar with 4.3.15
    def edge_add_to_mst(self, graph, new_edge):
        max_cycle_edge = self._get_max_cycle_edge(graph, new_edge)
        return new_edge < max_cycle_edge

    # 4.3.15 practice, the solution is given on the website,
    # see http://algs4.cs.princeton.edu/43mst/
    def incr_edge(self, graph, edge):
        max_cycle_edge = self._get_max_cycle_edge(graph, edge)
        self._mst.enqueue(edge)
        result = Queue([e for e in self._mst if e is not max_cycle_edge])
        self._mst = result
        return result

    # 4.3.14 practice, the solution is given on the website,
    # see http://algs4.cs.princeton.edu/43mst/
    def del_edge(self, graph, edge):

        if edge not in set(self._mst):
            return self._mst

        # init disjoint set with iterable object
        uf = GenericUnionFind([(e.either(), e.other(e.either()))
                               for e in self._mst if e is not edge])

        pq = MinPQ()
        for e in graph.edges():
            if e is not edge:
                pq.insert(e)

        tmp = Queue([e for e in self._mst if e is not edge])

        # find the minimum edge with both vertices is not connected
        while not pq.is_empty():
            min_edge = pq.del_min()
            vertx_a = min_edge.either()
            vertx_b = min_edge.other(vertx_a)

            if uf.connected(vertx_a, vertx_b):
                continue
            # only need one edge
            tmp.enqueue(min_edge)
            break

        self._mst = tmp
        return self._mst
Exemplo n.º 40
0
 def incr_edge(self, graph, edge):
     max_cycle_edge = self._get_max_cycle_edge(graph, edge)
     self._mst.enqueue(edge)
     result = Queue([e for e in self._mst if e is not max_cycle_edge])
     self._mst = result
     return result
Exemplo n.º 41
0
    def _get_max_cycle_edge(self, graph, new_edge):
        # put the new edge into the mst creates a unique cycle
        tmp = Queue(self._mst)
        tmp.enqueue(new_edge)
        mst_query_set = set(tmp)
        cycle = Queue()
        cycle.enqueue([new_edge])

        start_vertex = new_edge.either()
        end_vertex = new_edge.other(start_vertex)

        while start_vertex != end_vertex:
            path = cycle.dequeue()
            last_edge = path[-1]
            a, b = last_edge.either(), last_edge.other(last_edge.either())
            start_vertex = b if a == start_vertex else a
            for edge in graph.adjacent_edges(start_vertex):
                if edge is not new_edge and edge in mst_query_set:
                    path.append(edge)
                    cycle.enqueue(path)
        max_edge = max(cycle.dequeue())
        return max_edge
Exemplo n.º 42
0
class DynamicMST(object):
    """
    >>> 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)
    ...
    >>> dmst = DynamicMST(ewg)
    >>> new_edge = Edge(1, 6, 0.65) # add a new edge that doesn't change the mst result
    >>> ewg.add_edge(new_edge)
    >>> [e for e in dmst.incr_edge(ewg, new_edge)]
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 4-5 0.35, 6-2 0.4]
    >>> new_edge2 = Edge(3, 4, 0.3)
    >>> ewg.add_edge(new_edge2)
    >>> # add a new edge that change the mst result
    >>> # and if the new edge is in the mst, then it must be in the end of the queue.
    >>> [e for e in dmst.incr_edge(ewg, new_edge2)]
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 6-2 0.4, 3-4 0.3]
    >>> # delete edge operation, the edge is not actually deleted
    >>> # delete a edge that is out of the mst
    >>> [e for e in dmst.del_edge(ewg, new_edge)]
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 6-2 0.4, 3-4 0.3]
    >>> # really sad that the order of the edges is not weight-increased
    >>> [e for e in dmst.del_edge(ewg, new_edge2)]
    [0-7 0.16, 2-3 0.17, 1-7 0.19, 0-2 0.26, 5-7 0.28, 6-2 0.4, 4-5 0.35]
    >>> 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))
    >>> ewg2 = EdgeWeightedGraph()
    >>> for a, b, weight in test_data:
    ...    edge = Edge(a, b, weight)
    ...    ewg2.add_edge(edge)
    ...
    >>> dmst2 = DynamicMST(ewg2)
    >>> dmst2.edge_add_to_mst(ewg, Edge(1, 6, 0.41))
    False
    >>> dmst2.edge_add_to_mst(ewg, Edge(1, 6, 0.29))
    True
    >>> dmst2.edge_add_to_mst(ewg, Edge(4, 2, 0.3))
    True
    """
    def __init__(self, graph):
        self._mst = Queue()
        pq = self._init_priority_queue(graph)
        uf = GenericUnionFind()

        while not pq.is_empty(
        ) and self._mst.size() < graph.vertices_size() - 1:
            edge = pq.del_min()
            a = edge.either()
            b = edge.other(a)
            if uf.connected(a, b):
                continue
            uf.union(a, b)
            self._mst.enqueue(edge)

    def _init_priority_queue(self, graph):
        pq = MinPQ()
        for edge in graph.edges():
            pq.insert(edge)
        return pq

    def _get_max_cycle_edge(self, graph, new_edge):
        # put the new edge into the mst creates a unique cycle
        tmp = Queue(self._mst)
        tmp.enqueue(new_edge)
        mst_query_set = set(tmp)
        cycle = Queue()
        cycle.enqueue([new_edge])

        start_vertex = new_edge.either()
        end_vertex = new_edge.other(start_vertex)

        while start_vertex != end_vertex:
            path = cycle.dequeue()
            last_edge = path[-1]
            a, b = last_edge.either(), last_edge.other(last_edge.either())
            start_vertex = b if a == start_vertex else a
            for edge in graph.adjacent_edges(start_vertex):
                if edge is not new_edge and edge in mst_query_set:
                    path.append(edge)
                    cycle.enqueue(path)
        max_edge = max(cycle.dequeue())
        return max_edge

    # 4.3.16 practice, the solution is similar with 4.3.15
    def edge_add_to_mst(self, graph, new_edge):
        max_cycle_edge = self._get_max_cycle_edge(graph, new_edge)
        return new_edge < max_cycle_edge

    # 4.3.15 practice, the solution is given on the website,
    # see http://algs4.cs.princeton.edu/43mst/
    def incr_edge(self, graph, edge):
        max_cycle_edge = self._get_max_cycle_edge(graph, edge)
        self._mst.enqueue(edge)
        result = Queue([e for e in self._mst if e is not max_cycle_edge])
        self._mst = result
        return result

    # 4.3.14 practice, the solution is given on the website,
    # see http://algs4.cs.princeton.edu/43mst/
    def del_edge(self, graph, edge):

        if edge not in set(self._mst):
            return self._mst

        # init disjoint set with iterable object
        uf = GenericUnionFind([(e.either(), e.other(e.either()))
                               for e in self._mst if e is not edge])

        pq = MinPQ()
        for e in graph.edges():
            if e is not edge:
                pq.insert(e)

        tmp = Queue([e for e in self._mst if e is not edge])

        # find the minimum edge with both vertices is not connected
        while not pq.is_empty():
            min_edge = pq.del_min()
            vertx_a = min_edge.either()
            vertx_b = min_edge.other(vertx_a)

            if uf.connected(vertx_a, vertx_b):
                continue
            # only need one edge
            tmp.enqueue(min_edge)
            break

        self._mst = tmp
        return self._mst
class BellmanFordSP(ShortestPath):
    """
      BellmanFord Shortest Path algorithm. This version is not a traditional one,
    it's a queue-based version. First enqueue the source vertex, and dequeue the vertex,
    'relax' all adjacent edges and put the adjacent vertices into the queue until the queue
    is empty or find the negative cycle. A negative cycle check is nessesary every V times
    relaxtion.The cost of running time is proportional to O(V + E), the worst case is VE.
    This is a universal algorithm for Shortest Path algorithm.
    >>> 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, -1.2), (3, 6, 0.52), (6, 0, -1.4), (6, 4, -1.25))
    >>> ewd = EdgeWeightedDigraph()
    >>> for a, b, weight in test_data:
    ...     edge = DirectedEdge(a, b, weight)
    ...     ewd.add_edge(edge)
    ...
    >>> sp = BellmanFordSP(ewd, 0)
    >>> [sp.has_path_to(i) for i in range(8)]
    [True, True, True, True, True, True, True, True]
    >>> sp._has_negative_cycle()
    False
    >>> [edge for edge in sp.path_to(7)]
    [0->2 0.26, 2->7 0.34]
    >>> [edge for edge in sp.path_to(4)]
    [0->2 0.26, 2->7 0.34, 7->3 0.39, 3->6 0.52, 6->4 -1.25]
    """
    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._queue = Queue()
        self._queue.enqueue(source)
        self._on_queue = defaultdict(bool)
        self._on_queue[source] = True

        self._cost = 0
        self._cycle = None

        while not self._queue.is_empty() and not self._has_negative_cycle():
            vertex = self._queue.dequeue()
            self._on_queue[vertex] = False
            self.relax(graph, vertex)

        assert self.check(graph, source)

    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 not self._on_queue[end]:
                    self._queue.enqueue(end)
                    self._on_queue[end] = True

            if self._cost % graph.vertices_size() == 0:
                self._find_negative_cycle(graph)
            self._cost += 1

    def _find_negative_cycle(self, graph):
        spt = EdgeWeightedDigraph()
        for v in graph.vertices():
            if self._edge_to.get(v, None):
                spt.add_edge(self._edge_to[v])

        cf = EdgeWeightedDirectedCycle(spt)
        self._cycle = cf.cycle()

    def _has_negative_cycle(self):
        return self._cycle is not None

    def negative_cycle(self):
        return self._cycle

    def check(self, graph, source):
        # if negative cycle exists, check the total weight of the negative cycle is negative.
        if self._has_negative_cycle():
            if sum(e.weight for e in self.negative_cycle()) >= 0:
                print('positive weight from negative cycle')
                return False
        # no negative cycle
        else:
            # check vertex self._dist_to[v] and self._edge_to[v] are consistent
            if self._dist_to[source] != 0 or self._edge_to[source] is not None:
                print('the distance and edge_to of source vertex inconsistent')
                return False

            for v in graph.vertices():
                if v == source:
                    continue
                if self._edge_to[v] is None and self._dist_to[
                        v] != INFINITE_POSITIVE_NUMBER:
                    print('the distance and edge_to of {} inconsistent'.format(
                        v))
                    return False

            # check each edge is relaxed
            for v in graph.vertices():
                for e in graph.adjacent_edges(v):
                    if round(self._dist_to[v] + e.weight,
                             2) < self._dist_to[e.end]:
                        print('edge {} is not relaxed'.format(e))
                        return False

            # check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight()
            for v in graph.vertices():
                if self._edge_to[v] is None:
                    continue
                edge = self._edge_to[v]
                if v != edge.end:
                    print('here')
                    return False
                if round(self._dist_to[edge.start] + edge.weight,
                         2) != self._dist_to[v]:
                    print('edge {} on shortest path not tight'.format(edge))
                    return False

        return True
class TopologicalWithDegree(object):

    """
    >>> test_data = [(2, 3), (0, 6), (0, 1), (2, 0), (11, 12),
    ...              (9, 12), (9, 10), (9, 11), (3, 5), (8, 7),
    ...              (5, 4), (0, 5), (6, 4), (6, 9), (7, 6)]
    >>> graph = Digragh()
    >>> for a, b in test_data:
    ...     graph.add_edge(a, b)
    ...
    >>> twd = TopologicalWithDegree(graph)
    >>> twd.has_order()
    True
    >>> [v for v in twd.order()]
    [2, 8, 0, 3, 7, 1, 5, 6, 9, 4, 11, 10, 12]
    >>> twd.rank(8)
    1
    >>> twd.rank(10)
    11
    """

    def __init__(self, graph):
        indegree = defaultdict(int)
        self._order = Queue()
        self._rank = defaultdict(int)
        count = 0
        for v in graph.vertices():
            for adj in graph.get_adjacent_vertices(v):
                indegree[adj] += 1
        queue = Queue()
        for v in graph.vertices():
            if indegree[v] == 0:
                queue.enqueue(v)

        while not queue.is_empty():
            vertex = queue.dequeue()
            self._order.enqueue(vertex)
            self._rank[vertex] = count
            count += 1
            for v in graph.get_adjacent_vertices(vertex):
                indegree[v] -= 1
                if indegree[v] == 0:
                    queue.enqueue(v)

        if count != graph.vertices_size():
            self._order = None

        assert self.check(graph)

    def has_order(self):
        return self._order is not None

    def order(self):
        return self._order

    def rank(self, vertex):
        if vertex not in self._rank:
            return -1
        return self._rank[vertex]

    def check(self, graph):
        # digraph is acyclic
        if self.has_order():
            # check that ranks provide a valid topological order
            for vertex in graph.vertices():
                # check that vertex has a rank number
                if vertex not in self._rank:
                    return 1
                for adj in graph.get_adjacent_vertices(vertex):
                    if self._rank[vertex] > self._rank[adj]:
                        return 2
            # check that ranks provide a valid topological order
            for index, v in enumerate(self._order):
                if index != self._rank[v]:
                    return 3
            return True
        return False