Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Networkx python all_simple_paths returns path in (u, v, key) format

I am working on python 3 and networkx 2.0. For enumerating all simple paths between 2 nodes, I am using nx.all_simple_paths.

My graph is an undirected multigraph, nx.MultiGraph. Unfortunately, nx.all_simple_paths enumerates all the paths without including the edge key value. So it is not possible to distinguish easily between paths containing different parallel edges.

edge = [(1,2,1), (1,2,2), (1,2,3), (2,3,1), (2,3,2)]
g = nx.MultiGraph()
g.add_edges_from(edge)
for path in map(nx.utils.pairwise, nx.all_simple_paths(g,1,3)):     
    print(list(path))

Output for the above snippet is: (u, v)

[(1, 2), (2, 3)]
[(1, 2), (2, 3)]
[(1, 2), (2, 3)]
[(1, 2), (2, 3)]
[(1, 2), (2, 3)]
[(1, 2), (2, 3)]

But the desired output is: (u, v, key)

[(1, 2, 1), (2, 3, 1)]
[(1, 2, 1), (2, 3, 2)]
[(1, 2, 2), (2, 3, 1)]
[(1, 2, 2), (2, 3, 2)]
[(1, 2, 3), (2, 3, 1)]
[(1, 2, 3), (2, 3, 2)]

The reason why I would like the key value is that it would make my subsequent computations more efficient for mapping the corresponding edges.

I also tried to add key values while searching as follows:

def all_simple_paths(G, source=1, target=3, cutoff=(len(g) - 1)):
    if cutoff < 1:
        return
    visited = []
    for src, _, key in G.edges(source, keys=True):
        visited.append((src,key))
        stack = [((v, key) for u, v, key in G.edges(source, keys=True))]
        # print(list(stack))
        while stack:
            children = stack[-1]
            # print('children: ')
            child = next(children, None)
            # print(child)
            if child is None:
                # print('pop happened!')
                stack.pop()
                visited.pop()
            elif len(visited) < cutoff:
                # print('visited <cutoff: ')
                # print(visited)
                # print(list(child)[0])
                if child[0] == target:
                    # print('child is target')
                    print(visited + [target])
                    yield visited + [target]
                elif child not in visited:
                    # print("child not in visited")
                    visited.append(child)
                    # print(visited)
                    stack.append(((v, k) for u, v, k in G.edges(child, keys=True)))
            else:  # len(visited) == cutoff:
                # print('at cutoff')
                count = ([child] + list(children)).count(target)
                # print('count: ')
                # print(count)
                count = 1            # Dynamic count is not working
                for i in range(count):
                    # print(visited + [target])
                    yield visited + [target]
                stack.pop()
                visited.pop()

Output of the modified program (between nodes 1 and 3) is:

[(1, 1), (2, 1), 3]
[(1, 1), (2, 2), 3]
[(1, 1), (2, 3), 3]
[(1, 2), (2, 1), 3]
[(1, 2), (2, 2), 3]
[(1, 2), (2, 3), 3]
[(1, 3), (2, 1), 3]
[(1, 3), (2, 2), 3]
[(1, 3), (2, 3), 3]

The output is still not perfect. The key of edge 3 (refer the above output) is still missing and the count attribute in len(visited) == cutoff" is not dynamic (by default it returns 0)

like image 835
Arun Kumar Avatar asked Nov 15 '25 05:11

Arun Kumar


1 Answers

To get the desired output simply use nx.all_simple_edge_paths instead of nx.all_simple_paths

import networkx as nx

edge = [(1,2,1), (1,2,2), (1,2,3), (2,3,1), (2,3,2)]
g = nx.MultiGraph()
g.add_edges_from(edge)
for path in nx.all_simple_edge_paths(g,1,3):
    print(path)

Output:

[(1, 2, 1), (2, 3, 1)]
[(1, 2, 1), (2, 3, 2)]
[(1, 2, 2), (2, 3, 1)]
[(1, 2, 2), (2, 3, 2)]
[(1, 2, 3), (2, 3, 1)]
[(1, 2, 3), (2, 3, 2)]
like image 179
Ruan Carlo Weiers Britzke Avatar answered Nov 17 '25 17:11

Ruan Carlo Weiers Britzke



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!