Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add topology enums and dispatch decorator #248

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions dwave_networkx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from dwave_networkx.topology import *

import dwave_networkx.generators
from dwave_networkx.generators import *

Expand Down
23 changes: 8 additions & 15 deletions dwave_networkx/drawing/chimera_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@
from networkx import draw

from dwave_networkx.drawing.qubit_layout import draw_qubit_graph, draw_embedding, draw_yield
from dwave_networkx.generators.chimera import chimera_graph, find_chimera_indices, chimera_coordinates

from dwave_networkx.generators.chimera import find_chimera_indices, chimera_coordinates, defect_free_chimera
from ..topology import CHIMERA
boothby marked this conversation as resolved.
Show resolved Hide resolved

__all__ = ['chimera_layout', 'draw_chimera', 'draw_chimera_embedding', 'draw_chimera_yield']


@CHIMERA.layout.implementation
def chimera_layout(G, scale=1., center=None, dim=2):
"""Positions the nodes of graph ``G`` in a Chimera layout.

Expand Down Expand Up @@ -71,7 +72,7 @@ def chimera_layout(G, scale=1., center=None, dim=2):

# now we get chimera coordinates for the translation
# first, check if we made it
if G.graph.get("family") == "chimera":
if G.graph.get("family") == CHIMERA:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be compared by identity since both are enum members, right?

Suggested change
if G.graph.get("family") == CHIMERA:
if G.graph.get("family") is CHIMERA:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only concern with making that change is backwards-compatibilty with pickled graphs. I'm happy to make the change if you're unconcerned with that.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not particularly concerned, but I can't say that I'm aware of how much (if at all) this might disrupt some users that have old pickled instances of graphs. If so, keeping it as an eq comparison and adding a comment about it being kept for backward compatibility (potentially a deprecation note for the future).

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes should preferably be tracked in a changelog, possibly under breaking.

m = G.graph['rows']
n = G.graph['columns']
t = G.graph['tile']
Expand Down Expand Up @@ -189,6 +190,7 @@ def _xy_coords(i, j, u, k):
return _xy_coords


@CHIMERA.draw.implementation
def draw_chimera(G, **kwargs):
"""Draws graph ``G`` in a Chimera layout.

Expand Down Expand Up @@ -230,6 +232,7 @@ def draw_chimera(G, **kwargs):
draw_qubit_graph(G, chimera_layout(G), **kwargs)


@CHIMERA.draw_embedding.implementation
def draw_chimera_embedding(G, *args, **kwargs):
"""Draws an embedding onto the Chimera graph ``G``.

Expand Down Expand Up @@ -282,6 +285,7 @@ def draw_chimera_embedding(G, *args, **kwargs):
draw_embedding(G, chimera_layout(G), *args, **kwargs)


@CHIMERA.draw_yield.implementation
def draw_chimera_yield(G, **kwargs):
"""Draws graph ``G`` with highlighted faults.

Expand Down Expand Up @@ -312,16 +316,5 @@ def draw_chimera_yield(G, **kwargs):
the :func:`~networkx.drawing.nx_pylab.draw_networkx` ``node_color``
or ``edge_color`` parameters are ignored.
"""
try:
assert(G.graph["family"] == "chimera")
m = G.graph["rows"]
n = G.graph["columns"]
t = G.graph["tile"]
coordinates = G.graph["labels"] == "coordinate"
except:
raise ValueError("Target chimera graph needs to have columns, rows, \
tile, and label attributes to be able to identify faulty qubits.")

perfect_graph = chimera_graph(m,n,t, coordinates=coordinates)

perfect_graph = defect_free_chimera(G)
draw_yield(G, chimera_layout(perfect_graph), perfect_graph, **kwargs)
29 changes: 9 additions & 20 deletions dwave_networkx/drawing/pegasus_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@
import numpy as np

from dwave_networkx.drawing.qubit_layout import draw_qubit_graph, draw_embedding, draw_yield
from dwave_networkx.generators.pegasus import pegasus_graph, pegasus_coordinates
from dwave_networkx.generators.pegasus import pegasus_coordinates, defect_free_pegasus
from dwave_networkx.drawing.chimera_layout import chimera_node_placer_2d

from ..topology import PEGASUS

__all__ = ['pegasus_layout',
'draw_pegasus',
'draw_pegasus_embedding',
'draw_pegasus_yield',
]


@PEGASUS.layout.implementation
def pegasus_layout(G, scale=1., center=None, dim=2, crosses=False):
"""Positions the nodes of graph ``G`` in a Pegasus topology.

Expand Down Expand Up @@ -70,7 +70,7 @@ def pegasus_layout(G, scale=1., center=None, dim=2, crosses=False):

"""

if not isinstance(G, nx.Graph) or G.graph.get("family") != "pegasus":
if not isinstance(G, nx.Graph) or G.graph.get("family") != PEGASUS:
raise ValueError("G must be generated by dwave_networkx.pegasus_graph")

if G.graph.get('labels') == 'nice':
Expand Down Expand Up @@ -188,7 +188,7 @@ def _xy_coords(u, w, k, z):

return _xy_coords


@PEGASUS.draw.implementation
def draw_pegasus(G, crosses=False, **kwargs):
"""Draws graph ``G`` in a Pegasus topology.

