Esempio n. 1
0
def draw_embedding(G,
                   layout,
                   emb,
                   embedded_graph=None,
                   interaction_edges=None,
                   chain_color=None,
                   unused_color=(0.9, 0.9, 0.9, 1.0),
                   cmap=None,
                   show_labels=False,
                   overlapped_embedding=False,
                   **kwargs):
    """Draws an embedding onto the graph G, according to layout.

    If interaction_edges is not None, then only display the couplers in that
    list.  If embedded_graph is not None, the only display the couplers between
    chains with intended couplings according to embedded_graph.

    Parameters
    ----------
    G : NetworkX graph
        The graph to be drawn

    layout : dict
        A dict of coordinates associated with each node in G.  Should
        be of the form {node: coordinate, ...}.  Coordinates will be
        treated as vectors, and should all have the same length.

    emb : dict
        A dict of chains associated with each node in G.  Should be
        of the form {node: chain, ...}.  Chains should be iterables
        of qubit labels (qubits are nodes in G).

    embedded_graph : NetworkX graph (optional, default None)
        A graph which contains all keys of emb as nodes.  If specified,
        edges of G will be considered interactions if and only if they
        exist between two chains of emb if their keys are connected by
        an edge in embedded_graph

    interaction_edges : list (optional, default None)
        A list of edges which will be used as interactions.

    show_labels: boolean (optional, default False)
        If show_labels is True, then each chain in emb is labelled with its key.

    chain_color : dict (optional, default None)
        A dict of colors associated with each key in emb.  Should be
        of the form {node: rgba_color, ...}.  Colors should be length-4
        tuples of floats between 0 and 1 inclusive. If chain_color is None,
        each chain will be assigned a different color.

    cmap : str or matplotlib colormap (optional, default None)
        A matplotlib colormap for coloring of chains.  Only used if chain_color
        is None.

    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 involved
        in chains, and edges which are neither chain edges nor interactions.
        If unused_color is None, these nodes and edges will not be shown at all.

    overlapped_embedding: boolean (optional, default False)
        If overlapped_embedding is True, then chains in emb may overlap (contain
        the same vertices in G), and the drawing will display these overlaps 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.
    """
    try:
        import matplotlib.pyplot as plt
        import matplotlib as mpl
    except ImportError:
        raise ImportError("Matplotlib and numpy required for draw_chimera()")

    if nx.utils.is_string_like(unused_color):
        from matplotlib.colors import colorConverter
        alpha = kwargs.get('alpha', 1.0)
        unused_color = colorConverter.to_rgba(unused_color, alpha)

    if chain_color is None:
        import matplotlib.cm
        n = max(1., len(emb) - 1.)
        if cmap:
            color = matplotlib.cm.get_cmap(cmap)
        else:
            color = distinguishable_color_map(int(n + 1))
        var_i = {v: i for i, v in enumerate(emb)}
        chain_color = {v: color(i / n) for i, v in enumerate(emb)}

    if overlapped_embedding:
        bags = compute_bags(G, emb)
        base_node_size = kwargs.get('node_size', 100)
        node_size_dict = {v: base_node_size for v in G.nodes()}
        G, emb, interaction_edges = unoverlapped_embedding(
            G, emb, interaction_edges)
        for node, data in G.nodes(data=True):
            if 'dummy' in data:
                v, x = node
                layout[node] = layout[v]

        for v, bag in bags.items():
            for i, x in enumerate(bag):
                node_size_dict[(v, x)] = base_node_size * (len(bag) - i)**2

        kwargs['node_size'] = [node_size_dict[p] for p in G.nodes()]

    qlabel = {q: v for v, chain in emb.items() for q in chain}
    edgelist = []
    edge_color = []
    background_edgelist = []
    background_edge_color = []

    if interaction_edges is not None:
        interactions = nx.Graph()
        interactions.add_edges_from(interaction_edges)

        def show(p, q, u, v):
            return interactions.has_edge(p, q)
    elif embedded_graph is not None:

        def show(p, q, u, v):
            return embedded_graph.has_edge(u, v)
    else:

        def show(p, q, u, v):
            return True

    for (p, q) in G.edges():
        u = qlabel.get(p)
        v = qlabel.get(q)
        if u is None or v is None:
            ec = unused_color
        elif u == v:
            ec = chain_color.get(u)
        elif show(p, q, u, v):
            ec = (0, 0, 0, 1)
        else:
            ec = unused_color

        if ec == unused_color:
            background_edgelist.append((p, q))
            background_edge_color.append(ec)
        elif ec is not None:
            edgelist.append((p, q))
            edge_color.append(ec)

    nodelist = []
    node_color = []
    for p in G.nodes():
        u = qlabel.get(p)
        if u is None:
            pc = unused_color
        else:
            pc = chain_color.get(u)

        if pc is not None:
            nodelist.append(p)
            node_color.append(pc)

    labels = {}
    if show_labels:
        if overlapped_embedding:
            node_labels = {q: [] for q in bags.keys()}
            node_index = {p: i for i, p in enumerate(G.nodes())}
            for v in emb.keys():
                v_labelled = False
                chain = emb[v]
                for node in chain:
                    (q, _) = node
                    if len(bags[q]) == 1:
                        # if there's a node that only has this label, use that
                        labels[q] = str(v)
                        v_labelled = True
                        break
                if not v_labelled and chain:
                    # otherwise, pick a random node for this label
                    node = random.choice(list(chain))
                    (q, _) = node
                    node_labels[q].append(v)
            for q, label_vars in node_labels.items():
                x, y = layout[q]
                # TODO: find a better way of placing labels around the outside of nodes.
                # Currently, if the graph is resized, labels will appear at a strange distance from the vertices.
                # To fix this, the "scale" value below, rather than being a fixed constant, should be determined using
                # both the size of the nodes and the size of the coordinate space of the graph.
                scale = 0.1
                # spread the labels evenly around the node.
                for i, v in enumerate(label_vars):
                    theta = 2 * math.pi * i / len(label_vars)
                    new_x = x + scale * math.sin(theta)
                    new_y = y + scale * math.cos(theta)

                    plt.text(new_x,
                             new_y,
                             str(v),
                             color=node_color[node_index[(q, v)]],
                             horizontalalignment='center',
                             verticalalignment='center')
        else:
            for v in emb.keys():
                c = emb[v]
                labels[list(c)[0]] = str(v)

    # draw the background (unused) graph first
    if unused_color is not None:
        draw(G,
             layout,
             nodelist=nodelist,
             edgelist=background_edgelist,
             node_color=node_color,
             edge_color=background_edge_color,
             **kwargs)

    draw(G,
         layout,
         nodelist=nodelist,
         edgelist=edgelist,
         node_color=node_color,
         edge_color=edge_color,
         labels=labels,
         **kwargs)
