Skip to content

Add quantum.operator to Catalyst [Operator2 work]#2883

Open
dime10 wants to merge 23 commits into
mainfrom
operator2-base
Open

Add quantum.operator to Catalyst [Operator2 work]#2883
dime10 wants to merge 23 commits into
mainfrom
operator2-base

Conversation

@dime10
Copy link
Copy Markdown
Contributor

@dime10 dime10 commented May 27, 2026

Provides the new MLIR operation for advanced quantum operators as defined by this ADR. The following is provided in this PR:

  • the operation definition
  • op verifiers
  • custom assembly syntax
  • integration with the ParametrizedGate interface

Future PRs will tackle:

  • updates to existing passes (if necesary)
  • reference-semantic version of the op + conversion
  • lowering to the op from the frontend

[sc-120860]

@dime10 dime10 requested review from a team and mudit2812 May 27, 2026 19:05
@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.

@dime10 dime10 added the compiler Pull requests that update the compiler label May 27, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.90%. Comparing base (9798aa3) to head (5937954).
⚠️ Report is 36 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2883      +/-   ##
==========================================
- Coverage   97.01%   96.90%   -0.11%     
==========================================
  Files         167      166       -1     
  Lines       18828    19008     +180     
  Branches     1768     1760       -8     
==========================================
+ Hits        18266    18420     +154     
- Misses        417      433      +16     
- Partials      145      155      +10     

☔ 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.

dime10 added 2 commits May 27, 2026 16:12
Similar to qubit_map, a single param arg in python can map to multiple
parameter SSA values (e.g. with pytrees), so we need a list here.
Use this when the operator acts on a statically known set of wires. Qubits are
threaded through the op explicitly and can carry per-control values through
`in_ctrl_qubits` / `in_ctrl_values` (with matching `out_ctrl_qubits`).
This is the natural representation for fixed-arity gates and operators.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

arity?

Copy link
Copy Markdown
Contributor Author

@dime10 dime10 Jun 1, 2026

Choose a reason for hiding this comment

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

Generally, the number of inputs a mathematical operator acts on, in this case wires. Honestly we can just remove that sentence though:

Suggested change
This is the natural representation for fixed-arity gates and operators.

Comment thread mlir/lib/Quantum/IR/QuantumOps.cpp
Copy link
Copy Markdown
Contributor

@mudit2812 mudit2812 left a comment

Choose a reason for hiding this comment

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

Looks great @dime10 . My only blocking comment is about testing invalid operators with the custom format

Comment on lines +528 to +535
func.func @operator_basic_qubits(%q0 : !quantum.bit, %q1 : !quantum.bit) {
%o0, %o1 = "quantum.operator"(%q0, %q1) <{op_name = "basic_qubits", operandSegmentSizes = array<i32: 0, 0, 2, 0, 0, 0, 0, 0, 0>, resultSegmentSizes = array<i32: 2, 0, 0>}> : (!quantum.bit, !quantum.bit) -> (!quantum.bit, !quantum.bit)
return
}

//////////////////////
// quantum.operator //
//////////////////////
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
func.func @operator_basic_qubits(%q0 : !quantum.bit, %q1 : !quantum.bit) {
%o0, %o1 = "quantum.operator"(%q0, %q1) <{op_name = "basic_qubits", operandSegmentSizes = array<i32: 0, 0, 2, 0, 0, 0, 0, 0, 0>, resultSegmentSizes = array<i32: 2, 0, 0>}> : (!quantum.bit, !quantum.bit) -> (!quantum.bit, !quantum.bit)
return
}
//////////////////////
// quantum.operator //
//////////////////////
//////////////////////
// quantum.operator //
//////////////////////
func.func @operator_basic_qubits(%q0 : !quantum.bit, %q1 : !quantum.bit) {
%o0, %o1 = "quantum.operator"(%q0, %q1) <{op_name = "basic_qubits", operandSegmentSizes = array<i32: 0, 0, 2, 0, 0, 0, 0, 0, 0>, resultSegmentSizes = array<i32: 2, 0, 0>}> : (!quantum.bit, !quantum.bit) -> (!quantum.bit, !quantum.bit)
return
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just swapping test and the /////// comment

// 7. Quantum register
if (getInQreg()) {
p.printNewline();
p << "quregs(" << getInQreg() << ") indices(";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I've always found the inconsistency of using both qureg and qreg to be kind of weird. Though I haven't seem qureg(s) for operand/result names or in assembly formats before, so maybe this should just be qregs?

Suggested change
p << "quregs(" << getInQreg() << ") indices(";
p << "qregs(" << getInQreg() << ") indices(";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is purely stylistic though, so it's a non-blocking comment

Copy link
Copy Markdown
Contributor Author

@dime10 dime10 Jun 1, 2026

Choose a reason for hiding this comment

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

Yeah I share the frustration. On the one hand, "qureg" is more analogous to "qubit", on the other it is perhaps a bit more unconventional? If we look at precedent in Catalyst, the official name in the type system is QubitType and QuregType (written as quantum.bit and quantum.reg in the IR, avoiding the conundrum). qreg does appear as certain op argument/result names though, and maybe as program variables.


func.func @operator_custom_with_decompositions(%q : !quantum.bit) {
%out = quantum.operator "custom_with_decompositions"() qubits(%q)
decompositions = [@decomp_a, @decomp_b]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would've expected MLIR to have automatic verification about whether symbols exist in the IR or not. Should that be included in the verifier?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea! There is also a SymbolUser interface, although I'd have to check to see if it allows for optional symbols

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Gemini says yes, but I always take AI answers about MLIR with a grain of salt


// -----

func.func @operator_invalid_forward_args_without_uid(%fwd : i64, %q0 : !quantum.bit, %q1 : !quantum.bit) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should there be assembly format tests for this and following tests?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't think we gain from testing invalid states in custom assembly necessarily, unless the custom assembly enables invalid states that the generic form doesn't allow?

The `quantum.operator` is a generic representation for arbitrary quantum operations
that cannot be expressed by the simpler `quantum.custom` op and don't have a dedicated
operation.
It's purpose is to represent high-level operations from frontend languages such as
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
It's purpose is to represent high-level operations from frontend languages such as
Its purpose is to represent high-level operations from frontend languages such as

@paul0403
Copy link
Copy Markdown
Member

paul0403 commented Jun 5, 2026

Do you mind running make dialect-docs locally and commit the built doc files (just for QuantumOps.md is fine) too? It would be much easier to look at when reviewing 😅

Non blocking if it turns out to be too much trouble

@dime10
Copy link
Copy Markdown
Contributor Author

dime10 commented Jun 5, 2026

Do you mind running make dialect-docs locally and commit the built doc files (just for QuantumOps.md is fine) too? It would be much easier to look at when reviewing 😅

Great idea, thanks!

5937954, it hadn't been updated in a while, so there are few additional changes in there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compiler Pull requests that update the compiler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants