Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
4.83k stars 2.29k forks source link

Wrong circuits and wrong measurement results are produced by specific backend #12643

Closed weucode closed 5 days ago

weucode commented 1 week ago

Environment

What is happening?

When running program1, two wrong behaviors were found: (1) Some fake backends declare duplicated ancilla qubits. The number of duplicated ancilla qubits varies between different fake backends. (2) The Statevector simulator treats ancilla qubits as common qubits and measures all of them. This issue can also be reproduced by running program2. These issues appear to persist across multiple versions of qiskit (e.g., 1.0.2), not just the latest ones. Do you have any suggestions or workarounds for these behaviors?

How can we reproduce the issue?

program1:

from qiskit import QuantumCircuit, transpile
from qiskit.quantum_info import Statevector
from qiskit_ibm_runtime.fake_provider import FakeYorktownV2, FakeSherbrooke

qc = QuantumCircuit(2)
qc.cp(0.0, 1, 0)
qc.measure_all()

backend = FakeYorktownV2()
qc1 = transpile(qc, backend)
print(qc1) # wrong circuit

result = backend.run(qc1).result().get_counts()
print(result)

qc1.remove_final_measurements()
statevector = Statevector(qc1)
print(statevector.probabilities_dict()) # wrong measurement result

output1:

                ░ ┌─┐   
      q_0 -> 0 ─░─┤M├───
                ░ └╥┘┌─┐
      q_1 -> 1 ─░──╫─┤M├
                ░  ║ └╥┘
ancilla_0 -> 2 ────╫──╫─
                   ║  ║ 
ancilla_1 -> 3 ────╫──╫─
                   ║  ║ 
ancilla_2 -> 4 ────╫──╫─
                   ║  ║ 
       meas: 2/════╩══╩═
                   0  1 
{'01': 62, '10': 24, '00': 938}
{'00000': 1.0} # where should be {'00': 1.0}

The openqasm code:

OPENQASM 3.0;
include "stdgates.inc";
bit[1] meas;
barrier $0, $1;
meas[0] = measure $0;

program2:

from qiskit.qasm3 import dumps, load
from qiskit.quantum_info import Statevector
from qiskit_aer import AerSimulator, QasmSimulator

qc = load("demo.qasm")
backend = AerSimulator()
result = backend.run(qc).result().get_counts()
print(result)
qc.remove_final_measurements()
statevector =Statevector(qc)
print(statevector.probabilities_dict())

output2:

{'0': 1024}
{'00': 1.0} # where should be {'0': 1.0}

What should happen?

(1) The fake backends should not declare duplicated ancilla qubits. (2) Statevector should identify the correct number of declared qubits.

Any suggestions?

No response

jakelishman commented 1 week ago

These are both expected behaviours - when you transpile your circuit to hardware, it becomes a physical circuit, which means it must account for all the qubits on the device. These are the extra ancillas you're seeing.

The call Statevector(qc1) gets the statevector of all qubits in the circuit. After ancilla expansion, it's correct that it includes all hardware qubits; there are various swap-mapping and gate syntheses passes that could cause mid-circuit ancilla use, or even the ancillas to end in a dirty state at the end of the circuit. If you want to reduce it to the qubits you care about at the end, you'll need to use something like qiskit.quantum_info.partial_trace, and you can find the qubits arguments by inspecting qc.layout.final_index_layout.

weucode commented 5 days ago

Thank you for your quick response. I also found that using qc1.draw(idle_wires=False) is helpful for observing the key parts of the circuit.