Applying CNOT operator to specific qubits in a composite system

In the given problem statement, How do I apply the fourth operation i.e. how to apply a $$CNOT_{c=3,t=1}$$ to a 3-bit composite system:

Approach:

1. First, each bit is set to the state 0. Therefore operator expression becomes =

$$\begin{bmatrix} 1 \\ 0 \end{bmatrix} \otimes \begin{bmatrix} 1 \\ 0 \end{bmatrix} \otimes \begin{bmatrix} 1 \\ 0 \end{bmatrix}$$

1. Second, the fair coin operator $$\begin{bmatrix} 0.5 & 0.5 \\ 0.5 & 0.5 \end{bmatrix}$$ is applied to the second bit. And NOT operator $$\begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}$$ is applied to the first bit. Therefore operator expression becomes:

$$I_2 \otimes \begin{bmatrix} 0.5 & 0.5 \\ 0.5 & 0.5 \end{bmatrix} \otimes I_2$$ And then: $$\begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix} \otimes I_2 \otimes I_2$$

1. Third, the CNOT operator is applied on the second and third bits where the second bit is the control bit and the third bit is the target bit. Resultant operator is:

$$I_2 \otimes CNOT_{c=2, t=3}$$

1. The CNOT operator is applied on the third and first bits where the third bit is the control bit and the first bit is the target bit. What is resultant expression for this?

Note: $$I_2$$ is identity matrix $$(2 \times 2)$$ and $$CNOT_{c=2, t=3}$$ is $$(4 \times 4)$$ CNOT matrix.

First, let's take a look at how $$CNOT$$ acts on 2 qubits, with 0 the control and 1 the target.

array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0]])


This matrix will swap the 10 and 11 entries of the state vector, which you can interpret as swapping the 2nd (10 in binary) and 3rd (=11) rows (or columns) of $$I_4$$.

If the $$CNOT$$ gate uses 1 as the control and 0 as the target, we get

array([[1, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 1, 0, 0]])


We see that this time, the 01 and 11 entries are swapped instead.

Let's expand to 3 qubits, with $$I_2$$ on qubit 0 and $$CNOT$$ on qubits 2 and 1. The matrix is easily computed as a Kronecker product:

array([[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1, 0, 0]])


001 gets swapped with 011 and 101 gets swapped with 111. This makes sense because the $$CNOT$$ only acts on qubits 1 and 2, swapping 01 and 11 as before, but this time we have to do this swap for both possible values of qubit 0.

Finally, we get to $$CNOT_{2,0}$$ (instead of $$CNOT_{3,1}$$ since I'm using 0-indexing). Since the $$CNOT$$ ignores qubit 1, we should expect row 001 to swap with 101 and 011 to swap with 111, giving us the matrix

array([[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 1, 0, 0, 0, 0]])


This can be verified in the Amazon Braket SDK:

>>> from braket.circuits import Circuit
>>> Circuit().cnot(2, 0).i(1).to_unitary()


Generally, it's pretty clear from this that thinking in terms of 2-dimensional matrices can get confusing pretty fast as we increase our qubit count and gate generality. Instead, it's easier to think of the gates (and in turn the entire circuit unitary) in terms of tensors; for example $$CNOT$$ on qubits $$i$$ and $$j$$ is the tensor $$CNOT_{ij}^{kl}$$. You can find more details on this thought process in this answer.