diff --git a/docs/_images/zephyr_embedding_5clique.png b/docs/_images/zephyr_embedding_5clique.png new file mode 100644 index 00000000..25ba4d00 Binary files /dev/null and b/docs/_images/zephyr_embedding_5clique.png differ diff --git a/docs/reference/drawing.rst b/docs/reference/drawing.rst index 06f72629..1434d36a 100644 --- a/docs/reference/drawing.rst +++ b/docs/reference/drawing.rst @@ -1,5 +1,6 @@ .. _drawing: +******* Drawing ******* @@ -22,7 +23,7 @@ Chimera Graph Functions draw_chimera Example ---------- +~~~~~~~ This example uses the :func:`.chimera_layout()` function to show the positions of nodes of a simple 5-node NetworkX graph in a Chimera lattice. It then uses the @@ -74,7 +75,7 @@ Pegasus Graph Functions pegasus_node_placer_2d Example ---------- +~~~~~~~ This example uses the :func:`.draw_pegasus()` function to show the positions of nodes of a simple 5-node graph on a small Pegasus lattice. @@ -101,3 +102,42 @@ of nodes of a simple 5-node graph on a small Pegasus lattice. :alt: Graph H overlaid on a Pegasus lattice size 2. Graph H (blue) overlaid on a small Pegasus lattice(yellow nodes and black edges). + +Zephyr Graph Functions +---------------------- + +.. automodule:: dwave_networkx.drawing.zephyr_layout + +.. autosummary:: + :toctree: generated/ + + draw_zephyr + draw_zephyr_embedding + draw_zephyr_yield + zephyr_layout + +Example +~~~~~~~ + +This example uses the :func:`.draw_zephyr_embedding` function to show the positions +of a five-node clique on a small Zephyr graph. + +.. code-block:: python + + >>> import dwave_networkx as dnx + >>> import matplotlib.pyplot as plt + >>> import networkx as nx + ... + >>> G = dnx.zephyr_graph(1) + >>> embedding = {"N1": [13, 44], "N2": [11], "N3": [41], "N4": [40], "N5": [9, 37]} + ... + >>> plt.ion() + >>> dnx.draw_zephyr_embedding(G, embedding, show_labels=True) + +.. figure:: ../_images/zephyr_embedding_5clique.png + :align: center + :name: zephyr_embedding_5clique.png + :scale: 60 % + :alt: Five-node clique embedded in a small Zephyr graph. + + Five-node clique embedded in a small Zephyr graph. diff --git a/docs/reference/generators.rst b/docs/reference/generators.rst index 95318c6f..e3e9818c 100644 --- a/docs/reference/generators.rst +++ b/docs/reference/generators.rst @@ -15,6 +15,7 @@ D-Wave Systems chimera_graph pegasus_graph + zephyr_graph Example ~~~~~~~ diff --git a/docs/reference/utilities.rst b/docs/reference/utilities.rst index 1f177908..c55722be 100644 --- a/docs/reference/utilities.rst +++ b/docs/reference/utilities.rst @@ -51,6 +51,24 @@ Pegasus pegasus_coordinates.pegasus_to_linear pegasus_coordinates.pegasus_to_nice + +Zephyr +~~~~~~ + +.. autosummary:: + :toctree: generated/ + + zephyr_coordinates.graph_to_linear + zephyr_coordinates.graph_to_zephyr + zephyr_coordinates.iter_linear_to_zephyr + zephyr_coordinates.iter_linear_to_zephyr_pairs + zephyr_coordinates.iter_zephyr_to_linear + zephyr_coordinates.iter_zephyr_to_linear_pairs + zephyr_coordinates.linear_to_zephyr + zephyr_coordinates.zephyr_to_linear + zephyr_sublattice_mappings + + Exceptions ---------- .. automodule:: dwave_networkx.exceptions diff --git a/docs/reference/utilities/index.rst b/docs/reference/utilities/index.rst index c635a31b..abcf4bfb 100644 --- a/docs/reference/utilities/index.rst +++ b/docs/reference/utilities/index.rst @@ -8,3 +8,5 @@ Coordinates Conversion .. autoclass:: chimera_coordinates .. autoclass:: pegasus_coordinates + +.. autoclass:: zephyr_coordinates diff --git a/dwave_networkx/drawing/zephyr_layout.py b/dwave_networkx/drawing/zephyr_layout.py index 4ec7dc9a..7f22d6eb 100644 --- a/dwave_networkx/drawing/zephyr_layout.py +++ b/dwave_networkx/drawing/zephyr_layout.py @@ -169,14 +169,15 @@ def draw_zephyr(G, **kwargs): edges (i.e., :math:`i=j`) are treated as linear biases. kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the ``pos`` parameter, which is not used by this - function. If ``linear_biases`` or ``quadratic_biases`` are provided, - any provided ``node_color`` or ``edge_color`` arguments are ignored. + See :func:`~networkx.drawing.nx_pylab.draw_networkx` for a description of + optional keywords, with the exception of the ``pos`` parameter, which is + unsupported. If the ``linear_biases`` or ``quadratic_biases`` parameters + are provided, any provided ``node_color`` or ``edge_color`` arguments are + ignored. Examples -------- - This example plots a Zephyr graph with size parameter 2. + This example plots a Zephyr graph with size parameter 2. >>> import networkx as nx >>> import dwave_networkx as dnx @@ -200,14 +201,14 @@ def draw_zephyr_embedding(G, *args, **kwargs): the :func:`dwave_networkx.zephyr_graph` function. emb : dict - Chains, as a dict of form {qubit: chain, ...}, where qubits are - nodes in G and chains are iterables of qubit labels. + Minor-embedding as a dict of form {node: chain, ...}, where ``node`` are + nodes in G and ``chain`` are iterables of qubit labels. embedded_graph : NetworkX graph (optional, default None) A graph that contains all keys of ``emb`` as nodes. If specified, edges of G are considered interactions if and only if (1) they exist between two chains of ``emb`` and (2) the keys of the - corresponding chains are connected by an edge in embedded_graph. + corresponding chains are connected by an edge in the given graph. If given, only couplers between chains based on this graph are displayed. interaction_edges : list (optional, default None) @@ -233,10 +234,11 @@ def draw_zephyr_embedding(G, *args, **kwargs): in G), and these overlaps are displayed as concentric circles. kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the ``pos`` parameter, which is not used by this - function. If ``linear_biases`` or ``quadratic_biases`` are provided, - any provided ``node_color`` or ``edge_color`` arguments are ignored. + See :func:`~networkx.drawing.nx_pylab.draw_networkx` for a description of + optional keywords, with the exception of the ``pos`` parameter, which is + unsupported. If the ``linear_biases`` or ``quadratic_biases`` parameters + are provided, any provided ``node_color`` or ``edge_color`` arguments are + ignored. """ draw_embedding(G, zephyr_layout(G), *args, **kwargs) @@ -257,17 +259,20 @@ def draw_zephyr_yield(G, **kwargs): length-4 tuples of floats between 0 and 1 inclusive. fault_shape : string, optional (default='x') - The shape of the fault nodes. Specification is as matplotlib.scatter - marker, one of 'so^>v`_; + for example "o" (circle), "^" (triangle)", "s" (square) and many more + options. fault_style : string, optional (default='dashed') Edge fault line style (solid|dashed|dotted|dashdot) kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the `pos` parameter which is not used by this - function. If `linear_biases` or `quadratic_biases` are provided, - any provided `node_color` or `edge_color` arguments are ignored. + See :func:`~networkx.drawing.nx_pylab.draw_networkx` for a description of + optional keywords, with the exception of the ``pos`` parameter, which is + unsupported. If the ``linear_biases`` or ``quadratic_biases`` parameters + are provided, any provided ``node_color`` or ``edge_color`` arguments are + ignored. """ try: assert(G.graph["family"] == "zephyr") diff --git a/dwave_networkx/generators/zephyr.py b/dwave_networkx/generators/zephyr.py index 0362c27f..823a1384 100644 --- a/dwave_networkx/generators/zephyr.py +++ b/dwave_networkx/generators/zephyr.py @@ -34,7 +34,9 @@ def zephyr_graph(m, t=4, create_using=None, node_list=None, edge_list=None, data=True, coordinates=False): """ - Creates a Zephyr graph [brk]_ with grid parameter ``m`` and tile parameter ``t``. + Creates a Zephyr graph with grid parameter ``m`` and tile parameter ``t``. + + The Zephyr topology is described in [brk]_. Parameters ---------- @@ -49,16 +51,16 @@ def zephyr_graph(m, t=4, create_using=None, node_list=None, edge_list=None, Iterable of nodes in the graph. If None, calculated from ``m``. Note that this list is used to remove nodes, so only specified nodes that belong to the base node set (described in the ``coordinates`` - parameter below) will be added. + parameter) are added. edge_list : iterable, optional (default None) Iterable of edges in the graph. If None, edges are generated as described below. The nodes in each edge must be labeled according to the - ``coordinates`` parameter, described below. + ``coordinates`` parameter. data : bool, optional (default True) If True, adds to each node an attribute with a format that depends on - the ``coordinates`` parameter: - a 5-tuple ``'zephyr_index'`` if ``coordinates`` is False - an integer ``'linear_index'`` if ``coordinates`` is True + the ``coordinates`` parameter: a 5-tuple ``'zephyr_index'`` if + ``coordinates`` is False and an integer ``'linear_index'`` if ``coordinates`` + is True. coordinates : bool, optional (default False) If True, node labels are 5-tuple Zephyr indices. @@ -67,6 +69,7 @@ def zephyr_graph(m, t=4, create_using=None, node_list=None, edge_list=None, G : NetworkX Graph A Zephyr lattice for grid parameter ``m`` and tile parameter ``t``. + The maximum degree of this graph is :math:`4t+4`. The number of nodes is given by @@ -77,7 +80,7 @@ def zephyr_graph(m, t=4, create_using=None, node_list=None, edge_list=None, * ``zephyr_graph(1, t)``: :math:`2t(8t+3)` * ``zephyr_graph(m, t)``: :math:`2t((8t+8)m^2-2m-3)` if m > 1 - A Zephyr lattice is a graph minor of a lattice similar to Chimera, where + A Zephyr lattice is a graph minor of a lattice similar to Chimera, where unit tiles have odd couplers similar to Pegasus graphs. In its most general definition, prelattice :math:`Q(2m+1)` contains nodes of the form @@ -93,8 +96,8 @@ def zephyr_graph(m, t=4, create_using=None, node_list=None, edge_list=None, The minor---a Zephyr lattice---is constructed by contracting pairs of external edges:: - ``I(0, w, k, j, z) = [(2*z+j, w, 0, 2*k+j), (2*z+1+j, w, 0, 2*k+j)]`` - ``I(1, w, k, j, z) = [(w, 2*z+j, 1, 2*k+j), (w, 2*z+1+j, 1, 2*k+j)]`` + I(0, w, k, j, z) = [(2*z+j, w, 0, 2*k+j), (2*z+1+j, w, 0, 2*k+j)] + I(1, w, k, j, z) = [(w, 2*z+j, 1, 2*k+j), (w, 2*z+1+j, 1, 2*k+j)] and deleting the prelattice nodes of any pair not fully contained in :math:`Q(2m+1)`. @@ -123,7 +126,7 @@ def zephyr_graph(m, t=4, create_using=None, node_list=None, edge_list=None, Linear indices are computed from Zephyr indices by the formula:: - ``q = (((u * (2 * m + 1) + w) * t + k) * 2 + j) * m + z`` + q = (((u * (2 * m + 1) + w) * t + k) * 2 + j) * m + z Examples @@ -377,7 +380,7 @@ def _zephyr_zephyr_sublattice_mapping(source_to_zephyr, zephyr_to_target, offset The mappings implemented by this function interpret offsets in the grid of the Chimera(2m+1, 2m+1, 2*t) graphs underlying the source and tartget Zephyr - graphs. The formulas (see implementation) are somewhat complex, because + graphs. The formulas (see implementation) are somewhat complex, because * a shift by a y-unit induces a reversal of the orthogonal minor offset (j index) of vertical qubits, @@ -402,7 +405,7 @@ def _zephyr_zephyr_sublattice_mapping(source_to_zephyr, zephyr_to_target, offset The function implementing the mapping from the source Zephyr graph to the target Zephyr graph. We store ``offset`` in the attribute ``mapping.offset`` for later reconstruction. - + """ y_offset, x_offset = offset @@ -428,18 +431,18 @@ def _single_chimera_zephyr_sublattice_mapping(source_to_chimera, zephyr_to_targe The mappings implemented by this function view a ``chimera(2*m, 2*m, t)`` as a subgraph of ``zephyr_graph(m, t)`` through the mapping - + (2*y+j, x, 0, k) -> (0, x, k, j, y) (y, 2*x+j, 1, k) -> (1, y, k, j, x) - + which interprets odd couplers of Zephyr as external couplers of Chimera. The above is a slight simplification of matters; it is the simplest of a family of :math:`(t+1)^2` offsets (see how ``k_offset0`` and ``k_offset`` are used in the implementation). - + Additionally, the sublattice represented by the source graph can have x- and y-offsets into the chimera graph above, as with ordinary Chimera - subgraph mappings. + subgraph mappings. Parameters ---------- @@ -457,7 +460,7 @@ def _single_chimera_zephyr_sublattice_mapping(source_to_chimera, zephyr_to_targe The function implementing the mapping from the source Zephyr graph to the target Zephyr graph. We store ``offset`` in the attribute ``mapping.offset`` for later reconstruction. - + """ t, y_offset, x_offset, k_offset0, k_offset1 = offset @@ -476,7 +479,7 @@ def mapping(q): mapping.offset = offset return mapping - + def _double_chimera_zephyr_sublattice_mapping(source_to_chimera, zephyr_to_target, offset): """Constructs a mapping from a Chimera graph to a Zephyr graph, via an offset. This function is used by zephyr_sublattice_mappings, and serves to construct @@ -484,13 +487,13 @@ def _double_chimera_zephyr_sublattice_mapping(source_to_chimera, zephyr_to_targe The mappings implemented by this function view a ``chimera(m, m, 2*t)`` as a subgraph of ``zephyr_graph(m, t)`` through the mappings - + (y, x, 0, k) -> (0, x, k, j0, y) (y, x, 1, k) -> (1, y, k, j1, x) - - where j0 and j1 are each 0 or 1. Additionally, the sublattice represented + + where j0 and j1 are each 0 or 1. Additionally, the sublattice represented by the source graph can have x- and y-offsets into the chimera graph above, - as with ordinary Chimera subgraph mappings. + as with ordinary Chimera subgraph mappings. Parameters ---------- @@ -508,7 +511,7 @@ def _double_chimera_zephyr_sublattice_mapping(source_to_chimera, zephyr_to_targe The function implementing the mapping from the source Zephyr graph to the target Zephyr graph. We store ``offset`` in the attribute ``mapping.offset`` for later reconstruction. - + """ t, y_offset, x_offset, j0, j1 = offset def mapping(q): @@ -518,7 +521,7 @@ def mapping(q): return zephyr_to_target((u, 2 * (y + y_offset) + j0 + wz, kz, j1, x + x_offset)) else: return zephyr_to_target((u, 2 * (x + x_offset) + j1 + wz, kz, j0, y + y_offset)) - + #store the offset in the mapping, so the user can reconstruct it mapping.offset = offset @@ -527,36 +530,38 @@ def mapping(q): def zephyr_sublattice_mappings(source, target, offset_list=None): """Yields mappings from a Chimera or Zephyr graph into a Zephyr graph. - + A sublattice mapping is a function from nodes of + * a ``zephyr_graph(m_s, t)`` to nodes of a ``zephyr_graph(m_t, t)`` - where ``m_s <= m_t``, + where ``m_s <= m_t``, * a ``chimera_graph(m_s, n_s, t)`` to nodes of a ``zephyr_graph(m_t, t)`` - where ``m_s <= 2*m_t`` and ``n_s <= 2*m_t``, or + where ``m_s <= 2*m_t`` and ``n_s <= 2*m_t``, or * a ``chimera_graph(m_s, n_s, 2*t)`` to nodes of a ``zephyr_graph(m_t, t)`` - where ``m_s <= m_t`` and ``n_s <= m_t``, or + where ``m_s <= m_t`` and ``n_s <= m_t``, or - This is used to identify subgraphs of the target Zephyr graphs which are - isomorphic to the source graph. However, if the target graph is not of + This is used to identify subgraphs of the target Zephyr graphs which are + isomorphic to the source graph. However, if the target graph is not of perfect yield, these functions do not generally produce isomorphisms (for example, if a node is missing in the target graph, it may still appear in the image of the source graph). - - Note that we require the tile parameter of Chimera graphs to be either the - same our double that of the target Zephyr graphs; or if both graphs are - Zephyr graphs, we require the tile parameters to be the same. The mappings - we produce preserve the linear ordering of tile indices; see + + Note that the tile parameter of Chimera graphs must be either the + same or double that of the target Zephyr graphs; if both graphs are + Zephyr graphs, the tile parameters must be the same. The mappings + produced preserve the linear ordering of tile indices; see the ``_zephyr_zephyr_sublattice_mapping``, ``_double_chimera_zephyr_sublattice_mapping``, and - ``_single_chimera_zephyr_sublattice_mapping`` for more details. - - Academic note: the full group of isomorphisms of a Chimera graph includes + ``_single_chimera_zephyr_sublattice_mapping`` internal functions for more + details. + + Academic note: the full group of isomorphisms of a Chimera graph includes mappings which permute tile indices on a per-row and per-column basis, in - addition to reflections and rotations of the grid of unit cells where + addition to reflections and rotations of the grid of unit cells where rotations by 90 and 270 degrees induce a change in orientation. The - isomorphisms of Zephyr graphs permit permutations of major tile indices on a + isomorphisms of Zephyr graphs permit permutations of major tile indices on a per-row and per-column basis, in addition to reflections of the grid which - induce inversion of orthogonal minor offsets, and rotations which induce + induce inversion of orthogonal minor offsets, and rotations which induce inversions of minor offsets and/or orientation. The full set of sublattice mappings would take those isomorphisms into account; we do not undertake that complexity here. @@ -564,22 +569,22 @@ def zephyr_sublattice_mappings(source, target, offset_list=None): Parameters ---------- source : NetworkX Graph - The Chimera or Zephyr graph that nodes are input from + The Chimera or Zephyr graph that nodes are input from. target : NetworkX Graph - The Zephyr graph that nodes are output to + The Zephyr graph that nodes are output to. offset_list : iterable (tuple), optional (default None) - An iterable of offsets. This can be used to reconstruct a set of + An iterable of offsets. This can be used to reconstruct a set of mappings, as the offset used to generate a single mapping is stored in the ``offset`` attribute of that mapping. - + Yields ------ mapping : function A function from nodes of the source graph, to nodes of the target graph. The offset used to generate this mapping is stored in - ``mapping.offset`` -- these can be collected and passed into + ``mapping.offset`` -- these can be collected and passed into ``offset_list`` in a later session. - + """ if target.graph.get('family') != 'zephyr': raise ValueError("source graphs must a Zephyr graph constructed by dwave_networkx.zephyr_graph") @@ -595,7 +600,7 @@ def zephyr_to_target(q): else: raise ValueError(f"Zephyr node labeling {labels_t} not recognized") - labels_s = source.graph['labels'] + labels_s = source.graph['labels'] if source.graph.get('family') == 'chimera': t_t = source.graph['tile'] m_s = source.graph['rows'] @@ -648,4 +653,3 @@ def source_to_inner(q): for offset in offset_list: yield make_mapping(source_to_inner, zephyr_to_target, offset) -