Пример #1
0
def pegasus_layout(G, scale=1., center=None, dim=2, crosses=False):
    """Positions the nodes of graph G in a Pegasus topology.

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

    Parameters
    ----------
    G : NetworkX graph
        Should be a Pegasus graph or a subgraph of a Pegasus graph.
        This should be the product of dwave_networkx.pegasus_graph

    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.

    crosses: boolean (optional, default False)
        If crosses is True, K_4,4 subgraphs are shown in a cross
        rather than L configuration. Ignored if G was defined with
        nice_coordinates=True.

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

    Examples
    --------
    >>> G = dnx.pegasus_graph(1)
    >>> pos = dnx.pegasus_layout(G)

    """

    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':
        m = 3*(G.graph['rows']-1)
        c_coords = chimera_node_placer_2d(m, m, 4, scale=scale, center=center, dim=dim)
        def xy_coords(t, y, x, u, k): return c_coords(3*y+2-t, 3*x+t, u, k)
        pos = {v: xy_coords(*v) for v in G.nodes()}
    else:
        xy_coords = pegasus_node_placer_2d(G, scale, center, dim, crosses=crosses)

        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['pegasus_index']) for v, dat in G.nodes(data=True)}
        else:
            m = G.graph.get('rows')
            coord = pegasus_coordinates(m)
            pos = {v: xy_coords(*coord.tuple(v)) for v in G.nodes()}

    return pos
Пример #2
0
def pegasus_elimination_order(n, coordinates=False):
    """Provides a variable elimination order for the Pegasus graph.

    The treewidth of a Pegasus graph ``pegasus_graph(n)`` is lower-bounded by 
    :math:`12n-11` and upper bounded by :math:`12n-4` [bbrr]_ .

    Simple pegasus variable elimination order rules:

       - eliminate vertical qubits, one column at a time
       - eliminate horizontal qubits in each column once their adjacent vertical
         qubits have been eliminated

    Args
    ----
    n : int
        The size parameter for the Pegasus lattice.

    coordinates : bool, optional (default False)
        If True, the elimination order is given in terms of 4-term Pegasus
        coordinates, otherwise given in linear indices.

    Returns
    -------
    order : list
        An elimination order that provides an upper bound on the treewidth.


    .. [bbrr] Boothby, K., P. Bunky, J. Raymond, A. Roy. Next-Generation Topology
       of D-Wave Quantum Processors. Technical Report, Februrary 2019.
       https://www.dwavesys.com/resources/publications?type=white

    """
    m = n
    l = 12

    # ordering for horizontal qubits in each tile, from east to west:
    h_order = [4, 5, 6, 7, 0, 1, 2, 3, 8, 9, 10, 11]
    order = []
    for n_i in range(n):  # for each tile offset
        # eliminate vertical qubits:
        for l_i in range(0, l, 2):
            for l_v in range(l_i, l_i + 2):
                for m_i in range(m - 1):  # for each column
                    order.append((0, n_i, l_v, m_i))
            # eliminate horizontal qubits:
            if n_i > 0 and not(l_i % 4):
                # a new set of horizontal qubits have had all their neighbouring vertical qubits eliminated.
                for m_i in range(m):
                    for l_h in range(h_order[l_i], h_order[l_i] + 4):
                        order.append((1, m_i, l_h, n_i - 1))

    if coordinates:
        return order
    else:
        return list(pegasus_coordinates(n).iter_pegasus_to_linear(order))
Пример #3
0
def _pegasus_fragment_helper(m=None, target_graph=None):
    # This is a function that takes m or a target_graph and produces a
    # `processor` object for the corresponding Pegasus graph, and a function
    # that translates embeddings produced by that object back to the original
    # pegasus graph.  Consumed by `find_clique_embedding` and
    # `find_biclique_embedding`.

    # Organize parameter values
    if target_graph is None:
        if m is None:
            raise TypeError("m and target_graph cannot both be None.")
        target_graph = pegasus_graph(m)

    m = target_graph.graph['rows']  # We only support square Pegasus graphs

    # Deal with differences in ints vs coordinate target_graphs
    if target_graph.graph['labels'] == 'nice':
        back_converter = pegasus_coordinates.pegasus_to_nice
        back_translate = lambda embedding: {
            key: [back_converter(p) for p in chain]
            for key, chain in embedding.items()
        }
    elif target_graph.graph['labels'] == 'int':
        # Convert nodes in terms of Pegasus coordinates
        coord_converter = pegasus_coordinates(m)

        # A function to convert our final coordinate embedding to an ints embedding
        back_translate = lambda embedding: {
            key: list(coord_converter.iter_pegasus_to_linear(chain))
            for key, chain in embedding.items()
        }
    else:
        back_translate = lambda embedding: embedding

    # collect edges of the graph produced by splitting each Pegasus qubit into six pieces
    fragment_edges = list(fragmented_edges(target_graph))

    # Find clique embedding in K2,2 Chimera graph
    embedding_processor = processor(fragment_edges,
                                    M=m * 6,
                                    N=m * 6,
                                    L=2,
                                    linear=False)

    # Convert chimera fragment embedding in terms of Pegasus coordinates
    defragment_tuple = get_tuple_defragmentation_fn(target_graph)

    def embedding_to_pegasus(nodes, emb):
        emb = map(defragment_tuple, emb)
        emb = dict(zip(nodes, emb))
        emb = back_translate(emb)
        return emb

    return embedding_processor, embedding_to_pegasus
