def CompleteBipartiteGraph(p, q, set_position=True): r""" Return a Complete Bipartite Graph on `p + q` vertices. A Complete Bipartite Graph is a graph with its vertices partitioned into two groups, `V_1 = \{0,...,p-1\}` and `V_2 = \{p,...,p+q-1\}`. Each `u \in V_1` is connected to every `v \in V_2`. INPUT: - ``p,q`` -- number of vertices in each side - ``set_position`` -- boolean (default ``True``); if set to ``True``, we assign positions to the vertices so that the set of cardinality `p` is on the line `y=1` and the set of cardinality `q` is on the line `y=0`. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each complete bipartite graph will be displayed with the first `p` nodes on the top row (at `y=1`) from left to right. The remaining `q` nodes appear at `y=0`, also from left to right. The shorter row (partition with fewer nodes) is stretched to the same length as the longer row, unless the shorter row has 1 node; in which case it is centered. The `x` values in the plot are in domain `[0, \max(p, q)]`. In the Complete Bipartite graph, there is a visual difference in using the spring-layout algorithm vs. the position dictionary used in this constructor. The position dictionary flattens the graph and separates the partitioned nodes, making it clear which nodes an edge is connected to. The Complete Bipartite graph plotted with the spring-layout algorithm tends to center the nodes in `p` (see ``spring_med`` in examples below), thus overlapping its nodes and edges, making it typically hard to decipher. Filling the position dictionary in advance adds `O(n)` to the constructor. Feel free to race the constructors below in the examples section. The much larger difference is the time added by the spring-layout algorithm when plotting. (Also shown in the example below). The spring model is typically described as `O(n^3)`, as appears to be the case in the NetworkX source code. EXAMPLES: Two ways of constructing the complete bipartite graph, using different layout algorithms:: sage: import networkx sage: n = networkx.complete_bipartite_graph(389, 157); spring_big = Graph(n) # long time sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157) # long time Compare the plotting:: sage: n = networkx.complete_bipartite_graph(11, 17) sage: spring_med = Graph(n) sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17) Notice here how the spring-layout tends to center the nodes of `n1`:: sage: spring_med.show() # long time sage: posdict_med.show() # long time View many complete bipartite graphs with a Sage Graphics Array, with this constructor (i.e., the position dictionary filled):: sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.CompleteBipartiteGraph(i+1,4) ....: 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 = graphics_array(j) sage: G.show() # long time We compare to plotting with the spring-layout algorithm:: sage: g = [] sage: j = [] sage: for i in range(9): ....: spr = networkx.complete_bipartite_graph(i+1,4) ....: k = Graph(spr) ....: 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 = graphics_array(j) sage: G.show() # long time :trac:`12155`:: sage: graphs.CompleteBipartiteGraph(5,6).complement() complement(Complete bipartite graph of order 5+6): Graph on 11 vertices TESTS: Prevent negative dimensions (:trac:`18530`):: sage: graphs.CompleteBipartiteGraph(-1,1) Traceback (most recent call last): ... ValueError: the arguments p(=-1) and q(=1) must be positive integers sage: graphs.CompleteBipartiteGraph(1,-1) Traceback (most recent call last): ... ValueError: the arguments p(=1) and q(=-1) must be positive integers """ if p < 0 or q < 0: raise ValueError('the arguments p(={}) and q(={}) must be positive integers'.format(p, q)) G = Graph(p + q, name="Complete bipartite graph of order {}+{}".format(p, q)) G.add_edges((i, j) for i in range(p) for j in range(p, p + q)) # We now assign positions to vertices: # - vertices 0,..,p-1 are placed on the line (0, 1) to (max(p, q), 1) # - vertices p,..,p+q-1 are placed on the line (0, 0) to (max(p, q), 0) # If p (or q) is 1, the vertex is centered in the line. if set_position: nmax = max(p, q) G._line_embedding(list(range(p)), first=(0, 1), last=(nmax, 1)) G._line_embedding(list(range(p, p + q)), first=(0, 0), last=(nmax, 0)) return G
def CompleteMultipartiteGraph(l): r""" Return a complete multipartite graph. INPUT: - ``l`` -- a list of integers; the respective sizes of the components PLOTTING: Produce a layout of the vertices so that vertices in the same vertex set are adjacent and clearly separated from vertices in other vertex sets. This is done by calculating the vertices of an `r`-gon then calculating the slope between adjacent vertices. We then 'walk' around the `r`-gon placing graph vertices in regular intervals between adjacent vertices of the `r`-gon. Makes a nicely organized graph like in this picture: https://commons.wikimedia.org/wiki/File:Turan_13-4.svg EXAMPLES: A complete tripartite graph with sets of sizes `5, 6, 8`:: sage: g = graphs.CompleteMultipartiteGraph([5, 6, 8]); g Multipartite Graph with set sizes [5, 6, 8]: Graph on 19 vertices It clearly has a chromatic number of 3:: sage: g.chromatic_number() 3 """ r = len(l) # getting the number of partitions name = "Multipartite Graph with set sizes {}".format(l) if not r: g = Graph() elif r == 1: g = Graph(l[0]) g._line_embedding(range(l[0]), first=(0, 0), last=(l[0], 0)) elif r == 2: g = CompleteBipartiteGraph(l[0], l[1]) g.name(name) else: # This position code gives bad results on bipartite or isolated graphs points = [(cos(2 * pi * i / r), sin(2 * pi * i / r)) for i in range(r)] slopes = [(points[(i + 1) % r][0] - points[i % r][0], points[(i + 1) % r][1] - points[i % r][1]) for i in range(r)] counter = 0 positions = {} for i in range(r): vertex_set_size = l[i] + 1 for j in range(1, vertex_set_size): x = points[i][0] + slopes[i][0] * j / vertex_set_size y = points[i][1] + slopes[i][1] * j / vertex_set_size positions[counter] = (x, y) counter += 1 g = Graph(sum(l)) s = 0 for i in l: g.add_clique(range(s, s + i)) s += i g = g.complement() g.set_pos(positions) g.name(name) return g
def CompleteBipartiteGraph(n1, n2, set_position=True): r""" Return a Complete Bipartite Graph on `n1 + n2` vertices. A Complete Bipartite Graph is a graph with its vertices partitioned into two groups, `V_1 = \{0,...,n1-1\}` and `V_2 = \{n1,...,n1+n2-1\}`. Each `u \in V_1` is connected to every `v \in V_2`. INPUT: - ``n1, n2`` -- number of vertices in each side - ``set_position`` -- boolean (default ``True``); if set to ``True``, we assign positions to the vertices so that the set of cardinality `n1` is on the line `y=1` and the set of cardinality `n2` is on the line `y=0`. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each complete bipartite graph will be displayed with the first `n1` nodes on the top row (at `y=1`) from left to right. The remaining `n2` nodes appear at `y=0`, also from left to right. The shorter row (partition with fewer nodes) is stretched to the same length as the longer row, unless the shorter row has 1 node; in which case it is centered. The `x` values in the plot are in domain `[0, \max(n1, n2)]`. In the Complete Bipartite graph, there is a visual difference in using the spring-layout algorithm vs. the position dictionary used in this constructor. The position dictionary flattens the graph and separates the partitioned nodes, making it clear which nodes an edge is connected to. The Complete Bipartite graph plotted with the spring-layout algorithm tends to center the nodes in n1 (see spring_med in examples below), thus overlapping its nodes and edges, making it typically hard to decipher. Filling the position dictionary in advance adds `O(n)` to the constructor. Feel free to race the constructors below in the examples section. The much larger difference is the time added by the spring-layout algorithm when plotting. (Also shown in the example below). The spring model is typically described as `O(n^3)`, as appears to be the case in the NetworkX source code. EXAMPLES: Two ways of constructing the complete bipartite graph, using different layout algorithms:: sage: import networkx sage: n = networkx.complete_bipartite_graph(389, 157); spring_big = Graph(n) # long time sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157) # long time Compare the plotting:: sage: n = networkx.complete_bipartite_graph(11, 17) sage: spring_med = Graph(n) sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17) Notice here how the spring-layout tends to center the nodes of `n1`:: sage: spring_med.show() # long time sage: posdict_med.show() # long time View many complete bipartite graphs with a Sage Graphics Array, with this constructor (i.e., the position dictionary filled):: sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.CompleteBipartiteGraph(i+1,4) ....: 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 We compare to plotting with the spring-layout algorithm:: sage: g = [] sage: j = [] sage: for i in range(9): ....: spr = networkx.complete_bipartite_graph(i+1,4) ....: k = Graph(spr) ....: 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 :trac:`12155`:: sage: graphs.CompleteBipartiteGraph(5,6).complement() complement(Complete bipartite graph of order 5+6): Graph on 11 vertices TESTS: Prevent negative dimensions (:trac:`18530`):: sage: graphs.CompleteBipartiteGraph(-1,1) Traceback (most recent call last): ... ValueError: the arguments n1(=-1) and n2(=1) must be positive integers sage: graphs.CompleteBipartiteGraph(1,-1) Traceback (most recent call last): ... ValueError: the arguments n1(=1) and n2(=-1) must be positive integers """ if n1<0 or n2<0: raise ValueError('the arguments n1(={}) and n2(={}) must be positive integers'.format(n1,n2)) G = Graph(n1+n2, name="Complete bipartite graph of order {}+{}".format(n1, n2)) G.add_edges((i,j) for i in range(n1) for j in range(n1,n1+n2)) # We now assign positions to vertices: # - vertices 0,..,n1-1 are placed on the line (0, 1) to (max(n1, n2), 1) # - vertices n1,..,n1+n2-1 are placed on the line (0, 0) to (max(n1, n2), 0) # If n1 (or n2) is 1, the vertex is centered in the line. if set_position: nmax = max(n1, n2) G._line_embedding(list(range(n1)), first=(0, 1), last=(nmax, 1)) G._line_embedding(list(range(n1, n1+n2)), first=(0, 0), last=(nmax, 0)) return G