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]:
%matplotlib inline
# 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: 20.602746 kHz
![../../_images/tutorials_noise_1_hamiltonian_and_gate_characterization_7_1.png](../../_images/tutorials_noise_1_hamiltonian_and_gate_characterization_7_1.png)
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: |0>──────────────────────────────────────────────────────────────────────»
»
q1_1: |0>──────────────────────────────────────────────────────────────────────»
┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐ »
q1_2: |0>┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├───»
└─────────┘ ░ └─────────┘ ░ └─────────┘ ░ └─────────┘ ░ └─────────┘ »
q1_3: |0>──────────────────────────────────────────────────────────────────────»
┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐┌─┐»
q1_4: |0>┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├┤M├»
└─────────┘ ░ └─────────┘ ░ └─────────┘ ░ └─────────┘ ░ └─────────┘└╥┘»
c1_0: 0 ════════════════════════════════════════════════════════════════════╩═»
»
c1_1: 0 ══════════════════════════════════════════════════════════════════════»
»
«
«q1_0: ───
«
«q1_1: ───
« ┌─┐
«q1_2: ┤M├
« └╥┘
«q1_3: ─╫─
« ║
«q1_4: ─╫─
« ║
«c1_0: ═╬═
« ║
«c1_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]:
%matplotlib inline
# 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.100412 rads
![../../_images/tutorials_noise_1_hamiltonian_and_gate_characterization_14_1.png](../../_images/tutorials_noise_1_hamiltonian_and_gate_characterization_14_1.png)
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: |0>┤ U2(0,0) ├┤ U1(-0.2) ├─░─┤ U2(-pi/2,pi/2) ├─░─┤ U2(-pi/2,pi/2) ├»
├─────────┤├──────────┤ ░ ├────────────────┤ ░ ├────────────────┤»
q2_1: |0>┤ U2(0,0) ├┤ U1(-0.2) ├─░─┤ U2(-pi/2,pi/2) ├─░─┤ U2(-pi/2,pi/2) ├»
└─────────┘└──────────┘ ░ └────────────────┘ ░ └────────────────┘»
c2_0: 0 ═════════════════════════════════════════════════════════════════»
»
c2_1: 0 ═════════════════════════════════════════════════════════════════»
»
« ┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐┌──────────┐ ░ ┌────────────────┐»
«q2_0: ┤ U1(0.2) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├┤ U1(-0.2) ├─░─┤ U2(-pi/2,pi/2) ├»
« ├─────────┤ ░ ├─────────┤ ░ ├─────────┤├──────────┤ ░ ├────────────────┤»
«q2_1: ┤ U1(0.2) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├┤ U1(-0.2) ├─░─┤ U2(-pi/2,pi/2) ├»
« └─────────┘ ░ └─────────┘ ░ └─────────┘└──────────┘ ░ └────────────────┘»
«c2_0: ════════════════════════════════════════════════════════════════════════»
« »
«c2_1: ════════════════════════════════════════════════════════════════════════»
« »
« ░ ┌────────────────┐┌─────────┐ ░ ┌─────────┐ ░ ┌─────────┐┌──────────┐»
«q2_0: ─░─┤ U2(-pi/2,pi/2) ├┤ U1(0.2) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├┤ U1(-0.1) ├»
« ░ ├────────────────┤├─────────┤ ░ ├─────────┤ ░ ├─────────┤├──────────┤»
«q2_1: ─░─┤ U2(-pi/2,pi/2) ├┤ U1(0.2) ├─░─┤ U2(0,0) ├─░─┤ U2(0,0) ├┤ U1(-0.1) ├»
« ░ └────────────────┘└─────────┘ ░ └─────────┘ ░ └─────────┘└──────────┘»
«c2_0: ════════════════════════════════════════════════════════════════════════»
« »
«c2_1: ════════════════════════════════════════════════════════════════════════»
« »
« ┌────────────────┐┌─┐
«q2_0: ┤ U2(-pi/2,pi/2) ├┤M├───
« ├────────────────┤└╥┘┌─┐
«q2_1: ┤ U2(-pi/2,pi/2) ├─╫─┤M├
« └────────────────┘ ║ └╥┘
«c2_0: ═══════════════════╩══╬═
« ║
«c2_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]:
%matplotlib inline
# 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.096159 rads
![../../_images/tutorials_noise_1_hamiltonian_and_gate_characterization_21_1.png](../../_images/tutorials_noise_1_hamiltonian_and_gate_characterization_21_1.png)
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: |0>┤ U2(-pi/2,pi/2) ├─░─┤ X ├─░─┤ X ├┤M├───
└─────┬───┬──────┘ ░ └─┬─┘ ░ └─┬─┘└╥┘
q3_1: |0>──────┤ X ├────────░───■───░───■───╫────
┌─────┴───┴──────┐ ░ ┌───┐ ░ ┌───┐ ║ ┌─┐
q3_2: |0>┤ U2(-pi/2,pi/2) ├─░─┤ X ├─░─┤ X ├─╫─┤M├
└─────┬───┬──────┘ ░ └─┬─┘ ░ └─┬─┘ ║ └╥┘
q3_3: |0>──────┤ X ├────────░───■───░───■───╫──╫─
└───┘ ░ ░ ║ ║
c3_0: 0 ═══════════════════════════════════╩══╬═
║
c3_1: 0 ══════════════════════════════════════╩═
[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]:
%matplotlib inline
# 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.149493 rads
![../../_images/tutorials_noise_1_hamiltonian_and_gate_characterization_28_1.png](../../_images/tutorials_noise_1_hamiltonian_and_gate_characterization_28_1.png)
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: |0>┤ U2(0,0) ├┤ U1(-0.1) ├─░─┤ X ├┤ U1(0.1) ├┤ Y ├┤ U1(-0.1) ├─░─┤ X ├»
└──┬───┬──┘└──────────┘ ░ └─┬─┘└─────────┘└───┘└──────────┘ ░ └─┬─┘»
q4_1: |0>───┤ X ├────────────────░───■───────────────────────────────░───■──»
┌──┴───┴──┐┌──────────┐ ░ ┌───┐┌─────────┐┌───┐┌──────────┐ ░ ┌───┐»
q4_2: |0>┤ U2(0,0) ├┤ U1(-0.1) ├─░─┤ X ├┤ U1(0.1) ├┤ Y ├┤ U1(-0.1) ├─░─┤ X ├»
└──┬───┬──┘└──────────┘ ░ └─┬─┘└─────────┘└───┘└──────────┘ ░ └─┬─┘»
q4_3: |0>───┤ X ├────────────────░───■───────────────────────────────░───■──»
└───┘ ░ ░ »
c4_0: 0 ═══════════════════════════════════════════════════════════════════»
»
c4_1: 0 ═══════════════════════════════════════════════════════════════════»
»
« ┌─────────┐┌───┐┌────────────────┐┌─┐
«q4_0: ┤ U1(0.1) ├┤ Y ├┤ U2(-pi/2,pi/2) ├┤M├───
« └─────────┘└───┘└────────────────┘└╥┘
«q4_1: ───────────────────────────────────╫────
« ┌─────────┐┌───┐┌────────────────┐ ║ ┌─┐
«q4_2: ┤ U1(0.1) ├┤ Y ├┤ U2(-pi/2,pi/2) ├─╫─┤M├
« └─────────┘└───┘└────────────────┘ ║ └╥┘
«q4_3: ───────────────────────────────────╫──╫─
« ║ ║
«c4_0: ═══════════════════════════════════╩══╬═
« ║
«c4_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]:
%matplotlib inline
# 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.099402 rads
![../../_images/tutorials_noise_1_hamiltonian_and_gate_characterization_35_1.png](../../_images/tutorials_noise_1_hamiltonian_and_gate_characterization_35_1.png)
[2]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
Qiskit | None |
Terra | 0.9.0 |
Aer | 0.3.0 |
Ignis | 0.2.0 |
Aqua | 0.5.3 |
IBM Q Provider | 0.3.2rc1 |
System information | |
Python | 3.7.4 (default, Aug 13 2019, 15:17:50) [Clang 4.0.1 (tags/RELEASE_401/final)] |
OS | Darwin |
CPUs | 4 |
Memory (Gb) | 16.0 |
Wed Aug 21 21:30:24 2019 EDT |
This code is a part of Qiskit
© Copyright IBM 2017, 2019.
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.
[ ]: