Пример #1
0
def max_pairs(V1, V2, func=dfs):
    """
    ford fulkerson algorithm For maximum pairing:

    :param:
        @G: graph
        @V1,V2: groups of vertex for finding mach
        @func: function to use for find adding way by default is dfs, can be bfs


    :return: list of vertexes pairs for max pairing (=Original vertices)

    efficiency: O(|E|*n) where n is max pairing, in worst case n=|V1|
    """
    G_pairs = Graph()
    dic1, dic2 = {v: Vertex(name=v.name)
                  for v in V1}, {v: Vertex(name=v.name)
                                 for v in V2}
    dic, s, t = {**dic1, **dic2}, Vertex(name='s'), Vertex(name='t')
    dic = {dic[k]: k for k in dic}
    for v in dic1:
        G_pairs.connect(from_=s, to=dic1[v], weight=1)
    for v in dic2:
        G_pairs.connect(from_=dic2[v], to=t, weight=1)
    for v in dic1:
        for u in v.Adj:
            if u in dic2:
                G_pairs.connect(from_=dic1[v], to=dic2[u], weight=1)

    max_flow_ = ford_fulkerson(G_pairs, s, t, func=func)
    pairs = []
    for e in max_flow_:
        if max_flow_[e] and e.from_ != s and e.to != t:
            # pairs.append(dic[e.from_].Adj[dic[e.to]])
            pairs.append((dic[e.from_], dic[e.to]))
    return pairs
Пример #2
0
def johnson(G):
    """
    johnson algorithm:
        found distance between all pairs of vertex
        this method work also with negative edges

    @params:
        @G: graph

    return: (matrix of distances,matrix of pi)

    the algorithm:
        1. add vertex 's' with edges to all G.V with weight=0
        2. run bellman_ford from 's' => h[v] is the distance of v from 's' for all V
        3. for all w(v,u) from G.E add h[u]-h[v]
        4. D, PI = all_pairs_dijkstra(G)
        5. Correction of distances and edges: D[v,u]-=(h[u]-h[v])
                                              w(v,u)-= (h[u]-h[v]) for all G.E

    efficiency:
           if |E| * 0.75  < |V|^2: => O(V^2*log V)
           if |E| * 0.75  > |V|^2: => O(V*E) = O(|V|^3)
    """
    s = Vertex(name='s')
    G.V[s] = None
    for v in G.V:
        if v is not s:
            G.connect(from_=s, to=v, weight=0)
    pi = bellman_ford(G, s)
    if not pi:  # if there is negative circle in the graph
        return False
    h = {v: v.data['key'] for v in G.V}
    for e in G.E:
        e.weight += (h[e.from_] - h[e.to])

    D, PI = all_pairs_dijkstra(G)
    for i in range(len(D)):
        for j in range(len(D[i])):
            D[i][j] -= (h[list(G.V.keys())[i]] - h[list(G.V.keys())[j]])
    for e in list(s.edges.keys()):
        G.disconnect(e=e)
    del G.V[s]
    for e in G.E:
        e.weight -= (h[e.from_] - h[e.to])

    return list(np.array(D)[:-1, :-1]), list(np.array(PI)[:-1, :-1])
Пример #3
0
def kruskal(G, restore=False):
    """
       kruskal algorithm:

       @params:
           @G: graph
           @restore: if restore the solution

       return:
           return pi dictionary
           if restore=True the mst graph (=Minimal spreadsheet graph) will be return also

       efficiency:
           the sort of the edges: O(|E|log(|E|)) , the loop: O(|V|log(|V|) => total: O(|E|log(|E|)
           if the edges already sorted kruskal is fasted than prim
       """
    def union(e):
        v, u = set_id[e.from_], set_id[e.to]
        v, u = (v, u) if sets[v].n > sets[u].n else (u, v)
        for node in sets[u]:
            set_id[node.data] = v
        sets[v] = sets[v] + sets[u]
        sets.pop(u)

    E_sor, sets, set_id = sorted(
        G.E, key=lambda e: e.weight), {v: TwoWayList()
                                       for v in G.V}, {v: v
                                                       for v in G.V}
    for v, lis in sets.items():
        lis += v

    A = []
    for e in E_sor:
        if set_id[e.from_] is not set_id[e.to]:
            A.append(e)
            union(e)

    if restore:
        V = {v: Vertex(name=v.name, data=v.data) for v in G.V}
        G_mst = GraphNotAimed()
        for e in A:
            G_mst.connect(from_=V[e.from_], to=V[e.to], weight=e.weight)
        return A, G_mst

    return A
