Beispiel #1
0
    def setUp(self):

        M = 12
        N = 7
        L = 4

        eden_qubits = [(x, y, u, k) for x in range(M) for y in range(N)
                       for u in (0, 1) for k in range(L)]

        # one K_12, contains K_{8,8}
        Cliq1 = {(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (0, 2)}

        # another K_12
        Cliq2 = {(1, 4), (0, 5), (0, 6), (1, 5), (1, 6), (2, 5)}

        # K_{12,16} after deleting all horizontal qubits in alternating rows
        Rect1 = {(x, y) for x in range(4, 7) for y in range(7)}
        kill1 = {}

        # deleting those alternating rows
        Rect2 = {(x, y) for x in range(4, 7) for y in range(1, 7, 2)}
        kill2 = {(0, 0), (0, 1), (0, 2), (0, 3)}

        # K_{12,12} after deleting all u=1,k=3
        Rect3 = {(x, y) for x in range(8, 12) for y in range(3)}
        kill3 = {(1, 3)}

        # K_{8,16}
        Rect4 = {(x, y) for x in range(8, 12) for y in range(4, 6)}
        kill4 = {}

        XYFilter = Cliq1 | Cliq2 | Rect1 | Rect2 | Rect3 | Rect4

        def xyfilt(tup):
            x, y, u, k = tup
            return (x, y) in XYFilter

        eden_qubits = filter(xyfilt, eden_qubits)

        for rect, kill in zip((Rect1, Rect2, Rect3, Rect4),
                              (kill1, kill2, kill3, kill4)):

            def killf(tup):
                x, y, u, k = tup
                return ((x, y) not in rect) or ((u, k) not in kill)

            eden_qubits = filter(killf, eden_qubits)
            eden_qubits = list(eden_qubits)  # need to run the function now

        eden_qubits = set(eden_qubits)
        eden_couplers = [
            (q, n) for q in eden_qubits
            for n in set(_chimera_neighbors(M, N, L, q)) & eden_qubits
        ]
        eden_couplers.extend(
            ((x, y, 0, 0), (x, y, 1, 0)) for x, y in ((2, 2), (2, 3), (3, 3)))

        eden_couplers = [_bulk_to_linear(M, N, L, c) for c in eden_couplers]
        self.eden_proc = eden_proc = processor(eden_couplers, M=M, N=N, L=L)
        eden_proc._linear = False
Beispiel #2
0
    def setUp(self):
        M = 6
        N = 6
        L = 4

        eden_qubits = [(x, y, u, k) for x in range(M) for y in range(N)
                       for u in (0, 1) for k in range(L)]
        dead_qubits = [(3, 3, 1, 2), (4, 3, 0, 0), (4, 3, 1, 0), (5, 3, 1, 0),
                       (3, 4, 0, 1), (3, 4, 1, 0), (3, 4, 1, 2), (4, 4, 0, 0),
                       (4, 4, 1, 1), (3, 5, 0, 0), (3, 5, 0, 1), (3, 5, 0, 2)]
        XYFilter = [(0, 2), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2), (3, 0),
                    (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (4, 0), (4, 1),
                    (4, 2), (4, 3), (4, 4), (5, 0), (5, 1), (5, 2), (5, 3)]

        def xyfilt(tup):
            x, y, u, k = tup
            return (x, y) in XYFilter

        eden_qubits = filter(xyfilt, set(eden_qubits) - set(dead_qubits))
        eden_qubits = set(eden_qubits)
        eden_couplers = [
            (q, n) for q in eden_qubits
            for n in set(_chimera_neighbors(M, N, L, q)) & eden_qubits
        ]
        eden_couplers = [_bulk_to_linear(M, N, L, c) for c in eden_couplers]
        eden2_proc = processor(eden_couplers, M=M)
        eden2_proc._linear = False

        self.eden2_proc = eden2_proc
Beispiel #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
Beispiel #4
0
 def test_qubits_and_couplers(self):
     M = N = L = 2
     qubits = {(x, y, u, k)
               for x in range(M) for y in range(N) for u in range(2)
               for k in range(L)}
     couplers = [(p, q) for q in qubits
                 for p in _chimera_neighbors(M, N, L, q)]
     proc = processor(couplers, M=M, N=N, L=L, linear=False)._proc0
     for q in proc:
         assert proc[q] == set(_chimera_neighbors(
             M, N, L, q)), "Neighborhood is wrong!"
         qubits.remove(q)
     assert not qubits, "qubits are missing from proc"
Beispiel #5
0
    def test_evil_K_2_2(self):
        couplers = [((0, 0, 0, i), (1, 0, 0, i)) for i in range(4)]
        couplers += [((0, 0, 1, i), (0, 1, 1, i)) for i in range(4)]
        couplers += [((0, 0, 0, 0), (0, 0, 1, 0))]
        proc = processor(couplers,
                         M=2,
                         N=2,
                         L=4,
                         linear=False,
                         proc_limit=2**16)

        emb = proc.tightestNativeBiClique(1, 1)
        verify_biclique(proc, emb, 1, 1, 1, 1)
Beispiel #6
0
 def test_proclimit_cornercase(self):
     couplers = [((0, y, 1, i), (0, y + 1, 1, i)) for y in range(2)
                 for i in range(4)]
     couplers += [((0, y, 1, i), (0, y, 0, j)) for y in range(3)
                  for i in range(4) for j in range(4) if i != 0 or j != y]
     emb = None
     count = 0
     while emb is None and count < 100:
         proc = processor(couplers,
                          M=1,
                          N=3,
                          L=4,
                          linear=False,
                          proc_limit=2000)
         emb = proc.tightestNativeBiClique(3, 9, chain_imbalance=None)
         count += 1
     verify_biclique(proc, emb, 3, 9, 3, 1)
Beispiel #7
0
    def test_objectives(self):
        couplers = [((0, 0, 0, i), (1, 0, 0, i)) for i in range(4)]
        couplers += [((0, 0, 1, i), (0, 1, 1, i)) for i in range(4)]
        couplers += [((0, 0, 0, 0), (0, 0, 1, 0))]
        proc = processor(couplers,
                         M=2,
                         N=2,
                         L=4,
                         linear=False,
                         proc_limit=2**16)

        empty = proc._subprocessor(
            proc._proc0)  # an eden_processor with all qubits disabled
        emb = proc.tightestNativeBiClique(0, 0)
        proc._processors = [empty] + proc._processors + [empty]
        verify_biclique(proc, emb, 0, 0, 0, 0)

        empty.largestNativeBiClique = lambda *a, **k: (None, None)
        emb = proc.largestNativeBiClique()
        verify_biclique(proc, emb, 1, 1, 1, 1)
Beispiel #8
0
def find_clique_embedding(k, m, n=None, t=None, target_edges=None):
    """Find an embedding for a clique in a Chimera graph.

    Given the node labels or size of a clique (fully connected graph) and size or
    edges of the target :term:`Chimera` graph, attempts to find an embedding.

    Args:
        k (int/iterable):
            Clique to embed. If k is an integer, generates an embedding for a
            clique of size k labelled [0,k-1]. If k is an iterable of nodes,
            generates an embedding for a clique of size len(k) labelled
            for the given nodes.

        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.

        target_edges (iterable[edge]):
            A list of edges in the target Chimera graph. Nodes are labelled as
            returned by :func:`~dwave_networkx.chimera_graph`.

    Returns:
        dict: An embedding mapping a clique to the Chimera lattice.

    Examples:
        The first example finds an embedding for a :math:`K_4` complete graph in a single
        Chimera unit cell. The second for an alphanumerically labeled :math:`K_3`
        graph in 4 unit cells.

        >>> from dwave.embedding.chimera import find_clique_embedding
        ...
        >>> embedding = find_clique_embedding(4, 1, 1)
        >>> embedding  # doctest: +SKIP
        {0: [4, 0], 1: [5, 1], 2: [6, 2], 3: [7, 3]}

        >>> from dwave.embedding.chimera import find_clique_embedding
        ...
        >>> embedding = find_clique_embedding(['a', 'b', 'c'], m=2, n=2, t=4)
        >>> embedding  # doctest: +SKIP
        {'a': [20, 16], 'b': [21, 17], 'c': [22, 18]}

    """
    import random

    _, nodes = k

    m, n, t, target_edges = _chimera_input(m, n, t, target_edges)

    # Special cases to return optimal embeddings for small k.  The general clique embedder uses chains of length
    # at least 2, whereas cliques of size 1 and 2 can be embedded with single-qubit chains.

    if len(nodes) == 1:
        # If k == 1 we simply return a single chain consisting of a randomly sampled qubit.

        qubits = set().union(*target_edges)
        qubit = random.choice(tuple(qubits))
        embedding = [[qubit]]

    elif len(nodes) == 2:
        # If k == 2 we simply return two one-qubit chains that are the endpoints of a randomly sampled coupler.

        if not isinstance(target_edges, abc.Sequence):
            target_edges = list(target_edges)
        edge = random.choice(target_edges)
        embedding = [[edge[0]], [edge[1]]]

    else:
        # General case for k > 2.

        embedding = processor(target_edges, M=m, N=n,
                              L=t).tightestNativeClique(len(nodes))

    if not embedding:
        raise ValueError(
            "cannot find a K{} embedding for given Chimera lattice".format(
                len(nodes)))

    return dict(zip(nodes, embedding))
Beispiel #9
0
def find_biclique_embedding(a, b, m, n=None, t=None, target_edges=None):
    """Find an embedding for a biclique in a Chimera graph.

    Given a biclique (a bipartite graph where every vertex in a set in connected
    to all vertices in the other set) and a target :term:`Chimera` graph size or
    edges, attempts to find an embedding.

    Args:
        a (int/iterable):
            Left shore of the biclique to embed. If a is an integer, generates
            an embedding for a biclique with the left shore of size a labelled
            [0,a-1]. If a is an iterable of nodes, generates an embedding for a
            biclique with the left shore of size len(a) labelled for the given
            nodes.

        b (int/iterable):
            Right shore of the biclique to embed.If b is an integer, generates
            an embedding for a biclique with the right shore of size b labelled
            [0,b-1]. If b is an iterable of nodes, generates an embedding for a
            biclique with the right shore of size len(b) labelled for the given
            nodes.

        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.

        target_edges (iterable[edge]):
            A list of edges in the target Chimera graph. Nodes are labelled as
            returned by :func:`~dwave_networkx.chimera_graph`.

    Returns:
        tuple: A 2-tuple containing:

            dict: An embedding mapping the left shore of the biclique to
            the Chimera lattice.

            dict: An embedding mapping the right shore of the biclique to
            the Chimera lattice.

    Examples:
        This example finds an embedding for an alphanumerically labeled biclique in a single
        Chimera unit cell.

        >>> from dwave.embedding.chimera import find_biclique_embedding
        ...
        >>> left, right = find_biclique_embedding(['a', 'b', 'c'], ['d', 'e'], 1, 1)
        >>> print(left, right)  # doctest: +SKIP
        {'a': [4], 'b': [5], 'c': [6]} {'d': [0], 'e': [1]}

    """
    _, anodes = a
    _, bnodes = b

    m, n, t, target_edges = _chimera_input(m, n, t, target_edges)
    embedding = processor(target_edges, M=m, N=n,
                          L=t).tightestNativeBiClique(len(anodes), len(bnodes))

    if not embedding:
        raise ValueError(
            "cannot find a K{},{} embedding for given Chimera lattice".format(
                a, b))

    left, right = embedding
    return dict(zip(anodes, left)), dict(zip(bnodes, right))