2 quantum bits

I will be using qiskit to study quantum algorithms in my own way. Since this is a record of my personal study, I may have left out a lot of explanations.

I am following the qiskit website.

Last time we focused on the basic usage and gating operations for one qubit, this time we will understand operations for two qubits.

github

  • The file in jupyter notebook format is here

google colaboratory

  • If you want to run it on google colaboratory here

Author’s environment

!sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.6
BuildVersion: 18G103
Python -V
Python 3.8.5

Import the basic libraries and check their versions.

%matplotlib inline
%config InlineBackend.figure_format = 'svg'

import matplotlib
import matplotlib.pyplot as plt
import scipy
import numpy as np
import pandas as pd

print('matplotlib version :', matplotlib.__version__)
print('scipy version :', scipy.__version__)
print('numpy version :', np.__version__)
print('pandas version :', pd.__version__)
matplotlib version : 3.3.2
scipy version : 1.5.2
numpy version : 1.19.2
pandas version : 1.1.3
import qiskit
import json

dict(qiskit.__qiskit_version__)
{'qiskit-terra': '0.17.4',
 'qiskit-aer': '0.8.2',
 'qiskit-ignis': '0.6.0',
 'qiskit-ibmq-provider': '0.13.1',
 'qiskit-aqua': '0.9.1',
 'qiskit': '0.26.2',
 'qiskit-nature': None,
 'qiskit-finance': None,
 'qiskit-optimization': None,
 'qiskit-machine-learning': None}

Two-qubit state.

$$ |a\rangle=a_{00}|00\rangle+a_{01}|01\rangle+a_{10}|10\rangle+a_{11}|11\rangle=\left(\begin{array}{l} a_{00} \\ a_{01} \\ a_{10} \\ a_{11} \end{array}\right) $$

The components of each vector represent, from the top, the amplitudes of $|00\rangle$, $|01\rangle$, $|10\rangle$, and $|11\rangle$, respectively, just in binary notation.

The two-qubit state can be neatly represented using the tensor product.

$$ |a\rangle=\left(\begin{array}{l} a_{0} \\ a_{1} \end{array}\right), \quad|b\rangle=\left(\begin{array}{l} b_{0} \\ b_{1} \end{array}\right) $$

$$ |b a\rangle=|b\rangle \otimes|a\rangle=\left(\begin{array}{l} b_{0} \times\left(\begin{array}{c} a_{0} \\ a_{1} \end{array}\right) \\ b_{1} \times\left(\begin{array}{c}) a_{0} \\ a_{1} \end{array}\right) \end{array}\right)=\left(\begin{array}{c} b_{0} a_{0} \\ b_{0} a_{1} \\ b_{1} a_{0} \\ b_{1} a_{1} \end{array}\right) $$

The same is true for three qubits.

$$ |c b a\rangle=\left(\begin{array}{l} c_{0} b_{0} a_{0} \\ c_{0} b_{0} a_{1} \\ c_{0} b_{1} a_{0} \\ c_{0} b_{1} a_{1} \\ c_{1} b_{0} a_{0} \\ c_{1} b_{0} a_{1} \\ c_{1} b_{1} a_{0} \\ c_{1} b_{1} a_{1} \end{array}\right) $$

The way we think about vector elements and amplitudes is the same as in two dimensions.

Circuit

Let’s prepare three qubits and apply an adamantine gate to each of them.

from qiskit import *
from math import pi
import numpy as np
from qiskit.visualization import plot_bloch_multivector, plot_histogram
qc = QuantumCircuit(3)
qc.h(0)
qc.h(1)
qc.h(2)
qc.draw('mpl')
backend = Aer.get_backend('statevector_simulator')
final_state = execute(qc,backend).result().get_statevector()

from qiskit_textbook.tools import array_to_latex
array_to_latex(final_state, pretext="\\\\text{Statevector} = ")

$\displaystyle \text{Statevector} = \begin{bmatrix} \tfrac{1}{\sqrt{8}} \\ \tfrac{1}{\sqrt{8}} \\ \frac{1}{\sqrt{8}} \\ \tfrac{1}{\sqrt{8}} \\ \tfrac{1}{\sqrt{8}} \\ \tfrac{1}{\sqrt{8}} \\ \tfrac{1}{\sqrt{8}} \\ \tfrac{1}{\sqrt{8}} \end{bmatrix} $

The state created by the three $|+++\rangle$ is.

A single qubit gate to multiple qubits.

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

Simultaneous operations with $H$ and $X$ can be expressed using tensor products.

$$ X\left|q_{1}\right\rangle H\left|q_{0}\right\rangle=(X \otimes H)\left|q_{1} q_{0}\right\rangle $$

