4
Unit tests for PseudoGraph version of XGraph in xgraph.py
5
---------------------------------------------------------
8
In addition to the usual suspects
9
(the simple graphs P1, P2, P3, K1, K2, null, etc.)
10
we perform unit tests with the following three PseudoGraphs:
12
- G: PseudoGraph with nodes A,B,C,...
14
first grown and the deleted
18
- H: copy of G with extra integer nodes from P3 and K3
20
- K: famous Konigsberg graph (from Euler) with nodes: A,B,C,D
23
.. class:: doctest-block
24
.. image:: base_PseudoGraph_K.png
26
- Km: Konigsberg graph with named, multiple bridges
29
- Kms: Km + 2 self-loops at node D
30
(ms->multiedges=True and selfloops=True)
32
- L: PseudoGraph over two nodes 1 and 2 with 3 self-loops on 1
33
and 4 parallel edges between 1 and 2.
35
>>> from pprint import *
37
>>> from networkx import *
38
>>> from networkx.isomorph import graph_could_be_isomorphic
39
>>> is_isomorphic=graph_could_be_isomorphic
40
>>> from networkx.operators import convert_node_labels_to_integers as cnlti
46
>>> P1=cnlti(path_graph(1),first_label=1)
47
>>> P3=cnlti(path_graph(3),first_label=1)
48
>>> P10=cnlti(path_graph(10),first_label=1)
49
>>> K1=cnlti(complete_graph(1),first_label=1)
50
>>> K3=cnlti(complete_graph(3),first_label=1)
51
>>> K5=cnlti(complete_graph(5),first_label=1)
56
>>> G = XGraph(name="test", multiedges=True, selfloops=True)
57
>>> print G # test of __str__
62
>>> H=XGraph(multiedges=True, selfloops=True)
67
(cf. http://mathworld.wolfram.com/KoenigsbergBridgeProblem.html)
69
>>> K=XGraph(name="Konigsberg", multiedges=True, loops=True)
70
>>> sorted(K) # test empty K.__iter__
72
>>> 'Euler' in K # test __contains__
74
>>> len(K) # test K.__len__
76
>>> K.__str__() # name
86
>>> G.delete_node('A')
89
>>> G.add_nodes_from(list("ABCDEFGHIJKL"))
92
>>> G.delete_nodes_from(['H','I','J','K','L'])
93
>>> G.add_nodes_from([1,2,3,4])
95
[1, 2, 3, 4, 'A', 'B', 'C', 'D', 'E', 'F', 'G']
96
>>> sorted(G) # test __iter__
97
[1, 2, 3, 4, 'A', 'B', 'C', 'D', 'E', 'F', 'G']
98
>>> 'A' in G # test __contains__
100
>>> len(G) # test __len__
103
>>> G.clear() # test node portion of clear()
107
>>> G=XGraph(multiedges=True)
108
>>> G.add_edge(1,2,'a')
109
>>> G.add_edge(1,2,'b')
110
>>> G.add_edge(1,2,'c')
118
>>> G=XGraph(multiedges=True)
119
>>> G.add_edge(1,2,'a')
120
>>> G.add_edge(1,2,'b')
121
>>> G.add_edge(1,2,'c')
122
>>> G.delete_nodes_from([1])
129
>>> G=XDiGraph(multiedges=True)
130
>>> G.add_edge(1,2,20)
131
>>> G.add_edge(1,2,20)
132
>>> G.add_edge(1,2,20)
133
>>> G.add_edge(2,3,20)
134
>>> G.add_edge(2,3,20)
135
>>> G.add_edge(2,4,20)
136
>>> G.add_edge(2,1,20)
137
>>> G.delete_nodes_from([1])
141
[(2, 3, 20), (2, 3, 20), (2, 4, 20)]
144
Test add_node and delete_node acting for various nbunch
146
>>> G = XGraph(name="test", multiedges=True, selfloops=True)
151
>>> G.add_node('m') # no complaints
152
>>> G.delete_node('j') # NetworkXError
153
Traceback (most recent call last):
155
NetworkXError: node j not in graph
156
>>> G.delete_node('m')
162
>>> G.add_nodes_from(list("ABCD"))
163
>>> G.add_nodes_from(P3) # add nbunch of nodes (nbunch=Graph)
164
>>> sorted(G.nodes())
165
[1, 2, 3, 'A', 'B', 'C', 'D']
166
>>> G.delete_nodes_from(P3) # delete nbunch of nodes (nbunch=Graph)
167
>>> sorted(G.nodes())
172
>>> nbunch=set("ABCDEFGHIJKL")
173
>>> G.add_nodes_from(nbunch)
177
nbunch is a dict with nodes as keys
179
>>> nbunch={'I':"foo",'J':2,'K':True,'L':"spam"}
180
>>> G.delete_nodes_from(nbunch)
181
>>> sorted(G.nodes())
182
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
184
nbunch is an iterator
187
>>> n_iter=P3.nodes_iter()
188
>>> G.add_nodes_from(n_iter)
189
>>> sorted(G.nodes())
190
[1, 2, 3, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
191
>>> n_iter=P3.nodes_iter() # rebuild same iterator
192
>>> G.delete_nodes_from(n_iter) # delete nbunch of nodes (nbunch=iterator)
193
>>> sorted(G.nodes())
194
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
199
>>> G.add_nodes_from(nbunch)
200
>>> sorted(G.nodes())
201
[1, 2, 3, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
208
Traceback (most recent call last):
210
ValueError: need more than 1 value to unpack
212
>>> G.add_edge('A','B') # testing add_edge()
213
>>> G.add_edge('A','B') # should fail silently
214
>>> G.has_edge('A','B') # testing has_edge()
216
>>> G.has_edge('A','C')
218
>>> G.has_edge( ('A','B') )
220
>>> G.has_edge('B','A') # G is undirected
222
>>> G.has_neighbor('A','C') # same as has_edge
224
>>> G.has_neighbor('A','B')
227
>>> G.add_edge('A','C') # test directedness
228
>>> G.add_edge('C','A') # There should now be two undirected edges
229
>>> G.get_edge('A','C')
231
>>> G.delete_edge('C','A') # delete one of the two edges added
232
>>> G.get_edge('A','C')
234
>>> G.delete_edge('C','A') # delete second
235
>>> G.has_edge('A','C') # G is undirected
237
>>> G.has_edge('C','A')
241
>>> G.add_edge('A','C') # test directedness
242
>>> G.add_edge('C','A') # There should now be two undirected edges
243
>>> G.get_edge('A','C')
245
>>> G.delete_multiedge('C','A') # delete all edges
246
>>> G.has_edge('A','C') # G is undirected
248
>>> G.has_edge('C','A')
252
>>> G.add_edge('A','A') # test self loops
253
>>> G.has_edge('A','A')
256
>>> G.add_edge('A','Z') # should add the node silently
261
>>> G.add_edges_from([('B','C')]) # test add_edges_from()
262
>>> G.has_edge('B','C')
264
>>> G.has_edge('C','B') # undirected
266
>>> G.add_edges_from([('D','F'),('B','D')])
267
>>> G.has_edge('D','F')
269
>>> G.has_edge('B','D')
271
>>> G.has_edge('D','B') # undirected
273
>>> G.add_edges_from([tuple('HI'),tuple('DD'),tuple('IJ'),tuple('JK')])
274
>>> G.has_edge(('I','J'))
276
>>> G.has_edge(('D','D'))
278
>>> G.has_edge(('J','K'))
280
>>> G.has_edge(('K','J')) # undirected
283
>>> G.add_path(list('ACDE')) # test add_path() and add_cycle()
284
>>> G.has_edge('D','E')
286
>>> G.has_edge('E','C')
288
>>> G.add_cycle(list('MNOP'))
289
>>> G.has_edge('O','P')
291
>>> G.has_edge('P','M')
293
>>> G.delete_node('P') # tests delete_node()'s handling of edges.
294
>>> G.has_edge('P','M')
299
>>> G.delete_edge('M') # test delete_edge()
300
Traceback (most recent call last):
302
ValueError: need more than 1 value to unpack
303
>>> G.delete_edge('D','D') # test self loops
304
>>> G.has_edge('D','D')
306
>>> G.add_edge('N','M')
307
>>> G.get_edge('M','N')
309
>>> G.delete_multiedge('M','N') # delete all parallel edges
310
>>> G.has_edge('M','N')
312
>>> G.has_edge('N','M') # undirected
314
>>> G.delete_edges_from([list('HI'),list('DF'),tuple('KK'),tuple('JK')]) # self loop fails silently
315
>>> G.has_edge('H','I')
317
>>> G.has_edge('J','K')
319
>>> G.delete_edges_from([list('IJ'),list('KK'),list('JK')])
320
>>> G.has_edge('I','J')
322
>>> G.delete_nodes_from(list('ZEFHIMNO'))
323
>>> sorted(G.nodes())
324
[1, 2, 3, 'A', 'B', 'C', 'D', 'G', 'J', 'K']
325
>>> G.delete_nodes_from([1,2,3])
326
>>> sorted(G.nodes())
327
['A', 'B', 'C', 'D', 'G', 'J', 'K']
329
pprint(sorted(G.edges()))
331
>>> pprint(sorted(G.edges()))
340
Test G.edges(nbunch) with various forms of nbunch
342
node not in nbunch should be quietly ignored
344
>>> sorted(G.edges(6)) # non-iterable non-node
345
Traceback (most recent call last):
347
NetworkXError: nbunch is not a node or a sequence of nodes.
349
>>> sorted(G.edges('Z')) # iterable non-node
352
nbunch can be an empty list
354
>>> sorted(G.edges([]))
359
>>> sorted(G.edges(['A','B']))
360
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
364
>>> sorted(G.edges(set(['A','B'])))
365
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
367
nbunch can be a graph
370
>>> G1.add_nodes_from('AB')
371
>>> sorted(G.edges(G1)) # nbunch is a graph
372
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
374
nbunch can be a dict with nodes as keys
376
>>> ndict={'A': "thing1", 'B': "thing2"}
377
>>> sorted(G.edges(ndict))
378
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
380
nbunch can be a single node
382
>>> sorted(G.edges('A'))
383
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None)]
386
Test G.edges_iter(nbunch) with various forms of nbunch
388
node not in nbunch should be quietly ignored
390
>>> sorted(G.edges_iter('Z'))
393
nbunch can be an empty list
395
>>> sorted(G.edges_iter([]))
400
>>> sorted(G.edges_iter(['A','B']))
401
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
405
>>> sorted(G.edges_iter(set(['A','B'])))
406
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
408
nbunch can be a graph
411
>>> G1.add_nodes_from(['A','B'])
412
>>> sorted(G.edges_iter(G1)) # nbunch is a graph
413
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
415
nbunch can be a dict with nodes as keys
417
>>> ndict={'A': "thing1", 'B': "thing2"}
418
>>> sorted(G.edges_iter(ndict))
419
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
421
nbunch can be a single node
423
>>> sorted(G.edges_iter('A'))
424
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None)]
426
>>> sorted(G.edges_iter())
427
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'D', None), ('C', 'B', None), ('C', 'D', None)]
429
nbunch can be nothing (whole graph)
431
>>> sorted(G.edges_iter())
432
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'D', None), ('C', 'B', None), ('C', 'D', None)]
433
>>> sorted(G.nodes_iter())
434
['A', 'B', 'C', 'D', 'G', 'J', 'K']
436
At this stage G should be the following PseudoGraph:
438
.. class:: doctest-block
439
.. image:: base_PseudoGraph_G.png
445
>>> H.delete_nodes_from( ['G', 'J', 'K'])
446
>>> sorted(H.edges()) # test copy
447
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'D', None), ('C', 'B', None), ('C', 'D', None)]
449
Now grow and shrink H using various forms of nbunch
451
>>> H.add_nodes_from(P3) # add nbunch of nodes (nbunch=Graph)
452
>>> sorted(H.nodes())
453
[1, 2, 3, 'A', 'B', 'C', 'D']
454
>>> H.delete_nodes_from(P3) # delete nbunch of nodes (nbunch=Graph)
455
>>> sorted(H.nodes())
458
>>> nbunch=P3.nodes_iter()
459
>>> H.add_nodes_from(nbunch) # add nbunch of nodes (nbunch=iterator)
460
>>> sorted(H.nodes())
461
[1, 2, 3, 'A', 'B', 'C', 'D']
462
>>> nbunch=P3.nodes_iter() # rebuild same iterator
463
>>> H.delete_nodes_from(nbunch) # delete nbunch of nodes (nbunch=iterator)
464
>>> sorted(H.nodes())
467
>>> nbunch=P3.degree(with_labels=True) # create dict with keys to add to H
468
>>> H.add_nodes_from(nbunch) # add nbunch of nodes (nbunch=dict)
469
>>> sorted(H.nodes())
470
[1, 2, 3, 'A', 'B', 'C', 'D']
471
>>> H.delete_nodes_from(nbunch) # delete nbunch of nodes (nbunch=dict)
472
>>> sorted(H.nodes())
476
Build Konigsberg graph using only add_edge
478
>>> K.add_edges_from([("A","B"),("A","B")])
479
>>> K.add_edges_from([("A","C"),("A","C")])
480
>>> K.add_edges_from([("A","D"),("C","D"),("B","D")])
483
>>> sorted(K) # test K.__iter__
485
>>> 'A' in K # test contains
488
Build Km, Konigsberg graph with named edges
490
>>> Km=XGraph(name="Konigsberg",multiedges=True)
491
>>> Km.add_edges_from([("A","B","Honey"),("A","B","Blacksmith's")])
492
>>> Km.add_edges_from([("A","C","Green"),("A","C","Connecting")])
493
>>> Km.add_edges_from([("A","D","Merchant's"),("C","D","High"),("B","D","Wooden")])
495
Build Kms = Km + 2 self-loops at node D
497
>>> Kms=XGraph(name="Konigsberg",multiedges=True,selfloops=True)
498
>>> Kms.add_edges_from(Km.edges())
499
>>> Kms.add_edge(["D","D","D self-loop 1"])
500
>>> Kms.add_edge(["D","D","D self-loop 2"])
503
Build graph L: 3 self-loops + 4-skein
505
>>> L=XGraph(multiedges=True, selfloops=True)
506
>>> L.add_edges_from([(1,1),(1,1),(1,1)]) # 3 self-loops at node 1
507
>>> L.add_edges_from([(1,2),(1,2),(1,2),(1,2)]) # 4 parallel edges
508
>>> sorted(L.edges())
509
[(1, 1, None), (1, 1, None), (1, 1, None), (1, 2, None), (1, 2, None), (1, 2, None), (1, 2, None)]
511
>>> sorted(L.edges([1,2]))
512
[(1, 1, None), (1, 1, None), (1, 1, None), (1, 2, None), (1, 2, None), (1, 2, None), (1, 2, None)]
516
Extracting objects imbedded into edges.
517
---------------------------------------
520
>>> H.add_edge(1,2,"hi")
525
>>> sorted(H.edges_iter(1))
527
>>> sorted(H.nodes())
529
>>> H.add_edges_from([(1,2,"there"),(1,3,"oof"),(1,1,"loop")])
530
>>> sorted(H.edges(1))
531
[(1, 1, 'loop'), (1, 2, 'hi'), (1, 2, 'there'), (1, 3, 'oof')]
532
>>> sorted(H.edges(2))
533
[(2, 1, 'hi'), (2, 1, 'there')]
534
>>> sorted(H.edges())
535
[(1, 1, 'loop'), (1, 2, 'hi'), (1, 2, 'there'), (1, 3, 'oof')]
536
>>> sorted(H.edges_iter(1))
537
[(1, 1, 'loop'), (1, 2, 'hi'), (1, 2, 'there'), (1, 3, 'oof')]
538
>>> sorted(H.edges_iter(2))
539
[(2, 1, 'hi'), (2, 1, 'there')]
540
>>> sorted(H.edges_iter())
541
[(1, 1, 'loop'), (1, 2, 'hi'), (1, 2, 'there'), (1, 3, 'oof')]
542
>>> H.delete_edge(1,1,'ooops') # should fail silently
543
>>> H.delete_edge(1,1,'loop')
544
>>> sorted(H.edges(1))
545
[(1, 2, 'hi'), (1, 2, 'there'), (1, 3, 'oof')]
546
>>> H.delete_multiedge(1,2) # should delete both edges between 1 and 2
547
>>> sorted(H.edges(1))
549
>>> H.add_edges_from([(4,5),(4,6),(3,4)])
550
>>> sorted(H.edges(4))
551
[(4, 3, None), (4, 5, None), (4, 6, None)]
553
>>> sorted(H.edges(6))
554
[(6, 4, None), (6, 5, None)]
555
>>> H.add_edges_from([(4,5),(1,1)])
556
>>> sorted(H.edges(4))
557
[(4, 3, None), (4, 5, None), (4, 5, None), (4, 6, None)]
558
>>> sorted(H.edges(1))
559
[(1, 1, None), (1, 3, 'oof')]
560
>>> sorted(H.nodes())
562
>>> H.delete_nodes_from([1,2,3,4,5,6])
563
>>> sorted(H.edges(1))
564
Traceback (most recent call last):
566
NetworkXError: nbunch is not a node or a sequence of nodes.
573
degree of single node must return single int
578
degree of single node in iterable container must return list
583
with_labels=True always return a dict with nodes as keys
585
>>> G.degree('A',with_labels=True)
588
>>> G.degree(['A','B'])
590
>>> G.degree(['A','B'],with_labels=True)
593
>>> sorted(G.degree())
594
[0, 0, 0, 2, 3, 4, 5]
595
>>> sorted(list(G.degree_iter()))
596
[0, 0, 0, 2, 3, 4, 5]
606
>>> number_of_nodes(K)
608
>>> number_of_edges(K)
619
>>> H=G.copy() # copy
627
>>> Gsub=G.subgraph(['A','B','D']) # subgraph
628
>>> sorted(Gsub.nodes())
630
>>> sorted(Gsub.edges())
631
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('B', 'D', None)]
634
>>> Gdir=G.to_directed()
635
>>> Gdirsub=Gdir.subgraph(['A','B','D'])
636
>>> sorted(Gsub.nodes())
638
>>> sorted(Gsub.edges())
639
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('B', 'D', None)]
643
>>> Ksub=K.subgraph(['A','B'])
644
>>> sorted( Ksub.edges() )
645
[('A', 'B', None), ('A', 'B', None)]
650
>>> sorted(G['A']) # test __getitem__
652
>>> sorted(G.neighbors('A'))
654
>>> sorted(G.neighbors_iter('A'))
662
['A', 'B', 'C', 'D', 'G', 'J', 'K']
664
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'D', None), ('C', 'B', None), ('C', 'D', None)]
666
>>> sorted(degree(G))
667
[0, 0, 0, 2, 3, 4, 5]
668
>>> sorted(neighbors(G,'A'))
670
>>> number_of_nodes(G)
672
>>> number_of_edges(G)
680
>>> pprint(sorted(edges(K)))
689
>>> pprint(sorted(edges(Km)))
690
[('A', 'B', "Blacksmith's"),
692
('A', 'C', 'Connecting'),
694
('A', 'D', "Merchant's"),
695
('B', 'D', 'Wooden'),
698
>>> pprint(sorted(edges(Kms)))
699
[('A', 'B', "Blacksmith's"),
701
('A', 'C', 'Connecting'),
703
('A', 'D', "Merchant's"),
704
('B', 'D', 'Wooden'),
706
('D', 'D', 'D self-loop 1'),
707
('D', 'D', 'D self-loop 2')]
713
>>> sorted(G.nodes_iter())
714
['A', 'B', 'C', 'D', 'G', 'J', 'K']
715
>>> pprint(sorted(G.edges_iter()))
724
>>> sorted(G.degree())
725
[0, 0, 0, 2, 3, 4, 5]
727
>>> sorted(G.degree_iter())
728
[0, 0, 0, 2, 3, 4, 5]
730
>>> sorted(G.neighbors_iter('A'))
736
>>> sorted(K.nodes_iter())
738
>>> sorted(K.edges_iter())
739
[('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('A', 'C', None), ('A', 'D', None), ('B', 'D', None), ('C', 'D', None)]
741
>>> sorted(K.degree_iter())
744
>>> sorted(K.neighbors_iter('A'))
745
['B', 'B', 'C', 'C', 'D']
747
>>> sorted(K.neighbors_iter('B'))
750
>>> sorted(K.neighbors_iter('C'))
753
>>> sorted(K.neighbors_iter('D'))
756
>>> sorted(K.neighbors_iter('X'))
757
Traceback (most recent call last):
759
NetworkXError: node X not in graph
765
>>> G.ban_selfloops()
766
>>> sorted(G.edges())
767
[('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'D', None), ('C', 'B', None), ('C', 'D', None)]
769
>>> number_of_nodes(G)
774
>>> K.ban_selfloops() # no selfloops, so should be unchanged
775
>>> sorted(K.edges())
776
[('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('A', 'C', None), ('A', 'D', None), ('B', 'D', None), ('C', 'D', None)]
778
>>> number_of_nodes(K)