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

Refactor OpenQASM 2 exporter #9953

Merged
merged 3 commits into from
Apr 17, 2023
Merged

Conversation

jakelishman
Copy link
Member

This rewrites the handling of instructions in the OpenQASM 2 exporter in several places.

First, the definition and the call site are handled at the same time. Previously, these were handled at separate points and required two name munging steps, which mostly just needed to hope that they both converged on the same name. Instead, one singular point handles both, so there are no issues with name mismatches. In a similar vein, this now ensures that the two places will not disagree about when a definition has already been seen before; previously, duplicate definitions could be "used" but not defined.

Second, the gate-definition pass is now made properly recursive, so the exact same code is responsible for defining gates that appear in the body of the main circuit, and of custom definitions, including sharing the duplication detection. Previously, two custom definitions that both used the same gate could cause duplicate definitions to appear with incorrect names. Unifying this handling also has the natural consequence of correctly ordering all gate definitions, whereas before some inner gates could be defined after their first use.

Inside the call-site/definition-site handling, this refactor separates those into two separate objects. This massively simplified:

  • handling known-good Qiskit standard gates to have special-cased support for always exporting properly parametrised definitions;
  • handling UnitaryGate and Permutation specially, so they no longer need to output special OQ2 strings, but can just define a custom object to use as the source for both call-site and definition site;
  • handling gates with no definitions as opaque.

Details and comments

This fixes a whole slew of long-standing bugs, albeit not perfectly. The general case of user-defined parametrised gates are still not handled well, but Qiskit's standard gates now generally are. Even in the worst cases, the export should now be much safer and produce rather less invalid OQ2 code than it did before.

To do with duplicate definitions:

To do with the old UnitaryGate.qasm:

To do with bad orderings of definitions:

A bit more of a mix:

This rewrites the handling of instructions in the OpenQASM 2 exporter in
several places.

First, the definition and the call site are handled at the same time.
Previously, these were handled at separate points and required two name
munging steps, which mostly just needed to hope that they both converged
on the same name.  Instead, one singular point handles both, so there
are no issues with name mismatches.  In a similar vein, this now ensures
that the two places will not disagree about when a definition has
already been seen before; previously, duplicate definitions could be
"used" but not defined.

Second, the gate-definition pass is now made properly recursive, so the
exact same code is responsible for defining gates that appear in the
body of the main circuit, and of custom definitions, including sharing
the duplication detection.  Previously, two custom definitions that both
used the same gate could cause duplicate definitions to appear with
incorrect names.  Unifying this handling also has the natural
consequence of correctly ordering _all_ gate definitions, whereas before
some inner gates could be defined after their first use.

Inside the call-site/definition-site handling, this refactor separates
those into two separate objects.  This massively simplified:

- handling known-good Qiskit standard gates to have special-cased
  support for always exporting properly parametrised definitions;
- handling `UnitaryGate` and `Permutation` specially, so they no longer
  need to output special OQ2 strings, but can just define a custom
  object to use as the source for both call-site and definition site;
- handling gates with no definitions as `opaque`.
@jakelishman jakelishman added Changelog: Bugfix Include in the "Fixed" section of the changelog mod: qasm2 Relating to OpenQASM 2 import or export labels Apr 12, 2023
@jakelishman jakelishman requested a review from a team as a code owner April 12, 2023 01:52
@qiskit-bot
Copy link
Collaborator

Thank you for opening a new pull request.

Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient.

While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone.

One or more of the the following people are requested to review this:

@coveralls
Copy link

coveralls commented Apr 12, 2023

Pull Request Test Coverage Report for Build 4721104772

  • 65 of 66 (98.48%) changed or added relevant lines in 3 files are covered.
  • 9 unchanged lines in 3 files lost coverage.
  • Overall coverage increased (+0.02%) to 85.803%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/circuit/quantumcircuit.py 54 55 98.18%
Files with Coverage Reduction New Missed Lines %
qiskit/extensions/unitary.py 1 93.75%
crates/accelerate/src/sabre_swap/layer.rs 4 97.32%
crates/qasm2/src/lex.rs 4 90.63%
Totals Coverage Status
Change from base Build 4720871645: 0.02%
Covered Lines: 70444
Relevant Lines: 82100

💛 - Coveralls

operation.qasm(),
",".join([bit_labels[j] for j in instruction.qubits + instruction.clbits]),
bits_qasm = ",".join(
bit_labels[j] for j in itertools.chain(instruction.qubits, instruction.clbits)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not instruction.qubits + instruction.clbits as before?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, no particular reason - I probably just didn't notice I'd done it during the rewrite. itertools.chain is the normal idiom I personally use, so I just wouldn't have thought about it.

1ucian0
1ucian0 previously approved these changes Apr 15, 2023
Copy link
Member

@1ucian0 1ucian0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impressive work! Thanks for it!

none of my comments are blocking. LGTM!

Co-authored-by: Luciano Bello <bel@zurich.ibm.com>
@1ucian0 1ucian0 added this pull request to the merge queue Apr 17, 2023
Merged via the queue into Qiskit:main with commit 639bd58 Apr 17, 2023
@jakelishman jakelishman deleted the qasm2/rewrite-exporter branch April 18, 2023 02:26
king-p3nguin pushed a commit to king-p3nguin/qiskit-terra that referenced this pull request May 22, 2023
* Refactor OpenQASM 2 exporter

This rewrites the handling of instructions in the OpenQASM 2 exporter in
several places.

First, the definition and the call site are handled at the same time.
Previously, these were handled at separate points and required two name
munging steps, which mostly just needed to hope that they both converged
on the same name.  Instead, one singular point handles both, so there
are no issues with name mismatches.  In a similar vein, this now ensures
that the two places will not disagree about when a definition has
already been seen before; previously, duplicate definitions could be
"used" but not defined.

Second, the gate-definition pass is now made properly recursive, so the
exact same code is responsible for defining gates that appear in the
body of the main circuit, and of custom definitions, including sharing
the duplication detection.  Previously, two custom definitions that both
used the same gate could cause duplicate definitions to appear with
incorrect names.  Unifying this handling also has the natural
consequence of correctly ordering _all_ gate definitions, whereas before
some inner gates could be defined after their first use.

Inside the call-site/definition-site handling, this refactor separates
those into two separate objects.  This massively simplified:

- handling known-good Qiskit standard gates to have special-cased
  support for always exporting properly parametrised definitions;
- handling `UnitaryGate` and `Permutation` specially, so they no longer
  need to output special OQ2 strings, but can just define a custom
  object to use as the source for both call-site and definition site;
- handling gates with no definitions as `opaque`.

* Style tweak

Co-authored-by: Luciano Bello <bel@zurich.ibm.com>

---------

Co-authored-by: Luciano Bello <bel@zurich.ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment