Basic D-Wave usage¶
In this notebook you will learn how to:
- Query the D-Wave solvers available to your account
- Embed a QUBO problem, submit it to a solver and inspect the results
- Inspect the qubit connectivity of a QPU
- Submit the same QUBO problem as above, but with manual instead of automatic embedding
- Learn about the five-dimensional Pegasus coordinate system to identify the position of individual qubits on the chip
- Learn about the five-dimensional Zephyr coordinate system (Advantage2) to identify the position of individual qubits on the chip
Initialization¶
import dwave
import dwave.inspector
from dwave.system import DWaveSampler, EmbeddingComposite
from dwave.cloud import Client
import networkx as nx
import dwave_networkx as dnx
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
%matplotlib inline
client = Client.from_config(profile='defaults')
client.get_solvers()
[BQMSolver(id='hybrid_binary_quadratic_model_version2'), DQMSolver(id='hybrid_discrete_quadratic_model_version1'), CQMSolver(id='hybrid_constrained_quadratic_model_version1p'), StructuredSolver(id='Advantage_system6.4'), StructuredSolver(id='Advantage2_prototype2.3'), StructuredSolver(id='Advantage_system4.1')]
client = Client.from_config(profile='defaults', region='eu-central-1')
client.get_solvers()
[StructuredSolver(id='Advantage_system5.4')]
Solve a QUBO problem with embedding¶
qubo = {
(0,0): -1,
(1,1): -0.5,
(0,1): 2,
}
sampler = EmbeddingComposite(DWaveSampler(profile='defaults', solver='Advantage_system4.1')) # can replace solver by any other solver above (need to use region='eu-central-1' for the D-Wave systems in Jülich)
results = sampler.sample_qubo(qubo, num_reads=100)
results.to_pandas_dataframe()
| 0 | 1 | chain_break_fraction | energy | num_occurrences | |
|---|---|---|---|---|---|
| 0 | 1 | 0 | 0.0 | -1.0 | 91 |
| 1 | 0 | 1 | 0.0 | -0.5 | 9 |
dwave.inspector.show(results) # to visualize the results on the QPU interactively
Solve a QUBO problem without embedding¶
plt.figure(figsize=(16,6), dpi=70)
G = dnx.pegasus_graph(16)
dnx.draw_pegasus(G, with_labels=True, crosses=True, node_color="Yellow", node_size=1000)
plt.margins(x=-0.44, y=-0.48) # zoom into the graph
qubo = {
(1387,4327): -1,
(4327,4327): -0.5,
(1387,4327): 2,
}
sampler = DWaveSampler(profile='defaults', solver='Advantage_system4.1') # can replace solver by any other solver above (need to use region='eu-central-1' for the D-Wave systems in Jülich)
results = sampler.sample_qubo(qubo, num_reads=100)
results.to_pandas_dataframe()
| 1387 | 4327 | energy | num_occurrences | |
|---|---|---|---|---|
| 0 | 0 | 1 | -0.5 | 94 |
| 1 | 1 | 0 | 0.0 | 3 |
| 2 | 0 | 0 | 0.0 | 3 |
Pegasus coordinate system¶
Nice coordinates (t,y,x,u,k)¶
pegasus_coords = dnx.pegasus_coordinates(16) # there are also Chimera coordinates (for DW2000Q: dnx.chimera_coordinates(16,16,4)) or Zephyr coordinates
We can translate the linear physical qubit indices q above into a five-dimensional Pegasus coordinate system (that is compatible with Chimera too):
t, y, x, u, k = pegasus_coords.linear_to_nice(q)
pegasus_coords.linear_to_nice(1387)
(1, 7, 7, 0, 0)
pegasus_coords.linear_to_nice(4327)
(1, 7, 7, 1, 0)
pegasus_coords.linear_to_nice(346)
(1, 1, 1, 0, 3)
The "nice" Pegasus coordinates (t,y,x,u,k) enumerate the full Pegasus topology in the following way:
t: depth index of the three 8-qubit Chimera crosses within one unit cell (t=0,1,2)y: vertical unit cell indexx: horizontal unit cell indexu: denotes the horizontal (u=0) or vertical (u=1) 4 qubits withing an 8-qubit Chimera crossk: enumerates the four qubits within this part of the Chimera cross (k=0,1,2,3)
Note that these coordinates can be easily related to Chimera coordinates (y,x,u,k). In this context, the five-dimensional Pegasus coordinates only have the additional t dimension (t=0,1,2). The corresponding functions chimera_coords.linear_to_chimera(q) and chimera_coords.chimera_to_linear(y,x,u,k) from chimera_coords = dnx.chimera_coordinates(16,16,4) can be used for this purpose.
qubit_labels = {
pegasus_coords.nice_to_linear((0, 0, 0, 0, 2)): 'x,y=0\nt=0',
pegasus_coords.nice_to_linear((1, 0, 0, 0, 2)): 't=1',
pegasus_coords.nice_to_linear((2, 0, 0, 0, 2)): 't=2',
}
qubit_labels.update({
pegasus_coords.nice_to_linear((0, 0, x, 0, 2)): f'x={x}' for x in range(1,16)
})
qubit_labels.update({
pegasus_coords.nice_to_linear((0, y, 0, 0, 2)): f'y={y}' for y in range(1,15)
})
fig,ax = plt.subplots(1, 1, figsize=(20,20), dpi=70)
dnx.draw_pegasus(dnx.pegasus_graph(16), ax=ax, crosses=True, node_size=50, node_color='red', edge_color='gray')
dnx.draw_pegasus(dnx.pegasus_graph(16, node_list=qubit_labels), labels=qubit_labels, ax=ax, crosses=True, node_size=1000, node_color='yellow', edge_color='gray')
plt.margins(x=-0.02, y=-0.02)
qubit_labels = {
pegasus_coords.nice_to_linear((1, 7, 7, 0, 0)): 'u=0\nk=0',
pegasus_coords.nice_to_linear((1, 7, 7, 0, 1)): '\nk=1',
pegasus_coords.nice_to_linear((1, 7, 7, 0, 2)): '\nk=2',
pegasus_coords.nice_to_linear((1, 7, 7, 0, 3)): '\nk=3',
pegasus_coords.nice_to_linear((2, 7, 7, 1, 0)): 'u=1\nk=0',
pegasus_coords.nice_to_linear((2, 7, 7, 1, 1)): '\nk=1',
pegasus_coords.nice_to_linear((2, 7, 7, 1, 2)): '\nk=2',
pegasus_coords.nice_to_linear((2, 7, 7, 1, 3)): '\nk=3',
}
fig,ax = plt.subplots(figsize=(16,6), dpi=70)
dnx.draw_pegasus(dnx.pegasus_graph(16), ax=ax, crosses=True, node_size=500, node_color='red', edge_color='gray')
dnx.draw_pegasus(dnx.pegasus_graph(16, node_list=qubit_labels), labels=qubit_labels, ax=ax, crosses=True, node_size=1000, node_color='yellow', edge_color='gray')
plt.margins(x=-0.44, y=-0.48)
Pegasus coordinates (u,w,k,z)¶
In addition to the nice coordinates (t,y,x,u,k), there are the four-dimensional Pegasus coordinates (u,w,k,z).
Although a bit less intuitive, they can be more easily translated to the future Zephyr coordinates of Advantage2 (see below).
Further information can also be found in this D-Wave example notebook
pegasus_coords = dnx.pegasus_coordinates(16)
We can translate the linear physical qubit indices q above into four-dimensional Pegasus (m=16) coordinates:
u, w, k, z = pegasus_coords.linear_to_pegasus(q)
The Pegasus coordinates (u,w,k,z) enumerate the Pegasus topology (m=16) in the following way:
- u: qubit orientation (0 = vertical, 1 = horizontal)
- w: orthogonal major offset; 0 <= w <= 15
- k: orthogonal minor offset; 0 <= k <= 11
- z: parallel offset; 0 <= z <= 14
for u in (0,1):
qubit_labels = { pegasus_coords.pegasus_to_linear((u, 0, 0, 0)): f'w=0\nz=0' }
qubit_labels.update({ pegasus_coords.pegasus_to_linear((u, w, 0, 0)): f'w={w}' for w in range(1,16) })
qubit_labels.update({ pegasus_coords.pegasus_to_linear((u, 0, 0, z)): f'z={z}' for z in range(1,15) })
fig,ax = plt.subplots(1, 1, figsize=(20,20), dpi=70)
dnx.draw_pegasus(dnx.pegasus_graph(16), ax=ax, crosses=True, node_size=50, node_color='red', edge_color='gray')
dnx.draw_pegasus(dnx.pegasus_graph(16, node_list=qubit_labels), labels=qubit_labels, ax=ax, crosses=True, node_size=1000, node_color='yellow', edge_color='gray')
plt.title(f'u = {u}: {("vertical","horizontal")[u]}', fontsize=20, loc='left')
plt.margins(x=-0.02, y=-0.02)
plt.show()
for u in (0,1):
qubit_labels = { pegasus_coords.pegasus_to_linear((u, 7, k, 7)): f'w=7\nk={k}' if k%4==0 else f'\nk={k}' for k in range(12) }
qubit_labels_next_w = { pegasus_coords.pegasus_to_linear((u, 8, k, 7)): f'w=8\nk={k}' if k%4==0 else f'\nk={k}' for k in range(12) }
fig,ax = plt.subplots(figsize=(16,12), dpi=70)
dnx.draw_pegasus(dnx.pegasus_graph(16), ax=ax, crosses=True, node_size=500, node_color='red', edge_color='gray')
dnx.draw_pegasus(dnx.pegasus_graph(16, node_list=qubit_labels), labels=qubit_labels, ax=ax, crosses=True, node_size=1000, node_color='yellow', edge_color='gray')
dnx.draw_pegasus(dnx.pegasus_graph(16, node_list=qubit_labels_next_w), labels=qubit_labels_next_w, ax=ax, crosses=True, node_size=1000, node_color='lightgreen', edge_color='gray')
plt.title(f'u = {u}:', fontsize=20, loc='left')
plt.margins(x=-0.44, y=-0.44)
plt.show()