Пример #4
0
    def test_consistent_linear_nice_pegasus(self):
        P4 = dnx.pegasus_graph(4, nice_coordinates=True)

        coords = pegasus_coordinates(4)

        # `.*_to_*` methods

        for n, data in P4.nodes(data=True):
            p = data['pegasus_index']
            i = data['linear_index']
            self.assertEqual(coords.nice_to_pegasus(n), p)
            self.assertEqual(coords.pegasus_to_nice(p), n)
            self.assertEqual(coords.nice_to_linear(n), i)
            self.assertEqual(coords.linear_to_nice(i), n)
            self.assertEqual(coords.linear_to_pegasus(i), p)
            self.assertEqual(coords.pegasus_to_linear(p), i)

        # `.iter_*_to_*` methods

        nlist, plist, ilist = zip(*((n, d['pegasus_index'], d['linear_index'])
                                    for n, d in P4.nodes(data=True)))
        self.assertEqual(tuple(coords.iter_nice_to_pegasus(nlist)), plist)
        self.assertEqual(tuple(coords.iter_pegasus_to_nice(plist)), nlist)
        self.assertEqual(tuple(coords.iter_nice_to_linear(nlist)), ilist)
        self.assertEqual(tuple(coords.iter_linear_to_nice(ilist)), nlist)
        self.assertEqual(tuple(coords.iter_pegasus_to_linear(plist)), ilist)
        self.assertEqual(tuple(coords.iter_linear_to_pegasus(ilist)), plist)

        # `.iter_*_to_*_pairs` methods

        nedgelist = []
        pedgelist = []
        iedgelist = []
        for u, v in P4.edges:
            nedgelist.append((u, v))
            pedgelist.append((P4.nodes[u]['pegasus_index'],
                              P4.nodes[v]['pegasus_index']))
            iedgelist.append((P4.nodes[u]['linear_index'],
                              P4.nodes[v]['linear_index']))

        self.assertEqual(list(coords.iter_nice_to_pegasus_pairs(nedgelist)),
                         pedgelist)
        self.assertEqual(list(coords.iter_pegasus_to_nice_pairs(pedgelist)),
                         nedgelist)
        self.assertEqual(list(coords.iter_nice_to_linear_pairs(nedgelist)),
                         iedgelist)
        self.assertEqual(list(coords.iter_linear_to_nice_pairs(iedgelist)),
                         nedgelist)
        self.assertEqual(list(coords.iter_pegasus_to_linear_pairs(pedgelist)),
                         iedgelist)
        self.assertEqual(list(coords.iter_linear_to_pegasus_pairs(iedgelist)),
                         pedgelist)
Пример #5
0
def pegasus_layout(G, scale=1., center=None, dim=2):
    """Positions the nodes of graph G in a Pegasus topology.

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

    Parameters
    ----------
    G : NetworkX graph
        Should be a Pegasus graph or a subgraph of a Pegasus graph.
        This should be the product of dwave_networkx.pegasus_graph

    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.pegasus_graph(1)
    >>> pos = dnx.pegasus_layout(G)

    """

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

    xy_coords = pegasus_node_placer_2d(G, 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['pegasus_index'])
            for v, dat in G.nodes(data=True)
        }
    else:
        m = G.graph.get('rows')
        coord = pegasus_coordinates(m)
        pos = {v: xy_coords(*coord.tuple(v)) for v in G.nodes()}

    return pos
Пример #6
0
    def test_coordinate_subgraphs(self):
        from dwave_networkx.generators.pegasus import pegasus_coordinates
        from random import sample
        G = dnx.pegasus_graph(4)
        H = dnx.pegasus_graph(4, coordinates=True)
        coords = pegasus_coordinates(4)

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

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

        Gm = dnx.pegasus_graph(4, node_list=lmask)
        Hm = dnx.pegasus_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.pegasus_graph(4, edge_list=EG)
        Hn = dnx.pegasus_graph(4, edge_list=EH, coordinates=True)

        Gnodes = Gn.nodes
        Hnodes = Hn.nodes
        for v in Gnodes:
            q = Gnodes[v]['pegasus_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]['pegasus_index'], q)
            self.assertEqual(v, coords.int(q))
            self.assertEqual(q, coords.tuple(v))

        self.assertEqual(EG, sorted(map(sorted, coords.int_pairs(Hn.edges()))))
        self.assertEqual(EH, sorted(map(sorted,
                                        coords.tuple_pairs(Gn.edges()))))
Пример #7
0
 def test_coordinate_basics(self):
     G = dnx.pegasus_graph(4, fabric_only=False)
     H = dnx.pegasus_graph(4, coordinates=True, fabric_only=False)
     coords = pegasus_coordinates(4)
     Gnodes = G.nodes
     Hnodes = H.nodes
     for v in Gnodes:
         q = Gnodes[v]['pegasus_index']
         self.assertIn(q, Hnodes)
         self.assertEqual(Hnodes[q]['linear_index'], v)
         self.assertEqual(v, coords.pegasus_to_linear(q))
         self.assertEqual(q, coords.linear_to_pegasus(v))
     for q in Hnodes:
         v = Hnodes[q]['linear_index']
         self.assertIn(v, Gnodes)
         self.assertEqual(Gnodes[v]['pegasus_index'], q)
         self.assertEqual(v, coords.pegasus_to_linear(q))
         self.assertEqual(q, coords.linear_to_pegasus(v))
Пример #8
0
 def test_coordinate_basics(self):
     from dwave_networkx.generators.pegasus import pegasus_coordinates
     G = dnx.pegasus_graph(4, fabric_only=False)
     H = dnx.pegasus_graph(4, coordinates=True, fabric_only=False)
     coords = pegasus_coordinates(4)
     Gnodes = G.nodes
     Hnodes = H.nodes
     for v in Gnodes:
         q = Gnodes[v]['pegasus_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]['pegasus_index'], q)
         self.assertEqual(v, coords.int(q))
         self.assertEqual(q, coords.tuple(v))
Пример #9
0
    def test_coordinate_subgraphs(self):
        G = dnx.pegasus_graph(4)
        H = dnx.pegasus_graph(4, coordinates=True)
        coords = pegasus_coordinates(4)

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

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

        Gm = dnx.pegasus_graph(4, node_list=lmask)
        Hm = dnx.pegasus_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.pegasus_graph(4, edge_list=EG)
        Hn = dnx.pegasus_graph(4, edge_list=EH, coordinates=True)

        Gnodes = Gn.nodes
        Hnodes = Hn.nodes
        for v in Gnodes:
            q = Gnodes[v]['pegasus_index']
            self.assertIn(q, Hnodes)
            self.assertEqual(Hnodes[q]['linear_index'], v)
            self.assertEqual(v, coords.pegasus_to_linear(q))
            self.assertEqual(q, coords.linear_to_pegasus(v))
        for q in Hnodes:
            v = Hnodes[q]['linear_index']
            self.assertIn(v, Gnodes)
            self.assertEqual(Gnodes[v]['pegasus_index'], q)
            self.assertEqual(v, coords.pegasus_to_linear(q))
            self.assertEqual(q, coords.linear_to_pegasus(v))

        self.assertEqual(EG, sorted(map(sorted, coords.iter_pegasus_to_linear_pairs(Hn.edges()))))
        self.assertEqual(EH, sorted(map(sorted, coords.iter_linear_to_pegasus_pairs(Gn.edges()))))
Пример #10
0
def find_clique_embedding(k, m=None, target_graph=None):
    """Find an embedding of a k-sized clique on a Pegasus graph (target_graph).

    This clique is found by transforming the Pegasus graph into a K2,2 Chimera graph and then
    applying a Chimera clique finding algorithm. The results are then converted back in terms of
    Pegasus coordinates.

    Note: If target_graph is None, m will be used to generate a m-by-m Pegasus graph. Hence m and
    target_graph cannot both be None.

    Args:
        k (int/iterable/:obj:`networkx.Graph`): Number of members in the requested clique; list of nodes;
          a complete graph that you want to embed onto the target_graph
        m (int): Number of tiles in a row of a square Pegasus graph
        target_graph (:obj:`networkx.Graph`): A Pegasus graph

    Returns:
        dict: A dictionary representing target_graphs's clique embedding. Each dictionary key
        represents a node in said clique. Each corresponding dictionary value is a list of pegasus
        coordinates that should be chained together to represent said node.

    """
    # Organize parameter values
    if target_graph is None:
        if m is None:
            raise TypeError("m and target_graph cannot both be None.")
        target_graph = pegasus_graph(m)

    m = target_graph.graph['rows']  # We only support square Pegasus graphs
    _, nodes = k

    # Deal with differences in ints vs coordinate target_graphs
    if target_graph.graph['labels'] == 'nice':
        fwd_converter = get_nice_to_pegasus_fn(m=m)
        back_converter = get_pegasus_to_nice_fn(m=m)
        pegasus_coords = [fwd_converter(*p) for p in target_graph.nodes]
        back_translate = lambda embedding: {
            key: [back_converter(*p) for p in chain]
            for key, chain in embedding.items()
        }
    elif target_graph.graph['labels'] == 'int':
        # Convert nodes in terms of Pegasus coordinates
        coord_converter = pegasus_coordinates(m)
        pegasus_coords = map(coord_converter.tuple, target_graph.nodes)

        # A function to convert our final coordinate embedding to an ints embedding
        back_translate = lambda embedding: {
            key: list(coord_converter.ints(chain))
            for key, chain in embedding.items()
        }
    else:
        pegasus_coords = target_graph.nodes
        back_translate = lambda embedding: embedding

    # Break each Pegasus qubits into six Chimera fragments
    # Note: By breaking the graph in this way, you end up with a K2,2 Chimera graph
    fragment_tuple = get_tuple_fragmentation_fn(target_graph)
    fragments = fragment_tuple(pegasus_coords)

    # Create a K2,2 Chimera graph
    # Note: 6 * m because Pegasus qubits split into six pieces, so the number of rows and columns
    #   get multiplied by six
    chim_m = 6 * m
    chim_graph = chimera_graph(chim_m, t=2, coordinates=True)

    # Determine valid fragment couplers in a K2,2 Chimera graph
    edges = chim_graph.subgraph(fragments).edges()

    # Find clique embedding in K2,2 Chimera graph
    embedding_processor = processor(edges,
                                    M=chim_m,
                                    N=chim_m,
                                    L=2,
                                    linear=False)
    chimera_clique_embedding = embedding_processor.tightestNativeClique(
        len(nodes))

    # Convert chimera fragment embedding in terms of Pegasus coordinates
    defragment_tuple = get_tuple_defragmentation_fn(target_graph)
    pegasus_clique_embedding = map(defragment_tuple, chimera_clique_embedding)
    pegasus_clique_embedding = dict(zip(nodes, pegasus_clique_embedding))
    pegasus_clique_embedding = back_translate(pegasus_clique_embedding)

    if len(pegasus_clique_embedding) != len(nodes):
        raise ValueError("No clique embedding found")

    return pegasus_clique_embedding
Пример #11
0
def pegasus_layout(G, scale=1., center=None, dim=2, crosses=False):
    """Positions the nodes of graph G in a Pegasus topology.

    `NumPy <http://scipy.org>`_ is required for this function.

    Parameters
    ----------
    G : NetworkX graph
        A Pegasus graph or a subgraph of a Pegasus graph, as produced by
        the :func:`dwave_networkx.pegasus_graph` function.

    scale : float (default 1.)
        Scale factor. A setting of ``scale = 1`` fits all positions 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.

    crosses: boolean (optional, default False)
        If True, :math:`K_{4,4}` subgraphs are shown in a cross
        rather than L configuration. Ignored if G is defined with
        ``nice_coordinates=True``.

    Returns
    -------
    pos : dict
        Positions as a dictionary keyed by node.

    Examples
    --------
        This example gives the positions of a Pegasus lattice of size 2.

    >>> G = dnx.pegasus_graph(2)
    >>> pos = dnx.pegasus_layout(G)

    """

    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':
        m = 3*(G.graph['rows']-1)
        c_coords = chimera_node_placer_2d(m, m, 4, scale=scale, center=center, dim=dim)
        def xy_coords(t, y, x, u, k): return c_coords(3*y+2-t, 3*x+t, u, k)
        pos = {v: xy_coords(*v) for v in G.nodes()}
    else:
        xy_coords = pegasus_node_placer_2d(G, scale, center, dim, crosses=crosses)

        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['pegasus_index']) for v, dat in G.nodes(data=True)}
        else:
            m = G.graph.get('rows')
            coord = pegasus_coordinates(m)
            pos = {v: xy_coords(*coord.linear_to_pegasus(v)) for v in G.nodes()}

    return pos
