Working With Different Topologies

The examples shows how to construct software samplers with the same structure as the QPU, and how to work with embeddings with different topologies.

The code examples below will use the following imports:

>>> import neal
>>> import dimod
>>> import dwave_networkx as dnx
>>> import networkx as nx
>>> import dwave.embedding
...
>>> from dwave.system import DWaveSampler, EmbeddingComposite

Creating a Chimera Sampler

As detailed in Classical Solvers, you might want to use a classical solver while developing your code or writing tests. However, it is sometimes useful to work with a software solver that behaves more like a quantum computer.

One of the key features of the quantum computer is its working graph, which defines the connectivity allowed by the binary quadratic model.

To create a software solver with the same connectivity as a D-Wave 2000Q quantum computer you first need a representation of the Chimera graph which can be obtained from the dwave_networkx project using the chimera_graph() function.

>>> C16 = dnx.chimera_graph(16)

Next, you need a software sampler. Use the SimulatedAnnealingSampler found in dwave_neal, though the TabuSampler from dwave-tabu would work equally well.

>>> classical_sampler = neal.SimulatedAnnealingSampler()

Now, with a classical sampler and the desired graph, you can use dimod’s StructureComposite to create a Chimera-structured sampler.

>>> sampler = dimod.StructureComposite(classical_sampler, C16.nodes, C16.edges)

This sampler accepts Chimera-structured problems. In this case, create an Ising problem.

>>> 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)

You can even use the sampler with the EmbeddingComposite.

>>> embedding_sampler = EmbeddingComposite(sampler)

Finally, you can confirm that the sampler matches the DWaveSampler’s structure. Make sure that the QPU has the same topology you have been simulating. Also note that the working graph of the QPU is usually a subgraph of the full hardware graph.

>>> 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)
True
>>> all(edge in C16.edges for edge in QPUGraph.edges)      # doctest: +SKIP
True

Creating a Pegasus Sampler

Another topology of interest is the Pegasus topology.

As above, you can use the generator function dwave_networkx.pegasus_graph() found in dwave_networkx and the SimulatedAnnealingSampler found in dwave_neal to construct a sampler.

>>> P6 = dnx.pegasus_graph(6)
>>> classical_sampler = neal.SimulatedAnnealingSampler()
>>> sampler = dimod.StructureComposite(classical_sampler, P6.nodes, P6.edges)

Working With Embeddings

The example above using the EmbeddingComposite hints that you might be interested in trying embedding with different topologies.

One thing you might be interested in is the chain length when embedding your problem. Say that you have a fully connected problem with 40 variables and you want to know the chain length needed to embed it on a 2048 node Chimera graph.

You can use dwave-system’s find_clique_embedding() function to find the embedding and determine the maximum chain length.

>>> num_variables = 40
>>> embedding = dwave.embedding.chimera.find_clique_embedding(num_variables, 16)
>>> max(len(chain) for chain in embedding.values())
11

Similarly you can explore clique embeddings for a 40-variables fully connected problem with a 680 node Pegasus graph using dwave-system’s find_clique_embedding() function

>>> num_variables = 40
>>> embedding = dwave.embedding.pegasus.find_clique_embedding(num_variables, 6)
>>> max(len(chain) for chain in embedding.values())
6