I found this expression very easy to understand. The $|q_1\rangle$ and $H$ are commutative. The general tensor product is non-commutative.

$$ X \otimes H=\left(\begin{array}{ll} 0 & 1 \\ 1 & 0 \end{array}\right) \otimes \frac{1}{\sqrt{2}}\left(\begin{array}{cc} 1 & 1 \\ 1 & -1 \end{array}\right)=\frac{1}{\sqrt{2}}\left(\begin{array}{cc} 0 \times\left(\begin{array}{cc} 1 & 1 \\ 1 & -1 \end{array}\right) & 1 \times\left(\begin{array}{cc} 1 & 1 \\ 1 & -1 \end{array}\right) \\ 1 \times\left(\begin{array}{cc} 1 & 1 \\ 1 & -1 \end{array}\right) & 0 \times\left(\begin{array}{cc} 1 & 1 \\ 1 & -1 \end{array}\right) \end{array}\right)=\frac{1}{\sqrt{2}}\left(\begin{array}{cccc} 0 & 0 & 1 & 1 \\ 0 & 0 & 1 & -1 \\ 1 & 1 & 0 & 0 \\ 1 & -1 & 0 & 0 \end{array}\right) $$

This is also a very straightforward expression.

$$ X \otimes H=\left(\begin{array}{cc} 0 & H \\ H & 0 \end{array}\right) $$

You can easily get the operators around here with qiskit.

# Use the unitary simulator in the backend

backend = Aer.get_backend('unitary_simulator')
unitary = execute(qc,backend).result().get_unitary()
from qiskit_textbook.tools import array_to_latex
array_to_latex(unitary, pretext="\\\\text{Circuit = }\n")

$\displaystyle \text{Circuit = } \begin{bmatrix} 0 & 0 & \tfrac{1}{\sqrt{2}} & \tfrac{1}{\sqrt{2}} \\ 0 & 0 & \tfrac{1}{\sqrt{2}} & -\tfrac{1}{\sqrt{2}} \\ \tfrac{1}{\sqrt{2}} & \tfrac{1}{\sqrt{2}} & 0 & 0 \\ \tfrac{1}{\sqrt{2}} & -\tfrac{1}{\sqrt{2}} & 0 & 0 \\ \end{bmatrix} $$ $

This result is the same as

$$ X \otimes H=\left(\begin{array}{cc} 0 & H \\ H & 0 \end{array}\right) $$

The following is the result.

CNOT gate

qc = QuantumCircuit(2)
qc.cx(0,1)

qc.draw('mpl')

backend = Aer.get_backend('unitary_simulator')
unitary = execute(qc,backend).result().get_unitary()
array_to_latex(unitary, pretext="\\\\text{Circuit = }\n")

$\displaystyle \text{Circuit = } \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ \end{bmatrix} $$ $

$$ \begin{array}{|c|c|} \hline \text { Input (t,c) } & \text { Output (t,c) } \\ \hline 00 & 00 \\ 01 & 11 \\ 10 & 10 \\ 11 & 01 \\ \hline \end{array} $$

CNOT gates for bits in superposition state

qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0,1)
qc.draw('mpl')
backend = Aer.get_backend('statevector_simulator')
final_state = execute(qc,backend).result().get_statevector()
array_to_latex(final_state, pretext="\\\\text{Statevector = }")

$\displaystyle \text{Statevector = }\begin{bmatrix} \tfrac{1}{\sqrt{2}} \\ 0 \\ 0 \\ \tfrac{1}{\sqrt{2}} \end{bmatrix} $

$$ \operatorname{CNOT}|0+\rangle=\frac{1}{\sqrt{2}}(|00\rangle+|11\rangle) $$

We were able to create a bell state with the Adamant and CNOT gates. This is a swap of the amplitudes, $a_{01}$ and $a_{11}$.

Bell state

$$ \operatorname{CNOT}|0+\rangle=\frac{1}{\sqrt{2}}(|00\rangle+|11\rangle) $$

is called the bell state and is in a tangled state. As is well known, measuring the state of one bit, for example, will instantly determine the state of the other qubit, no matter how far apart they are.

results = execute(qc,backend).results().get_counts()
plot_histogram(results)

Phase kickback

from qiskit.visualization import plot_bloch_multivector, plot_histogram, array_to_latex
qc = QuantumCircuit(2)
qc.h(0)
qc.h(1)
qc.cx(0,1)
qc.h(0)
qc.h(1)
display(qc.draw('mpl'))

qc.save_unitary()
usim = Aer.get_backend('aer_simulator')
qobj = assemble(qc)
unitary = usim.run(qobj).result().get_unitary()
array_to_latex(unitary, prefix="\\\\text{Circuit = }")

