Path: blob/master/src/sage/graphs/generators/random.py
8815 views
# -*- coding: utf-8 -*-1r"""2Random Graphs34The methods defined here appear in :mod:`sage.graphs.graph_generators`.5"""6###########################################################################7#8# Copyright (C) 2006 Robert L. Miller <[email protected]>9# and Emily A. Kirkman10# Copyright (C) 2009 Michael C. Yurko <[email protected]>11#12# Distributed under the terms of the GNU General Public License (GPL)13# http://www.gnu.org/licenses/14###########################################################################1516# import from Sage library17from sage.graphs.graph import Graph18from sage.misc.randstate import current_randstate1920def RandomGNP(n, p, seed=None, fast=True, method='Sage'):21r"""22Returns a random graph on `n` nodes. Each edge is inserted independently23with probability `p`.2425INPUTS:2627- ``n`` -- number of nodes of the graph2829- ``p`` -- probability of an edge3031- ``seed`` -- integer seed for random number generator (default=None).3233- ``fast`` -- boolean set to True (default) to use the algorithm with34time complexity in `O(n+m)` proposed in [BatBra2005]_. It is designed35for generating large sparse graphs. It is faster than other methods for36*LARGE* instances (try it to know whether it is useful for you).3738- ``method`` -- By default (```method='Sage'``), this function uses the39method implemented in ```sage.graphs.graph_generators_pyx.pyx``. When40``method='networkx'``, this function calls the NetworkX function41``fast_gnp_random_graph``, unless ``fast=False``, then42``gnp_random_graph``. Try them to know which method is the best for43you. The ``fast`` parameter is not taken into account by the 'Sage'44method so far.4546REFERENCES:4748.. [ErdRen1959] P. Erdos and A. Renyi. On Random Graphs, Publ.49Math. 6, 290 (1959).5051.. [Gilbert1959] E. N. Gilbert. Random Graphs, Ann. Math. Stat.,5230, 1141 (1959).5354.. [BatBra2005] V. Batagelj and U. Brandes. Efficient generation of55large random networks. Phys. Rev. E, 71, 036113, 2005.5657PLOTTING: When plotting, this graph will use the default spring-layout58algorithm, unless a position dictionary is specified.5960EXAMPLES: We show the edge list of a random graph on 6 nodes with61probability `p = .4`::6263sage: set_random_seed(0)64sage: graphs.RandomGNP(6, .4).edges(labels=False)65[(0, 1), (0, 5), (1, 2), (2, 4), (3, 4), (3, 5), (4, 5)]6667We plot a random graph on 12 nodes with probability `p = .71`::6869sage: gnp = graphs.RandomGNP(12,.71)70sage: gnp.show() # long time7172We view many random graphs using a graphics array::7374sage: g = []75sage: j = []76sage: for i in range(9):77....: k = graphs.RandomGNP(i+3,.43)78....: g.append(k)79sage: for i in range(3):80....: n = []81....: for m in range(3):82....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))83....: j.append(n)84sage: G = sage.plot.graphics.GraphicsArray(j)85sage: G.show() # long time86sage: graphs.RandomGNP(4,1)87Complete graph: Graph on 4 vertices8889TESTS::9091sage: graphs.RandomGNP(50,.2,method=50)92Traceback (most recent call last):93...94ValueError: 'method' must be equal to 'networkx' or to 'Sage'.95sage: set_random_seed(0)96sage: graphs.RandomGNP(50,.2, method="Sage").size()9724398sage: graphs.RandomGNP(50,.2, method="networkx").size()99258100"""101if n < 0:102raise ValueError("The number of nodes must be positive or null.")103if 0.0 > p or 1.0 < p:104raise ValueError("The probability p must be in [0..1].")105106if seed is None:107seed = current_randstate().long_seed()108if p == 1:109from sage.graphs.generators.basic import CompleteGraph110return CompleteGraph(n)111112if method == 'networkx':113import networkx114if fast:115G = networkx.fast_gnp_random_graph(n, p, seed=seed)116else:117G = networkx.gnp_random_graph(n, p, seed=seed)118return Graph(G)119elif method in ['Sage', 'sage']:120# We use the Sage generator121from sage.graphs.graph_generators_pyx import RandomGNP as sageGNP122return sageGNP(n, p)123else:124raise ValueError("'method' must be equal to 'networkx' or to 'Sage'.")125126def RandomBarabasiAlbert(n, m, seed=None):127u"""128Return a random graph created using the Barabasi-Albert preferential129attachment model.130131A graph with m vertices and no edges is initialized, and a graph of n132vertices is grown by attaching new vertices each with m edges that are133attached to existing vertices, preferentially with high degree.134135INPUT:136137- ``n`` - number of vertices in the graph138139- ``m`` - number of edges to attach from each new node140141- ``seed`` - for random number generator142143EXAMPLES:144145We show the edge list of a random graph on 6 nodes with m = 2.146147::148149sage: graphs.RandomBarabasiAlbert(6,2).edges(labels=False)150[(0, 2), (0, 3), (0, 4), (1, 2), (2, 3), (2, 4), (2, 5), (3, 5)]151152We plot a random graph on 12 nodes with m = 3.153154::155156sage: ba = graphs.RandomBarabasiAlbert(12,3)157sage: ba.show() # long time158159We view many random graphs using a graphics array::160161sage: g = []162sage: j = []163sage: for i in range(1,10):164....: k = graphs.RandomBarabasiAlbert(i+3, 3)165....: g.append(k)166sage: for i in range(3):167....: n = []168....: for m in range(3):169....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))170....: j.append(n)171sage: G = sage.plot.graphics.GraphicsArray(j)172sage: G.show() # long time173174"""175if seed is None:176seed = current_randstate().long_seed()177import networkx178return Graph(networkx.barabasi_albert_graph(n,m,seed=seed))179180def RandomBipartite(n1,n2, p):181r"""182Returns a bipartite graph with `n1+n2` vertices183such that any edge from `[n1]` to `[n2]` exists184with probability `p`.185186INPUT:187188- ``n1,n2`` : Cardinalities of the two sets189- ``p`` : Probability for an edge to exist190191192EXAMPLE::193194sage: g=graphs.RandomBipartite(5,2,0.5)195sage: g.vertices()196[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)]197198TESTS::199200sage: g=graphs.RandomBipartite(5,-3,0.5)201Traceback (most recent call last):202...203ValueError: n1 and n2 should be integers strictly greater than 0204sage: g=graphs.RandomBipartite(5,3,1.5)205Traceback (most recent call last):206...207ValueError: Parameter p is a probability, and so should be a real value between 0 and 1208209Trac ticket #12155::210211sage: graphs.RandomBipartite(5,6,.2).complement()212complement(Random bipartite graph of size 5+6 with edge probability 0.200000000000000): Graph on 11 vertices213"""214if not (p>=0 and p<=1):215raise ValueError, "Parameter p is a probability, and so should be a real value between 0 and 1"216if not (n1>0 and n2>0):217raise ValueError, "n1 and n2 should be integers strictly greater than 0"218219from numpy.random import uniform220221g=Graph(name="Random bipartite graph of size "+str(n1) +"+"+str(n2)+" with edge probability "+str(p))222223S1=[(0,i) for i in range(n1)]224S2=[(1,i) for i in range(n2)]225g.add_vertices(S1)226g.add_vertices(S2)227228for w in range(n2):229for v in range(n1):230if uniform()<=p :231g.add_edge((0,v),(1,w))232233pos = {}234for i in range(n1):235pos[(0,i)] = (0, i/(n1-1.0))236for i in range(n2):237pos[(1,i)] = (1, i/(n2-1.0))238239g.set_pos(pos)240241return g242243def RandomBoundedToleranceGraph(n):244r"""245Returns a random bounded tolerance graph.246247The random tolerance graph is built from a random bounded248tolerance representation by using the function249`ToleranceGraph`. This representation is a list250`((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where251`k = n-1` and `I_i = (l_i,r_i)` denotes a random interval and252`t_i` a random positive value less then or equal to the length253of the interval `I_i`. The width of the representation is254limited to n**2 * 2**n.255256.. NOTE::257258The tolerance representation used to create the graph can259be recovered using ``get_vertex()`` or ``get_vertices()``.260261INPUT:262263- ``n`` -- number of vertices of the random graph.264265EXAMPLE:266267Every (bounded) tolerance graph is perfect. Hence, the268chromatic number is equal to the clique number ::269270sage: g = graphs.RandomBoundedToleranceGraph(8)271sage: g.clique_number() == g.chromatic_number()272True273"""274from sage.misc.prandom import randint275from sage.graphs.generators.intersection import ToleranceGraph276277W = n**2 * 2**n278279tolrep = map(lambda (l,r): (l,r,randint(0,r-l)),280[sorted((randint(0,W), randint(0,W))) for i in range(n)])281282return ToleranceGraph(tolrep)283284def RandomGNM(n, m, dense=False, seed=None):285"""286Returns a graph randomly picked out of all graphs on n vertices287with m edges.288289INPUT:290291- ``n`` - number of vertices.292293- ``m`` - number of edges.294295- ``dense`` - whether to use NetworkX's296dense_gnm_random_graph or gnm_random_graph297298299EXAMPLES: We show the edge list of a random graph on 5 nodes with30010 edges.301302::303304sage: graphs.RandomGNM(5, 10).edges(labels=False)305[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]306307We plot a random graph on 12 nodes with m = 12.308309::310311sage: gnm = graphs.RandomGNM(12, 12)312sage: gnm.show() # long time313314We view many random graphs using a graphics array::315316sage: g = []317sage: j = []318sage: for i in range(9):319....: k = graphs.RandomGNM(i+3, i^2-i)320....: g.append(k)321sage: for i in range(3):322....: n = []323....: for m in range(3):324....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))325....: j.append(n)326sage: G = sage.plot.graphics.GraphicsArray(j)327sage: G.show() # long time328"""329if seed is None:330seed = current_randstate().long_seed()331import networkx332if dense:333return Graph(networkx.dense_gnm_random_graph(n, m, seed=seed))334else:335return Graph(networkx.gnm_random_graph(n, m, seed=seed))336337def RandomNewmanWattsStrogatz(n, k, p, seed=None):338"""339Returns a Newman-Watts-Strogatz small world random graph on n340vertices.341342From the NetworkX documentation: First create a ring over n nodes.343Then each node in the ring is connected with its k nearest344neighbors. Then shortcuts are created by adding new edges as345follows: for each edge u-v in the underlying "n-ring with k nearest346neighbors"; with probability p add a new edge u-w with347randomly-chosen existing node w. In contrast with348watts_strogatz_graph(), no edges are removed.349350INPUT:351352- ``n`` - number of vertices.353354- ``k`` - each vertex is connected to its k nearest355neighbors356357- ``p`` - the probability of adding a new edge for358each edge359360- ``seed`` - for the random number generator361362363EXAMPLE: We show the edge list of a random graph on 7 nodes with 2364"nearest neighbors" and probability `p = 0.2`::365366sage: graphs.RandomNewmanWattsStrogatz(7, 2, 0.2).edges(labels=False)367[(0, 1), (0, 2), (0, 3), (0, 6), (1, 2), (2, 3), (2, 4), (3, 4), (3, 6), (4, 5), (5, 6)]368369::370371sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3)372sage: G.show() # long time373374REFERENCE:375376.. [NWS99] Newman, M.E.J., Watts, D.J. and Strogatz, S.H. Random377graph models of social networks. Proc. Nat. Acad. Sci. USA37899, 2566-2572.379"""380if seed is None:381seed = current_randstate().long_seed()382import networkx383return Graph(networkx.newman_watts_strogatz_graph(n, k, p, seed=seed))384385def RandomHolmeKim(n, m, p, seed=None):386"""387Returns a random graph generated by the Holme and Kim algorithm for388graphs with power law degree distribution and approximate average389clustering.390391INPUT:392393- ``n`` - number of vertices.394395- ``m`` - number of random edges to add for each new396node.397398- ``p`` - probability of adding a triangle after399adding a random edge.400401- ``seed`` - for the random number generator.402403404From the NetworkX documentation: The average clustering has a hard405time getting above a certain cutoff that depends on m. This cutoff406is often quite low. Note that the transitivity (fraction of407triangles to possible triangles) seems to go down with network408size. It is essentially the Barabasi-Albert growth model with an409extra step that each random edge is followed by a chance of making410an edge to one of its neighbors too (and thus a triangle). This411algorithm improves on B-A in the sense that it enables a higher412average clustering to be attained if desired. It seems possible to413have a disconnected graph with this algorithm since the initial m414nodes may not be all linked to a new node on the first iteration415like the BA model.416417EXAMPLE: We show the edge list of a random graph on 8 nodes with 2418random edges per node and a probability `p = 0.5` of419forming triangles.420421::422423sage: graphs.RandomHolmeKim(8, 2, 0.5).edges(labels=False)424[(0, 2), (0, 5), (1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (2, 7),425(3, 4), (3, 6), (3, 7), (4, 5)]426427::428429sage: G = graphs.RandomHolmeKim(12, 3, .3)430sage: G.show() # long time431432REFERENCE:433434.. [HolmeKim2002] Holme, P. and Kim, B.J. Growing scale-free networks435with tunable clustering, Phys. Rev. E (2002). vol 65, no 2, 026107.436"""437if seed is None:438seed = current_randstate().long_seed()439import networkx440return Graph(networkx.powerlaw_cluster_graph(n, m, p, seed=seed))441442def RandomInterval(n):443"""444:meth:`RandomInterval` is deprecated. Use :meth:`RandomIntervalGraph` instead.445446TEST::447448sage: g = graphs.RandomInterval(8)449doctest:...: DeprecationWarning: RandomInterval() is deprecated. Use RandomIntervalGraph() instead.450See http://trac.sagemath.org/13283 for details.451"""452from sage.misc.superseded import deprecation453deprecation(13283, "RandomInterval() is deprecated. Use RandomIntervalGraph() instead.")454return RandomIntervalGraph(n)455456def RandomIntervalGraph(n):457"""458Returns a random interval graph.459460An interval graph is built from a list `(a_i,b_i)_{1\leq i \leq n}`461of intervals : to each interval of the list is associated one462vertex, two vertices being adjacent if the two corresponding463intervals intersect.464465A random interval graph of order `n` is generated by picking466random values for the `(a_i,b_j)`, each of the two coordinates467being generated from the uniform distribution on the interval468`[0,1]`.469470This definitions follows [boucheron2001]_.471472.. NOTE::473474The vertices are named 0, 1, 2, and so on. The intervals475used to create the graph are saved with the graph and can476be recovered using ``get_vertex()`` or ``get_vertices()``.477478INPUT:479480- ``n`` (integer) -- the number of vertices in the random481graph.482483EXAMPLE:484485As for any interval graph, the chromatic number is equal to486the clique number ::487488sage: g = graphs.RandomIntervalGraph(8)489sage: g.clique_number() == g.chromatic_number()490True491492REFERENCE:493494.. [boucheron2001] Boucheron, S. and FERNANDEZ de la VEGA, W.,495On the Independence Number of Random Interval Graphs,496Combinatorics, Probability and Computing v10, issue 05,497Pages 385--396,498Cambridge Univ Press, 2001499"""500501from sage.misc.prandom import random502from sage.graphs.generators.intersection import IntervalGraph503504intervals = [tuple(sorted((random(), random()))) for i in range(n)]505return IntervalGraph(intervals,True)506507def RandomLobster(n, p, q, seed=None):508"""509Returns a random lobster.510511A lobster is a tree that reduces to a caterpillar when pruning all512leaf vertices. A caterpillar is a tree that reduces to a path when513pruning all leaf vertices (q=0).514515INPUT:516517- ``n`` - expected number of vertices in the backbone518519- ``p`` - probability of adding an edge to the520backbone521522- ``q`` - probability of adding an edge (claw) to the523arms524525- ``seed`` - for the random number generator526527528EXAMPLE: We show the edge list of a random graph with 3 backbone529nodes and probabilities `p = 0.7` and `q = 0.3`::530531sage: graphs.RandomLobster(3, 0.7, 0.3).edges(labels=False)532[(0, 1), (1, 2)]533534::535536sage: G = graphs.RandomLobster(9, .6, .3)537sage: G.show() # long time538"""539if seed is None:540seed = current_randstate().long_seed()541import networkx542return Graph(networkx.random_lobster(n, p, q, seed=seed))543544def RandomTree(n):545"""546Returns a random tree on `n` nodes numbered `0` through `n-1`.547548By Cayley's theorem, there are `n^{n-2}` trees with vertex549set `\{0,1,...,n-1\}`. This constructor chooses one of these uniformly550at random.551552ALGORITHM:553554The algoritm works by generating an `(n-2)`-long555random sequence of numbers chosen independently and uniformly556from `\{0,1,\ldots,n-1\}` and then applies an inverse557Prufer transformation.558559INPUT:560561- ``n`` - number of vertices in the tree562563EXAMPLE::564565sage: G = graphs.RandomTree(10)566sage: G.is_tree()567True568sage: G.show() # long569570TESTS:571572Ensuring that we encounter no unexpected surprise ::573574sage: all( graphs.RandomTree(10).is_tree()575....: for i in range(100) )576True577578"""579from sage.misc.prandom import randint580g = Graph()581582# create random Prufer code583code = [ randint(0,n-1) for i in xrange(n-2) ]584585# We count the number of symbols of each type.586# count[k] is the no. of times k appears in code587#588# (count[k] is set to -1 when the corresponding vertex is not589# available anymore)590count = [ 0 for i in xrange(n) ]591for k in code:592count[k] += 1593594g.add_vertices(range(n))595596for s in code:597for x in range(n):598if count[x] == 0:599break600601count[x] = -1602g.add_edge(x,s)603count[s] -= 1604605# Adding as an edge the last two available vertices606last_edge = [ v for v in range(n) if count[v] != -1 ]607g.add_edge(last_edge)608609return g610611def RandomTreePowerlaw(n, gamma=3, tries=100, seed=None):612"""613Returns a tree with a power law degree distribution. Returns False614on failure.615616From the NetworkX documentation: A trial power law degree sequence617is chosen and then elements are swapped with new elements from a618power law distribution until the sequence makes a tree (size = order619- 1).620621INPUT:622623- ``n`` - number of vertices624625- ``gamma`` - exponent of power law626627- ``tries`` - number of attempts to adjust sequence to628make a tree629630- ``seed`` - for the random number generator631632633EXAMPLE: We show the edge list of a random graph with 10 nodes and634a power law exponent of 2.635636::637638sage: graphs.RandomTreePowerlaw(10, 2).edges(labels=False)639[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (6, 8), (6, 9)]640641::642643sage: G = graphs.RandomTreePowerlaw(15, 2)644sage: if G:645....: G.show() # random output, long time646"""647if seed is None:648seed = current_randstate().long_seed()649import networkx650try:651return Graph(networkx.random_powerlaw_tree(n, gamma, seed=seed, tries=tries))652except networkx.NetworkXError:653return False654655def RandomRegular(d, n, seed=None):656"""657Returns a random d-regular graph on n vertices, or returns False on658failure.659660Since every edge is incident to two vertices, n\*d must be even.661662INPUT:663664- ``n`` - number of vertices665666- ``d`` - degree667668- ``seed`` - for the random number generator669670671EXAMPLE: We show the edge list of a random graph with 8 nodes each672of degree 3.673674::675676sage: graphs.RandomRegular(3, 8).edges(labels=False)677[(0, 1), (0, 4), (0, 7), (1, 5), (1, 7), (2, 3), (2, 5), (2, 6), (3, 4), (3, 6), (4, 5), (6, 7)]678679::680681sage: G = graphs.RandomRegular(3, 20)682sage: if G:683....: G.show() # random output, long time684685REFERENCES:686687.. [KimVu2003] Kim, Jeong Han and Vu, Van H. Generating random regular688graphs. Proc. 35th ACM Symp. on Thy. of Comp. 2003, pp689213-222. ACM Press, San Diego, CA, USA.690http://doi.acm.org/10.1145/780542.780576691692.. [StegerWormald1999] Steger, A. and Wormald, N. Generating random693regular graphs quickly. Prob. and Comp. 8 (1999), pp 377-396.694"""695if seed is None:696seed = current_randstate().long_seed()697import networkx698try:699N = networkx.random_regular_graph(d, n, seed=seed)700if N is False: return False701return Graph(N, sparse=True)702except Exception:703return False704705def RandomShell(constructor, seed=None):706"""707Returns a random shell graph for the constructor given.708709INPUT:710711- ``constructor`` - a list of 3-tuples (n,m,d), each712representing a shell713714- ``n`` - the number of vertices in the shell715716- ``m`` - the number of edges in the shell717718- ``d`` - the ratio of inter (next) shell edges to719intra shell edges720721- ``seed`` - for the random number generator722723724EXAMPLE::725726sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)])727sage: G.edges(labels=False)728[(0, 3), (0, 7), (0, 8), (1, 2), (1, 5), (1, 8), (1, 9), (3, 6), (3, 11), (4, 6), (4, 7), (4, 8), (4, 21), (5, 8), (5, 9), (6, 9), (6, 10), (7, 8), (7, 9), (8, 18), (10, 11), (10, 13), (10, 19), (10, 22), (10, 26), (11, 18), (11, 26), (11, 28), (12, 13), (12, 14), (12, 28), (12, 29), (13, 16), (13, 21), (13, 29), (14, 18), (16, 20), (17, 18), (17, 26), (17, 28), (18, 19), (18, 22), (18, 27), (18, 28), (19, 23), (19, 25), (19, 28), (20, 22), (24, 26), (24, 27), (25, 27), (25, 29)]729sage: G.show() # long time730"""731if seed is None:732seed = current_randstate().long_seed()733import networkx734return Graph(networkx.random_shell_graph(constructor, seed=seed))735736def RandomToleranceGraph(n):737r"""738Returns a random tolerance graph.739740The random tolerance graph is built from a random tolerance representation741by using the function `ToleranceGraph`. This representation is a list742`((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where `k = n-1` and743`I_i = (l_i,r_i)` denotes a random interval and `t_i` a random positive744value. The width of the representation is limited to n**2 * 2**n.745746.. NOTE::747748The vertices are named 0, 1, ..., n-1. The tolerance representation used749to create the graph is saved with the graph and can be recovered using750``get_vertex()`` or ``get_vertices()``.751752INPUT:753754- ``n`` -- number of vertices of the random graph.755756EXAMPLE:757758Every tolerance graph is perfect. Hence, the chromatic number is equal to759the clique number ::760761sage: g = graphs.RandomToleranceGraph(8)762sage: g.clique_number() == g.chromatic_number()763True764765TEST:766767sage: g = graphs.RandomToleranceGraph(-2)768Traceback (most recent call last):769...770ValueError: The number `n` of vertices must be >= 0.771"""772from sage.misc.prandom import randint773from sage.graphs.generators.intersection import ToleranceGraph774775if n<0:776raise ValueError('The number `n` of vertices must be >= 0.')777778W = n**2 * 2**n779780tolrep = [tuple(sorted((randint(0,W), randint(0,W)))) + (randint(0,W),) for i in range(n)]781782return ToleranceGraph(tolrep)783784785786