Note
This page was generated from tutorials/noise/1_hamiltonian_and_gate_characterization.ipynb.
Hamiltonian and Gate Characterization¶
This notebook gives examples to demonstrate how to use the characterization.hamiltonian
and characterization.gates
modules in Qiskit Ignis. For a theory background see the Ignis Community Notebooks.
[1]:
import numpy as np
import matplotlib.pyplot as plt
import qiskit
from qiskit.providers.aer.noise.errors.standard_errors import coherent_unitary_error
from qiskit.providers.aer.noise import NoiseModel
from qiskit.ignis.characterization.hamiltonian import ZZFitter, zz_circuits
from qiskit.ignis.characterization.gates import (AmpCalFitter, ampcal_1Q_circuits,
AngleCalFitter, anglecal_1Q_circuits,
AmpCalCXFitter, ampcal_cx_circuits,
AngleCalCXFitter, anglecal_cx_circuits)
Measuring ZZ¶
The characterization.hamiltonian.zz_circuits
module builds the circuits to perform an experiment to measure ZZ between a pair of qubits. Here, ZZ is defined as the energy shift on the \(|11\rangle\) state:
The experiment to measure \(\xi\) is to perform a Ramsey experiment on Q0 (H-t-H) and repeat the Ramsey experiment with Q1 in the excited state. The difference in frequency between these experiments is the rate \(\xi\).
[2]:
# ZZ rates are typically ~ 100kHz so we want Ramsey oscillations around 1MHz
# 12 numbers ranging from 10 to 1000, logarithmically spaced
# extra point at 1500
num_of_gates = np.arange(0,150,5)
gate_time = 0.1
# Select the qubits whose ZZ will be measured
qubits = [0]
spectators = [1]
# Generate experiments
circs, xdata, osc_freq = zz_circuits(num_of_gates, gate_time, qubits, spectators, nosc=2)
One of the features of the fitters is that we can split the circuits into multiple jobs and then give the results to the fitter as a list. This is demonstrated below.
[3]:
# Set the simulator with ZZ
zz_unitary = np.eye(4,dtype=complex)
zz_unitary[3,3] = np.exp(1j*2*np.pi*0.02*gate_time)
error = coherent_unitary_error(zz_unitary)
noise_model = NoiseModel()
noise_model.add_nonlocal_quantum_error(error, 'id', [0], [0,1])
# Run the simulator
backend = qiskit.Aer.get_backend('qasm_simulator')
shots = 500
# For demonstration purposes split the execution into two jobs
print("Running the first 20 circuits")
backend_result1 = qiskit.execute(circs[0:20], backend,
shots=shots, noise_model=noise_model).result()
print("Running the rest of the circuits")
backend_result2 = qiskit.execute(circs[20:], backend,
shots=shots, noise_model=noise_model).result()
Running the first 20 circuits
Running the rest of the circuits
[4]:
# Fit the data to an oscillation
plt.figure(figsize=(10, 6))
initial_a = 1
initial_c = 0
initial_f = osc_freq
initial_phi = -np.pi/20
# Instantiate the fitter
# pass the 2 results in as a list of results
fit = ZZFitter([backend_result1, backend_result2], xdata, qubits, spectators,
fit_p0=[initial_a, initial_f, initial_phi, initial_c],
fit_bounds=([-0.5, 0, -np.pi, -0.5],
[1.5, 2*osc_freq, np.pi, 1.5]))
fit.plot_ZZ(0, ax=plt.gca())
print("ZZ Rate: %f kHz"%(fit.ZZ_rate()[0]*1e3))
plt.show()
ZZ Rate: 0.012224 kHz

Amplitude Error Characterization for Single Qubit Gates¶
Measure the amplitude error in the single qubit gates. Here this measures the error in the \(\pi/2\) pulse. Note that we can run multiple amplitude calibrations in parallel. Here we measure on qubits 2 and 4.
[5]:
qubits = [4,2]
circs, xdata = ampcal_1Q_circuits(10, qubits)
This shows the sequence of the calibration, which is a repeated application of Y90 (U2[0,0]). Note that the measurements are mapped to a minimal number of classical registers in order of the qubit list.
[6]:
print(circs[2])
q1_0: ─────────────────────────────────────────────────────────────────────────
q1_1: ─────────────────────────────────────────────────────────────────────────
┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐ ┌─┐
q1_2: ┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├───┤M├
└─────────┘ ░ └─────────┘ ░ └─────────┘ ░ └─────────┘ ░ └─────────┘ └╥┘
q1_3: ───────────────────────────────────────────────────────────────────────╫─
┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐┌─┐ ║
q1_4: ┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├┤M├─╫─
└─────────┘ ░ └─────────┘ ░ └─────────┘ ░ └─────────┘ ░ └─────────┘└╥┘ ║
c1: 2/════════════════════════════════════════════════════════════════════╩══╩═
0 1
[7]:
# Set the simulator
# Add a rotation error
err_unitary = np.zeros([2,2],dtype=complex)
angle_err = 0.1
for i in range(2):
err_unitary[i,i] = np.cos(angle_err)
err_unitary[i,(i+1) % 2] = np.sin(angle_err)
err_unitary[0,1] *= -1.0
error = coherent_unitary_error(err_unitary)
noise_model = NoiseModel()
noise_model.add_all_qubit_quantum_error(error, 'u2')
# Run the simulator
backend = qiskit.Aer.get_backend('qasm_simulator')
shots = 500
backend_result1 = qiskit.execute(circs, backend,
shots=shots, noise_model=noise_model).result()
[8]:
# Fit the data to an oscillation
plt.figure(figsize=(10, 6))
initial_theta = 0.02
initial_c = 0.5
initial_phi = 0.1
fit = AmpCalFitter(backend_result1, xdata, qubits,
fit_p0=[initial_theta, initial_c],
fit_bounds=([-np.pi, -1],
[np.pi, 1]))
# plot the result for the number 1 indexed qubit.
# In this case that refers to Q2 since we passed in as [4, 2])
fit.plot(1, ax=plt.gca())
print("Rotation Error on U2: %f rads"%(fit.angle_err()[0]))
plt.show()
Rotation Error on U2: 0.100430 rads

Angle Error Characterization for Single Qubit Gates¶
Measure the angle between the X and Y gates:
[9]:
qubits = [0,1]
circs, xdata = anglecal_1Q_circuits(10, qubits, angleerr=0.1)
The gate sequence for measuring the angle error:
[10]:
#The U1 gates are added errors to test the procedure
print(circs[2])
┌─────────┐┌──────────┐ ░ ┌──────────────┐ ░ ┌──────────────┐┌─────────┐»
q2_0: ┤ U2(0,0) ├┤ U1(-0.2) ├─░─┤ U2(-π/2,π/2) ├─░─┤ U2(-π/2,π/2) ├┤ U1(0.2) ├»
├─────────┤├──────────┤ ░ ├──────────────┤ ░ ├──────────────┤├─────────┤»
q2_1: ┤ U2(0,0) ├┤ U1(-0.2) ├─░─┤ U2(-π/2,π/2) ├─░─┤ U2(-π/2,π/2) ├┤ U1(0.2) ├»
└─────────┘└──────────┘ ░ └──────────────┘ ░ └──────────────┘└─────────┘»
c2: 2/════════════════════════════════════════════════════════════════════════»
»
« ░ ┌─────────┐ ░ ┌─────────┐┌──────────┐ ░ ┌──────────────┐ ░ »
«q2_0: ─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├┤ U1(-0.2) ├─░─┤ U2(-π/2,π/2) ├─░─»
« ░ ├─────────┤ ░ ├─────────┤├──────────┤ ░ ├──────────────┤ ░ »
«q2_1: ─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├┤ U1(-0.2) ├─░─┤ U2(-π/2,π/2) ├─░─»
« ░ └─────────┘ ░ └─────────┘└──────────┘ ░ └──────────────┘ ░ »
«c2: 2/══════════════════════════════════════════════════════════════»
« »
« ┌──────────────┐┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐┌──────────┐»
«q2_0: ┤ U2(-π/2,π/2) ├┤ U1(0.2) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├┤ U1(-0.1) ├»
« ├──────────────┤├─────────┤ ░ ├─────────┤ ░ ├─────────┤├──────────┤»
«q2_1: ┤ U2(-π/2,π/2) ├┤ U1(0.2) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├┤ U1(-0.1) ├»
« └──────────────┘└─────────┘ ░ └─────────┘ ░ └─────────┘└──────────┘»
«c2: 2/═══════════════════════════════════════════════════════════════════»
« »
« ┌──────────────┐┌─┐
«q2_0: ┤ U2(-π/2,π/2) ├┤M├───
« ├──────────────┤└╥┘┌─┐
«q2_1: ┤ U2(-π/2,π/2) ├─╫─┤M├
« └──────────────┘ ║ └╥┘
«c2: 2/═════════════════╩══╩═
« 0 1
[11]:
# Set the simulator
# Run the simulator
backend = qiskit.Aer.get_backend('qasm_simulator')
shots = 1000
backend_result1 = qiskit.execute(circs, backend,
shots=shots).result()
[12]:
# Fit the data to an oscillation
plt.figure(figsize=(10, 6))
initial_theta = 0.02
initial_c = 0.5
initial_phi = 0.01
fit = AngleCalFitter(backend_result1, xdata, qubits,
fit_p0=[initial_theta, initial_c],
fit_bounds=([-np.pi, -1],
[np.pi, 1]))
fit.plot(0, ax=plt.gca())
print("Angle error between X and Y: %f rads"%(fit.angle_err()[0]))
plt.show()
Angle error between X and Y: 0.097006 rads

