fix: reject quantum.adjoint input in ppr-to-ppm with a clear error#3020
fix: reject quantum.adjoint input in ppr-to-ppm with a clear error#3020mvanhorn wants to merge 2 commits into
Conversation
The ppr-to-ppm pass converts PPR ops into Pauli product measurement (pbc.ppm) ops, which the adjoint-lowering pass cannot reverse. When the input contained a quantum.adjoint region, the later adjoint-lowering walk hit a raw IRMapping assertion instead of a clear error. Guard PPRToPPMPass::runOnOperation to walk for a quantum.adjoint op and emit a clear diagnostic before any PPMs are generated, then fail the pass. Adds an MLIR lit test asserting the diagnostic and a changelog entry. Fixes PennyLaneAI#2934 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QXwvFKU1BuKiw1hKwr8fwC
|
Hi @mvanhorn, welcome to Catalyst, and thanks for the PR! 🎉 The team will review shortly. The changes looks good overall, but just one thing to flag for discussion. While I think the input rejection at the Also note that to be compliant with our policy you must label the AI agent used to assist you in the PR description. |
Generalize the reverse-pass guard so any operation left unhandled that produces or consumes quantum values (including non-Quantum-dialect ops such as pbc.ppm) emits a clear diagnostic and fails the pass, instead of falling through to a raw IRMapping assertion. Purely classical ops are still skipped. Adds a lit test and a changelog entry for PennyLaneAI#2934.
|
Good call, and agreed the adjoint-lowering pass is the right place for the general fix. Pushed in 1010942: the reverse-pass dispatch now emits a clear error for any op it leaves unhandled that produces or consumes quantum values, including non-Quantum-dialect ops like pbc.ppm, instead of falling through to the raw IRMapping assertion. Purely classical ops are still skipped, so it only fires on ops that actually participate in the quantum data flow. That covers the case @dime10 raised where another user pass introduces incompatible ops, not just ppr-to-ppm. I kept the ppr-to-ppm guard too since it gives an earlier, more specific message. Added a lit test with a pbc.ppm inside a quantum.adjoint region asserting the diagnostic, plus a changelog entry. clang-format is clean; I could not run the MLIR lit/build locally (no LLVM build in my environment), so I am relying on CI for that. Also added the AI-tool disclosure to the PR description per your policy. |
|
Thank you for working on this issue! I think where we landed on is that the PBC conversion needs to be better built out as a change in representation: from the generic gate model (quantum dialect) to the pauli-based representation (pbc dialect). Right it now, it is a basic pass that targets PPR gates from certain quantum ops. Adding a narrow check for adjoint op is helpful, but doesn't exactly fix the broader issue. Roughly, I had the following in mind:
|
|
That framing makes sense to me, and I'd rather build it the right way than bolt adjoint on as a special case. Reworking it as a full quantum -> pbc semantic conversion (renaming the pass and updating the docs to match) sounds like the right direction. On allowlist vs blocklist - agreed, and for exactly the reason you gave: a blocklist silently rots every time the quantum dialect gains an op, since nobody adding a new op is thinking about the PBC conversion. I'll switch to an allowlist of ops we know how to convert ( The part I'd like your steer on is the automatic conversion steps:
Once I know your preference on those two I'll rework the pass accordingly. |
|
@mehrdad2m Any thoughts here? |
|
Before submitting
All new functions and code must be clearly commented and documented.
Ensure that code is properly formatted by running
make format.All new features must include a unit test.
Context:
As reported in #2934, applying the
to_pprand thenppr-to-ppmtransforms to a circuit thatcontains a functional adjoint (e.g.
qp.adjoint(lambda: qp.S(0))()) crashes the compiler with araw MLIR assertion:
surfaced to the user as
CompileError: catalyst failed with error code -6.The root cause is a pass-ordering interaction. The default
quantum-compilation-pipelinerunsadjoint-loweringautomatically after the user transforms, and that pass reverses aquantum.adjointregion by walking its ops.
adjoint-loweringcan reversepbc.pprops (seemlir/test/PBC/AdjointTest.mlir), but onceppr-to-ppmhas turned the region's PPRs into Pauliproduct measurement (
pbc.ppm) ops, those measurements are not reversible, so the reversal hits theIRMappingassertion instead of reporting anything actionable.Description of the Change:
Following the maintainer's direction on the issue to tighten the pass's input requirements at the
start of the PBC conversion rather than failing later, this adds an input-validation guard at the
very start of
PPRToPPMPass::runOnOperation, before any patterns are applied. The pass now walksits operation for a
quantum.adjointop and, if one is found, emits a clear error explaining thatppr-to-ppmcannot be applied inside aquantum.adjointregion because the resulting Pauli productmeasurements cannot be adjoint-lowered, then signals pass failure.
The guard is scoped to
ppr-to-ppmonly;to_pprproduces PPRs, whichadjoint-loweringhandlescorrectly, and is left unchanged.
A lit test is added to
mlir/test/PBC/PPRToPPM.mlirthat wraps apbc.pprin aquantum.adjointregion and asserts, via
-verify-diagnostics, that the pass emits the new diagnostic and failscleanly instead of asserting.
Benefits:
A malformed input that previously aborted the compiler with an internal assertion (
error code -6)now produces a clear, actionable diagnostic that names the unsupported construct and the location of
the offending op.
Possible Drawbacks:
The guard is deliberately conservative: any
quantum.adjointop reachingppr-to-ppmis rejected,matching the maintainer's "no unexpected ops through the pass" framing, rather than attempting to
detect whether a given adjoint region would in fact receive generated measurements.
Related GitHub Issues:
Fixes #2934
AI tool disclosure (per the PennyLane AI Tool Use Policy): this contribution was developed with AI assistance (Claude Code, and Codex for follow-up revisions). I reviewed all generated code and text, wrote this description myself, and am accountable for the work as its author. Happy to answer questions about the implementation during review.