
Boundary
========

>>> import networkx
>>> from networkx.algorithms.boundary import *
>>> from networkx import null_graph, path_graph, complete_graph, petersen_graph
>>> from networkx.operators import convert_node_labels_to_integers as cnlti

Some small graphs
-----------------

>>> null=null_graph()
>>> P10=cnlti(path_graph(10),first_label=1)
>>> K10=cnlti(complete_graph(10),first_label=1)

Node and Edge Boundaries
------------------------

null graph has empty boundaries

>>> node_boundary(null,[])
[]
>>> node_boundary(null,[],[])
[]
>>> node_boundary(null,[1,2,3])
[]
>>> node_boundary(null,[1,2,3],[4,5,6])
[]
>>> node_boundary(null,[1,2,3],[3,4,5])
[]


>>> edge_boundary(null,[])
[]
>>> edge_boundary(null,[],[])
[]
>>> edge_boundary(null,[1,2,3])
[]
>>> edge_boundary(null,[1,2,3],[4,5,6])
[]
>>> edge_boundary(null,[1,2,3],[3,4,5])
[]

Check boundaries in path graph.

>>> node_boundary(P10,[])
[]
>>> node_boundary(P10,[],[])
[]
>>> node_boundary(P10,[1,2,3])
[4]
>>> sorted(node_boundary(P10,[4,5,6]))
[3, 7]
>>> sorted(node_boundary(P10,[3,4,5,6,7]))
[2, 8]
>>> node_boundary(P10,[8,9,10])
[7]
>>> sorted(node_boundary(P10,[4,5,6],[9,10]))
[]
>>> node_boundary(P10,[1,2,3],[3,4,5]) 
[4]

# Note we used to raise an exception when bunches not disjoint.


>>> edge_boundary(P10,[])
[]
>>> edge_boundary(P10,[],[])
[]
>>> edge_boundary(P10,[1,2,3])
[(3, 4)]
>>> sorted(edge_boundary(P10,[4,5,6]))
[(4, 3), (6, 7)]
>>> sorted(edge_boundary(P10,[3,4,5,6,7]))
[(3, 2), (7, 8)]
>>> edge_boundary(P10,[8,9,10])
[(8, 7)]
>>> sorted(edge_boundary(P10,[4,5,6],[9,10]))
[]
>>> edge_boundary(P10,[1,2,3],[3,4,5]) 
[(2, 3), (3, 4)]

Check boundaries in a complete graph

>>> node_boundary(K10,[])
[]
>>> node_boundary(K10,[],[])
[]
>>> sorted(node_boundary(K10,[1,2,3]))
[4, 5, 6, 7, 8, 9, 10]
>>> sorted(node_boundary(K10,[4,5,6]))
[1, 2, 3, 7, 8, 9, 10]
>>> sorted(node_boundary(K10,[3,4,5,6,7]))
[1, 2, 8, 9, 10]
>>> sorted(node_boundary(K10,[4,5,6],[]))
[]
>>> node_boundary(K10,K10)
[]
>>> node_boundary(K10,[1,2,3],[3,4,5]) 
[4, 5]


>>> edge_boundary(K10,[])
[]
>>> edge_boundary(K10,[],[])
[]
>>> len(edge_boundary(K10,[1,2,3]))
21
>>> len(edge_boundary(K10,[4,5,6,7]))
24
>>> len(edge_boundary(K10,[3,4,5,6,7]))
25
>>> len(edge_boundary(K10,[8,9,10]))
21
>>> sorted(edge_boundary(K10,[4,5,6],[9,10]))
[(4, 9), (4, 10), (5, 9), (5, 10), (6, 9), (6, 10)]
>>> edge_boundary(K10,[1,2,3],[3,4,5]) 
[(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5)]

Check boundaries in the petersen graph

  cheeger(G,k)=min(|bdy(S)|/|S| for |S|=k, 0<k<=|V(G)|/2)

>>> from random import sample
>>> P=petersen_graph()
>>> def cheeger(G,k):
...    return  min([float(len(node_boundary(G,sample(G.nodes(),k))))/k for n in xrange(100)])
>>> print "%4.2f"%cheeger(P,1)
3.00
>>> print "%4.2f"%cheeger(P,2)
2.00
>>> print "%4.2f"%cheeger(P,3)
1.67
>>> print "%4.2f"%cheeger(P,4)
1.00
>>> print "%4.2f"%cheeger(P,5)
0.80
>>> print "%4.2f"%cheeger(P,6)
0.50
>>> print "%4.2f"%cheeger(P,7)
0.43
>>> print "%4.2f"%cheeger(P,8)
0.25
>>> print "%4.2f"%cheeger(P,9)
0.11
>>> print "%4.2f"%cheeger(P,10)
0.00

