def test_empty_list(self):
        # Set up fragmentation function
        pg = pegasus_graph(3)
        fragment_tuple = get_tuple_fragmentation_fn(pg)

        # Fragment pegasus coordinates
        fragments = fragment_tuple([])
        self.assertEqual([], fragments)
Exemple #2
0
    def test_valid_clique_ints(self):
        k = nx.complete_graph(15)
        m = 4

        # Find embedding
        pg = pegasus_graph(m)
        embedding = find_clique_embedding(k, target_graph=pg)

        self.assertTrue(is_valid_embedding(embedding, k, pg))
Exemple #3
0
    def test_k_parameter_int(self):
        k_int = 5
        m = 3

        # Find embedding
        pg = pegasus_graph(m, coordinates=True)
        embedding = find_clique_embedding(k_int, target_graph=pg)

        self.assertTrue(is_valid_embedding(embedding, nx.complete_graph(k_int), pg))
Exemple #4
0
    def test_k_parameter_list(self):
        k_nodes = ['one', 'two', 'three']
        m = 4

        # Find embedding
        pg = pegasus_graph(m, coordinates=True)
        embedding = find_clique_embedding(k_nodes, target_graph=pg)

        self.assertTrue(is_valid_embedding(embedding, nx.complete_graph(k_nodes), pg))
Exemple #5
0
    def test_one_clique(self):
        k = 1
        m = 4

        # Find embedding
        pg = pegasus_graph(m, coordinates=True)
        embedding = find_clique_embedding(k, target_graph=pg)

        self.assertTrue(is_valid_embedding(embedding, nx.complete_graph(k), pg))
    def test_valid_clique_coord(self):
        k = nx.complete_graph(55)
        m = 6

        # Find embedding
        pg = pegasus_graph(m, coordinates=True)
        embedding = find_clique_embedding(k, target_graph=pg)

        self.assertTrue(is_valid_embedding(embedding, k, pg))
    def test_impossible_clique(self):
        k = 55
        m = 2

        # Find embedding
        pg = pegasus_graph(m)

        with self.assertRaises(ValueError):
            find_clique_embedding(k, target_graph=pg)
    def test_empty_list(self):
        # Set up defragmentation function
        pg = pegasus_graph(2)
        defragment_tuple = get_tuple_defragmentation_fn(pg)

        # De-fragment chimera coordinates
        chimera_coords = []
        pegasus_coords = defragment_tuple(chimera_coords)

        self.assertEqual([], pegasus_coords)
    def test_zero_clique(self):
        k = 0
        m = 3

        # Find embedding
        pg = pegasus_graph(m)
        embedding = find_clique_embedding(k, target_graph=pg)

        self.assertEqual(k, len(embedding))
        self.assertEqual({}, embedding)
    def test_single_fragment(self):
        # Set up defragmentation function
        pg = pegasus_graph(4)
        defragment_tuple = get_tuple_defragmentation_fn(pg)

        # De-fragment chimera coordinates
        chimera_coords = [(3, 7, 0, 0)]
        pegasus_coords = defragment_tuple(chimera_coords)

        expected_pegasus_coords = [(0, 1, 2, 0)]
        self.assertEqual(expected_pegasus_coords, pegasus_coords)
    def test_mixed_fragments(self):
        # Set up defragmenation function
        pg = pegasus_graph(8)
        defragment_tuple = get_tuple_defragmentation_fn(pg)

        # De-fragment chimera coordinates
        chimera_coords = [(17, 14, 0, 0), (22, 14, 0, 0), (24, 32, 1, 0), (1, 31, 0, 0)]
        pegasus_coords = defragment_tuple(chimera_coords)

        expected_pegasus_coords = {(0, 2, 4, 2), (1, 4, 0, 4), (0, 5, 2, 0)}
        self.assertEqual(expected_pegasus_coords, set(pegasus_coords))
Exemple #12
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
    def test_multiple_fragments_from_same_qubit(self):
        # Set up defragmentation function
        pg = pegasus_graph(3)
        defragment_tuple = get_tuple_defragmentation_fn(pg)

        # De-fragment chimera coordinates
        chimera_coords = [(9, 8, 1, 1), (9, 11, 1, 1)]
        pegasus_coords = defragment_tuple(chimera_coords)

        expected_pegasus_coords = [(1, 1, 7, 1)]
        self.assertEqual(expected_pegasus_coords, pegasus_coords)
