from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit.tools.visualization import plot_histogram, circuit_drawer, matplotlib_circuit_drawer
from qiskit import available_backends, execute, register
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# define function to draw circuits
# drawer = lambda qc: circuit_drawer(qc, basis='u1,u2,u3,id,cx,h,x,ry')
drawer = lambda qc: matplotlib_circuit_drawer(qc, basis='u1,u2,u3,id,cx,h,x,ry')
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
# See a list of available local simulators
print('local backends: ', available_backends({'local': True}))
# select a backend for the tutorial
backend = 'local_qasm_simulator'
Before we can work with qubits and quantum gates, we first have to initialize our quantum circuit with the corresponding quantum and classical registers.
# create a quantum and classical registers
q = QuantumRegister(2)
c = ClassicalRegister(2)
# create a quantum circuit
qc = QuantumCircuit(q, c)
The X gate is the quantum equivalent to the classical NOT gate and, thus, flips $|0\rangle$ to $|1\rangle$ and vice versa.
In matrix form the quantum gate reads
$\left(\begin{array}{cc} 0 & 1 \\ 1 & 0 \end{array} \right)$.
# create a quantum and classical registers
q = QuantumRegister(2)
c = ClassicalRegister(2)
# create a quantum circuit
qc = QuantumCircuit(q, c)
# add a X gate on qubit, flipping it from |0> to |1>
qc.x(q[0])
# qc.x(q[1])
# measure qubit
qc.measure(q, c);
# plot the circuit
drawer(qc)
# compile and run the quantum circuit on the local simulator
number_of_shots = 1
job_sim = execute(qc, backend, shots=number_of_shots)
sim_results = job_sim.result()
print("simulation:", sim_results)
print("counts: ", sim_results.get_counts())
The H gate reads $\frac{1}{\sqrt{2}}\left(\begin{array}{cc} 1 & 1 \\ 1 & -1 \end{array} \right)$. Thus, it maps $|0\rangle$ to $\frac{1}{\sqrt{2}}(|0\rangle + |1\rangle) =: |+\rangle$, i.e., into the equal superposition state.
# create a quantum and classical registers
q = QuantumRegister(1)
c = ClassicalRegister(1)
# create a quantum circuit
qc = QuantumCircuit(q, c)
# add a H gate on qubit 0, flipping the qubit from |0> to |1>
qc.h(q[0])
# measure qubit
qc.measure(q, c)
# plot the circuit
drawer(qc)
# compile and run the quantum circuit on the local simulator
number_of_shots = 1
job_sim = execute(qc, backend, shots=number_of_shots)
sim_results = job_sim.result()
print("simulation:", sim_results)
print("counts: ", sim_results.get_counts())
# plot results
plot_histogram(sim_results.get_counts())
A Y-rotation of angle $\theta$, denoted $R_y(\theta)$, acts like
$e^{-i\frac{\theta}{2}Y} = \left(\begin{array}{cc} \cos(\theta/2) & -\sin(\theta/2) \\ \sin(\theta/2) & \cos(\theta/2) \end{array} \right)$.
It rotates a single qubit state around the Y-axis of the Bloch sphere.
When applied to $|0\rangle$, the probability of measuring $|1\rangle$ equals $\sin^2(\theta/2)$.
Exercise:
Find $\theta$ such that $\mathbb{P}[|1\rangle] = 75\%$ and verify it by executing the circuit.
# create a quantum and classical registers
q = QuantumRegister(1)
c = ClassicalRegister(1)
# create a quantum circuit
qc = QuantumCircuit(q, c)
# add a X gate on qubit 0, flipping the qubit from |0> to |1>
theta = np.pi/2
qc.ry(theta, q[0])
# measure qubit
qc.measure(q, c)
# plot the circuit
drawer(qc)
# compile and run the quantum circuit on the local simulator
number_of_shots = 1024
job_sim = execute(qc, backend, shots=number_of_shots)
sim_results = job_sim.result()
print("simulation:", sim_results)
print("counts: ", sim_results.get_counts())
# plot results
plot_histogram(sim_results.get_counts())
A controlled X (CX) gate acts on two qubits like $\left(\begin{array}{cccc} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \end{array} \right)$.
# create a quantum and classical registers
q = QuantumRegister(2)
c = ClassicalRegister(2)
# create a quantum circuit
qc = QuantumCircuit(q, c)
# set initial state
qc.x(q[0]) # flips q[0] from |0> to |1>
# qc.x(q[1]) # flips q[1] from |0> to |1>
# apply CX gate with control q[0] and target q[1]
qc.cx(q[0], q[1])
# measure qubit
qc.measure(q, c)
# plot the circuit
drawer(qc)
# compile and run the quantum circuit on the local simulator
number_of_shots = 1
job_sim = execute(qc, backend, shots=number_of_shots)
sim_results = job_sim.result()
print("simulation:", sim_results)
print("counts: ", sim_results.get_counts())
# plot results
plot_histogram(sim_results.get_counts())
A Bell state is a fully entangled state of two qubits that has no classical counter part.
Given an initial two qubit system $|00\rangle$, we create a Bell state by applying an H gate to the first qubit and, then, a CX gate where the first qubit acts as control and the second qubit as target state.
# create a quantum and classical registers
q = QuantumRegister(2)
c = ClassicalRegister(2)
# create a quantum circuit
qc = QuantumCircuit(q, c)
# add a H gate on qubit 0, putting this qubit in superposition
qc.h(q[0])
# add a CX (CNOT) gate on control qubit 0 and target qubit 1
qc.cx(q[0], q[1])
# add a measure gate to see the state.
qc.measure(q, c)
# plot the circuit
drawer(qc)
# compile and run the quantum circuit on the local simulator
number_of_shots = 1024
job_sim = execute(qc, backend, shots=number_of_shots)
sim_results = job_sim.result()
print("simulation:", sim_results)
print("counts: ", sim_results.get_counts())
# plot results
plot_histogram(sim_results.get_counts())
Exercise:
Prepare the following state: $\frac{1}{\sqrt{2}}(|01\rangle + |10\rangle)$ by designing a quantum circuit that is similar to the Bell state construction.
q = QuantumRegister(2)
c = ClassicalRegister(2)
qc = QuantumCircuit(q, c)
# Write your circuit here:
#
#
#
qc.measure(q, c)
drawer(qc)
# compile and run the quantum circuit on the local simulator
job_sim = execute(qc, backend, shots=1024)
sim_results = job_sim.result()
print("simulation:", sim_results)
print("counts: ", sim_results.get_counts())
# plot results
plot_histogram(sim_results.get_counts())