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)
66
>>> G2=XGraph(data={1:[1]}, name="test", selfloops=True)
73
(cf. http://mathworld.wolfram.com/KoenigsbergBridgeProblem.html)
75
>>> K=XGraph(name="Konigsberg", multiedges=True, selfloops=True)
76
>>> sorted(K) # test empty K.__iter__
78
>>> 'Euler' in K # test __contains__
80
>>> len(K) # test K.__len__
82
>>> K.__str__() # name
92
>>> G.delete_node('A')
95
>>> G.add_nodes_from(list("ABCDEFGHIJKL"))
98
>>> G.delete_nodes_from(['H','I','J','K','L'])
99
>>> G.add_nodes_from([1,2,3,4])
100
>>> sorted(G.nodes())
101
[1, 2, 3, 4, 'A', 'B', 'C', 'D', 'E', 'F', 'G']
102
>>> sorted(G) # test __iter__
103
[1, 2, 3, 4, 'A', 'B', 'C', 'D', 'E', 'F', 'G']
104
>>> 'A' in G # test __contains__
106
>>> len(G) # test __len__
109
>>> G.clear() # test node portion of clear()
113
>>> G=XGraph(multiedges=True)
114
>>> G.add_edge(1,2,'a')
115
>>> G.add_edge(1,2,'b')
116
>>> G.add_edge(1,2,'c')
124
>>> G=XGraph(multiedges=True)
125
>>> G.add_edge(1,2,'a')
126
>>> G.add_edge(1,2,'b')
127
>>> G.add_edge(1,2,'c')
128
>>> G.delete_nodes_from([1])
135
>>> G=XDiGraph(multiedges=True)
136
>>> G.add_edge(1,2,20)
137
>>> G.add_edge(1,2,20)
138
>>> G.add_edge(1,2,20)
139
>>> G.add_edge(2,3,20)
140
>>> G.add_edge(2,3,20)
141
>>> G.add_edge(2,4,20)
142
>>> G.add_edge(2,1,20)
143
>>> G.delete_nodes_from([1])
147
[(2, 3, 20), (2, 3, 20), (2, 4, 20)]
150
Test add_node and delete_node acting for various nbunch
152
>>> G = XGraph(name="test", multiedges=True, selfloops=True)
157
>>> G.add_node('m') # no complaints
158
>>> G.delete_node('j') # NetworkXError
159
Traceback (most recent call last):
161
NetworkXError: node j not in graph
162
>>> G.delete_node('m')
168
>>> G.add_nodes_from(list("ABCD"))
169
>>> G.add_nodes_from(P3) # add nbunch of nodes (nbunch=Graph)
170
>>> sorted(G.nodes())
171
[1, 2, 3, 'A', 'B', 'C', 'D']
172
>>> G.delete_nodes_from(P3) # delete nbunch of nodes (nbunch=Graph)
173
>>> sorted(G.nodes())
178
>>> nbunch=set("ABCDEFGHIJKL")
179
>>> G.add_nodes_from(nbunch)
183
nbunch is a dict with nodes as keys
185
>>> nbunch={'I':"foo",'J':2,'K':True,'L':"spam"}
186
>>> G.delete_nodes_from(nbunch)
187
>>> sorted(G.nodes())
188
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
190
nbunch is an iterator
193
>>> n_iter=P3.nodes_iter()
194
>>> G.add_nodes_from(n_iter)
195
>>> sorted(G.nodes())
196
[1, 2, 3, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
197
>>> n_iter=P3.nodes_iter() # rebuild same iterator
198
>>> G.delete_nodes_from(n_iter) # delete nbunch of nodes (nbunch=iterator)
199
>>> sorted(G.nodes())
200
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
205
>>> G.add_nodes_from(nbunch)
206
>>> sorted(G.nodes())
207
[1, 2, 3, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
214
Traceback (most recent call last):
216
ValueError: need more than 1 value to unpack
218
>>> G.add_edge('A','B') # testing add_edge()
219
>>> G.add_edge('A','B') # should fail silently
220
>>> G.has_edge('A','B') # testing has_edge()
222
>>> G.has_edge('A','C')
224
>>> G.has_edge( ('A','B') )
226
>>> G.has_edge('B','A') # G is undirected
228
>>> G.has_neighbor('A','C') # same as has_edge
230
>>> G.has_neighbor('A','B')
233
>>> G.add_edge('A','C') # test directedness
234
>>> G.add_edge('C','A') # There should now be two undirected edges
235
>>> G.get_edge('A','C')
237
>>> G.delete_edge('C','A') # delete one of the two edges added
238
>>> G.get_edge('A','C')
240
>>> G.delete_edge('C','A') # delete second
241
>>> G.has_edge('A','C') # G is undirected
243
>>> G.has_edge('C','A')
247
>>> G.add_edge('A','C') # test directedness
248
>>> G.add_edge('C','A') # There should now be two undirected edges
249
>>> G.get_edge('A','C')
251
>>> G.delete_multiedge('C','A') # delete all edges
252
>>> G.has_edge('A','C') # G is undirected
254
>>> G.has_edge('C','A')
258
>>> G.add_edge('A','A') # test self loops
259
>>> G.has_edge('A','A')
262
>>> G.add_edge('A','Z') # should add the node silently
267
>>> G.add_edges_from([('B','C')]) # test add_edges_from()
268
>>> G.has_edge('B','C')
270
>>> G.has_edge('C','B') # undirected
272
>>> G.add_edges_from([('D','F'),('B','D')])
273
>>> G.has_edge('D','F')
275
>>> G.has_edge('B','D')
277
>>> G.has_edge('D','B') # undirected
279
>>> G.add_edges_from([tuple('HI'),tuple('DD'),tuple('IJ'),tuple('JK')])
280
>>> G.has_edge(('I','J'))
282
>>> G.has_edge(('D','D'))
284
>>> G.has_edge(('J','K'))
286
>>> G.has_edge(('K','J')) # undirected
289
>>> G.add_path(list('ACDE')) # test add_path() and add_cycle()
290
>>> G.has_edge('D','E')
292
>>> G.has_edge('E','C')
294
>>> G.add_cycle(list('MNOP'))
295
>>> G.has_edge('O','P')
297
>>> G.has_edge('P','M')
299
>>> G.delete_node('P') # tests delete_node()'s handling of edges.
300
>>> G.has_edge('P','M')
305
>>> G.delete_edge('M') # test delete_edge()
306
Traceback (most recent call last):
308
ValueError: need more than 1 value to unpack
309
>>> G.delete_edge('D','D') # test self loops
310
>>> G.has_edge('D','D')
312
>>> G.add_edge('N','M')
313
>>> G.get_edge('M','N')
315
>>> G.delete_multiedge('M','N') # delete all parallel edges
316
>>> G.has_edge('M','N')
318
>>> G.has_edge('N','M') # undirected
320
>>> G.delete_edges_from([list('HI'),list('DF'),tuple('KK'),tuple('JK')]) # self loop fails silently
321
>>> G.has_edge('H','I')
323
>>> G.has_edge('J','K')
325
>>> G.delete_edges_from([list('IJ'),list('KK'),list('JK')])
326
>>> G.has_edge('I','J')
328
>>> G.delete_nodes_from(list('ZEFHIMNO'))
329
>>> sorted(G.nodes())
330
[1, 2, 3, 'A', 'B', 'C', 'D', 'G', 'J', 'K']
331
>>> G.delete_nodes_from([1,2,3])
332
>>> sorted(G.nodes())
333
['A', 'B', 'C', 'D', 'G', 'J', 'K']
335
pprint(sorted(G.edges()))
337
>>> pprint(sorted(G.edges()))
346
Test G.edges(nbunch) with various forms of nbunch
348
node not in nbunch should be quietly ignored
350
>>> sorted(G.edges(6)) # non-iterable non-node
353
>>> sorted(G.edges('Z')) # iterable non-node
356
nbunch can be an empty list
358
>>> sorted(G.edges([]))
363
>>> sorted(G.edges(['A','B']))
364
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
368
>>> sorted(G.edges(set(['A','B'])))
369
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
371
nbunch can be a graph
374
>>> G1.add_nodes_from('AB')
375
>>> sorted(G.edges(G1)) # nbunch is a graph
376
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
378
nbunch can be a dict with nodes as keys
380
>>> ndict={'A': "thing1", 'B': "thing2"}
381
>>> sorted(G.edges(ndict))
382
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
384
nbunch can be a single node
386
>>> sorted(G.edges('A'))
387
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None)]
390
Test G.edges_iter(nbunch) with various forms of nbunch
392
node not in nbunch should be quietly ignored
394
>>> sorted(G.edges_iter('Z'))
397
nbunch can be an empty list
399
>>> sorted(G.edges_iter([]))
404
>>> sorted(G.edges_iter(['A','B']))
405
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
409
>>> sorted(G.edges_iter(set(['A','B'])))
410
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
412
nbunch can be a graph
415
>>> G1.add_nodes_from(['A','B'])
416
>>> sorted(G.edges_iter(G1)) # nbunch is a graph
417
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
419
nbunch can be a dict with nodes as keys
421
>>> ndict={'A': "thing1", 'B': "thing2"}
422
>>> sorted(G.edges_iter(ndict))
423
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'C', None), ('B', 'D', None)]
425
nbunch can be a single node
427
>>> sorted(G.edges_iter('A'))
428
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None)]
430
>>> sorted(G.edges_iter())
431
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'D', None), ('C', 'B', None), ('C', 'D', None)]
433
nbunch can be nothing (whole graph)
435
>>> sorted(G.edges_iter())
436
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'D', None), ('C', 'B', None), ('C', 'D', None)]
437
>>> sorted(G.nodes_iter())
438
['A', 'B', 'C', 'D', 'G', 'J', 'K']
440
At this stage G should be the following PseudoGraph:
442
.. class:: doctest-block
443
.. image:: base_PseudoGraph_G.png
449
>>> H.delete_nodes_from( ['G', 'J', 'K'])
450
>>> sorted(H.edges()) # test copy
451
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'D', None), ('C', 'B', None), ('C', 'D', None)]
453
Now grow and shrink H using various forms of nbunch
455
>>> H.add_nodes_from(P3) # add nbunch of nodes (nbunch=Graph)
456
>>> sorted(H.nodes())
457
[1, 2, 3, 'A', 'B', 'C', 'D']
458
>>> H.delete_nodes_from(P3) # delete nbunch of nodes (nbunch=Graph)
459
>>> sorted(H.nodes())
462
>>> nbunch=P3.nodes_iter()
463
>>> H.add_nodes_from(nbunch) # add nbunch of nodes (nbunch=iterator)
464
>>> sorted(H.nodes())
465
[1, 2, 3, 'A', 'B', 'C', 'D']
466
>>> nbunch=P3.nodes_iter() # rebuild same iterator
467
>>> H.delete_nodes_from(nbunch) # delete nbunch of nodes (nbunch=iterator)
468
>>> sorted(H.nodes())
471
>>> nbunch=P3.degree(with_labels=True) # create dict with keys to add to H
472
>>> H.add_nodes_from(nbunch) # add nbunch of nodes (nbunch=dict)
473
>>> sorted(H.nodes())
474
[1, 2, 3, 'A', 'B', 'C', 'D']
475
>>> H.delete_nodes_from(nbunch) # delete nbunch of nodes (nbunch=dict)
476
>>> sorted(H.nodes())
480
Build Konigsberg graph using only add_edge
482
>>> K.add_edges_from([("A","B"),("A","B")])
483
>>> K.add_edges_from([("A","C"),("A","C")])
484
>>> K.add_edges_from([("A","D"),("C","D"),("B","D")])
487
>>> sorted(K) # test K.__iter__
489
>>> 'A' in K # test contains
492
Build Km, Konigsberg graph with named edges
494
>>> Km=XGraph(name="Konigsberg",multiedges=True)
495
>>> Km.add_edges_from([("A","B","Honey"),("A","B","Blacksmith's")])
496
>>> Km.add_edges_from([("A","C","Green"),("A","C","Connecting")])
497
>>> Km.add_edges_from([("A","D","Merchant's"),("C","D","High"),("B","D","Wooden")])
499
Build Kms = Km + 2 self-loops at node D
501
>>> Kms=XGraph(name="Konigsberg",multiedges=True,selfloops=True)
502
>>> Kms.add_edges_from(Km.edges())
503
>>> Kms.add_edge(["D","D","D self-loop 1"])
504
>>> Kms.add_edge(["D","D","D self-loop 2"])
507
Build graph L: 3 self-loops + 4-skein
509
>>> L=XGraph(multiedges=True, selfloops=True)
510
>>> L.add_edges_from([(1,1),(1,1),(1,1)]) # 3 self-loops at node 1
511
>>> L.add_edges_from([(1,2),(1,2),(1,2),(1,2)]) # 4 parallel edges
512
>>> sorted(L.edges())
513
[(1, 1, None), (1, 1, None), (1, 1, None), (1, 2, None), (1, 2, None), (1, 2, None), (1, 2, None)]
515
>>> sorted(L.edges([1,2]))
516
[(1, 1, None), (1, 1, None), (1, 1, None), (1, 2, None), (1, 2, None), (1, 2, None), (1, 2, None)]
520
Extracting objects imbedded into edges.
521
---------------------------------------
524
>>> H.add_edge(1,2,"hi")
529
>>> sorted(H.edges_iter(1))
531
>>> sorted(H.nodes())
533
>>> H.add_edges_from([(1,2,"there"),(1,3,"oof"),(1,1,"loop")])
534
>>> sorted(H.edges(1))
535
[(1, 1, 'loop'), (1, 2, 'hi'), (1, 2, 'there'), (1, 3, 'oof')]
536
>>> sorted(H.edges(2))
537
[(2, 1, 'hi'), (2, 1, 'there')]
538
>>> sorted(H.edges())
539
[(1, 1, 'loop'), (1, 2, 'hi'), (1, 2, 'there'), (1, 3, 'oof')]
540
>>> sorted(H.edges_iter(1))
541
[(1, 1, 'loop'), (1, 2, 'hi'), (1, 2, 'there'), (1, 3, 'oof')]
542
>>> sorted(H.edges_iter(2))
543
[(2, 1, 'hi'), (2, 1, 'there')]
544
>>> sorted(H.edges_iter())
545
[(1, 1, 'loop'), (1, 2, 'hi'), (1, 2, 'there'), (1, 3, 'oof')]
546
>>> H.delete_edge(1,1,'ooops') # should fail silently
547
>>> H.delete_edge(1,1,'loop')
548
>>> sorted(H.edges(1))
549
[(1, 2, 'hi'), (1, 2, 'there'), (1, 3, 'oof')]
550
>>> H.delete_multiedge(1,2) # should delete both edges between 1 and 2
551
>>> sorted(H.edges(1))
553
>>> H.add_edges_from([(4,5),(4,6),(3,4)])
554
>>> sorted(H.edges(4))
555
[(4, 3, None), (4, 5, None), (4, 6, None)]
557
>>> sorted(H.edges(6))
558
[(6, 4, None), (6, 5, None)]
559
>>> H.add_edges_from([(4,5),(1,1)])
560
>>> sorted(H.edges(4))
561
[(4, 3, None), (4, 5, None), (4, 5, None), (4, 6, None)]
562
>>> sorted(H.edges(1))
563
[(1, 1, None), (1, 3, 'oof')]
564
>>> sorted(H.nodes())
566
>>> H.delete_nodes_from([1,2,3,4,5,6])
567
>>> sorted(H.edges(1))
575
degree of single node must return single int
580
degree of single node in iterable container must return list
585
with_labels=True always return a dict with nodes as keys
587
>>> G.degree('A',with_labels=True)
590
>>> G.degree(['A','B'])
592
>>> G.degree(['A','B'],with_labels=True)
595
>>> sorted(G.degree())
596
[0, 0, 0, 2, 3, 4, 5]
597
>>> sorted(list(G.degree_iter()))
598
[0, 0, 0, 2, 3, 4, 5]
608
>>> number_of_nodes(K)
610
>>> number_of_edges(K)
621
>>> H=G.copy() # copy
629
>>> Gsub=G.subgraph(['A','B','D']) # subgraph
630
>>> sorted(Gsub.nodes())
632
>>> sorted(Gsub.edges())
633
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('B', 'D', None)]
636
>>> Gdir=G.to_directed()
637
>>> Gdirsub=Gdir.subgraph(['A','B','D'])
638
>>> sorted(Gsub.nodes())
640
>>> sorted(Gsub.edges())
641
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('B', 'D', None)]
645
>>> Ksub=K.subgraph(['A','B'])
646
>>> sorted( Ksub.edges() )
647
[('A', 'B', None), ('A', 'B', None)]
652
>>> sorted(G['A']) # test __getitem__
654
>>> sorted(G.neighbors('A'))
656
>>> sorted(G.neighbors_iter('A'))
664
['A', 'B', 'C', 'D', 'G', 'J', 'K']
666
[('A', 'A', None), ('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'D', None), ('C', 'B', None), ('C', 'D', None)]
668
>>> sorted(degree(G))
669
[0, 0, 0, 2, 3, 4, 5]
670
>>> sorted(neighbors(G,'A'))
672
>>> number_of_nodes(G)
674
>>> number_of_edges(G)
682
>>> pprint(sorted(edges(K)))
691
>>> pprint(sorted(edges(Km)))
692
[('A', 'B', "Blacksmith's"),
694
('A', 'C', 'Connecting'),
696
('A', 'D', "Merchant's"),
697
('B', 'D', 'Wooden'),
700
>>> pprint(sorted(edges(Kms)))
701
[('A', 'B', "Blacksmith's"),
703
('A', 'C', 'Connecting'),
705
('A', 'D', "Merchant's"),
706
('B', 'D', 'Wooden'),
708
('D', 'D', 'D self-loop 1'),
709
('D', 'D', 'D self-loop 2')]
715
>>> sorted(G.nodes_iter())
716
['A', 'B', 'C', 'D', 'G', 'J', 'K']
717
>>> pprint(sorted(G.edges_iter()))
726
>>> sorted(G.degree())
727
[0, 0, 0, 2, 3, 4, 5]
729
>>> sorted(G.degree_iter())
730
[0, 0, 0, 2, 3, 4, 5]
732
>>> sorted(G.neighbors_iter('A'))
738
>>> sorted(K.nodes_iter())
740
>>> sorted(K.edges_iter())
741
[('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('A', 'C', None), ('A', 'D', None), ('B', 'D', None), ('C', 'D', None)]
743
>>> sorted(K.degree_iter())
746
>>> sorted(K.neighbors_iter('A'))
747
['B', 'B', 'C', 'C', 'D']
749
>>> sorted(K.neighbors_iter('B'))
752
>>> sorted(K.neighbors_iter('C'))
755
>>> sorted(K.neighbors_iter('D'))
758
>>> sorted(K.neighbors_iter('X'))
759
Traceback (most recent call last):
761
NetworkXError: node X not in graph
767
>>> G.ban_selfloops()
768
>>> sorted(G.edges())
769
[('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('B', 'D', None), ('C', 'B', None), ('C', 'D', None)]
771
>>> number_of_nodes(G)
776
>>> K.ban_selfloops() # no selfloops, so should be unchanged
777
>>> sorted(K.edges())
778
[('A', 'B', None), ('A', 'B', None), ('A', 'C', None), ('A', 'C', None), ('A', 'D', None), ('B', 'D', None), ('C', 'D', None)]
780
>>> number_of_nodes(K)
787
>>> X=XDiGraph(multiedges=True,selfloops=True)
788
>>> X.add_edge(1,1,'a')
789
>>> X.add_edge(1,1,'a')
790
>>> X.add_edge(1,1,'b')
791
>>> X.add_edge(1,2,'aa')
793
>>> X.number_of_edges()
795
>>> X.number_of_edges(1,1)
797
>>> X.number_of_edges((1,1))
799
>>> X.number_of_edges(1,1,'a')
801
>>> X.number_of_edges((1,1,'a'))
803
>>> X.number_of_edges(1,1,'b')
805
>>> X.number_of_edges(1,2)
807
>>> X.number_of_edges(1,4)