def RandomGNM(n, m, dense=False, seed=None): """ Returns a graph randomly picked out of all graphs on n vertices with m edges. INPUT: - ``n`` - number of vertices. - ``m`` - number of edges. - ``dense`` - whether to use NetworkX's dense_gnm_random_graph or gnm_random_graph EXAMPLES: We show the edge list of a random graph on 5 nodes with 10 edges. :: sage: graphs.RandomGNM(5, 10).edges(labels=False) [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] We plot a random graph on 12 nodes with m = 12. :: sage: gnm = graphs.RandomGNM(12, 12) sage: gnm.show() # long time We view many random graphs using a graphics array:: sage: g = [] sage: j = [] sage: for i in range(9): ... k = graphs.RandomGNM(i+3, i^2-i) ... g.append(k) ... sage: for i in range(3): ... n = [] ... for m in range(3): ... n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ... j.append(n) ... sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ if seed is None: seed = current_randstate().long_seed() import networkx if dense: return graph.Graph(networkx.dense_gnm_random_graph(n, m, seed=seed)) else: return graph.Graph(networkx.gnm_random_graph(n, m, seed=seed))
def GemGraph(): """ Return a gem graph with 5 nodes. A gem graph is a fan graph (4,1). PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the gem graph is drawn as a gem, with the sharp part on the bottom. EXAMPLES: Construct and show a gem graph:: sage: g = graphs.GemGraph() sage: g.show() # long time """ pos_dict = { 0: (0.5, 0), 1: (0, 0.75), 2: (0.25, 1), 3: (0.75, 1), 4: (1, 0.75) } edges = [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (2, 3), (3, 4)] return graph.Graph(edges, pos=pos_dict, name="Gem Graph")
def RandomShell(constructor, seed=None): """ Returns a random shell graph for the constructor given. INPUT: - ``constructor`` - a list of 3-tuples (n,m,d), each representing a shell - ``n`` - the number of vertices in the shell - ``m`` - the number of edges in the shell - ``d`` - the ratio of inter (next) shell edges to intra shell edges - ``seed`` - for the random number generator EXAMPLE:: sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)]) sage: G.edges(labels=False) [(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)] sage: G.show() # long time """ if seed is None: seed = current_randstate().long_seed() import networkx return graph.Graph(networkx.random_shell_graph(constructor, seed=seed))
def IcosahedralGraph(): """ Returns an Icosahedral graph (with 12 nodes). The regular icosahedron is a 20-sided triangular polyhedron. The icosahedral graph corresponds to the connectivity of the vertices of the icosahedron. It is dual to the dodecahedral graph. The icosahedron is symmetric, so the spring-layout algorithm will be very effective for display. PLOTTING: The Icosahedral graph should be viewed in 3 dimensions. We chose to use the default spring-layout algorithm here, so that multiple iterations might yield a different point of reference for the user. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a string argument will be added to select the flat spring-layout over a future implementation. EXAMPLES: Construct and show an Octahedral graph :: sage: g = graphs.IcosahedralGraph() sage: g.show() # long time Create several icosahedral graphs in a Sage graphics array. They will be drawn differently due to the use of the spring-layout algorithm. :: sage: g = [] sage: j = [] sage: for i in range(9): ... k = graphs.IcosahedralGraph() ... g.append(k) ... sage: for i in range(3): ... n = [] ... for m in range(3): ... n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ... j.append(n) ... sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ import networkx G = networkx.icosahedral_graph() pos = {} r1 = 5 r2 = 2 for i, v in enumerate([2, 8, 7, 11, 4, 6]): i = i + .5 pos[v] = (r1 * cos(i * pi / 3), r1 * sin(i * pi / 3)) for i, v in enumerate([1, 9, 0, 10, 5, 3]): i = i + .5 pos[v] = (r2 * cos(i * pi / 3), r2 * sin(i * pi / 3)) return graph.Graph(G, name="Icosahedron", pos=pos)
def ClawGraph(): """ Returns a claw graph. A claw graph is named for its shape. It is actually a complete bipartite graph with (n1, n2) = (1, 3). PLOTTING: See CompleteBipartiteGraph. EXAMPLES: Show a Claw graph :: sage: (graphs.ClawGraph()).show() # long time Inspect a Claw graph :: sage: G = graphs.ClawGraph() sage: G Claw graph: Graph on 4 vertices """ edge_list = [(0, 1), (0, 2), (0, 3)] pos_dict = {0:(0,1),1:(-1,0),2:(0,0),3:(1,0)} return graph.Graph(edge_list, pos=pos_dict, name="Claw graph")
def HouseGraph(): """ Returns a house graph with 5 nodes. A house graph is named for its shape. It is a triangle (roof) over a square (walls). This constructor depends on NetworkX numeric labeling. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the house graph is drawn with the first node in the lower-left corner of the house, the second in the lower-right corner of the house. The third node is in the upper-left corner connecting the roof to the wall, and the fourth is in the upper-right corner connecting the roof to the wall. The fifth node is the top of the roof, connected only to the third and fourth. EXAMPLES: Construct and show a house graph :: sage: g = graphs.HouseGraph() sage: g.show() # long time """ pos_dict = {0: (-1, 0), 1: (1, 0), 2: (-1, 1), 3: (1, 1), 4: (0, 2)} import networkx G = networkx.house_graph() return graph.Graph(G, pos=pos_dict, name="House Graph")
def DiamondGraph(): """ Returns a diamond graph with 4 nodes. A diamond graph is a square with one pair of diagonal nodes connected. This constructor depends on NetworkX numeric labeling. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the diamond graph is drawn as a diamond, with the first node on top, second on the left, third on the right, and fourth on the bottom; with the second and third node connected. EXAMPLES: Construct and show a diamond graph :: sage: g = graphs.DiamondGraph() sage: g.show() # long time """ pos_dict = {0: (0, 1), 1: (-1, 0), 2: (1, 0), 3: (0, -1)} edges = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)] return graph.Graph(edges, pos=pos_dict, name="Diamond Graph")
def HouseXGraph(): """ Returns a house X graph with 5 nodes. A house X graph is a house graph with two additional edges. The upper-right corner is connected to the lower-left. And the upper-left corner is connected to the lower-right. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the house X graph is drawn with the first node in the lower-left corner of the house, the second in the lower-right corner of the house. The third node is in the upper-left corner connecting the roof to the wall, and the fourth is in the upper-right corner connecting the roof to the wall. The fifth node is the top of the roof, connected only to the third and fourth. EXAMPLES: Construct and show a house X graph :: sage: g = graphs.HouseXGraph() sage: g.show() # long time """ pos_dict = {0:(-1,0),1:(1,0),2:(-1,1),3:(1,1),4:(0,2)} edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3), (2, 4), (3, 4)] return graph.Graph(edges, pos=pos_dict, name="House Graph")
def RandomLobster(n, p, q, seed=None): """ Returns a random lobster. A lobster is a tree that reduces to a caterpillar when pruning all leaf vertices. A caterpillar is a tree that reduces to a path when pruning all leaf vertices (q=0). INPUT: - ``n`` - expected number of vertices in the backbone - ``p`` - probability of adding an edge to the backbone - ``q`` - probability of adding an edge (claw) to the arms - ``seed`` - for the random number generator EXAMPLE: We show the edge list of a random graph with 3 backbone nodes and probabilities `p = 0.7` and `q = 0.3`:: sage: graphs.RandomLobster(3, 0.7, 0.3).edges(labels=False) [(0, 1), (1, 2)] :: sage: G = graphs.RandomLobster(9, .6, .3) sage: G.show() # long time """ if seed is None: seed = current_randstate().long_seed() import networkx return graph.Graph(networkx.random_lobster(n, p, q, seed=seed))
def GridGraph(dim_list): """ Returns an n-dimensional grid graph. INPUT: - ``dim_list`` - a list of integers representing the number of nodes to extend in each dimension. PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dictionary is specified. EXAMPLES:: sage: G = graphs.GridGraph([2,3,4]) sage: G.show() # long time :: sage: C = graphs.CubeGraph(4) sage: G = graphs.GridGraph([2,2,2,2]) sage: C.show() # long time sage: G.show() # long time """ import networkx dim = [int(a) for a in dim_list] G = networkx.grid_graph(dim) return graph.Graph(G, name="Grid Graph for %s" % dim)
def DegreeSequenceExpected(deg_sequence, seed=None): """ Returns a random graph with expected given degree sequence. Raises a NetworkX error if the proposed degree sequence cannot be that of a graph. One requirement is that the sum of the degrees must be even, since every edge must be incident with two vertices. INPUT: - ``deg_sequence`` - a list of integers with each entry corresponding to the expected degree of a different vertex. - ``seed`` - for the random number generator. EXAMPLE:: sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3]) sage: G.edges(labels=False) [(0, 2), (0, 3), (1, 1), (1, 4), (2, 3), (2, 4), (3, 4), (4, 4)] sage: G.show() # long time REFERENCE: - [1] Chung, Fan and Lu, L. Connected components in random graphs with given expected degree sequences. Ann. Combinatorics (6), 2002 pp. 125-145. """ if seed is None: seed = current_randstate().long_seed() import networkx return graph.Graph(networkx.expected_degree_graph( [int(i) for i in deg_sequence], seed=seed), loops=True)
def EmptyGraph(): """ Returns an empty graph (0 nodes and 0 edges). This is useful for constructing graphs by adding edges and vertices individually or in a loop. PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dictionary is specified. EXAMPLES: Add one vertex to an empty graph and then show:: sage: empty1 = graphs.EmptyGraph() sage: empty1.add_vertex() 0 sage: empty1.show() # long time Use for loops to build a graph from an empty graph:: sage: empty2 = graphs.EmptyGraph() sage: for i in range(5): ....: empty2.add_vertex() # add 5 nodes, labeled 0-4 0 1 2 3 4 sage: for i in range(3): ....: empty2.add_edge(i,i+1) # add edges {[0:1],[1:2],[2:3]} sage: for i in range(4)[1:]: ....: empty2.add_edge(4,i) # add edges {[1:4],[2:4],[3:4]} sage: empty2.show() # long time """ return graph.Graph(sparse=True)
def Grid2dGraph(n1, n2): r""" Returns a `2`-dimensional grid graph with `n_1n_2` nodes (`n_1` rows and `n_2` columns). A 2d grid graph resembles a `2` dimensional grid. All inner nodes are connected to their `4` neighbors. Outer (non-corner) nodes are connected to their `3` neighbors. Corner nodes are connected to their 2 neighbors. This constructor depends on NetworkX numeric labels. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, nodes are labelled in (row, column) pairs with `(0, 0)` in the top left corner. Edges will always be horizontal and vertical - another advantage of filling the position dictionary. EXAMPLES: Construct and show a grid 2d graph Rows = `5`, Columns = `7` :: sage: g = graphs.Grid2dGraph(5,7) sage: g.show() # long time TESTS: Senseless input:: sage: graphs.Grid2dGraph(5,0) Traceback (most recent call last): ... ValueError: Parameters n1 and n2 must be positive integers ! sage: graphs.Grid2dGraph(-1,0) Traceback (most recent call last): ... ValueError: Parameters n1 and n2 must be positive integers ! The graph name contains the dimension:: sage: g = graphs.Grid2dGraph(5,7) sage: g.name() '2D Grid Graph for [5, 7]' """ if n1 <= 0 or n2 <= 0: raise ValueError("Parameters n1 and n2 must be positive integers !") pos_dict = {} for i in range(n1): y = -i for j in range(n2): x = j pos_dict[i, j] = (x, y) import networkx G = networkx.grid_2d_graph(n1, n2) return graph.Graph(G, pos=pos_dict, name="2D Grid Graph for " + str([n1, n2]))
def RandomHolmeKim(n, m, p, seed=None): """ Returns a random graph generated by the Holme and Kim algorithm for graphs with power law degree distribution and approximate average clustering. INPUT: - ``n`` - number of vertices. - ``m`` - number of random edges to add for each new node. - ``p`` - probability of adding a triangle after adding a random edge. - ``seed`` - for the random number generator. From the NetworkX documentation: The average clustering has a hard time getting above a certain cutoff that depends on m. This cutoff is often quite low. Note that the transitivity (fraction of triangles to possible triangles) seems to go down with network size. It is essentially the Barabasi-Albert growth model with an extra step that each random edge is followed by a chance of making an edge to one of its neighbors too (and thus a triangle). This algorithm improves on B-A in the sense that it enables a higher average clustering to be attained if desired. It seems possible to have a disconnected graph with this algorithm since the initial m nodes may not be all linked to a new node on the first iteration like the BA model. EXAMPLE: We show the edge list of a random graph on 8 nodes with 2 random edges per node and a probability `p = 0.5` of forming triangles. :: sage: graphs.RandomHolmeKim(8, 2, 0.5).edges(labels=False) [(0, 2), (0, 5), (1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (2, 7), (3, 4), (3, 6), (3, 7), (4, 5)] :: sage: G = graphs.RandomHolmeKim(12, 3, .3) sage: G.show() # long time REFERENCE: - [1] Holme, P. and Kim, B.J. Growing scale-free networks with tunable clustering, Phys. Rev. E (2002). vol 65, no 2, 026107. """ if seed is None: seed = current_randstate().long_seed() import networkx return graph.Graph(networkx.powerlaw_cluster_graph(n, m, p, seed=seed))
def white_graph(self): """ Return the white graph of a non-split link projection. This method generates a multigraph whose vertices correspond to the faces of the diagram, with an edge joining two vertices whenever the corresponding faces contain opposite corners at some crossing. To avoid hashability issues, the vertex corresponding to a face is the index of the face in the list returned by Link.faces(). According to the conventions of "Gordon, C. McA. and Litherland, R. A, 'On the signature of a link', Inventiones math. 47, 23-69 (1978)", in a checkerboard coloring of a link diagram the unbounded region is always the first white region. Of course, the choice of which region is unbounded is arbitrary; it is just a matter of which region on S^2 contains the point at infinity. In this method an equivalent arbitrary choice is made by just returning the second component of the multigraph, as determined by Graph.connected_components(). (Empirically, the second component tends to be smaller than the first.) Note that this may produce a meaningless result in the case of a split link diagram. Consequently if the diagram is split, i.e if the multigraph has more than 2 components, a ValueError is raised:: sage: K=Link('5_1') sage: K.white_graph() Subgraph of (): Multi-graph on 2 vertices """ # Map corners (i.e. CrossingStrands) to faces. face_of = dict((corner, n) for n, face in enumerate(self.faces()) for corner in face) # Create the edges, labeled with crossing and sign. edges = [] for c in self.crossings: edges.append( (face_of[CrossingStrand(c, 0)], face_of[CrossingStrand(c, 2)], { 'crossing': c, 'sign': 1 })) edges.append( (face_of[CrossingStrand(c, 1)], face_of[CrossingStrand(c, 3)], { 'crossing': c, 'sign': -1 })) # Build the graph. G = graph.Graph(edges, multiedges=True) components = G.connected_components() if len(components) > 2: raise ValueError('The link diagram is split.') return G.subgraph(components[1])
def LollipopGraph(n1, n2): """ Returns a lollipop graph with n1+n2 nodes. A lollipop graph is a path graph (order n2) connected to a complete graph (order n1). (A barbell graph minus one of the bells). This constructor depends on NetworkX numeric labels. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the complete graph will be drawn in the lower-left corner with the (n1)th node at a 45 degree angle above the right horizontal center of the complete graph, leading directly into the path graph. EXAMPLES: Construct and show a lollipop graph Candy = 13, Stick = 4 :: sage: g = graphs.LollipopGraph(13,4) sage: g.show() # long time Create several lollipop graphs in a Sage graphics array :: sage: g = [] sage: j = [] sage: for i in range(6): ....: k = graphs.LollipopGraph(i+3,4) ....: g.append(k) sage: for i in range(2): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ pos_dict = {} for i in range(n1): x = float(cos((pi / 4) - ((2 * pi) / n1) * i) - n2 / 2 - 1) y = float(sin((pi / 4) - ((2 * pi) / n1) * i) - n2 / 2 - 1) j = n1 - 1 - i pos_dict[j] = (x, y) for i in range(n1, n1 + n2): x = float(i - n1 - n2 / 2 + 1) y = float(i - n1 - n2 / 2 + 1) pos_dict[i] = (x, y) G = graph.Graph(dict((i, range(i + 1, n1)) for i in range(n1)), pos=pos_dict, name="Lollipop Graph") G.add_vertices(range(n1 + n2)) G.add_path(range(n1 - 1, n1 + n2)) return G
def ButterflyGraph(): r""" Returns the butterfly graph. Let `C_3` be the cycle graph on 3 vertices. The butterfly or bowtie graph is obtained by joining two copies of `C_3` at a common vertex, resulting in a graph that is isomorphic to the friendship graph `F_2`. For more information, see this `Wikipedia article on the butterfly graph <http://en.wikipedia.org/wiki/Butterfly_graph>`_. .. SEEALSO:: - :meth:`GraphGenerators.FriendshipGraph` EXAMPLES: The butterfly graph is a planar graph on 5 vertices and having 6 edges. :: sage: G = graphs.ButterflyGraph(); G Butterfly graph: Graph on 5 vertices sage: G.show() # long time sage: G.is_planar() True sage: G.order() 5 sage: G.size() 6 It has diameter 2, girth 3, and radius 1. :: sage: G.diameter() 2 sage: G.girth() 3 sage: G.radius() 1 The butterfly graph is Eulerian, with chromatic number 3. :: sage: G.is_eulerian() True sage: G.chromatic_number() 3 """ edge_dict = { 0: [3,4], 1: [2,4], 2: [4], 3: [4]} pos_dict = { 0: [-1, 1], 1: [1, 1], 2: [1, -1], 3: [-1, -1], 4: [0, 0]} return graph.Graph(edge_dict, pos=pos_dict, name="Butterfly graph")
def HexahedralGraph(): """ Returns a hexahedral graph (with 8 nodes). A regular hexahedron is a 6-sided cube. The hexahedral graph corresponds to the connectivity of the vertices of the hexahedron. This graph is equivalent to a 3-cube. PLOTTING: The hexahedral graph should be viewed in 3 dimensions. We chose to use the default spring-layout algorithm here, so that multiple iterations might yield a different point of reference for the user. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a string argument will be added to select the flat spring-layout over a future implementation. EXAMPLES: Construct and show a Hexahedral graph :: sage: g = graphs.HexahedralGraph() sage: g.show() # long time Create several hexahedral graphs in a Sage graphics array. They will be drawn differently due to the use of the spring-layout algorithm. :: sage: g = [] sage: j = [] sage: for i in range(9): ... k = graphs.HexahedralGraph() ... g.append(k) ... sage: for i in range(3): ... n = [] ... for m in range(3): ... n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ... j.append(n) ... sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ return graph.Graph({0:[1,3,4], 1:[2,5], 2:[3,6], 3:[7], 4:[5,7],\ 5:[6], 6:[7]}, name="Hexahedron", pos = { 0 : (0,0), 1 : (1,0), 3 : (0,1), 2 : (1,1), 4 : (.5,.5), 5 : (1.5,.5), 7 : (.5,1.5), 6 : (1.5,1.5) })
def TetrahedralGraph(): """ Returns a tetrahedral graph (with 4 nodes). A tetrahedron is a 4-sided triangular pyramid. The tetrahedral graph corresponds to the connectivity of the vertices of the tetrahedron. This graph is equivalent to a wheel graph with 4 nodes and also a complete graph on four nodes. (See examples below). PLOTTING: The tetrahedral graph should be viewed in 3 dimensions. We chose to use the default spring-layout algorithm here, so that multiple iterations might yield a different point of reference for the user. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a string argument will be added to select the flat spring-layout over a future implementation. EXAMPLES: Construct and show a Tetrahedral graph :: sage: g = graphs.TetrahedralGraph() sage: g.show() # long time The following example requires networkx:: sage: import networkx as NX Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout algorithm below in a Sage graphics array:: sage: tetra_pos = graphs.TetrahedralGraph() sage: tetra_spring = Graph(NX.tetrahedral_graph()) sage: wheel = graphs.WheelGraph(4) sage: complete = graphs.CompleteGraph(4) sage: g = [tetra_pos, tetra_spring, wheel, complete] sage: j = [] sage: for i in range(2): ... n = [] ... for m in range(2): ... n.append(g[i + m].plot(vertex_size=50, vertex_labels=False)) ... j.append(n) sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ import networkx G = networkx.tetrahedral_graph() return graph.Graph(G, name="Tetrahedron", pos={ 0: (0, 0), 1: (0, 1), 2: (cos(3.5 * pi / 3), sin(3.5 * pi / 3)), 3: (cos(5.5 * pi / 3), sin(5.5 * pi / 3)) })
def CircularLadderGraph(n): """ Returns a circular ladder graph with 2\*n nodes. A Circular ladder graph is a ladder graph that is connected at the ends, i.e.: a ladder bent around so that top meets bottom. Thus it can be described as two parallel cycle graphs connected at each corresponding node pair. This constructor depends on NetworkX numeric labels. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the circular ladder graph is displayed as an inner and outer cycle pair, with the first n nodes drawn on the inner circle. The first (0) node is drawn at the top of the inner-circle, moving clockwise after that. The outer circle is drawn with the (n+1)th node at the top, then counterclockwise as well. EXAMPLES: Construct and show a circular ladder graph with 26 nodes :: sage: g = graphs.CircularLadderGraph(13) sage: g.show() # long time Create several circular ladder graphs in a Sage graphics array :: sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.CircularLadderGraph(i+3) ....: g.append(k) sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ pos_dict = {} for i in range(n): x = float(cos((pi / 2) + ((2 * pi) / n) * i)) y = float(sin((pi / 2) + ((2 * pi) / n) * i)) pos_dict[i] = [x, y] for i in range(n, 2 * n): x = float(2 * (cos((pi / 2) + ((2 * pi) / n) * (i - n)))) y = float(2 * (sin((pi / 2) + ((2 * pi) / n) * (i - n)))) pos_dict[i] = (x, y) import networkx G = networkx.circular_ladder_graph(n) return graph.Graph(G, pos=pos_dict, name="Circular Ladder graph")
def GridGraph(dim_list): """ Returns an n-dimensional grid graph. INPUT: - ``dim_list`` - a list of integers representing the number of nodes to extend in each dimension. PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dictionary is specified. EXAMPLES:: sage: G = graphs.GridGraph([2,3,4]) sage: G.show() # long time :: sage: C = graphs.CubeGraph(4) sage: G = graphs.GridGraph([2,2,2,2]) sage: C.show() # long time sage: G.show() # long time TESTS: The graph name contains the dimension:: sage: g = graphs.GridGraph([5, 7]) sage: g.name() 'Grid Graph for [5, 7]' sage: g = graphs.GridGraph([2, 3, 4]) sage: g.name() 'Grid Graph for [2, 3, 4]' sage: g = graphs.GridGraph([2, 4, 3]) sage: g.name() 'Grid Graph for [2, 4, 3]' All dimensions must be positive integers:: sage: g = graphs.GridGraph([2,-1,3]) Traceback (most recent call last): ... ValueError: All dimensions must be positive integers ! """ import networkx dim = [int(a) for a in dim_list] if any(a <= 0 for a in dim): raise ValueError("All dimensions must be positive integers !") # We give a copy of dim to networkx because it modifies the list G = networkx.grid_graph(list(dim)) return graph.Graph(G, name="Grid Graph for " + str(dim))
def RandomBarabasiAlbert(n, m, seed=None): u""" Return a random graph created using the Barabasi-Albert preferential attachment model. A graph with m vertices and no edges is initialized, and a graph of n vertices is grown by attaching new vertices each with m edges that are attached to existing vertices, preferentially with high degree. INPUT: - ``n`` - number of vertices in the graph - ``m`` - number of edges to attach from each new node - ``seed`` - for random number generator EXAMPLES: We show the edge list of a random graph on 6 nodes with m = 2. :: sage: graphs.RandomBarabasiAlbert(6,2).edges(labels=False) [(0, 2), (0, 3), (0, 4), (1, 2), (2, 3), (2, 4), (2, 5), (3, 5)] We plot a random graph on 12 nodes with m = 3. :: sage: ba = graphs.RandomBarabasiAlbert(12,3) sage: ba.show() # long time We view many random graphs using a graphics array:: sage: g = [] sage: j = [] sage: for i in range(1,10): ... k = graphs.RandomBarabasiAlbert(i+3, 3) ... g.append(k) ... sage: for i in range(3): ... n = [] ... for m in range(3): ... n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ... j.append(n) ... sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ if seed is None: seed = current_randstate().long_seed() import networkx return graph.Graph(networkx.barabasi_albert_graph(n, m, seed=seed))
def spanning_trees(G): """ Function 'span' from Read paper """ if G.is_connected(): part_G = graph.Graph([]) part_G.add_vertices(G.vertices()) part_G.add_edges(bridge_finding.find_bridges(G)) return rec(part_G, G) else: return []
def RandomRegular(d, n, seed=None): """ Returns a random d-regular graph on n vertices, or returns False on failure. Since every edge is incident to two vertices, n\*d must be even. INPUT: - ``n`` - number of vertices - ``d`` - degree - ``seed`` - for the random number generator EXAMPLE: We show the edge list of a random graph with 8 nodes each of degree 3. :: sage: graphs.RandomRegular(3, 8).edges(labels=False) [(0, 1), (0, 4), (0, 7), (1, 5), (1, 7), (2, 3), (2, 5), (2, 6), (3, 4), (3, 6), (4, 5), (6, 7)] :: sage: G = graphs.RandomRegular(3, 20) sage: if G: ... G.show() # random output, long time REFERENCES: - [1] Kim, Jeong Han and Vu, Van H. Generating random regular graphs. Proc. 35th ACM Symp. on Thy. of Comp. 2003, pp 213-222. ACM Press, San Diego, CA, USA. http://doi.acm.org/10.1145/780542.780576 - [2] Steger, A. and Wormald, N. Generating random regular graphs quickly. Prob. and Comp. 8 (1999), pp 377-396. """ if seed is None: seed = current_randstate().long_seed() import networkx try: N = networkx.random_regular_graph(d, n, seed=seed) if N is False: return False return graph.Graph(N, sparse=True) except StandardError: return False
def RandomNewmanWattsStrogatz(n, k, p, seed=None): """ Returns a Newman-Watts-Strogatz small world random graph on n vertices. From the NetworkX documentation: First create a ring over n nodes. Then each node in the ring is connected with its k nearest neighbors. Then shortcuts are created by adding new edges as follows: for each edge u-v in the underlying "n-ring with k nearest neighbors"; with probability p add a new edge u-w with randomly-chosen existing node w. In contrast with watts_strogatz_graph(), no edges are removed. INPUT: - ``n`` - number of vertices. - ``k`` - each vertex is connected to its k nearest neighbors - ``p`` - the probability of adding a new edge for each edge - ``seed`` - for the random number generator EXAMPLE: We show the edge list of a random graph on 7 nodes with 2 "nearest neighbors" and probability `p = 0.2`:: sage: graphs.RandomNewmanWattsStrogatz(7, 2, 0.2).edges(labels=False) [(0, 1), (0, 2), (0, 3), (0, 6), (1, 2), (2, 3), (2, 4), (3, 4), (3, 6), (4, 5), (5, 6)] :: sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) sage: G.show() # long time REFERENCE: - [1] Newman, M.E.J., Watts, D.J. and Strogatz, S.H. Random graph models of social networks. Proc. Nat. Acad. Sci. USA 99, 2566-2572. """ if seed is None: seed = current_randstate().long_seed() import networkx return graph.Graph(networkx.newman_watts_strogatz_graph(n, k, p, seed=seed))
def LadderGraph(n): """ Returns a ladder graph with 2\*n nodes. A ladder graph is a basic structure that is typically displayed as a ladder, i.e.: two parallel path graphs connected at each corresponding node pair. This constructor depends on NetworkX numeric labels. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each ladder graph will be displayed horizontally, with the first n nodes displayed left to right on the top horizontal line. EXAMPLES: Construct and show a ladder graph with 14 nodes :: sage: g = graphs.LadderGraph(7) sage: g.show() # long time Create several ladder graphs in a Sage graphics array :: sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.LadderGraph(i+2) ....: g.append(k) sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ pos_dict = {} for i in range(n): pos_dict[i] = (i, 1) for i in range(n, 2 * n): x = i - n pos_dict[i] = (x, 0) import networkx G = networkx.ladder_graph(n) return graph.Graph(G, pos=pos_dict, name="Ladder graph")
def DegreeSequence(deg_sequence): """ Returns a graph with the given degree sequence. Raises a NetworkX error if the proposed degree sequence cannot be that of a graph. Graph returned is the one returned by the Havel-Hakimi algorithm, which constructs a simple graph by connecting vertices of highest degree to other vertices of highest degree, resorting the remaining vertices by degree and repeating the process. See Theorem 1.4 in [1]. INPUT: - ``deg_sequence`` - a list of integers with each entry corresponding to the degree of a different vertex. EXAMPLES:: sage: G = graphs.DegreeSequence([3,3,3,3]) sage: G.edges(labels=False) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] sage: G.show() # long time :: sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) sage: G.show() # long time :: sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4]) sage: G.show() # long time :: sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1]) sage: G.show() # long time REFERENCE: - [1] Chartrand, G. and Lesniak, L. Graphs and Digraphs. Chapman and Hall/CRC, 1996. """ import networkx return graph.Graph(networkx.havel_hakimi_graph([int(i) for i in deg_sequence]))
def DegreeSequenceConfigurationModel(deg_sequence, seed=None): """ Returns a random pseudograph with the given degree sequence. Raises a NetworkX error if the proposed degree sequence cannot be that of a graph with multiple edges and loops. One requirement is that the sum of the degrees must be even, since every edge must be incident with two vertices. INPUT: - ``deg_sequence`` - a list of integers with each entry corresponding to the expected degree of a different vertex. - ``seed`` - for the random number generator. EXAMPLES:: sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) sage: G.adjacency_matrix() [0 1] [1 0] Note: as of this writing, plotting of loops and multiple edges is not supported, and the output is allowed to contain both types of edges. :: sage: G = graphs.DegreeSequenceConfigurationModel([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) sage: G.edges(labels=False) [(0, 2), (0, 10), (0, 15), (1, 6), (1, 16), (1, 17), (2, 5), (2, 19), (3, 7), (3, 14), (3, 14), (4, 9), (4, 13), (4, 19), (5, 6), (5, 15), (6, 11), (7, 11), (7, 17), (8, 11), (8, 18), (8, 19), (9, 12), (9, 13), (10, 15), (10, 18), (12, 13), (12, 16), (14, 17), (16, 18)] sage: G.show() # long time REFERENCE: - [1] Newman, M.E.J. The Structure and function of complex networks, SIAM Review vol. 45, no. 2 (2003), pp. 167-256. """ if seed is None: seed = current_randstate().long_seed() import networkx return graph.Graph(networkx.configuration_model( [int(i) for i in deg_sequence], seed=seed), loops=True, multiedges=True, sparse=True)
def RandomTreePowerlaw(n, gamma=3, tries=100, seed=None): """ Returns a tree with a power law degree distribution. Returns False on failure. From the NetworkX documentation: A trial power law degree sequence is chosen and then elements are swapped with new elements from a power law distribution until the sequence makes a tree (size = order - 1). INPUT: - ``n`` - number of vertices - ``gamma`` - exponent of power law - ``tries`` - number of attempts to adjust sequence to make a tree - ``seed`` - for the random number generator EXAMPLE: We show the edge list of a random graph with 10 nodes and a power law exponent of 2. :: sage: graphs.RandomTreePowerlaw(10, 2).edges(labels=False) [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (6, 8), (6, 9)] :: sage: G = graphs.RandomTreePowerlaw(15, 2) sage: if G: ... G.show() # random output, long time """ if seed is None: seed = current_randstate().long_seed() import networkx try: return graph.Graph( networkx.random_powerlaw_tree(n, gamma, seed=seed, tries=tries)) except networkx.NetworkXError: return False
def black_graph(self): """ Returns the black graph of K. If the black graph is disconnected (which can only happen for a split link diagram), returns one connected component. The edges are labeled by the crossings they correspond to. Example:: sage: K=Link('5_1') sage: K.black_graph() Subgraph of (): Multi-graph on 2 vertices WARNING: While there is also a "white_graph" method, it need not be the case that these two graphs are complementary in the expected way. """ faces = [] for x in self.faces(): l = [] for y in x: l.append((y[0], y[1])) l.append((y[0], (y[1] + 1) % 4)) faces.append(l) coords = list() for i in range(len(faces) - 1): for j in range(i + 1, len(faces)): a = set(faces[i]) b = set(faces[j]) s = a.union(b) for x in range(len(self.crossings)): crossings = [ self.crossings[x][0], self.crossings[x][1], self.crossings[x][2], self.crossings[x][3] ] total = set(crossings) if total.issubset(s): coords.append( (tuple(faces[i]), tuple(faces[j]), self.crossings[x])) #label by the crossing. G = graph.Graph(coords, multiedges=True) component = G.connected_components(sort=False)[1] G = G.subgraph(component) return G