Michele Amoretti's answer is essentially correct but there is a neater and less error-prone way to do it. There's no need to try to find the correct unitary matrix expressed with the correct qubit significance-ordering because the unitary matrices are all available in Qiskit's Gate classes as NumPy arrays. Taking them from here also saves you from manually typing the matrix out or copy-pasting it to have an explicit array in code (they can be printed anyway).
import numpy as np
import cmath
from qiskit.circuit.library import CXGate, IGate
from qiskit.aqua.utils import tensorproduct
cx_gate = CXGate().to_matrix()
id_gate = IGate().to_matrix()
layer1 = tensorproduct(id_gate, cx_gate)
layer2 = tensorproduct(cx_gate, id_gate)
qcirc_uni = np.matmul(layer2, layer1)
print(qcirc_uni.real)
array([[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., 0.],
[0., 0., 0., 0., 0., 0., 0., 1.],
[0., 0., 1., 0., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0., 0., 0.]])
Since this unitary matrix is real I used cmath
's real
method to display it more clearly.
The reason that order of the matrices in your tensor products in your first computation is incorrect is because of the qubit significance-ordering convention used in Qiskit: Why does Qiskit order its qubits the way it does? 1 Minute Qiskit. It's a really good idea to get on top of this.