SirSteel
SirSteel

Reputation: 153

Efficiently check if path is valid in graph using NetworkX?

I would like to find an efficient way to check if a given "Walk" through a graph is valid.

Such a function should accept a Graph (nodes, edges) and a string of node names, and should output True if nodes can be visited in the given sequence according to the graph and false if not.

Preferably, I would use the NetworkX library, since I already use it to store and represent the graph.

Something resembling this:

""" G:
    Q1 -> Q1
    Q1 -> Q2
    Q2 -> Q2
"""
accepts(G, ["Q1", "Q1", "Q2"]) 
>> True
accepts(G, ["Q2", "Q2", "Q2"]) 
>> True
accepts(G, ["Q2", "Q2", "Q1"]) 
>> False
accepts(G, ["Q1", "Q2", "Q1"]) 
>> False
accepts(G, ["Q1", "Q1", "Q2", "Q1"]) 
>> False

This would be used for a automata class. To basically check for membership of a string given a language represented by the graph.

Upvotes: 0

Views: 1534

Answers (2)

Aleksi Torhamo
Aleksi Torhamo

Reputation: 6632

While @newbie's sentiment that "You only need to check if all the edges of the path are valid" is correct, the implementation he gives is far from efficient; graph.edges() rebuilds a list of all the graph's edges from scratch for every edge in the path. Instead of (u, v) in g.edges() you should always use g.has_edge(u, v), which is a constant-time operation. Although it seems you're working with DiGraph at the moment, the latter method also has the added benefit of working for both Graph and DiGraph, while the earlier method only works for DiGraph. (This is because a Graph's edges() method only returns the edges in one (random) direction, so checking for the edge in one direction only does not suffice; g.has_edge() does the right thing here for both Graph and DiGraph)

Long story short, use:

def accepts(g, path):
    return all([g.has_edge(path[i], path[i+1]) for i in range(len(path)-1)])

Or, a bit more concisely:

def accepts(g, path):
    return all(map(g.has_edge, path, path[1:]))

Upvotes: 1

abc
abc

Reputation: 11929

You only need to check if all the edges of the path are valid.

def accepts(g, path):
    return all([(path[i],path[i+1]) in g.edges() for i in range(len(path)-1)])

Example:

g=nx.DiGraph()
g.add_edge("Q1","Q1")
g.add_edge("Q1","Q2")
g.add_edge("Q2","Q2")

print(accepts(g, ["Q1", "Q1", "Q2"]))
print(accepts(g, ["Q2", "Q2", "Q2"]))
print(accepts(g, ["Q2", "Q2", "Q1"]))
print(accepts(g, ["Q1", "Q2", "Q1"]))
print(accepts(g, ["Q1", "Q1", "Q2", "Q1"]))

Upvotes: 2

Related Questions