Skip to content

fix(capture): distinguish operator tracers from tensor data - #10156

Merged
andrijapau merged 24 commits into
mainfrom
fix/mixed-op-arith
Oct 20, 2026
Merged

andrijapau merged 24 commits into
mainfrom
fix/mixed-op-arith

Conversation

@andrijapau

@andrijapau andrijapau commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Note

Partner PR in Catalyst: PennyLaneAI/catalyst#3371 that removes xfails

Context:

During capture, PennyLane treated some operators as scalar values. This added an unwanted Identity and broke expressions such as qp.Y(0) @ qp.X(1) + 3 * qp.X(2) (sc-130866).

Description of the Change:

  • Distinguish captured operators from tensor data.
  • Keep runtime checks working on Python 3.12 while preserving support for static type checkers.
  • Remove the unused InterfaceTensor helper.
  • Handle mixed operator arithmetic and reject unsupported operands.
  • Add regression tests and explain what can be simplified after Python 3.12 support ends.

Benefits:

Fixes mixed operator arithmetic during capture without losing Python 3.12 or static typing support.

Possible Drawbacks:

Code that inspects TensorLike at runtime will now see a class instead of a union. The runtime checks and static type definition must be kept in sync.

AI Assistance:

Developed with assistance from OpenAI Codex.

[sc-130866]

Comment thread doc/releases/changelog-dev.md Outdated
Co-authored-by: Andrija Paurevic <46359773+andrijapau@users.noreply.github.com>
@codecov

codecov Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.44%. Comparing base (962a77d) to head (89dce74).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #10156      +/-   ##
==========================================
- Coverage   99.44%   99.44%   -0.01%     
==========================================
  Files         617      617              
  Lines       68032    68037       +5     
==========================================
+ Hits        67652    67656       +4     
- Misses        380      381       +1     

☔ View full report in Codecov by Harness.
📢 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.

@andrijapau andrijapau added the WIP 🚧 Work-in-progress label Sep 16, 2026
andrijapau added a commit to PennyLaneAI/catalyst that referenced this pull request Sep 16, 2026
**Context:**

Two PRs from PennyLane caused failures:

- PennyLaneAI/pennylane#10113 
- Issue (JukeBox support): The observable in the test is `qp.Y(0) @
qp.X(1) + 3 * qp.X(2)`. Under capture, the two halves now have different
Python types:
        ```
left = Prod2 isinstance(Operator)=True <- Operator2 returns an instance
right = DynamicJaxprTracer isinstance(Operator)=False <- Operator1 SProd
returns a tracer
        ```
Before #10113, `Y(0) @ X(1)` produced a legacy `Prod`, so both sides
were tracers and + went through `AbstractOperator._add`. Now the left
side is a real `Prod2`, so Python calls `Operator2.__add__`, which tests
in this order:
        ```
if isinstance(other, Operator): # False for an operator-valued tracer
            return qp.sum(self, other, lazy=False)
if isinstance(other, TensorLike): # True -- a JAX tracer is TensorLike
return qp.sum(self, qp.s_prod(scalar=other,
operator=qp.Identity(self.wires), lazy=False), ...)
        ```
So the right-hand operator gets used as a scalar coefficient, producing
`SProd(scalar=<operator tracer>, base=Identity([0,1]))`, a stray
Identity appears in the plxpr. That is silent at capture time. It
explodes when Catalyst's from_plxpr re-traces: `Sum._build_pauli_rep`
evaluates `new_rep[pw] += coeff` with `coeff` being that operator
tracer, `0.0 + tracer` defers to `AbstractOperator._radd`, which doesn't
exist.

- Fix: Requires changes in PennyLane:
PennyLaneAI/pennylane#10156
- PennyLaneAI/pennylane#10144
    - Issue: Gave a `DecompositionRule` a name dunder
- Fix: Adjust stale test and add a new one to ensure proper behaviour.

[sc-130870]
@andrijapau andrijapau changed the title fix mixed op arithmetic to unblock LLL fix mixed op1 and op2 arithmetic Oct 14, 2026
@andrijapau andrijapau changed the title fix mixed op1 and op2 arithmetic fix(capture): treat operator tracers as operators in Operator2 Oct 20, 2026
@andrijapau andrijapau changed the title fix(capture): treat operator tracers as operators in Operator2 fix(capture): don't treat captured operators as scalars in Operator2 +/- Oct 20, 2026
@andrijapau andrijapau changed the title fix(capture): don't treat captured operators as scalars in Operator2 +/- fix(capture): exclude AbstractOperator tracers from TensorLike Oct 20, 2026
@andrijapau andrijapau changed the title fix(capture): exclude AbstractOperator tracers from TensorLike fix(capture): distinguish operator tracers from tensor data Oct 20, 2026
@andrijapau andrijapau added review-ready 👌 PRs which are ready for review by someone from the core team. and removed WIP 🚧 Work-in-progress labels Oct 20, 2026
@andrijapau
andrijapau requested a review from mudit2812 October 20, 2026 19:26

@mudit2812 mudit2812 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Happy to approve once the imports are top-level in the tests

Comment thread tests/test_typing.py Outdated
@andrijapau
andrijapau added this pull request to the merge queue Oct 20, 2026
Merged via the queue into main with commit 1806cda Oct 20, 2026
54 checks passed
@andrijapau
andrijapau deleted the fix/mixed-op-arith branch October 20, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-ready 👌 PRs which are ready for review by someone from the core team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants