comparison planemo/lib/python3.7/site-packages/networkx/generators/lattice.py @ 1:56ad4e20f292 draft

"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author guerler
date Fri, 31 Jul 2020 00:32:28 -0400
parents
children
comparison
equal deleted inserted replaced
0:d30785e31577 1:56ad4e20f292
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2004-2019 by
3 # Aric Hagberg <hagberg@lanl.gov>
4 # Dan Schult <dschult@colgate.edu>
5 # Pieter Swart <swart@lanl.gov>
6 # All rights reserved.
7 # BSD license.
8 #
9 # Authors: Aric Hagberg (hagberg@lanl.gov)
10 # Pieter Swart (swart@lanl.gov)
11 # Joel Miller (jmiller@lanl.gov)
12 # Dan Schult (dschult@lanl.gov)
13 """Functions for generating grid graphs and lattices
14
15 The :func:`grid_2d_graph`, :func:`triangular_lattice_graph`, and
16 :func:`hexagonal_lattice_graph` functions correspond to the three
17 `regular tilings of the plane`_, the square, triangular, and hexagonal
18 tilings, respectively. :func:`grid_graph` and :func:`hypercube_graph`
19 are similar for arbitrary dimensions. Useful relevant discussion can
20 be found about `Triangular Tiling`_, and `Square, Hex and Triangle Grids`_
21
22 .. _regular tilings of the plane: https://en.wikipedia.org/wiki/List_of_regular_polytopes_and_compounds#Euclidean_tilings
23 .. _Square, Hex and Triangle Grids: http://www-cs-students.stanford.edu/~amitp/game-programming/grids/
24 .. _Triangular Tiling: https://en.wikipedia.org/wiki/Triangular_tiling
25
26 """
27
28 from math import sqrt
29
30 from networkx.classes import Graph
31 from networkx.classes import set_node_attributes
32 from networkx.algorithms.minors import contracted_nodes
33 from networkx.algorithms.operators.product import cartesian_product
34 from networkx.exception import NetworkXError
35 from networkx.relabel import relabel_nodes
36 from networkx.utils import flatten
37 from networkx.utils import nodes_or_number
38 from networkx.utils import pairwise
39 from networkx.generators.classic import cycle_graph
40 from networkx.generators.classic import empty_graph
41 from networkx.generators.classic import path_graph
42
43 __all__ = ['grid_2d_graph', 'grid_graph', 'hypercube_graph',
44 'triangular_lattice_graph', 'hexagonal_lattice_graph']
45
46
47 @nodes_or_number([0, 1])
48 def grid_2d_graph(m, n, periodic=False, create_using=None):
49 """Returns the two-dimensional grid graph.
50
51 The grid graph has each node connected to its four nearest neighbors.
52
53 Parameters
54 ----------
55 m, n : int or iterable container of nodes
56 If an integer, nodes are from `range(n)`.
57 If a container, elements become the coordinate of the nodes.
58
59 periodic : bool (default: False)
60 If this is ``True`` the nodes on the grid boundaries are joined
61 to the corresponding nodes on the opposite grid boundaries.
62
63 create_using : NetworkX graph constructor, optional (default=nx.Graph)
64 Graph type to create. If graph instance, then cleared before populated.
65
66 Returns
67 -------
68 NetworkX graph
69 The (possibly periodic) grid graph of the specified dimensions.
70
71 """
72 G = empty_graph(0, create_using)
73 row_name, rows = m
74 col_name, cols = n
75 G.add_nodes_from((i, j) for i in rows for j in cols)
76 G.add_edges_from(((i, j), (pi, j))
77 for pi, i in pairwise(rows) for j in cols)
78 G.add_edges_from(((i, j), (i, pj))
79 for i in rows for pj, j in pairwise(cols))
80 if periodic is True:
81 if len(rows) > 2:
82 first = rows[0]
83 last = rows[-1]
84 G.add_edges_from(((first, j), (last, j)) for j in cols)
85 if len(cols) > 2:
86 first = cols[0]
87 last = cols[-1]
88 G.add_edges_from(((i, first), (i, last)) for i in rows)
89 # both directions for directed
90 if G.is_directed():
91 G.add_edges_from((v, u) for u, v in G.edges())
92 return G
93
94
95 def grid_graph(dim, periodic=False):
96 """Returns the *n*-dimensional grid graph.
97
98 The dimension *n* is the length of the list `dim` and the size in
99 each dimension is the value of the corresponding list element.
100
101 Parameters
102 ----------
103 dim : list or tuple of numbers or iterables of nodes
104 'dim' is a tuple or list with, for each dimension, either a number
105 that is the size of that dimension or an iterable of nodes for
106 that dimension. The dimension of the grid_graph is the length
107 of `dim`.
108
109 periodic : bool
110 If `periodic is True` the nodes on the grid boundaries are joined
111 to the corresponding nodes on the opposite grid boundaries.
112
113 Returns
114 -------
115 NetworkX graph
116 The (possibly periodic) grid graph of the specified dimensions.
117
118 Examples
119 --------
120 To produce a 2 by 3 by 4 grid graph, a graph on 24 nodes:
121
122 >>> from networkx import grid_graph
123 >>> G = grid_graph(dim=[2, 3, 4])
124 >>> len(G)
125 24
126 >>> G = grid_graph(dim=[range(7, 9), range(3, 6)])
127 >>> len(G)
128 6
129 """
130 dlabel = "%s" % dim
131 if not dim:
132 return empty_graph(0)
133
134 func = cycle_graph if periodic else path_graph
135 G = func(dim[0])
136 for current_dim in dim[1:]:
137 Gnew = func(current_dim)
138 G = cartesian_product(Gnew, G)
139 # graph G is done but has labels of the form (1, (2, (3, 1))) so relabel
140 H = relabel_nodes(G, flatten)
141 return H
142
143
144 def hypercube_graph(n):
145 """Returns the *n*-dimensional hypercube graph.
146
147 The nodes are the integers between 0 and ``2 ** n - 1``, inclusive.
148
149 For more information on the hypercube graph, see the Wikipedia
150 article `Hypercube graph`_.
151
152 .. _Hypercube graph: https://en.wikipedia.org/wiki/Hypercube_graph
153
154 Parameters
155 ----------
156 n : int
157 The dimension of the hypercube.
158 The number of nodes in the graph will be ``2 ** n``.
159
160 Returns
161 -------
162 NetworkX graph
163 The hypercube graph of dimension *n*.
164 """
165 dim = n * [2]
166 G = grid_graph(dim)
167 return G
168
169
170 def triangular_lattice_graph(m, n, periodic=False, with_positions=True,
171 create_using=None):
172 r"""Returns the $m$ by $n$ triangular lattice graph.
173
174 The `triangular lattice graph`_ is a two-dimensional `grid graph`_ in
175 which each square unit has a diagonal edge (each grid unit has a chord).
176
177 The returned graph has $m$ rows and $n$ columns of triangles. Rows and
178 columns include both triangles pointing up and down. Rows form a strip
179 of constant height. Columns form a series of diamond shapes, staggered
180 with the columns on either side. Another way to state the size is that
181 the nodes form a grid of `m+1` rows and `(n + 1) // 2` columns.
182 The odd row nodes are shifted horizontally relative to the even rows.
183
184 Directed graph types have edges pointed up or right.
185
186 Positions of nodes are computed by default or `with_positions is True`.
187 The position of each node (embedded in a euclidean plane) is stored in
188 the graph using equilateral triangles with sidelength 1.
189 The height between rows of nodes is thus $\sqrt(3)/2$.
190 Nodes lie in the first quadrant with the node $(0, 0)$ at the origin.
191
192 .. _triangular lattice graph: http://mathworld.wolfram.com/TriangularGrid.html
193 .. _grid graph: http://www-cs-students.stanford.edu/~amitp/game-programming/grids/
194 .. _Triangular Tiling: https://en.wikipedia.org/wiki/Triangular_tiling
195
196 Parameters
197 ----------
198 m : int
199 The number of rows in the lattice.
200
201 n : int
202 The number of columns in the lattice.
203
204 periodic : bool (default: False)
205 If True, join the boundary vertices of the grid using periodic
206 boundary conditions. The join between boundaries is the final row
207 and column of triangles. This means there is one row and one column
208 fewer nodes for the periodic lattice. Periodic lattices require
209 `m >= 3`, `n >= 5` and are allowed but misaligned if `m` or `n` are odd
210
211 with_positions : bool (default: True)
212 Store the coordinates of each node in the graph node attribute 'pos'.
213 The coordinates provide a lattice with equilateral triangles.
214 Periodic positions shift the nodes vertically in a nonlinear way so
215 the edges don't overlap so much.
216
217 create_using : NetworkX graph constructor, optional (default=nx.Graph)
218 Graph type to create. If graph instance, then cleared before populated.
219
220 Returns
221 -------
222 NetworkX graph
223 The *m* by *n* triangular lattice graph.
224 """
225 H = empty_graph(0, create_using)
226 if n == 0 or m == 0:
227 return H
228 if periodic:
229 if n < 5 or m < 3:
230 msg = "m > 2 and n > 4 required for periodic. m={}, n={}"
231 raise NetworkXError(msg.format(m, n))
232
233 N = (n + 1) // 2 # number of nodes in row
234 rows = range(m + 1)
235 cols = range(N + 1)
236 # Make grid
237 H.add_edges_from(((i, j), (i + 1, j)) for j in rows for i in cols[:N])
238 H.add_edges_from(((i, j), (i, j + 1)) for j in rows[:m] for i in cols)
239 # add diagonals
240 H.add_edges_from(((i, j), (i + 1, j + 1))
241 for j in rows[1:m:2] for i in cols[:N])
242 H.add_edges_from(((i + 1, j), (i, j + 1))
243 for j in rows[:m:2] for i in cols[:N])
244 # identify boundary nodes if periodic
245 if periodic is True:
246 for i in cols:
247 H = contracted_nodes(H, (i, 0), (i, m))
248 for j in rows[:m]:
249 H = contracted_nodes(H, (0, j), (N, j))
250 elif n % 2:
251 # remove extra nodes
252 H.remove_nodes_from(((N, j) for j in rows[1::2]))
253
254 # Add position node attributes
255 if with_positions:
256 ii = (i for i in cols for j in rows)
257 jj = (j for i in cols for j in rows)
258 xx = (0.5 * (j % 2) + i for i in cols for j in rows)
259 h = sqrt(3) / 2
260 if periodic:
261 yy = (h * j + .01 * i * i for i in cols for j in rows)
262 else:
263 yy = (h * j for i in cols for j in rows)
264 pos = {(i, j): (x, y) for i, j, x, y in zip(ii, jj, xx, yy)
265 if (i, j) in H}
266 set_node_attributes(H, pos, 'pos')
267 return H
268
269
270 def hexagonal_lattice_graph(m, n, periodic=False, with_positions=True,
271 create_using=None):
272 """Returns an `m` by `n` hexagonal lattice graph.
273
274 The *hexagonal lattice graph* is a graph whose nodes and edges are
275 the `hexagonal tiling`_ of the plane.
276
277 The returned graph will have `m` rows and `n` columns of hexagons.
278 `Odd numbered columns`_ are shifted up relative to even numbered columns.
279
280 Positions of nodes are computed by default or `with_positions is True`.
281 Node positions creating the standard embedding in the plane
282 with sidelength 1 and are stored in the node attribute 'pos'.
283 `pos = nx.get_node_attributes(G, 'pos')` creates a dict ready for drawing.
284
285 .. _hexagonal tiling: https://en.wikipedia.org/wiki/Hexagonal_tiling
286 .. _Odd numbered columns: http://www-cs-students.stanford.edu/~amitp/game-programming/grids/
287
288 Parameters
289 ----------
290 m : int
291 The number of rows of hexagons in the lattice.
292
293 n : int
294 The number of columns of hexagons in the lattice.
295
296 periodic : bool
297 Whether to make a periodic grid by joining the boundary vertices.
298 For this to work `n` must be odd and both `n > 1` and `m > 1`.
299 The periodic connections create another row and column of hexagons
300 so these graphs have fewer nodes as boundary nodes are identified.
301
302 with_positions : bool (default: True)
303 Store the coordinates of each node in the graph node attribute 'pos'.
304 The coordinates provide a lattice with vertical columns of hexagons
305 offset to interleave and cover the plane.
306 Periodic positions shift the nodes vertically in a nonlinear way so
307 the edges don't overlap so much.
308
309 create_using : NetworkX graph constructor, optional (default=nx.Graph)
310 Graph type to create. If graph instance, then cleared before populated.
311 If graph is directed, edges will point up or right.
312
313 Returns
314 -------
315 NetworkX graph
316 The *m* by *n* hexagonal lattice graph.
317 """
318 G = empty_graph(0, create_using)
319 if m == 0 or n == 0:
320 return G
321 if periodic and (n % 2 == 1 or m < 2 or n < 2):
322 msg = "periodic hexagonal lattice needs m > 1, n > 1 and even n"
323 raise NetworkXError(msg)
324
325 M = 2 * m # twice as many nodes as hexagons vertically
326 rows = range(M + 2)
327 cols = range(n + 1)
328 # make lattice
329 col_edges = (((i, j), (i, j + 1)) for i in cols for j in rows[:M + 1])
330 row_edges = (((i, j), (i + 1, j)) for i in cols[:n] for j in rows
331 if i % 2 == j % 2)
332 G.add_edges_from(col_edges)
333 G.add_edges_from(row_edges)
334 # Remove corner nodes with one edge
335 G.remove_node((0, M + 1))
336 G.remove_node((n, (M + 1) * (n % 2)))
337
338 # identify boundary nodes if periodic
339 if periodic:
340 for i in cols[:n]:
341 G = contracted_nodes(G, (i, 0), (i, M))
342 for i in cols[1:]:
343 G = contracted_nodes(G, (i, 1), (i, M + 1))
344 for j in rows[1:M]:
345 G = contracted_nodes(G, (0, j), (n, j))
346 G.remove_node((n, M))
347
348 # calc position in embedded space
349 ii = (i for i in cols for j in rows)
350 jj = (j for i in cols for j in rows)
351 xx = (0.5 + i + i // 2 + (j % 2) * ((i % 2) - .5)
352 for i in cols for j in rows)
353 h = sqrt(3) / 2
354 if periodic:
355 yy = (h * j + .01 * i * i for i in cols for j in rows)
356 else:
357 yy = (h * j for i in cols for j in rows)
358 # exclude nodes not in G
359 pos = {(i, j): (x, y) for i, j, x, y in zip(ii, jj, xx, yy) if (i, j) in G}
360 set_node_attributes(G, pos, 'pos')
361 return G