fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(12, 6))

# Draw the QUBO as a networkx graph
pos = nx.spring_layout(G)
nx.draw_networkx(G,
                 pos=pos,
                 font_size=10,
                 node_size=100,
                 node_color='cyan',
                 ax=axes[0])

# Embed the graph on Chimera
dwave_sampler_chimera = DWaveSampler(solver={'topology__type': 'chimera'})
chimera_edges = dwave_sampler_chimera.edgelist
chimera_graph = dnx.chimera_graph(16, edge_list=chimera_edges)
clique_embedding_chimera = find_clique_embedding(N, chimera_graph)

# Draw the graph embedded on Chimera
dnx.draw_chimera_embedding(chimera_graph,
                           clique_embedding_chimera,
                           embedded_graph=G,
                           unused_color=None,
                           ax=axes[1])

# Embed the graph on Pegasus
dwave_sampler_pegasus = DWaveSampler(solver={'topology__type': 'pegasus'})
pegasus_edges = dwave_sampler_pegasus.edgelist
pegasus_graph = dnx.pegasus_graph(16, edge_list=pegasus_edges)
clique_embedding_pegasus = find_clique_embedding(N, pegasus_graph)
Example #2
0
 def reconstruct(nodes):
     return dnx.chimera_graph(16, node_list=nodes)
Example #3
0
def Chimera(n, l=4):
    return dnx.chimera_graph(n, n, l, coordinates=True)
Example #4
0
def generate_graphs():

    # Store the results in csv files
    dir_path = os.path.dirname(os.path.abspath(__file__))
    results_path = os.path.join(dir_path, "results/embedding/")
    if not (os.path.exists(results_path)):
        print('Results directory ' + results_path +
              ' does not exist. We will create it.')
        os.makedirs(results_path)

    file_name = instance + '_graphs'
    file_name = os.path.join(results_path, file_name)

    # time horizons and time limit in seconds
    if TEST:
        random.seed(seed)
        time_limit = 120
        # Number of times the heuristic is run
        n_heur = 100
    else:
        time_limit = 3600
        # Number of times the heuristic is run
        n_heur = 1000

    columns = [
        'id', 'n_nodes', 'n_edges', 'nodes', 'edges', 'alpha', 'target',
        'density_target'
    ]
    results = pd.DataFrame(columns=columns)

    # Graph corresponding to D-Wave 2000Q
    qpu = DWaveSampler()
    qpu_edges = qpu.edgelist
    qpu_nodes = qpu.nodelist
    X = dnx.chimera_graph(16, node_list=qpu_nodes, edge_list=qpu_edges)
    nx.write_edgelist(X, os.path.join(results_path, "X.edgelist"))

    for k in range(K):
        for n in range(n0, N):
            print(n)
            temp = dict()

            # Target graph statistics
            temp['target'] = qpu.solver.id
            temp['density_target'] = nx.density(X)

            # Graph generation
            if instance == "cycle":
                # Cycle graphs
                Input = nx.cycle_graph(n)
                temp['id'] = "cycle_" + str(n)
                alpha = np.floor(n / 2)
            elif instance == "devil":
                # Devil graphs
                Input, alpha = devil_graphs(n)
                temp['id'] = "devil_rank_" + str(n)
            else:
                # Random graphs
                Input = nx.erdos_renyi_graph(n, prob)
                temp['id'] = "random_" + str(n) + "_" + str(prob) + "_" + str(
                    k)
                alpha = 0

            # Input graph parameters
            temp['alpha'] = alpha
            temp['n_nodes'] = Input.number_of_nodes()
            temp['n_edges'] = Input.number_of_edges()
            temp['nodes'] = Input.nodes()
            temp['edges'] = Input.edges()

            # Problem reformulations
            # Proposed and Laserre reformulation
            reforms = ['p', 'l']
            for ref in reforms:
                if ref == 'p':
                    Q, offset = proposed(Input, M=1, draw=False)
                elif ref == 'l':
                    Q, offset = laserre(Input, draw=False)

                # Graphs generation
                bqm = dimod.BinaryQuadraticModel.from_qubo(Q, offset=offset)
                edges = list(
                    itertools.chain(bqm.quadratic,
                                    ((v, v) for v in bqm.linear)))

                G = nx.Graph()
                G.add_edges_from(edges)

                # Graph statistics
                temp['nodes_' + ref] = G.nodes()
                temp['edges_' + ref] = G.edges()
                temp['n_nodes_' + ref] = G.number_of_nodes()
                temp['n_edges_' + ref] = G.number_of_edges()
                temp['density_' + ref] = nx.density(G)

            results = results.append(temp, ignore_index=True)

            results.to_csv(file_name + ".csv")

    sol_total = pd.DataFrame.from_dict(results)

    sol_total.to_excel(os.path.join(results_path, file_name + ".xlsx"))
Example #5
0
    def test__matching_qubo(self):
        # _matching_qubo creates a qubo that gives a matching for the given graph.
        # let's check that the solutions are all matchings

        G = nx.complete_graph(5)
        MAG = .75  # magnitude arg for _matching_qubo

        edge_mapping = {edge: idx for idx, edge in enumerate(G.edges())}
        edge_mapping.update({(e1, e0): idx
                             for (e0, e1), idx in edge_mapping.items()})
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Q = _matching_qubo(G, edge_mapping, magnitude=MAG)

        # now for each combination of ege, we check that if the combination
        # is a matching, it has qubo_energy 0, otherwise greater than 0. Which
        # is the desired behaviour
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            if dnx.is_matching(potential_matching):
                self.assertEqual(qubo_energy(sample, Q), 0.)
            else:
                en = qubo_energy(sample, Q)
                if en < infeasible_gap:
                    infeasible_gap = en
                self.assertGreaterEqual(en, MAG)

        self.assertEqual(MAG, infeasible_gap)

        #
        # Another graph, Chimera tile this time
        #

        G = dnx.chimera_graph(1, 1, 4)
        MAG = .67

        edge_mapping = {edge: idx for idx, edge in enumerate(G.edges())}
        edge_mapping.update({(e1, e0): idx
                             for (e0, e1), idx in edge_mapping.items()})
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Q = _matching_qubo(G, edge_mapping, magnitude=MAG)

        # now for each combination of ege, we check that if the combination
        # is a matching, it has qubo_energy 0, otherwise greater than 0. Which
        # is the desired behaviour
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            if dnx.is_matching(potential_matching):
                self.assertEqual(qubo_energy(sample, Q), 0.)
            else:
                en = qubo_energy(sample, Q)
                if en < infeasible_gap:
                    infeasible_gap = en
                self.assertGreaterEqual(en, MAG)

        self.assertEqual(MAG, infeasible_gap)
Example #6
0
    def test__maximal_matching_qubo(self):

        G = nx.complete_graph(5)
        B = 1  # magnitude arg for _maximal_matching_qubo

        edge_mapping = {edge: idx for idx, edge in enumerate(G.edges())}
        edge_mapping.update({(e1, e0): idx
                             for (e0, e1), idx in edge_mapping.items()})
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Q = _maximal_matching_qubo(G, edge_mapping, magnitude=B)

        # now for each combination of edges, we check that if the combination
        # is a maximal matching, it has energy magnitude * |edges|
        ground_energy = -1. * B * len(G.edges())
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            if dnx.is_maximal_matching(G, potential_matching):
                self.assertEqual(qubo_energy(sample, Q), ground_energy)
            elif not dnx.is_matching(potential_matching):
                # for now we don't care about these, they should be covered by the _matching_qubo
                # part of the QUBO function
                pass
            else:
                en = qubo_energy(sample, Q)

                gap = en - ground_energy
                if gap < infeasible_gap:
                    infeasible_gap = gap

        self.assertLessEqual(B, infeasible_gap)

        #
        # Another graph, Chimera tile this time
        #

        G = dnx.chimera_graph(1, 2, 2)
        B = 1  # magnitude arg for _maximal_matching_qubo

        edge_mapping = {edge: idx for idx, edge in enumerate(G.edges())}
        edge_mapping.update({(e1, e0): idx
                             for (e0, e1), idx in edge_mapping.items()})
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Q = _maximal_matching_qubo(G, edge_mapping, magnitude=B)

        # now for each combination of edges, we check that if the combination
        # is a maximal matching, it has energy magnitude * |edges|
        ground_energy = -1. * B * len(G.edges())
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            if dnx.is_maximal_matching(G, potential_matching):
                # print potential_matching, qubo_energy(Q, sample)
                self.assertLess(abs(qubo_energy(sample, Q) - ground_energy),
                                10**-8)
            elif not dnx.is_matching(potential_matching):
                # for now we don't care about these, they should be covered by the _matching_qubo
                # part of the QUBO function
                pass
            else:
                en = qubo_energy(sample, Q)

                gap = en - ground_energy
                if gap < infeasible_gap:
                    infeasible_gap = gap

        self.assertLessEqual(B - infeasible_gap, 10**-8)
Example #7
0
File: main.py Project: oeams/gurkal
def check_if_proper():

    nP = 2
    instances = [[[1, 2, 3, 4], [0]], [[2, 3, 4, 5], [0]], [[2, 4, 6, 8], [0]],
                 [[1, 2, 3, 6], [0]], [[2, 3, 4, 7], [2]],
                 [[10, 11, 12, 15], [2]], [[10, 20, 30, 40], [0]]]

    for i in instances:
        jobs = i[0]
        diff = i[1]
        table = []
        print
        print("#########################")
        print("Instance ", i)
        print(
            "c1       | c2        | Optimum   | Range     | Gap       |Relation"
        )
        for c1_mult in range(1, 11):
            c1 = max(jobs) * c1_mult + 1
            Q = create.createQUBO(jobs, nP, diff, c1_mult, 1)
            best, second, worst = solve.solution_distribution(
                Q, len(jobs), nP, diff, c1, 1)
            print(c1, "     | 1         | ", best, "    | ", worst - best,
                  "  | ", second - best, "       | ",
                  float(second - best) / float(worst - best))

            embedding = {
                0: [1760, 1632, 1764],
                1: [1628, 1636, 1634],
                2: [1638, 1630, 1627],
                3: [1752, 1624, 1759, 1767],
                4: [1763, 1635, 1765],
                5: [1761, 1633],
                6: [1754, 1626, 1758, 1766],
                7: [1631, 1639, 1625],
                8: [1637, 1629]
            }

            base_sampler = neal.SimulatedAnnealingSampler()
            G = dnx.chimera_graph(16, 16, 4)
            nodelist = G.nodes()
            edgelist = G.edges()
            source_edgelist = list(Q)
            sampler = dimod.StructureComposite(base_sampler, nodelist,
                                               edgelist)
            new_sampler = FixedEmbeddingComposite(sampler, embedding)
            solution = {'energy': [], "valid": [], 'max_time': []}
            for k in range(100):
                s = solve.solveQUBO(Q, jobs, nP, new_sampler)
                solution['energy'].append(s['energy'])
                solution['valid'].append(s['valid'])
                solution['max_time'].append(s['max_time'])
            table.append(solution)

        print("Solutions ")
        print(
            "c1       | c2    | Energies                                          | Valid                                                | Max_Time       "
        )
        for c1_mult in range(1, 11):
            print(
                max(jobs) * c1_mult + 1, "     | 1         | ",
                table[c1_mult - 1]['energy'], "    | ",
                table[c1_mult - 1]['valid'], "  | ",
                table[c1_mult - 1]['max_time'])
Example #8
0
 def test__shore_size_tiles(self):
     for t in range(1, 8):
         G = dnx.chimera_graph(1, 1, t)
         self.assertEqual(_chimera_shore_size(G.adj, len(G.edges)), t)
Example #9
0
from concurrent.futures import Future
from unittest import mock
from uuid import uuid4

import numpy as np

import dimod
import dwave_networkx as dnx

from dwave.cloud.exceptions import SolverOfflineError, SolverNotFoundError

from dwave.system.samplers import DWaveSampler
from dwave.system.warnings import EnergyScaleWarning, TooFewSamplesWarning


C16 = dnx.chimera_graph(16)

# remove one node from C16 to simulate a not-fully-yielded system
C16.remove_node(42)

edges = set(tuple(edge) for edge in C16.edges)
edges.update([(v, u) for u, v in edges])  # solver has bi-directional


class MockSolver():
    nodes = set(range(2048))
    edges = edges
    properties = {'readout_thermalization_range': [0.0, 10000.0],
                  'annealing_time_range': [1.0, 2000.0],
                  'default_readout_thermalization': 0.0,
                  'parameters': {'num_spin_reversal_transforms': '',
Example #10
0
def make_origin_embeddings(qpu_sampler=None, lattice_type=None):
    """Creates optimal embeddings for a lattice.

    The embeddings created are compatible with the topology and shape of a
    specified ``qpu_sampler``.

    Args:
        qpu_sampler (:class:`dimod.Sampler`, optional):
            Quantum sampler such as a D-Wave system. If not specified, the
            :class:`~dwave.system.samplers.DWaveSampler` sampler class is used 
            to select a QPU solver with a topology compatible with the specified
            ``lattice_type`` (e.g. an Advantage system for a 'pegasus' lattice 
            type).

        lattice_type (str, optional, default=qpu_sampler.properties['topology']['type']):
            Options are:
                * "cubic"
                    Embeddings compatible with the schemes arXiv:2009.12479 and
                    arXiv:2003.00133 are created for a ``qpu_sampler`` of
                    topology type either 'pegasus' or 'chimera'.

                * "pegasus"
                    Embeddings are chain length one (minimal and native).
                    If ``qpu_sampler`` topology type is 'pegasus', maximum
                    scale subgraphs are embedded using the ``nice_coordinates``
                    vector labeling scheme for variables.

                * "chimera"
                    Embeddings are chain length one (minimal and native).
                    If ``qpu_sampler`` topology type is 'chimera', maximum
                    scale chimera subgraphs are embedded using the chimera
                    vector labeling scheme for variables.

    Returns:
        A list of embeddings. Each embedding is a dictionary, mapping
        geometric problem keys to sets of qubits (chains) compatible with
        the ``qpu_sampler``.

    Examples:
        This example creates a list of three cubic lattice embeddings
        compatible with the default online system. These three embeddings are
        related by rotation of the lattice: for a Pegasus P16 system the
        embeddings are for lattices of size (15,15,12), (12,15,15) and (15,12,15)
        respectively.

        >>> from dwave.system.samplers import DWaveSampler   # doctest: +SKIP
        >>> sampler = DWaveSampler()  # doctest: +SKIP
        >>> embeddings = make_origin_embeddings(qpu_sampler=sampler,
        ...                                     lattice_type='cubic')  # doctest: +SKIP

    """
    if qpu_sampler is None:
        if lattice_type == 'pegasus' or lattice_type == 'chimera':
            qpu_sampler = DWaveSampler(solver={'topology__type': lattice_type})
        else:
            qpu_sampler = DWaveSampler()

    qpu_type = qpu_sampler.properties['topology']['type']
    if lattice_type is None:
        lattice_type = qpu_type
    qpu_shape = qpu_sampler.properties['topology']['shape']

    target = nx.Graph()
    target.add_edges_from(qpu_sampler.edgelist)

    if qpu_type == lattice_type:
        # Fully yielded fully utilized native topology problem.
        # This method is also easily adapted to work for any chain-length 1
        # embedding
        origin_embedding = {q: [q] for q in qpu_sampler.properties['qubits']}
        if lattice_type == 'pegasus':
            # Trimming to nice_coordinate supported embeddings is not a unique,
            # options, it has some advantages and some disadvantages:
            proposed_source = dnx.pegasus_graph(qpu_shape[0],
                                                nice_coordinates=True)
            proposed_source = nx.relabel_nodes(
                proposed_source, {
                    q: dnx.pegasus_coordinates(qpu_shape[0]).nice_to_linear(q)
                    for q in proposed_source.nodes()
                })
            lin_to_vec = dnx.pegasus_coordinates(qpu_shape[0]).linear_to_nice

        elif lattice_type == 'chimera':
            proposed_source = dnx.chimera_graph(qpu_shape[0], qpu_shape[1],
                                                qpu_shape[2])
            lin_to_vec = dnx.chimera_coordinates(
                qpu_shape[0]).linear_to_chimera
        else:
            raise ValueError(
                f'Unsupported native processor topology {qpu_type}. '
                'Support for Zephyr and other topologies is straightforward to '
                'add subject to standard dwave_networkx library tool availability.'
            )

    elif lattice_type == 'cubic':
        if qpu_type == 'pegasus':
            vec_to_lin = dnx.pegasus_coordinates(
                qpu_shape[0]).pegasus_to_linear
            L = qpu_shape[0] - 1
            dimensions = [L, L, 12]
            # See arXiv:2003.00133
            origin_embedding = {
                (x, y, z): [
                    vec_to_lin((0, x, z + 4, y)),
                    vec_to_lin((1, y + 1, 7 - z, x))
                ]
                for x in range(L) for y in range(L) for z in range(8)
                if target.has_edge(vec_to_lin((
                    0, x, z + 4, y)), vec_to_lin((1, y + 1, 7 - z, x)))
            }
            origin_embedding.update({
                (x, y, z): [
                    vec_to_lin((0, x + 1, z - 8, y)),
                    vec_to_lin((1, y, 19 - z, x))
                ]
                for x in range(L) for y in range(L) for z in range(8, 12)
                if target.has_edge(vec_to_lin((
                    0, x + 1, z - 8, y)), vec_to_lin((1, y, 19 - z, x)))
            })
        elif qpu_type == 'chimera':
            vec_to_lin = dnx.chimera_coordinates(
                qpu_shape[0], qpu_shape[1], qpu_shape[2]).chimera_to_linear
            L = qpu_shape[0] // 2
            dimensions = [L, L, 8]
            # See arxiv:2009.12479, one choice amongst many
            origin_embedding = {
                (x, y, z): [
                    vec_to_lin(coord)
                    for coord in [(2 * x + 1, 2 * y, 0,
                                   z), (2 * x, 2 * y, 0,
                                        z), (2 * x, 2 * y, 1,
                                             z), (2 * x, 2 * y + 1, 1, z)]
                ]
                for x in range(L) for y in range(L) for z in range(4)
                if target.has_edge(vec_to_lin((
                    2 * x + 1, 2 * y, 0, z)), vec_to_lin((2 * x, 2 * y, 0, z)))
                and target.has_edge(vec_to_lin((
                    2 * x, 2 * y, 0, z)), vec_to_lin((2 * x, 2 * y, 1, z)))
                and target.has_edge(vec_to_lin((
                    2 * x, 2 * y, 1, z)), vec_to_lin((2 * x, 2 * y + 1, 1, z)))
            }
            origin_embedding.update({
                (x, y, 4 + z): [
                    vec_to_lin(coord)
                    for coord in [(2 * x + 1, 2 * y, 1,
                                   z), (2 * x + 1, 2 * y + 1, 1,
                                        z), (2 * x + 1, 2 * y + 1, 0,
                                             z), (2 * x, 2 * y + 1, 0, z)]
                ]
                for x in range(L) for y in range(L) for z in range(4)
                if target.has_edge(vec_to_lin((
                    2 * x + 1, 2 * y, 1,
                    z)), vec_to_lin((2 * x + 1, 2 * y + 1, 1, z)))
                and target.has_edge(vec_to_lin((
                    2 * x + 1, 2 * y + 1, 1,
                    z)), vec_to_lin((2 * x + 1, 2 * y + 1, 0, z))) and target.
                has_edge(vec_to_lin((2 * x + 1, 2 * y + 1, 0,
                                     z)), vec_to_lin((2 * x, 2 * y + 1, 0, z)))
            })
        else:
            raise ValueError(f'Unsupported qpu_sampler topology {qpu_type} '
                             'for cubic lattice solver')

        proposed_source = _make_cubic_lattice(dimensions)
    else:
        raise ValueError('Unsupported combination of lattice_type '
                         'and qpu_sampler topology')

    origin_embedding = _yield_limited_origin_embedding(origin_embedding,
                                                       proposed_source, target)

    if qpu_type == lattice_type:
        # Convert keys to standard vector scheme:
        origin_embedding = {
            lin_to_vec(node): origin_embedding[node]
            for node in origin_embedding
        }

    # We can propose additional embeddings. Or we can use symmetries of the
    # target graph (automorphisms), to create additional embedding options.
    # This is important in the cubic case, because the subregion shape and
    # embedding features are asymmetric in the x, y and z directions.
    # Various symmetries can be exploited in all lattices.
    origin_embeddings = [origin_embedding]
    if lattice_type == 'cubic':
        # A rotation is sufficient for demonstration purposes:
        origin_embeddings.append({(key[2], key[0], key[1]): value
                                  for key, value in origin_embedding.items()})
        origin_embeddings.append({(key[1], key[2], key[0]): value
                                  for key, value in origin_embedding.items()})
    elif lattice_type == 'pegasus':
        # A horizontal to vertical flip is sufficient for demonstration purposes:       # Flip north-east to south-west axis (see draw_pegasus):
        L = qpu_shape[0]
        origin_embeddings.append({(key[0], L - 2 - key[2], L - 2 - key[1],
                                   1 - key[3], 3 - key[4]): value
                                  for key, value in origin_embedding.items()})

    else:
        # A horizontal to vertical flip is sufficient for demonstration purposes:
        origin_embeddings.append({(key[1], key[0], 1 - key[2], key[3]): value
                                  for key, value in origin_embedding.items()})

    return origin_embeddings
 def test_dimod_response_vs_list(self):
     # should be able to handle either a dimod response or a list of dicts
     G = dnx.chimera_graph(1, 1, 3)
     coloring = dnx.min_vertex_coloring(G, ExactSolver())
     coloring = dnx.min_vertex_coloring(G, SimulatedAnnealingSampler())
Example #12
0
    def __init__(self, sampler, sub_m, sub_n, t=4):

        self.parameters = sampler.parameters.copy()
        self.properties = properties = {'child_properties': sampler.properties}

        tile = dnx.chimera_graph(sub_m, sub_n, t)
        self.nodelist = sorted(tile.nodes)
        self.edgelist = sorted(sorted(edge) for edge in tile.edges)
        # dimod.Structured abstract base class automatically populates adjacency and structure as
        # mixins based on nodelist and edgelist

        if not isinstance(sampler, dimod.Structured):
            # we could also just tile onto the unstructured sampler but in that case we would need
            # to know how many tiles to use
            raise ValueError("given child sampler should be structured")
        self.children = [sampler]

        nodes_per_cell = t * 2
        edges_per_cell = t * t
        m = n = int(
            ceil(sqrt(ceil(len(sampler.structure.nodelist) /
                           nodes_per_cell))))  # assume square lattice shape
        system = dnx.chimera_graph(m,
                                   n,
                                   t,
                                   node_list=sampler.structure.nodelist,
                                   edge_list=sampler.structure.edgelist)
        c2i = {
            chimera_index: linear_index
            for (linear_index,
                 chimera_index) in system.nodes(data='chimera_index')
        }
        sub_c2i = {
            chimera_index: linear_index
            for (linear_index,
                 chimera_index) in tile.nodes(data='chimera_index')
        }

        # Count the connections between these qubits
        def _between(qubits1, qubits2):
            edges = [
                edge for edge in system.edges
                if edge[0] in qubits1 and edge[1] in qubits2
            ]
            return len(edges)

        # Get the list of qubits in a cell
        def _cell_qubits(i, j):
            return [
                c2i[(i, j, u, k)] for u in range(2) for k in range(t)
                if (i, j, u, k) in c2i
            ]

        # get a mask of complete cells
        cells = [[False for _ in range(n)] for _ in range(m)]
        for i in range(m):
            for j in range(n):
                qubits = _cell_qubits(i, j)
                cells[i][j] = len(qubits) == nodes_per_cell and _between(
                    qubits, qubits) == edges_per_cell

        # List of 'embeddings'
        self.embeddings = properties['embeddings'] = embeddings = []

        # For each possible chimera cell check if the next few cells are complete
        for i in range(m + 1 - sub_m):
            for j in range(n + 1 - sub_n):

                # Check if the sub cells are matched
                match = all(cells[i + sub_i][j + sub_j]
                            for sub_i in range(sub_m)
                            for sub_j in range(sub_n))

                # Check if there are connections between the cells.
                for sub_i in range(sub_m):
                    for sub_j in range(sub_n):
                        if sub_m > 1 and sub_i < sub_m - 1:
                            match &= _between(
                                _cell_qubits(i + sub_i, j + sub_j),
                                _cell_qubits(i + sub_i + 1, j + sub_j)) == t
                        if sub_n > 1 and sub_j < sub_n - 1:
                            match &= _between(
                                _cell_qubits(i + sub_i, j + sub_j),
                                _cell_qubits(i + sub_i, j + sub_j + 1)) == t

                if match:
                    # Pull those cells out into an embedding.
                    embedding = {}
                    for sub_i in range(sub_m):
                        for sub_j in range(sub_n):
                            cells[i +
                                  sub_i][j +
                                         sub_j] = False  # Mark cell as matched
                            for u in range(2):
                                for k in range(t):
                                    embedding[sub_c2i[sub_i, sub_j, u, k]] = {
                                        c2i[(i + sub_i, j + sub_j, u, k)]
                                    }

                    embeddings.append(embedding)

        if len(embeddings) == 0:
            raise ValueError(
                "no tile embeddings found; is the sampler Chimera structured?")
Example #13
0
 def reconstructor(m, n, t):
     return lambda nodes: dnx.chimera_graph(
         m, n=n, t=t, node_list=nodes)
 def test_chimera_layout_nodata(self):
     G = dnx.chimera_graph(2, 2, 4, data=False)
     pos = dnx.chimera_layout(G)
 def test_draw_chimera_yield(self):
     G = dnx.chimera_graph(2, 2, 4, data=False)
     G.remove_edges_from([(0, 6), (10, 13), (26, 31)])
     G.remove_nodes_from([18, 23])
     dnx.draw_chimera_yield(G)
 def test_chimera_layout_edgelist_singletile(self):
     G = dnx.chimera_graph(1, 1, 16, data=False)
     pos = dnx.chimera_layout(G.edges())
 def test_chimera_layout_basic(self):
     G = dnx.chimera_graph(1, 1, 4)
     pos = dnx.chimera_layout(G)
Example #18
0
 def test__shore_size_columns(self):
     # 2, 1, 1 is the same as 1, 1, 2
     for m in range(2, 11):
         for t in range(9, 1, -1):
             G = dnx.chimera_graph(m, 1, t)
             self.assertEqual(_chimera_shore_size(G.adj, len(G.edges)), t)
 def test_chimera_layout_typical(self):
     G = dnx.chimera_graph(2, 2, 4)
     pos = dnx.chimera_layout(G)
Example #20
0
    def test_maximal_matching_combined_qubo(self):
        """combine the qubo's generated by _maximal_matching_qubo and _matching_qubo
        and make sure they have the correct infeasible gap"""

        G = nx.complete_graph(5)
        delta = max(G.degree(node) for node in G)  # maximum degree
        A = 1  # magnitude arg for _matching_qubo
        B = .75 * A / (delta - 2.)  # magnitude arg for _maximal_matching_qubo

        edge_mapping = {edge: idx for idx, edge in enumerate(G.edges())}
        edge_mapping.update({(e1, e0): idx
                             for (e0, e1), idx in edge_mapping.items()})
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Qm = _matching_qubo(G, edge_mapping, magnitude=A)
        Qmm = _maximal_matching_qubo(G, edge_mapping, magnitude=B)

        Q = defaultdict(float)
        for edge, bias in Qm.items():
            Q[edge] += bias
        for edge, bias in Qmm.items():
            Q[edge] += bias
        Q = dict(Q)

        # now for each combination of edges, we check that if the combination
        # is a maximal matching, and if so that is has ground energy, else
        # there is an infeasible gap
        ground_energy = -1. * B * len(G.edges())  # from maximal matching
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            if dnx.is_maximal_matching(G, potential_matching):
                # print potential_matching, qubo_energy(Q, sample)
                self.assertLess(abs(qubo_energy(sample, Q) - ground_energy),
                                10**-8)
            else:
                en = qubo_energy(sample, Q)

                gap = en - ground_energy
                if gap < infeasible_gap:
                    infeasible_gap = gap

        self.assertLessEqual(B - infeasible_gap, 10**-8)

        #
        # Another graph, Chimera tile this time
        #

        G = dnx.chimera_graph(1, 1, 4)
        delta = max(G.degree(node) for node in G)  # maximum degree
        A = 1  # magnitude arg for _matching_qubo
        B = .95 * A / (delta - 2.)  # magnitude arg for _maximal_matching_qubo

        edge_mapping = {edge: idx for idx, edge in enumerate(G.edges())}
        edge_mapping.update({(e1, e0): idx
                             for (e0, e1), idx in edge_mapping.items()})
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Qm = _matching_qubo(G, edge_mapping, magnitude=A)
        Qmm = _maximal_matching_qubo(G, edge_mapping, magnitude=B)

        Q = defaultdict(float)
        for edge, bias in Qm.items():
            Q[edge] += bias
        for edge, bias in Qmm.items():
            Q[edge] += bias
        Q = dict(Q)

        # now for each combination of edges, we check that if the combination
        # is a maximal matching, and if so that is has ground energy, else
        # there is an infeasible gap
        ground_energy = -1. * B * len(G.edges())  # from maximal matching
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            if dnx.is_maximal_matching(G, potential_matching):
                # print potential_matching, qubo_energy(Q, sample)
                self.assertLess(abs(qubo_energy(sample, Q) - ground_energy),
                                10**-8)
            else:
                en = qubo_energy(sample, Q)

                gap = en - ground_energy
                if gap < infeasible_gap:
                    infeasible_gap = gap

        self.assertLessEqual(B - infeasible_gap, 10**-8)
 def test_chimera_layout_center(self):
     G = dnx.chimera_graph(2, 2, 4)
     pos = dnx.chimera_layout(G, center=(5, 5))
     with self.assertRaises(ValueError):
         pos = dnx.chimera_layout(G, center=(5, 5, 5))
Example #22
0
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.
#
# =============================================================================
import unittest

import dimod
import dimod.testing as dtest
import dwave_networkx
from dimod import ExactSolver

from dwave.system import ReverseBatchStatesComposite, ReverseAdvanceComposite

C4 = dwave_networkx.chimera_graph(4, 4, 4)


class MockReverseSampler(dimod.Sampler, dimod.Structured):
    nodelist = None
    edgelist = None
    properties = None
    parameters = None

    def __init__(self, broken_nodes=None):
        if broken_nodes is None:
            self.nodelist = sorted(C4.nodes)
            self.edgelist = sorted(sorted(edge) for edge in C4.edges)
        else:
            self.nodelist = sorted(v for v in C4.nodes
                                   if v not in broken_nodes)
 def test_chimera_layout_lowdim(self):
     G = dnx.chimera_graph(2, 2, 4)
     with self.assertRaises(ValueError):
         pos = dnx.chimera_layout(G, dim=1)
Example #24
0
H_0 = -(IX + XI)
λ, v = np.linalg.eigh(H_0)
print("Eigenvalues:", λ)
print("Eigenstate for lowest eigenvalue", v[:, 0])

# Annealing
J = {(0, 1): 1.0, (1, 2): -1.0}
h = {0: 0, 1: 0, 2: 0}
model = dimod.BinaryQuadraticModel(h, J, 0.0, dimod.SPIN)
sampler = dimod.SimulatedAnnealingSampler()
response = sampler.sample(model, num_reads=10)
print("Energy of samples:")
print([solution.energy for solution in response.data()])

# Chimera graph for connectivity structure
connectivity_structure = dnx.chimera_graph(2, 2)
dnx.draw_chimera(connectivity_structure)
plt.show()

G = nx.complete_graph(9)
plt.axis("off")
nx.draw_networkx(G, with_labels=False)
embedded_graph = minorminer.find_embedding(G.edges(),
                                           connectivity_structure.edges())
dnx.draw_chimera_embedding(connectivity_structure, embedded_graph)
plt.show()
max_chain_length = 0
for _, chain in embedded_graph.items():
    if len(chain) > max_chain_length:
        max_chain_length = len(chain)
print(max_chain_length)
 def test_chimera_layout_weird_nodata(self):
     G = dnx.chimera_graph(2, 2, 4)
     del G.graph["family"]
     with self.assertRaises(ValueError):
         pos = dnx.chimera_layout(G, dim=1)
# %%
# initialize
# https://docs.ocean.dwavesys.com/en/latest/examples/topology_samplers.html
import neal
import dimod
import dwave_networkx as dnx
import networkx as nx
import dwave.embedding
from dwave.system import DWaveSampler, EmbeddingComposite
import matplotlib.pyplot as plt

# %%
# Creating a Chimera Sapmler
C16 = dnx.chimera_graph(16)
# print(C16)
classical_sampler = neal.SimulatedAnnealingSampler()
sampler = dimod.StructureComposite(classical_sampler, C16.nodes, C16.edges)
h = {v: 0.0 for v in C16.nodes}
J = {(u, v): 1 for u, v in C16.edges}
sampleset = sampler.sample_ising(h, J)

embedding_sampler = EmbeddingComposite(sampler)

qpu_sampler = DWaveSampler(solver={
    'qpu': True,
    'num_active_qubits__within': [2000, 2048]
})
QPUGraph = nx.Graph(qpu_sampler.edgelist)
all(v in C16.nodes for v in QPUGraph.nodes)
all(edge in C16.edges for edge in QPUGraph.edges)
 def test_chimera_layout_coords(self):
     G = dnx.chimera_graph(2, 2, 4, coordinates=True)
     pos = dnx.chimera_layout(G)
Example #28
0
    def __init__(self, sampler, sub_m, sub_n, t=4):

        self.parameters = sampler.parameters.copy()
        self.properties = properties = {'child_properties': sampler.properties}

        tile = dnx.chimera_graph(sub_m, sub_n, t)
        self.nodelist = sorted(tile.nodes)
        self.edgelist = sorted(sorted(edge) for edge in tile.edges)
        # dimod.Structured abstract base class automatically populates adjacency
        # and structure as mixins based on nodelist and edgelist

        if not isinstance(sampler, dimod.Structured):
            # we could also just tile onto the unstructured sampler but in that
            # case we would need to know how many tiles to use
            raise ValueError("given child sampler should be structured")
        self.children = [sampler]
        # Chimera values (unless pegasus specified)
        num_sublattices = 1
        nodes_per_cell = t * 2
        edges_per_cell = t * t
        if not ('topology' in sampler.properties
                and 'type' in sampler.properties['topology']
                and 'shape' in sampler.properties['topology']):
            raise ValueError('To use this composite it is necessary for the'
                             'structured sampler to have an explicit topology'
                             '(sampler.properties[\'topology\']). Necessary'
                             'fields are \'type\' and \'shape\'. ')
        if sampler.properties['topology']['type'] == 'chimera':
            if len(sampler.properties['topology']['shape']) != 3:
                raise ValueError('topology shape is not of length 3 '
                                 '(not compatible with chimera)')
            if sampler.properties['topology']['shape'][2] != t:
                raise ValueError('Tiling methodology requires that solver'
                                 'and subproblem have identical shore size')
            m = sampler.properties['topology']['shape'][0]
            n = sampler.properties['topology']['shape'][1]
        else:
            if len(sampler.properties['topology']['shape']) != 1:
                raise ValueError('topology shape is not of length 1 '
                                 '(not compatible with pegasus)')
            # Full yield in odd-couplers also required.
            # Generalizes chimera subgraph requirement and leads to some
            # simplification of expressions, but at with a cost in cell-yield
            edges_per_cell += t
            # Square solvers only by pegasus lattice definition PN yields
            # 3 by N-1 by N-1 cells:
            num_sublattices = 3
            m = n = sampler.properties['topology']['shape'][0] - 1
            if t != 4:
                raise ValueError(
                    't=4 for all pegasus processors, value is not typically'
                    'stored in solver properties and is difficult to infer.'
                    'Therefore only the value t=4 is supported.')

        if num_sublattices == 1:
            # Chimera defaults. Appended coordinates (treat as first and only sublattice)
            system = dnx.chimera_graph(m,
                                       n,
                                       t,
                                       node_list=sampler.structure.nodelist,
                                       edge_list=sampler.structure.edgelist)

            c2i = {(0, *chimera_index): linear_index
                   for (linear_index,
                        chimera_index) in system.nodes(data='chimera_index')}
        else:
            system = dnx.pegasus_graph(m,
                                       node_list=sampler.structure.nodelist,
                                       edge_list=sampler.structure.edgelist)
            # Vector specification in terms of nice coordinates:
            c2i = {
                dnx.pegasus_coordinates(m + 1).linear_to_nice(linear_index):
                linear_index
                for linear_index in system.nodes()
            }

        sub_c2i = {
            chimera_index: linear_index
            for (linear_index,
                 chimera_index) in tile.nodes(data='chimera_index')
        }

        # Count the connections between these qubits
        def _between(qubits1, qubits2):
            edges = [
                edge for edge in system.edges
                if edge[0] in qubits1 and edge[1] in qubits2
            ]
            return len(edges)

        # Get the list of qubits in a cell
        def _cell_qubits(s, i, j):
            return [
                c2i[(s, i, j, u, k)] for u in range(2) for k in range(t)
                if (s, i, j, u, k) in c2i
            ]

        # get a mask of complete cells
        cells = [[[False for _ in range(n)] for _ in range(m)]
                 for _ in range(num_sublattices)]

        for s in range(num_sublattices):
            for i in range(m):
                for j in range(n):
                    qubits = _cell_qubits(s, i, j)
                    cells[s][i][j] = (len(qubits) == nodes_per_cell
                                      and _between(qubits,
                                                   qubits) == edges_per_cell)

        # List of 'embeddings'
        self.embeddings = properties['embeddings'] = embeddings = []

        # For each possible chimera cell check if the next few cells are complete
        for s in range(num_sublattices):
            for i in range(m + 1 - sub_m):
                for j in range(n + 1 - sub_n):

                    # Check if the sub cells are matched
                    match = all(cells[s][i + sub_i][j + sub_j]
                                for sub_i in range(sub_m)
                                for sub_j in range(sub_n))

                    # Check if there are connections between the cells.
                    # Both Pegasus and Chimera have t vertical and t horizontal between cells:
                    for sub_i in range(sub_m):
                        for sub_j in range(sub_n):
                            if sub_m > 1 and sub_i < sub_m - 1:
                                match &= _between(
                                    _cell_qubits(s, i + sub_i, j + sub_j),
                                    _cell_qubits(s, i + sub_i + 1,
                                                 j + sub_j)) == t
                            if sub_n > 1 and sub_j < sub_n - 1:
                                match &= _between(
                                    _cell_qubits(s, i + sub_i, j + sub_j),
                                    _cell_qubits(s, i + sub_i,
                                                 j + sub_j + 1)) == t

                    if match:
                        # Pull those cells out into an embedding.
                        embedding = {}
                        for sub_i in range(sub_m):
                            for sub_j in range(sub_n):
                                cells[s][i + sub_i][
                                    j + sub_j] = False  # Mark cell as matched
                                for u in range(2):
                                    for k in range(t):
                                        embedding[sub_c2i[sub_i, sub_j, u,
                                                          k]] = {
                                                              c2i[(s,
                                                                   i + sub_i,
                                                                   j + sub_j,
                                                                   u, k)]
                                                          }

                        self.embeddings.append(embedding)

        if len(self.embeddings) == 0:
            raise ValueError("no tile embeddings found; "
                             "is the sampler Pegasus or Chimera structured?")
Example #29
0
    def __init__(self,
                 broken_nodes=None,
                 broken_edges=None,
                 topology_type='chimera',
                 topology_shape=None,
                 **config):

        if topology_type == 'zephyr':
            if topology_shape is None:
                topology_shape = [2, 4]
            elif len(topology_shape) != 2:
                raise ValueError('topology_shape must be a 2-value '
                                 'list for Zephyr')
            # Z2 for small manageable (but non-trivial) default.
            # Z15 full scale.
            solver_graph = dnx.zephyr_graph(topology_shape[0],
                                            topology_shape[1])
        elif topology_type == 'pegasus':
            if topology_shape is None:
                topology_shape = [3]
            elif len(topology_shape) != 1:
                raise ValueError('topology_shape must be a single-value '
                                 'list for Pegasus')
            # P3 fabric_only for small manageable (but non-trivial) default.
            # P16 full scale.
            solver_graph = dnx.pegasus_graph(topology_shape[0],
                                             fabric_only=True)
        elif topology_type == 'chimera':
            if topology_shape is None:
                topology_shape = [4, 4, 4]
            elif len(topology_shape) != 3:
                raise ValueError('topology_shape must be 3-value list '
                                 'for Chimera')
            # solver_graph for small manageable (but non-trivial) default.
            # C16 full scale.
            solver_graph = dnx.chimera_graph(topology_shape[0],
                                             topology_shape[1],
                                             topology_shape[2])
        else:
            raise ValueError("Only 'chimera', 'pegasus' and 'zephyr' "
                             "topologies are supported")

        if broken_nodes is None and broken_edges is None:
            self.nodelist = sorted(solver_graph.nodes)
            self.edgelist = sorted(
                tuple(sorted(edge)) for edge in solver_graph.edges)
        else:
            if broken_nodes is None:
                broken_nodes = []
            self.nodelist = sorted(
                set(solver_graph.nodes).difference(broken_nodes))
            if broken_edges == None:
                broken_edges = []
            self.edgelist = sorted(
                tuple(sorted((u, v))) for u, v in solver_graph.edges
                if u not in broken_nodes and v not in broken_nodes and (
                    u, v) not in broken_edges and (v, u) not in broken_edges)
        # mark the sample kwargs
        self.parameters = parameters = {}
        parameters['num_reads'] = ['num_reads_range']
        parameters['flux_biases'] = ['j_range']
        parameters['label'] = []

        # add the interesting properties manually
        self.properties = properties = {}
        properties['j_range'] = [-1.0, 1.0]
        properties['h_range'] = [-2.0, 2.0]
        properties['num_reads_range'] = [1, 10000]
        properties['num_qubits'] = len(solver_graph)
        properties['category'] = 'qpu'
        properties['quota_conversion_rate'] = 1
        properties['topology'] = {
            'type': topology_type,
            'shape': topology_shape
        }
        properties['chip_id'] = 'MockDWaveSampler'
        properties['annealing_time_range'] = [1.0, 2000.0]
        properties['num_qubits'] = len(self.nodelist)
        properties['extended_j_range'] = [-2.0, 1.0]
        properties["supported_problem_types"] = ['ising', 'qubo']
        # add some occasionally useful properties
        properties["default_annealing_time"] = 20.0
        properties["default_programming_thermalization"] = 1000.0
        properties["default_readout_thermalization"] = 0.0
        properties["h_gain_schedule_range"] = [-4.0, 4.0]
        properties["max_anneal_schedule_points"] = 12
        properties["max_h_gain_schedule_points"] = 20
        properties["per_qubit_coupling_range"] = [-18.0, 15.0]
        properties["problem_run_duration_range"] = [0.0, 1000000.0]
        properties["programming_thermalization_range"] = [0.0, 10000.0]
        properties["readout_thermalization_range"] = [0.0, 10000.0]
        properties["qubits"] = self.nodelist.copy()
        properties["couplers"] = self.edgelist.copy()