Expand Down Expand Up @@ -236,6 +236,7 @@ def draw_pegasus(G, crosses=False, **kwargs):
draw_qubit_graph(G, pegasus_layout(G, crosses=crosses), **kwargs)


@PEGASUS.draw_embedding.implementation
def draw_pegasus_embedding(G, *args, **kwargs):
"""Draws an embedding onto Pegasus graph ``G``.

Expand Down Expand Up @@ -292,6 +293,7 @@ def draw_pegasus_embedding(G, *args, **kwargs):
crosses = kwargs.pop("crosses", False)
draw_embedding(G, pegasus_layout(G, crosses=crosses), *args, **kwargs)

@PEGASUS.draw_yield.implementation
def draw_pegasus_yield(G, **kwargs):
"""Draws graph ``G`` with highlighted faults.

Expand Down Expand Up @@ -322,18 +324,5 @@ def draw_pegasus_yield(G, **kwargs):
the :func:`~networkx.drawing.nx_pylab.draw_networkx` ``node_color``
or ``edge_color`` parameters are ignored.
"""
try:
assert(G.graph["family"] == "pegasus")
m = G.graph['columns']
offset_lists = (G.graph['vertical_offsets'], G.graph['horizontal_offsets'])
coordinates = G.graph["labels"] == "coordinate"
nice = G.graph["labels"] == "nice"
# Can't interpret fabric_only from graph attributes
except:
raise ValueError("Target pegasus graph needs to have columns, rows, \
tile, and label attributes to be able to identify faulty qubits.")


perfect_graph = pegasus_graph(m, offset_lists=offset_lists, coordinates=coordinates, nice_coordinates=nice)

draw_yield(G, pegasus_layout(perfect_graph), perfect_graph, **kwargs)
perfect_graph = defect_free_pegasus(G)
draw_yield(G, pegasus_layout(perfect_graph), perfect_graph, **kwargs)
6 changes: 4 additions & 2 deletions dwave_networkx/drawing/qubit_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

from dwave_networkx.drawing.distinguishable_colors import distinguishable_color_map

__all__ = ['draw_qubit_graph']
__all__ = ['draw_qubit_graph_generic', 'draw_embedding_generic', 'draw_yield_generic']



def draw_qubit_graph(G, layout, linear_biases=None, quadratic_biases=None,
Expand Down Expand Up @@ -430,7 +431,6 @@ def draw_yield(G, layout, perfect_graph, unused_color=(0.9, 0.9, 0.9, 1.0),
perfect_graph : NetworkX graph
The graph to be drawn with highlighted faults


unused_color : tuple or color string (optional, default (0.9,0.9,0.9,1.0))
The color to use for nodes and edges of G which are not faults.
If unused_color is None, these nodes and edges will not be shown at all.
Expand Down Expand Up @@ -487,3 +487,5 @@ def draw_yield(G, layout, perfect_graph, unused_color=(0.9, 0.9, 0.9, 1.0),
draw(perfect_graph, layout, nodelist=nodelist, edgelist=edgelist,
node_color=unused_node_color, edge_color=unused_edge_color,
**kwargs)


26 changes: 9 additions & 17 deletions dwave_networkx/drawing/zephyr_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@
from networkx import draw
import numpy as np

from dwave_networkx.drawing.qubit_layout import draw_qubit_graph, draw_embedding, draw_yield
from dwave_networkx.generators.zephyr import zephyr_graph, zephyr_coordinates

from dwave_networkx.drawing.qubit_layout import draw_qubit_graph, draw_embedding
from dwave_networkx.generators.zephyr import zephyr_coordinates, defect_free_zephyr
from ..topology import ZEPHYR

__all__ = ['zephyr_layout',
'draw_zephyr',
'draw_zephyr_embedding',
'draw_zephyr_yield',
]


@ZEPHYR.layout.implementation
def zephyr_layout(G, scale=1., center=None, dim=2):
"""Positions the nodes of graph ``G`` in a Zephyr topology.

Expand Down Expand Up @@ -65,7 +65,7 @@ def zephyr_layout(G, scale=1., center=None, dim=2):

"""

if not isinstance(G, nx.Graph) or G.graph.get("family") != "zephyr":
if not isinstance(G, nx.Graph) or G.graph.get("family") != ZEPHYR:
raise ValueError("G must be generated by dwave_networkx.zephyr_graph")

xy_coords = zephyr_node_placer_2d(G, scale, center, dim)
Expand Down Expand Up @@ -160,6 +160,7 @@ def _xy_coords(u, w, k, j, z):
return _xy_coords


@ZEPHYR.draw.implementation
def draw_zephyr(G, **kwargs):
"""Draws graph ``G`` in a Zephyr topology.

Expand Down Expand Up @@ -202,6 +203,7 @@ def draw_zephyr(G, **kwargs):
draw_qubit_graph(G, zephyr_layout(G), **kwargs)


