I need to find a path (requirements see below) in a directed graph, whose nodes can be categeorized into layers. These layers are important for the structure of the graph (properties of graph see below)
Example of such a layered directed graph
Requirements of the path to be found:
- The path must start in the first layer and end in the last layer.
- There must be no nodes u,v of the path, which are connected by a backedge e=(u,v), (i.e. there must be no circle, whose nodes are all part of the path).
Example of an allowed path
Allowed path: p=(1,2,5,6,8,9), because there is no backedge between any of these nodes, i.e. there is no circle in the graph, which only consists of nodes from p.
Example of a disallowed path
Disallowed path: p=(1,2,4,6,8,9), because there is a backedge e=(4,1), i.e. there is a circle c=(1,2,4,1), where all the nodes are part of p.
Restricting properties of the directed graph:
- Each layer contains at least one node.
- A directed edge e=(u,v) can only exist, if layer(v) = layer(u) + 1 (i.e. to the next layer)
- A backedge e=(u,v) can only exist, if layer(u) >= layer(v) + 2 (i.e. at least two layers back)
- There is always atleast one "normal" path from first to last node.
- A special path (as described above) might not exist though.
I thought about a DFS like approach, or topological sorting (by ignoring back edge first). But I couldnt find an algorithm with feasable runtime. The Graph can get quite big (e.g. >100 nodes per layer with more than ten layers). Any ideas/hints, if an algorithm with reasonable complexity exists?
Context: This graph theory problem is a (hopefully useful) abstraction of another, more complex problem I'm trying to solve.
Edit1:
Here is the implementation, as suggested below, using python+networkx. Note, that the graph is built in such a way, that if there is a backedge e=(u,v) then always u>v applies. The user-data file is too big to post (>17000 lines).
def is_result(path, forbidden_pairs):
for (u,v) in forbidden_pairs:
if u in path and v in path:
return False;
return True;
def find_path(G, s, e):
forbidden_pairs = set()
for (u,v) in G.edges:
if (u > v):
forbidden_pairs.add((u,v))
for (u,v) in forbidden_pairs:
G.remove_edge(u,v)
for path in nx.all_shortest_paths(G, s, e):
if is_result(path, forbidden_pairs):
return(path)