How to use qiskit and a single qubit
I am going to use qiskit to study quantum algorithms in my own way. Since this is a record of my personal study, I may have left out a lot of explanations.
I am following the qiskit website.
github
- The file in jupyter notebook format is here
google colaboratory
- To run it in google colaboratory here
Author’s environment
!sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.6
BuildVersion: 18G103
Python -V
Python 3.8.5
Import the basic libraries and check their versions.
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
import matplotlib
import matplotlib.pyplot as plt
import scipy
import numpy as np
import pandas as pd
print('matplotlib version :', matplotlib.__version__)
print('scipy version :', scipy.__version__)
print('numpy version :', np.__version__)
print('pandas version :', pd.__version__)
matplotlib version : 3.3.2
scipy version : 1.5.2
numpy version : 1.19.2
pandas version : 1.1.3
import qiskit
import json
dict(qiskit.__qiskit_version__)
{'qiskit-terra': '0.17.4',
'qiskit-aer': '0.8.2',
'qiskit-ignis': '0.6.0',
'qiskit-ibmq-provider': '0.13.1',
'qiskit-aqua': '0.9.1',
'qiskit': '0.26.2',
'qiskit-nature': None,
'qiskit-finance': None,
'qiskit-optimization': None,
'qiskit-machine-learning': None}
Basics of Qiskit syntax
We will run through the basics by hand and learn the operations.
qc = QuantumCircuit()
qr = QuantumRegister(2, 'qreg')
qc.add_register(qr)
qc.qregs
[QuantumRegister(2, 'qreg')].
qc.draw(output='mpl')
# Apply an adamantine gate to the first qubit
qc.h(qr[0])
# Apply CNOT gate to qr0 and qr1
qc.cx(qr[0], qr[1]);
qc.draw(output='mpl')
# Prepare the backend simulator
vector_sim = Aer.get_backend('statevector_simulator')
# Prepare the backend
Aer.backends()
[AerSimulator('aer_simulator'),
AerSimulator('aer_simulator_statevector'),
AerSimulator('aer_simulator_density_matrix'),
AerSimulator('aer_simulator_stabilizer'),
AerSimulator('aer_simulator_matrix_product_state'),
AerSimulator('aer_simulator_extended_stabilizer'),
AerSimulator('aer_simulator_unitary'),
AerSimulator('aer_simulator_superop'),
QasmSimulator('qasm_simulator'),
StatevectorSimulator('statevector_simulator'),
UnitarySimulator('unitary_simulator'),
PulseSimulator('pulse_simulator')]
# Run the simulator
job = execute(qc, vector_sim)
job.result().get_statevector()
array([0.70710678+0.j, 0. +0.j, 0. +0.j, 0.70710678+0.j])
Now we can get the bell state.
Measure
To measure, we need a classical register as well as a qubit.
cr = ClassicalRegister(2,'creg')
qc.add_register(cr)
qc.measure(qr[0], cr[0])
qc.measure(qr[1], cr[1])
qc.draw(output='mpl')
Specify the number of measurements to get statistics based on the probability amplitude.
emulator = Aer.get_backend('qasm_simulator')
job = execute(qc, emulator, shots=8192)
hist = job.result().get_counts()
print(hist)
{'00': 4006, '11': 4186}
# Display the histogram
from qiskit.visualization import plot_histogram
plot_histogram(hist)
# Get the list of results
job = execute(qc, emulator, shots=10, memory=True)
samples = job.result().get_memory()
print(samples)
['11', '11', '11', '00', '00', '11', '11', '00', '11', '00', '00']
Notation for bits
Bits are labeled from right to left.
qubit = QuantumRegister(8)
bit = ClassicalRegister(8)
circuit = QuantumCircuit(qubit,bit)
circuit.x(qubit[7])
circuit.measure(qubit,bit) # this is a way to do all the qc.measure(qr8[j],cr8[j]) at once
execute(circuit, emulator, shots=8192).result().get_counts()
{'10000000': 8192}
This represents a binary representation like the following.
simplified notation
### A single quantum register only circuit with no classical registers
qc = QuantumCircuit(3)
# Can be manipulated by specifying a number
qc.h(1)
qc.draw(output='mpl')
# To define a classical register at the same time, set two arguments
qc = QuantumCircuit(2,1)
qc.h(0)
qc.cx(0,1)
qc.measure(1,0)
qc.draw(output='mpl')
1 qubit
from qiskit import QuantumCircuit, execute, Aer
from qiskit.visualization import plot_histogram, plot_bloch_vector
from math import sqrt, pi
backend = Aer.get_backend('statevector_simulator')
qc = QuantumCircuit(1)
qc.draw('mpl')
result = execute(qc, backend).result()
out_state = result.get_statevector()
plot_bloch_multivector(out_state)
## Display the state vector
out_state
array([0.+0.j, 1.+0.j])
counts = result.get_counts()
plot_histogram(counts)
Set the initial state
You can set the initial state with initial_state
qc = QuantumCircuit(1)
initial_state = [0,1].
qc.initialize(initial_state, 0)
qc.draw('mpl')
result = execute(qc,backend).result()
out_state = result.get_statevector()
plot_bloch_multivector(out_state)
out_state
array([0.+0.j, 1.+0.j])
counts = result.get_counts()
plot_histogram(counts)
Setting the initial state 2
You can set the initial state with initial_state
qc = QuantumCircuit(1)
initial_state = [1/sqrt(2), complex(0, 1/sqrt(2))]]
qc.initialize(initial_state, 0)
qc.draw('mpl')
result = execute(qc,backend).result()
out_state = result.get_statevector()
plot_bloch_multivector(out_state)
out_state
array([0.70710678+0.j , 0. +0.70710678j])
counts = result.get_counts()
plot_histogram(counts)
For now, we can display the quantum circuit, use the Bloch sphere, display the state vector, and make measurements.
Manipulating a single qubit
A single qubit can be represented as follows. where and are real numbers.
Gates in classical computers
These are typical logic circuits, except for the NOT circuit, which is a two-input, one-output circuit. We will implement these equivalent circuits in our quantum circuit.
AND circuit
OR circuit
NOT circuit
NAND circuit
NOR circuit
XOR circuit
Pauli Gate
The Pauli gate is the equivalent of the classical gate NOT circuit, except that there is a NOT for each of the X, Y, and Z axes. There is a NOT for each of the X, Y, and Z axes, but the bit is rotated by for each axis.
X gate
Y-gate
Z-gate
Adamar gate
In the xz-plane, the gate will be rotated by around the line.
Let’s look at the result with the Bloch vector.
qc = QuantumCircuit(1)
qc.h(0)
out = execute(qc,backend).result().get_statevector()
plot_bloch_multivector(out)
The adamantine gates applied to and are written as and , respectively. These are the orthonormal bases, called Y-bases, respectively.
R_{\phi}Gate
The gate is a gate that rotates around the Z axis by . In matrix form, it looks like this.
Let us apply the above to the qubit of
So, we can see that it is indeed rotated by with respect to the Z axis.
Let’s see it in action.
From the following initial state, let’s act on each gate operator and see how the Bloch vector changes.
Initial state
qc = QuantumCircuit(1)
initial_state = [1/sqrt(2), complex(0, 1/sqrt(2))]]
qc.initialize(initial_state, 0)
out = execute(qc,backend).result().get_statevector()
plot_bloch_multivector(out)
X-gates
qc = QuantumCircuit(1)
initial_state = [1/sqrt(2), complex(0, 1/sqrt(2))].
qc.initialize(initial_state, 0)
qc.x(0)
out = execute(qc,backend).result().get_statevector()
plot_bloch_multivector(out)
Y-gate
qc = QuantumCircuit(1)
initial_state = [1/sqrt(2), complex(0, 1/sqrt(2))].
qc.initialize(initial_state, 0)
qc.y(0)
out = execute(qc,backend).result().get_statevector()
plot_bloch_multivector(out)
There is no change for the Y axis. It is an eigenvector.
Z-gate
qc = QuantumCircuit(1)
initial_state = [1/sqrt(2), complex(0, 1/sqrt(2))].
qc.initialize(initial_state, 0)
qc.z(0)
out = execute(qc,backend).result().get_statevector()
plot_bloch_multivector(out)
H-gate
qc = QuantumCircuit(1)
initial_state = [1/sqrt(2), complex(0, 1/sqrt(2))].
qc.initialize(initial_state, 0)
qc.h(0)
out = execute(qc,backend).result().get_statevector()
plot_bloch_multivector(out)
R_{\phi}gate
qc = QuantumCircuit(1)
initial_state = [1/sqrt(2), complex(0, 1/sqrt(2))]]
qc.initialize(initial_state, 0)
qc.rz(pi/4, 0)
out = execute(qc,backend).result().get_statevector()
plot_bloch_multivector(out)
You can see that it has been properly rotated on the Z axis by .
Summary
For now, I’ve tried to understand the basic usage and manipulation of one qubit using qiskit. Well, it is very useful. It’s also easy to understand visually. I’m going to study it further to deepen my understanding.