예제 #1
0
def chimera_elimination_order(m, n=None, t=4, coordinates=False):
    """Provides a variable elimination order for a Chimera graph.

    A graph defined by ``chimera_graph(m,n,t)`` has treewidth :math:`max(m,n)*t`.
    This function outputs a variable elimination order inducing a tree
    decomposition of that width.

    Parameters
    ----------
    m : int
        Number of rows in the Chimera lattice.
    n : int (optional, default m)
        Number of columns in the Chimera lattice.
    t : int (optional, default 4)
        Size of the shore within each Chimera tile.
    coordinates bool (optional, default False):
        If True, the elimination order is given in terms of 4-term Chimera
        coordinates, otherwise given in linear indices.
        
    Returns
    -------
    order : list
        An elimination order that induces the treewidth of chimera_graph(m,n,t).

    Examples
    --------

    >>> G = dnx.chimera_elimination_order(1, 1, 4)  # a single Chimera tile

    """
    if n is None:
        n = m

    index_flip = m > n
    if index_flip:
        m, n = n, m

    def chimeraI(m0, n0, k0, l0):
        if index_flip:
            return m*2*t*n0 + 2*t*m0 + t*(1-k0) + l0
        else:
            return n*2*t*m0 + 2*t*n0 + t*k0 + l0

    order = []

    for n_i in range(n):
        for t_i in range(t):
            for m_i in range(m):
                order.append(chimeraI(m_i, n_i, 0, t_i))

    for n_i in range(n):
        for m_i in range(m):
            for t_i in range(t):
                order.append(chimeraI(m_i, n_i, 1, t_i))

    if coordinates:
        return list(chimera_coordinates(m,n,t).iter_linear_to_chimera(order))
    else:
        return order
    def test_3x3_identity(self):
        C33 = dnx.chimera_graph(3, 3)
        coord = chimera_coordinates(3, 3, 4)

        labels = canonical_chimera_labeling(C33)
        labels = {v: coord.chimera_to_linear(labels[v]) for v in labels}

        G = nx.relabel_nodes(C33, labels, copy=True)

        self.assertTrue(nx.is_isomorphic(G, C33))
    def test_row_identity(self):
        C41 = dnx.chimera_graph(4, 1)
        coord = chimera_coordinates(4, 1, 4)

        labels = canonical_chimera_labeling(C41)
        labels = {v: coord.chimera_to_linear(labels[v]) for v in labels}

        G = nx.relabel_nodes(C41, labels, copy=True)

        self.assertTrue(nx.is_isomorphic(G, C41))
    def test_tile_identity(self):
        C1 = dnx.chimera_graph(1)
        coord = chimera_coordinates(1, 1, 4)

        labels = canonical_chimera_labeling(C1)
        labels = {v: coord.chimera_to_linear(labels[v]) for v in labels}

        G = nx.relabel_nodes(C1, labels, copy=True)

        self.assertTrue(nx.is_isomorphic(G, C1))
        self.assertEqual(set(G), set(C1))
    def test_bqm_tile_identity(self):
        C1bqm = dimod.BinaryQuadraticModel.from_ising(
            {}, {e: -1
                 for e in dnx.chimera_graph(1).edges})
        coord = chimera_coordinates(1, 1, 4)

        labels = canonical_chimera_labeling(C1bqm)
        labels = {v: coord.chimera_to_linear(labels[v]) for v in labels}

        bqm = C1bqm.relabel_variables(labels, inplace=False)

        self.assertEqual(bqm, C1bqm)
예제 #6
0
    def test_reversed(self):
        C33 = nx.OrderedGraph()
        C33.add_nodes_from(reversed(range(3 * 3 * 4)))
        C33.add_edges_from(dnx.chimera_graph(3, 3, 4).edges)
        coord = chimera_coordinates(3, 3, 4)

        labels = canonical_chimera_labeling(C33)
        labels = {v: coord.chimera_to_linear(labels[v]) for v in labels}

        G = nx.relabel_nodes(C33, labels, copy=True)

        self.assertTrue(nx.is_isomorphic(G, C33))
