참고

Run interactively in the IBM Quantum lab.

# Obtaining information about your backend¶

## Note: All the attributes of the backend are described in detail in theQiskit 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.

[1]:

from qiskit.test.mock import FakeAlmaden



### 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.

[2]:

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 fake_almaden, and is on version 1.4.6. It has 20 qubits. It supports OpenPulse programs. The basis gates supported on this device are ['id', 'u1', 'u2', 'u3', 'cx'].


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.

[3]:

config.dt  # units of seconds

[3]:

2.2222222222222221e-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, see this page – COMING SOON.

[4]:

config.meas_levels

[4]:

[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:

[5]:

config.dtm

[5]:

2.2222222222222221e-10


The measurement map, explained in detail on [this page COMING SOON], is also found here.

[6]:

config.meas_map

[6]:

[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]]


The configuration also supplies convenient methods for getting channels for your schedule programs. For instance:

[7]:

config.drive(0)

[7]:

DriveChannel(0)

[8]:

config.measure(0)

[8]:

MeasureChannel(0)

[9]:

config.acquire(0)

[9]:

AcquireChannel(0)


It is a matter of style and personal preference whether you use config.drive(0) or DriveChannel(0).

### Properties¶

The backend properties contain data that was measured and optionally reported by the provider. Let’s see what kind of information is reported for qubit 0.

[10]:

props = backend.properties()

[11]:

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('u2', qubit),
properties.gate_length('u2', qubit) * ns,
properties.frequency(qubit) * GHz))

describe_qubit(0, props)

Qubit 0 has a
- T1 time of 96.36208105210916 microseconds
- T2 time of 43.4363963452638 microseconds
- U2 gate error of 0.0011847011560486597
- U2 gate duration of 35.55555555555556 nanoseconds
- resonant frequency of 4.85648672471907 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.

[12]:

defaults = backend.defaults()


#### Drive frequencies¶

Defaults contains the default frequency settings for the drive and measurement signal channels:

[13]:

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.85648672471907 GHz.
MeasureChannel(0) defaults to a modulation frequency of 7.264856891000002 GHz.


#### Pulse Schedule definitions for QuantumCircuit instructions¶

Finally, one of the most important aspects of the backend for Schedule building is the InstructionScheduleMap. This is a basic mapping from a circuit operation’s name and qubit to the default pulse-level implementation of that instruction.

[14]:

calibrations = defaults.instruction_schedule_map
print(calibrations)

<InstructionScheduleMap(1Q instructions:
q0: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q1: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q2: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q3: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q4: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q5: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q6: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q7: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q8: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q9: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q10: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q11: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q12: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q13: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q14: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q15: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q16: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q17: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q18: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
q19: {'u3', 'id', 'x', 'u2', 'u1', 'measure'}
Multi qubit instructions:
(0, 1): {'cx'}
(1, 0): {'cx'}
(1, 2): {'cx'}
(1, 6): {'cx'}
(2, 1): {'cx'}
(2, 3): {'cx'}
(3, 2): {'cx'}
(3, 4): {'cx'}
(3, 8): {'cx'}
(4, 3): {'cx'}
(5, 6): {'cx'}
(5, 10): {'cx'}
(6, 1): {'cx'}
(6, 5): {'cx'}
(6, 7): {'cx'}
(7, 6): {'cx'}
(7, 8): {'cx'}
(7, 12): {'cx'}
(8, 3): {'cx'}
(8, 7): {'cx'}
(8, 9): {'cx'}
(9, 8): {'cx'}
(9, 14): {'cx'}
(10, 5): {'cx'}
(10, 11): {'cx'}
(11, 10): {'cx'}
(11, 12): {'cx'}
(11, 16): {'cx'}
(12, 7): {'cx'}
(12, 11): {'cx'}
(12, 13): {'cx'}
(13, 12): {'cx'}
(13, 14): {'cx'}
(13, 18): {'cx'}
(14, 9): {'cx'}
(14, 13): {'cx'}
(15, 16): {'cx'}
(16, 11): {'cx'}
(16, 15): {'cx'}
(16, 17): {'cx'}
(17, 16): {'cx'}
(17, 18): {'cx'}
(18, 13): {'cx'}
(18, 17): {'cx'}
(18, 19): {'cx'}
(19, 18): {'cx'}
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19): {'measure'}
)>


Rather than build a measurement schedule from scratch, let’s see what was calibrated by the backend to measure the qubits on this device:

[15]:

measure_schedule = calibrations.get('measure', [q for q in range(config.n_qubits)])
measure_schedule.draw(plot_range=[0, 1000])

[15]:


This can easily be appended to your own Pulse Schedule (sched += calibrations.get('measure', <qubits>) << sched.duration)!

Likewise, each qubit will have a Schedule defined for each basis gate, and they can be appended directly to any Schedule you build.

[16]:

# You can use has to see if an operation is defined. Ex: Does qubit 3 have an x gate defined?
calibrations.has('x', 3)

[16]:

True

[17]:

# Some circuit operations take parameters. U1 takes a rotation angle:
calibrations.get('u1', 0, P0=3.1415)

[17]:

Schedule((0, ShiftPhase(-3.1415, DriveChannel(0))), (0, ShiftPhase(-3.1415, ControlChannel(1))), name="u1")


While building your schedule, you can also use calibrations.add(name, qubits, schedule) to store useful Schedules that you’ve made yourself.

On this page, we’ll show how to schedule QuantumCircuits into Pulse Schedules.

[18]:

import qiskit.tools.jupyter
%qiskit_version_table


### Version Information

Qiskit SoftwareVersion
Qiskit0.23.2
Terra0.16.2
Aer0.7.2
Ignis0.5.1
Aqua0.8.1
IBM Q Provider0.11.1
System information
Python3.9.1 (default, Dec 10 2020, 10:36:35) [Clang 12.0.0 (clang-1200.0.32.27)]
OSDarwin
CPUs6
Memory (Gb)32.0
Tue Jan 26 15:30:30 2021 EST