Пример #12
0
def find_clique_embedding(k, m=None, target_graph=None):
    """Find an embedding for a clique in a Pegasus graph.

    Given a clique (fully connected graph) and target Pegasus graph, attempts
    to find an embedding by transforming the Pegasus graph into a :math:`K_{2,2}`
    Chimera graph and then applying a Chimera clique-finding algorithm. Results
    are converted back to Pegasus coordinates.

    Args:
        k (int/iterable/:obj:`networkx.Graph`): A complete graph to embed,
            formatted as a number of nodes, node labels, or a NetworkX graph.
        m (int): Number of tiles in a row of a square Pegasus graph. Required to
            generate an m-by-m Pegasus graph when `target_graph` is None.
        target_graph (:obj:`networkx.Graph`): A Pegasus graph. Required when `m`
            is None.

    Returns:
        dict: An embedding as a dict, where keys represent the clique's nodes and
        values, formatted as lists, represent chains of pegasus coordinates.

    Examples:
        This example finds an embedding for a :math:`K_3` complete graph in a
        2-by-2 Pegaus graph.

        >>> from dwave.embedding.pegasus import find_clique_embedding
        ...
        >>> print(find_clique_embedding(3, 2))    # doctest: +SKIP
        {0: [10, 34], 1: [35, 11], 2: [32, 12]}

    """
    # Organize parameter values
    if target_graph is None:
        if m is None:
            raise TypeError("m and target_graph cannot both be None.")
        target_graph = pegasus_graph(m)

    m = target_graph.graph['rows']     # We only support square Pegasus graphs
    _, nodes = k

    # Deal with differences in ints vs coordinate target_graphs
    if target_graph.graph['labels'] == 'nice':
        fwd_converter = get_nice_to_pegasus_fn()
        back_converter = get_pegasus_to_nice_fn()
        pegasus_coords = [fwd_converter(*p) for p in target_graph.nodes]
        back_translate = lambda embedding: {key: [back_converter(*p) for p in chain]
                                      for key, chain in embedding.items()}
    elif target_graph.graph['labels'] == 'int':
        # Convert nodes in terms of Pegasus coordinates
        coord_converter = pegasus_coordinates(m)
        pegasus_coords = map(coord_converter.tuple, target_graph.nodes)

        # A function to convert our final coordinate embedding to an ints embedding
        back_translate = lambda embedding: {key: list(coord_converter.ints(chain))
                                      for key, chain in embedding.items()}
    else:
        pegasus_coords = target_graph.nodes
        back_translate = lambda embedding: embedding

    # Break each Pegasus qubits into six Chimera fragments
    # Note: By breaking the graph in this way, you end up with a K2,2 Chimera graph
    fragment_tuple = get_tuple_fragmentation_fn(target_graph)
    fragments = fragment_tuple(pegasus_coords)

    # Create a K2,2 Chimera graph
    # Note: 6 * m because Pegasus qubits split into six pieces, so the number of rows and columns
    #   get multiplied by six
    chim_m = 6 * m
    chim_graph = chimera_graph(chim_m, t=2, coordinates=True)

    # Determine valid fragment couplers in a K2,2 Chimera graph
    edges = chim_graph.subgraph(fragments).edges()

    # Find clique embedding in K2,2 Chimera graph
    embedding_processor = processor(edges, M=chim_m, N=chim_m, L=2, linear=False)
    chimera_clique_embedding = embedding_processor.tightestNativeClique(len(nodes))

    # Convert chimera fragment embedding in terms of Pegasus coordinates
    defragment_tuple = get_tuple_defragmentation_fn(target_graph)
    pegasus_clique_embedding = map(defragment_tuple, chimera_clique_embedding)
    pegasus_clique_embedding = dict(zip(nodes, pegasus_clique_embedding))
    pegasus_clique_embedding = back_translate(pegasus_clique_embedding)

    if len(pegasus_clique_embedding) != len(nodes):
        raise ValueError("No clique embedding found")

    return pegasus_clique_embedding