$$ \text{Circuit = } \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ \end{bmatrix} $$

qc = QuantumCircuit(2)
qc.cx(1,0)
display(qc.draw('mpl'))
qc.save_unitary()

qobj = assemble(qc)
unitary = usim.run(qobj).result().get_unitary()
array_to_latex(unitary, prefix="\\\\text{Circuit = }")

$$ \text{Circuit = } \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ \end{bmatrix} $$

The above is an equivalent unitary matrix, even though the control bits are reversed. This is an example of phase kickback.

An interesting example is when the control bits are superimposed: if we apply the CNOT gate to $|-+\rangle$, strangely enough, the control bits are affected more.

$$ \begin{aligned} \mathrm{CNOT}|-+\rangle &=\frac{1}{\sqrt{2}}}(\mathrm{CNOT}|-0\rangle+\mathrm{CNOT}|-1\rangle) \\ &=\frac{1}{\sqrt{2}}(|-0\rangle+X|-1\rangle) \\ &=\frac{1}{\sqrt{2}}(|-0\rangle-|-1\rangle) \\ &=|-\rangle \otimes \frac{1}{\sqrt{2}}(|-0\rangle-|-1\rangle) \\ &=|-\rangle \end{aligned} $$

The control bit, $|+\rangle$, has changed to $|-\rangle$.

Next, let’s apply the T-gate to the control bits in the superposition state.

qc = QuantumCircuit(2)
qc.cp(pi/4, 0, 1)
display(qc.draw('mpl'))
# See Results:
qc.save_unitary()
qobj = assemble(qc)
unitary = usim.run(qobj).result().get_unitary()
array_to_latex(unitary, prefix="\\\\text{Controlled-T} = \n")

$$ \text{Controlled-T} =

\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & \tfrac{1}{\sqrt{2}}(1 + i) \\ \end{bmatrix} $$

The control T is the target of the notation in the figure above.

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

qc.save_statevector()
qobj = assemble(qc)
final_state = svsim.run(qobj).result().get_statevector()
plot_bloch_multivector(final_state)
qc = QuantumCircuit(2)
qc.h(0)
qc.x(1)

# Add Controlled-T
qc.cp(pi/4, 0, 1)
display(qc.draw('mpl'))

qc.save_statevector()
qobj = assemble(qc)
final_state = svsim.run(qobj).result().get_statevector()
plot_bloch_multivector(final_state)

Here too, we can see that the control bit is rotated by $\displaystyle \frac{\pi}{4}$ relative to the Z axis. It seems that the control Z-gate has no distinction between control and target qubits. This is why, in qiskit, the control Z-rotation gate is represented in a symmetric form. Excellent.

The phase kickback is nicely summarized in this article.

It explains phase kickback from a simple model where you have two qubits, apply an adamantine gate to the first qubit, and then apply a controlled unitary gate to the second qubit.

qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0,1)
display(qc.draw('mpl'))

To summarize, when we input the unitary gate and its eigenvector to the control bit, the eigenvalues mysteriously appear in the phase of $|1\rangle$ in the control bit. The eigenvalues of the unitary gate and eigenvector input to the target bit somehow appear in the control bit, which I think is a kickback.

$$ \begin{array}{|c|c|c|l|} \hline \text{Unitary} & |q_1\rangle & \text{eigenvalue of }|q_1\rangle & \text{status} \\ \hline Z & |0\rangle & +1 & |+\rangle=\frac{1}{\sqrt{2}}(|0\rangle+1|1\rangle) \\ \hline Z & |1\hlangle & -1 & |-\hlangle=\frac{1}{\sqrt{2}}(|0\hlangle-1|1\hlangle) \\ \hline X &+\hlangle & +1 & |+\hlangle=\frac{1}{\sqrt{2}}(|0\hlangle+1|1\hlangle) \\ \hline X & |-\rangle & -1 & |-\rangle=\frac{1}{\sqrt{2}}(|0\rangle-1|1\rangle) \\ \hline \end{array} $$

About matrices in general

Unitary matrices, Hermitian matrices, and gate sets are explained in this section.

I am a graduate of the Department of Physics in the Faculty of Science, and I remember having studied quantum mechanics, statistical physics, and quantum information, but when I studied it again, I had the impression that it was a complete theory and very easy to understand.

At the time, I had a hard time understanding the theory, but now that I am older and my mind is not as flexible as it was then, I find it relatively easy to understand. Of course, at the time, the textbook was written by a theoretical physics professor of particle theory, and there was not much information on the Internet, so I was relying only on that textbook for my study.

I am very happy with IBM.