Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/graphs/generators/chessboard.py
8817 views
1
# -*- coding: utf-8 -*-
2
r"""
3
Chessboard Graphs
4
5
The methods defined here appear in :mod:`sage.graphs.graph_generators`.
6
7
- :meth:`BishopGraph <GraphGenerators.BishopGraph>`
8
- :meth:`KingGraph <GraphGenerators.KingGraph>`
9
- :meth:`KnightGraph <GraphGenerators.KnightGraph>`
10
- :meth:`QueenGraph <GraphGenerators.QueenGraph>`
11
- :meth:`RookGraph <GraphGenerators.RookGraph>`
12
13
AUTHORS:
14
15
- David Coudert (2012)
16
"""
17
18
################################################################################
19
# Copyright (C) 2012 David Coudert <[email protected]>
20
#
21
# Distributed under the terms of the GNU General Public License (GPL)
22
# http://www.gnu.org/licenses/
23
################################################################################
24
25
def ChessboardGraphGenerator(dim_list,
26
rook = True, rook_radius = None,
27
bishop = True, bishop_radius = None,
28
knight = True, knight_x = 1, knight_y = 2,
29
relabel = False):
30
r"""
31
Returns a Graph built on a `d`-dimensional chessboard with prescribed
32
dimensions and interconnections.
33
34
This function allows to generate many kinds of graphs corresponding to legal
35
movements on a `d`-dimensional chessboard: Queen Graph, King Graph, Knight
36
Graphs, Bishop Graph, and many generalizations. It also allows to avoid
37
redondant code.
38
39
INPUTS:
40
41
- ``dim_list`` -- an iterable object (list, set, dict) providing the
42
dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.
43
44
- ``rook`` -- (default: ``True``) boolean value indicating if the chess
45
piece is able to move as a rook, that is at any distance along a
46
dimension.
47
48
- ``rook_radius`` -- (default: None) integer value restricting the rook-like
49
movements to distance at most `rook_radius`.
50
51
- ``bishop`` -- (default: ``True``) boolean value indicating if the chess
52
piece is able to move like a bishop, that is along diagonals.
53
54
- ``bishop_radius`` -- (default: None) integer value restricting the
55
bishop-like movements to distance at most `bishop_radius`.
56
57
- ``knight`` -- (default: ``True``) boolean value indicating if the chess
58
piece is able to move like a knight.
59
60
- ``knight_x`` -- (default: 1) integer indicating the number on steps the
61
chess piece moves in one dimension when moving like a knight.
62
63
- ``knight_y`` -- (default: 2) integer indicating the number on steps the
64
chess piece moves in the second dimension when moving like a knight.
65
66
- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices
67
must be relabeled as integers.
68
69
OUTPUTS:
70
71
- A Graph build on a `d`-dimensional chessboard with prescribed dimensions,
72
and with edges according given parameters.
73
74
- A string encoding the dimensions. This is mainly useful for providing
75
names to graphs.
76
77
EXAMPLES:
78
79
A `(2,2)`-King Graph is isomorphic to the complete graph on 4 vertices::
80
81
sage: G, _ = graphs.ChessboardGraphGenerator( [2,2] )
82
sage: G.is_isomorphic( graphs.CompleteGraph(4) )
83
True
84
85
A Rook's Graph in 2 dimensions is isomporphic to the cartesian product of 2
86
complete graphs::
87
88
sage: G, _ = graphs.ChessboardGraphGenerator( [3,4], rook=True, rook_radius=None, bishop=False, knight=False )
89
sage: H = ( graphs.CompleteGraph(3) ).cartesian_product( graphs.CompleteGraph(4) )
90
sage: G.is_isomorphic(H)
91
True
92
93
TESTS:
94
95
Giving dimensions less than 2::
96
97
sage: graphs.ChessboardGraphGenerator( [0, 2] )
98
Traceback (most recent call last):
99
...
100
ValueError: The dimensions must be positive integers larger than 1.
101
102
Giving non integer dimensions::
103
104
sage: graphs.ChessboardGraphGenerator( [4.5, 2] )
105
Traceback (most recent call last):
106
...
107
ValueError: The dimensions must be positive integers larger than 1.
108
109
Giving too few dimensions::
110
111
sage: graphs.ChessboardGraphGenerator( [2] )
112
Traceback (most recent call last):
113
...
114
ValueError: The chessboard must have at least 2 dimensions.
115
116
Giving a non-iterable object as first parameter::
117
118
sage: graphs.ChessboardGraphGenerator( 2, 3 )
119
Traceback (most recent call last):
120
...
121
TypeError: The first parameter must be an iterable object.
122
123
Giving too small rook radius::
124
125
sage: graphs.ChessboardGraphGenerator( [2, 3], rook=True, rook_radius=0 )
126
Traceback (most recent call last):
127
...
128
ValueError: The rook_radius must be either None or have an integer value >= 1.
129
130
Giving wrong values for knights movements::
131
132
sage: graphs.ChessboardGraphGenerator( [2, 3], rook=False, bishop=False, knight=True, knight_x=1, knight_y=-1 )
133
Traceback (most recent call last):
134
...
135
ValueError: The knight_x and knight_y values must be integers of value >= 1.
136
"""
137
from sage.rings.integer_ring import ZZ
138
139
# We decode the dimensions of the chessboard
140
try:
141
dim = list(dim_list)
142
nb_dim = len(dim)
143
except TypeError:
144
raise TypeError('The first parameter must be an iterable object.')
145
if nb_dim < 2:
146
raise ValueError('The chessboard must have at least 2 dimensions.')
147
if any(a not in ZZ or a < 1 for a in dim):
148
raise ValueError('The dimensions must be positive integers larger than 1.')
149
dimstr = str(tuple(dim))
150
151
# We check the radius toward neighbors
152
if rook:
153
if rook_radius is None:
154
rook_radius = max(dim)
155
elif not rook_radius in ZZ or rook_radius < 1:
156
raise ValueError('The rook_radius must be either None or have an integer value >= 1.')
157
if bishop:
158
if bishop_radius is None:
159
bishop_radius = max(dim)
160
elif not bishop_radius in ZZ or bishop_radius < 1:
161
raise ValueError('The bishop_radius must be either None or have an integer value >= 1.')
162
if knight and ( not knight_x in ZZ or not knight_y in ZZ or knight_x < 1 or knight_y < 1 ):
163
raise ValueError('The knight_x and knight_y values must be integers of value >= 1.')
164
165
# We build the set of vertices of the d-dimensionnal chessboard
166
from itertools import product
167
V = map(list,list(product(*map(range,dim))))
168
169
from sage.combinat.combination import Combinations
170
combin = Combinations(range(nb_dim),2)
171
172
from sage.graphs.graph import Graph
173
G = Graph()
174
for u in V:
175
uu = tuple(u)
176
G.add_vertex(uu)
177
178
if rook:
179
# We add edges to vertices we can reach when moving in one dimension
180
for d in xrange(nb_dim):
181
v = u[:]
182
for k in xrange(v[d]+1, min(dim[d],v[d]+1+rook_radius)):
183
v[d] = k
184
G.add_edge( uu, tuple(v) )
185
186
if bishop or knight:
187
# We add edges to vertices we can reach when moving in two dimensions
188
for dx,dy in combin:
189
n = dim[dx]
190
m = dim[dy]
191
v = u[:]
192
i = u[dx]
193
j = u[dy]
194
195
if bishop:
196
# Diagonal
197
for k in xrange(1, min(n-i,m-j,bishop_radius+1)):
198
v[dx] = i+k
199
v[dy] = j+k
200
G.add_edge( uu, tuple(v) )
201
202
# Anti-diagonal
203
for k in xrange(min(i, m-j-1, bishop_radius)):
204
v[dx] = i-k-1
205
v[dy] = j+k+1
206
G.add_edge( uu, tuple(v) )
207
208
if knight:
209
# Moving knight_x in one dimension and knight_y in another
210
# dimension
211
if i+knight_y < n:
212
if j+knight_x < m:
213
v[dx] = i+knight_y
214
v[dy] = j+knight_x
215
G.add_edge( uu, tuple(v) )
216
if j-knight_x >= 0:
217
v[dx] = i+knight_y
218
v[dy] = j-knight_x
219
G.add_edge( uu, tuple(v) )
220
if j+knight_y < m:
221
if i+knight_x < n:
222
v[dx] = i+knight_x
223
v[dy] = j+knight_y
224
G.add_edge( uu, tuple(v) )
225
if i-knight_x >= 0:
226
v[dx] = i-knight_x
227
v[dy] = j+knight_y
228
G.add_edge( uu, tuple(v) )
229
230
if relabel:
231
G.relabel( inplace=True )
232
return G, dimstr
233
234
235
def QueenGraph(dim_list, radius=None, relabel=False):
236
r"""
237
Returns the `d`-dimensional Queen Graph with prescribed dimensions.
238
239
The 2-dimensional Queen Graph of parameters `n` and `m` is a graph with `nm`
240
vertices in which each vertex represents a square in an `n \times m`
241
chessboard, and each edge corresponds to a legal move by a queen.
242
243
The `d`-dimensional Queen Graph with `d >= 2` has for vertex set the cells
244
of a `d`-dimensional grid with prescribed dimensions, and each edge
245
corresponds to a legal move by a queen in either one or two dimensions.
246
247
All 2-dimensional Queen Graphs are Hamiltonian and biconnected. The
248
chromatic number of a `(n,n)`-Queen Graph is at least `n`, and it is exactly
249
`n` when `n\equiv 1,5 \bmod{6}`.
250
251
INPUTS:
252
253
- ``dim_list`` -- an iterable object (list, set, dict) providing the
254
dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.
255
256
- ``radius`` -- (default: ``None``) by setting the radius to a positive
257
integer, one may reduce the visibility of the queen to at most ``radius``
258
steps. When radius is 1, the resulting graph is a King Graph.
259
260
- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices
261
must be relabeled as integers.
262
263
EXAMPLES:
264
265
The `(2,2)`-Queen Graph is isomorphic to the complete graph on 4 vertices::
266
267
sage: G = graphs.QueenGraph( [2, 2] )
268
sage: G.is_isomorphic( graphs.CompleteGraph(4) )
269
True
270
271
The Queen Graph with radius 1 is isomorphic to the King Graph::
272
273
sage: G = graphs.QueenGraph( [4, 5], radius=1 )
274
sage: H = graphs.KingGraph( [5, 4] )
275
sage: G.is_isomorphic( H )
276
True
277
278
Also True in higher dimensions::
279
280
sage: G = graphs.QueenGraph( [3, 4, 5], radius=1 )
281
sage: H = graphs.KingGraph( [5, 3, 4] )
282
sage: G.is_isomorphic( H )
283
True
284
285
The Queen Graph can be obtained from the Rook Graph and the Bishop Graph::
286
287
sage: for d in xrange(3,12): # long time
288
....: for r in xrange(1,d+1):
289
....: G = graphs.QueenGraph([d,d],radius=r)
290
....: H = graphs.RookGraph([d,d],radius=r)
291
....: B = graphs.BishopGraph([d,d],radius=r)
292
....: H.add_edges(B.edges())
293
....: if not G.is_isomorphic(H):
294
....: print "that's not good!"
295
296
"""
297
G, dimstr = ChessboardGraphGenerator(dim_list,
298
rook=True, rook_radius=radius,
299
bishop=True, bishop_radius=radius,
300
knight=False,
301
relabel=relabel)
302
if radius is None:
303
G.name(dimstr+"-Queen Graph")
304
else:
305
G.name(dimstr+"-Queen Graph with radius "+str(radius))
306
return G
307
308
309
def KingGraph(dim_list, radius=None, relabel=False):
310
r"""
311
Returns the `d`-dimensional King Graph with prescribed dimensions.
312
313
The 2-dimensional King Graph of parameters `n` and `m` is a graph with `nm`
314
vertices in which each vertex represents a square in an `n \times m`
315
chessboard, and each edge corresponds to a legal move by a king.
316
317
The d-dimensional King Graph with `d >= 2` has for vertex set the cells of a
318
d-dimensional grid with prescribed dimensions, and each edge corresponds to
319
a legal move by a king in either one or two dimensions.
320
321
All 2-dimensional King Graphs are Hamiltonian, biconnected, and have
322
chromatic number 4 as soon as both dimensions are larger or equal to 2.
323
324
INPUTS:
325
326
- ``dim_list`` -- an iterable object (list, set, dict) providing the
327
dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.
328
329
- ``radius`` -- (default: ``None``) by setting the radius to a positive
330
integer, one may increase the power of the king to at least ``radius``
331
steps. When the radius equals the higher size of the dimensions, the
332
resulting graph is a Queen Graph.
333
334
- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices
335
must be relabeled as integers.
336
337
EXAMPLES:
338
339
The `(2,2)`-King Graph is isomorphic to the complete graph on 4 vertices::
340
341
sage: G = graphs.QueenGraph( [2, 2] )
342
sage: G.is_isomorphic( graphs.CompleteGraph(4) )
343
True
344
345
The King Graph with large enough radius is isomorphic to a Queen Graph::
346
347
sage: G = graphs.KingGraph( [5, 4], radius=5 )
348
sage: H = graphs.QueenGraph( [4, 5] )
349
sage: G.is_isomorphic( H )
350
True
351
352
Also True in higher dimensions::
353
354
sage: G = graphs.KingGraph( [2, 5, 4], radius=5 )
355
sage: H = graphs.QueenGraph( [4, 5, 2] )
356
sage: G.is_isomorphic( H )
357
True
358
"""
359
G, dimstr = ChessboardGraphGenerator(dim_list,
360
rook=True, rook_radius=(1 if radius is None else radius),
361
bishop=True, bishop_radius=(1 if radius is None else radius),
362
knight=False,
363
relabel=relabel)
364
if radius is None:
365
G.name(dimstr+"-King Graph")
366
else:
367
G.name(dimstr+"-King Graph with radius "+str(radius))
368
return G
369
370
371
def KnightGraph(dim_list, one=1, two=2, relabel=False):
372
r"""
373
Returns the d-dimensional Knight Graph with prescribed dimensions.
374
375
The 2-dimensional Knight Graph of parameters `n` and `m` is a graph with
376
`nm` vertices in which each vertex represents a square in an `n \times m`
377
chessboard, and each edge corresponds to a legal move by a knight.
378
379
The d-dimensional Knight Graph with `d >= 2` has for vertex set the cells of
380
a d-dimensional grid with prescribed dimensions, and each edge corresponds
381
to a legal move by a knight in any pairs of dimensions.
382
383
The `(n,n)`-Knight Graph is Hamiltonian for even `n > 4`.
384
385
INPUTS:
386
387
- ``dim_list`` -- an iterable object (list, set, dict) providing the
388
dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.
389
390
- ``one`` -- (default: ``1``) integer indicating the number on steps in one
391
dimension.
392
393
- ``two`` -- (default: ``2``) integer indicating the number on steps in the
394
second dimension.
395
396
- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices
397
must be relabeled as integers.
398
399
EXAMPLES:
400
401
The `(3,3)`-Knight Graph has an isolated vertex::
402
403
sage: G = graphs.KnightGraph( [3, 3] )
404
sage: G.degree( (1,1) )
405
0
406
407
The `(3,3)`-Knight Graph minus vertex (1,1) is a cycle of order 8::
408
409
sage: G = graphs.KnightGraph( [3, 3] )
410
sage: G.delete_vertex( (1,1) )
411
sage: G.is_isomorphic( graphs.CycleGraph(8) )
412
True
413
414
The `(6,6)`-Knight Graph is Hamiltonian::
415
416
sage: G = graphs.KnightGraph( [6, 6] )
417
sage: G.is_hamiltonian()
418
True
419
"""
420
G, dimstr = ChessboardGraphGenerator(dim_list,
421
rook=False, bishop=False,
422
knight=True, knight_x=one, knight_y=two,
423
relabel=relabel)
424
if one+two == 3:
425
G.name(dimstr+"-Knight Graph")
426
else:
427
G.name(dimstr+"-Knight Graph with edges at distance ("+str(one)+", "+str(two)+")")
428
return G
429
430
431
def RookGraph(dim_list, radius=None, relabel=False):
432
r"""
433
Returns the `d`-dimensional Rook's Graph with prescribed dimensions.
434
435
The 2-dimensional Rook's Graph of parameters `n` and `m` is a graph with
436
`nm` vertices in which each vertex represents a square in an `n \times m`
437
chessboard, and each edge corresponds to a legal move by a rook.
438
439
The `d`-dimensional Rook Graph with `d >= 2` has for vertex set the cells of
440
a `d`-dimensional grid with prescribed dimensions, and each edge corresponds
441
to a legal move by a rook in any of the dimensions.
442
443
The Rook's Graph for an `n\times m` chessboard may also be defined as the
444
Cartesian product of two complete graphs `K_n \square K_m`.
445
446
INPUTS:
447
448
- ``dim_list`` -- an iterable object (list, set, dict) providing the
449
dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.
450
451
- ``radius`` -- (default: ``None``) by setting the radius to a positive
452
integer, one may decrease the power of the rook to at most ``radius``
453
steps. When the radius is 1, the resulting graph is a d-dimensional grid.
454
455
- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices
456
must be relabeled as integers.
457
458
EXAMPLES:
459
460
The `(n,m)`-Rook's Graph is isomorphic to the cartesian product of two
461
complete graphs::
462
463
sage: G = graphs.RookGraph( [3, 4] )
464
sage: H = ( graphs.CompleteGraph(3) ).cartesian_product( graphs.CompleteGraph(4) )
465
sage: G.is_isomorphic( H )
466
True
467
468
When the radius is 1, the Rook's Graph is a grid::
469
470
sage: G = graphs.RookGraph( [3, 3, 4], radius=1 )
471
sage: H = graphs.GridGraph( [3, 4, 3] )
472
sage: G.is_isomorphic( H )
473
True
474
"""
475
G, dimstr = ChessboardGraphGenerator(dim_list,
476
rook=True, rook_radius=radius,
477
bishop=False, knight=False,
478
relabel=relabel)
479
if radius is None:
480
G.name(dimstr+"-Rook Graph")
481
else:
482
G.name(dimstr+"-Rook Graph with radius "+str(radius))
483
return G
484
485
486
def BishopGraph(dim_list, radius=None, relabel=False):
487
r"""
488
Returns the `d`-dimensional Bishop Graph with prescribed dimensions.
489
490
The 2-dimensional Bishop Graph of parameters `n` and `m` is a graph with
491
`nm` vertices in which each vertex represents a square in an `n \times m`
492
chessboard, and each edge corresponds to a legal move by a bishop.
493
494
The `d`-dimensional Bishop Graph with `d >= 2` has for vertex set the cells
495
of a `d`-dimensional grid with prescribed dimensions, and each edge
496
corresponds to a legal move by a bishop in any pairs of dimensions.
497
498
The Bishop Graph is not connected.
499
500
INPUTS:
501
502
- ``dim_list`` -- an iterable object (list, set, dict) providing the
503
dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.
504
505
- ``radius`` -- (default: ``None``) by setting the radius to a positive
506
integer, one may decrease the power of the bishop to at most ``radius``
507
steps.
508
509
- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices
510
must be relabeled as integers.
511
512
EXAMPLES:
513
514
The (n,m)-Bishop Graph is not connected::
515
516
sage: G = graphs.BishopGraph( [3, 4] )
517
sage: G.is_connected()
518
False
519
520
The Bishop Graph can be obtained from Knight Graphs::
521
522
sage: for d in xrange(3,12): # long time
523
....: H = Graph()
524
....: for r in xrange(1,d+1):
525
....: B = graphs.BishopGraph([d,d],radius=r)
526
....: H.add_edges( graphs.KnightGraph([d,d],one=r,two=r).edges() )
527
....: if not B.is_isomorphic(H):
528
....: print "that's not good!"
529
530
"""
531
G, dimstr = ChessboardGraphGenerator(dim_list,
532
rook=False, knight=False,
533
bishop=True, bishop_radius=radius,
534
relabel=relabel)
535
if radius is None:
536
G.name(dimstr+"-Bishop Graph")
537
else:
538
G.name(dimstr+"-Bishop Graph with radius "+str(radius))
539
return G
540
541