{
"cells": [
{
"cell_type": "markdown",
"id": "85be67db",
"metadata": {},
"source": [
"# Quantum circuits and simulation of noisy algorithms\n",
"\n",
"Welcome to this hands-on session. The session is build around interactive Notebooks, that include code, explanations and tasks. Please run the code cells on your computer and follow the instructions of the tasks to deepen your learning. \n",
"\n",
"Jami Rönkkö, IQM Quantum Computers, email: jami@meetiqm.com"
]
},
{
"cell_type": "markdown",
"id": "7fafd7c7",
"metadata": {},
"source": [
"# Basics of quantum circuits: gates and superposition\n",
"\n",
"In this notebook you will learn:\n",
"- how to create and execute quantum logic circuits\n",
"- the concepts of superposition, phase and entanglement\n",
"\n",
"The most commonplace way of expressing quantum algorithms is by using **quantum logic circuits**. They are analogous to the (classical) logic circuits that describe how computers process binary information. \n",
"\n",
"Main difference between classical and quantum logic circuits is the different set of *logical operations* or **gates** they can include. Classical logic circuits include gates such as `NOT`, `OR` and `NAND`. This notebook introduces basic quantum gates X, H, P($\\phi$) and CNOT.\n",
"\n",
"In these Notebooks, we use IBM's open source quantum computing package `qiskit` for creating and executing circuits."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4d1ce9e7",
"metadata": {},
"outputs": [],
"source": [
"# Import everything from qiskit \n",
"from qiskit import *"
]
},
{
"cell_type": "markdown",
"id": "c89253b9",
"metadata": {},
"source": [
"## TASK 1

\n",
"> Read and run the two code snippets below to get an idea of the basic workflow of creating and executing circuits on qiskit."
]
},
{
"cell_type": "markdown",
"id": "14cdaaca",
"metadata": {},
"source": [
"### Creating circuit"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "71071014",
"metadata": {},
"outputs": [],
"source": [
"# Create a quantum circuit\n",
"circuit = QuantumCircuit(1) # The input defines number of qubits in the circuit\n",
"\n",
"# Add X gate to the first qubit of the circuit\n",
"circuit.x(0) \n",
"\n",
"# Visualise the circuit\n",
"circuit.draw(output='mpl') # The 'mpl' output looks better, but might require you to install some packages "
]
},
{
"cell_type": "markdown",
"id": "858dfe04",
"metadata": {},
"source": [
"Our circuit has one qubit and only one gate applied to it. Note that qubits start from 0 state. (or ∣0⟩ in quantum convention). Next we execute this circuit with a simulator backend."
]
},
{
"cell_type": "markdown",
"id": "8c7e1c2c",
"metadata": {},
"source": [
"### State vector simulation "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "600ae7ee",
"metadata": {},
"outputs": [],
"source": [
"# Create a simulator from qiskit's Aer -simulator package \n",
"simulator = Aer.get_backend(\"statevector_simulator\") # We choose the statevector_simulator\n",
"\n",
"# To see all available simulators in Aer, write:\n",
"#Aer.backends()\n",
"\n",
"# Execute the circuit on simulator and extract the result\n",
"result = execute(circuit, backend = simulator).result()\n",
"\n",
"# Get the statevector describing qubit's state\n",
"statevector = result.get_statevector()\n",
"\n",
"statevector.draw(\"latex\")"
]
},
{
"cell_type": "markdown",
"id": "d4bf6970",
"metadata": {},
"source": [
"We see that the X gate flipped the qubit from ∣0⟩ to ∣1⟩ state; meaning that it is the `NOT` gate from classical logic circuits. Let us now look at a gate that actually utilises the difference between bits and qubits."
]
},
{
"cell_type": "markdown",
"id": "770d14b0",
"metadata": {},
"source": [
"## TASK 2

\n",
"> Change the `x` gate to `h`. in the above snippet and rerun the cells. The H gate i.e. Hadamard gate is the usual gate for creating superpositions. Looking at the statevector now, is the qubit in state ∣0⟩ or ∣1⟩? "
]
},