Possible Duplicate:
[python]: path between two nodes
Can anyone point me to some resources on how to do this? I'm using networkx
as my python library.
Thanks!
2.1.0.7 Simple DAG Properties (A) Every DAG G has at least one source and at least one sink.
Do a topological sort of the DAG, then scan the vertices from the target backwards to the source. For each vertex v , keep a count of the number of paths from v to the target.
In a DAG, a source is a vertex without incoming edges; a sink is a vertex without outgoing edges.
Given a Weighted Directed Acyclic Graph and a source vertex in the graph, find the shortest paths from given source to all other vertices. For a general weighted graph, we can calculate single source shortest distances in O(VE) time using Bellman–Ford Algorithm.
This is based on Alex Martelli's answer, but it should work. It depends on the expression source_node.children
yielding an iterable that will iterate over all the children of source_node
. It also relies on there being a working way for the ==
operator to compare two nodes to see if they are the same. Using is
may be a better choice. Apparently, in the library you're using, the syntax for getting an iterable over all the children is graph[source_node]
, so you will need to adjust the code accordingly.
def allpaths(source_node, sink_node):
if source_node == sink_node: # Handle trivial case
return frozenset([(source_node,)])
else:
result = set()
for new_source in source_node.children:
paths = allpaths(new_source, sink_node, memo_dict)
for path in paths:
path = (source_node,) + path
result.add(path)
result = frozenset(result)
return result
My main concern is that this does a depth first search, it will waste effort when there are several paths from the source to a node that's a grandchild, great grandchild, etc all of source, but not necessarily a parent of sink. If it memoized the answer for a given source and sink node it would be possible to avoid the extra effort.
Here is an example of how that would work:
def allpaths(source_node, sink_node, memo_dict = None):
if memo_dict is None:
# putting {}, or any other mutable object
# as the default argument is wrong
memo_dict = dict()
if source_node == sink_node: # Don't memoize trivial case
return frozenset([(source_node,)])
else:
pair = (source_node, sink_node)
if pair in memo_dict: # Is answer memoized already?
return memo_dict[pair]
else:
result = set()
for new_source in source_node.children:
paths = allpaths(new_source, sink_node, memo_dict)
for path in paths:
path = (source_node,) + path
result.add(path)
result = frozenset(result)
# Memoize answer
memo_dict[(source_node, sink_node)] = result
return result
This also allows you to save the memoization dictionary between invocations so if you need to compute the answer for multiple source and sink nodes you can avoid a lot of extra effort.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With