Exemple #14
0
    def test_single_vertical_coordinate(self):
        # Set up fragmentation function
        pg = pegasus_graph(6)
        fragment_tuple = get_tuple_fragmentation_fn(pg)

        pegasus_coord = (0, 1, 3, 1)
        fragments = fragment_tuple([pegasus_coord])

        expected_fragments = {(7, 7, 0, 1), (8, 7, 0, 1), (9, 7, 0, 1),
                              (10, 7, 0, 1), (11, 7, 0, 1), (12, 7, 0, 1)}

        self.assertEqual(expected_fragments, set(fragments))
 def test_nice_coordinates(self):
     p = pegasus_graph(3, nice_coordinates=True)
     c = chimera_graph(24, coordinates=True)
     num_edges = 0
     for u, v in fragmented_edges(p):
         self.assertTrue(c.has_edge(u, v))
         num_edges += 1
     #This is a weird edgecount: each node produces 5 extra edges for the internal connections
     #between fragments corresponding to a pegasus qubit.  But then we need to delete the odd
     #couplers, which aren't included in the chimera graph -- odd couplers make a perfect
     #matching, so thats 1/2 an edge per node.
     self.assertEqual(p.number_of_edges() + 9 * p.number_of_nodes()//2, num_edges)
Exemple #16
0
    def test_single_horizontal_coordinate(self):
        # Set up fragmentation function
        pg = pegasus_graph(2)
        fragment_tuple = get_tuple_fragmentation_fn(pg)

        # Fragment pegasus coordinates
        pegasus_coord = (1, 0, 0, 0)
        fragments = fragment_tuple([pegasus_coord])

        expected_fragments = {(0, 3, 1, 0), (0, 4, 1, 0), (0, 5, 1, 0),
                              (0, 6, 1, 0), (0, 7, 1, 0), (0, 8, 1, 0)}

        self.assertEqual(expected_fragments, set(fragments))
Exemple #17
0
    def test_list_of_coordinates(self):
        # Set up fragmentation function
        pg = pegasus_graph(6)
        fragment_tuple = get_tuple_fragmentation_fn(pg)

        # Fragment pegasus coordinates
        pegasus_coords = [(1, 5, 11, 4), (0, 2, 2, 3)]
        fragments = fragment_tuple(pegasus_coords)

        expected_fragments = {(35, 29, 1, 1), (35, 30, 1, 1), (35, 31, 1, 1),
                              (35, 32, 1, 1), (35, 33, 1, 1), (35, 34, 1, 1),
                              (19, 13, 0, 0), (20, 13, 0, 0), (21, 13, 0, 0),
                              (22, 13, 0, 0), (23, 13, 0, 0), (24, 13, 0, 0)}

        self.assertEqual(expected_fragments, set(fragments))
Exemple #18
0
    def test_clique_incomplete_graph(self):
        k = 5
        m = 2

        # Nodes in a known K5 embedding
        # Note: {0: [14, 32], 1: [33, 15], 2: [16, 34], 3: [35, 17], 4: [36, 12]}
        known_embedding_nodes = {14, 32, 33, 15, 16, 34, 35, 17, 36, 12}

        # Create graph with missing nodes
        incomplete_pg = pegasus_graph(m)
        removed_nodes = set(incomplete_pg.nodes) - known_embedding_nodes
        incomplete_pg.remove_nodes_from(removed_nodes)

        # See if clique embedding is found
        embedding = find_clique_embedding(k, target_graph=incomplete_pg)
        self.assertTrue(is_valid_embedding(embedding, nx.complete_graph(k), incomplete_pg))
Exemple #19
0
def draw_pegasus_yield(G, **kwargs):
    """Draws the given graph G with highlighted faults, according to layout.

    Parameters
    ----------
    G : NetworkX graph
        The graph to be parsed for 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.

    fault_color : tuple or color string (optional, default (1.0,0.0,0.0,1.0))
        A color to represent nodes absent from the graph G. Colors should be
        length-4 tuples of floats between 0 and 1 inclusive.

    fault_shape : string, optional (default='x')
        The shape of the fault nodes. Specification is as matplotlib.scatter
        marker, one of 'so^>v<dph8'.

    fault_style : string, optional (default='dashed')
        Edge fault line style (solid|dashed|dotted,dashdot)

    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:
        assert (G.graph["family"] == "pegasus")
        m = G.graph['columns']
        offset_lists = (G.graph['vertical_offsets'],
                        G.graph['horizontal_offsets'])
        coordinates = G.graph["labels"] == "coordinate"
        # 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)

    draw_yield(G, pegasus_layout(perfect_graph), perfect_graph, **kwargs)
Exemple #20
0
    def test_clique_missing_edges(self):
        k = 9
        m = 2

        pg = pegasus_graph(m)

        #pick a random ordering of the edges
        edges = list(pg.edges())
        shuffle(edges)

        K = nx.complete_graph(k)

        #now delete edges, one at a time, until we can no longer embed K
        with self.assertRaises(ValueError):
            while 1:
                (u, v) = edges.pop()
                pg.remove_edge(u, v)

                # See if clique embedding is found
                embedding = find_clique_embedding(k, target_graph=pg)
                self.assertTrue(is_valid_embedding(embedding, K, pg))
Exemple #21
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
Exemple #22
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