Amplitude Error Characterization for CX Gates¶
This looks for a rotation error in the CX gate, i.e. if the gate is actually \(CR_x(\pi/2+\delta)\) measure \(\delta\). This is very similar to the single qubit amplitude error calibration except we need to specify a control qubit (which is set to be in state \(|1\rangle\)) and the rotation is \(\pi\).
[13]:
# We can specify more than one CX gate to calibrate in parallel
# but these lists must be the same length and not contain
# any duplicate elements
qubits = [0,2]
controls = [1,3]
circs, xdata = ampcal_cx_circuits(15, qubits, controls)
The gate sequence to calibrate the amplitude of the CX gate on Q0-Q1 and Q2-Q3 in parallel:
[14]:
print(circs[2])
┌──────────────┐ ░ ┌───┐ ░ ┌───┐┌─┐
q3_0: ┤ U2(-π/2,π/2) ├─░─┤ X ├─░─┤ X ├┤M├───
└────┬───┬─────┘ ░ └─┬─┘ ░ └─┬─┘└╥┘
q3_1: ─────┤ X ├───────░───■───░───■───╫────
┌────┴───┴─────┐ ░ ┌───┐ ░ ┌───┐ ║ ┌─┐
q3_2: ┤ U2(-π/2,π/2) ├─░─┤ X ├─░─┤ X ├─╫─┤M├
└────┬───┬─────┘ ░ └─┬─┘ ░ └─┬─┘ ║ └╥┘
q3_3: ─────┤ X ├───────░───■───░───■───╫──╫─
└───┘ ░ ░ ║ ║
c3: 2/═════════════════════════════════╩══╩═
0 1
[15]:
# Set the simulator
# Add a rotation error on CX
# only if the control is in the excited state
err_unitary = np.eye(4,dtype=complex)
angle_err = 0.15
for i in range(2):
err_unitary[2+i,2+i] = np.cos(angle_err)
err_unitary[2+i,2+(i+1) % 2] = -1j*np.sin(angle_err)
error = coherent_unitary_error(err_unitary)
noise_model = NoiseModel()
noise_model.add_nonlocal_quantum_error(error, 'cx', [1,0], [0,1])
# Run the simulator
backend = qiskit.Aer.get_backend('qasm_simulator')
shots = 1500
backend_result1 = qiskit.execute(circs, backend,
shots=shots, noise_model=noise_model).result()
[16]:
# Fit the data to an oscillation
plt.figure(figsize=(10, 6))
initial_theta = 0.02
initial_c = 0.5
initial_phi = 0.01
fit = AmpCalCXFitter(backend_result1, xdata, qubits,
fit_p0=[initial_theta, initial_c],
fit_bounds=([-np.pi, -1],
[np.pi, 1]))
fit.plot(0, ax=plt.gca())
print("Rotation Error on CX: %f rads"%(fit.angle_err()[0]))
plt.show()
Rotation Error on CX: 0.150365 rads

