Skip to content

[qref 3.9] Migrate handle_decomposition_rule to reference semantics#2834

Merged
paul0403 merged 34 commits into
paul0403/qref_frontend_mainfrom
paul0403/qref_decomp
May 28, 2026
Merged

[qref 3.9] Migrate handle_decomposition_rule to reference semantics#2834
paul0403 merged 34 commits into
paul0403/qref_frontend_mainfrom
paul0403/qref_decomp

Conversation

@paul0403
Copy link
Copy Markdown
Member

@paul0403 paul0403 commented May 13, 2026

Context:
Migrate handle_decomposition_rule to reference semantics.

Mostly, the change is to just get rid of the QubitHandler. This was the machinery that converted reference semantics plxpr to value semantics catalyst jaxpr. But now catalyst jaxpr is also reference semantics, so this conversion in the frontend is not needed anymore.

This makes the code significantly simpler.

[sc-119731]

Comment thread frontend/catalyst/from_plxpr/qfunc_interpreter.py
@github-actions
Copy link
Copy Markdown
Contributor

Hello. You may have forgotten to update the changelog!
Please edit doc/releases/changelog-dev.md on your branch with:

  • A one-to-two sentence description of the change. You may include a small working example for new features.
  • A link back to this PR.
  • Your name (or GitHub username) in the contributors section.

@paul0403 paul0403 requested review from kipawaa and maliasadi May 25, 2026 17:11
Copy link
Copy Markdown
Contributor

@kipawaa kipawaa left a comment

Choose a reason for hiding this comment

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

Congrats! No more qubit_handler! 🎉

@paul0403 paul0403 requested a review from rniczh May 25, 2026 17:24
Copy link
Copy Markdown
Member

@rniczh rniczh left a comment

Choose a reason for hiding this comment

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

Awesome! @paul0403

Comment thread frontend/catalyst/from_plxpr/qubit_handler.py
Base automatically changed from paul0403/qref_frontend_subroutines to paul0403/qref_frontend_main May 28, 2026 16:12
@paul0403 paul0403 merged commit b79fc3b into paul0403/qref_frontend_main May 28, 2026
33 of 34 checks passed
@paul0403 paul0403 deleted the paul0403/qref_decomp branch May 28, 2026 17:51
paul0403 added a commit that referenced this pull request Jun 2, 2026
…#2663)

**Context:**
Migrate capture frontend to produce reference semantics MLIR.

This is the main PR. Each item will come into this PR as its own PR.

**Description of the Change:**
- Expose python bindings for operations in the `qref` MLIR dialect, and
define their corresponding jax primitives and lowering rules on these
primitives
- The conversion from plxpr to catalyst jaxpr now produces qref
primitives whenever possible. This includes allocation, deallocation,
extract (now `qref.get`; note that reference semantics does not have an
"insert" op), observables, gates and adjoints
- For the following primitives, the conversion from the PL version to
catalyst version is no longer done. Instead, we define lowering rule on
the PL primitives directly: `for_loop`, `while_loop`, `if`, `adjoint`.
This is because with reference semantics, their MLIR operation now take
in and return purely classical values, so the special handling regarding
the quantum values in their operands is not needed anymore.
- At the beginning of the default pipeline, and at the beginning of
various xdsl tools, the following passes are added (in this order):
   - `--canonicalize`
   - `--verify-no-quantum-use-after-free`
   - `--convert-to-value-semantics`
   - `--canonicalize`

- `QubitHandler` (along with the entirety of
`from_plxpr/qubit_handler.py`, and its tests
`test_from_plxpr_qubit_handler.py`) has been removed 🥳
This was the machinery to convert reference semantics plxpr to value
semantics catxpr, but this conversion is no longer needed.
- Tests are edited correspondingly, mostly to update their expected
results to check for reference semantics, i.e. all checks that are
looking for `quantum.blah` ops in the mlir compiled from frontend now
look for `qref.blah`. There are some tests that experienced extra
updates:
1. In `pytest/from_plxpr/test_from_plxpr.py`:
- Tests comparing catxpr generated from capture and legacy frontends are
removed. They are converted to proper lit tests (under
`frontend/tests/lit/test_qref`), checking for the qref MLIR generated
from the capture path. As a result, the `compare_call_jaxpr` test util
has been removed. Note that the checks for execution results on these
tests are kept.
- Tests checking for value semantics catalyst primitives have been
updated to check for the corresponding qref primitives.
2. In `pytest/test_dynamic_qubit_alllocation.py`, dynamically allocated
qubits from outside an adjoint can now be used by the adjoint, so the
xfailed test is changed to a regular test
3. In `lit/test_from_plxpr.py`, there are many tests checking for the
value semantcis qubit extract/insert topology. I have removed these
tests as the `from_plxpr` conversion is no longer responsible for
creating the value semantics extract/insert operations.The value
semantics extract/insert op strategy is now exclusively documented and
tested in the `--convert-to-value-semantics` pass itself.

**Benefits:**
1. Significantly, and I mean truly significantly, simplifies the capture
frontend. Many plxpr primitives are used directly, which is a big step
towards lowering plxpr and removing catxpr from the pipeline altogether.
6. Many tech debts are automatically fixed. Here's an (incomplete) list:
- Adjoints can take in dynamically allocated wires [sc-102216]
- Fixes dataflow in value semantics: no longer missing an insert before
gates on dynamically indexed wires #2526
- Fixes dataflow in value semantics: no longer missing an insert before
observables on dynamically indexed wires #2527
- Passes that need to identify the qubit label does not have to walk
back all the way back up the gate chain in value semantics. For example,
judgement of non-commuting observables is much easier (to check if two
observables are on the same qubit or not).
3. Greatly improve data flow around control flow/adjoint/subroutine
regions. We no longer have to insert all qubits into their registers and
let these regions take in the registers. Frontend just generates mlir
where the regions see qref values from above via closure, and the
`--convert-to-value-semantics` pass will only create value semantics
regions that take in individual qubit values, instead of entire register
values.

**Related GitHub Issues:**
closes #2526 [sc-112704]
closes #2527 [sc-112706]

- [x] [sc-115868]: alloc and observables #2664 
- [x] [sc-115869]: gates #2672 , also handles basic dynamic qubit
allocation
- [x] [sc-115870]: for loops #2694 
- [x] [sc-115871]: while loops #2717 
- [x] [sc-115872]: if statements, also handles MCMs with reset #2740
- [x] [sc-115873]: adjoints #2720
- [x] [sc-115874]: subroutines and calls #2781 
- [x] [sc-118243] xdsl pipeline converts qref mlir to value seamntics at
the beginning #2757
- [x] [sc-119731] graph decomp frontend is reference semantics #2834 
- [x] update old frontend lit tests to check for `qref` instead of
`quantum` #2878

---------

Co-authored-by: albi3ro <chrissie.c.l@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants