From 3850cecce5d6cd384b781e40c7d1e23b1da76a18 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 16 Jan 2026 14:38:17 -0500 Subject: [PATCH 1/3] Add verifiers to quantum.paulirot op --- mlir/include/Quantum/IR/QuantumAttrDefs.td | 1 + mlir/include/Quantum/IR/QuantumOps.td | 4 ++-- mlir/lib/Quantum/IR/QuantumOps.cpp | 21 +++++++++++++++++++++ mlir/test/Quantum/VerifierTest.mlir | 17 +++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/mlir/include/Quantum/IR/QuantumAttrDefs.td b/mlir/include/Quantum/IR/QuantumAttrDefs.td index 133462bae1..716c60b2aa 100644 --- a/mlir/include/Quantum/IR/QuantumAttrDefs.td +++ b/mlir/include/Quantum/IR/QuantumAttrDefs.td @@ -38,5 +38,6 @@ def NamedObservable : I32EnumAttr<"NamedObservable", def NamedObservableAttr : EnumAttr; +def PauliWord : TypedArrayAttrBase; #endif // QUANTUM_ATTR_DEFS diff --git a/mlir/include/Quantum/IR/QuantumOps.td b/mlir/include/Quantum/IR/QuantumOps.td index 165aa880d1..8e3e4a9ad7 100644 --- a/mlir/include/Quantum/IR/QuantumOps.td +++ b/mlir/include/Quantum/IR/QuantumOps.td @@ -534,8 +534,6 @@ def CustomOp : UnitaryGate_Op<"custom", [DifferentiableGate, NoMemoryEffect, let hasVerifier = 1; } -def PauliWord : TypedArrayAttrBase; - def PauliRotOp : UnitaryGate_Op<"paulirot", [DifferentiableGate, NoMemoryEffect, AttrSizedOperandSegments, AttrSizedResultSegments]> { let summary = "Apply a Pauli Product Rotation"; @@ -571,6 +569,8 @@ def PauliRotOp : UnitaryGate_Op<"paulirot", [DifferentiableGate, NoMemoryEffect, return getODSOperands(getParamOperandIdx()); } }]; + + let hasVerifier = 1; } def GlobalPhaseOp : UnitaryGate_Op<"gphase", [DifferentiableGate, AttrSizedOperandSegments]> { diff --git a/mlir/lib/Quantum/IR/QuantumOps.cpp b/mlir/lib/Quantum/IR/QuantumOps.cpp index 47686d99e2..13dacb38c2 100644 --- a/mlir/lib/Quantum/IR/QuantumOps.cpp +++ b/mlir/lib/Quantum/IR/QuantumOps.cpp @@ -262,6 +262,27 @@ static LogicalResult verifyTensorResult(Type ty, int64_t length0, int64_t length // ----- gates +static const mlir::StringSet<> validPauliWords = {"X", "Y", "Z", "I"}; + +LogicalResult PauliRotOp::verify() +{ + size_t pauliWordLength = getPauliProduct().size(); + size_t numQubits = getInQubits().size(); + if (pauliWordLength != numQubits) { + return emitOpError() << "length of Pauli word (" << pauliWordLength + << ") and number of qubits (" << numQubits << ") must be the same"; + } + + if (!llvm::all_of(getPauliProduct(), [](mlir::Attribute attr) { + auto pauliStr = llvm::cast(attr); + return validPauliWords.contains(pauliStr.getValue()); + })) { + return emitOpError() << "Only \"X\", \"Y\", \"Z\", and \"I\" are valid Pauli words."; + } + + return success(); +} + LogicalResult QubitUnitaryOp::verify() { size_t dim = std::pow(2, getInQubits().size()); diff --git a/mlir/test/Quantum/VerifierTest.mlir b/mlir/test/Quantum/VerifierTest.mlir index f6fbb90ac1..31686aa350 100644 --- a/mlir/test/Quantum/VerifierTest.mlir +++ b/mlir/test/Quantum/VerifierTest.mlir @@ -127,6 +127,23 @@ func.func @controlled2(%1 : !quantum.bit, %2 : !quantum.bit, %3 : !quantum.bit) return } +// ----- + +func.func @test_paulirot_length_mismatch(%1 : !quantum.bit, %angle: f64) { + // expected-error@+1 {{length of Pauli word (2) and number of qubits (1) must be the same}} + %q = quantum.paulirot ["Z", "X"](%angle) %1 : !quantum.bit + return +} + +// ----- + +func.func @test_paulirot_bad_pauli_word(%1 : !quantum.bit, %angle: f64) { + // expected-error@+1 {{Only "X", "Y", "Z", and "I" are valid Pauli words.}} + %q = quantum.paulirot ["bad"](%angle) %1 : !quantum.bit + return +} + +// ----- ////////////////// // Measurements // From b7a355f9438b59c1cdf1adbb3071b3dc8ab5f6c4 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 16 Jan 2026 15:36:56 -0500 Subject: [PATCH 2/3] changelog --- doc/releases/changelog-dev.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index b082fef31f..f4254cb39a 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -13,6 +13,10 @@ program outputs are typically probabilistic and statistics produced by measurement processes are conditional on the selected decision tree path. +* Two new verifiers were added to the `quantum.paulirot` operation. They verify that the Pauli word + length and the number of qubit operands are the same, and that all of the Pauli words are legal. + [(#2405)](https://github.com/PennyLaneAI/catalyst/pull/2405) +

Breaking changes 💔

Deprecations 👋

@@ -44,6 +48,7 @@

Contributors ✍️

This release contains contributions from (in alphabetical order): -Ali Asadi +Ali Asadi, Sengthai Heng, -Jeffrey Kam. +Jeffrey Kam, +Paul Haochen Wang. From 53e49f0d6f6342da7cf9f507291677bb56d024c4 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Mon, 19 Jan 2026 13:13:02 -0500 Subject: [PATCH 3/3] CI