
{
"cell_type": "markdown",
"id": "ed66c444",
"metadata": {},
"source": [
"### Bloch sphere for visualising qubit state\n",
"As we saw in Task 2, the qubit is not restricted to being either ∣0⟩ or ∣1⟩ like a classical bit. Instead, the possible states of a qubit can be visualised as a surface of a ball. In this sphere, called **the Bloch sphere**, the North-pole corresponds to state ∣0⟩ and South-pole corresponds to ∣1⟩.\n",
"\n",
"All other points on the sphere are possible superpositions in which the qubit can be. The factors, like $\\sqrt 2/2$, in front of the qubit basis states are called **probability amplitudes**. They describe the location of the qubit's state on the Bloch sphere.\n",
"\n",
"In the snippet below, we will visualize the state resulting from Hadamard gate (Task 2): \n",
"\n",
"$$\n",
"\\frac{\\sqrt 2}{2}|0\\hspace{-0.1cm}> + \\frac{\\sqrt 2}{2}|1\\hspace{-0.1cm}>\n",
"$$\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "95a38bbe",
"metadata": {},
"outputs": [],
"source": [
"# Import and use the Bloch sphere visualisation tool\n",
"from qiskit.visualization import plot_bloch_multivector\n",
"\n",
"plot_bloch_multivector(statevector)"
]
},
{
"cell_type": "markdown",
"id": "3d6928e9",
"metadata": {},
"source": [
"We see that the qubit's state is halfway between ∣0⟩ and ∣1⟩. Which makes sense, since the basis states have equal probability amplitudes in our superposition state."
]
},
{
"cell_type": "markdown",
"id": "8f6b6909",
"metadata": {},
"source": [
"## TASK 3

\n",
"> Try changing the $\\phi$ parameter of the P($\\phi$) gate below and plot the Bloch sphere representation of the qubit's statevector for different values of $\\phi$. What does the this *phase gate* do?\n",
">\n",
"> Apply phase gate with such an angle, that the qubit state points along the Y-axis on the Bloch sphere. What is the probability amplitude of the ∣1⟩ state now?\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "67ea95cf",
"metadata": {},
"outputs": [],
"source": [
"from numpy import pi\n",
"\n",
"# Create a quantum circuit\n",
"circuit = QuantumCircuit(1) \n",
"\n",
"# Add Hadamard and then Phase or p gate to the first qubit of the circuit\n",
"circuit.h(0)\n",
"\n",
"phi = pi # Try different values\n",
"circuit.p(phi, 0) # First argument is the parameter phi and second is the qubit we act on \n",
"\n",
"# Visualise the circuit\n",
"circuit.draw(output='mpl')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bfd00bbb",
"metadata": {},
"outputs": [],
"source": [
"# Create a simulator from qiskit's Aer -simulator package \n",
"simulator = Aer.get_backend(\"statevector_simulator\")\n",
"\n",
"# Execute the circuit on simulator and get the result\n",
"result = execute(circuit, backend = simulator).result()\n",
"\n",
"# Extract the result from the executed job and look at the statevector\n",
"statevector = result.get_statevector()\n",
"statevector.draw(\"latex\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "82278143",
"metadata": {},
"outputs": [],
"source": [
"plot_bloch_multivector(statevector)"
]
},
{
"cell_type": "markdown",
"id": "fc233514",
"metadata": {},
"source": [
"We see that the phase gate rotates qubit state around the vertical Z-axis of the Bloch sphere. The qubit remains to be in 50/50 superposition of ∣0⟩ and ∣1⟩, but the argument or *phase* of ∣1⟩ state's complex probability amplitude changes. (Think of the X-Y plane of Bloch sphere as the complex plane: https://en.wikipedia.org/wiki/Argument_(complex_analysis)).\n",
"\n",
"This feature of superposition enables the smart manipulation of states that we see in most quantum algorithms: \n",
"- States with opposite phases will cancel each other while states with the same phase will strenghten each other in **interference** (think of waves).\n",
"\n",
"- One should build a circuit such that the state(s) whose probability amplitudes are strenghtened by interference are the one(s) encoding the correct answer, while probability amplitudes of unwanted states are weakened."
]
},
{
"cell_type": "markdown",
"id": "ac7f1ef1",
"metadata": {},
"source": [
"## Takeaway\n",
"\n",
"- Qubits can be in a superposition of ∣0⟩ and ∣1⟩ states\n",
"- Quantum gates change the state(vector) of qubits\n",
"- Sequence of gates defines a quantum circuit that describes an algorithm\n",
"\n",
"Next notebook introduces two-qubit gates, *entanglement* and the concept of measuring qubits."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.13"
},
"vscode": {
"interpreter": {
"hash": "36cf16204b8548560b1c020c4e8fb5b57f0e4c58016f52f2d4be01e192833930"
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}