Пример #4
0
def prim(G, restore=False):
    """
    prim algorithm:
        if |E| * 0.75  < |V|^2 : the struct will be min heap
        else:                    the struct will be array

    @params:
        @G: graph
        @restore: if restore the solution

    return:
        return pi dict
        if restore=True the mst graph (=Minimal spreadsheet graph) will be return also

    efficiency:
        if |E| * 0.75  < |V|^2: => O(Vlog V)
        if |E| * 0.75  > |V|^2: => O(E) = O(|V|^2)
    """
    struct = 'heap' if len(G.E) < (len(G.V)**2) * 0.75 else 'array'
    pi = {v: None for v in G.V}
    for v in G.V:
        v.data = {'key': float('inf'), 'in heap': True}
    list(G.V.keys())[0].data['key'] = 0
    key = lambda v: v.data['key']
    Q = BinaryHeapPrim(arr=G.V, compare=min,
                       key=key) if struct == 'heap' else [v for v in G.V]

    while struct == 'heap' and Q.arr or struct == 'array' and Q:
        v, v.data['in heap'] = Q.extract() if struct == 'heap' else Q.pop(
            Q.index(min(Q, key=key))), False
        for e in v.edges:
            if e.to.data['in heap'] and e.weight < e.to.data['key']:
                pi[e.to], e.to.data['key'] = v, e.weight
                if struct == 'heap':
                    Q.add(Q.pop(e.to.data['i']))

    if restore:
        V = {v: Vertex(name=v.name, data=v.data) for v in G.V}
        G_mst = GraphNotAimed()
        for v, u in pi.items():
            if u:
                G_mst.connect(from_=V[v], to=V[u], weight=v.data['key'])
        return pi, G_mst

    return pi
Пример #5
0
def init_G_r(G):
    """
    init the Residual graph

    @params:
        @G: graph

    efficiency: O(|E|+|V|)
    """
    G_r = Graph()
    V = [Vertex(name=v.name) for v in G.V]
    dic = {}
    for v1, v2 in zip(G.V, V):
        dic[v1] = v2

    for e in G.E:
        G_r.connect(from_=dic[e.from_], to=dic[e.to], weight=e.weight)

    return G_r, dic
Пример #6
0
def tie_well_graph(G):
    """
    efficiency: O(V+E)
    """
    tie_well = sccg(G)
    G_scc = Graph()

    for v_group, i in zip(tie_well, range(len(tie_well))):
        v = Vertex(name=str(v_group), data={'group': v_group})
        for v1 in v_group:
            v1.data['group'] = v
    for v in G.V:
        for u in v.Adj:
            if v.data['group'] != u.data['group']:
                G_scc.connect(from_=v.data['group'],
                              to=u.data['group'],
                              weight=v.Adj[u].weight)

    return G_scc
Пример #7
0
    for v in dic1:
        for u in v.Adj:
            if u in dic2:
                G_pairs.connect(from_=dic1[v], to=dic2[u], weight=1)

    max_flow_ = ford_fulkerson(G_pairs, s, t, func=func)
    pairs = []
    for e in max_flow_:
        if max_flow_[e] and e.from_ != s and e.to != t:
            # pairs.append(dic[e.from_].Adj[dic[e.to]])
            pairs.append((dic[e.from_], dic[e.to]))
    return pairs


if __name__ == '__main__':
    V = [Vertex(name=str(i)) for i in range(8)]
    V[0].name, V[1].name, V[2].name, V[3].name, V[4].name, V[5].name, V[6].name, V[7].name = \
        's', '1', '2', '3', '4', '5', '6', 't'
    G = Graph()
    for i in range(8):
        G.V[V[i]] = None
    G.connect(from_=V[0], to=V[1], weight=3)
    G.connect(from_=V[0], to=V[2], weight=3)
    G.connect(from_=V[1], to=V[2], weight=1)
    G.connect(from_=V[1], to=V[3], weight=3)
    G.connect(from_=V[2], to=V[3], weight=1)
    G.connect(from_=V[2], to=V[4], weight=3)
    G.connect(from_=V[3], to=V[4], weight=2)
    G.connect(from_=V[3], to=V[5], weight=3)
    G.connect(from_=V[4], to=V[5], weight=2)
    G.connect(from_=V[4], to=V[6], weight=3)
Пример #8
0
    D, PI = all_pairs_dijkstra(G)
    for i in range(len(D)):
        for j in range(len(D[i])):
            D[i][j] -= (h[list(G.V.keys())[i]] - h[list(G.V.keys())[j]])
    for e in list(s.edges.keys()):
        G.disconnect(e=e)
    del G.V[s]
    for e in G.E:
        e.weight -= (h[e.from_] - h[e.to])

    return list(np.array(D)[:-1, :-1]), list(np.array(PI)[:-1, :-1])


if __name__ == '__main__':
    V = [Vertex(name=str(i)) for i in range(8)]
    # V[0].name, V[1].name, V[2].name, V[3].name, V[4].name, V[5].name, V[6].name = '0', '1', '2', '3', '4', '5', '6'
    # r = Edge(from_=V[0], to=V[1], weight=3)
    G = GraphNotAimed()
    for i in range(8):
        G.V[V[i]] = None
    G.connect(from_=V[0], to=V[1], weight=4)
    G.connect(from_=V[0], to=V[4], weight=3)
    G.connect(from_=V[0], to=V[3], weight=2)
    G.connect(from_=V[1], to=V[2], weight=5)
    G.connect(from_=V[1], to=V[4], weight=4)
    G.connect(from_=V[1], to=V[5], weight=6)
    G.connect(from_=V[2], to=V[5], weight=1)
    G.connect(from_=V[3], to=V[4], weight=6)
    G.connect(from_=V[4], to=V[5], weight=8)
    # ---------------------