Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/graphs/generators/basic.py
8815 views
1
# -*- coding: utf-8 -*-
2
r"""
3
Basic Graphs
4
5
The methods defined here appear in :mod:`sage.graphs.graph_generators`.
6
7
"""
8
###########################################################################
9
#
10
# Copyright (C) 2006 Robert L. Miller <[email protected]>
11
# and Emily A. Kirkman
12
# Copyright (C) 2009 Michael C. Yurko <[email protected]>
13
#
14
# Distributed under the terms of the GNU General Public License (GPL)
15
# http://www.gnu.org/licenses/
16
###########################################################################
17
18
# import from Sage library
19
from sage.graphs.graph import Graph
20
from sage.graphs import graph
21
from math import sin, cos, pi
22
23
def BullGraph():
24
r"""
25
Returns a bull graph with 5 nodes.
26
27
A bull graph is named for its shape. It's a triangle with horns.
28
This constructor depends on `NetworkX <http://networkx.lanl.gov>`_
29
numeric labeling. For more information, see this
30
:wikipedia:`Wikipedia article on the bull graph <Bull_graph>`.
31
32
PLOTTING:
33
34
Upon construction, the position dictionary is filled to
35
override the spring-layout algorithm. By convention, the bull graph
36
is drawn as a triangle with the first node (0) on the bottom. The
37
second and third nodes (1 and 2) complete the triangle. Node 3 is
38
the horn connected to 1 and node 4 is the horn connected to node
39
2.
40
41
ALGORITHM:
42
43
Uses `NetworkX <http://networkx.lanl.gov>`_.
44
45
EXAMPLES:
46
47
Construct and show a bull graph::
48
49
sage: g = graphs.BullGraph(); g
50
Bull graph: Graph on 5 vertices
51
sage: g.show() # long time
52
53
The bull graph has 5 vertices and 5 edges. Its radius is 2, its
54
diameter 3, and its girth 3. The bull graph is planar with chromatic
55
number 3 and chromatic index also 3. ::
56
57
sage: g.order(); g.size()
58
5
59
5
60
sage: g.radius(); g.diameter(); g.girth()
61
2
62
3
63
3
64
sage: g.chromatic_number()
65
3
66
67
The bull graph has chromatic polynomial `x(x - 2)(x - 1)^3` and
68
Tutte polynomial `x^4 + x^3 + x^2 y`. Its characteristic polynomial
69
is `x(x^2 - x - 3)(x^2 + x - 1)`, which follows from the definition of
70
characteristic polynomials for graphs, i.e. `\det(xI - A)`, where
71
`x` is a variable, `A` the adjacency matrix of the graph, and `I`
72
the identity matrix of the same dimensions as `A`. ::
73
74
sage: chrompoly = g.chromatic_polynomial()
75
sage: bool(expand(x * (x - 2) * (x - 1)^3) == chrompoly)
76
True
77
sage: charpoly = g.characteristic_polynomial()
78
sage: M = g.adjacency_matrix(); M
79
[0 1 1 0 0]
80
[1 0 1 1 0]
81
[1 1 0 0 1]
82
[0 1 0 0 0]
83
[0 0 1 0 0]
84
sage: Id = identity_matrix(ZZ, M.nrows())
85
sage: D = x*Id - M
86
sage: bool(D.determinant() == charpoly)
87
True
88
sage: bool(expand(x * (x^2 - x - 3) * (x^2 + x - 1)) == charpoly)
89
True
90
"""
91
pos_dict = {0:(0,0), 1:(-1,1), 2:(1,1), 3:(-2,2), 4:(2,2)}
92
import networkx
93
G = networkx.bull_graph()
94
return graph.Graph(G, pos=pos_dict, name="Bull graph")
95
96
def ButterflyGraph():
97
r"""
98
Returns the butterfly graph.
99
100
Let `C_3` be the cycle graph on 3 vertices. The butterfly or bowtie
101
graph is obtained by joining two copies of `C_3` at a common vertex,
102
resulting in a graph that is isomorphic to the friendship graph `F_2`.
103
For more information, see this
104
`Wikipedia article on the butterfly graph <http://en.wikipedia.org/wiki/Butterfly_graph>`_.
105
106
.. seealso::
107
108
- :meth:`GraphGenerators.FriendshipGraph`
109
110
EXAMPLES:
111
112
The butterfly graph is a planar graph on 5 vertices and having
113
6 edges. ::
114
115
sage: G = graphs.ButterflyGraph(); G
116
Butterfly graph: Graph on 5 vertices
117
sage: G.show() # long time
118
sage: G.is_planar()
119
True
120
sage: G.order()
121
5
122
sage: G.size()
123
6
124
125
It has diameter 2, girth 3, and radius 1. ::
126
127
sage: G.diameter()
128
2
129
sage: G.girth()
130
3
131
sage: G.radius()
132
1
133
134
The butterfly graph is Eulerian, with chromatic number 3. ::
135
136
sage: G.is_eulerian()
137
True
138
sage: G.chromatic_number()
139
3
140
"""
141
edge_dict = {
142
0: [3,4],
143
1: [2,4],
144
2: [4],
145
3: [4]}
146
pos_dict = {
147
0: [-1, 1],
148
1: [1, 1],
149
2: [1, -1],
150
3: [-1, -1],
151
4: [0, 0]}
152
return graph.Graph(edge_dict, pos=pos_dict, name="Butterfly graph")
153
154
def CircularLadderGraph(n):
155
"""
156
Returns a circular ladder graph with 2\*n nodes.
157
158
A Circular ladder graph is a ladder graph that is connected at the
159
ends, i.e.: a ladder bent around so that top meets bottom. Thus it
160
can be described as two parallel cycle graphs connected at each
161
corresponding node pair.
162
163
This constructor depends on NetworkX numeric labels.
164
165
PLOTTING: Upon construction, the position dictionary is filled to
166
override the spring-layout algorithm. By convention, the circular
167
ladder graph is displayed as an inner and outer cycle pair, with
168
the first n nodes drawn on the inner circle. The first (0) node is
169
drawn at the top of the inner-circle, moving clockwise after that.
170
The outer circle is drawn with the (n+1)th node at the top, then
171
counterclockwise as well.
172
173
EXAMPLES: Construct and show a circular ladder graph with 26 nodes
174
175
::
176
177
sage: g = graphs.CircularLadderGraph(13)
178
sage: g.show() # long time
179
180
Create several circular ladder graphs in a Sage graphics array
181
182
::
183
184
sage: g = []
185
sage: j = []
186
sage: for i in range(9):
187
....: k = graphs.CircularLadderGraph(i+3)
188
....: g.append(k)
189
sage: for i in range(3):
190
....: n = []
191
....: for m in range(3):
192
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
193
....: j.append(n)
194
sage: G = sage.plot.graphics.GraphicsArray(j)
195
sage: G.show() # long time
196
"""
197
pos_dict = {}
198
for i in range(n):
199
x = float(cos((pi/2) + ((2*pi)/n)*i))
200
y = float(sin((pi/2) + ((2*pi)/n)*i))
201
pos_dict[i] = [x,y]
202
for i in range(n,2*n):
203
x = float(2*(cos((pi/2) + ((2*pi)/n)*(i-n))))
204
y = float(2*(sin((pi/2) + ((2*pi)/n)*(i-n))))
205
pos_dict[i] = (x,y)
206
import networkx
207
G = networkx.circular_ladder_graph(n)
208
return graph.Graph(G, pos=pos_dict, name="Circular Ladder graph")
209
210
def ClawGraph():
211
"""
212
Returns a claw graph.
213
214
A claw graph is named for its shape. It is actually a complete
215
bipartite graph with (n1, n2) = (1, 3).
216
217
PLOTTING: See CompleteBipartiteGraph.
218
219
EXAMPLES: Show a Claw graph
220
221
::
222
223
sage: (graphs.ClawGraph()).show() # long time
224
225
Inspect a Claw graph
226
227
::
228
229
sage: G = graphs.ClawGraph()
230
sage: G
231
Claw graph: Graph on 4 vertices
232
"""
233
pos_dict = {0:(0,1),1:(-1,0),2:(0,0),3:(1,0)}
234
import networkx
235
G = networkx.complete_bipartite_graph(1,3)
236
return graph.Graph(G, pos=pos_dict, name="Claw graph")
237
238
def CycleGraph(n):
239
r"""
240
Returns a cycle graph with n nodes.
241
242
A cycle graph is a basic structure which is also typically called
243
an n-gon.
244
245
This constructor is dependent on vertices numbered 0 through n-1 in
246
NetworkX ``cycle_graph()``
247
248
PLOTTING: Upon construction, the position dictionary is filled to
249
override the spring-layout algorithm. By convention, each cycle
250
graph will be displayed with the first (0) node at the top, with
251
the rest following in a counterclockwise manner.
252
253
The cycle graph is a good opportunity to compare efficiency of
254
filling a position dictionary vs. using the spring-layout algorithm
255
for plotting. Because the cycle graph is very symmetric, the
256
resulting plots should be similar (in cases of small n).
257
258
Filling the position dictionary in advance adds O(n) to the
259
constructor.
260
261
EXAMPLES: Compare plotting using the predefined layout and
262
networkx::
263
264
sage: import networkx
265
sage: n = networkx.cycle_graph(23)
266
sage: spring23 = Graph(n)
267
sage: posdict23 = graphs.CycleGraph(23)
268
sage: spring23.show() # long time
269
sage: posdict23.show() # long time
270
271
We next view many cycle graphs as a Sage graphics array. First we
272
use the ``CycleGraph`` constructor, which fills in the
273
position dictionary::
274
275
sage: g = []
276
sage: j = []
277
sage: for i in range(9):
278
....: k = graphs.CycleGraph(i+3)
279
....: g.append(k)
280
sage: for i in range(3):
281
....: n = []
282
....: for m in range(3):
283
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
284
....: j.append(n)
285
sage: G = sage.plot.graphics.GraphicsArray(j)
286
sage: G.show() # long time
287
288
Compare to plotting with the spring-layout algorithm::
289
290
sage: g = []
291
sage: j = []
292
sage: for i in range(9):
293
....: spr = networkx.cycle_graph(i+3)
294
....: k = Graph(spr)
295
....: g.append(k)
296
sage: for i in range(3):
297
....: n = []
298
....: for m in range(3):
299
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
300
....: j.append(n)
301
sage: G = sage.plot.graphics.GraphicsArray(j)
302
sage: G.show() # long time
303
"""
304
pos_dict = {}
305
for i in range(n):
306
x = float(cos((pi/2) + ((2*pi)/n)*i))
307
y = float(sin((pi/2) + ((2*pi)/n)*i))
308
pos_dict[i] = (x,y)
309
import networkx
310
G = networkx.cycle_graph(n)
311
return graph.Graph(G, pos=pos_dict, name="Cycle graph")
312
313
def CompleteGraph(n):
314
"""
315
Returns a complete graph on n nodes.
316
317
A Complete Graph is a graph in which all nodes are connected to all
318
other nodes.
319
320
This constructor is dependent on vertices numbered 0 through n-1 in
321
NetworkX complete_graph()
322
323
PLOTTING: Upon construction, the position dictionary is filled to
324
override the spring-layout algorithm. By convention, each complete
325
graph will be displayed with the first (0) node at the top, with
326
the rest following in a counterclockwise manner.
327
328
In the complete graph, there is a big difference visually in using
329
the spring-layout algorithm vs. the position dictionary used in
330
this constructor. The position dictionary flattens the graph,
331
making it clear which nodes an edge is connected to. But the
332
complete graph offers a good example of how the spring-layout
333
works. The edges push outward (everything is connected), causing
334
the graph to appear as a 3-dimensional pointy ball. (See examples
335
below).
336
337
EXAMPLES: We view many Complete graphs with a Sage Graphics Array,
338
first with this constructor (i.e., the position dictionary
339
filled)::
340
341
sage: g = []
342
sage: j = []
343
sage: for i in range(9):
344
....: k = graphs.CompleteGraph(i+3)
345
....: g.append(k)
346
sage: for i in range(3):
347
....: n = []
348
....: for m in range(3):
349
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
350
....: j.append(n)
351
sage: G = sage.plot.graphics.GraphicsArray(j)
352
sage: G.show() # long time
353
354
We compare to plotting with the spring-layout algorithm::
355
356
sage: import networkx
357
sage: g = []
358
sage: j = []
359
sage: for i in range(9):
360
....: spr = networkx.complete_graph(i+3)
361
....: k = Graph(spr)
362
....: g.append(k)
363
sage: for i in range(3):
364
....: n = []
365
....: for m in range(3):
366
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
367
....: j.append(n)
368
sage: G = sage.plot.graphics.GraphicsArray(j)
369
sage: G.show() # long time
370
371
Compare the constructors (results will vary)
372
373
::
374
375
sage: import networkx
376
sage: t = cputime()
377
sage: n = networkx.complete_graph(389); spring389 = Graph(n)
378
sage: cputime(t) # random
379
0.59203700000000126
380
sage: t = cputime()
381
sage: posdict389 = graphs.CompleteGraph(389)
382
sage: cputime(t) # random
383
0.6680419999999998
384
385
We compare plotting::
386
387
sage: import networkx
388
sage: n = networkx.complete_graph(23)
389
sage: spring23 = Graph(n)
390
sage: posdict23 = graphs.CompleteGraph(23)
391
sage: spring23.show() # long time
392
sage: posdict23.show() # long time
393
"""
394
pos_dict = {}
395
for i in range(n):
396
x = float(cos((pi/2) + ((2*pi)/n)*i))
397
y = float(sin((pi/2) + ((2*pi)/n)*i))
398
pos_dict[i] = (x,y)
399
import networkx
400
G = networkx.complete_graph(n)
401
return graph.Graph(G, pos=pos_dict, name="Complete graph")
402
403
def CompleteBipartiteGraph(n1, n2):
404
"""
405
Returns a Complete Bipartite Graph sized n1+n2, with each of the
406
nodes [0,(n1-1)] connected to each of the nodes [n1,(n2-1)] and
407
vice versa.
408
409
A Complete Bipartite Graph is a graph with its vertices partitioned
410
into two groups, V1 and V2. Each v in V1 is connected to every v in
411
V2, and vice versa.
412
413
PLOTTING: Upon construction, the position dictionary is filled to
414
override the spring-layout algorithm. By convention, each complete
415
bipartite graph will be displayed with the first n1 nodes on the
416
top row (at y=1) from left to right. The remaining n2 nodes appear
417
at y=0, also from left to right. The shorter row (partition with
418
fewer nodes) is stretched to the same length as the longer row,
419
unless the shorter row has 1 node; in which case it is centered.
420
The x values in the plot are in domain [0,maxn1,n2].
421
422
In the Complete Bipartite graph, there is a visual difference in
423
using the spring-layout algorithm vs. the position dictionary used
424
in this constructor. The position dictionary flattens the graph and
425
separates the partitioned nodes, making it clear which nodes an
426
edge is connected to. The Complete Bipartite graph plotted with the
427
spring-layout algorithm tends to center the nodes in n1 (see
428
spring_med in examples below), thus overlapping its nodes and
429
edges, making it typically hard to decipher.
430
431
Filling the position dictionary in advance adds O(n) to the
432
constructor. Feel free to race the constructors below in the
433
examples section. The much larger difference is the time added by
434
the spring-layout algorithm when plotting. (Also shown in the
435
example below). The spring model is typically described as
436
`O(n^3)`, as appears to be the case in the NetworkX source
437
code.
438
439
EXAMPLES: Two ways of constructing the complete bipartite graph,
440
using different layout algorithms::
441
442
sage: import networkx
443
sage: n = networkx.complete_bipartite_graph(389,157); spring_big = Graph(n) # long time
444
sage: posdict_big = graphs.CompleteBipartiteGraph(389,157) # long time
445
446
Compare the plotting::
447
448
sage: n = networkx.complete_bipartite_graph(11,17)
449
sage: spring_med = Graph(n)
450
sage: posdict_med = graphs.CompleteBipartiteGraph(11,17)
451
452
Notice here how the spring-layout tends to center the nodes of n1
453
454
::
455
456
sage: spring_med.show() # long time
457
sage: posdict_med.show() # long time
458
459
View many complete bipartite graphs with a Sage Graphics Array,
460
with this constructor (i.e., the position dictionary filled)::
461
462
sage: g = []
463
sage: j = []
464
sage: for i in range(9):
465
....: k = graphs.CompleteBipartiteGraph(i+1,4)
466
....: g.append(k)
467
sage: for i in range(3):
468
....: n = []
469
....: for m in range(3):
470
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
471
....: j.append(n)
472
sage: G = sage.plot.graphics.GraphicsArray(j)
473
sage: G.show() # long time
474
475
We compare to plotting with the spring-layout algorithm::
476
477
sage: g = []
478
sage: j = []
479
sage: for i in range(9):
480
....: spr = networkx.complete_bipartite_graph(i+1,4)
481
....: k = Graph(spr)
482
....: g.append(k)
483
sage: for i in range(3):
484
....: n = []
485
....: for m in range(3):
486
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
487
....: j.append(n)
488
sage: G = sage.plot.graphics.GraphicsArray(j)
489
sage: G.show() # long time
490
491
Trac ticket #12155::
492
493
sage: graphs.CompleteBipartiteGraph(5,6).complement()
494
complement(Complete bipartite graph): Graph on 11 vertices
495
"""
496
pos_dict = {}
497
c1 = 1 # scaling factor for top row
498
c2 = 1 # scaling factor for bottom row
499
c3 = 0 # pad to center if top row has 1 node
500
c4 = 0 # pad to center if bottom row has 1 node
501
if n1 > n2:
502
if n2 == 1:
503
c4 = (n1-1)/2
504
else:
505
c2 = ((n1-1)/(n2-1))
506
elif n2 > n1:
507
if n1 == 1:
508
c3 = (n2-1)/2
509
else:
510
c1 = ((n2-1)/(n1-1))
511
for i in range(n1):
512
x = c1*i + c3
513
y = 1
514
pos_dict[i] = (x,y)
515
for i in range(n1+n2)[n1:]:
516
x = c2*(i-n1) + c4
517
y = 0
518
pos_dict[i] = (x,y)
519
import networkx
520
G = networkx.complete_bipartite_graph(n1,n2)
521
return Graph(G, pos=pos_dict, name="Complete bipartite graph")
522
523
def CompleteMultipartiteGraph(l):
524
r"""
525
Returns a complete multipartite graph.
526
527
INPUT:
528
529
- ``l`` -- a list of integers : the respective sizes
530
of the components.
531
532
EXAMPLE:
533
534
A complete tripartite graph with sets of sizes
535
`5, 6, 8`::
536
537
sage: g = graphs.CompleteMultipartiteGraph([5, 6, 8]); g
538
Multipartite Graph with set sizes [5, 6, 8]: Graph on 19 vertices
539
540
It clearly has a chromatic number of 3::
541
542
sage: g.chromatic_number()
543
3
544
"""
545
g = Graph()
546
for i in l:
547
g = g + CompleteGraph(i)
548
549
g = g.complement()
550
g.name("Multipartite Graph with set sizes "+str(l))
551
552
return g
553
554
def DiamondGraph():
555
"""
556
Returns a diamond graph with 4 nodes.
557
558
A diamond graph is a square with one pair of diagonal nodes
559
connected.
560
561
This constructor depends on NetworkX numeric labeling.
562
563
PLOTTING: Upon construction, the position dictionary is filled to
564
override the spring-layout algorithm. By convention, the diamond
565
graph is drawn as a diamond, with the first node on top, second on
566
the left, third on the right, and fourth on the bottom; with the
567
second and third node connected.
568
569
EXAMPLES: Construct and show a diamond graph
570
571
::
572
573
sage: g = graphs.DiamondGraph()
574
sage: g.show() # long time
575
"""
576
pos_dict = {0:(0,1),1:(-1,0),2:(1,0),3:(0,-1)}
577
import networkx
578
G = networkx.diamond_graph()
579
return graph.Graph(G, pos=pos_dict, name="Diamond Graph")
580
581
def EmptyGraph():
582
"""
583
Returns an empty graph (0 nodes and 0 edges).
584
585
This is useful for constructing graphs by adding edges and vertices
586
individually or in a loop.
587
588
PLOTTING: When plotting, this graph will use the default
589
spring-layout algorithm, unless a position dictionary is
590
specified.
591
592
EXAMPLES: Add one vertex to an empty graph and then show::
593
594
sage: empty1 = graphs.EmptyGraph()
595
sage: empty1.add_vertex()
596
0
597
sage: empty1.show() # long time
598
599
Use for loops to build a graph from an empty graph::
600
601
sage: empty2 = graphs.EmptyGraph()
602
sage: for i in range(5):
603
....: empty2.add_vertex() # add 5 nodes, labeled 0-4
604
0
605
1
606
2
607
3
608
4
609
sage: for i in range(3):
610
....: empty2.add_edge(i,i+1) # add edges {[0:1],[1:2],[2:3]}
611
sage: for i in range(4)[1:]:
612
....: empty2.add_edge(4,i) # add edges {[1:4],[2:4],[3:4]}
613
sage: empty2.show() # long time
614
"""
615
return graph.Graph(sparse=True)
616
617
def ToroidalGrid2dGraph(n1, n2):
618
r"""
619
Returns a toroidal 2-dimensional grid graph with `n_1n_2` nodes (`n_1`
620
rows and `n_2` columns).
621
622
The toroidal 2-dimensional grid with parameters `n_1,n_2` is the
623
2-dimensional grid graph with identical parameters to which are added
624
the edges `((i,0),(i,n_2-1))` and `((0,i),(n_1-1,i))`.
625
626
EXAMPLE:
627
628
The toroidal 2-dimensional grid is a regular graph, while the usual
629
2-dimensional grid is not ::
630
631
sage: tgrid = graphs.ToroidalGrid2dGraph(8,9)
632
sage: print tgrid
633
Toroidal 2D Grid Graph with parameters 8,9
634
sage: grid = graphs.Grid2dGraph(8,9)
635
sage: grid.is_regular()
636
False
637
sage: tgrid.is_regular()
638
True
639
"""
640
641
g = Grid2dGraph(n1,n2)
642
643
g.add_edges([((i,0),(i,n2-1)) for i in range(n1)] + [((0,i),(n1-1,i)) for i in range(n2)])
644
645
g.name("Toroidal 2D Grid Graph with parameters "+str(n1)+","+str(n2))
646
647
d = g.get_pos()
648
n1 += 0.
649
n2 += 0.
650
uf = (n1/2)*(n1/2)
651
vf = (n2/2)*(n2/2)
652
for u,v in d:
653
x,y = d[(u,v)]
654
x += 0.25*(1.0+u*(u-n1+1)/uf)
655
y += 0.25*(1+v*(v-n2+1)/vf)
656
d[(u,v)] = (x,y)
657
658
return g
659
660
def Toroidal6RegularGrid2dGraph(n1, n2):
661
r"""
662
Returns a toroidal 6-regular grid.
663
664
The toroidal 6-regular grid is a 6-regular graph on `n_1\times n_2`
665
vertices and its elements have coordinates `(i,j)` for `i \in \{0...i-1\}`
666
and `j \in \{0...j-1\}`.
667
668
Its edges are those of the :meth:`ToroidalGrid2dGraph`, to which are
669
added the edges between `(i,j)` and `((i+1)\%n_1, (j+1)\%n_2)`.
670
671
INPUT:
672
673
- ``n1, n2`` (integers) -- see above.
674
675
EXAMPLE:
676
677
The toroidal 6-regular grid on `25` elements::
678
679
sage: g = graphs.Toroidal6RegularGrid2dGraph(5,5)
680
sage: g.is_regular(k=6)
681
True
682
sage: g.is_vertex_transitive()
683
True
684
sage: g.line_graph().is_vertex_transitive()
685
True
686
sage: g.automorphism_group().cardinality()
687
300
688
sage: g.is_hamiltonian()
689
True
690
691
TESTS:
692
693
Senseless input::
694
695
sage: graphs.Toroidal6RegularGrid2dGraph(5,2)
696
Traceback (most recent call last):
697
...
698
ValueError: Parameters n1 and n2 must be integers larger than 3 !
699
sage: graphs.Toroidal6RegularGrid2dGraph(2,0)
700
Traceback (most recent call last):
701
...
702
ValueError: Parameters n1 and n2 must be integers larger than 3 !
703
"""
704
705
if n1 <= 3 or n2 <= 3:
706
raise ValueError("Parameters n1 and n2 must be integers larger than 3 !")
707
708
g = ToroidalGrid2dGraph(n1,n2)
709
for u,v in g:
710
g.add_edge((u,v),((u+1)%n1,(v+1)%n2))
711
712
g.name("Toroidal Hexagonal Grid graph on "+str(n1)+"x"+str(n2)+" elements")
713
return g
714
715
def Grid2dGraph(n1, n2):
716
r"""
717
Returns a `2`-dimensional grid graph with `n_1n_2` nodes (`n_1` rows and
718
`n_2` columns).
719
720
A 2d grid graph resembles a `2` dimensional grid. All inner nodes are
721
connected to their `4` neighbors. Outer (non-corner) nodes are
722
connected to their `3` neighbors. Corner nodes are connected to their
723
2 neighbors.
724
725
This constructor depends on NetworkX numeric labels.
726
727
PLOTTING: Upon construction, the position dictionary is filled to
728
override the spring-layout algorithm. By convention, nodes are
729
labelled in (row, column) pairs with `(0, 0)` in the top left corner.
730
Edges will always be horizontal and vertical - another advantage of
731
filling the position dictionary.
732
733
EXAMPLES: Construct and show a grid 2d graph Rows = `5`, Columns = `7`
734
735
::
736
737
sage: g = graphs.Grid2dGraph(5,7)
738
sage: g.show() # long time
739
740
TESTS:
741
742
Senseless input::
743
744
sage: graphs.Grid2dGraph(5,0)
745
Traceback (most recent call last):
746
...
747
ValueError: Parameters n1 and n2 must be positive integers !
748
sage: graphs.Grid2dGraph(-1,0)
749
Traceback (most recent call last):
750
...
751
ValueError: Parameters n1 and n2 must be positive integers !
752
753
The graph name contains the dimension::
754
755
sage: g = graphs.Grid2dGraph(5,7)
756
sage: g.name()
757
'2D Grid Graph for [5, 7]'
758
"""
759
760
if n1 <= 0 or n2 <= 0:
761
raise ValueError("Parameters n1 and n2 must be positive integers !")
762
763
pos_dict = {}
764
for i in range(n1):
765
y = -i
766
for j in range(n2):
767
x = j
768
pos_dict[i, j] = (x, y)
769
import networkx
770
G = networkx.grid_2d_graph(n1, n2)
771
return graph.Graph(G, pos=pos_dict, name="2D Grid Graph for "+str([n1, n2]))
772
773
def GridGraph(dim_list):
774
"""
775
Returns an n-dimensional grid graph.
776
777
INPUT:
778
779
780
- ``dim_list`` - a list of integers representing the
781
number of nodes to extend in each dimension.
782
783
784
PLOTTING: When plotting, this graph will use the default
785
spring-layout algorithm, unless a position dictionary is
786
specified.
787
788
EXAMPLES::
789
790
sage: G = graphs.GridGraph([2,3,4])
791
sage: G.show() # long time
792
793
::
794
795
sage: C = graphs.CubeGraph(4)
796
sage: G = graphs.GridGraph([2,2,2,2])
797
sage: C.show() # long time
798
sage: G.show() # long time
799
800
TESTS:
801
802
The graph name contains the dimension::
803
804
sage: g = graphs.GridGraph([5, 7])
805
sage: g.name()
806
'Grid Graph for [5, 7]'
807
sage: g = graphs.GridGraph([2, 3, 4])
808
sage: g.name()
809
'Grid Graph for [2, 3, 4]'
810
sage: g = graphs.GridGraph([2, 4, 3])
811
sage: g.name()
812
'Grid Graph for [2, 4, 3]'
813
814
All dimensions must be positive integers::
815
816
sage: g = graphs.GridGraph([2,-1,3])
817
Traceback (most recent call last):
818
...
819
ValueError: All dimensions must be positive integers !
820
"""
821
import networkx
822
dim = [int(a) for a in dim_list]
823
if any(a <= 0 for a in dim):
824
raise ValueError("All dimensions must be positive integers !")
825
# We give a copy of dim to networkx because it modifies the list
826
G = networkx.grid_graph(list(dim))
827
return graph.Graph(G, name="Grid Graph for " + str(dim))
828
829
def HouseGraph():
830
"""
831
Returns a house graph with 5 nodes.
832
833
A house graph is named for its shape. It is a triangle (roof) over a
834
square (walls).
835
836
This constructor depends on NetworkX numeric labeling.
837
838
PLOTTING: Upon construction, the position dictionary is filled to
839
override the spring-layout algorithm. By convention, the house
840
graph is drawn with the first node in the lower-left corner of the
841
house, the second in the lower-right corner of the house. The third
842
node is in the upper-left corner connecting the roof to the wall,
843
and the fourth is in the upper-right corner connecting the roof to
844
the wall. The fifth node is the top of the roof, connected only to
845
the third and fourth.
846
847
EXAMPLES: Construct and show a house graph
848
849
::
850
851
sage: g = graphs.HouseGraph()
852
sage: g.show() # long time
853
"""
854
pos_dict = {0:(-1,0),1:(1,0),2:(-1,1),3:(1,1),4:(0,2)}
855
import networkx
856
G = networkx.house_graph()
857
return graph.Graph(G, pos=pos_dict, name="House Graph")
858
859
def HouseXGraph():
860
"""
861
Returns a house X graph with 5 nodes.
862
863
A house X graph is a house graph with two additional edges. The
864
upper-right corner is connected to the lower-left. And the
865
upper-left corner is connected to the lower-right.
866
867
This constructor depends on NetworkX numeric labeling.
868
869
PLOTTING: Upon construction, the position dictionary is filled to
870
override the spring-layout algorithm. By convention, the house X
871
graph is drawn with the first node in the lower-left corner of the
872
house, the second in the lower-right corner of the house. The third
873
node is in the upper-left corner connecting the roof to the wall,
874
and the fourth is in the upper-right corner connecting the roof to
875
the wall. The fifth node is the top of the roof, connected only to
876
the third and fourth.
877
878
EXAMPLES: Construct and show a house X graph
879
880
::
881
882
sage: g = graphs.HouseXGraph()
883
sage: g.show() # long time
884
"""
885
pos_dict = {0:(-1,0),1:(1,0),2:(-1,1),3:(1,1),4:(0,2)}
886
import networkx
887
G = networkx.house_x_graph()
888
return graph.Graph(G, pos=pos_dict, name="House Graph")
889
890
def LadderGraph(n):
891
"""
892
Returns a ladder graph with 2\*n nodes.
893
894
A ladder graph is a basic structure that is typically displayed as
895
a ladder, i.e.: two parallel path graphs connected at each
896
corresponding node pair.
897
898
This constructor depends on NetworkX numeric labels.
899
900
PLOTTING: Upon construction, the position dictionary is filled to
901
override the spring-layout algorithm. By convention, each ladder
902
graph will be displayed horizontally, with the first n nodes
903
displayed left to right on the top horizontal line.
904
905
EXAMPLES: Construct and show a ladder graph with 14 nodes
906
907
::
908
909
sage: g = graphs.LadderGraph(7)
910
sage: g.show() # long time
911
912
Create several ladder graphs in a Sage graphics array
913
914
::
915
916
sage: g = []
917
sage: j = []
918
sage: for i in range(9):
919
....: k = graphs.LadderGraph(i+2)
920
....: g.append(k)
921
sage: for i in range(3):
922
....: n = []
923
....: for m in range(3):
924
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
925
....: j.append(n)
926
sage: G = sage.plot.graphics.GraphicsArray(j)
927
sage: G.show() # long time
928
"""
929
pos_dict = {}
930
for i in range(n):
931
pos_dict[i] = (i,1)
932
for i in range(n,2*n):
933
x = i - n
934
pos_dict[i] = (x,0)
935
import networkx
936
G = networkx.ladder_graph(n)
937
return graph.Graph(G, pos=pos_dict, name="Ladder graph")
938
939
def LollipopGraph(n1, n2):
940
"""
941
Returns a lollipop graph with n1+n2 nodes.
942
943
A lollipop graph is a path graph (order n2) connected to a complete
944
graph (order n1). (A barbell graph minus one of the bells).
945
946
This constructor depends on NetworkX numeric labels.
947
948
PLOTTING: Upon construction, the position dictionary is filled to
949
override the spring-layout algorithm. By convention, the complete
950
graph will be drawn in the lower-left corner with the (n1)th node
951
at a 45 degree angle above the right horizontal center of the
952
complete graph, leading directly into the path graph.
953
954
EXAMPLES: Construct and show a lollipop graph Candy = 13, Stick =
955
4
956
957
::
958
959
sage: g = graphs.LollipopGraph(13,4)
960
sage: g.show() # long time
961
962
Create several lollipop graphs in a Sage graphics array
963
964
::
965
966
sage: g = []
967
sage: j = []
968
sage: for i in range(6):
969
....: k = graphs.LollipopGraph(i+3,4)
970
....: g.append(k)
971
sage: for i in range(2):
972
....: n = []
973
....: for m in range(3):
974
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
975
....: j.append(n)
976
sage: G = sage.plot.graphics.GraphicsArray(j)
977
sage: G.show() # long time
978
"""
979
pos_dict = {}
980
981
for i in range(n1):
982
x = float(cos((pi/4) - ((2*pi)/n1)*i) - n2/2 - 1)
983
y = float(sin((pi/4) - ((2*pi)/n1)*i) - n2/2 - 1)
984
j = n1-1-i
985
pos_dict[j] = (x,y)
986
for i in range(n1, n1+n2):
987
x = float(i - n1 - n2/2 + 1)
988
y = float(i - n1 - n2/2 + 1)
989
pos_dict[i] = (x,y)
990
991
import networkx
992
G = networkx.lollipop_graph(n1,n2)
993
return graph.Graph(G, pos=pos_dict, name="Lollipop Graph")
994
995
def PathGraph(n, pos=None):
996
"""
997
Returns a path graph with n nodes. Pos argument takes a string
998
which is either 'circle' or 'line', (otherwise the default is
999
used). See the plotting section below for more detail.
1000
1001
A path graph is a graph where all inner nodes are connected to
1002
their two neighbors and the two end-nodes are connected to their
1003
one inner neighbors. (i.e.: a cycle graph without the first and
1004
last node connected).
1005
1006
This constructor depends on NetworkX numeric labels.
1007
1008
PLOTTING: Upon construction, the position dictionary is filled to
1009
override the spring-layout algorithm. By convention, the graph may
1010
be drawn in one of two ways: The 'line' argument will draw the
1011
graph in a horizontal line (left to right) if there are less than
1012
11 nodes. Otherwise the 'line' argument will append horizontal
1013
lines of length 10 nodes below, alternating left to right and right
1014
to left. The 'circle' argument will cause the graph to be drawn in
1015
a cycle-shape, with the first node at the top and then about the
1016
circle in a clockwise manner. By default (without an appropriate
1017
string argument) the graph will be drawn as a 'circle' if 10 n 41
1018
and as a 'line' for all other n.
1019
1020
EXAMPLES: Show default drawing by size: 'line': n 11
1021
1022
::
1023
1024
sage: p = graphs.PathGraph(10)
1025
sage: p.show() # long time
1026
1027
'circle': 10 n 41
1028
1029
::
1030
1031
sage: q = graphs.PathGraph(25)
1032
sage: q.show() # long time
1033
1034
'line': n 40
1035
1036
::
1037
1038
sage: r = graphs.PathGraph(55)
1039
sage: r.show() # long time
1040
1041
Override the default drawing::
1042
1043
sage: s = graphs.PathGraph(5,'circle')
1044
sage: s.show() # long time
1045
"""
1046
pos_dict = {}
1047
1048
# Choose appropriate drawing pattern
1049
circle = False
1050
if pos == "circle": circle = True
1051
elif pos == "line": circle = False
1052
# Otherwise use default by size of n
1053
elif 10 < n < 41: circle = True
1054
1055
# Draw 'circle'
1056
if circle:
1057
for i in range(n):
1058
x = float(cos((pi/2) + ((2*pi)/n)*i))
1059
y = float(sin((pi/2) + ((2*pi)/n)*i))
1060
pos_dict[i] = (x,y)
1061
# Draw 'line'
1062
else:
1063
counter = 0 # node index
1064
rem = n%10 # remainder to appear on last row
1065
rows = n//10 # number of rows (not counting last row)
1066
lr = True # left to right
1067
1068
for i in range(rows): # note that rows doesn't include last row
1069
y = -i
1070
for j in range(10):
1071
if lr:
1072
x = j
1073
else:
1074
x = 9 - j
1075
pos_dict[counter] = (x,y)
1076
counter += 1
1077
if lr: lr = False
1078
else: lr = True
1079
y = -rows
1080
for j in range(rem): # last row
1081
if lr:
1082
x = j
1083
else:
1084
x = 9 - j
1085
pos_dict[counter] = (x,y)
1086
counter += 1
1087
1088
import networkx
1089
G = networkx.path_graph(n)
1090
return graph.Graph(G, pos=pos_dict, name="Path Graph")
1091
1092
def StarGraph(n):
1093
"""
1094
Returns a star graph with n+1 nodes.
1095
1096
A Star graph is a basic structure where one node is connected to
1097
all other nodes.
1098
1099
This constructor is dependent on NetworkX numeric labels.
1100
1101
PLOTTING: Upon construction, the position dictionary is filled to
1102
override the spring-layout algorithm. By convention, each star
1103
graph will be displayed with the first (0) node in the center, the
1104
second node (1) at the top, with the rest following in a
1105
counterclockwise manner. (0) is the node connected to all other
1106
nodes.
1107
1108
The star graph is a good opportunity to compare efficiency of
1109
filling a position dictionary vs. using the spring-layout algorithm
1110
for plotting. As far as display, the spring-layout should push all
1111
other nodes away from the (0) node, and thus look very similar to
1112
this constructor's positioning.
1113
1114
EXAMPLES::
1115
1116
sage: import networkx
1117
1118
Compare the plots::
1119
1120
sage: n = networkx.star_graph(23)
1121
sage: spring23 = Graph(n)
1122
sage: posdict23 = graphs.StarGraph(23)
1123
sage: spring23.show() # long time
1124
sage: posdict23.show() # long time
1125
1126
View many star graphs as a Sage Graphics Array
1127
1128
With this constructor (i.e., the position dictionary filled)
1129
1130
::
1131
1132
sage: g = []
1133
sage: j = []
1134
sage: for i in range(9):
1135
....: k = graphs.StarGraph(i+3)
1136
....: g.append(k)
1137
sage: for i in range(3):
1138
....: n = []
1139
....: for m in range(3):
1140
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
1141
....: j.append(n)
1142
sage: G = sage.plot.graphics.GraphicsArray(j)
1143
sage: G.show() # long time
1144
1145
Compared to plotting with the spring-layout algorithm
1146
1147
::
1148
1149
sage: g = []
1150
sage: j = []
1151
sage: for i in range(9):
1152
....: spr = networkx.star_graph(i+3)
1153
....: k = Graph(spr)
1154
....: g.append(k)
1155
sage: for i in range(3):
1156
....: n = []
1157
....: for m in range(3):
1158
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
1159
....: j.append(n)
1160
sage: G = sage.plot.graphics.GraphicsArray(j)
1161
sage: G.show() # long time
1162
"""
1163
pos_dict = {}
1164
pos_dict[0] = (0,0)
1165
for i in range(1,n+1):
1166
x = float(cos((pi/2) + ((2*pi)/n)*(i-1)))
1167
y = float(sin((pi/2) + ((2*pi)/n)*(i-1)))
1168
pos_dict[i] = (x,y)
1169
import networkx
1170
G = networkx.star_graph(n)
1171
return graph.Graph(G, pos=pos_dict, name="Star graph")
1172
1173
1174