Path: blob/master/src/sage/graphs/digraph_generators.py
8815 views
r"""1Common Digraphs23Generators for common digraphs.45.. csv-table::6:class: contentstable7:widths: 30, 708:delim: |910:meth:`~DiGraphGenerators.ButterflyGraph` | Returns a n-dimensional butterfly graph.11:meth:`~DiGraphGenerators.Circuit` | Returns the circuit on `n` vertices.12:meth:`~DiGraphGenerators.Circulant` | Returns a circulant digraph on `n` vertices from a set of integers.13:meth:`~DiGraphGenerators.DeBruijn` | Returns the De Bruijn digraph with parameters `k,n`.14:meth:`~DiGraphGenerators.GeneralizedDeBruijn` | Returns the generalized de Bruijn digraph of order `n` and degree `d`.15:meth:`~DiGraphGenerators.ImaseItoh` | Returns the digraph of Imase and Itoh of order `n` and degree `d`.16:meth:`~DiGraphGenerators.Kautz` | Returns the Kautz digraph of degree `d` and diameter `D`.17:meth:`~DiGraphGenerators.Path` | Returns a directed path on `n` vertices.18:meth:`~DiGraphGenerators.RandomDirectedGNC` | Returns a random GNC (growing network with copying) digraph with `n` vertices.19:meth:`~DiGraphGenerators.RandomDirectedGNM` | Returns a random labelled digraph on `n` nodes and `m` arcs.20:meth:`~DiGraphGenerators.RandomDirectedGNP` | Returns a random digraph on `n` nodes.21:meth:`~DiGraphGenerators.RandomDirectedGN` | Returns a random GN (growing network) digraph with `n` vertices.22:meth:`~DiGraphGenerators.RandomDirectedGNR` | Returns a random GNR (growing network with redirection) digraph.23:meth:`~DiGraphGenerators.RandomTournament` | Returns a random tournament on `n` vertices.24:meth:`~DiGraphGenerators.TransitiveTournament`| Returns a transitive tournament on `n` vertices.25:meth:`~DiGraphGenerators.tournaments_nauty` | Returns all tournaments on `n` vertices using Nauty.2627AUTHORS:2829- Robert L. Miller (2006)30- Emily A. Kirkman (2006)31- Michael C. Yurko (2009)32- David Coudert (2012)3334Functions and methods35---------------------3637"""3839################################################################################40# Copyright (C) 2006 Robert L. Miller <[email protected]>41# and Emily A. Kirkman42# Copyright (C) 2009 Michael C. Yurko <[email protected]>43#44# Distributed under the terms of the GNU General Public License (GPL)45# http://www.gnu.org/licenses/46################################################################################4748from math import sin, cos, pi49from sage.misc.randstate import current_randstate50from sage.graphs.digraph import DiGraph515253class DiGraphGenerators():54r"""55A class consisting of constructors for several common digraphs,56including orderly generation of isomorphism class representatives.5758A list of all graphs and graph structures in this database is59available via tab completion. Type "digraphs." and then hit tab to60see which graphs are available.6162The docstrings include educational information about each named63digraph with the hopes that this class can be used as a reference.6465The constructors currently in this class include::6667Random Directed Graphs:68- RandomDirectedGN69- RandomDirectedGNC70- RandomDirectedGNP71- RandomDirectedGNM72- RandomDirectedGNR7374Families of Graphs:75- DeBruijn76- GeneralizedDeBruijn77- Kautz78- Path79- ImaseItoh80- RandomTournament81- TransitiveTournament82- tournaments_nauty83848586ORDERLY GENERATION: digraphs(vertices, property=lambda x: True,87augment='edges', size=None)8889Accesses the generator of isomorphism class representatives.90Iterates over distinct, exhaustive representatives.9192INPUT:939495- ``vertices`` - natural number9697- ``property`` - any property to be tested on digraphs98before generation.99100- ``augment`` - choices:101102- ``'vertices'`` - augments by adding a vertex, and103edges incident to that vertex. In this case, all digraphs on up to104n=vertices are generated. If for any digraph G satisfying the105property, every subgraph, obtained from G by deleting one vertex106and only edges incident to that vertex, satisfies the property,107then this will generate all digraphs with that property. If this108does not hold, then all the digraphs generated will satisfy the109property, but there will be some missing.110111- ``'edges'`` - augments a fixed number of vertices by112adding one edge In this case, all digraphs on exactly n=vertices113are generated. If for any graph G satisfying the property, every114subgraph, obtained from G by deleting one edge but not the vertices115incident to that edge, satisfies the property, then this will116generate all digraphs with that property. If this does not hold,117then all the digraphs generated will satisfy the property, but118there will be some missing.119120- ``implementation`` - which underlying implementation to use (see DiGraph?)121122- ``sparse`` - ignored if implementation is not ``c_graph``123124EXAMPLES: Print digraphs on 2 or less vertices.125126::127128sage: for D in digraphs(2, augment='vertices'):129... print D130...131Digraph on 0 vertices132Digraph on 1 vertex133Digraph on 2 vertices134Digraph on 2 vertices135Digraph on 2 vertices136137Note that we can also get digraphs with underlying Cython implementation::138139sage: for D in digraphs(2, augment='vertices', implementation='c_graph'):140... print D141...142Digraph on 0 vertices143Digraph on 1 vertex144Digraph on 2 vertices145Digraph on 2 vertices146Digraph on 2 vertices147148Print digraphs on 3 vertices.149150::151152sage: for D in digraphs(3):153... print D154Digraph on 3 vertices155Digraph on 3 vertices156...157Digraph on 3 vertices158Digraph on 3 vertices159160Generate all digraphs with 4 vertices and 3 edges.161162::163164sage: L = digraphs(4, size=3)165sage: len(list(L))16613167168Generate all digraphs with 4 vertices and up to 3 edges.169170::171172sage: L = list(digraphs(4, lambda G: G.size() <= 3))173sage: len(L)17420175sage: graphs_list.show_graphs(L) # long time176177Generate all digraphs with degree at most 2, up to 5 vertices.178179::180181sage: property = lambda G: ( max([G.degree(v) for v in G] + [0]) <= 2 )182sage: L = list(digraphs(5, property, augment='vertices'))183sage: len(L)18475185186Generate digraphs on the fly: (see http://oeis.org/classic/A000273)187188::189190sage: for i in range(0, 5):191... print len(list(digraphs(i)))19211931194319516196218197198REFERENCE:199200- Brendan D. McKay, Isomorph-Free Exhaustive generation. Journal201of Algorithms Volume 26, Issue 2, February 1998, pages 306-324.202"""203204def ButterflyGraph(self, n, vertices='strings'):205"""206Returns a n-dimensional butterfly graph. The vertices consist of207pairs (v,i), where v is an n-dimensional tuple (vector) with binary208entries (or a string representation of such) and i is an integer in209[0..n]. A directed edge goes from (v,i) to (w,i+1) if v and w are210identical except for possibly v[i] != w[i].211212A butterfly graph has `(2^n)(n+1)` vertices and213`n2^{n+1}` edges.214215INPUT:216217218- ``vertices`` - 'strings' (default) or 'vectors',219specifying whether the vertices are zero-one strings or actually220tuples over GF(2).221222223EXAMPLES::224225sage: digraphs.ButterflyGraph(2).edges(labels=False)226[(('00', 0), ('00', 1)),227(('00', 0), ('10', 1)),228(('00', 1), ('00', 2)),229(('00', 1), ('01', 2)),230(('01', 0), ('01', 1)),231(('01', 0), ('11', 1)),232(('01', 1), ('00', 2)),233(('01', 1), ('01', 2)),234(('10', 0), ('00', 1)),235(('10', 0), ('10', 1)),236(('10', 1), ('10', 2)),237(('10', 1), ('11', 2)),238(('11', 0), ('01', 1)),239(('11', 0), ('11', 1)),240(('11', 1), ('10', 2)),241(('11', 1), ('11', 2))]242sage: digraphs.ButterflyGraph(2,vertices='vectors').edges(labels=False)243[(((0, 0), 0), ((0, 0), 1)),244(((0, 0), 0), ((1, 0), 1)),245(((0, 0), 1), ((0, 0), 2)),246(((0, 0), 1), ((0, 1), 2)),247(((0, 1), 0), ((0, 1), 1)),248(((0, 1), 0), ((1, 1), 1)),249(((0, 1), 1), ((0, 0), 2)),250(((0, 1), 1), ((0, 1), 2)),251(((1, 0), 0), ((0, 0), 1)),252(((1, 0), 0), ((1, 0), 1)),253(((1, 0), 1), ((1, 0), 2)),254(((1, 0), 1), ((1, 1), 2)),255(((1, 1), 0), ((0, 1), 1)),256(((1, 1), 0), ((1, 1), 1)),257(((1, 1), 1), ((1, 0), 2)),258(((1, 1), 1), ((1, 1), 2))]259"""260# We could switch to Sage integers to handle arbitrary n.261if vertices=='strings':262if n>=31:263raise NotImplementedError, "vertices='strings' is only valid for n<=30."264from sage.graphs.generic_graph_pyx import binary265butterfly = {}266for v in xrange(2**n):267for i in range(n):268w = v269w ^= (1 << i) # push 1 to the left by i and xor with w270bv = binary(v)271bw = binary(w)272# pad and reverse the strings273padded_bv = ('0'*(n-len(bv))+bv)[::-1]274padded_bw = ('0'*(n-len(bw))+bw)[::-1]275butterfly[(padded_bv,i)]=[(padded_bv,i+1), (padded_bw,i+1)]276elif vertices=='vectors':277from sage.modules.free_module import VectorSpace278from sage.rings.finite_rings.constructor import FiniteField279from copy import copy280butterfly = {}281for v in VectorSpace(FiniteField(2),n):282for i in xrange(n):283w=copy(v)284w[i] += 1 # Flip the ith bit285# We must call tuple since vectors are mutable. To obtain286# a vector from the tuple t, just call vector(t).287butterfly[(tuple(v),i)]=[(tuple(v),i+1), (tuple(w),i+1)]288else:289raise NotImplementedError, "vertices must be 'strings' or 'vectors'."290return DiGraph(butterfly)291292def Path(self,n):293r"""294Returns a directed path on `n` vertices.295296INPUT:297298- ``n`` (integer) -- number of vertices in the path.299300EXAMPLES::301302sage: g = digraphs.Path(5)303sage: g.vertices()304[0, 1, 2, 3, 4]305sage: g.size()3064307sage: g.automorphism_group().cardinality()3081309"""310g = DiGraph(n)311g.name("Path")312313if n:314g.add_path(range(n))315316g.set_pos({i:(i,0) for i in range(n)})317return g318319def TransitiveTournament(self, n):320r"""321Returns a transitive tournament on `n` vertices.322323In this tournament there is an edge from `i` to `j` if `i<j`.324325See :wikipedia:`Tournament_(graph_theory)`326327INPUT:328329- ``n`` (integer) -- number of vertices in the tournament.330331EXAMPLES::332333sage: g = digraphs.TransitiveTournament(5)334sage: g.vertices()335[0, 1, 2, 3, 4]336sage: g.size()33710338sage: g.automorphism_group().cardinality()3391340341TESTS::342343sage: digraphs.TransitiveTournament(-1)344Traceback (most recent call last):345...346ValueError: The number of vertices cannot be strictly negative!347"""348g = DiGraph(n)349g.name("Transitive Tournament")350351for i in range(n-1):352for j in range(i+1, n):353g.add_edge(i, j)354355if n:356from sage.graphs.graph_plot import _circle_embedding357_circle_embedding(g, range(n))358359return g360361def RandomTournament(self, n):362r"""363Returns a random tournament on `n` vertices.364365For every pair of vertices, the tournament has an edge from366`i` to `j` with probability `1/2`, otherwise it has an edge367from `j` to `i`.368369See :wikipedia:`Tournament_(graph_theory)`370371INPUT:372373- ``n`` (integer) -- number of vertices.374375EXAMPLES::376377sage: T = digraphs.RandomTournament(10); T378Random Tournament: Digraph on 10 vertices379sage: T.size() == binomial(10, 2)380True381sage: digraphs.RandomTournament(-1)382Traceback (most recent call last):383...384ValueError: The number of vertices cannot be strictly negative!385"""386from sage.misc.prandom import random387g = DiGraph(n)388g.name("Random Tournament")389390for i in range(n-1):391for j in range(i+1, n):392if random() <= .5:393g.add_edge(i, j)394else:395g.add_edge(j, i)396397if n:398from sage.graphs.graph_plot import _circle_embedding399_circle_embedding(g, range(n))400401return g402403def tournaments_nauty(self, n,404min_out_degree = None, max_out_degree = None,405strongly_connected = False, debug=False, options=""):406r"""407Returns all tournaments on `n` vertices using Nauty.408409INPUT:410411- ``n`` (integer) -- number of vertices.412413- ``min_out_degree``, ``max_out_degree`` (integers) -- if set to414``None`` (default), then the min/max out-degree is not constrained.415416- ``debug`` (boolean) -- if ``True`` the first line of genbg's output to417standard error is captured and the first call to the generator's418``next()`` function will return this line as a string. A line leading419with ">A" indicates a successful initiation of the program with some420information on the arguments, while a line beginning with ">E"421indicates an error with the input.422423- ``options`` (string) -- anything else that should be forwarded as424input to Nauty's genbg. See its documentation for more information :425`<http://cs.anu.edu.au/~bdm/nauty/>`_.426427428.. NOTE::429430To use this method you must first install the Nauty spkg.431432EXAMPLES::433434sage: for g in digraphs.tournaments_nauty(4): # optional - nauty435....: print g.edges(labels = False) # optional - nauty436[(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)]437[(1, 0), (1, 3), (2, 0), (2, 1), (3, 0), (3, 2)]438[(0, 2), (1, 0), (2, 1), (3, 0), (3, 1), (3, 2)]439[(0, 2), (0, 3), (1, 0), (2, 1), (3, 1), (3, 2)]440sage: tournaments = digraphs.tournaments_nauty441sage: [len(list(tournaments(x))) for x in range(1,8)] # optional - nauty442[1, 1, 2, 4, 12, 56, 456]443sage: [len(list(tournaments(x, strongly_connected = True))) for x in range(1,9)] # optional - nauty444[1, 0, 1, 1, 6, 35, 353, 6008]445"""446import subprocess447from sage.misc.package import is_package_installed448if not is_package_installed("nauty"):449raise TypeError("The optional nauty spkg does not seem to be installed")450451nauty_input = options452453if min_out_degree is None:454min_out_degree = 0455if max_out_degree is None:456max_out_degree = n-1457458nauty_input += " -d"+str(min_out_degree)459nauty_input += " -D"+str(max_out_degree)460461if strongly_connected:462nauty_input += " -c"463464nauty_input += " "+str(n) +" "465466sp = subprocess.Popen("nauty-gentourng {0}".format(nauty_input), shell=True,467stdin=subprocess.PIPE, stdout=subprocess.PIPE,468stderr=subprocess.PIPE, close_fds=True)469470if debug:471yield sp.stderr.readline()472473gen = sp.stdout474while True:475try:476s = gen.next()477except StopIteration:478raise StopIteration("Exhausted list of graphs from nauty geng")479480G = DiGraph(n)481i = 0482j = 1483for b in s[:-1]:484if b == '0':485G.add_edge(i,j)486else:487G.add_edge(j,i)488489if j == n-1:490i += 1491j = i+1492else:493j += 1494495yield G496497def Circuit(self,n):498r"""499Returns the circuit on `n` vertices500501The circuit is an oriented ``CycleGraph``502503EXAMPLE:504505A circuit is the smallest strongly connected digraph::506507sage: circuit = digraphs.Circuit(15)508sage: len(circuit.strongly_connected_components()) == 1509True510"""511g = DiGraph(n)512g.name("Circuit")513514if n==0:515return g516elif n == 1:517g.allow_loops(True)518g.add_edge(0,0)519return g520else:521g.add_edges([(i,i+1) for i in xrange(n-1)])522g.add_edge(n-1,0)523return g524525def Circulant(self,n,integers):526r"""527Returns a circulant digraph on `n` vertices from a set of integers.528529INPUT:530531- ``n`` (integer) -- number of vertices.532533- ``integers`` -- the list of integers such that there is an edge from534`i` to `j` if and only if ``(j-i)%n in integers``.535536EXAMPLE::537538sage: digraphs.Circulant(13,[3,5,7])539Circulant graph ([3, 5, 7]): Digraph on 13 vertices540541TESTS::542543sage: digraphs.Circulant(13,[3,5,7,"hey"])544Traceback (most recent call last):545...546ValueError: The list must contain only relative integers.547sage: digraphs.Circulant(3,[3,5,7,3.4])548Traceback (most recent call last):549...550ValueError: The list must contain only relative integers.551"""552from sage.graphs.graph_plot import _circle_embedding553from sage.rings.integer_ring import ZZ554555# Bad input and loops556loops = False557for i in integers:558if not i in ZZ:559raise ValueError("The list must contain only relative integers.")560if (i%n) == 0:561loops = True562563G=DiGraph(n, name="Circulant graph ("+str(integers)+")", loops=loops)564565_circle_embedding(G, range(n))566for v in range(n):567G.add_edges([(v,(v+j)%n) for j in integers])568569return G570571def DeBruijn(self, k, n, vertices = 'strings'):572r"""573Returns the De Bruijn digraph with parameters `k,n`.574575The De Bruijn digraph with parameters `k,n` is built upon a set of576vertices equal to the set of words of length `n` from a dictionary of577`k` letters.578579In this digraph, there is an arc `w_1w_2` if `w_2` can be obtained from580`w_1` by removing the leftmost letter and adding a new letter at its581right end. For more information, see the582:wikipedia:`Wikipedia article on De Bruijn graph <De_Bruijn_graph>`.583584INPUT:585586- ``k`` -- Two possibilities for this parameter :587- An integer equal to the cardinality of the alphabet to use, that588is the degree of the digraph to be produced.589- An iterable object to be used as the set of letters. The degree590of the resulting digraph is the cardinality of the set of591letters.592593- ``n`` -- An integer equal to the length of words in the De Bruijn594digraph when ``vertices == 'strings'``, and also to the diameter of595the digraph.596597- ``vertices`` -- 'strings' (default) or 'integers', specifying whether598the vertices are words build upon an alphabet or integers.599600EXAMPLES::601602sage: db=digraphs.DeBruijn(2,2); db603De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices604sage: db.order()6054606sage: db.size()6078608609TESTS::610611sage: digraphs.DeBruijn(5,0)612De Bruijn digraph (k=5, n=0): Looped multi-digraph on 1 vertex613sage: digraphs.DeBruijn(0,0)614De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices615"""616from sage.combinat.words.words import Words617from sage.rings.integer import Integer618619W = Words(range(k) if isinstance(k, Integer) else k, n)620A = Words(range(k) if isinstance(k, Integer) else k, 1)621g = DiGraph(loops=True)622623if vertices == 'strings':624if n == 0 :625g.allow_multiple_edges(True)626v = W[0]627for a in A:628g.add_edge(v.string_rep(), v.string_rep(), a.string_rep())629else:630for w in W:631ww = w[1:]632for a in A:633g.add_edge(w.string_rep(), (ww*a).string_rep(), a.string_rep())634else:635d = W.size_of_alphabet()636g = digraphs.GeneralizedDeBruijn(d**n, d)637638g.name( "De Bruijn digraph (k=%s, n=%s)"%(k,n) )639return g640641def GeneralizedDeBruijn(self, n, d):642r"""643Returns the generalized de Bruijn digraph of order `n` and degree `d`.644645The generalized de Bruijn digraph has been defined in [RPK80]_646[RPK83]_. It has vertex set `V=\{0, 1,..., n-1\}` and there is an arc647from vertex `u \in V` to all vertices `v \in V` such that648`v \equiv (u*d + a) \mod{n}` with `0 \leq a < d`.649650When `n = d^{D}`, the generalized de Bruijn digraph is isomorphic to the651de Bruijn digraph of degree `d` and diameter `D`.652653INPUTS:654655- ``n`` -- is the number of vertices of the digraph656657- ``d`` -- is the degree of the digraph658659.. SEEALSO::660661* :meth:`sage.graphs.generic_graph.GenericGraph.is_circulant` --662checks whether a (di)graph is circulant, and/or returns all663possible sets of parameters.664665EXAMPLE::666667sage: GB = digraphs.GeneralizedDeBruijn(8, 2)668sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certify = True)669(True, {0: '000', 1: '001', 2: '010', 3: '011', 4: '100', 5: '101', 6: '110', 7: '111'})670671TESTS:672673An exception is raised when the degree is less than one::674675sage: G = digraphs.GeneralizedDeBruijn(2, 0)676Traceback (most recent call last):677...678ValueError: The generalized de Bruijn digraph is defined for degree at least one.679680An exception is raised when the order of the graph is less than one::681682sage: G = digraphs.GeneralizedDeBruijn(0, 2)683Traceback (most recent call last):684...685ValueError: The generalized de Bruijn digraph is defined for at least one vertex.686687688REFERENCES:689690.. [RPK80] S. M. Reddy, D. K. Pradhan, and J. Kuhl. Directed graphs with691minimal diameter and maximal connectivity, School Eng., Oakland Univ.,692Rochester MI, Tech. Rep., July 1980.693694.. [RPK83] S. Reddy, P. Raghavan, and J. Kuhl. A Class of Graphs for695Processor Interconnection. *IEEE International Conference on Parallel696Processing*, pages 154-157, Los Alamitos, Ca., USA, August 1983.697"""698if n < 1:699raise ValueError("The generalized de Bruijn digraph is defined for at least one vertex.")700if d < 1:701raise ValueError("The generalized de Bruijn digraph is defined for degree at least one.")702703GB = DiGraph(loops = True)704GB.allow_multiple_edges(True)705for u in xrange(n):706for a in xrange(u*d, u*d+d):707GB.add_edge(u, a%n)708709GB.name( "Generalized de Bruijn digraph (n=%s, d=%s)"%(n,d) )710return GB711712713def ImaseItoh(self, n, d):714r"""715Returns the digraph of Imase and Itoh of order `n` and degree `d`.716717The digraph of Imase and Itoh has been defined in [II83]_. It has vertex718set `V=\{0, 1,..., n-1\}` and there is an arc from vertex `u \in V` to719all vertices `v \in V` such that `v \equiv (-u*d-a-1) \mod{n}` with720`0 \leq a < d`.721722When `n = d^{D}`, the digraph of Imase and Itoh is isomorphic to the de723Bruijn digraph of degree `d` and diameter `D`. When `n = d^{D-1}(d+1)`,724the digraph of Imase and Itoh is isomorphic to the Kautz digraph725[Kautz68]_ of degree `d` and diameter `D`.726727INPUTS:728729- ``n`` -- is the number of vertices of the digraph730731- ``d`` -- is the degree of the digraph732733EXAMPLES::734735sage: II = digraphs.ImaseItoh(8, 2)736sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certify = True)737(True, {0: '010', 1: '011', 2: '000', 3: '001', 4: '110', 5: '111', 6: '100', 7: '101'})738739sage: II = digraphs.ImaseItoh(12, 2)740sage: II.is_isomorphic(digraphs.Kautz(2, 3), certify = True)741(True, {0: '010', 1: '012', 2: '021', 3: '020', 4: '202', 5: '201', 6: '210', 7: '212', 8: '121', 9: '120', 10: '102', 11: '101'})742743744TESTS:745746An exception is raised when the degree is less than one::747748sage: G = digraphs.ImaseItoh(2, 0)749Traceback (most recent call last):750...751ValueError: The digraph of Imase and Itoh is defined for degree at least one.752753An exception is raised when the order of the graph is less than two::754755sage: G = digraphs.ImaseItoh(1, 2)756Traceback (most recent call last):757...758ValueError: The digraph of Imase and Itoh is defined for at least two vertices.759760761REFERENCE:762763.. [II83] M. Imase and M. Itoh. A design for directed graphs with764minimum diameter, *IEEE Trans. Comput.*, vol. C-32, pp. 782-784, 1983.765"""766if n < 2:767raise ValueError("The digraph of Imase and Itoh is defined for at least two vertices.")768if d < 1:769raise ValueError("The digraph of Imase and Itoh is defined for degree at least one.")770771II = DiGraph(loops = True)772II.allow_multiple_edges(True)773for u in xrange(n):774for a in xrange(-u*d-d, -u*d):775II.add_edge(u, a % n)776777II.name( "Imase and Itoh digraph (n=%s, d=%s)"%(n,d) )778return II779780781def Kautz(self, k, D, vertices = 'strings'):782r"""783Returns the Kautz digraph of degree `d` and diameter `D`.784785The Kautz digraph has been defined in [Kautz68]_. The Kautz digraph of786degree `d` and diameter `D` has `d^{D-1}(d+1)` vertices. This digraph is787build upon a set of vertices equal to the set of words of length `D`788from an alphabet of `d+1` letters such that consecutive letters are789differents. There is an arc from vertex `u` to vertex `v` if `v` can be790obtained from `u` by removing the leftmost letter and adding a new791letter, distinct from the rightmost letter of `u`, at the right end.792793The Kautz digraph of degree `d` and diameter `D` is isomorphic to the794digraph of Imase and Itoh [II83]_ of degree `d` and order795`d^{D-1}(d+1)`.796797See also the798:wikipedia:`Wikipedia article on Kautz Graphs <Kautz_graph>`.799800INPUTS:801802- ``k`` -- Two possibilities for this parameter :803- An integer equal to the degree of the digraph to be produced, that804is the cardinality minus one of the alphabet to use.805- An iterable object to be used as the set of letters. The degree of806the resulting digraph is the cardinality of the set of letters807minus one.808809- ``D`` -- An integer equal to the diameter of the digraph, and also to810the length of a vertex label when ``vertices == 'strings'``.811812- ``vertices`` -- 'strings' (default) or 'integers', specifying whether813the vertices are words build upon an alphabet or integers.814815816EXAMPLES::817818sage: K = digraphs.Kautz(2, 3)819sage: K.is_isomorphic(digraphs.ImaseItoh(12, 2), certify = True)820(True, {'201': 5, '120': 9, '202': 4, '212': 7, '210': 6, '010': 0, '121': 8, '012': 1, '021': 2, '020': 3, '102': 10, '101': 11})821822sage: K = digraphs.Kautz([1,'a','B'], 2)823sage: K.edges()824[('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'), ('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'), ('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'), ('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')]825826sage: K = digraphs.Kautz([1,'aA','BB'], 2)827sage: K.edges()828[('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'), ('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'), ('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'), ('BB,aA', 'aA,1', '1'), ('BB,aA', 'aA,BB', 'BB'), ('aA,1', '1,BB', 'BB'), ('aA,1', '1,aA', 'aA'), ('aA,BB', 'BB,1', '1'), ('aA,BB', 'BB,aA', 'aA')]829830831TESTS:832833An exception is raised when the degree is less than one::834835sage: G = digraphs.Kautz(0, 2)836Traceback (most recent call last):837...838ValueError: Kautz digraphs are defined for degree at least one.839840sage: G = digraphs.Kautz(['a'], 2)841Traceback (most recent call last):842...843ValueError: Kautz digraphs are defined for degree at least one.844845An exception is raised when the diameter of the graph is less than one::846847sage: G = digraphs.Kautz(2, 0)848Traceback (most recent call last):849...850ValueError: Kautz digraphs are defined for diameter at least one.851852853REFERENCE:854855.. [Kautz68] W. H. Kautz. Bounds on directed (d, k) graphs. Theory of856cellular logic networks and machines, AFCRL-68-0668, SRI Project 7258,857Final Rep., pp. 20-28, 1968.858"""859if D < 1:860raise ValueError("Kautz digraphs are defined for diameter at least one.")861862from sage.combinat.words.words import Words863from sage.rings.integer import Integer864865my_alphabet = Words([str(i) for i in range(k+1)] if isinstance(k, Integer) else k, 1)866if my_alphabet.size_of_alphabet() < 2:867raise ValueError("Kautz digraphs are defined for degree at least one.")868869if vertices == 'strings':870871# We start building the set of vertices872V = [i for i in my_alphabet]873for i in range(D-1):874VV = []875for w in V:876VV += [w*a for a in my_alphabet if not w.has_suffix(a) ]877V = VV878879# We now build the set of arcs880G = DiGraph()881for u in V:882for a in my_alphabet:883if not u.has_suffix(a):884G.add_edge(u.string_rep(), (u[1:]*a).string_rep(), a.string_rep())885886else:887d = my_alphabet.size_of_alphabet()-1888G = digraphs.ImaseItoh( (d+1)*(d**(D-1)), d)889890G.name( "Kautz digraph (k=%s, D=%s)"%(k,D) )891return G892893894def RandomDirectedGN(self, n, kernel=lambda x:x, seed=None):895"""896Returns a random GN (growing network) digraph with n vertices.897898The digraph is constructed by adding vertices with a link to one899previously added vertex. The vertex to link to is chosen with a900preferential attachment model, i.e. probability is proportional to901degree. The default attachment kernel is a linear function of902degree. The digraph is always a tree, so in particular it is a903directed acyclic graph.904905INPUT:906907908- ``n`` - number of vertices.909910- ``kernel`` - the attachment kernel911912- ``seed`` - for the random number generator913914915EXAMPLE::916917sage: D = digraphs.RandomDirectedGN(25)918sage: D.edges(labels=False)919[(1, 0), (2, 0), (3, 1), (4, 0), (5, 0), (6, 1), (7, 0), (8, 3), (9, 0), (10, 8), (11, 3), (12, 9), (13, 8), (14, 0), (15, 11), (16, 11), (17, 5), (18, 11), (19, 6), (20, 5), (21, 14), (22, 5), (23, 18), (24, 11)]920sage: D.show() # long time921922REFERENCE:923924- [1] Krapivsky, P.L. and Redner, S. Organization of Growing925Random Networks, Phys. Rev. E vol. 63 (2001), p. 066123.926"""927if seed is None:928seed = current_randstate().long_seed()929import networkx930return DiGraph(networkx.gn_graph(n, kernel, seed=seed))931932def RandomDirectedGNC(self, n, seed=None):933"""934Returns a random GNC (growing network with copying) digraph with n935vertices.936937The digraph is constructed by adding vertices with a link to one938previously added vertex. The vertex to link to is chosen with a939preferential attachment model, i.e. probability is proportional to940degree. The new vertex is also linked to all of the previously941added vertex's successors.942943INPUT:944945946- ``n`` - number of vertices.947948- ``seed`` - for the random number generator949950951EXAMPLE::952953sage: D = digraphs.RandomDirectedGNC(25)954sage: D.edges(labels=False)955[(1, 0), (2, 0), (2, 1), (3, 0), (4, 0), (4, 1), (5, 0), (5, 1), (5, 2), (6, 0), (6, 1), (7, 0), (7, 1), (7, 4), (8, 0), (9, 0), (9, 8), (10, 0), (10, 1), (10, 2), (10, 5), (11, 0), (11, 8), (11, 9), (12, 0), (12, 8), (12, 9), (13, 0), (13, 1), (14, 0), (14, 8), (14, 9), (14, 12), (15, 0), (15, 8), (15, 9), (15, 12), (16, 0), (16, 1), (16, 4), (16, 7), (17, 0), (17, 8), (17, 9), (17, 12), (18, 0), (18, 8), (19, 0), (19, 1), (19, 4), (19, 7), (20, 0), (20, 1), (20, 4), (20, 7), (20, 16), (21, 0), (21, 8), (22, 0), (22, 1), (22, 4), (22, 7), (22, 19), (23, 0), (23, 8), (23, 9), (23, 12), (23, 14), (24, 0), (24, 8), (24, 9), (24, 12), (24, 15)]956sage: D.show() # long time957958REFERENCE:959960- [1] Krapivsky, P.L. and Redner, S. Network Growth by961Copying, Phys. Rev. E vol. 71 (2005), p. 036118.962"""963if seed is None:964seed = current_randstate().long_seed()965import networkx966return DiGraph(networkx.gnc_graph(n, seed=seed))967968def RandomDirectedGNP(self, n, p, loops = False, seed = None):969r"""970Returns a random digraph on `n` nodes. Each edge is inserted971independently with probability `p`.972973INPUTS:974975- ``n`` -- number of nodes of the digraph976977- ``p`` -- probability of an edge978979- ``loops`` -- is a boolean set to True if the random digraph may have980loops, and False (default) otherwise.981982- ``seed`` -- integer seed for random number generator (default=None).983984REFERENCES:985986.. [1] P. Erdos and A. Renyi, On Random Graphs, Publ. Math. 6, 290987(1959).988989.. [2] E. N. Gilbert, Random Graphs, Ann. Math. Stat., 30, 1141 (1959).990991992PLOTTING: When plotting, this graph will use the default spring-layout993algorithm, unless a position dictionary is specified.994995EXAMPLE::996997sage: set_random_seed(0)998sage: D = digraphs.RandomDirectedGNP(10, .2)999sage: D.num_verts()1000101001sage: D.edges(labels=False)1002[(1, 0), (1, 2), (3, 6), (3, 7), (4, 5), (4, 7), (4, 8), (5, 2), (6, 0), (7, 2), (8, 1), (8, 9), (9, 4)]1003"""1004from sage.graphs.graph_generators_pyx import RandomGNP1005if 0.0 > p or 1.0 < p:1006raise ValueError("The probability p must be in [0..1].")10071008if seed is None:1009seed = current_randstate().long_seed()10101011return RandomGNP(n, p, directed = True, loops = loops)10121013def RandomDirectedGNM(self, n, m, loops = False):1014r"""1015Returns a random labelled digraph on `n` nodes and `m` arcs.10161017INPUT:10181019- ``n`` (integer) -- number of vertices.10201021- ``m`` (integer) -- number of edges.10221023- ``loops`` (boolean) -- whether to allow loops (set to ``False`` by1024default).10251026PLOTTING: When plotting, this graph will use the default spring-layout1027algorithm, unless a position dictionary is specified.10281029EXAMPLE::10301031sage: D = digraphs.RandomDirectedGNM(10, 5)1032sage: D.num_verts()1033101034sage: D.edges(labels=False)1035[(0, 3), (1, 5), (5, 1), (7, 0), (8, 5)]10361037With loops::10381039sage: D = digraphs.RandomDirectedGNM(10, 100, loops = True)1040sage: D.num_verts()1041101042sage: D.loops()1043[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None), (4, 4, None), (5, 5, None), (6, 6, None), (7, 7, None), (8, 8, None), (9, 9, None)]10441045TESTS::10461047sage: digraphs.RandomDirectedGNM(10,-3)1048Traceback (most recent call last):1049...1050ValueError: The number of edges must satisfy 0<= m <= n(n-1) when no loops are allowed, and 0<= m <= n^2 otherwise.10511052sage: digraphs.RandomDirectedGNM(10,100)1053Traceback (most recent call last):1054...1055ValueError: The number of edges must satisfy 0<= m <= n(n-1) when no loops are allowed, and 0<= m <= n^2 otherwise.1056"""1057n, m = int(n), int(m)10581059# The random graph is built by drawing randomly and uniformly two1060# integers u,v, and adding the corresponding edge if it does not exist,1061# as many times as necessary.10621063# When the graph is dense, we actually compute its complement. This will1064# prevent us from drawing the same pair u,v too many times.10651066from sage.misc.prandom import _pyrand1067rand = _pyrand()1068D = DiGraph(n, loops = loops)10691070# Ensuring the parameters n,m make sense.1071#1072# If the graph is dense, we actually want to build its complement. We1073# update m accordingly.10741075good_input = True1076is_dense = False10771078if m < 0:1079good_input = False10801081if loops:1082if m > n*n:1083good_input = False1084elif m > n*n/2:1085is_dense = True1086m = n*n - m10871088else:1089if m > n*(n-1):1090good_input = False1091elif m > n*(n-1)/2:1092is_dense = True1093m = n*(n-1) - m10941095if not good_input:1096raise ValueError("The number of edges must satisfy 0<= m <= n(n-1) when no loops are allowed, and 0<= m <= n^2 otherwise.")10971098# When the given number of edges defines a density larger than 1/2, it1099# should be faster to compute the complement of the graph (less edges to1100# generate), then to return its complement. This being said, the1101# .complement() method for sparse graphs is very slow at the moment.11021103# Similarly, it is faster to test whether a pair belongs to a dictionary1104# than to test the adjacency of two vertices in a graph. For these1105# reasons, the following code mainly works on dictionaries.11061107adj = dict( (i, dict()) for i in range(n) )11081109# We fill the dictionary structure, but add the corresponding edge in1110# the graph only if is_dense is False. If it is true, we will add the1111# edges in a second phase.111211131114while m > 0:11151116# It is better to obtain random numbers this way than by calling the1117# randint or randrange method. This, because they are very expensive1118# when trying to compute MANY random integers, and because the1119# following lines is precisely what they do anyway, after checking1120# their parameters are correct.11211122u=int(rand.random()*n)1123v=int(rand.random()*n)11241125if (u != v or loops) and (not v in adj[u]):1126adj[u][v] = 11127m -= 11128if not is_dense:1129D.add_edge(u,v)11301131# If is_dense is True, it means the graph has not been built. We fill D1132# with the complement of the edges stored in the adj dictionary11331134if is_dense:1135for u in range(n):1136for v in range(n):1137if ((u != v) or loops) and (not (v in adj[u])):1138D.add_edge(u,v)11391140return D11411142def RandomDirectedGNR(self, n, p, seed=None):1143"""1144Returns a random GNR (growing network with redirection) digraph1145with n vertices and redirection probability p.11461147The digraph is constructed by adding vertices with a link to one1148previously added vertex. The vertex to link to is chosen uniformly.1149With probability p, the arc is instead redirected to the successor1150vertex. The digraph is always a tree.11511152INPUT:115311541155- ``n`` - number of vertices.11561157- ``p`` - redirection probability11581159- ``seed`` - for the random number generator.116011611162EXAMPLE::11631164sage: D = digraphs.RandomDirectedGNR(25, .2)1165sage: D.edges(labels=False)1166[(1, 0), (2, 0), (2, 1), (3, 0), (4, 0), (4, 1), (5, 0), (5, 1), (5, 2), (6, 0), (6, 1), (7, 0), (7, 1), (7, 4), (8, 0), (9, 0), (9, 8), (10, 0), (10, 1), (10, 2), (10, 5), (11, 0), (11, 8), (11, 9), (12, 0), (12, 8), (12, 9), (13, 0), (13, 1), (14, 0), (14, 8), (14, 9), (14, 12), (15, 0), (15, 8), (15, 9), (15, 12), (16, 0), (16, 1), (16, 4), (16, 7), (17, 0), (17, 8), (17, 9), (17, 12), (18, 0), (18, 8), (19, 0), (19, 1), (19, 4), (19, 7), (20, 0), (20, 1), (20, 4), (20, 7), (20, 16), (21, 0), (21, 8), (22, 0), (22, 1), (22, 4), (22, 7), (22, 19), (23, 0), (23, 8), (23, 9), (23, 12), (23, 14), (24, 0), (24, 8), (24, 9), (24, 12), (24, 15)]1167sage: D.show() # long time11681169REFERENCE:11701171- [1] Krapivsky, P.L. and Redner, S. Organization of Growing1172Random Networks, Phys. Rev. E vol. 63 (2001), p. 066123.1173"""1174if seed is None:1175seed = current_randstate().long_seed()1176import networkx1177return DiGraph(networkx.gnc_graph(n, seed=seed))11781179################################################################################1180# DiGraph Iterators1181################################################################################11821183def __call__(self, vertices, property=lambda x: True, augment='edges', size=None, implementation='c_graph', sparse=True):1184"""1185Accesses the generator of isomorphism class representatives.1186Iterates over distinct, exhaustive representatives.11871188INPUT:118911901191- ``vertices`` - natural number11921193- ``property`` - any property to be tested on digraphs1194before generation.11951196- ``augment`` - choices:11971198- ``'vertices'`` - augments by adding a vertex, and1199edges incident to that vertex. In this case, all digraphs on up to1200n=vertices are generated. If for any digraph G satisfying the1201property, every subgraph, obtained from G by deleting one vertex1202and only edges incident to that vertex, satisfies the property,1203then this will generate all digraphs with that property. If this1204does not hold, then all the digraphs generated will satisfy the1205property, but there will be some missing.12061207- ``'edges'`` - augments a fixed number of vertices by1208adding one edge In this case, all digraphs on exactly n=vertices1209are generated. If for any graph G satisfying the property, every1210subgraph, obtained from G by deleting one edge but not the vertices1211incident to that edge, satisfies the property, then this will1212generate all digraphs with that property. If this does not hold,1213then all the digraphs generated will satisfy the property, but1214there will be some missing.12151216- ``implementation`` - which underlying implementation to use (see DiGraph?)12171218- ``sparse`` - ignored if implementation is not ``c_graph``12191220EXAMPLES: Print digraphs on 2 or less vertices.12211222::12231224sage: for D in digraphs(2, augment='vertices'):1225... print D1226...1227Digraph on 0 vertices1228Digraph on 1 vertex1229Digraph on 2 vertices1230Digraph on 2 vertices1231Digraph on 2 vertices12321233Print digraphs on 3 vertices.12341235::12361237sage: for D in digraphs(3):1238... print D1239Digraph on 3 vertices1240Digraph on 3 vertices1241...1242Digraph on 3 vertices1243Digraph on 3 vertices12441245For more examples, see the class level documentation, or type12461247::12481249sage: digraphs? # not tested12501251REFERENCE:12521253- Brendan D. McKay, Isomorph-Free Exhaustive generation.1254Journal of Algorithms Volume 26, Issue 2, February 1998,1255pages 306-324.1256"""1257if size is not None:1258extra_property = lambda x: x.size() == size1259else:1260extra_property = lambda x: True1261if augment == 'vertices':1262from sage.graphs.graph_generators import canaug_traverse_vert1263g = DiGraph(implementation=implementation, sparse=sparse)1264for gg in canaug_traverse_vert(g, [], vertices, property, dig=True, implementation=implementation, sparse=sparse):1265if extra_property(gg):1266yield gg1267elif augment == 'edges':1268from sage.graphs.graph_generators import canaug_traverse_edge1269g = DiGraph(vertices, implementation=implementation, sparse=sparse)1270gens = []1271for i in range(vertices-1):1272gen = range(i)1273gen.append(i+1); gen.append(i)1274gen += range(i+2, vertices)1275gens.append(gen)1276for gg in canaug_traverse_edge(g, gens, property, dig=True, implementation=implementation, sparse=sparse):1277if extra_property(gg):1278yield gg1279else:1280raise NotImplementedError()128112821283# Easy access to the graph generators from the command line:1284digraphs = DiGraphGenerators()1285128612871288128912901291