✅ Put your name here

Pre-Class Assignment 23: Background for Quantum Computing

This notebook starts a unit introducing a different model of computation, a model that plays by the rules of quantum physics rather than classical physics.

I hope you're not intimidated! Unfortunately, quantum physics gets a bad rap of being inherently confusing. This is not at all the case! Quantum physics sounds strange due to some weird consequences that we'll see shortly, but it's actually really easy to do, involving some simple mathematics that you have probably seen before. And it doesn't require you to know any classical physics! (If you do, you'll see why quantum physics is a strange theory.)

Quantum computing is a relatively new field that started in the 1980s and 1990s. Due to recent advances in experimental physics and engineering, we have today some of the world's first quantum computers, and the field has received a lot of attention recently. At the end of this unit, you'll have the opportunity to program a quantum computer!

Itinerary for Quantum Computing Unit

Assignment Topic Description
Pre Class 23 Background for Quantum Computing How Computers Store Information
In Class 23 Classsical and Quantum Bits Information in Quantum States
Pre Class 24 Software for Quantum Computing High Level Software and the Circuit Model
In Class 24 Programming Quantum Computers Manipulating Quantum Bits to Perform Useful Computations

Before you start...

Take ten seconds to answer these survey questions:

In [ ]:
from IPython.display import HTML

Learning Goals for Today's Pre-Class Assignment

By the end of today's pre-class assignment, you should be able to:

  1. Describe how computers store information using binary digits.
  2. State the fundamental difference between classical and quantum computers in terms of how they store information.
  3. Review/learn complex numbers, probability distributions, and vectors to more deeply understand quantum binary digits.

How Computers Store Information

Watch the following video to learn about binary digits, or bits, the fundamental unit of information for all data in a computer.

In [ ]:
"""How computers work: binary & data."""
from IPython.display import YouTubeVideo
YouTubeVideo("USCBCmwMCDA", width=640, height=360)

Question: What are the possible values of a bit?

Answer: Erase the contents of this cell and put your answer here!

The video mentioned that 1001 in binary is equal to 9 in decimal. You should understand how to convert from binary to decimal ($1001$ means $1 \cdot 2^3 + 0 \cdot 2^2 + 0 \cdot 2^1 + 1 \cdot 2^0 = 9$). There's a cool trick for doing this in Python, shown below.

In [ ]:
"""Cool trick! Converting from binary to decimal."""
int("1001", 2)

Here, the first argument to int is what gets converted to a number. The second argument to int represents the base of the number system to use (binary = base 2). You can change the first argument to get different resulting numbers and test your understanding of binary.

Question: All data on a computer--including text, images, and sound--is stored in bits. Pick one of these (text, images, or sound) and explain how bits are used to represent this information.

Answer: Erase the contents of this cell and put your answer here!

Question: What do we use to physically represent bits in computers?

Answer: Erase the contents of this cell and put your answer here!

How Quantum Computers Store Information

Recall the last statement from the above video on bits and data:

"If you want to understand how computers work on the inside, it all comes down to these simple ones and zeros and the electrical signals in the circuits behind them."

In the same way, if you want to understand how quantum computers work, it all comes down to how information is stored.

Quantum computers store information in quantum bits, or qubits (pronounced "CUE bits") for short.

Watch the following short video to get introduced to qubits.

In [ ]:
"""Introduction to qubits."""
from IPython.display import YouTubeVideo

Understanding Qubits: Three Key Concepts

To understand a qubit, we only have to understand three concepts.

  1. Complex numbers.
  2. Probability.
  3. Vectors.

Watch the next three videos to see each concept in turn, and complete the exercises to test your understanding.

The goal of these concepts is to understand a qubit at a deeper level. Each may seem unrelated, but everything will tie together at the end of the notebook.

In [ ]:
"""Imports for the notebook."""
import numpy as np
import matplotlib.pyplot as plt

Concept #1: Complex Numbers

Watch the following video on complex numbers.

In [ ]:
"""Complex numbers."""
from IPython.display import YouTubeVideo

Video Recap

  • The imaginary unit, which we'll denote $i$, is defined by the property that $i^2 = -1$. (Note: In Python, j is used for the imaginary unit.)

  • A complex number has the form

\begin{equation} \alpha = a + b i \end{equation}

where $a$ and $b$ are real numbers. (The symbol $\alpha$ is the Greek letter alpha. We'll use Greek letters for complex numbers to not confuse them with real numbers.)

  • The addition of two complex numbers is defined by
\begin{equation} \alpha + \beta = (a + b i) + (c + d i) := (a + c) + (b + d)i . \end{equation}
  • We define the complex conjugate of a complex number $\alpha = a + bi$ to be
\begin{equation} \alpha^* := a - bi . \end{equation}

(That is, we flip the sign of the imaginary part.)

  • The modulus squared of $\alpha$ is defined to be the product of itself with its complex conjugate:
\begin{equation} |\alpha|^2 := \alpha^* \alpha = a^2 + b^2 \end{equation}

As you might guess, the modulus is just the square root of the modulus squared.

Exercise: Working with Complex Numbers

Do this: Run the cell below to see how to perform some operations on complex numbers in Python.

In [ ]:
"""Working with complex numbers in Python."""
# define two complex numbers
alpha = 1 + 2j # note: j is used for the imaginary unit in Python
beta = 3 - 4j
print("alpha =", alpha)
print("beta =", beta)

# print out the type of alpha
print("\ntype(alpha) =", type(alpha))

# print out the real and imaginary part of alpha
print("\nThe real part of alpha is", alpha.real)
print("The imaginary part of alpha is", alpha.imag)

# print out the sum of alpha and beta
print("\nalpha + beta =", alpha + beta)

# print out the complex conjugate of alpha and beta
print("\nalpha* =", alpha.conjugate())
print("beta* =", beta.conjugate())

Do this: Write a function called modulus_squared that inputs a complex number $\alpha$ and returns its modulus squared $|\alpha|^2 = \alpha^* \alpha$.

Important: Make sure your function returns a float, not a complex number. You can do this by using the real part of the modulus squared.

In [ ]:
"""Put code for implementing your function here!"""
def modulus_squared(alpha):
In [ ]:
def modulus_squared(alpha):
    # one way
    return (alpha.conjugate() * alpha).real

    # another way
    return abs(alpha)**2

The next cell contains test cases for your function. If your function is correct, this cell will execute without error. (Note: assert EXPRESSION throws an error if the EXPRESSION is False. Otherwise, nothing happens. For this reason, it's often used to test code.)

In [ ]:
"""Test cases: run this cell to ensure your function is correct."""
assert np.isclose(modulus_squared(3+4j), 25.0)
assert np.isclose(modulus_squared(1), 1.0)
assert np.isclose(modulus_squared(1j), 1.0)
assert np.isclose(modulus_squared(-3 - 4j), 25.0)

Concept #2: Probability

Watch the following video on probability distributions.

In [ ]:
from IPython.display import YouTubeVideo

Video Recap

A probability distribution is a list of numbers $p_1, ..., p_n$ that satisfy the following conditions:

  • Each probability is non-negative.
\begin{equation} p_i \ge 0 \end{equation}
  • The sum over all probabilites is equal to one.
\begin{equation} \sum_{i = 1}^{n} p_i = 1 . \end{equation}

Exercise: Working with Probabilities

Question: Could the following list of numbers be a probability distribution? Why or why not?

In [ ]:
"""Potential probability distribution."""
distribution = np.array([0.1, 0.3, 0.2, 0.2, 0.1, 0.2])

Answer: Erase the contents of this cell and put your answer here!

Question: Write a function, called is_valid, that inputs a numpy array and returns True if the list of numbers defines a valid probability distribution, else returns False.

In [ ]:
"""Put code for implementing your function here!"""
def is_valid(array):
In [ ]:
def is_valid(array):
    if any(array < 0) or sum(array) != 1:
        return False
    return True

Run the next cell to test your function. If your function is correct, no errors should be thrown.

In [ ]:
"""Run this cell to test your function."""
assert is_valid(np.array([0.5, 0.3, 0.2]))
assert not is_valid(np.array([0.2, 0.4, 0.2]))
assert not is_valid(np.array([1.0, -1.0, 1.0]))

Concept #3: Linear Algebra & Vectors

Watch the following video on vectors.

In [ ]:
"""Linear algebra and vectors."""
from IPython.display import YouTubeVideo

Video Recap

  • A vector is the formal mathematical term for a list of numbers. (You may understand vectors as objects with size and direction, which is an equally valid definition. For the purposes of quantum computing, it's more convenient to think of vectors as just lists of numbers.)

  • An example of a vector is

\begin{equation} |0\rangle := \left[ \begin{matrix} 1 \\ 0 \\ \end{matrix} \right], \end{equation}

and another example of a vector is

\begin{equation} |1\rangle := \left[ \begin{matrix} 0 \\ 1 \\ \end{matrix} \right] \end{equation}
  • The angled-bracket notation $|\rangle$ denotes that an object is a vector. The number inside of the angled brackets is a label for which vector it is. (You'll see why we label the vectors 0 and 1 in the next In Class Assignment. In principle, though, any symbol could be used to label the vector.)

  • Vector addition is defined component-wise. For example,

\begin{equation} |0\rangle + |1\rangle = \left[ \begin{matrix} 1 \\ 0 \\ \end{matrix} \right] + \left[ \begin{matrix} 0 \\ 1 \\ \end{matrix} \right] = \left[ \begin{matrix} 1 + 0 \\ 0 + 1 \\ \end{matrix} \right] = \left[ \begin{matrix} 1 \\ 1 \\ \end{matrix} \right] \end{equation}
  • We can also take scalar multiples of vectors, for example
\begin{equation} \alpha |0\rangle = \alpha \left[ \begin{matrix} 1 \\ 0 \\ \end{matrix} \right] = \left[ \begin{matrix} \alpha \cdot 1 \\ \alpha \cdot 0 \\ \end{matrix} \right] = \left[ \begin{matrix} \alpha \\ 0 \\ \end{matrix} \right]. \end{equation}

In general, we multiply each component of the vector by the number $\alpha$.

  • This allows us to write superpositions, which are scalar multiples and sums of vectors. That is, equations of the form
\begin{equation} \alpha |0\rangle + \beta |1\rangle \end{equation}
  • In Python, Numpy arrays handle vector operations for us.

Exercise: Working with Vectors

The following cell shows how we use Numpy arrays to work with vectors in Python.

In [ ]:
"""Using numpy to perform vector operations."""
# the |0> == zero vector and |1> == one vector from above
zero = np.array([1, 0], dtype=np.complex64)
one = np.array([0, 1], dtype=np.complex64)

# print out the vectors
print("|0> =", zero)
print("|1> =", one)

# some complex numbers
alpha = 0.5 + 0.5j
beta = 1 - 2j

Do this: Run the following code cell to see how Numpy arrays handle vector operations for us. Complete the last portion, labeled TODO.

In [ ]:
"""Run this cell. Complete the last portion."""
# print out the sum of zero and one
print("|0> + |1> =", zero + one)

# compute and print out alpha * |0>
print("alpha |0> =", alpha * zero)

# compute and print out beta * |1>
print("beta |1>> =", beta * one)

# TODO: print out the superposition alpha |0> + beta |1>
In [ ]:
# TODO: print out the superposition alpha |0> + beta |1>
print("alpha |0> + beta |1> =", alpha * zero + beta * one)

Question: Is this output of the cell above what you expect based on the definition of vector addition and scalar multiples of vectors?

Answer: Erase the contents of this cell and put your answer here!

Tying Together the Concepts

When we introduced a qubit, we said it could be the state $|0\rangle$, $|1\rangle$, or superpositions of $|0\rangle$ and $|1\rangle$. We can now fully understand this statement.

A superposition is a sum of scalar multiples of vectors. So, the most general state of a qubit can be written

\begin{equation} |\psi\rangle = \alpha |0\rangle + \beta |1\rangle = \left[ \begin{matrix} \alpha \\ \beta \\ \end{matrix} \right] \end{equation}

where $|\alpha|^2 + |\beta|^2 = 1$.

That is, a qubit is a vector of complex numbers. These complex numbers determine the probability of measuring a particular state, as we'll discuss in upcoming assignments.

Unlike bits, which are only 0 or 1, qubits can exist in superposition states. This is the first idea that there is "more" processing power with qubits (quantum computers) than with bits (classical computers).

However, this isn't the entire story. Teaser of what's to come: When we measure qubits, we record either 0 with a probability that depends on $\alpha$, the coefficient of $|0\rangle$. In particular,

\begin{equation} p(\text{measuring 0}) = |\alpha|^2 \end{equation}

Similarly for measuring 1:

\begin{equation} p(\text{measuring 1}) = |\beta|^2 \end{equation}

This is why we requre $|\alpha|^2 + |\beta|^2 = 1$ for qubits. The next in class assignment will explore measurements further and give you more practice working with qubits.

(Brief remark for those interested: A qubit is an example of a wavefunction in quantum physics. A wavefunction is a mathematical description of a quantum system. In the discrete case (like a qubit), it consists of a vector of complex numbers which determine the probability of measuring particular states.)

Assignment Wrapup


In [ ]:
from IPython.display import HTML

Congrats, You're Finished!

Now, you just need to submit this assignment by uploading it to the course Desire2Learn web page for today's submission folder. (Don't forget to add your name in the first cell.)

© Copyright 2019, Michigan State University Board of Trustees.