Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

qiskit.qasm3.loads( ) loses qubit mapping #11480

Closed
balewski opened this issue Jan 2, 2024 · 2 comments
Closed

qiskit.qasm3.loads( ) loses qubit mapping #11480

balewski opened this issue Jan 2, 2024 · 2 comments
Labels
bug Something isn't working mod: qasm3 Related to OpenQASM 3 import or export

Comments

@balewski
Copy link

balewski commented Jan 2, 2024

Environment

Python 3.10.12
openqasm3 0.5.0
qiskit-qasm3-import 0.4.1
pytket-qiskit 0.46.0
qiskit 0.45.1
qiskit-aer 0.13.1
qiskit-algorithms 0.2.1
qiskit-dynamics 0.4.2
qiskit-experiments 0.5.4
qiskit-ibm-experiment 0.3.5
qiskit-ibm-provider 0.7.2
qiskit-ibm-runtime 0.17.0
qiskit-terra 0.45.1

What is happening?

When a simple circuit, like GHZ, is transpiled for a backend, next saved as Qasm3,
the qiskit.qasm3.loads( .) forgets the qubit mapping assigned by the transpiler and counts qubits from 0 to N-1. Such a read-in circuit would not run on the HW properly.

How can we reproduce the issue?

Run this reproducer:
https://bitbucket.org/balewski/quantummind/src/master/Qiskit/issues/issue27b_qasm3_IO.py
It executes 3 commands:

 qcT = transpile(qc, backend=backend, optimization_level=3, seed_transpiler=111)
 qasm1=qiskit.qasm3.dumps(qcT)
 qc2=qiskit.qasm3.loads(qasm1)

And shows qcT uses qubits IDs ~100, but qc2 drops ids to be 0-3

What should happen?

Both circuits: qcT and qc2 should use the same qubits

Any suggestions?

No response

@balewski balewski added the bug Something isn't working label Jan 2, 2024
@jakelishman jakelishman added the mod: qasm3 Related to OpenQASM 3 import or export label Jan 2, 2024
@jakelishman
Copy link
Member

Brining in the minimal reproducer inline (it's helpful if all the context is in the issue, and using as few additional libraries as possible):

from qiskit import QuantumCircuit, transpile
from qiskit.providers.fake_provider import FakeWashington
import qiskit.qasm3

backend = FakeWashington()

qc = QuantumCircuit(4)
qc.h(0)
for i in range(1, 4):
    qc.cx(0, i)
qc.measure_all()
transpiled = transpile(qc, backend=backend, optimization_level=3, seed_transpiler=111)
roundtrip = qiskit.qasm3.loads(qiskit.qasm3.dumps(transpiled))

Now the result of drawing transpiled and roundtrip shows a difference:

transpiled.draw(idle_wires=False)
global phase: π/4
                                      ┌───┐           ░    ┌─┐
q_1 -> 48 ────────────────────────────┤ X ├───────────░────┤M├──────
          ┌─────────┐┌────┐┌─────────┐└─┬─┘           ░ ┌─┐└╥┘
q_0 -> 49 ┤ Rz(π/2) ├┤ √X ├┤ Rz(π/2) ├──■────■────■───░─┤M├─╫───────
          └─────────┘└────┘└─────────┘     ┌─┴─┐  │   ░ └╥┘ ║ ┌─┐
q_2 -> 50 ─────────────────────────────────┤ X ├──┼───░──╫──╫─┤M├───
                                           └───┘┌─┴─┐ ░  ║  ║ └╥┘┌─┐
q_3 -> 55 ──────────────────────────────────────┤ X ├─░──╫──╫──╫─┤M├
                                                └───┘ ░  ║  ║  ║ └╥┘
  meas: 4/═══════════════════════════════════════════════╩══╩══╩══╩═
                                                         0  1  2  3
roundtrip.draw(idle_wires=False)
        ┌─────────┐┌────┐┌─────────┐                ░ ┌─┐
      0 ┤ Rz(π/2) ├┤ √X ├┤ Rz(π/2) ├──■────■────■───░─┤M├─────────
        └─────────┘└────┘└─────────┘┌─┴─┐  │    │   ░ └╥┘┌─┐
      1 ────────────────────────────┤ X ├──┼────┼───░──╫─┤M├──────
                                    └───┘┌─┴─┐  │   ░  ║ └╥┘┌─┐
      2 ─────────────────────────────────┤ X ├──┼───░──╫──╫─┤M├───
                                         └───┘┌─┴─┐ ░  ║  ║ └╥┘┌─┐
      3 ──────────────────────────────────────┤ X ├─░──╫──╫──╫─┤M├
                                              └───┘ ░  ║  ║  ║ └╥┘
meas: 4/═══════════════════════════════════════════════╩══╩══╩══╩═
                                                       0  1  2  3

However, the OQ3 import actually has brought in the physical-qubit layout information in some form:

roundtrip.layout
TranspileLayout(initial_layout=Layout({
49: <qiskit.circuit.quantumregister.Qubit object at 0x12783b540>,
48: <qiskit.circuit.quantumregister.Qubit object at 0x12783b300>,
50: <qiskit.circuit.quantumregister.Qubit object at 0x12783b140>,
55: <qiskit.circuit.quantumregister.Qubit object at 0x12783b100>
}), input_qubit_mapping={<qiskit.circuit.quantumregister.Qubit object at 0x12783b540>: 49, <qiskit.circuit.quantumregister.Qubit object at 0x12783b300>: 48, <qiskit.circuit.quantumregister.Qubit object at 0x12783b140>: 50, <qiskit.circuit.quantumregister.Qubit object at 0x12783b100>: 55}, final_layout=None, _input_qubit_count=None, _output_qubit_list=None)

There are two problems with this at the moment:

  • the resulting roundtrip contains virtual-qubit objects, but has a set layout. This isn't the canonical form of physical circuits, which is why subsequent qiskit.qasm3.dumps calls and the visualisers draw it incorrectly.
  • the OpenQASM 3 language doesn't (without custom extensions) allow us enough to freedom to transmit all the necessary information inline when outputting in physical-qubit mode. Notably, there's no current way in OpenQASM 3 to declare how many hardware qubits are involved in total (even if unused), which Qiskit currently needs for its data model. There was some (stalled) discussion of that in Make declaration of physical qubits legal openqasm/openqasm#417, but I don't think that's progressed in a while.

I suspect the most reasonable solution to this will be for the Qiskit qasm3.loads method to gain a keyword argument that tells it how many hardware qubits to allocate, which is an API change we'll consider once the new OpenQASM 3 parser is in place. At the moment, the loads API is deliberately limited because we knew we'd be replacing its driver, and didn't want to commit to API surface we couldn't guarantee during the transition.

@jakelishman
Copy link
Member

I believe that the majority of this issue should have been fixed by Qiskit/qiskit-qasm3-import#30. The handling isn't entirely perfect (the drawer visualisation still is awkward, for example), but the physical qubit numbers are now certainly round-tripped.

I'll close this as "complete" for now, but feel free to re-open if there's more to discuss.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working mod: qasm3 Related to OpenQASM 3 import or export
Projects
None yet
Development

No branches or pull requests

2 participants