# Transpilation on restricted topology does not yield an equivalent circuit in Qiskit

Here is an MWE: a simple circuit on three qubits with a CNOT acting on qubits 0 and 2. The coupling map prohibits a two-qubit gate between qubits 0 and 2 and so qubit 1 must get involved.

from qiskit import QuantumCircuit
from qiskit.compiler import transpile
from qiskit.transpiler import CouplingMap
from qiskit.quantum_info import Operator
from qiskit.circuit.library import Permutation

from itertools import permutations

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

coupling_map = CouplingMap([[0, 1], [1, 0], [1, 2], [2, 1]])

transpiled_qc = transpile(qc, basis_gates=['cx'], coupling_map=coupling_map)


Now, if I check

Operator(transpiled_qc).equiv(qc) # False


Although the resulting circuit looks reasonable

I thought that the difference between the original and the transpiled circuit might be a permutation of qubits, but the following check did not work either

for p in permutations([0, 1, 2]):
permutted_qc = qc.compose(Permutation(3, p))
print(Operator(transpiled_qc).equiv(permutted_qc)) # All False


If I fix the initial_layout in the transpilation options

transpiled_qc = transpile(qc, basis_gates=['cx'],
coupling_map=coupling_map, initial_layout=[0, 1, 2])


then the resulting circuit

is indeed equivalent to the transpiled circuit plus a permutation

permutted_qc = qc.compose(Permutation(3, [1, 0, 2]))
print(Operator(transpiled_qc).equiv(permutted_qc)) # True


My questions is now I guess -- how to be systematic about it? How to read out an appropriate permutation before trying all options (I have much more complicated circuits in mind). I mean, isn't it a basic human need to transpile a circuit and get True as a result of the equivalence test?

• The "resulting circuit" looks perfectly valid, right? It's swapped qubit 2 to qubit 1, and applied a cnot from 0 to 1. So, to actually implement the cnot from 0 to 2 as originally required, you just have to swap back qubits 1 and 2. So it should be correct up to a permutation. So I assume it's your last bit of checking code that has an error. Jun 15, 2021 at 7:28
• The first 3 operations is the SWAP gate, then it performs a CNOT, but since your circuit is only have one CNOT ($CNOT_{[0,2]}$) it did not swap the qubit back to the original position. So theoretically, if you have another gate applying to $q_2$, then it would swap the qubit back before applying that gate. Jun 15, 2021 at 7:30
• Could it be that compose modifies qc ? Jun 15, 2021 at 7:40

As noted in the comments by DaftWullie and me, the circuit is just missing a SWAP operation to return the qubit back to its original position... but this is not needed since your circuit only have one CNOT gate between the two end qubits. No other operations is being applied after the CNOT, hence you don't need to perform the SWAP again to return the qubit to its original position. If you do, however, you will see that both the circuit would have the same unitary matrix representation.

First, note that your original circuit is:

from qiskit import QuantumRegiste
qreg_q = QuantumRegister(3, 'q')
circuit = QuantumCircuit(qreg_q)
circuit.cx(qreg_q[0], qreg_q[2])
circuit.draw()


which has the unitary matrix representation of:

from qiskit.visualization.array import array_to_latex
from qiskit.quantum_info import Operator
array_to_latex(Operator(circuit))


And if you consider the circuit:

qreg_q = QuantumRegister(3, 'q')
circuit = QuantumCircuit(qreg_q)
circuit.cx(qreg_q[0], qreg_q[1])
circuit.cx(qreg_q[1], qreg_q[0])
circuit.cx(qreg_q[0], qreg_q[1])
circuit.cx(qreg_q[1], qreg_q[2])
circuit.cx(qreg_q[0], qreg_q[1])
circuit.cx(qreg_q[1], qreg_q[0])
circuit.cx(qreg_q[0], qreg_q[1])
circuit.draw()


and if you look at its matrix representation, array_to_latex(Operator(circuit)), you will have:

which is the same as the one above.

• Thanks, I get the idea! I'm still unsure though how to solve my issue technically. Why my permutation check did not work? How can I get qiskit to transpile and get exactly equivalent circuit (adding an extra permutation, if needed). Jun 15, 2021 at 7:59

When you transpile a circuit the addition of SWAP gates means that your two unitaries, original and transpiled, are related by a one-sided permutation matrix. This can be found by, for example,

op = Operator(qc)
t_op = Operator(transpiled_qc)


• Hi! Thanks for your answer, but this is still way too implicit for my taste. (1) Are the original and the transpiled circuits related by the right permutation irrespective of the initial layout? I found that only when I fix the initial layout to range(n_qubits) this is true. (2) Can I ask the transpiler to output a circuit involving the necessary permutation? My goal is very simple -- I want the transpiled circuit to be equivalent to the original one as witnessed by the Operator.equiv check. Jun 21, 2021 at 11:54
• And also, do you know if the transpiler does a consistency check as its last step? If os, how is it done if not with Operator.equiv? Jun 21, 2021 at 11:55
• Alright, I see. But does your trick of computing $U_{transpiled}^{\dagger} U_{original}$ to find the permutation work for large circuits? Jun 21, 2021 at 12:34