@ZEPHYR.draw_embedding.implementation
def draw_zephyr_embedding(G, *args, **kwargs):
"""Draws an embedding onto a Zephyr graph ``G``.

Expand Down Expand Up @@ -252,6 +254,7 @@ def draw_zephyr_embedding(G, *args, **kwargs):
"""
draw_embedding(G, zephyr_layout(G), *args, **kwargs)

@ZEPHYR.draw_yield.implementation
def draw_zephyr_yield(G, **kwargs):
"""Draws graph ``G`` with highlighted faults, according to the Zephyr layout.

Expand Down Expand Up @@ -282,16 +285,5 @@ def draw_zephyr_yield(G, **kwargs):
the :func:`~networkx.drawing.nx_pylab.draw_networkx` ``node_color``
or ``edge_color`` parameters are ignored.
"""
try:
assert(G.graph["family"] == "zephyr")
m = G.graph['columns']
t = G.graph['tile']
coordinates = G.graph["labels"] == "coordinate"
except:
raise ValueError("Target zephyr graph needs to have columns, rows, \
tile, and label attributes to be able to identify faulty qubits.")


perfect_graph = zephyr_graph(m, t, coordinates=coordinates)

perfect_graph = defect_free_zephyr(G)
draw_yield(G, zephyr_layout(perfect_graph), perfect_graph, **kwargs)
23 changes: 20 additions & 3 deletions dwave_networkx/generators/chimera.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from itertools import product

from .common import _add_compatible_nodes, _add_compatible_edges, _add_compatible_terms
from ..topology import CHIMERA

__all__ = ['chimera_graph',
'chimera_coordinates',
Expand All @@ -39,6 +40,7 @@
]


@CHIMERA.generator.implementation
def chimera_graph(m, n=None, t=None, create_using=None, node_list=None, edge_list=None,
data=True, coordinates=False, check_node_list=False, check_edge_list=False):
"""Creates a Chimera lattice of size (m, n, t).
Expand Down Expand Up @@ -154,7 +156,7 @@ def chimera_graph(m, n=None, t=None, create_using=None, node_list=None, edge_lis

G.name = "chimera_graph(%s, %s, %s)" % (m, n, t)

construction = (("family", "chimera"), ("rows", m), ("columns", n),
construction = (("family", CHIMERA), ("rows", m), ("columns", n),
("tile", t), ("data", data),
("labels", "coordinate" if coordinates else "int"))

Expand Down Expand Up @@ -252,6 +254,18 @@ def checkadd(v, q):
return G


@CHIMERA.defect_free_graph.implementation
def defect_free_chimera(G):
"""Construct a defect-free Chimera graph based on the properties of G."""
Comment on lines +258 to +259
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Parameters and Returns.

attrib = G.graph
family = attrib.get('family')
if family != CHIMERA:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if family != CHIMERA:
if family is not CHIMERA:

Similarly in other files.

raise ValueError("G must be constructed by dwave_networkx.chimera_graph")
args = attrib['rows'], attrib['columns'], attrib['tile']
kwargs = {'coordinates': attrib['labels'] == 'coordinate'}
return chimera_graph(*args, **kwargs)


def find_chimera_indices(G):
"""Determines the Chimera indices of the nodes in graph ``G``.

Expand Down Expand Up @@ -331,6 +345,7 @@ def find_chimera_indices(G):
raise Exception('not yet implemented for Chimera graphs with more than one tile')


@CHIMERA.coordinates.implementation
class chimera_coordinates(object):
"""Provides coordinate converters for the chimera indexing scheme.

Expand Down Expand Up @@ -681,7 +696,7 @@ def mapping(q):

return mapping


@CHIMERA.sublattice_mappings.implementation
def chimera_sublattice_mappings(source, target, offset_list=None):
r"""Yields mappings from a Chimera graph into a larger Chimera graph.

Expand Down Expand Up @@ -738,7 +753,7 @@ def chimera_sublattice_mappings(source, target, offset_list=None):
into account, this function does not handle that complex task.

"""
if not (source.graph.get('family') == target.graph.get('family') == 'chimera'):
if not (source.graph.get('family') == target.graph.get('family') == CHIMERA):
raise ValueError("source and target graphs must be Chimera graphs constructed by dwave_networkx.chimera_graph")

t = source.graph['tile']
Expand Down Expand Up @@ -775,6 +790,8 @@ def chimera_to_target(q):
for offset in offset_list:
yield _chimera_sublattice_mapping(source_to_chimera, chimera_to_target, offset)


@CHIMERA.torus_generator.implementation
def chimera_torus(m, n=None, t=None, node_list=None, edge_list=None):
"""Creates a defect-free Chimera lattice of size :math:`(m, n, t)`
subject to periodic boundary conditions.
Expand Down
14 changes: 14 additions & 0 deletions dwave_networkx/generators/common.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# Copyright 2022 D-Wave
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


def _add_compatible_edges(G, edge_list):
# Check edge_list defines a subgraph of G and create subgraph.
Expand Down
Loading