Skip to content

Support adjoint of operators who decompose with control flow#2667

Open
dime10 wants to merge 4 commits intomainfrom
operator_adjoint_cf_fix
Open

Support adjoint of operators who decompose with control flow#2667
dime10 wants to merge 4 commits intomainfrom
operator_adjoint_cf_fix

Conversation

@dime10
Copy link
Copy Markdown
Contributor

@dime10 dime10 commented Apr 8, 2026

Currently, something like the following fails with an error:

import pennylane as qp

class MyOperator(qp.operation.Operation):

    def decomposition(self):
        with qp.queuing.AnnotatedQueue() as q:
            _my_decomposition(self.wires)

        if qp.QueuingManager.recording():
            for op in q.queue:
                qp.apply(op)

        return q.queue

def _my_decomposition(wires, **_):

    qp.H(wires[0])

    @qp.for_loop(1, len(wires))
    def _loop(i):
        array_wires = qp.math.array(wires, like=i)
        qp.CNOT(wires=[array_wires[i - 1], array_wires[i]])

    _loop()

@qp.qjit
@qp.qnode(qp.device("lightning.qubit", wires=4))
def circuit():
    MyOperator([0, 1, 2, 3])
    qp.adjoint(MyOperator)([0, 1, 2, 3])

    return qp.state()
catalyst.utils.exceptions.CompileError: Cannot compile PennyLane inverse of the hybrid op <class 'catalyst.api_extensions.control_flow.ForLoop'>.

The reason is that the adjoint is applied directly to an operator, generating a symbolic Adjoint() op instance, whereas applying adjoint to functions generates HybridAdjoint() instances with a separate body region. While the latter has support for computing the adjoint of control flow operations in the compiler, the former (in Python PennyLane) does not.
This hasn't been a problem so far because ForLoop instances are not manipulated directly in user workflows, and so adjoint with control flow would have always generated the function version. With control flow appearing as part of decompositions however it's possible for Adjoint(ForLoop) instances to be generated now, for example when an adjointed operator like a template needs to be decomposed.

The fix consists of automatically "decomposing" Adjoint(ForLoop) into HybridAdjoint([ForLoop]). The same is done for while loops and conditionals. However, switch statements are not yet included because the adjoint algorithm in catalyst does not have support for it (since it was added later).

closes #2669
[sc-116053]

dime10 added 2 commits April 8, 2026 16:26
Catalyst doesn't accept control operations that are wrapped directly in
a symbolic Adjoint operator. However, adjoint regions with control flow
operations inside are supported. So we update the decomposition
mechanism to automatically turn operator adjoints into qfunc adjoints
when applied to control flow.
@dime10 dime10 requested a review from a team April 8, 2026 21:02
@dime10 dime10 force-pushed the operator_adjoint_cf_fix branch from 6139b06 to 2c59f3a Compare April 8, 2026 21:06
@PennyLaneAI PennyLaneAI deleted a comment from github-actions bot Apr 8, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.12%. Comparing base (a963e11) to head (5cef5c7).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2667   +/-   ##
=======================================
  Coverage   97.12%   97.12%           
=======================================
  Files         156      156           
  Lines       17733    17743   +10     
  Branches     1696     1695    -1     
=======================================
+ Hits        17223    17233   +10     
  Misses        373      373           
  Partials      137      137           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Member

@paul0403 paul0403 left a comment

Choose a reason for hiding this comment

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

Nice!

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.

Templates with control flow decompositions cannot be adjointed

2 participants