Esempio n. 2
0
def draw_embedding(G, layout, emb, embedded_graph=None, interaction_edges=None,
                   chain_color=None, unused_color=(0.9,0.9,0.9,1.0), cmap=None,
                   show_labels=False, **kwargs):
    """Draws an embedding onto the graph G, according to layout.

    If interaction_edges is not None, then only display the couplers in that
    list.  If embedded_graph is not None, the only display the couplers between
    chains with intended couplings according to embedded_graph.

    Parameters
    ----------
    G : NetworkX graph
        The graph to be drawn

    layout : dict
        A dict of coordinates associated with each node in G.  Should
        be of the form {node: coordinate, ...}.  Coordinates will be
        treated as vectors, and should all have the same length.

    emb : dict
        A dict of chains associated with each node in G.  Should be
        of the form {node: chain, ...}.  Chains should be iterables
        of qubit labels (qubits are nodes in G).

    embedded_graph : NetworkX graph (optional, default None)
        A graph which contains all keys of emb as nodes.  If specified,
        edges of G will be considered interactions if and only if they
        exist between two chains of emb if their keys are connected by
        an edge in embedded_graph

    interaction_edges : list (optional, default None)
        A list of edges which will be used as interactions.

    show_labels: boolean (optional, default False)
        If show_labels is True, then each chain in emb is labelled with its key.

    chain_color : dict (optional, default None)
        A dict of colors associated with each key in emb.  Should be
        of the form {node: rgba_color, ...}.  Colors should be length-4
        tuples of floats between 0 and 1 inclusive. If chain_color is None,
        each chain will be assigned a different color.

    unused_color : tuple (optional, default (0.9,0.9,0.9,1.0))
        The color to use for nodes and edges of G which are not involved
        in chains, and edges which are neither chain edges nor interactions.
        If unused_color is None, these nodes and edges will not be shown at all.

    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.
    """
    try:
        import matplotlib.pyplot as plt
        import matplotlib as mpl
    except ImportError:
        raise ImportError("Matplotlib and numpy required for draw_chimera()")

    if chain_color is None:
        import matplotlib.cm
        n = max(1., len(emb) - 1.)
        if kwargs.get("cmap"):
            color = matplotlib.cm.get_cmap(kwargs.get("cmap"))
        else:
            color = distinguishable_color_map(int(n+1))
        var_i = {v: i for i, v in enumerate(emb)}
        chain_color = {v: color(i/n) for i, v in enumerate(emb)}

    qlabel = {q: v for v, chain in iteritems(emb) for q in chain}
    edgelist = []
    edge_color = []
    background_edgelist = []
    background_edge_color = []

    if interaction_edges is not None:
        interactions = nx.Graph()
        interactions.add_edges_from(interaction_edges)

        def show(p, q, u, v): return interactions.has_edge(p, q)
    elif embedded_graph is not None:
        def show(p, q, u, v): return embedded_graph.has_edge(u, v)
    else:
        def show(p, q, u, v): return True

    for (p, q) in G.edges():
        u = qlabel.get(p)
        v = qlabel.get(q)
        if u is None or v is None:
            ec = unused_color
        elif u == v:
            ec = chain_color.get(u)
        elif show(p, q, u, v):
            ec = (0, 0, 0, 1)
        else:
            ec = unused_color

        if ec == unused_color:
            background_edgelist.append((p, q))
            background_edge_color.append(ec)
        elif ec is not None:
            edgelist.append((p, q))
            edge_color.append(ec)

    nodelist = []
    node_color = []
    for p in G.nodes():
        u = qlabel.get(p)
        if u is None:
            pc = unused_color
        else:
            pc = chain_color.get(u)

        if pc is not None:
            nodelist.append(p)
            node_color.append(pc)

    labels = {}
    if show_labels:
        for v in emb.keys():
            c = emb[v]
            labels[list(c)[0]] = str(v)

    # draw the background (unused) graph first
    if unused_color is not None:
        draw(G, layout, nodelist=nodelist, edgelist=background_edgelist,
             node_color=node_color, edge_color=background_edge_color,
             **kwargs)

    draw(G, layout, nodelist=nodelist, edgelist=edgelist,
         node_color=node_color, edge_color=edge_color, labels=labels,
         **kwargs)