Angle Error Characterization for CX Gates¶
Measure the angle error \(\theta\) in the CX gate, i.e. \(CR_{\cos(\theta)X+\sin(\theta)Y}(\pi/2)\) with respect to the angle of the single qubit gates.
[17]:
qubits = [0,2]
controls = [1,3]
circs, xdata = anglecal_cx_circuits(15, qubits, controls, angleerr=0.1)
The gate sequence to calibrate the CX angle for Q0-Q1 and Q3-Q4 in parallel:
[18]:
print(circs[2])
┌─────────┐┌──────────┐ ░ ┌───┐┌─────────┐┌───┐┌──────────┐ ░ ┌───┐»
q4_0: ┤ U2(0,0) ├┤ U1(-0.1) ├─░─┤ X ├┤ U1(0.1) ├┤ Y ├┤ U1(-0.1) ├─░─┤ X ├»
└──┬───┬──┘└──────────┘ ░ └─┬─┘└─────────┘└───┘└──────────┘ ░ └─┬─┘»
q4_1: ───┤ X ├────────────────░───■───────────────────────────────░───■──»
┌──┴───┴──┐┌──────────┐ ░ ┌───┐┌─────────┐┌───┐┌──────────┐ ░ ┌───┐»
q4_2: ┤ U2(0,0) ├┤ U1(-0.1) ├─░─┤ X ├┤ U1(0.1) ├┤ Y ├┤ U1(-0.1) ├─░─┤ X ├»
└──┬───┬──┘└──────────┘ ░ └─┬─┘└─────────┘└───┘└──────────┘ ░ └─┬─┘»
q4_3: ───┤ X ├────────────────░───■───────────────────────────────░───■──»
└───┘ ░ ░ »
c4: 2/═══════════════════════════════════════════════════════════════════»
»
« ┌─────────┐┌───┐┌──────────────┐┌─┐
«q4_0: ┤ U1(0.1) ├┤ Y ├┤ U2(-π/2,π/2) ├┤M├───
« └─────────┘└───┘└──────────────┘└╥┘
«q4_1: ─────────────────────────────────╫────
« ┌─────────┐┌───┐┌──────────────┐ ║ ┌─┐
«q4_2: ┤ U1(0.1) ├┤ Y ├┤ U2(-π/2,π/2) ├─╫─┤M├
« └─────────┘└───┘└──────────────┘ ║ └╥┘
«q4_3: ─────────────────────────────────╫──╫─
« ║ ║
«c4: 2/═════════════════════════════════╩══╩═
« 0 1
[19]:
# Set the simulator
# Run the simulator
backend = qiskit.Aer.get_backend('qasm_simulator')
shots = 1000
backend_result1 = qiskit.execute(circs, backend,
shots=shots).result()
[20]:
# Fit the data to an oscillation
plt.figure(figsize=(10, 6))
initial_theta = 0.02
initial_c = 0.5
initial_phi = 0.01
fit = AngleCalCXFitter(backend_result1, xdata, qubits,
fit_p0=[initial_theta, initial_c],
fit_bounds=([-np.pi, -1],
[np.pi, 1]))
fit.plot(0, ax=plt.gca())
print("Rotation Error on CX: %f rads"%(fit.angle_err()[0]))
plt.show()
Rotation Error on CX: 0.100132 rads

[21]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
/home/computertreker/git/qiskit/qiskit/.tox/docs/lib/python3.7/site-packages/qiskit/aqua/__init__.py:86: DeprecationWarning: The package qiskit.aqua is deprecated. It was moved/refactored to qiskit-terra For more information see <https://github.com/Qiskit/qiskit-aqua/blob/main/README.md#migration-guide>
warn_package('aqua', 'qiskit-terra')
Version Information
Qiskit Software | Version |
---|---|
qiskit-terra | 0.18.2 |
qiskit-aer | 0.8.2 |
qiskit-ignis | 0.6.0 |
qiskit-ibmq-provider | 0.16.0 |
qiskit-aqua | 0.9.5 |
qiskit | 0.29.1 |
qiskit-nature | 0.2.2 |
qiskit-finance | 0.3.0 |
qiskit-optimization | 0.2.3 |
qiskit-machine-learning | 0.2.1 |
System information | |
Python | 3.7.12 (default, Nov 22 2021, 14:57:10) [GCC 11.1.0] |
OS | Linux |
CPUs | 32 |
Memory (Gb) | 125.71650314331055 |
Tue Jan 04 11:08:35 2022 EST |
This code is a part of Qiskit
© Copyright IBM 2017, 2022.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.
[ ]: