0

In the context of graph theory, I'm trying to get all the possible simple paths between two nodes.

I record the network using an adjacency matrix stored in a pandas dataframe, in a way that network[x][y] store the value of the arrow which goes from x to y.

To get the paths between two nodes, what I do is:

I get all the possible permutations with all the nodes (using it.permutations -as the path is simple there is no repetitions). Then I use an ad hoc function: adjacent (which gives me the neighbours of a node), to check which among all the possible paths are true.

This takes too long, and it's not efficient. Do you know how I can improve the code? May be with a recursive function??

For a non relevant reason I don't want to use Networkx

def get_simple_paths(self, node, node_objective):

    # Gives you all simple path between two nodes

    #We get all possibilities and then we will filter it
    nodes = self.nodes #The list of all nodes
    possible_paths = [] #Store all possible paths
    simple_paths = [] #Store the truly paths
    l = 2        
    while l <= len(nodes):
        for x in it.permutations(nodes, l): #They are neighbourgs
            if x[0] == node and x[-1] == node_objective:
                possible_paths.append(x)
        l += 1

    # Now check which of those paths exists
    for x_pos, x in enumerate(possible_paths):
        for i_pos, i in enumerate(x): 
#We use it to check among all the path, 
#if two of the nodes are not neighbours, the loop brokes 
            if i in self.adjacencies(x[i_pos+1]):
                if i_pos+2 == len(x):
                    simple_paths.append(x)
                    break
                else:
                    continue
            else:
                break
    #Return simple paths    
    return(simple_paths)
Xbel
  • 735
  • 1
  • 10
  • 30
  • The number of simple paths may be exponential in the number of nodes. Take the directed `n x n`-grid graph as an example ( `G=(V,E); V(G) = { (x,y) in {0,..,n}^2 }, E = { ((x,y), (x+1,y)) | 0 <= x < n, 0 <= y <= n } U { ((x,y), (x,y+1)) | 0 <= x <= n, 0 <= y < n }`. The number of simple paths between `(0,0)` and any sink `(n,n)` is strictly larger than the number of paths to the diagonal ( `{ (x,n-x) | 0 <= x <= n }` ) which is `2^n`. Therefore your code will not produce a result 'efficiently' since printing out the the result is 'inefficent'. Note that the graph itself is planar, ie. sparse. – collapsar Feb 05 '18 at 17:53
  • Addendum: [This MO post](https://math.stackexchange.com/questions/2071755/bound-for-the-number-of-simple-paths-between-s-and-t) discusses the worst case (complete undirected graph). – collapsar Feb 05 '18 at 18:12
  • Thanks for the comment. I know which kind of problem is, in fact it has the tag NP. I'm not asking for the 'best' way to do it, I'm asking if there is a better way than mine to do it (which I'm sure it is). This is, the problem can be solved in different inefficient ways, I'm looking for one which, despite being inefficient works better than mine. – Xbel Feb 05 '18 at 20:57
  • Ok, though I'd guess this problem was beyond np - the correctness of an exponential number of enumerated paths needs to be checked. A modified dfs should do the trick, without cross edge detection (cycles would still be detected by retracting from back edges; during the dfs maintain the current root path; whenever the dfs reaches the target node, add the then current root path to the result list). This seems to be better than generating all node permutations and then weeding out all paths containing edges not in `G`. – collapsar Feb 05 '18 at 21:16
  • Thanks, I'll try. – Xbel Feb 06 '18 at 08:52

0 Answers0