Path: blob/master/src/sage/graphs/generators/chessboard.py
8817 views
# -*- coding: utf-8 -*-1r"""2Chessboard Graphs34The methods defined here appear in :mod:`sage.graphs.graph_generators`.56- :meth:`BishopGraph <GraphGenerators.BishopGraph>`7- :meth:`KingGraph <GraphGenerators.KingGraph>`8- :meth:`KnightGraph <GraphGenerators.KnightGraph>`9- :meth:`QueenGraph <GraphGenerators.QueenGraph>`10- :meth:`RookGraph <GraphGenerators.RookGraph>`1112AUTHORS:1314- David Coudert (2012)15"""1617################################################################################18# Copyright (C) 2012 David Coudert <[email protected]>19#20# Distributed under the terms of the GNU General Public License (GPL)21# http://www.gnu.org/licenses/22################################################################################2324def ChessboardGraphGenerator(dim_list,25rook = True, rook_radius = None,26bishop = True, bishop_radius = None,27knight = True, knight_x = 1, knight_y = 2,28relabel = False):29r"""30Returns a Graph built on a `d`-dimensional chessboard with prescribed31dimensions and interconnections.3233This function allows to generate many kinds of graphs corresponding to legal34movements on a `d`-dimensional chessboard: Queen Graph, King Graph, Knight35Graphs, Bishop Graph, and many generalizations. It also allows to avoid36redondant code.3738INPUTS:3940- ``dim_list`` -- an iterable object (list, set, dict) providing the41dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.4243- ``rook`` -- (default: ``True``) boolean value indicating if the chess44piece is able to move as a rook, that is at any distance along a45dimension.4647- ``rook_radius`` -- (default: None) integer value restricting the rook-like48movements to distance at most `rook_radius`.4950- ``bishop`` -- (default: ``True``) boolean value indicating if the chess51piece is able to move like a bishop, that is along diagonals.5253- ``bishop_radius`` -- (default: None) integer value restricting the54bishop-like movements to distance at most `bishop_radius`.5556- ``knight`` -- (default: ``True``) boolean value indicating if the chess57piece is able to move like a knight.5859- ``knight_x`` -- (default: 1) integer indicating the number on steps the60chess piece moves in one dimension when moving like a knight.6162- ``knight_y`` -- (default: 2) integer indicating the number on steps the63chess piece moves in the second dimension when moving like a knight.6465- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices66must be relabeled as integers.6768OUTPUTS:6970- A Graph build on a `d`-dimensional chessboard with prescribed dimensions,71and with edges according given parameters.7273- A string encoding the dimensions. This is mainly useful for providing74names to graphs.7576EXAMPLES:7778A `(2,2)`-King Graph is isomorphic to the complete graph on 4 vertices::7980sage: G, _ = graphs.ChessboardGraphGenerator( [2,2] )81sage: G.is_isomorphic( graphs.CompleteGraph(4) )82True8384A Rook's Graph in 2 dimensions is isomporphic to the cartesian product of 285complete graphs::8687sage: G, _ = graphs.ChessboardGraphGenerator( [3,4], rook=True, rook_radius=None, bishop=False, knight=False )88sage: H = ( graphs.CompleteGraph(3) ).cartesian_product( graphs.CompleteGraph(4) )89sage: G.is_isomorphic(H)90True9192TESTS:9394Giving dimensions less than 2::9596sage: graphs.ChessboardGraphGenerator( [0, 2] )97Traceback (most recent call last):98...99ValueError: The dimensions must be positive integers larger than 1.100101Giving non integer dimensions::102103sage: graphs.ChessboardGraphGenerator( [4.5, 2] )104Traceback (most recent call last):105...106ValueError: The dimensions must be positive integers larger than 1.107108Giving too few dimensions::109110sage: graphs.ChessboardGraphGenerator( [2] )111Traceback (most recent call last):112...113ValueError: The chessboard must have at least 2 dimensions.114115Giving a non-iterable object as first parameter::116117sage: graphs.ChessboardGraphGenerator( 2, 3 )118Traceback (most recent call last):119...120TypeError: The first parameter must be an iterable object.121122Giving too small rook radius::123124sage: graphs.ChessboardGraphGenerator( [2, 3], rook=True, rook_radius=0 )125Traceback (most recent call last):126...127ValueError: The rook_radius must be either None or have an integer value >= 1.128129Giving wrong values for knights movements::130131sage: graphs.ChessboardGraphGenerator( [2, 3], rook=False, bishop=False, knight=True, knight_x=1, knight_y=-1 )132Traceback (most recent call last):133...134ValueError: The knight_x and knight_y values must be integers of value >= 1.135"""136from sage.rings.integer_ring import ZZ137138# We decode the dimensions of the chessboard139try:140dim = list(dim_list)141nb_dim = len(dim)142except TypeError:143raise TypeError('The first parameter must be an iterable object.')144if nb_dim < 2:145raise ValueError('The chessboard must have at least 2 dimensions.')146if any(a not in ZZ or a < 1 for a in dim):147raise ValueError('The dimensions must be positive integers larger than 1.')148dimstr = str(tuple(dim))149150# We check the radius toward neighbors151if rook:152if rook_radius is None:153rook_radius = max(dim)154elif not rook_radius in ZZ or rook_radius < 1:155raise ValueError('The rook_radius must be either None or have an integer value >= 1.')156if bishop:157if bishop_radius is None:158bishop_radius = max(dim)159elif not bishop_radius in ZZ or bishop_radius < 1:160raise ValueError('The bishop_radius must be either None or have an integer value >= 1.')161if knight and ( not knight_x in ZZ or not knight_y in ZZ or knight_x < 1 or knight_y < 1 ):162raise ValueError('The knight_x and knight_y values must be integers of value >= 1.')163164# We build the set of vertices of the d-dimensionnal chessboard165from itertools import product166V = map(list,list(product(*map(range,dim))))167168from sage.combinat.combination import Combinations169combin = Combinations(range(nb_dim),2)170171from sage.graphs.graph import Graph172G = Graph()173for u in V:174uu = tuple(u)175G.add_vertex(uu)176177if rook:178# We add edges to vertices we can reach when moving in one dimension179for d in xrange(nb_dim):180v = u[:]181for k in xrange(v[d]+1, min(dim[d],v[d]+1+rook_radius)):182v[d] = k183G.add_edge( uu, tuple(v) )184185if bishop or knight:186# We add edges to vertices we can reach when moving in two dimensions187for dx,dy in combin:188n = dim[dx]189m = dim[dy]190v = u[:]191i = u[dx]192j = u[dy]193194if bishop:195# Diagonal196for k in xrange(1, min(n-i,m-j,bishop_radius+1)):197v[dx] = i+k198v[dy] = j+k199G.add_edge( uu, tuple(v) )200201# Anti-diagonal202for k in xrange(min(i, m-j-1, bishop_radius)):203v[dx] = i-k-1204v[dy] = j+k+1205G.add_edge( uu, tuple(v) )206207if knight:208# Moving knight_x in one dimension and knight_y in another209# dimension210if i+knight_y < n:211if j+knight_x < m:212v[dx] = i+knight_y213v[dy] = j+knight_x214G.add_edge( uu, tuple(v) )215if j-knight_x >= 0:216v[dx] = i+knight_y217v[dy] = j-knight_x218G.add_edge( uu, tuple(v) )219if j+knight_y < m:220if i+knight_x < n:221v[dx] = i+knight_x222v[dy] = j+knight_y223G.add_edge( uu, tuple(v) )224if i-knight_x >= 0:225v[dx] = i-knight_x226v[dy] = j+knight_y227G.add_edge( uu, tuple(v) )228229if relabel:230G.relabel( inplace=True )231return G, dimstr232233234def QueenGraph(dim_list, radius=None, relabel=False):235r"""236Returns the `d`-dimensional Queen Graph with prescribed dimensions.237238The 2-dimensional Queen Graph of parameters `n` and `m` is a graph with `nm`239vertices in which each vertex represents a square in an `n \times m`240chessboard, and each edge corresponds to a legal move by a queen.241242The `d`-dimensional Queen Graph with `d >= 2` has for vertex set the cells243of a `d`-dimensional grid with prescribed dimensions, and each edge244corresponds to a legal move by a queen in either one or two dimensions.245246All 2-dimensional Queen Graphs are Hamiltonian and biconnected. The247chromatic number of a `(n,n)`-Queen Graph is at least `n`, and it is exactly248`n` when `n\equiv 1,5 \bmod{6}`.249250INPUTS:251252- ``dim_list`` -- an iterable object (list, set, dict) providing the253dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.254255- ``radius`` -- (default: ``None``) by setting the radius to a positive256integer, one may reduce the visibility of the queen to at most ``radius``257steps. When radius is 1, the resulting graph is a King Graph.258259- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices260must be relabeled as integers.261262EXAMPLES:263264The `(2,2)`-Queen Graph is isomorphic to the complete graph on 4 vertices::265266sage: G = graphs.QueenGraph( [2, 2] )267sage: G.is_isomorphic( graphs.CompleteGraph(4) )268True269270The Queen Graph with radius 1 is isomorphic to the King Graph::271272sage: G = graphs.QueenGraph( [4, 5], radius=1 )273sage: H = graphs.KingGraph( [5, 4] )274sage: G.is_isomorphic( H )275True276277Also True in higher dimensions::278279sage: G = graphs.QueenGraph( [3, 4, 5], radius=1 )280sage: H = graphs.KingGraph( [5, 3, 4] )281sage: G.is_isomorphic( H )282True283284The Queen Graph can be obtained from the Rook Graph and the Bishop Graph::285286sage: for d in xrange(3,12): # long time287....: for r in xrange(1,d+1):288....: G = graphs.QueenGraph([d,d],radius=r)289....: H = graphs.RookGraph([d,d],radius=r)290....: B = graphs.BishopGraph([d,d],radius=r)291....: H.add_edges(B.edges())292....: if not G.is_isomorphic(H):293....: print "that's not good!"294295"""296G, dimstr = ChessboardGraphGenerator(dim_list,297rook=True, rook_radius=radius,298bishop=True, bishop_radius=radius,299knight=False,300relabel=relabel)301if radius is None:302G.name(dimstr+"-Queen Graph")303else:304G.name(dimstr+"-Queen Graph with radius "+str(radius))305return G306307308def KingGraph(dim_list, radius=None, relabel=False):309r"""310Returns the `d`-dimensional King Graph with prescribed dimensions.311312The 2-dimensional King Graph of parameters `n` and `m` is a graph with `nm`313vertices in which each vertex represents a square in an `n \times m`314chessboard, and each edge corresponds to a legal move by a king.315316The d-dimensional King Graph with `d >= 2` has for vertex set the cells of a317d-dimensional grid with prescribed dimensions, and each edge corresponds to318a legal move by a king in either one or two dimensions.319320All 2-dimensional King Graphs are Hamiltonian, biconnected, and have321chromatic number 4 as soon as both dimensions are larger or equal to 2.322323INPUTS:324325- ``dim_list`` -- an iterable object (list, set, dict) providing the326dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.327328- ``radius`` -- (default: ``None``) by setting the radius to a positive329integer, one may increase the power of the king to at least ``radius``330steps. When the radius equals the higher size of the dimensions, the331resulting graph is a Queen Graph.332333- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices334must be relabeled as integers.335336EXAMPLES:337338The `(2,2)`-King Graph is isomorphic to the complete graph on 4 vertices::339340sage: G = graphs.QueenGraph( [2, 2] )341sage: G.is_isomorphic( graphs.CompleteGraph(4) )342True343344The King Graph with large enough radius is isomorphic to a Queen Graph::345346sage: G = graphs.KingGraph( [5, 4], radius=5 )347sage: H = graphs.QueenGraph( [4, 5] )348sage: G.is_isomorphic( H )349True350351Also True in higher dimensions::352353sage: G = graphs.KingGraph( [2, 5, 4], radius=5 )354sage: H = graphs.QueenGraph( [4, 5, 2] )355sage: G.is_isomorphic( H )356True357"""358G, dimstr = ChessboardGraphGenerator(dim_list,359rook=True, rook_radius=(1 if radius is None else radius),360bishop=True, bishop_radius=(1 if radius is None else radius),361knight=False,362relabel=relabel)363if radius is None:364G.name(dimstr+"-King Graph")365else:366G.name(dimstr+"-King Graph with radius "+str(radius))367return G368369370def KnightGraph(dim_list, one=1, two=2, relabel=False):371r"""372Returns the d-dimensional Knight Graph with prescribed dimensions.373374The 2-dimensional Knight Graph of parameters `n` and `m` is a graph with375`nm` vertices in which each vertex represents a square in an `n \times m`376chessboard, and each edge corresponds to a legal move by a knight.377378The d-dimensional Knight Graph with `d >= 2` has for vertex set the cells of379a d-dimensional grid with prescribed dimensions, and each edge corresponds380to a legal move by a knight in any pairs of dimensions.381382The `(n,n)`-Knight Graph is Hamiltonian for even `n > 4`.383384INPUTS:385386- ``dim_list`` -- an iterable object (list, set, dict) providing the387dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.388389- ``one`` -- (default: ``1``) integer indicating the number on steps in one390dimension.391392- ``two`` -- (default: ``2``) integer indicating the number on steps in the393second dimension.394395- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices396must be relabeled as integers.397398EXAMPLES:399400The `(3,3)`-Knight Graph has an isolated vertex::401402sage: G = graphs.KnightGraph( [3, 3] )403sage: G.degree( (1,1) )4040405406The `(3,3)`-Knight Graph minus vertex (1,1) is a cycle of order 8::407408sage: G = graphs.KnightGraph( [3, 3] )409sage: G.delete_vertex( (1,1) )410sage: G.is_isomorphic( graphs.CycleGraph(8) )411True412413The `(6,6)`-Knight Graph is Hamiltonian::414415sage: G = graphs.KnightGraph( [6, 6] )416sage: G.is_hamiltonian()417True418"""419G, dimstr = ChessboardGraphGenerator(dim_list,420rook=False, bishop=False,421knight=True, knight_x=one, knight_y=two,422relabel=relabel)423if one+two == 3:424G.name(dimstr+"-Knight Graph")425else:426G.name(dimstr+"-Knight Graph with edges at distance ("+str(one)+", "+str(two)+")")427return G428429430def RookGraph(dim_list, radius=None, relabel=False):431r"""432Returns the `d`-dimensional Rook's Graph with prescribed dimensions.433434The 2-dimensional Rook's Graph of parameters `n` and `m` is a graph with435`nm` vertices in which each vertex represents a square in an `n \times m`436chessboard, and each edge corresponds to a legal move by a rook.437438The `d`-dimensional Rook Graph with `d >= 2` has for vertex set the cells of439a `d`-dimensional grid with prescribed dimensions, and each edge corresponds440to a legal move by a rook in any of the dimensions.441442The Rook's Graph for an `n\times m` chessboard may also be defined as the443Cartesian product of two complete graphs `K_n \square K_m`.444445INPUTS:446447- ``dim_list`` -- an iterable object (list, set, dict) providing the448dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.449450- ``radius`` -- (default: ``None``) by setting the radius to a positive451integer, one may decrease the power of the rook to at most ``radius``452steps. When the radius is 1, the resulting graph is a d-dimensional grid.453454- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices455must be relabeled as integers.456457EXAMPLES:458459The `(n,m)`-Rook's Graph is isomorphic to the cartesian product of two460complete graphs::461462sage: G = graphs.RookGraph( [3, 4] )463sage: H = ( graphs.CompleteGraph(3) ).cartesian_product( graphs.CompleteGraph(4) )464sage: G.is_isomorphic( H )465True466467When the radius is 1, the Rook's Graph is a grid::468469sage: G = graphs.RookGraph( [3, 3, 4], radius=1 )470sage: H = graphs.GridGraph( [3, 4, 3] )471sage: G.is_isomorphic( H )472True473"""474G, dimstr = ChessboardGraphGenerator(dim_list,475rook=True, rook_radius=radius,476bishop=False, knight=False,477relabel=relabel)478if radius is None:479G.name(dimstr+"-Rook Graph")480else:481G.name(dimstr+"-Rook Graph with radius "+str(radius))482return G483484485def BishopGraph(dim_list, radius=None, relabel=False):486r"""487Returns the `d`-dimensional Bishop Graph with prescribed dimensions.488489The 2-dimensional Bishop Graph of parameters `n` and `m` is a graph with490`nm` vertices in which each vertex represents a square in an `n \times m`491chessboard, and each edge corresponds to a legal move by a bishop.492493The `d`-dimensional Bishop Graph with `d >= 2` has for vertex set the cells494of a `d`-dimensional grid with prescribed dimensions, and each edge495corresponds to a legal move by a bishop in any pairs of dimensions.496497The Bishop Graph is not connected.498499INPUTS:500501- ``dim_list`` -- an iterable object (list, set, dict) providing the502dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.503504- ``radius`` -- (default: ``None``) by setting the radius to a positive505integer, one may decrease the power of the bishop to at most ``radius``506steps.507508- ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices509must be relabeled as integers.510511EXAMPLES:512513The (n,m)-Bishop Graph is not connected::514515sage: G = graphs.BishopGraph( [3, 4] )516sage: G.is_connected()517False518519The Bishop Graph can be obtained from Knight Graphs::520521sage: for d in xrange(3,12): # long time522....: H = Graph()523....: for r in xrange(1,d+1):524....: B = graphs.BishopGraph([d,d],radius=r)525....: H.add_edges( graphs.KnightGraph([d,d],one=r,two=r).edges() )526....: if not B.is_isomorphic(H):527....: print "that's not good!"528529"""530G, dimstr = ChessboardGraphGenerator(dim_list,531rook=False, knight=False,532bishop=True, bishop_radius=radius,533relabel=relabel)534if radius is None:535G.name(dimstr+"-Bishop Graph")536else:537G.name(dimstr+"-Bishop Graph with radius "+str(radius))538return G539540541