$$ CNOT =
\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 0 & 1 \\
0 & 0 & 1 & 0 \\
\end{bmatrix}
$$

But what does this matrix *mean*? The above matrix means: on a two qubit system (such as $\left|00\right>$, $\left|10\right>$, $\left|11\right>$, etc.) if the first qubit is a one, apply the not gate (X) on the second qubit. That's cool, but what if you have a 4 qubit system $\left(\left|0101\right>\right)$ or an 8 qubit system $\left(\left|00010011\right>\right)$ ? Also, let's say on the 8 qubit system you want to apply the X gate on the 7th qubit if the 2nd is one, how would you go about constructing this matrix?

## Cookbook Method

Most books and articles will discuss a cookbook method where you build a matrix based on what the operation does to the base states. Let's work through this for the 2 qubit CNOT gate above. The above gate says if the first qubit is 1 then apply an X to the 2nd qubit. An X just changes the qubit from a 0 to a 1 or a 1 to a 0. The base states for a two qubit system are: $\left|00\right>,\, \left|01\right>,\, \left|10\right>,\, \left|11\right>$

How do I know those are the 4 states? Quantum qubit systems grow as $2^q$ where $q$ is the number of qubits. For a two qubit system $q=2$ therefore there are 4 qubit states. Then you count from 0 to 3 in binary. That is all.

First, this is how CNOT operates on the base states:

$$ CNOT\left|00\right> \rightarrow \left|00\right> $$$$ CNOT\left|01\right> \rightarrow \left|01\right> $$$$ CNOT\left|10\right> \rightarrow \left|11\right> $$$$ CNOT\left|11\right> \rightarrow \left|10\right> $$

To build a matrix you use the following trick:

\begin{align*}
CNOT &= \begin{bmatrix}\left<00|CNOT|00\right> && \left<00|CNOT|01\right> && \left<00|CNOT|10\right> && \left<00|CNOT|11\right> \\
\left<01|CNOT|00\right> && \left<01|CNOT|01\right> && \left<01|CNOT|10\right> && \left<01|CNOT|11\right> \\
\left<10|CNOT|00\right> && \left<10|CNOT|01\right> && \left<10|CNOT|10\right> && \left<10|CNOT|11\right> \\
\left<11|CNOT|00\right> && \left<11|CNOT|01\right> && \left<11|CNOT|10\right> && \left<11|CNOT|11\right> \end{bmatrix} \\ \\
&= \begin{bmatrix}\left<00|00\right> && \left<00|01\right> && \left<00|11\right> && \left<00|10\right> \\
\left<01|00\right> && \left<01|01\right> && \left<01|11\right> && \left<01|10\right> \\
\left<10|00\right> && \left<10|01\right> && \left<10|11\right> && \left<10|10\right> \\
\left<11|00\right> && \left<11|01\right> && \left<11|11\right> && \left<11|10\right> \end{bmatrix} \\ \\
&=\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 0 & 1 \\
0 & 0 & 1 & 0 \\
\end{bmatrix}
\end{align*}

This is nice, but now suppose you want a CNOT gate between the 3rd and 9th qubit of a 10 qubit system? You will have $2^{10}$ base states and a $2^{10} \times 2^{10}$ matrix! Good luck with the cookbook method! What we need is an *algorithmic* method that we can code up in Python.

## The Algorithmic Method

A better algorithmic way to think about quantum control gates is by using operators and tensor products. Suppose we have a two qubit system.

To say "If the first qubit is $\left|0\right>$ leave the second qubit alone":
$$ \left|0\rangle\langle0\right| \otimes I $$
to leave a qubit alone you apply the Identity operator / matrix $I$

To say "If the first qubit is $\left|1\right>$ apply X to the second qubit":

$$ \left|1\rangle\langle1\right| \otimes X $$

Now put them together by adding them, "If the first qubit is $\left|0\right>$ leave the second qubit alone and If the first qubit is $\left|1\right>$ apply X to the second qubit":

$$ \left|0\rangle\langle0\right| \otimes I + \left|1\rangle\langle1\right| \otimes X $$
In [3]:

from qudotpy import qudot
import numpy as np
zero_matrix = qudot.ZERO.ket * qudot.ZERO.bra
one_matrix = qudot.ONE.ket * qudot.ONE.bra
CNOT = np.kron(zero_matrix, np.eye(2)) + np.kron(one_matrix, qudot.X.matrix)
print(CNOT)

[[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j]
[ 0.+0.j 1.+0.j 0.+0.j 0.+0.j]
[ 0.+0.j 0.+0.j 0.+0.j 1.+0.j]
[ 0.+0.j 0.+0.j 1.+0.j 0.+0.j]]

Nice! This is a good algorithmic way to make CNOT gates (or control gates in general). For example, suppose now you want a CNOT gate of a 10 qubit system where the 3rd qubit is the control and the 9th qubit is the target:

"If the third qubit is $\left|0\right>$ leave the ninth qubit alone:"
$$ I \otimes I \otimes \left|0\rangle\langle0\right| \otimes I \otimes I \otimes I \otimes I \otimes I \otimes I \otimes I $$

"If the third qubit is $\left|1\right>$ apply X to the ninth qubit":
$$ I \otimes I \otimes \left|1\rangle\langle1\right| \otimes I \otimes I \otimes I \otimes I \otimes I \otimes X \otimes I $$

Add those two expression together and you have your 10 qubit CNOT gate.

The above algorithm is straightforward to implement in Python.

You might enjoy this post about introducing an algebraic "control value": http://algassert.com/impractical-experiments/2015/05/17/Treating-Controls-like-Values.html

– Craig Gidney – 2019-01-11T11:18:29.920I wrote a blog post about how to describe CNOT gates and Control-U gates a couple years ago you may find helpful. It is basically the same as the Projection operator answer but goes into a bit more detail and has examples in Python using the QuDotPy opensource quantum computing library. You can find the blog post here: Quantum Control Gates in Python

– Perry Sakkaris – 2019-01-12T01:39:37.690