-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Description
Environment
- Qiskit Terra version: 0.24.1 (but it also should affect 0.24.2 and main)
- Python version: 3.11
- Operating system: Linux
What is happening?
When running transpile()
if the VF2PostLayout
pass finds a better letter and re-applies the initial layout the final layout is not adjusted to correct for that change in initial position. This previously was not an issue because the final layout was an internal implementation detail (primarily used only for sabre layout) and we were done using it after layout in the transpiler. But now we're returning the final layout as part of the public interface in a QuantumCircuit.
How can we reproduce the issue?
from qiskit import QuantumCircuit, transpile
from qiskit.providers.fake_provider import FakeVigo
from qiskit_aer import AerSimulator
backend = AerSimulator.from_backend(FakeVigo())
qubits = 3
qc = QuantumCircuit(qubits)
for i in range(5):
qc.cx(i % qubits, int(i + qubits / 2) % qubits)
tqc = transpile(qc, backend=backend, callback=callback)
print(tqc)
print(tqc.layout)
What should happen?
In that example if VF2PostLayout
runs the final layout will potentially point to incorrect qubits. One example incorrect output is:
ancilla_0 -> 0 ───────────────────────────────────────────────────────
┌───┐ ┌───┐┌───┐ ┌───┐ ┌───┐┌───┐
q_0 -> 1 ──■──┤ X ├──■──┤ X ├┤ X ├──■──┤ X ├──■──┤ X ├┤ X ├──■──
┌─┴─┐└─┬─┘ │ └─┬─┘└─┬─┘ │ └─┬─┘┌─┴─┐└─┬─┘└─┬─┘┌─┴─┐
q_1 -> 2 ┤ X ├──┼────┼────┼────■────┼────■──┤ X ├──■────┼──┤ X ├
└───┘ │ ┌─┴─┐ │ ┌─┴─┐ └───┘ │ └───┘
q_2 -> 3 ───────■──┤ X ├──■───────┤ X ├─────────────────■───────
└───┘ └───┘
ancilla_1 -> 4 ───────────────────────────────────────────────────────
TranspileLayout(initial_layout=Layout({
1: Qubit(QuantumRegister(3, 'q'), 0),
2: Qubit(QuantumRegister(3, 'q'), 1),
3: Qubit(QuantumRegister(3, 'q'), 2),
0: Qubit(QuantumRegister(2, 'ancilla'), 0),
4: Qubit(QuantumRegister(2, 'ancilla'), 1)
}), input_qubit_mapping={Qubit(QuantumRegister(3, 'q'), 0): 0, Qubit(QuantumRegister(3, 'q'), 1): 1, Qubit(QuantumRegister(3, 'q'), 2): 2, Qubit(QuantumRegister(2, 'ancilla'), 0): 3, Qubit(QuantumRegister(2, 'ancilla'), 1): 4}, final_layout=Layout({
0: Qubit(QuantumRegister(5, 'q'), 0),
3: Qubit(QuantumRegister(5, 'q'), 1),
2: Qubit(QuantumRegister(5, 'q'), 2),
4: Qubit(QuantumRegister(5, 'q'), 3),
1: Qubit(QuantumRegister(5, 'q'), 4)
}))
In this case the final layout is incorrect because it's not taking into account that vf2postlayout changed the initial layout. Instead it should be:
Layout({
0: Qubit(QuantumRegister(5, 'q'), 0),
3: Qubit(QuantumRegister(5, 'q'), 1),
1: Qubit(QuantumRegister(5, 'q'), 2),
2: Qubit(QuantumRegister(5, 'q'), 3),
4: Qubit(QuantumRegister(5, 'q'), 4)
}))
(I was running without seeds set so it was random failure based on sabre's output)
Any suggestions?
We should update the ApplyLayout
pass to also update the final_layout
in the property set if it's present, just like it does for the layout
field.