Obtaining information about your backend¶
Note: All the attributes of the backend are described in detail in the Qiskit Backend Specifications. This page reviews a subset of the spec.¶
Programming a quantum computer at the microwave pulse level requires more information about the device than is required at the circuit level. A quantum circuit is built for an abstract quantum computer -- it will yield the same quantum state on any quantum computer (except for varying performance levels). A pulse schedule, on the other hand, is so specific to the device, that running one program on two different backends is not expected to have the same result, even on perfectly noiseless systems.
As a basic example, imagine a drive pulse q0_X180 calibrated on qubit 0 to enact an $X180$ pulse, which flips the state of qubit 0. If we use the samples from that pulse on qubit 1 on the same device, or qubit 0 on another device, we do not know what the resulting state will be -- but we can be pretty sure it won't be an $X180$ operation. The qubits are each unique, with various drive coupling strengths. If we have specified a frequency for the drive pulse, it's very probable that pulse would have little effect on another qubit, which has its own resonant frequency.
With that, we have motivated why information from the backend may be very useful at times for building Pulse schedules. The information included in a backend is broken into three main parts:
- Configuration: static backend features
- Properties: measured and reported backend characteristics
- Defaults: default settings for the OpenPulse-enabled backend
which are each covered in the following sections. While all three of these contain interesting data for Pulse users, the defaults are only provided for backends enabled with OpenPulse.
The first thing you'll need to do is grab a backend to inspect. Here we use a mocked backend that contains a snapshot of data from the real OpenPulse-enabled backend.
%load_ext dotenv
%dotenv
import os
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
from qiskit.visualization import plot_histogram
token = os.environ["IBMQ_TOKEN"]
service = QiskitRuntimeService(
token=token,
channel="ibm_quantum",
)
backend = service.least_busy(operational=True, simulator=False)
/tmp/ipykernel_9744/3214271246.py:2: DeprecationWarning: The "ibm_quantum" channel option is deprecated and will be sunset on 1 July. After this date, ibm_cloud will be the only valid channel. For information on migrating to the new IBM Quantum Platform on the "ibm_cloud" channel, review the migration guide https://quantum.cloud.ibm.com/docs/migration-guides/classic-iqp-to-cloud-iqp . service = QiskitRuntimeService(
Configuration¶
The configuration is where you'll find data about the static setup of the device, such as its name, version, the number of qubits, and the types of features it supports.
Let's build a description of our backend using information from the backend's config.
config = backend.configuration()
# Basic Features
print("This backend is called {0}, and is on version {1}. It has {2} qubit{3}. It "
"{4} OpenPulse programs. The basis gates supported on this device are {5}."
"".format(config.backend_name,
config.backend_version,
config.n_qubits,
'' if config.n_qubits == 1 else 's',
'supports' if config.open_pulse else 'does not support',
config.basis_gates))
This backend is called ibm_brisbane, and is on version 1.1.115. It has 127 qubits. It supports OpenPulse programs. The basis gates supported on this device are ['ecr', 'id', 'rz', 'sx', 'x'].
Neat! All of the above configuration is available for any backend, whether enabled with OpenPulse or not, although it is not an exhaustive list. There are additional attributes available on Pulse backends. Let's go into a bit more detail with those.
The timescale, dt, is backend dependent. Think of this as the inverse sampling rate of the control rack's arbitrary waveform generators. Each sample point and duration in a Pulse Schedule is given in units of this timescale.
config.dt # units of seconds
5e-10
The configuration also provides information that is useful for building measurements. Pulse supports three measurement levels: 0: RAW, 1: KERNELED, and 2: DISCRIMINATED. The meas_levels attribute tells us which of those are supported by this backend. To learn how to execute programs with these different levels
config.meas_levels
[1, 2]
For backends which support measurement level 0, the sampling rate of the control rack's analog-to-digital converters (ADCs) also becomes relevant. The configuration also has this info, where dtm is the time per sample returned:
config.dtm
5e-10
The measurement map, explained in detail on [this page COMING SOON], is also found here.
config.meas_map
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126]]
props = backend.properties()
def describe_qubit(qubit, properties):
"""Print a string describing some of reported properties of the given qubit."""
# Conversion factors from standard SI units
us = 1e6
ns = 1e9
GHz = 1e-9
print("Qubit {0} has a \n"
" - T1 time of {1} microseconds\n"
" - T2 time of {2} microseconds\n"
" - U2 gate error of {3}\n"
" - U2 gate duration of {4} nanoseconds\n"
" - resonant frequency of {5} GHz".format(
qubit,
properties.t1(qubit) * us,
properties.t2(qubit) * us,
properties.gate_error('sx', qubit),
properties.gate_length('sx', qubit) * ns,
properties.frequency(qubit) * GHz))
describe_qubit(0, props)
Qubit 0 has a - T1 time of 315.32988680168523 microseconds - T2 time of 57.508663902391426 microseconds - U2 gate error of 0.0001756228696857236 - U2 gate duration of 59.99999999999999 nanoseconds - resonant frequency of 4.7219057784834355 GHz
Properties are not guaranteed to be reported, but backends without Pulse access typically also provide this data.
Defaults¶
Unlike the other two sections, PulseDefaults are only available for Pulse-enabled backends. It contains the default program settings run on the device.
defaults = backend.defaults()
/tmp/ipykernel_9744/3348888366.py:1: DeprecationWarning: The defaults method and the PulseDefaults class have been deprecated as of qiskit-ibm-runtime 0.38.0 and will be removed no sooner than 3 months after the release date. IBM backends no longer support pulse gates and are no longer used to construct the backend target. defaults = backend.defaults()
Drive frequencies¶
Defaults contains the default frequency settings for the drive and measurement signal channels:
q0_freq = defaults.qubit_freq_est[0] # Hz
q0_meas_freq = defaults.meas_freq_est[0] # Hz
GHz = 1e-9
print("DriveChannel(0) defaults to a modulation frequency of {} GHz.".format(q0_freq * GHz))
print("MeasureChannel(0) defaults to a modulation frequency of {} GHz.".format(q0_meas_freq * GHz))
DriveChannel(0) defaults to a modulation frequency of 4.7219057784834355 GHz. MeasureChannel(0) defaults to a modulation frequency of 7.175428524047674 GHz.
Dynamic backend information¶
Backends can also have properties that change whenever the backed is calibrated, such as qubit frequency and operation error rates. Backends are usually calibrated every 24 hours, and their properties update after the calibration sequence completes. These properties can be used when optimizing quantum circuits or to construct noise models for a classical simulator.
backend.qubit_properties(0) # properties of qubit 0
QubitProperties(t1=0.00031532988680168524, t2=5.750866390239143e-05, frequency=4721905778.483436)
backend.target["ecr"][(1, 0)]
InstructionProperties(duration=6.6e-07, error=0.0033926162842485563, calibration=None)
backend.target["measure"][(0,)]
InstructionProperties(duration=1.3e-06, error=0.034423828125, calibration=None)