DiGraph ======= from networkx import * Unit tests for XDiGraph class in xbase.py ----------------------------------------- In addition to the classic graphs (see base_Graph.txt) (P1, P2, P3, K1, K2, null, etc.) we also use: P1di, P2di, etc. where Xdi=to_directed(X) G -- named "test" -- grown and deleted, with nodes A,B,C,... ----------------------------------------------------- .. class:: doctest-block .. figure:: xbase_XDiGraph_G.png G = XDiGraph(name="test") ----------------------------------------------------- H -- copy of G with extra integer nodes inherited from P3 and K3 ----------------------------------------------------- Z, Zm, Zs, Zms -- four XDiGraphs built on 5 nodes (labeled 1,..,5) where m=>multiedges=True and s=>selfloops=True). For each graph, edges are added with the same calls to add_edges_from(Zelist) (some of these edges are ignored depending on whether or not multiedges and/or selfloops are allowed.) Zelist=[(1,2,100),(1,2,100),(1,2,200),(1,1,"A"), (1,3,100),(4,2,100),(3,3,"B"),(3,3,"B"), (3,3,"BB")] ----------------------------------------------------- .. class:: doctest-block .. figure:: xbase_XDiGraph_Zms.png Zms = XDiGraph(multiedges=True,selfloops=True) ----------------------------------------------------- .. class:: doctest-block .. figure:: xbase_XDiGraph_Zm.png Zm = XDiGraph(multiedges=True,selfloops=False) ----------------------------------------------------- .. class:: doctest-block .. figure:: xbase_XDiGraph_Zs.png Zs = XDiGraph(multiedges=False,selfloops=True) ----------------------------------------------------- .. class:: doctest-block .. figure:: xbase_XDiGraph_Z.png Z = XDiGraph(multiedges=False,selfloops=False) ----------------------------------------------------- >>> from networkx import * >>> from networkx.isomorph import graph_could_be_isomorphic >>> is_isomorphic=graph_could_be_isomorphic >>> from networkx.operators 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) >>> K5=cnlti(complete_graph(5),first_label=1) Some small digraphs >>> nulldi=null.to_directed() >>> P1di=P1.to_directed() >>> P3di=P3.to_directed() >>> P10di=P10.to_directed() >>> K1di=K1.to_directed() >>> K3di=K3.to_directed() >>> K5di=K5.to_directed() Some small empty XDiGraphs >>> Xe0=empty_graph(0,create_using=XDiGraph()) >>> Xe0m=empty_graph(0,create_using=XDiGraph(multiedges=True)) >>> Xe0s=empty_graph(0,create_using=XDiGraph(selfloops=True)) >>> Xe0ms=empty_graph(0, ... create_using=XDiGraph(multiedges=True,selfloops=True)) >>> Xe3=empty_graph(3,create_using=XDiGraph()) >>> Xe3m=empty_graph(3,create_using=XDiGraph(multiedges=True)) >>> Xe3s=empty_graph(3,create_using=XDiGraph(selfloops=True)) >>> Xe3ms=empty_graph(3, ... create_using=XDiGraph(multiedges=True,selfloops=True)) Four digraphs; Z, Zm, Zs, Zms, each constructed using the identical sequence of add_edges and add_node commands. >>> Zms= XDiGraph(multiedges=True,selfloops=True) >>> Zm = XDiGraph(multiedges=True,selfloops=False) >>> Zs = XDiGraph(multiedges=False,selfloops=True) >>> Z = XDiGraph(multiedges=False,selfloops=False) >>> Zdigraphs=[Z,Zs,Zm,Zms] >>> Zelist=[(1,2,100),(1,2,100),(1,2,200),(1,1,"A"), ... (1,3,100),(4,2,100),(3,3,"B"),(3,3,"B"), ... (3,3,"BB")] >>> for z in Zdigraphs: ... z.add_edges_from(Zelist) ... z.add_node(5) Name ---- >>> G = XDiGraph(name="test") >>> print G # test of __str__ test >>> print G.name test >>> H= XDiGraph() >>> print H.name Nodes ----- >>> G.add_node('A') >>> G.has_node('A') True >>> G.delete_node('A') >>> G.has_node('A') False >>> G.add_nodes_from(list("ABCDEFGHIJKL")) >>> G.has_node("L") True >>> G.delete_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'] >>> 'A' in G # test __contains__ True >>> len(G) # test __len__ 11 >>> G.clear() # test node portion of clear() >>> G.nodes() [] Test add_node and delete_node acting for various nbunch >>> G.add_node('m') >>> G.has_node('m') True >>> G.add_node('m') # no complaints >>> G.delete_node('j') # NetworkXError Traceback (most recent call last): ... NetworkXError: node j not in graph >>> G.delete_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.delete_nodes_from(P3) # delete 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.delete_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.delete_nodes_from(n_iter) # delete 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): ... ValueError: need more than 1 value to unpack >>> 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('B','A') # G is directed, so B->A is not an edge False >>> G.has_neighbor('A','C') # same as has_edge False >>> G.has_neighbor('A','B') True >>> G.add_edge('A','C') # test directedness >>> G.add_edge('C','A') >>> G.delete_edge('C','A') >>> G.has_edge('A','C') # G is directed True >>> G.has_edge('C','A') False >>> G.add_edge('A','A') # test self loops >>> G.has_edge('A','A') False >>> G.add_edge('X','X') >>> G.has_node('X') # added node but not self loop True >>> G.delete_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') # directed False >>> G.add_edges_from([('D','F'),('B','D')]) # test add_edges_from() >>> G.has_edge('D','F') True >>> G.has_edge('B','D') True >>> G.has_edge('D','B') # directed False >>> G.add_edges_from([tuple('IJ'),list('KK'),tuple('JK')]) # after failing silently, should add 3rd edge >>> G.has_edge(('I','J')) True >>> G.has_edge(('K','K')) False >>> G.has_edge(('J','K')) True >>> G.has_edge(('K','J')) # directed False >>> G.add_path(list('ACDE')) # test add_path() and add_cycle() >>> G.has_edge('D','E') True >>> G.has_edge('E','C') False >>> G.add_cycle(list('MNOP')) >>> G.has_edge('O','P') True >>> G.has_edge('P','M') True >>> G.delete_node('P') # tests delete_node()'s handling of edges. >>> G.has_edge('P','M') False >>> G.delete_edge('M') # test delete_edge() Traceback (most recent call last): ... ValueError: need more than 1 value to unpack >>> G.add_edge('N','M') >>> G.has_edge('M','N') True >>> G.delete_edge('M','N') >>> G.has_edge('M','N') False >>> G.has_edge('N','M') # directed True >>> G.delete_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.delete_nodes_from(set('ZEFHIMNO')) >>> sorted(G.nodes()) [1, 2, 3, 'A', 'B', 'C', 'D', 'G', 'J', 'K'] >>> G.delete_nodes_from([1,2,3]) >>> sorted(G.nodes()) ['A', 'B', 'C', 'D', 'G', 'J', 'K'] >>> sorted(G.edges()) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None), ('C', 'D', None)] 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.in_edges(6)) # non-iterable non-node Traceback (most recent call last): ... NetworkXError: nbunch is not a node or a sequence of nodes. >>> sorted(G.out_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', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)] nbunch can be a set >>> sorted(G.edges(set(['A','B']))) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)] nbunch can be a graph >>> G1=Graph() >>> G1.add_nodes_from('AB') >>> sorted(G.edges(G1)) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)] nbunch can be a dict with nodes as keys >>> ndict={'A': "thing1", 'B': "thing2"} >>> sorted(G.edges(ndict)) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)] nbunch can be a single node >>> sorted(G.edges('A')) [('A', 'B', None), ('A', 'C', None)] 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', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)] nbunch can be a set >>> sorted(G.edges_iter(set(['A','B']))) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)] nbunch can be a graph >>> G1=Graph() >>> G1.add_nodes_from(['A','B']) >>> sorted(G.edges_iter(G1)) # nbunch is a graph [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)] nbunch can be a dict with nodes as keys >>> ndict={'A': "thing1", 'B': "thing2"} >>> sorted(G.edges_iter(ndict)) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)] nbunch can be a single node >>> sorted(G.edges_iter('A')) [('A', 'B', None), ('A', 'C', None)] nbunch can be nothing (whole graph) >>> sorted(G.edges_iter()) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None), ('C', 'D', None)] >>> 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 list >>> G.degree(['A']) [2] degree of nonnode which is also noniterator >>> G.degree(6) # non-iterable non-node Traceback (most recent call last): ... NetworkXError: nbunch is not a node or a sequence of nodes. >>> G.in_degree(6) # non-iterable non-node Traceback (most recent call last): ... NetworkXError: nbunch is not a node or a sequence of nodes. >>> G.out_degree(6) # non-iterable non-node Traceback (most recent call last): ... NetworkXError: nbunch is not a node or a sequence of nodes. with_labels=True always return a dict >>> G.degree('A',with_labels=True) {'A': 2} >>> G.degree(['A','B']) [2, 3] >>> G.degree(['A','B'],with_labels=True) {'A': 2, 'B': 3} >>> sorted(G.in_degree()) [0, 0, 0, 0, 1, 2, 2] >>> G.in_degree(with_labels=True) {'A': 0, 'C': 2, 'B': 1, 'D': 2, 'G': 0, 'K': 0, 'J': 0} >>> sorted(G.out_degree()) [0, 0, 0, 0, 1, 2, 2] >>> G.out_degree(with_labels=True) {'A': 2, 'C': 1, 'B': 2, 'D': 0, 'G': 0, 'K': 0, 'J': 0} >>> sorted(G.degree()) [0, 0, 0, 2, 2, 3, 3] >>> sorted(list(G.in_degree_iter())) [0, 0, 0, 0, 1, 2, 2] >>> dict(G.in_degree_iter(with_labels=True)) {'A': 0, 'C': 2, 'B': 1, 'D': 2, 'G': 0, 'K': 0, 'J': 0} >>> sorted(list(G.out_degree_iter())) [0, 0, 0, 0, 1, 2, 2] >>> dict(G.out_degree_iter(with_labels=True)) {'A': 2, 'C': 1, 'B': 2, 'D': 0, 'G': 0, 'K': 0, 'J': 0} >>> sorted(list(G.degree_iter())) [0, 0, 0, 2, 2, 3, 3] >>> H=XDiGraph() >>> H.add_edges_from([(1,24),(1,2)]) >>> H.in_degree([1,24]) [0, 1] >>> H.out_degree([1,24]) [2, 0] >>> H.degree([1,24]) [2, 1] >>> P3=path_graph(3) >>> P5=path_graph(5) >>> P3.degree(['A','B']) # silently ignore nodes not in P3 [] >>> sorted(P5.degree(P3)) # nbunch can be a graph [1, 2, 2] >>> sorted(P3.degree(P5)) # nbunch can be a graph thats way to big [1, 1, 2] >>> P5.degree([]) [] >>> list(P5.degree_iter([])) [] >>> dict( P5.degree_iter([],with_labels=True) ) {} >>> dict(P5.degree_iter([],with_labels=True)) {} Test degree on empty XDiGraphs >>> Xe0.degree() [] >>> Xe0.degree(with_labels=True) {} >>> list(Xe0.degree_iter()) [] >>> dict(Xe0.degree_iter(with_labels=True)) {} >>> Xe0m.degree() [] >>> Xe0m.degree(with_labels=True) {} >>> list(Xe0m.degree_iter()) [] >>> dict(Xe0m.degree_iter(with_labels=True)) {} >>> Xe0ms.degree() [] >>> Xe0ms.degree(with_labels=True) {} >>> list(Xe0ms.degree_iter()) [] >>> dict(Xe0ms.degree_iter(with_labels=True)) {} >>> Xe0s.degree() [] >>> Xe0s.degree(with_labels=True) {} >>> list(Xe0s.degree_iter()) [] >>> dict(Xe0s.degree_iter(with_labels=True)) {} Test degree on Zms, Zm, Zs, Z >>> nlist=[1,2,3,4,5] >>> Zms.degree(nlist) [6, 4, 7, 1, 0] >>> Zm.degree(nlist) [4, 4, 1, 1, 0] >>> Zs.degree(nlist) [4, 2, 3, 1, 0] >>> Z.degree(nlist) [2, 2, 1, 1, 0] Test in_degree on Zms, Zm, Zs, Z >>> Zms.in_degree(nlist) [1, 4, 4, 0, 0] >>> Zm.in_degree(nlist) [0, 4, 1, 0, 0] >>> Zs.in_degree(nlist) [1, 2, 2, 0, 0] >>> Z.in_degree(nlist) [0, 2, 1, 0, 0] Test out_degree on Zms, Zm, Zs, Z >>> Zms.out_degree(nlist) [5, 0, 3, 1, 0] >>> Zm.out_degree(nlist) [4, 0, 0, 1, 0] >>> Zs.out_degree(nlist) [3, 0, 1, 1, 0] >>> Z.out_degree(nlist) [2, 0, 0, 1, 0] >>> G.order() 7 >>> G.size() 5 >>> print Zms.successors(1) [1, 2, 2, 2, 3] >>> print Zm.successors(1) [2, 2, 2, 3] >>> print Zs.successors(1) [1, 2, 3] >>> print Z.successors(1) [2, 3] >>> print Zms.neighbors(1) [1, 2, 2, 2, 3] >>> print Zm.neighbors(1) [2, 2, 2, 3] >>> print Zs.neighbors(1) [1, 2, 3] >>> print Z.neighbors(1) [2, 3] >>> print Zms.predecessors(3) [1, 3, 3, 3] >>> print Zm.predecessors(3) [1] >>> print Zs.predecessors(3) [1, 3] >>> print Z.predecessors(3) [1] Operations ----------- >>> H=G.copy() # copy >>> H.adj==G.adj True >>> H.name==G.name True >>> H==G False >>> SG=G.subgraph(['A','B','D']) # subgraph >>> sorted(SG.nodes()) ['A', 'B', 'D'] >>> sorted(SG.edges()) [('A', 'B', None), ('B', 'D', None)] >>> Gcopy=G.copy() >>> UG=G.to_undirected() # to_undirected >>> UG==G False >>> UG.is_directed() False >>> G.is_directed() True >>> UG.name==G.name True >>> UG.adj==G.adj False >>> sorted(UG.edges(list('AB'))) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)] >>> sorted(UG.edges(['A','B'])) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)] >>> UG.delete_edge('A','B') >>> UG.has_edge('B','A') False >>> UG.has_edge('A','B') False # to_directed # to_weightedgraph # to_pseudograph Neighbors, Predecessors and Successors -------------------------------------- >>> sorted(G.neighbors('C')) ['D'] >>> sorted(G.successors('C')) ['D'] >>> sorted(G['C']) ['D'] >>> sorted(G.neighbors('A')) ['B', 'C'] >>> sorted(G.neighbors_iter('A')) ['B', 'C'] >>> sorted(G.successors_iter('A')) ['B', 'C'] >>> sorted(G.neighbors_iter('C')) ['D'] >>> sorted(G.successors('A')) ['B', 'C'] >>> sorted(G.successors_iter('A')) ['B', 'C'] >>> sorted(G.predecessors('C')) ['A', 'B'] >>> sorted(G.predecessors_iter('C')) ['A', 'B'] >>> sorted(G.successors('G')) # no edges [] >>> sorted(G.predecessors('G')) [] >>> sorted(G.predecessors('A')) # some edges but wrong direction [] >>> sorted(G.successors('D')) [] >>> sorted(G.successors_iter('G')) # no edges [] >>> sorted(G.predecessors_iter('G')) [] >>> sorted(G.predecessors_iter('A')) # some edges but wrong direction [] >>> sorted(G.successors_iter('D')) [] >>> sorted(G.neighbors('j')) Traceback (most recent call last): ... NetworkXError: node j not in graph >>> sorted(G.predecessors('j')) Traceback (most recent call last): ... NetworkXError: node j not in graph >>> sorted(G.successors('j')) Traceback (most recent call last): ... NetworkXError: node j not in graph >>> sorted(G.neighbors_iter('j')) Traceback (most recent call last): ... NetworkXError: node j not in graph >>> sorted(G.predecessors_iter('j')) Traceback (most recent call last): ... NetworkXError: node j not in graph >>> sorted(G.successors_iter('j')) Traceback (most recent call last): ... NetworkXError: node j not in graph Functional interface -------------------- >>> sorted(nodes(G)) ['A', 'B', 'C', 'D', 'G', 'J', 'K'] >>> sorted(nodes_iter(G)) ['A', 'B', 'C', 'D', 'G', 'J', 'K'] >>> sorted(edges(G)) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None), ('C', 'D', None)] >>> sorted(edges_iter(G)) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None), ('C', 'D', None)] >>> sorted(degree(G)) [0, 0, 0, 2, 2, 3, 3] >>> sorted(neighbors(G,'A')) ['B', 'C'] >>> number_of_nodes(G) 7 >>> number_of_edges(G) 5 >>> density(G)==5/(7*(7-1)*0.5) True >>> degree_histogram(G) [3, 0, 2, 2] Iterators --------- >>> sorted(G.nodes_iter()) ['A', 'B', 'C', 'D', 'G', 'J', 'K'] >>> sorted(G.edges_iter()) [('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None), ('C', 'D', None)] >>> sorted(G.degree_iter()) [0, 0, 0, 2, 2, 3, 3] >>> sorted(G.degree_iter(with_labels=True)) [('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: node X not in 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 >>> J5=K5.copy() >>> H=J5.subgraph(1,inplace=True) >>> is_isomorphic(H,K1) True >>> is_isomorphic(J5,K1) True Test G.subgraph(nbunch), where nbunch is a set >>> H=K5.subgraph(set([1])) >>> is_isomorphic(H,K1) True >>> J5=K5.copy() >>> H=J5.subgraph(set([1]),inplace=True) >>> is_isomorphic(H,K1) True >>> is_isomorphic(J5,K1) True Test G.subgraph(nbunch), where nbunch is an iterator >>> H=K5.subgraph(iter(K3)) >>> is_isomorphic(H,K3) True >>> J5=K5.copy() >>> H=J5.subgraph(iter(K3),inplace=True) >>> is_isomorphic(H,K3) True >>> is_isomorphic(J5,K3) True Test G.subgraph(nbunch), where nbunch is another graph >>> H=K5.subgraph(K3) >>> is_isomorphic(H,K3) True >>> J5=K5.copy() >>> H=J5.subgraph(K3,inplace=True) >>> is_isomorphic(H,K3) True >>> is_isomorphic(J5,K3) True Test for no error when nbunch has node not in G.nodes() >>> H=K5.subgraph([9]) >>> is_isomorphic(H,null_graph()) True