Graph ===== Unit tests for Graph Class -------------------------- >>> from networkx import * >>> import networkx >>> is_isomorphic=networkx.algorithms.isomorphism.isomorph.graph_could_be_isomorphic >>> from networkx import convert_node_labels_to_integers as cnlti Some small graphs ----------------- >>> null=null_graph() >>> P1=cnlti(path_graph(1),first_label=1) >>> P3=cnlti(path_graph(3),first_label=1) >>> P10=cnlti(path_graph(10),first_label=1) >>> K1=cnlti(complete_graph(1),first_label=1) >>> K3=cnlti(complete_graph(3),first_label=1) >>> K4=cnlti(complete_graph(4),first_label=1) >>> K5=cnlti(complete_graph(5),first_label=1) >>> K10=cnlti(complete_graph(10),first_label=1) Name ---- >>> G = Graph(name="test") >>> print G # test of __str__ test >>> print G.name test >>> H=Graph() >>> print H.name >>> G2=Graph(data={1:[2],2:[1]}, name="test") >>> print G2.edges() [(1, 2)] >>> print G2.name test Nodes ----- >>> G.add_node('A') >>> G.has_node('A') True Test if a non-hashable object is in the Graph. A python dict will raise a TypeError, but for a Graph class a simple False should be returned (see Graph __contains__). If it cannot be a node then it is not a node. >>> G.has_node(['A']) False >>> G.has_node({'A':1}) False >>> G.remove_node('A') >>> G.has_node('A') False >>> G.add_nodes_from(list("ABCDEFGHIJKL")) >>> G.has_node("L") True >>> G.remove_nodes_from(['H','I','J','K','L']) >>> G.add_nodes_from([1,2,3,4]) >>> sorted(G.nodes()) [1, 2, 3, 4, 'A', 'B', 'C', 'D', 'E', 'F', 'G'] >>> sorted(G) # test __iter__ [1, 2, 3, 4, 'A', 'B', 'C', 'D', 'E', 'F', 'G'] test __contains__ >>> 'A' in G True >>> [] in G # never raise a Key or TypeError in this test False >>> {1:1} in G False test __len__ >>> len(G) 11 test node portion of clear() >>> G.clear() >>> G.nodes() [] Test add_node and remove_node acting for various nbunch >>> G.add_node('m') >>> G.has_node('m') True >>> G.add_node('m') # no complaints >>> G.remove_node('j') # NetworkXError Traceback (most recent call last): ... NetworkXError: The node j is not in the graph. >>> G.remove_node('m') >>> G.nodes() [] nbunch is a list. >>> G.add_nodes_from(list("ABCD")) >>> G.add_nodes_from(P3) # add nbunch of nodes (nbunch=Graph) >>> sorted(G.nodes()) [1, 2, 3, 'A', 'B', 'C', 'D'] >>> G.remove_nodes_from(P3) # remove nbunch of nodes (nbunch=Graph) >>> sorted(G.nodes()) ['A', 'B', 'C', 'D'] nbunch is a set >>> nbunch=set("ABCDEFGHIJKL") >>> G.add_nodes_from(nbunch) >>> G.has_node("L") True nbunch is a dict with nodes as keys >>> nbunch={'I':"foo",'J':2,'K':True,'L':"spam"} >>> G.remove_nodes_from(nbunch) >>> sorted(G.nodes()) ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] nbunch is an iterator >>> n_iter=P3.nodes_iter() >>> G.add_nodes_from(n_iter) >>> sorted(G.nodes()) [1, 2, 3, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] >>> n_iter=P3.nodes_iter() # rebuild same iterator >>> G.remove_nodes_from(n_iter) # remove nbunch of nodes (nbunch=iterator) >>> sorted(G.nodes()) ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] nbunch is a graph >>> nbunch=K3 >>> G.add_nodes_from(nbunch) >>> sorted(G.nodes()) [1, 2, 3, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] Edges ----- >>> G.add_edge('A') Traceback (most recent call last): ... TypeError: add_edge() takes at least 3 arguments (2 given) >>> G.add_edge('A','B') # testing add_edge() >>> G.add_edge('A','B') # should fail silently >>> G.has_edge('A','B') # testing has_edge() True >>> G.has_edge('A','C') False >>> G.has_edge( *('A','B') ) True >>> G.has_edge('B','A') # G is undirected, so B->A is an edge True >>> G.add_edge('A','C') # test directedness >>> G.add_edge('C','A') >>> G.remove_edge('C','A') >>> G.has_edge('A','C') # G is undirected False >>> G.has_edge('C','A') False >>> G.add_edge('A','A') # test self loops >>> G.has_edge('A','A') # should have edge True >>> G.remove_edge('A','A') >>> G.add_edge('X','X') >>> G.has_node('X') # added node but not self loop True >>> G.remove_node('X') >>> G.add_edge('A','Z') # should add the node silently >>> G.has_node('Z') True >>> G.add_edges_from([('B','C')]) # test add_edges_from() >>> G.has_edge('B','C') True >>> G.has_edge('C','B') # undirected True >>> G.add_edges_from([('D','F'),('B','D')]) >>> G.has_edge('D','F') True >>> G.has_edge('B','D') True >>> G.has_edge('D','B') # undirected True >>> G.add_edges_from([tuple('IJ'),list('KK'),tuple('JK')]) # after failing silently, should add 2nd edge >>> G.has_edge(*('I','J')) True >>> G.has_edge(*('K','K')) True >>> G.has_edge(*('J','K')) True >>> G.has_edge(*('K','J')) # undirected True >>> G.add_edges_from(zip(list('ACD'),list('CDE'))) >>> G.has_edge('D','E') True >>> G.has_edge('E','C') False >>> G.add_edges_from(zip(list('MNOP'),list('NOPM'))) >>> G.has_edge('O','P') True >>> G.has_edge('P','M') True >>> G.remove_node('P') # tests remove_node()'s handling of edges. >>> G.has_edge('P','M') False >>> G.remove_edge('M') # test remove_edge() Traceback (most recent call last): ... TypeError: remove_edge() takes exactly 3 arguments (2 given) >>> G.add_edge('N','M') >>> G.has_edge('M','N') True >>> G.remove_edge('M','N') >>> G.has_edge('M','N') False >>> G.has_edge('N','M') # undirected False >>> G.remove_edges_from([list('HI'),list('DF'),tuple('KK'),tuple('JK')]) # self loop fails silently >>> G.has_edge('H','I') False >>> G.has_edge('J','K') False >>> G.remove_edges_from([list('IJ'),list('KK'),list('JK')]) >>> G.has_edge('I','J') False >>> G.remove_nodes_from(set('ZEFHIMNO')) >>> sorted(G.nodes()) [1, 2, 3, 'A', 'B', 'C', 'D', 'G', 'J', 'K'] >>> G.remove_nodes_from([1,2,3]) >>> sorted(G.nodes()) ['A', 'B', 'C', 'D', 'G', 'J', 'K'] >>> sorted(G.edges()) [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'B'), ('C', 'D')] Test G.edges(nbunch) with various forms of nbunch node not in nbunch should be quietly ignored >>> sorted(G.edges(6)) # non-iterable non-node Traceback (most recent call last): ... NetworkXError: nbunch is not a node or a sequence of nodes. >>> sorted(G.edges('Z')) # iterable non-node [] nbunch can be an empty list >>> sorted(G.edges([])) [] nbunch can be a list >>> sorted(G.edges(['A','B'])) [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')] nbunch can be a set >>> sorted(G.edges(set(['A','B']))) [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')] nbunch can be a graph >>> G1=Graph() >>> G1.add_nodes_from('AB') >>> sorted(G.edges(G1)) # nbunch is a graph [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')] nbunch can be a dict with nodes as keys >>> ndict={'A': "thing1", 'B': "thing2"} >>> sorted(G.edges(ndict)) [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')] nbunch can be a single node >>> sorted(G.edges('A')) [('A', 'B'), ('A', 'C')] Test G.edges_iter(nbunch) with various forms of nbunch node not in nbunch should be quietly ignored >>> sorted(G.edges_iter('Z')) [] nbunch can be an empty list >>> sorted(G.edges_iter([])) [] nbunch can be a list >>> sorted(G.edges_iter(['A','B'])) [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')] nbunch can be a set >>> sorted(G.edges_iter(set(['A','B']))) [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')] nbunch can be a graph >>> G1=Graph() >>> G1.add_nodes_from(['A','B']) >>> sorted(G.edges_iter(G1)) # nbunch is a graph [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')] nbunch can be a dict with nodes as keys >>> ndict={'A': "thing1", 'B': "thing2"} >>> sorted(G.edges_iter(ndict)) [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')] nbunch can be a single node >>> sorted(G.edges_iter('A')) [('A', 'B'), ('A', 'C')] nbunch can be nothing (whole graph) >>> sorted(G.edges_iter()) [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'B'), ('C', 'D')] >>> sorted(G.nodes_iter()) ['A', 'B', 'C', 'D', 'G', 'J', 'K'] Properties ---------- degree of single node must return single int >>> G.degree('A') 2 degree of single node in iterable container must return dict >>> G.degree(['A']).values() [2] >>> G.degree(['A']) {'A': 2} >>> G.degree(['A','B']).values() [2, 3] >>> G.degree(['A','B']) {'A': 2, 'B': 3} >>> sorted(G.degree().values()) [0, 0, 0, 2, 2, 3, 3] sorted(list(G.degree_iter())) [0, 0, 0, 2, 2, 3, 3] >>> H=Graph() >>> H.add_edges_from([(1,24),(1,2)]) >>> sorted(H.degree([1,24]).values()) [1, 2] >>> P3=path_graph(3) >>> P5=path_graph(5) >>> P3.degree(['A','B']) # silently ignore nodes not in P3 {} >>> sorted(P5.degree(P3).values()) # nbunch can be a graph [1, 2, 2] >>> sorted(P3.degree(P5).values()) # nbunch can be a graph thats way to big [1, 1, 2] >>> P5.degree([]) {} >>> list(P5.degree_iter([])) [] >>> dict( P5.degree_iter([]) ) {} >>> dict(P5.degree_iter([])) {} >>> null=null_graph() >>> null.degree() {} >>> list(null.degree_iter()) [] >>> dict(null.degree_iter()) {} >>> G.order() 7 >>> G.size() 5 >>> G.number_of_edges() 5 >>> G.number_of_edges('A','B') 1 >>> G.number_of_edges('A','D') 0 Operations ----------- copy ~~~~ >>> H=G.copy() # copy >>> H.adj==G.adj True >>> H.name==G.name True >>> H==G False subgraph >>> SG=G.subgraph(['A','B','D']) >>> sorted(SG.nodes()) ['A', 'B', 'D'] >>> sorted(SG.edges()) [('A', 'B'), ('B', 'D')] to_directed DG=G.to_directed() DG==G False DG.is_directed() True G.is_directed() False DG.name==G.name True DG.adj==G.adj True sorted(DG.out_edges(list('AB'))) [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('B', 'D')] DG.remove_edge('A','B') DG.has_edge('B','A') # this removes B-A but not A-B True DG.has_edge('A','B') False # to_undirected Neighbors --------- >>> sorted(G['A']) ['B', 'C'] >>> sorted(G.neighbors('A')) ['B', 'C'] >>> sorted(G.neighbors_iter('A')) ['B', 'C'] >>> sorted(G.neighbors('G')) [] >>> sorted(G.neighbors('j')) Traceback (most recent call last): ... NetworkXError: The node j is not in the graph. Iterators --------- >>> sorted(G.nodes_iter()) ['A', 'B', 'C', 'D', 'G', 'J', 'K'] >>> sorted(G.edges_iter()) [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'B'), ('C', 'D')] sorted(G.degree_iter()) [0, 0, 0, 2, 2, 3, 3] >>> sorted(G.degree_iter()) [('A', 2), ('B', 3), ('C', 3), ('D', 2), ('G', 0), ('J', 0), ('K', 0)] >>> sorted(G.neighbors_iter('A')) ['B', 'C'] >>> sorted(G.neighbors_iter('X')) Traceback (most recent call last): ... NetworkXError: The node X is not in the graph. >>> G.clear() >>> number_of_nodes(G) 0 >>> number_of_edges(G) 0 Subgraph -------- Subgraph of a null graph is a null graph >>> nullgraph=null_graph() >>> G=null_graph() >>> H=G.subgraph([]) >>> is_isomorphic(H,nullgraph) True Subgraph of an empty graph is an empty graph. test 1 >>> E5=empty_graph(5) >>> E10=empty_graph(10) >>> H=E10.subgraph([]) >>> is_isomorphic(H,nullgraph) True Subgraph of an empty graph is an empty graph. test 2 >>> H=E10.subgraph([1,2,3,4,5]) >>> is_isomorphic(H,E5) True Subgraph of a complete graph is a complete graph >>> K1=complete_graph(1) >>> K3=complete_graph(3) >>> K5=complete_graph(5) >>> H=K5.subgraph([1,2,3]) >>> is_isomorphic(H,K3) True Test G.subgraph(nbunch), where nbunch is a single node >>> H=K5.subgraph(1) >>> is_isomorphic(H,K1) True Test G.subgraph(nbunch), where nbunch is a set >>> H=K5.subgraph(set([1])) >>> is_isomorphic(H,K1) True Test G.subgraph(nbunch), where nbunch is an iterator >>> H=K5.subgraph(iter(K3)) >>> is_isomorphic(H,K3) True Test G.subgraph(nbunch), where nbunch is another graph >>> H=K5.subgraph(K3) >>> is_isomorphic(H,K3) True Test for no error when nbunch has node not in G.nodes() >>> H=K5.subgraph([9]) >>> is_isomorphic(H,null_graph()) True Test error handling of tuple as a node >>> H.remove_node((1,2)) Traceback (most recent call last): ... NetworkXError: The node (1, 2) is not in the graph. >>> H.remove_nodes_from([(1,2)]) was Traceback (most recent call last): ... NetworkXError: The node (1, 2) is not in the graph. >>> H.neighbors((1,2)) Traceback (most recent call last): ... NetworkXError: The node (1, 2) is not in the graph.