# Import Numpy for linear algebra
import numpy as np
Lecture 6: Qubits, Superposition, and Introduction to Qiskit
Author: Julie Butler
Date Created: August 24, 2024
Last Modified: August 26, 2024
Part 1: Defining Qubits in Python
# Define the two possible states of a single qubit
= np.array([1,0])
up = np.array([0,1]) down
# Define a down qubit
= down
qubit print("Example Qubit:")
print(qubit)
Example Qubit:
[0 1]
Part 2: Defining Quantum Gates in Python and Applying Them to Qubits
# Define the NOT gate, the Z gate, and the Hadamard gate
= np.array([[0,1],[1,0]])
X = np.array([[1,0],[0,-1]])
Z = (1/np.sqrt(2))*np.array([[1,1],[1,-1]]) H
# Check that each gate is unitary
print("X Unitary?")
print(X.T@X)
print("Z Unitary?")
print(Z.T@Z)
print("H Unitary?")
print(H.T@H)
X Unitary?
[[1 0]
[0 1]]
Z Unitary?
[[1 0]
[0 1]]
H Unitary?
[[ 1.00000000e+00 -2.23711432e-17]
[-2.23711432e-17 1.00000000e+00]]
# Apply the NOT gate to each single qubit
print("X and up")
print(X@up)
print("X and down")
print(X@down)
X and up
[0 1]
X and down
[1 0]
# Apply the Z gate to each single qubit
print("Z and up")
print(Z@up)
print("Z and down")
print(Z@down)
Z and up
[1 0]
Z and down
[ 0 -1]
# Apply the Hadamard gate to each single qubit
print("H and up")
print(H@up)
print("H and down")
print(H@down)
H and up
[0.70710678 0.70710678]
H and down
[ 0.70710678 -0.70710678]
Part 3: Defining a Superposition of Qubits in Python
# Define a qubit using our previous computational basis
# Remember that in Python, j takes the place of the imaginary
# number i
= 3*up + 4j*down
qubit # Print the qubit and its norm
# Note that the qubit is not normalized
print("Superposition Qubit and Magnitude")
print(qubit)
print(np.linalg.norm(qubit))
Superposition Qubit and Magnitude
[3.+0.j 0.+4.j]
5.0
# Normalize the qubit
= np.linalg.norm(qubit)
mag = qubit/mag
qubit
# Print the normalized qubit and its new magnitude
print("Normalized Superposition Qubit and Magnitude")
print(qubit)
print(np.linalg.norm(qubit))
Normalized Superposition Qubit and Magnitude
[0.6+0.j 0. +0.8j]
1.0
# Find the probability that upon measurement, an up result is
# obtained
= np.dot(np.conjugate(up),qubit)*\
prob_up
np.conjugate(np.dot(np.conjugate(up),qubit))# Find the probability that upon measurement, an down result is
# obtained
= np.dot(np.conjugate(down),qubit)*\
prob_down
np.conjugate(np.dot(np.conjugate(down),qubit))
# Print the probability of obtaining an up result, a down result,
# and ensure that the total probability is 1
print("Probability of obtaining up, probability of obtaining down, total probability")
print(prob_up, prob_down, prob_up+prob_down)
Probability of obtaining up, probability of obtaining down, total probability
(0.3600000000000001+0j) (0.6400000000000001+0j) (1.0000000000000002+0j)
# Define the first state of our new computational basis and
# ensure that it is normalized
= (up + down)/np.sqrt(2)
plus
print("+ qubit and magnitude")
print(plus)
print(np.linalg.norm(plus))
+ qubit and magnitude
[0.70710678 0.70710678]
0.9999999999999999
# Define the second state of our new computational basis and
# ensure that it is normalized
= (up - down)/np.sqrt(2)
minus
print("- qubit and magnitude")
print(minus)
print(np.linalg.norm(minus))
- qubit and magnitude
[ 0.70710678 -0.70710678]
0.9999999999999999
# Check that + and - can be built with up, down, and H
print(H@up == plus)
print(H@down == minus)
[ True True]
[ True True]
Part 5: Introduction to One Qubit Quantum Circuits with Qiskit
# Needed to set up the quantum circuit
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
# Needed to simulate running a quantum computer
from qiskit_aer import AerSimulator
# Neded to visualize the results of running a quantum computer
from qiskit.visualization import plot_histogram
# creates a Quantum register of 1 qubit
= QuantumRegister(1)
q # creates a classical register of 1 bit
= ClassicalRegister(1)
c # creates a quantum circuit that maps the result of a qubit
# to a classical bit
= QuantumCircuit(q, c)
qc # measure the current quantum circuit and draw a diagram
qc.measure(q, c)print(qc.draw())
# Run the quantum circuit on a simulated quantum computer 1024 times
= AerSimulator()
simulator = simulator.run(qc).result().get_counts()
results # Create a histogram of the results
plot_histogram(results)
┌─┐
q19: ┤M├
└╥┘
c18: 1/═╩═
0
# Create the same quantum circuit as before, but add a NOT gate before
# measuring
= QuantumRegister(1)
q = ClassicalRegister(1)
c = QuantumCircuit(q, c)
qc 0)
qc.x(
qc.measure(q, c)print(qc.draw())
= AerSimulator()
simulator = simulator.run(qc).result().get_counts()
results plot_histogram(results)
┌───┐┌─┐
q20: ┤ X ├┤M├
└───┘└╥┘
c19: 1/══════╩═
0
# Replace the NOT gate with a Z gate
= QuantumRegister(1)
q = ClassicalRegister(1)
c = QuantumCircuit(q, c)
qc 0)
qc.z(
qc.measure(q, c)print(qc.draw())
= AerSimulator()
simulator = simulator.run(qc).result().get_counts()
results plot_histogram(results)
┌───┐┌─┐
q21: ┤ Z ├┤M├
└───┘└╥┘
c20: 1/══════╩═
0
# Replace the Z gate with a Hadamard gate
# Create the plus state
= QuantumRegister(1)
q = ClassicalRegister(1)
c = QuantumCircuit(q, c)
qc 0)
qc.h(
qc.measure(q, c)print(qc.draw())
= AerSimulator()
simulator = simulator.run(qc).result().get_counts()
results plot_histogram(results)
┌───┐┌───┐┌─┐
q34: ┤ H ├┤ T ├┤M├
└───┘└───┘└╥┘
c33: 1/═══════════╩═
0
# Chain together a NOT gate and a Hadamard gate
# Creates the minus state
= QuantumRegister(1)
q = ClassicalRegister(1)
c = QuantumCircuit(q, c)
qc 0)
qc.x(0)
qc.h(
qc.measure(q, c)print(qc.draw())
= AerSimulator()
simulator = simulator.run(qc).result().get_counts()
results plot_histogram(results)
┌───┐┌───┐┌─┐
q12: ┤ X ├┤ H ├┤M├
└───┘└───┘└╥┘
c11: 1/═══════════╩═
0