| """Generators for some classic graphs. |
| |
| The typical graph builder function is called as follows: |
| |
| >>> G = nx.complete_graph(100) |
| |
| returning the complete graph on n nodes labeled 0, .., 99 |
| as a simple graph. Except for `empty_graph`, all the functions |
| in this module return a Graph class (i.e. a simple, undirected graph). |
| |
| """ |
|
|
| import itertools |
| import numbers |
|
|
| import networkx as nx |
| from networkx.classes import Graph |
| from networkx.exception import NetworkXError |
| from networkx.utils import nodes_or_number, pairwise |
|
|
| __all__ = [ |
| "balanced_tree", |
| "barbell_graph", |
| "binomial_tree", |
| "complete_graph", |
| "complete_multipartite_graph", |
| "circular_ladder_graph", |
| "circulant_graph", |
| "cycle_graph", |
| "dorogovtsev_goltsev_mendes_graph", |
| "empty_graph", |
| "full_rary_tree", |
| "kneser_graph", |
| "ladder_graph", |
| "lollipop_graph", |
| "null_graph", |
| "path_graph", |
| "star_graph", |
| "tadpole_graph", |
| "trivial_graph", |
| "turan_graph", |
| "wheel_graph", |
| ] |
|
|
|
|
| |
| |
| |
|
|
|
|
| def _tree_edges(n, r): |
| if n == 0: |
| return |
| |
| |
| nodes = iter(range(n)) |
| parents = [next(nodes)] |
| while parents: |
| source = parents.pop(0) |
| for i in range(r): |
| try: |
| target = next(nodes) |
| parents.append(target) |
| yield source, target |
| except StopIteration: |
| break |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def full_rary_tree(r, n, create_using=None): |
| """Creates a full r-ary tree of `n` nodes. |
| |
| Sometimes called a k-ary, n-ary, or m-ary tree. |
| "... all non-leaf nodes have exactly r children and all levels |
| are full except for some rightmost position of the bottom level |
| (if a leaf at the bottom level is missing, then so are all of the |
| leaves to its right." [1]_ |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.full_rary_tree(2, 10)) |
| |
| Parameters |
| ---------- |
| r : int |
| branching factor of the tree |
| n : int |
| Number of nodes in the tree |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| Returns |
| ------- |
| G : networkx Graph |
| An r-ary tree with n nodes |
| |
| References |
| ---------- |
| .. [1] An introduction to data structures and algorithms, |
| James Andrew Storer, Birkhauser Boston 2001, (page 225). |
| """ |
| G = empty_graph(n, create_using) |
| G.add_edges_from(_tree_edges(n, r)) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def kneser_graph(n, k): |
| """Returns the Kneser Graph with parameters `n` and `k`. |
| |
| The Kneser Graph has nodes that are k-tuples (subsets) of the integers |
| between 0 and ``n-1``. Nodes are adjacent if their corresponding sets are disjoint. |
| |
| Parameters |
| ---------- |
| n: int |
| Number of integers from which to make node subsets. |
| Subsets are drawn from ``set(range(n))``. |
| k: int |
| Size of the subsets. |
| |
| Returns |
| ------- |
| G : NetworkX Graph |
| |
| Examples |
| -------- |
| >>> G = nx.kneser_graph(5, 2) |
| >>> G.number_of_nodes() |
| 10 |
| >>> G.number_of_edges() |
| 15 |
| >>> nx.is_isomorphic(G, nx.petersen_graph()) |
| True |
| """ |
| if n <= 0: |
| raise NetworkXError("n should be greater than zero") |
| if k <= 0 or k > n: |
| raise NetworkXError("k should be greater than zero and smaller than n") |
|
|
| G = nx.Graph() |
| |
| subsets = list(itertools.combinations(range(n), k)) |
|
|
| if 2 * k > n: |
| G.add_nodes_from(subsets) |
|
|
| universe = set(range(n)) |
| comb = itertools.combinations |
| G.add_edges_from((s, t) for s in subsets for t in comb(universe - set(s), k)) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def balanced_tree(r, h, create_using=None): |
| """Returns the perfectly balanced `r`-ary tree of height `h`. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.balanced_tree(2, 3)) |
| |
| Parameters |
| ---------- |
| r : int |
| Branching factor of the tree; each node will have `r` |
| children. |
| |
| h : int |
| Height of the tree. |
| |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| Returns |
| ------- |
| G : NetworkX graph |
| A balanced `r`-ary tree of height `h`. |
| |
| Notes |
| ----- |
| This is the rooted tree where all leaves are at distance `h` from |
| the root. The root has degree `r` and all other internal nodes |
| have degree `r + 1`. |
| |
| Node labels are integers, starting from zero. |
| |
| A balanced tree is also known as a *complete r-ary tree*. |
| |
| """ |
| |
| |
| |
| |
| |
| if r == 1: |
| n = h + 1 |
| else: |
| |
| |
| n = (1 - r ** (h + 1)) // (1 - r) |
| return full_rary_tree(r, n, create_using=create_using) |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def barbell_graph(m1, m2, create_using=None): |
| """Returns the Barbell Graph: two complete graphs connected by a path. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.barbell_graph(4, 2)) |
| |
| Parameters |
| ---------- |
| m1 : int |
| Size of the left and right barbells, must be greater than 2. |
| |
| m2 : int |
| Length of the path connecting the barbells. |
| |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| Only undirected Graphs are supported. |
| |
| Returns |
| ------- |
| G : NetworkX graph |
| A barbell graph. |
| |
| Notes |
| ----- |
| |
| |
| Two identical complete graphs $K_{m1}$ form the left and right bells, |
| and are connected by a path $P_{m2}$. |
| |
| The `2*m1+m2` nodes are numbered |
| `0, ..., m1-1` for the left barbell, |
| `m1, ..., m1+m2-1` for the path, |
| and `m1+m2, ..., 2*m1+m2-1` for the right barbell. |
| |
| The 3 subgraphs are joined via the edges `(m1-1, m1)` and |
| `(m1+m2-1, m1+m2)`. If `m2=0`, this is merely two complete |
| graphs joined together. |
| |
| This graph is an extremal example in David Aldous |
| and Jim Fill's e-text on Random Walks on Graphs. |
| |
| """ |
| if m1 < 2: |
| raise NetworkXError("Invalid graph description, m1 should be >=2") |
| if m2 < 0: |
| raise NetworkXError("Invalid graph description, m2 should be >=0") |
|
|
| |
| G = complete_graph(m1, create_using) |
| if G.is_directed(): |
| raise NetworkXError("Directed Graph not supported") |
|
|
| |
| G.add_nodes_from(range(m1, m1 + m2 - 1)) |
| if m2 > 1: |
| G.add_edges_from(pairwise(range(m1, m1 + m2))) |
|
|
| |
| G.add_edges_from( |
| (u, v) for u in range(m1 + m2, 2 * m1 + m2) for v in range(u + 1, 2 * m1 + m2) |
| ) |
|
|
| |
| G.add_edge(m1 - 1, m1) |
| if m2 > 0: |
| G.add_edge(m1 + m2 - 1, m1 + m2) |
|
|
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def binomial_tree(n, create_using=None): |
| """Returns the Binomial Tree of order n. |
| |
| The binomial tree of order 0 consists of a single node. A binomial tree of order k |
| is defined recursively by linking two binomial trees of order k-1: the root of one is |
| the leftmost child of the root of the other. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.binomial_tree(3)) |
| |
| Parameters |
| ---------- |
| n : int |
| Order of the binomial tree. |
| |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| Returns |
| ------- |
| G : NetworkX graph |
| A binomial tree of $2^n$ nodes and $2^n - 1$ edges. |
| |
| """ |
| G = nx.empty_graph(1, create_using) |
|
|
| N = 1 |
| for i in range(n): |
| |
| edges = [(u + N, v + N) for (u, v) in G.edges()] |
| G.add_edges_from(edges) |
| G.add_edge(0, N) |
| N *= 2 |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| @nodes_or_number(0) |
| def complete_graph(n, create_using=None): |
| """Return the complete graph `K_n` with n nodes. |
| |
| A complete graph on `n` nodes means that all pairs |
| of distinct nodes have an edge connecting them. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.complete_graph(5)) |
| |
| Parameters |
| ---------- |
| n : int or iterable container of nodes |
| If n is an integer, nodes are from range(n). |
| If n is a container of nodes, those nodes appear in the graph. |
| Warning: n is not checked for duplicates and if present the |
| resulting graph may not be as desired. Make sure you have no duplicates. |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| Examples |
| -------- |
| >>> G = nx.complete_graph(9) |
| >>> len(G) |
| 9 |
| >>> G.size() |
| 36 |
| >>> G = nx.complete_graph(range(11, 14)) |
| >>> list(G.nodes()) |
| [11, 12, 13] |
| >>> G = nx.complete_graph(4, nx.DiGraph()) |
| >>> G.is_directed() |
| True |
| |
| """ |
| _, nodes = n |
| G = empty_graph(nodes, create_using) |
| if len(nodes) > 1: |
| if G.is_directed(): |
| edges = itertools.permutations(nodes, 2) |
| else: |
| edges = itertools.combinations(nodes, 2) |
| G.add_edges_from(edges) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def circular_ladder_graph(n, create_using=None): |
| """Returns the circular ladder graph $CL_n$ of length n. |
| |
| $CL_n$ consists of two concentric n-cycles in which |
| each of the n pairs of concentric nodes are joined by an edge. |
| |
| Node labels are the integers 0 to n-1 |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.circular_ladder_graph(5)) |
| |
| """ |
| G = ladder_graph(n, create_using) |
| G.add_edge(0, n - 1) |
| G.add_edge(n, 2 * n - 1) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def circulant_graph(n, offsets, create_using=None): |
| r"""Returns the circulant graph $Ci_n(x_1, x_2, ..., x_m)$ with $n$ nodes. |
| |
| The circulant graph $Ci_n(x_1, ..., x_m)$ consists of $n$ nodes $0, ..., n-1$ |
| such that node $i$ is connected to nodes $(i + x) \mod n$ and $(i - x) \mod n$ |
| for all $x$ in $x_1, ..., x_m$. Thus $Ci_n(1)$ is a cycle graph. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.circulant_graph(10, [1])) |
| |
| Parameters |
| ---------- |
| n : integer |
| The number of nodes in the graph. |
| offsets : list of integers |
| A list of node offsets, $x_1$ up to $x_m$, as described above. |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| Returns |
| ------- |
| NetworkX Graph of type create_using |
| |
| Examples |
| -------- |
| Many well-known graph families are subfamilies of the circulant graphs; |
| for example, to create the cycle graph on n points, we connect every |
| node to nodes on either side (with offset plus or minus one). For n = 10, |
| |
| >>> G = nx.circulant_graph(10, [1]) |
| >>> edges = [ |
| ... (0, 9), |
| ... (0, 1), |
| ... (1, 2), |
| ... (2, 3), |
| ... (3, 4), |
| ... (4, 5), |
| ... (5, 6), |
| ... (6, 7), |
| ... (7, 8), |
| ... (8, 9), |
| ... ] |
| >>> sorted(edges) == sorted(G.edges()) |
| True |
| |
| Similarly, we can create the complete graph |
| on 5 points with the set of offsets [1, 2]: |
| |
| >>> G = nx.circulant_graph(5, [1, 2]) |
| >>> edges = [ |
| ... (0, 1), |
| ... (0, 2), |
| ... (0, 3), |
| ... (0, 4), |
| ... (1, 2), |
| ... (1, 3), |
| ... (1, 4), |
| ... (2, 3), |
| ... (2, 4), |
| ... (3, 4), |
| ... ] |
| >>> sorted(edges) == sorted(G.edges()) |
| True |
| |
| """ |
| G = empty_graph(n, create_using) |
| G.add_edges_from((i, (i - j) % n) for i in range(n) for j in offsets) |
| G.add_edges_from((i, (i + j) % n) for i in range(n) for j in offsets) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| @nodes_or_number(0) |
| def cycle_graph(n, create_using=None): |
| """Returns the cycle graph $C_n$ of cyclically connected nodes. |
| |
| $C_n$ is a path with its two end-nodes connected. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.cycle_graph(5)) |
| |
| Parameters |
| ---------- |
| n : int or iterable container of nodes |
| If n is an integer, nodes are from `range(n)`. |
| If n is a container of nodes, those nodes appear in the graph. |
| Warning: n is not checked for duplicates and if present the |
| resulting graph may not be as desired. Make sure you have no duplicates. |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| Notes |
| ----- |
| If create_using is directed, the direction is in increasing order. |
| |
| """ |
| _, nodes = n |
| G = empty_graph(nodes, create_using) |
| G.add_edges_from(pairwise(nodes, cyclic=True)) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def dorogovtsev_goltsev_mendes_graph(n, create_using=None): |
| """Returns the hierarchically constructed Dorogovtsev--Goltsev--Mendes graph. |
| |
| The Dorogovtsev--Goltsev--Mendes [1]_ procedure deterministically produces a |
| scale-free graph with ``3/2 * (3**(n-1) + 1)`` nodes |
| and ``3**n`` edges for a given `n`. |
| |
| Note that `n` denotes the number of times the state transition is applied, |
| starting from the base graph with ``n = 0`` (no transitions), as in [2]_. |
| This is different from the parameter ``t = n - 1`` in [1]_. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.dorogovtsev_goltsev_mendes_graph(3)) |
| |
| Parameters |
| ---------- |
| n : integer |
| The generation number. |
| |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. Directed graphs and multigraphs are not supported. |
| |
| Returns |
| ------- |
| G : NetworkX `Graph` |
| |
| Raises |
| ------ |
| NetworkXError |
| If `n` is less than zero. |
| |
| If `create_using` is a directed graph or multigraph. |
| |
| Examples |
| -------- |
| >>> G = nx.dorogovtsev_goltsev_mendes_graph(3) |
| >>> G.number_of_nodes() |
| 15 |
| >>> G.number_of_edges() |
| 27 |
| >>> nx.is_planar(G) |
| True |
| |
| References |
| ---------- |
| .. [1] S. N. Dorogovtsev, A. V. Goltsev and J. F. F. Mendes, |
| "Pseudofractal scale-free web", Physical Review E 65, 066122, 2002. |
| https://arxiv.org/pdf/cond-mat/0112143.pdf |
| .. [2] Weisstein, Eric W. "Dorogovtsev--Goltsev--Mendes Graph". |
| From MathWorld--A Wolfram Web Resource. |
| https://mathworld.wolfram.com/Dorogovtsev-Goltsev-MendesGraph.html |
| """ |
| if n < 0: |
| raise NetworkXError("n must be greater than or equal to 0") |
|
|
| G = empty_graph(0, create_using) |
| if G.is_directed(): |
| raise NetworkXError("directed graph not supported") |
| if G.is_multigraph(): |
| raise NetworkXError("multigraph not supported") |
|
|
| G.add_edge(0, 1) |
| new_node = 2 |
| for _ in range(n): |
| new_edges = [] |
| for u, v in G.edges(): |
| new_edges.append((u, new_node)) |
| new_edges.append((v, new_node)) |
| new_node += 1 |
|
|
| G.add_edges_from(new_edges) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| @nodes_or_number(0) |
| def empty_graph(n=0, create_using=None, default=Graph): |
| """Returns the empty graph with n nodes and zero edges. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.empty_graph(5)) |
| |
| Parameters |
| ---------- |
| n : int or iterable container of nodes (default = 0) |
| If n is an integer, nodes are from `range(n)`. |
| If n is a container of nodes, those nodes appear in the graph. |
| create_using : Graph Instance, Constructor or None |
| Indicator of type of graph to return. |
| If a Graph-type instance, then clear and use it. |
| If None, use the `default` constructor. |
| If a constructor, call it to create an empty graph. |
| default : Graph constructor (optional, default = nx.Graph) |
| The constructor to use if create_using is None. |
| If None, then nx.Graph is used. |
| This is used when passing an unknown `create_using` value |
| through your home-grown function to `empty_graph` and |
| you want a default constructor other than nx.Graph. |
| |
| Examples |
| -------- |
| >>> G = nx.empty_graph(10) |
| >>> G.number_of_nodes() |
| 10 |
| >>> G.number_of_edges() |
| 0 |
| >>> G = nx.empty_graph("ABC") |
| >>> G.number_of_nodes() |
| 3 |
| >>> sorted(G) |
| ['A', 'B', 'C'] |
| |
| Notes |
| ----- |
| The variable create_using should be a Graph Constructor or a |
| "graph"-like object. Constructors, e.g. `nx.Graph` or `nx.MultiGraph` |
| will be used to create the returned graph. "graph"-like objects |
| will be cleared (nodes and edges will be removed) and refitted as |
| an empty "graph" with nodes specified in n. This capability |
| is useful for specifying the class-nature of the resulting empty |
| "graph" (i.e. Graph, DiGraph, MyWeirdGraphClass, etc.). |
| |
| The variable create_using has three main uses: |
| Firstly, the variable create_using can be used to create an |
| empty digraph, multigraph, etc. For example, |
| |
| >>> n = 10 |
| >>> G = nx.empty_graph(n, create_using=nx.DiGraph) |
| |
| will create an empty digraph on n nodes. |
| |
| Secondly, one can pass an existing graph (digraph, multigraph, |
| etc.) via create_using. For example, if G is an existing graph |
| (resp. digraph, multigraph, etc.), then empty_graph(n, create_using=G) |
| will empty G (i.e. delete all nodes and edges using G.clear()) |
| and then add n nodes and zero edges, and return the modified graph. |
| |
| Thirdly, when constructing your home-grown graph creation function |
| you can use empty_graph to construct the graph by passing a user |
| defined create_using to empty_graph. In this case, if you want the |
| default constructor to be other than nx.Graph, specify `default`. |
| |
| >>> def mygraph(n, create_using=None): |
| ... G = nx.empty_graph(n, create_using, nx.MultiGraph) |
| ... G.add_edges_from([(0, 1), (0, 1)]) |
| ... return G |
| >>> G = mygraph(3) |
| >>> G.is_multigraph() |
| True |
| >>> G = mygraph(3, nx.Graph) |
| >>> G.is_multigraph() |
| False |
| |
| See also create_empty_copy(G). |
| |
| """ |
| if create_using is None: |
| G = default() |
| elif isinstance(create_using, type): |
| G = create_using() |
| elif not hasattr(create_using, "adj"): |
| raise TypeError("create_using is not a valid NetworkX graph type or instance") |
| else: |
| |
| create_using.clear() |
| G = create_using |
|
|
| _, nodes = n |
| G.add_nodes_from(nodes) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def ladder_graph(n, create_using=None): |
| """Returns the Ladder graph of length n. |
| |
| This is two paths of n nodes, with |
| each pair connected by a single edge. |
| |
| Node labels are the integers 0 to 2*n - 1. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.ladder_graph(5)) |
| |
| """ |
| G = empty_graph(2 * n, create_using) |
| if G.is_directed(): |
| raise NetworkXError("Directed Graph not supported") |
| G.add_edges_from(pairwise(range(n))) |
| G.add_edges_from(pairwise(range(n, 2 * n))) |
| G.add_edges_from((v, v + n) for v in range(n)) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| @nodes_or_number([0, 1]) |
| def lollipop_graph(m, n, create_using=None): |
| """Returns the Lollipop Graph; ``K_m`` connected to ``P_n``. |
| |
| This is the Barbell Graph without the right barbell. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.lollipop_graph(3, 4)) |
| |
| Parameters |
| ---------- |
| m, n : int or iterable container of nodes |
| If an integer, nodes are from ``range(m)`` and ``range(m, m+n)``. |
| If a container of nodes, those nodes appear in the graph. |
| Warning: `m` and `n` are not checked for duplicates and if present the |
| resulting graph may not be as desired. Make sure you have no duplicates. |
| |
| The nodes for `m` appear in the complete graph $K_m$ and the nodes |
| for `n` appear in the path $P_n$ |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| Returns |
| ------- |
| Networkx graph |
| A complete graph with `m` nodes connected to a path of length `n`. |
| |
| Notes |
| ----- |
| The 2 subgraphs are joined via an edge ``(m-1, m)``. |
| If ``n=0``, this is merely a complete graph. |
| |
| (This graph is an extremal example in David Aldous and Jim |
| Fill's etext on Random Walks on Graphs.) |
| |
| """ |
| m, m_nodes = m |
| M = len(m_nodes) |
| if M < 2: |
| raise NetworkXError("Invalid description: m should indicate at least 2 nodes") |
|
|
| n, n_nodes = n |
| if isinstance(m, numbers.Integral) and isinstance(n, numbers.Integral): |
| n_nodes = list(range(M, M + n)) |
| N = len(n_nodes) |
|
|
| |
| G = complete_graph(m_nodes, create_using) |
| if G.is_directed(): |
| raise NetworkXError("Directed Graph not supported") |
|
|
| |
| G.add_nodes_from(n_nodes) |
| if N > 1: |
| G.add_edges_from(pairwise(n_nodes)) |
|
|
| if len(G) != M + N: |
| raise NetworkXError("Nodes must be distinct in containers m and n") |
|
|
| |
| if M > 0 and N > 0: |
| G.add_edge(m_nodes[-1], n_nodes[0]) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def null_graph(create_using=None): |
| """Returns the Null graph with no nodes or edges. |
| |
| See empty_graph for the use of create_using. |
| |
| """ |
| G = empty_graph(0, create_using) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| @nodes_or_number(0) |
| def path_graph(n, create_using=None): |
| """Returns the Path graph `P_n` of linearly connected nodes. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.path_graph(5)) |
| |
| Parameters |
| ---------- |
| n : int or iterable |
| If an integer, nodes are 0 to n - 1. |
| If an iterable of nodes, in the order they appear in the path. |
| Warning: n is not checked for duplicates and if present the |
| resulting graph may not be as desired. Make sure you have no duplicates. |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| """ |
| _, nodes = n |
| G = empty_graph(nodes, create_using) |
| G.add_edges_from(pairwise(nodes)) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| @nodes_or_number(0) |
| def star_graph(n, create_using=None): |
| """Return a star graph. |
| |
| The star graph consists of one center node connected to `n` outer nodes. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.star_graph(6)) |
| |
| Parameters |
| ---------- |
| n : int or iterable |
| If an integer, node labels are ``0`` to `n`, with center ``0``. |
| If an iterable of nodes, the center is the first. |
| Warning: `n` is not checked for duplicates and if present, the |
| resulting graph may not be as desired. Make sure you have no duplicates. |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| Examples |
| -------- |
| A star graph with 3 spokes can be generated with |
| |
| >>> G = nx.star_graph(3) |
| >>> sorted(G.edges) |
| [(0, 1), (0, 2), (0, 3)] |
| |
| For directed graphs, the convention is to have edges pointing from the hub |
| to the spokes: |
| |
| >>> DG1 = nx.star_graph(3, create_using=nx.DiGraph) |
| >>> sorted(DG1.edges) |
| [(0, 1), (0, 2), (0, 3)] |
| |
| Other possible definitions have edges pointing from the spokes to the hub: |
| |
| >>> DG2 = nx.star_graph(3, create_using=nx.DiGraph).reverse() |
| >>> sorted(DG2.edges) |
| [(1, 0), (2, 0), (3, 0)] |
| |
| or have bidirectional edges: |
| |
| >>> DG3 = nx.star_graph(3).to_directed() |
| >>> sorted(DG3.edges) |
| [(0, 1), (0, 2), (0, 3), (1, 0), (2, 0), (3, 0)] |
| |
| Notes |
| ----- |
| The graph has ``n + 1`` nodes for integer `n`. |
| So ``star_graph(3)`` is the same as ``star_graph(range(4))``. |
| """ |
| n, nodes = n |
| if isinstance(n, numbers.Integral): |
| nodes.append(int(n)) |
| G = empty_graph(nodes, create_using) |
|
|
| if len(nodes) > 1: |
| hub, *spokes = nodes |
| G.add_edges_from((hub, node) for node in spokes) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| @nodes_or_number([0, 1]) |
| def tadpole_graph(m, n, create_using=None): |
| """Returns the (m,n)-tadpole graph; ``C_m`` connected to ``P_n``. |
| |
| This graph on m+n nodes connects a cycle of size `m` to a path of length `n`. |
| It looks like a tadpole. It is also called a kite graph or a dragon graph. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.tadpole_graph(3, 5)) |
| |
| Parameters |
| ---------- |
| m, n : int or iterable container of nodes |
| If an integer, nodes are from ``range(m)`` and ``range(m,m+n)``. |
| If a container of nodes, those nodes appear in the graph. |
| Warning: `m` and `n` are not checked for duplicates and if present the |
| resulting graph may not be as desired. |
| |
| The nodes for `m` appear in the cycle graph $C_m$ and the nodes |
| for `n` appear in the path $P_n$. |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| Returns |
| ------- |
| Networkx graph |
| A cycle of size `m` connected to a path of length `n`. |
| |
| Raises |
| ------ |
| NetworkXError |
| If ``m < 2``. The tadpole graph is undefined for ``m<2``. |
| |
| Notes |
| ----- |
| The 2 subgraphs are joined via an edge ``(m-1, m)``. |
| If ``n=0``, this is a cycle graph. |
| `m` and/or `n` can be a container of nodes instead of an integer. |
| |
| """ |
| m, m_nodes = m |
| M = len(m_nodes) |
| if M < 2: |
| raise NetworkXError("Invalid description: m should indicate at least 2 nodes") |
|
|
| n, n_nodes = n |
| if isinstance(m, numbers.Integral) and isinstance(n, numbers.Integral): |
| n_nodes = list(range(M, M + n)) |
|
|
| |
| G = cycle_graph(m_nodes, create_using) |
| if G.is_directed(): |
| raise NetworkXError("Directed Graph not supported") |
|
|
| |
| nx.add_path(G, [m_nodes[-1]] + list(n_nodes)) |
|
|
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def trivial_graph(create_using=None): |
| """Return the Trivial graph with one node (with label 0) and no edges. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.trivial_graph(), with_labels=True) |
| |
| """ |
| G = empty_graph(1, create_using) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def turan_graph(n, r): |
| r"""Return the Turan Graph |
| |
| The Turan Graph is a complete multipartite graph on $n$ nodes |
| with $r$ disjoint subsets. That is, edges connect each node to |
| every node not in its subset. |
| |
| Given $n$ and $r$, we create a complete multipartite graph with |
| $r-(n \mod r)$ partitions of size $n/r$, rounded down, and |
| $n \mod r$ partitions of size $n/r+1$, rounded down. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.turan_graph(6, 2)) |
| |
| Parameters |
| ---------- |
| n : int |
| The number of nodes. |
| r : int |
| The number of partitions. |
| Must be less than or equal to n. |
| |
| Notes |
| ----- |
| Must satisfy $1 <= r <= n$. |
| The graph has $(r-1)(n^2)/(2r)$ edges, rounded down. |
| """ |
|
|
| if not 1 <= r <= n: |
| raise NetworkXError("Must satisfy 1 <= r <= n") |
|
|
| partitions = [n // r] * (r - (n % r)) + [n // r + 1] * (n % r) |
| G = complete_multipartite_graph(*partitions) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| @nodes_or_number(0) |
| def wheel_graph(n, create_using=None): |
| """Return the wheel graph |
| |
| The wheel graph consists of a hub node connected to a cycle of (n-1) nodes. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.wheel_graph(5)) |
| |
| Parameters |
| ---------- |
| n : int or iterable |
| If an integer, node labels are 0 to n with center 0. |
| If an iterable of nodes, the center is the first. |
| Warning: n is not checked for duplicates and if present the |
| resulting graph may not be as desired. Make sure you have no duplicates. |
| create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| Graph type to create. If graph instance, then cleared before populated. |
| |
| Node labels are the integers 0 to n - 1. |
| """ |
| _, nodes = n |
| G = empty_graph(nodes, create_using) |
| if G.is_directed(): |
| raise NetworkXError("Directed Graph not supported") |
|
|
| if len(nodes) > 1: |
| hub, *rim = nodes |
| G.add_edges_from((hub, node) for node in rim) |
| if len(rim) > 1: |
| G.add_edges_from(pairwise(rim, cyclic=True)) |
| return G |
|
|
|
|
| @nx._dispatchable(graphs=None, returns_graph=True) |
| def complete_multipartite_graph(*subset_sizes): |
| """Returns the complete multipartite graph with the specified subset sizes. |
| |
| .. plot:: |
| |
| >>> nx.draw(nx.complete_multipartite_graph(1, 2, 3)) |
| |
| Parameters |
| ---------- |
| subset_sizes : tuple of integers or tuple of node iterables |
| The arguments can either all be integer number of nodes or they |
| can all be iterables of nodes. If integers, they represent the |
| number of nodes in each subset of the multipartite graph. |
| If iterables, each is used to create the nodes for that subset. |
| The length of subset_sizes is the number of subsets. |
| |
| Returns |
| ------- |
| G : NetworkX Graph |
| Returns the complete multipartite graph with the specified subsets. |
| |
| For each node, the node attribute 'subset' is an integer |
| indicating which subset contains the node. |
| |
| Examples |
| -------- |
| Creating a complete tripartite graph, with subsets of one, two, and three |
| nodes, respectively. |
| |
| >>> G = nx.complete_multipartite_graph(1, 2, 3) |
| >>> [G.nodes[u]["subset"] for u in G] |
| [0, 1, 1, 2, 2, 2] |
| >>> list(G.edges(0)) |
| [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)] |
| >>> list(G.edges(2)) |
| [(2, 0), (2, 3), (2, 4), (2, 5)] |
| >>> list(G.edges(4)) |
| [(4, 0), (4, 1), (4, 2)] |
| |
| >>> G = nx.complete_multipartite_graph("a", "bc", "def") |
| >>> [G.nodes[u]["subset"] for u in sorted(G)] |
| [0, 1, 1, 2, 2, 2] |
| |
| Notes |
| ----- |
| This function generalizes several other graph builder functions. |
| |
| - If no subset sizes are given, this returns the null graph. |
| - If a single subset size `n` is given, this returns the empty graph on |
| `n` nodes. |
| - If two subset sizes `m` and `n` are given, this returns the complete |
| bipartite graph on `m + n` nodes. |
| - If subset sizes `1` and `n` are given, this returns the star graph on |
| `n + 1` nodes. |
| |
| See also |
| -------- |
| complete_bipartite_graph |
| """ |
| |
| G = Graph() |
|
|
| if len(subset_sizes) == 0: |
| return G |
|
|
| |
| try: |
| extents = pairwise(itertools.accumulate((0,) + subset_sizes)) |
| subsets = [range(start, end) for start, end in extents] |
| except TypeError: |
| subsets = subset_sizes |
| else: |
| if any(size < 0 for size in subset_sizes): |
| raise NetworkXError(f"Negative number of nodes not valid: {subset_sizes}") |
|
|
| |
| |
| try: |
| for i, subset in enumerate(subsets): |
| G.add_nodes_from(subset, subset=i) |
| except TypeError as err: |
| raise NetworkXError("Arguments must be all ints or all iterables") from err |
|
|
| |
| |
| for subset1, subset2 in itertools.combinations(subsets, 2): |
| G.add_edges_from(itertools.product(subset1, subset2)) |
| return G |
|
|