Learn Quantum Computing with Qiskit: Multiple Qubits and Entanglement

Lecture 7: Multiple Qubits and Entanglement

Monit Sharma
11 min readJul 18, 2023

We’ve seen some interesting effects with isolated qubits and single qubit gates, but the true power of quantum computing comes from interactions between qubits. In this section we will introduce multiple qubit gates and explore the interesting behaviors of multi-qubit systems.

%pip install qiskit
%pip install pylatexenc

Prerequisite material

Check the Medium articles for it:Introduction to Quantum Computing and Qiskit

Introduction

Typically, the gates that can be directly implemented in hardware will act only on one or two qubits. 🧑‍💻 In our circuits, we may want to use complex gates that act on a great number of qubits. Fortunately, this will not be a problem. 🙌 With the one and two qubit gates given to us by the hardware, it is possible to build any other gate. 🔧💡

In this series, we will first introduce the most basic multi-qubit gates, as well as the mathematics used to describe and analyze them. 🔢🔬 Then we’ll show how to prove that these gates can be used to create any possible quantum algorithm. 📚✨ The chapter then concludes by looking at small-scale uses of quantum gates. For example, we see how to build three-qubit gates like the Toffoli from single- and two-qubit operations. 🧩🔗

This is a Toffoli gate with 3 qubits.

Single qubits are intriguing, but on their own, they don’t provide any computational advantage. 😕 We will now explore how we can represent multiple qubits and understand how these qubits can interact with one another. 🔄🔁 We’ve already learned how to represent a qubit’s state using a 2D-vector, and now we’ll delve into representing the state of multiple qubits. 🎯🔢

Representing Multi-Qubit States

We saw that a single bit has two possible states, and a qubit has two complex amplitudes. Similarly, two bits have four possible states:

and to describe the state of two qubits requires four complex amplitudes. We need a 4D vector to write it down:

The rules of measurement are still the same as mentioned in this article

And the same implications hold, such as the normalization condition:

If we have two separated qubits, we can describe their collective state using the Kronecker product:

And following the same rules, we can use the Kronecker product to describe the collective state of any number of qubits. Here is an example with three qubits:

If we have n qubits, we will need to keep track of 2^n complex amplitudes. As we can see, these vectors grow exponentially with the number of qubits. This is the reason quantum computers with large numbers of qubits are so difficult to simulate. A modern laptop can easily simulate a general quantum state of around 20 qubits, but simulating 100 qubits is too difficult for the largest supercomputers.

Let’s code this up:

from qiskit import QuantumCircuit, Aer
from qiskit.visualization import plot_histogram, plot_bloch_multivector
qc = QuantumCircuit(3)
# Apply H-gate to each qubit:
for i in range(3):
qc.h(i)
# See the circuit:
qc.draw('mpl')

Each qubit is in the state |+⟩, so we should see this vector:

# Let's see the result
sim = Aer.get_backend('aer_simulator')
qc.save_statevector()

final_state = sim.run(qc).result().get_statevector()

In Jupyter Notebooks we can display this nicely using Latex. If not using Jupyter Notebooks you may need to remove the array_to_latex function and use print(final_state) instead.

qc.draw('mpl')
from qiskit.visualization import array_to_latex
array_to_latex(final_state, prefix="\\text{Statevector} = ")

Single Qubit Gates on Multi-Qubit Statevectors

We know that X gate is represented by the matrix

and when it acts on the |0⟩ , it becomes:

but how it acts on multiple qubits. Turns out, it;s very trivial, we just need the Kronecker product to calculate multi-qubit statevectors, and we use tensor products to calculate the matrices.

If you wane to learn about tensor products, revisit the previous article on linear algebra

qc = QuantumCircuit(2)
qc.h(0)
qc.x(1)
qc.draw('mpl')

we can represent the simultaneous operations (H & X) using their Kronecker product:

The operation looks like this:

Which we can then apply to our 4D statevector. This can become quite messy, you will often see the clearer notation:

Instead of calculating this by hand, we can use Qiskit’s aer_simulator to calculate this for us. The Aer simulator multiplies all the gates in our circuit together to compile a single unitary matrix that performs the whole quantum circuit:

sim = Aer.get_backend('aer_simulator')
qc.save_unitary() # save the unitatry matrix
unitary = sim.run(qc).result().get_unitary()

Let’s see the result in matrix form:

# In Jupyter Notebooks we can display this nicely using Latex.
# If not using Jupyter Notebooks you may need to remove the
# array_to_latex function and use print(unitary) instead.
from qiskit.visualization import array_to_latex
array_to_latex(unitary, prefix="\\text{Circuit = }\n")

If we want to apply a gate to only one qubit at a time (such as in the circuit below), we describe this using Kronecker product with the identity matrix, e.g.:

qc = QuantumCircuit(2)
qc.x(1)
qc.draw('mpl')

Simulate and see the matrix:

# Simulate the unitary
sim = Aer.get_backend('aer_simulator')
qc.save_unitary()

unitary = sim.run(qc).result().get_unitary()
# Display the results:
array_to_latex(unitary, prefix="\\text{Circuit = } ")

We can see Qiskit has performed the Kronecker product:

Multi Qubit Gates

Now we have seen how the states of single qubit gates represented on multiple qubits. We will now see how multiple qubit gates make the qubits interact with each other. An important two Qubit gate is the CNOT gate.

The CNOT Gate

This gate is a conditional gate, it performs the X gate operation on the target qubit , if and only if the state of the control qubit is |1⟩. Let’s see this in action:

qc = QuantumCircuit(2)
# appkt the cnot gate

qc.cx(0,1) # the first number represent the control qubit and the second qubit represent the target qubit

# draw it

qc.draw('mpl')

It’s very simple to understand the action of this qubit from the below truth table:

And acting on our 4D statevector, it has one of the two matrices:

depending on which qubit is the control and which qubit is the target. The left matrix represent the state of our circuit given above. This matrix swaps the amplitudes of |01⟩ and |11⟩ in our statevector

# Simulate the unitary
sim = Aer.get_backend('aer_simulator')
qc.save_unitary()

unitary = sim.run(qc).result().get_unitary()
# Display the results:
array_to_latex(unitary, prefix="\\text{Circuit = } ")

Here we see, we get the same matrix, as we have described. Now to get the other matrix, just change the target and control qubit in the circuit, as done below:

qc = QuantumCircuit(2)
# appkt the cnot gate

qc.cx(1,0) # the first number represent the control qubit and the second qubit represent the target qubit

# draw it

qc.draw('mpl')
# Simulate the unitary
sim = Aer.get_backend('aer_simulator')
qc.save_unitary()

unitary = sim.run(qc).result().get_unitary()
# Display the results:
array_to_latex(unitary, prefix="\\text{Circuit = } ")

Here you see we get the other matrix.

What happens in Superposition?

Let’s see what happens when our qubit is in superposition. We will put one qubit in |+⟩ state:

qc = QuantumCircuit(2)
# Apply H-gate to the first:
qc.h(0)
qc.draw('mpl')
# Let's see the result:
sim = Aer.get_backend('aer_simulator')
qc.save_statevector()
final_state = sim.run(qc).result().get_statevector()
# Print the statevector neatly:
array_to_latex(final_state, prefix="\\text{Statevector = }")

As expected, this produces the state |0⟩⊗|+⟩=|0+⟩

Note : Don’t get confused by 2/√2 in the output, it’s same as 1/√2

Now, Let’s apply the CNOT gate:

qc = QuantumCircuit(2)
# Apply H-gate to the first:
qc.h(0)
# Apply a CNOT:
qc.cx(0,1)
qc.draw('mpl')
# Let's get the result:
qc.save_statevector()
result = sim.run(qc).result()
# Print the statevector neatly:
final_state = result.get_statevector()
array_to_latex(final_state, prefix="\\text{Statevector = }")

We see we have the state:

This state is very important to us, because this state is Entangled

Entangled States

We created the state:

in the previous section.

This is known as the Bell State. We can see that this state has 50% probability of being measured in the state |00⟩ and 50% chance of being measured in the state |11⟩. Interestingly, it has 0% chance of being measured in the state |01⟩ and |10⟩.

Let’s see that:

plot_histogram(result.get_counts())

This combined state cannot be written as two separate qubit states, which in turn has interesting implications.

Although our qubits are in superposition, measuring one will tell us the state of the other and collapse its superposition. For example, if we measured the top qubit and got the state |1⟩, the collective state of our qubits changes like so:

Even if we separated these qubits light-years away, measuring one qubit collapses the superposition and appears to have an immediate effect on the other. This is the ‘spooky action at a distance’ that upset so many physicists in the early 20th century.

It’s important to note that the measurement result is random, and the measurement statistics of one qubit are not affected by any operation on the other qubit. Because of this, there is no way to use shared quantum states to communicate. This is known as the no-communication theorem

Visualizing the Entangled States

We know that these states can’t be written as two separate qubit states, this also means we lose information when we try to plot it on Bloch sphere:

plot_bloch_multivector(final_state)

It’s not be clear how Qiskit even calculates the Bloch vectors with entangled qubits like this, because in single-qubit case, the position of Bloch vector along an axis nicely corresponds to the expectation value of measuring in that basis. If we take this as the rule of plotting Bloch vectors, we arrive at this conclusion above.

This shows us there is no single-qubit measurement basis for which a specific measurement is guaranteed. This contrasts with our single qubit states, in which we could always pick a single-qubit basis. Looking at the individual qubits in this way, we miss the important effect of correlation between the qubits. We cannot distinguish between different entangled states. For example, the two states:

will both look the same on these separate Bloch spheres, despite being very different states with different measurement outcomes.

How else could we visualize this statevector?

This statevector is simply a collection of four amplitudes (complex numbers), and there are endless ways we can map this to an image.

One such visualization is the Q-sphere, here each amplitude is represented by a blob on the surface of a sphere. The size of the blob is proportional to the magnitude of the amplitude, and the color is proportional to the phase of the amplitude. The amplitudes for |00⟩ and |11⟩ are equal, and all other amplitudes are 0:

from qiskit.visualization import plot_state_qsphere
plot_state_qsphere(final_state)

Here we can clearly see the correlation between the qubits. The Q-sphere’s shape has no significance, it is simply a nice way of arranging our blobs; the number of 0s in the state is proportional to the states position on the Z-axis, so here we can see the amplitude of |00⟩ is at the top pole of the sphere, and the amplitude of |11⟩ is at the bottom pole of the sphere.

Conclusion

Multiple qubits and their associated quantum gates unlock a new level of computational possibilities in the realm of quantum computing. In this article, we have explored the enthralling domain of multiple qubits and the remarkable phenomena that arise when these qubits interact and entangle their quantum states.

Furthermore, multiple qubit gates, such as the celebrated CNOT gate, play a crucial role in manipulating the entangled states of qubits. In the next article, we will dive deep into the inner workings of the CNOT gate, unraveling its operations and showcasing its significance in quantum computing. Additionally, we will explore the concept of phase kickback, a fascinating phenomenon that arises when applying certain quantum gates to multiple qubits.

Check the entire blog series : Learn Quantum Computing with Qiskit

or visit my website for more such learning resources :

The Quantum Classroom

--

--