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
<BLANKLINE>

>>> G2=XDiGraph(data={1:[2],2:[1]}, name="test")
>>> print G2.edges()
[(1, 2, None), (2, 1, None)]
>>> print G2.name
test


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
[]
>>> sorted(G.in_edges(6))    # non-iterable non-node
[]
>>> sorted(G.out_edges(6))    # non-iterable non-node
[]

>>> 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
[]
>>> G.in_degree(6)    # non-iterable non-node
[]
>>> G.out_degree(6)    # non-iterable non-node
[]

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


number_of_edges
---------------

>>> X=XDiGraph()
>>> X.add_edge(1,2,'a')
>>> X.add_edge(1,3,'a')
>>> X.number_of_edges()
2
>>> X.number_of_edges(1,2)
1
>>> X.number_of_edges((1,2))
1
>>> X.number_of_edges(1,2,'a')
1
>>> X.number_of_edges((1,2,'a'))
1
>>> X.number_of_edges(1,2,'b')
0
>>> X.number_of_edges(1,4)
0
