Suppose I have 2 graphs A and B and I want to know if A is a subgraph of B.
The nodes contain attributes, say, 'size' and 'material'.
When I run:
GM = networkx.algorithms.isomorphism.GraphMatcher(B,A)
print networkx.algorithms.isomorphism.subgraph_is_isomorphic()
This only matches graph by edges only and not by edges and attribute.
Any clue on how check attributes?
Also, suppose B contains 2 connected graphs of A.
When I run:
GM.mapping
This will output only 1 of the subgraphs of A. Any idea on how to output every subgraph?
I've solved this by using:
print GM = iso.GraphMatcher(B,A,node_match=iso.categorical_node_match(['material', 'size'],['metal',1]))
What I didn't know before is that ['metal',1] is just a default and not a hard match.
You can iterate over all possible subgraphs in the following way
GM = networkx.algorithms.isomorphism.GraphMatcher(B,A)
for subgraph in GM.subgraph_isomorphisms_iter():
print subgraph
subgraph in this example is a dictionary that maps nodes of B to nodes of A.
For the question of attribute matching, drum's suggestion has worked for me. Additional attribute matching actually speeds up things significantly for large graphs.
Related
I'm trying to detect some minimal patterns with properties in random digraphs. Namely, I have a list called patterns of adjacency matrix of various size. For instance, I have [0] (a sink), but also a [0100 0001 1000 0010] (cycle of size 4), [0100, 0010, 0001, 0000] a path of length 3, etc.
When I generate a digraph, I compute all sets that may be new patterns. However, in most of the case it is something that I don't care about: for instance, if the potential new pattern is a cycle of size 5, it does not teach me anything because it has a cycle of length 3 as an induced subgraph.
I suppose one way to do it would look like this:
#D is the adjacency matrix of a possible new pattern
new_pattern = True
for pi in patterns:
k = len(pi)
induced_subgraphs = all_induced_subgraphs(D, k)
for s in induced_subgraphs:
if isomorphic(s, pi):
new_pattern = False
break
where all_induced_subgraphs(D,k) gives all possible induced subgraphs of D of size k, and isomorphic(s,pi) determines if s and pi are isomorphic digraphs.
However, checking all induced subgraphs of a digraph seems absolutely horrible to do. Is there a clever thing to do there?
Thanks to #Stef I learned that this problem has a name
and can be solved using on netwokx with a function described on this page.
Personally I use igraph on my project so I will use this.
Given 1 graph (A) and another graph (B) , minimum number of edges and vertice to add or remove such that you can get from graph A to graph B.
Current Approach: Find the number of vertices that are present in graph A but not in graph B. Both the graphs can have branches. In the example it's a linked list but it doesn't always need to be like that. Then remove all those vertices, then remove all the edges that dont exist in A but are present in B. Then add vertices that are present in graph A but not in graph B. Then add edges that are not present. However, this approach doesnt take in consideration the subgraph method, but just edge by Edge. The issue is that graph A can have multiple same nodes:
A - B - A - A - B - C
graph B:
B - B - A
B B - A
But now I am not sure which B should I add the A-B, i.e. not sure which B corresponds from graph B to graph A. In the example it is the second B that corresponds with the first B in graph A. I have been working on this for the past 2 days and I am stuck here. This is not a homework, its a problem I have been working on. Any help will be appreciated. A premade library in python would also help. Thanks
Imagine that you have a set of nodes (1 2 3) and that these nodes are connected through arcs (1,2), (1,3) and (2,3). Together representing a network.
How can I create a subset of nodes, containing all neighboring nodes? i.e. I wan't the following subset to be something like:
NeighborNode
1 2 3
2 1 3
3 1 2
This Python code is far off, but maybe you get the idea:
def NNode_rule(model,i):
for i in model.Nodes:
model.NNodes[i].add(model.ToNode[i]) if model.Nodes[i]==model.FromNode[i]
model.NNodes = Set(model.Nodes, initialize=NNode_rule)
Do you know what Object-oriented programming is?
I think the easiest solution is to create a simple class (e.g. Node) that has an attribute neighbors which is a list of other nodes.
You also need a method that adds an edge between two nodes, something like this:
def add_edge(self, other_node):
self.neighbors.append(other_node)
other_node.neighbors.append(self)
Then every Node holds the information which neighbors it has.
Hope this helps ;)
I have made large graph with NetworkX with about 20,000 nodes. I would like to delete nodes with only one tie (or zero ties) to try to reduce the clutter. Since it is a very large graph I do not know the nodes by name or ID that have tie=1 or 0.
Does anyone know how to delete these nodes without specifying the node ID or name?
Iterating on a Graph g yields all of g's nodes, one at a time -- I believe you can't alter g during the iteration itself, but you can selectively make a list of nodes to be deleted, then remove them all:
to_del = [n for n in g if g.degree(n) <= 1]
g.remove_nodes_from(to_del)
I think you're after this one-liner:
G= nx.k_core(G,k=2)
You should be aware that if you delete some nodes, you'll have new nodes whose degree is just 1 or 0. If you want to repeat this process until no such nodes exist, you're generating the "k-core" with k=2. That is you're generating the largest network for which all nodes have degree at least 2. This is a built-in function:
import networkx as nx
G = nx.fast_gnp_random_graph(10000,0.0004) #erdos renyi graph, average degree = 4
G = nx.k_core(G,k=2)
You could instead do:
for node in G.nodes():
if G.degree(node)<2:
G.remove_node(node)
but this would yield a different result from the 2-core I described above, and a different result from A Martelli's as well since some of the later nodes in the list may originally have degree 2 but be reduced to 1 before you reach them. And it wouldn't be as clean because it creates the list G.nodes() rather than using a nicer iterator (if you're in networkx v1.x and you aren't altering a graph in the loop, it's usually better to loop through the nodes with G.nodes_iter() rather than G.nodes())
I am trying to calculate shortest path between 2 points using Dijkstra and A Star algorithms (in a directed NetworkX graph).
At the moment it works fine and I can see the calculated path but I would like to find a way of restricting certain paths.
For example if we have following nodes:
nodes = [1,2,3,4]
With these edges:
edges = ( (1,2),(2,3),(3,4) )
Is there a way of blocking/restricting 1 -> 2 -> 3 but still allow 2 -> 3 & 1 -> 2.
This would mean that:
can travel from 1 to 2
can travel from 2 to 3
cannot travel from 1 to 3 .. directly or indirectly (i.e. restrict 1->2->3 path).
Can this be achieved in NetworkX.. if not is there another graph library in Python that would allow this ?
Thanks.
Interesting question, I never heard of this problem, probably because I don't have much background in this topic, nor much experience with NetworkX. However, I do have a idea for a algorithm. This may just be the most naive way to do this and I'd be glad to hear of a cleverer algorithm.
The idea is that you can use your restriction rules to transform you graph to a new graph where all edges are valid, using the following algorithm.
The restriction of path (1,2,3) can be split in two rules:
If you came over (1,2) then remove (2,3)
If you leave over (2,3) then remove (1,2)
To put this in the graph you can insert copies of node 2 for each case. I'll call the new nodes 1_2 and 2_3 after the valid edge in the respective case. For both nodes, you copy all incoming and outgoing edges minus the restricted edge.
For example:
Nodes = [1,2,3,4]
Edges = [(1,2),(2,3),(4,2)]
The valid path shall only be 4->2->3 not 1->2->3. So we expand the graph:
Nodes = [1,1_2,2_3,3,4] # insert the two states of 2
Edges = [ # first case: no (1_2,3) because of the restriction
(1,1_2), (4, 1_2)
# 2nd case, no (1,2_3)
(2_3,3), (4,2_3)]
The only valid path in this graph is 4->2_3->3. This simply maps to 4->2->3 in the original graph.
I hope this answer can at least help you if you find no existing solution. Longer restriction rules would blow up the graph with a exponentially growing number of state nodes, so either this algorithm is too simple, or the problem is hard ;-)
You could set your node data {color=['blue']} for node 1, node 2 has {color=['red','blue']} and node3 has {color=['red']}. Then use an networkx.algorithms. astar_path() approach setting the
heuristic is set to a function which returns a might_as_well_be_infinity when it encountered an node without the same color you are searching for
weight=less_than_infinity.