diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index 32b7de372d..59b4527d52 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 👋

@@ -47,7 +51,8 @@

Contributors ✍️

This release contains contributions from (in alphabetical order): -Ali Asadi +Ali Asadi, Sengthai Heng, Jeffrey Kam, -Mudit Pandey. +Mudit Pandey, +Paul Haochen Wang. 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 //