예제 #7
0
    def test_coordinate_subgraphs(self):
        from dwave_networkx.generators.chimera import chimera_coordinates
        from random import sample
        G = dnx.chimera_graph(4)
        H = dnx.chimera_graph(4, coordinates=True)
        coords = chimera_coordinates(4)

        lmask = sample(list(G.nodes()), G.number_of_nodes() // 2)
        cmask = list(coords.iter_linear_to_chimera(lmask))

        self.assertEqual(lmask, list(coords.iter_chimera_to_linear(cmask)))

        Gm = dnx.chimera_graph(4, node_list=lmask)
        Hm = dnx.chimera_graph(4, node_list=cmask, coordinates=True)

        Gs = G.subgraph(lmask)
        Hs = H.subgraph(cmask)

        EG = sorted(map(sorted, Gs.edges()))
        EH = sorted(map(sorted, Hs.edges()))

        self.assertEqual(EG, sorted(map(sorted, Gm.edges())))
        self.assertEqual(EH, sorted(map(sorted, Hm.edges())))

        Gn = dnx.chimera_graph(4, edge_list=EG)
        Hn = dnx.chimera_graph(4, edge_list=EH, coordinates=True)

        Gnodes = Gn.nodes
        Hnodes = Hn.nodes
        for v in Gnodes:
            q = Gnodes[v]['chimera_index']
            self.assertIn(q, Hnodes)
            self.assertEqual(Hnodes[q]['linear_index'], v)
            self.assertEqual(v, coords.chimera_to_linear(q))
            self.assertEqual(q, coords.linear_to_chimera(v))
        for q in Hnodes:
            v = Hnodes[q]['linear_index']
            self.assertIn(v, Gnodes)
            self.assertEqual(Gnodes[v]['chimera_index'], q)
            self.assertEqual(v, coords.chimera_to_linear(q))
            self.assertEqual(q, coords.linear_to_chimera(v))

        self.assertEqual(
            EG,
            sorted(map(sorted,
                       coords.iter_chimera_to_linear_pairs(Hn.edges()))))
        self.assertEqual(
            EH,
            sorted(map(sorted,
                       coords.iter_linear_to_chimera_pairs(Gn.edges()))))
예제 #8
0
 def test_coordinate_basics(self):
     from dwave_networkx.generators.chimera import chimera_coordinates
     G = dnx.chimera_graph(4)
     H = dnx.chimera_graph(4, coordinates=True)
     coords = chimera_coordinates(4)
     Gnodes = G.nodes
     Hnodes = H.nodes
     for v in Gnodes:
         q = Gnodes[v]['chimera_index']
         self.assertIn(q, Hnodes)
         self.assertEqual(Hnodes[q]['linear_index'], v)
         self.assertEqual(v, coords.int(q))
         self.assertEqual(q, coords.tuple(v))
     for q in Hnodes:
         v = Hnodes[q]['linear_index']
         self.assertIn(v, Gnodes)
         self.assertEqual(Gnodes[v]['chimera_index'], q)
         self.assertEqual(v, coords.int(q))
         self.assertEqual(q, coords.tuple(v))
    def test_construction_string_labels(self):
        C22 = dnx.chimera_graph(2, 2, 3)
        coord = chimera_coordinates(2, 2, 3)

        alpha = 'abcdefghijklmnopqrstuvwxyz'

        bqm = dimod.BinaryQuadraticModel.empty(dimod.BINARY)

        for u, v in reversed(list(C22.edges)):
            bqm.add_interaction(alpha[u], alpha[v], 1)

        assert len(bqm.quadratic) == len(C22.edges)
        assert len(bqm) == len(C22)

        labels = canonical_chimera_labeling(bqm)
        labels = {v: alpha[coord.chimera_to_linear(labels[v])] for v in labels}

        bqm2 = bqm.relabel_variables(labels, inplace=False)

        self.assertEqual(bqm, bqm2)
    def __init__(self, S, Tg, **params):

        # Parse parameters
        self.origin = params.pop('origin', None)
        self.orientation = params.pop('orientation', None)

        # Parse Target graph
        self.Tg = Tg
        if Tg.graph['family'] != 'chimera':
            raise ValueError(
                "Invalid target graph family. Only valid for 'chimera' graphs")

        self.m = Tg.graph['columns']
        self.n = Tg.graph['rows']
        self.t = Tg.graph['tile']
        self.coordinates = Tg.graph['labels'] == 'coordinate'

        self.qubit_cols = self.m * self.t
        self.qubit_rows = self.n * self.t

        self.c2i = chimera_coordinates(self.m, self.n, self.t)

        # Parse Source graph.
        try:
            P, Q = nx.bipartite.sets(nx.Graph(S))
        except:
            try:
                Sg = nx.complete_bipartite_graph(*S)
                P = set()
                Q = set()
                for v, data in Sg.nodes(data=True):
                    if data['bipartite'] == 1: Q.add(v)
                    else: P.add(v)
            except:
                raise RuntimeError("Input must be iterable of edges of a "
                                   "complete bipartite graph, or tuple with "
                                   "dimensions (p,q).")
        self.P = {k: [] for k in P}
        self.Q = {k: [] for k in Q}
        self.faults = None
예제 #11
0
def chimera_layout(G, scale=1., center=None, dim=2):
    """Positions the nodes of graph G in a Chimera cross topology.

    NumPy (https://scipy.org) is required for this function.

    Parameters
    ----------
    G : NetworkX graph
        Should be a Chimera graph or a subgraph of a
        Chimera graph. If every node in G has a `chimera_index`
        attribute, those are used to place the nodes. Otherwise makes
        a best-effort attempt to find positions.

    scale : float (default 1.)
        Scale factor. When scale = 1,  all positions fit within [0, 1]
        on the x-axis and [-1, 0] on the y-axis.

    center : None or array (default None)
        Coordinates of the top left corner.

    dim : int (default 2)
        Number of dimensions. When dim > 2, all extra dimensions are
        set to 0.

    Returns
    -------
    pos : dict
        A dictionary of positions keyed by node.

    Examples
    --------
    >>> G = dnx.chimera_graph(1)
    >>> pos = dnx.chimera_layout(G)

    """

    if not isinstance(G, nx.Graph):
        empty_graph = nx.Graph()
        empty_graph.add_edges_from(G)
        G = empty_graph

    # now we get chimera coordinates for the translation
    # first, check if we made it
    if G.graph.get("family") == "chimera":
        m = G.graph['rows']
        n = G.graph['columns']
        t = G.graph['tile']
        # get a node placement function
        xy_coords = chimera_node_placer_2d(m, n, t, scale, center, dim)

        if G.graph.get('labels') == 'coordinate':
            pos = {v: xy_coords(*v) for v in G.nodes()}
        elif G.graph.get('data'):
            pos = {
                v: xy_coords(*dat['chimera_index'])
                for v, dat in G.nodes(data=True)
            }
        else:
            coord = chimera_coordinates(m, n, t)
            pos = {
                v: xy_coords(*coord.linear_to_chimera(v))
                for v in G.nodes()
            }
    else:
        # best case scenario, each node in G has a chimera_index attribute. Otherwise
        # we will try to determine it using the find_chimera_indices function.
        if all('chimera_index' in dat for __, dat in G.nodes(data=True)):
            chimera_indices = {
                v: dat['chimera_index']
                for v, dat in G.nodes(data=True)
            }
        else:
            chimera_indices = find_chimera_indices(G)

        # we could read these off of the name attribute for G, but we would want the values in
        # the nodes to override the name in case of conflict.
        m = max(idx[0] for idx in chimera_indices.values()) + 1
        n = max(idx[1] for idx in chimera_indices.values()) + 1
        t = max(idx[3] for idx in chimera_indices.values()) + 1
        xy_coords = chimera_node_placer_2d(m, n, t, scale, center, dim)

        # compute our coordinates
        pos = {
            v: xy_coords(i, j, u, k)
            for v, (i, j, u, k) in chimera_indices.items()
        }

    return pos