From 811b6ebd58115f4b2e6b483aa16cae67c1590a02 Mon Sep 17 00:00:00 2001 From: Joey Carter Date: Tue, 11 Nov 2025 17:32:52 -0500 Subject: [PATCH 1/7] Initial commit --- mlir/include/CMakeLists.txt | 1 + mlir/include/PauliFrame/CMakeLists.txt | 2 + mlir/include/PauliFrame/IR/CMakeLists.txt | 5 + .../include/PauliFrame/IR/PauliFrameDialect.h | 31 +++++ .../PauliFrame/IR/PauliFrameDialect.td | 79 +++++++++++ mlir/include/PauliFrame/IR/PauliFrameOps.h | 30 +++++ mlir/include/PauliFrame/IR/PauliFrameOps.td | 126 ++++++++++++++++++ .../PauliFrame/Transforms/CMakeLists.txt | 4 + mlir/lib/CMakeLists.txt | 1 + mlir/lib/PauliFrame/CMakeLists.txt | 2 + mlir/lib/PauliFrame/IR/CMakeLists.txt | 10 ++ mlir/lib/PauliFrame/IR/PauliFrameDialect.cpp | 61 +++++++++ mlir/lib/PauliFrame/IR/PauliFrameOps.cpp | 28 ++++ mlir/test/PauliFrame/ConversionTest.mlir | 0 mlir/test/PauliFrame/DialectTest.mlir | 0 15 files changed, 380 insertions(+) create mode 100644 mlir/include/PauliFrame/CMakeLists.txt create mode 100644 mlir/include/PauliFrame/IR/CMakeLists.txt create mode 100644 mlir/include/PauliFrame/IR/PauliFrameDialect.h create mode 100644 mlir/include/PauliFrame/IR/PauliFrameDialect.td create mode 100644 mlir/include/PauliFrame/IR/PauliFrameOps.h create mode 100644 mlir/include/PauliFrame/IR/PauliFrameOps.td create mode 100644 mlir/include/PauliFrame/Transforms/CMakeLists.txt create mode 100644 mlir/lib/PauliFrame/CMakeLists.txt create mode 100644 mlir/lib/PauliFrame/IR/CMakeLists.txt create mode 100644 mlir/lib/PauliFrame/IR/PauliFrameDialect.cpp create mode 100644 mlir/lib/PauliFrame/IR/PauliFrameOps.cpp create mode 100644 mlir/test/PauliFrame/ConversionTest.mlir create mode 100644 mlir/test/PauliFrame/DialectTest.mlir diff --git a/mlir/include/CMakeLists.txt b/mlir/include/CMakeLists.txt index 85180214a9..3107f2b8e9 100644 --- a/mlir/include/CMakeLists.txt +++ b/mlir/include/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(hlo-extensions) add_subdirectory(Ion) add_subdirectory(MBQC) add_subdirectory(Mitigation) +add_subdirectory(PauliFrame) add_subdirectory(QEC) add_subdirectory(Quantum) add_subdirectory(Test) diff --git a/mlir/include/PauliFrame/CMakeLists.txt b/mlir/include/PauliFrame/CMakeLists.txt new file mode 100644 index 0000000000..68ac6312e7 --- /dev/null +++ b/mlir/include/PauliFrame/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(IR) +# add_subdirectory(Transforms) diff --git a/mlir/include/PauliFrame/IR/CMakeLists.txt b/mlir/include/PauliFrame/IR/CMakeLists.txt new file mode 100644 index 0000000000..86d7dada36 --- /dev/null +++ b/mlir/include/PauliFrame/IR/CMakeLists.txt @@ -0,0 +1,5 @@ +add_mlir_dialect(PauliFrameOps pauli_frame) +add_mlir_doc(PauliFrameDialect PauliFrameDialect PauliFrame/ -gen-dialect-doc -gen-op-doc) +add_mlir_doc(PauliFrameOps PauliFrameOps PauliFrame/ -gen-op-doc) + +set(LLVM_TARGET_DEFINITIONS PauliFrameOps.td) diff --git a/mlir/include/PauliFrame/IR/PauliFrameDialect.h b/mlir/include/PauliFrame/IR/PauliFrameDialect.h new file mode 100644 index 0000000000..611b5e3f39 --- /dev/null +++ b/mlir/include/PauliFrame/IR/PauliFrameDialect.h @@ -0,0 +1,31 @@ +// Copyright 2025 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "mlir/IR/Dialect.h" + +//===----------------------------------------------------------------------===// +// PauliFrame dialect declarations. +//===----------------------------------------------------------------------===// + +#include "PauliFrame/IR/PauliFrameOpsDialect.h.inc" + +//===----------------------------------------------------------------------===// +// PauliFrame type declarations. +//===----------------------------------------------------------------------===// + +/// Uncomment the lines below if defining types for the PauliFrame dialect +// #define GET_TYPEDEF_CLASSES +// #include "PauliFrame/IR/PauliFrameOpsTypes.h.inc" diff --git a/mlir/include/PauliFrame/IR/PauliFrameDialect.td b/mlir/include/PauliFrame/IR/PauliFrameDialect.td new file mode 100644 index 0000000000..fe88ed9d14 --- /dev/null +++ b/mlir/include/PauliFrame/IR/PauliFrameDialect.td @@ -0,0 +1,79 @@ +// Copyright 2025 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PAULI_FRAME_DIALECT +#define PAULI_FRAME_DIALECT + +include "mlir/IR/DialectBase.td" +include "mlir/IR/OpBase.td" + +//===----------------------------------------------------------------------===// +// PauliFrame dialect definition. +//===----------------------------------------------------------------------===// + +def PauliFrame_Dialect : Dialect { + let summary = "A dialect for Pauli frame tracking."; + let description = [{ + The Pauli frame tracking dialect includes a set of abstractions and operations for + interacting with an external Pauli frame tracking library. A *Pauli frame tracker* [1] is a + system that tracks gates from the Pauli group in classical electronics instead of applying + them to qubits on the device. Doing so reduces the number of quantum operations applied to + the system, thus reducing the probability of errors. + + [1] Knill, E. Quantum computing with realistically noisy devices. Nature 434, 39-44 (2005). + https://doi.org/10.1038/nature03350. + + > [!IMPORTANT] + > The pauli_frame dialect is experimental and and will not maintain API stability between releases. + > Use at your own risk. + }]; + + /// This is the namespace of the dialect in MLIR, which is used as a prefix for types and ops. + let name = "pauli_frame"; + + /// This is the C++ namespace in which the dialect and all of its sub-components are placed. + let cppNamespace = "::catalyst::pauli_frame"; + + let dependentDialects = [ + "quantum::QuantumDialect" + ]; + + /// Use the default type printing/parsing hooks, otherwise we would have to explicitly define them. + let useDefaultAttributePrinterParser = 1; + + /// Uncomment the line below if defining types for the PauliFrame dialect + // let useDefaultTypePrinterParser = 1; +} + + +//===----------------------------------------------------------------------===// +// PauliFrame dialect types. +//===----------------------------------------------------------------------===// + +/// Uncomment the lines below if defining types for the PauliFrame dialect +// class PauliFrame_Type traits = []> +// : TypeDef { +// let mnemonic = typeMnemonic; +// } + + +//===----------------------------------------------------------------------===// +// PauliFrame dialect base operation. +//===----------------------------------------------------------------------===// + +class PauliFrame_Op traits = []> : + Op; + + +#endif // PAULI_FRAME_DIALECT diff --git a/mlir/include/PauliFrame/IR/PauliFrameOps.h b/mlir/include/PauliFrame/IR/PauliFrameOps.h new file mode 100644 index 0000000000..46661d0900 --- /dev/null +++ b/mlir/include/PauliFrame/IR/PauliFrameOps.h @@ -0,0 +1,30 @@ +// Copyright 2025 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Quantum/IR/QuantumDialect.h" + +#include "PauliFrame/IR/PauliFrameDialect.h" + +//===----------------------------------------------------------------------===// +// PauliFrame ops declarations. +//===----------------------------------------------------------------------===// + +/// Uncomment the lines below if defining attributes for the PauliFrame dialect +// #define GET_ATTRDEF_CLASSES +// #include "PauliFrame/IR/PauliFrameAttributes.h.inc" + +#define GET_OP_CLASSES +#include "PauliFrame/IR/PauliFrameOps.h.inc" diff --git a/mlir/include/PauliFrame/IR/PauliFrameOps.td b/mlir/include/PauliFrame/IR/PauliFrameOps.td new file mode 100644 index 0000000000..3d5fd5a617 --- /dev/null +++ b/mlir/include/PauliFrame/IR/PauliFrameOps.td @@ -0,0 +1,126 @@ +// Copyright 2025 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PAULI_FRAME_OPS +#define PAULI_FRAME_OPS + +include "mlir/IR/AttrTypeBase.td" +include "mlir/IR/EnumAttr.td" + +include "Quantum/IR/QuantumDialect.td" + +include "PauliFrame/IR/PauliFrameDialect.td" + +//===----------------------------------------------------------------------===// +// PauliFrame dialect enums. +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// PauliFrame dialect traits. +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// PauliFrame dialect attributes. +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// PauliFrame dialect operations. +//===----------------------------------------------------------------------===// + +def SetRecordOp : PauliFrame_Op<"set_record"> { + let summary = "Set the Pauli record of the target qubit(s)"; + let description = [{ + Set the Pauli record of the target qubit(s). + }]; + + let arguments = (ins + Variadic:$in_qubits, + I1:$x_parity, + I1:$z_parity + ); + + let results = (outs + Variadic:$out_qubits + ); + + let assemblyFormat = [{ + `[` $x_parity `,` $z_parity `]` $in_qubits attr-dict `:` type(results) + }]; +} + +def ReadRecordOp : PauliFrame_Op<"read_record"> { + let summary = "Read the Pauli record of the target qubit(s)"; + let description = [{ + Read the Pauli record of the target qubit(s). + }]; + + let arguments = (ins + Variadic:$in_qubits + ); + + let results = (outs + I1:$x_parity, + I1:$z_parity, + Variadic:$out_qubits + ); + + let assemblyFormat = [{ + $in_qubits attr-dict `:` type(results) + }]; +} + +def CorrectMeasurementOp : PauliFrame_Op<"correct_measurement"> { + let summary = "Correct the measurement result given the Pauli record"; + let description = [{ + Correct the measurement result given the Pauli record. + }]; + + let arguments = (ins + I1:$x_parity, + I1:$z_parity, + I1:$in_mres + ); + + let results = (outs + I1:$out_mres + ); + + let assemblyFormat = [{ + `[` $x_parity `,` $z_parity `]` $in_mres attr-dict `:` type(results) + }]; +} + +def FlushRecordOp : PauliFrame_Op<"flush_record"> { + let summary = "Flush the Pauli record(s) of the target qubit(s)"; + let description = [{ + Flush the Pauli record(s) of the target qubit(s). + }]; + + let arguments = (ins + Variadic:$in_qubits + ); + + let results = (outs + Variadic:$out_qubits + ); + + let assemblyFormat = [{ + $in_qubits attr-dict `:` type(results) + }]; +} + +#endif // PAULI_FRAME_OPS diff --git a/mlir/include/PauliFrame/Transforms/CMakeLists.txt b/mlir/include/PauliFrame/Transforms/CMakeLists.txt new file mode 100644 index 0000000000..12b38e7d69 --- /dev/null +++ b/mlir/include/PauliFrame/Transforms/CMakeLists.txt @@ -0,0 +1,4 @@ +set(LLVM_TARGET_DEFINITIONS Passes.td) +mlir_tablegen(Passes.h.inc -gen-pass-decls -name PauliFrame) +add_public_tablegen_target(MLIRPauliFramePassIncGen) +add_mlir_doc(Passes PauliFramePasses ./ -gen-pass-doc) diff --git a/mlir/lib/CMakeLists.txt b/mlir/lib/CMakeLists.txt index 687046ef64..71f74ad71a 100644 --- a/mlir/lib/CMakeLists.txt +++ b/mlir/lib/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(hlo-extensions) add_subdirectory(Ion) add_subdirectory(MBQC) add_subdirectory(Mitigation) +add_subdirectory(PauliFrame) add_subdirectory(QEC) add_subdirectory(Quantum) add_subdirectory(Test) diff --git a/mlir/lib/PauliFrame/CMakeLists.txt b/mlir/lib/PauliFrame/CMakeLists.txt new file mode 100644 index 0000000000..68ac6312e7 --- /dev/null +++ b/mlir/lib/PauliFrame/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(IR) +# add_subdirectory(Transforms) diff --git a/mlir/lib/PauliFrame/IR/CMakeLists.txt b/mlir/lib/PauliFrame/IR/CMakeLists.txt new file mode 100644 index 0000000000..2b29473c33 --- /dev/null +++ b/mlir/lib/PauliFrame/IR/CMakeLists.txt @@ -0,0 +1,10 @@ +add_mlir_library(MLIRPauliFrame + PauliFrameDialect.cpp + PauliFrameOps.cpp + + ADDITIONAL_HEADER_DIRS + ${PROJECT_SOURCE_DIR}/include/PauliFrame + + DEPENDS + MLIRPauliFrameOpsIncGen +) diff --git a/mlir/lib/PauliFrame/IR/PauliFrameDialect.cpp b/mlir/lib/PauliFrame/IR/PauliFrameDialect.cpp new file mode 100644 index 0000000000..7553596b0f --- /dev/null +++ b/mlir/lib/PauliFrame/IR/PauliFrameDialect.cpp @@ -0,0 +1,61 @@ +// Copyright 2025 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "mlir/IR/Builders.h" +#include "mlir/IR/DialectImplementation.h" // needed for generated type parser +#include "llvm/ADT/TypeSwitch.h" // needed for generated type parser + +#include "PauliFrame/IR/PauliFrameDialect.h" +#include "PauliFrame/IR/PauliFrameOps.h" + +using namespace mlir; +using namespace catalyst::pauli_frame; + +//===----------------------------------------------------------------------===// +// PauliFrame dialect definitions. +//===----------------------------------------------------------------------===// + +#include "PauliFrame/IR/PauliFrameOpsDialect.cpp.inc" + +void PauliFrameDialect::initialize() +{ + /// Uncomment the lines below if defining types for the PauliFrame dialect + // addTypes< + // #define GET_TYPEDEF_LIST + // #include "PauliFrame/IR/PauliFrameOpsTypes.cpp.inc" + // >(); + + /// Uncomment the lines below if defining attributes for the PauliFrame dialect + // addAttributes< + // #define GET_ATTRDEF_LIST + // #include "PauliFrame/IR/PauliFrameAttributes.cpp.inc" + // >(); + + addOperations< +#define GET_OP_LIST +#include "PauliFrame/IR/PauliFrameOps.cpp.inc" + >(); +} + +//===----------------------------------------------------------------------===// +// PauliFrame type definitions. +//===----------------------------------------------------------------------===// + +/// Uncomment the lines below if defining types for the PauliFrame dialect +// #define GET_TYPEDEF_CLASSES +// #include "PauliFrame/IR/PauliFrameOpsTypes.cpp.inc" + +/// Uncomment the lines below if defining attributes for the PauliFrame dialect +// #define GET_ATTRDEF_CLASSES +// #include "PauliFrame/IR/PauliFrameAttributes.cpp.inc" diff --git a/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp b/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp new file mode 100644 index 0000000000..bec9ebe4e3 --- /dev/null +++ b/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp @@ -0,0 +1,28 @@ +// Copyright 2025 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "mlir/IR/Builders.h" + +#include "PauliFrame/IR/PauliFrameDialect.h" +#include "PauliFrame/IR/PauliFrameOps.h" + +using namespace mlir; +using namespace catalyst::pauli_frame; + +//===----------------------------------------------------------------------===// +// PauliFrame op definitions. +//===----------------------------------------------------------------------===// + +#define GET_OP_CLASSES +#include "PauliFrame/IR/PauliFrameOps.cpp.inc" diff --git a/mlir/test/PauliFrame/ConversionTest.mlir b/mlir/test/PauliFrame/ConversionTest.mlir new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mlir/test/PauliFrame/DialectTest.mlir b/mlir/test/PauliFrame/DialectTest.mlir new file mode 100644 index 0000000000..e69de29bb2 From a8197860f1fc49bea09492fc469091411a9644b4 Mon Sep 17 00:00:00 2001 From: Joey Carter Date: Wed, 12 Nov 2025 11:42:08 -0500 Subject: [PATCH 2/7] Remove PauliFrame ConversionTest.mlir This will come later... --- mlir/test/PauliFrame/ConversionTest.mlir | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 mlir/test/PauliFrame/ConversionTest.mlir diff --git a/mlir/test/PauliFrame/ConversionTest.mlir b/mlir/test/PauliFrame/ConversionTest.mlir deleted file mode 100644 index e69de29bb2..0000000000 From b815a220bb38c54c7ce7698f3fa839d6fce67d9e Mon Sep 17 00:00:00 2001 From: Joey Carter Date: Wed, 12 Nov 2025 14:47:27 -0500 Subject: [PATCH 3/7] Add verifiers, dialect tests and other infra --- .../PauliFrame/IR/PauliFrameDialect.td | 3 +- mlir/include/PauliFrame/IR/PauliFrameOps.td | 14 ++-- mlir/lib/PauliFrame/IR/PauliFrameOps.cpp | 26 +++++++ mlir/test/CMakeLists.txt | 1 + mlir/test/PauliFrame/DialectTest.mlir | 70 +++++++++++++++++++ mlir/tools/catalyst-cli/CMakeLists.txt | 2 + mlir/tools/quantum-lsp-server/CMakeLists.txt | 1 + .../quantum-lsp-server/quantum-lsp-server.cpp | 2 + mlir/tools/quantum-opt/CMakeLists.txt | 2 + mlir/tools/quantum-opt/quantum-opt.cpp | 2 + 10 files changed, 117 insertions(+), 6 deletions(-) diff --git a/mlir/include/PauliFrame/IR/PauliFrameDialect.td b/mlir/include/PauliFrame/IR/PauliFrameDialect.td index fe88ed9d14..1e9c36efac 100644 --- a/mlir/include/PauliFrame/IR/PauliFrameDialect.td +++ b/mlir/include/PauliFrame/IR/PauliFrameDialect.td @@ -50,7 +50,8 @@ def PauliFrame_Dialect : Dialect { ]; /// Use the default type printing/parsing hooks, otherwise we would have to explicitly define them. - let useDefaultAttributePrinterParser = 1; + /// Uncomment the line below if defining attributes for the PauliFrame dialect + // let useDefaultAttributePrinterParser = 1; /// Uncomment the line below if defining types for the PauliFrame dialect // let useDefaultTypePrinterParser = 1; diff --git a/mlir/include/PauliFrame/IR/PauliFrameOps.td b/mlir/include/PauliFrame/IR/PauliFrameOps.td index 3d5fd5a617..f408cde6a9 100644 --- a/mlir/include/PauliFrame/IR/PauliFrameOps.td +++ b/mlir/include/PauliFrame/IR/PauliFrameOps.td @@ -60,26 +60,28 @@ def SetRecordOp : PauliFrame_Op<"set_record"> { let assemblyFormat = [{ `[` $x_parity `,` $z_parity `]` $in_qubits attr-dict `:` type(results) }]; + + let hasVerifier = 1; } def ReadRecordOp : PauliFrame_Op<"read_record"> { - let summary = "Read the Pauli record of the target qubit(s)"; + let summary = "Read the Pauli record of the target qubit"; let description = [{ - Read the Pauli record of the target qubit(s). + Read the Pauli record of the target qubit. }]; let arguments = (ins - Variadic:$in_qubits + QubitType:$in_qubit ); let results = (outs I1:$x_parity, I1:$z_parity, - Variadic:$out_qubits + QubitType:$out_qubit ); let assemblyFormat = [{ - $in_qubits attr-dict `:` type(results) + $in_qubit attr-dict `:` type(results) }]; } @@ -121,6 +123,8 @@ def FlushRecordOp : PauliFrame_Op<"flush_record"> { let assemblyFormat = [{ $in_qubits attr-dict `:` type(results) }]; + + let hasVerifier = 1; } #endif // PAULI_FRAME_OPS diff --git a/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp b/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp index bec9ebe4e3..6611c61632 100644 --- a/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp +++ b/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp @@ -26,3 +26,29 @@ using namespace catalyst::pauli_frame; #define GET_OP_CLASSES #include "PauliFrame/IR/PauliFrameOps.cpp.inc" + +//===----------------------------------------------------------------------===// +// PauliFrame op verifiers. +//===----------------------------------------------------------------------===// + +LogicalResult SetRecordOp::verify() +{ + if (getInQubits().size() == 0) { + return emitOpError("expected to have at least one qubit"); + } + if (getInQubits().size() != getOutQubits().size()) { + return emitOpError("expected to consume and return the same number of qubits"); + } + return success(); +} + +LogicalResult FlushRecordOp::verify() +{ + if (getInQubits().size() == 0) { + return emitOpError("expected to have at least one qubit"); + } + if (getInQubits().size() != getOutQubits().size()) { + return emitOpError("expected to consume and return the same number of qubits"); + } + return success(); +} diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt index 06339bc7ec..0e973a5d3f 100644 --- a/mlir/test/CMakeLists.txt +++ b/mlir/test/CMakeLists.txt @@ -25,6 +25,7 @@ set(TEST_SUITES Catalyst Ion MBQC + PauliFrame cli QEC ) diff --git a/mlir/test/PauliFrame/DialectTest.mlir b/mlir/test/PauliFrame/DialectTest.mlir index e69de29bb2..f2b1220c0f 100644 --- a/mlir/test/PauliFrame/DialectTest.mlir +++ b/mlir/test/PauliFrame/DialectTest.mlir @@ -0,0 +1,70 @@ +// Copyright 2025 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// RUN: quantum-opt --split-input-file --verify-diagnostics %s + +func.func @test_set_record_single_qubit(%q0 : !quantum.bit) { + %0 = arith.constant 0 : i1 + %1 = arith.constant 1 : i1 + %q1 = pauli_frame.set_record [%0, %0] %q0 : !quantum.bit + %q2 = pauli_frame.set_record [%0, %1] %q1 : !quantum.bit + %q3 = pauli_frame.set_record [%1, %0] %q2 : !quantum.bit + %q4 = pauli_frame.set_record [%1, %1] %q3 : !quantum.bit + func.return +} + +// ----- + +func.func @test_set_record_multi_qubit(%q00 : !quantum.bit, %q10 : !quantum.bit) { + %0 = arith.constant 0 : i1 + %1 = arith.constant 1 : i1 + %q01, %q11 = pauli_frame.set_record [%0, %0] %q00, %q10 : !quantum.bit, !quantum.bit + %q02, %q12 = pauli_frame.set_record [%0, %1] %q01, %q11 : !quantum.bit, !quantum.bit + %q03, %q13 = pauli_frame.set_record [%1, %0] %q02, %q12 : !quantum.bit, !quantum.bit + %q04, %q14 = pauli_frame.set_record [%1, %1] %q03, %q13 : !quantum.bit, !quantum.bit + func.return +} + +// ----- + +func.func @test_read_record(%q0 : !quantum.bit) { + %record_x, %record_z, %out_qubit = pauli_frame.read_record %q0 : i1, i1, !quantum.bit + func.return +} + +// ----- + +func.func @test_correct_measurement(%mres : i1) { + %0 = arith.constant 0 : i1 + %1 = arith.constant 1 : i1 + %out_mres_0 = pauli_frame.correct_measurement [%0, %0] %mres : i1 + %out_mres_1 = pauli_frame.correct_measurement [%0, %1] %mres : i1 + %out_mres_2 = pauli_frame.correct_measurement [%1, %0] %mres : i1 + %out_mres_3 = pauli_frame.correct_measurement [%1, %1] %mres : i1 + func.return +} + +// ----- + +func.func @test_flush_record_single_qubit(%q0 : !quantum.bit) { + %q1 = pauli_frame.flush_record %q0 : !quantum.bit + func.return +} + +// ----- + +func.func @test_flush_record_multi_qubit(%q00 : !quantum.bit, %q10 : !quantum.bit) { + %q01, %q11 = pauli_frame.flush_record %q00, %q10 : !quantum.bit, !quantum.bit + func.return +} diff --git a/mlir/tools/catalyst-cli/CMakeLists.txt b/mlir/tools/catalyst-cli/CMakeLists.txt index 1dd3d9693d..a6ecd22ca4 100644 --- a/mlir/tools/catalyst-cli/CMakeLists.txt +++ b/mlir/tools/catalyst-cli/CMakeLists.txt @@ -38,6 +38,8 @@ set(LIBS mbqc-transforms MLIRMitigation mitigation-transforms + MLIRPauliFrame + # pauli-frame-transforms MLIRIon ion-transforms MLIRCatalystTest diff --git a/mlir/tools/quantum-lsp-server/CMakeLists.txt b/mlir/tools/quantum-lsp-server/CMakeLists.txt index 507480ef00..9ec8860f5e 100644 --- a/mlir/tools/quantum-lsp-server/CMakeLists.txt +++ b/mlir/tools/quantum-lsp-server/CMakeLists.txt @@ -12,6 +12,7 @@ set(LIBS MLIRGradient MLIRMBQC MLIRMitigation + MLIRPauliFrame MLIRIon ) diff --git a/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp b/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp index a98de69942..f89ca70198 100644 --- a/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp +++ b/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp @@ -21,6 +21,7 @@ #include "Ion/IR/IonDialect.h" #include "MBQC/IR/MBQCDialect.h" #include "Mitigation/IR/MitigationDialect.h" +#include "PauliFrame/IR/PauliFrameDialect.h" #include "QEC/IR/QECDialect.h" #include "Quantum/IR/QuantumDialect.h" @@ -36,6 +37,7 @@ int main(int argc, char **argv) registry.insert(); registry.insert(); registry.insert(); + registry.insert(); registry.insert(); mlir::stablehlo::registerAllDialects(registry); diff --git a/mlir/tools/quantum-opt/CMakeLists.txt b/mlir/tools/quantum-opt/CMakeLists.txt index 617398b03c..34c67d192c 100644 --- a/mlir/tools/quantum-opt/CMakeLists.txt +++ b/mlir/tools/quantum-opt/CMakeLists.txt @@ -22,6 +22,8 @@ set(LIBS mbqc-transforms MLIRMitigation mitigation-transforms + MLIRPauliFrame + # pauli-frame-transforms MLIRIon ion-transforms MLIRCatalystTest diff --git a/mlir/tools/quantum-opt/quantum-opt.cpp b/mlir/tools/quantum-opt/quantum-opt.cpp index a9b4140c9d..e3058d2356 100644 --- a/mlir/tools/quantum-opt/quantum-opt.cpp +++ b/mlir/tools/quantum-opt/quantum-opt.cpp @@ -40,6 +40,7 @@ #include "Ion/IR/IonDialect.h" #include "MBQC/IR/MBQCDialect.h" #include "Mitigation/IR/MitigationDialect.h" +#include "PauliFrame/IR/PauliFrameDialect.h" #include "QEC/IR/QECDialect.h" #include "Quantum/IR/QuantumDialect.h" #include "Quantum/Transforms/BufferizableOpInterfaceImpl.h" @@ -68,6 +69,7 @@ int main(int argc, char **argv) registry.insert(); registry.insert(); registry.insert(); + registry.insert(); registry.insert(); registry.insert(); From a9c68396083014d914b9a91dc88379b256bbe893 Mon Sep 17 00:00:00 2001 From: Joey Carter Date: Wed, 12 Nov 2025 16:15:52 -0500 Subject: [PATCH 4/7] Rejig set of ops and add more documentation --- .../PauliFrame/IR/PauliFrameDialect.td | 37 ++++++++- mlir/include/PauliFrame/IR/PauliFrameOps.td | 77 ++++++++++++++++--- mlir/lib/PauliFrame/IR/PauliFrameDialect.cpp | 2 - mlir/lib/PauliFrame/IR/PauliFrameOps.cpp | 26 ++++++- mlir/test/PauliFrame/DialectTest.mlir | 72 +++++++++++++---- 5 files changed, 180 insertions(+), 34 deletions(-) diff --git a/mlir/include/PauliFrame/IR/PauliFrameDialect.td b/mlir/include/PauliFrame/IR/PauliFrameDialect.td index 1e9c36efac..c3297921ec 100644 --- a/mlir/include/PauliFrame/IR/PauliFrameDialect.td +++ b/mlir/include/PauliFrame/IR/PauliFrameDialect.td @@ -31,11 +31,46 @@ def PauliFrame_Dialect : Dialect { them to qubits on the device. Doing so reduces the number of quantum operations applied to the system, thus reducing the probability of errors. + A single Pauli record *Rq* tracks all the Pauli gates that are applied on qubit *q*. Every + set of tracked Pauli gates can be reduced to one of the elements in the set {I, X, Z, XZ}, + hence a single Pauli record can be stored using two bits, encoded as X- and Z-parity bits: + + I = (0, 0), X = (1, 0), Z = (0, 1), XZ = (1, 1) + + The operations in this dialect aim to represent the Pauli frame tracking components of the + following five quantum processes required to maintain a system of universal quantum + computation, as described in Ref. [2]: + + 1. Initialization of a qubit to |0>: + a. Set Pauli record of target qubit to I. + b. Initialize target qubit to |0>. + 2. Measurement: + a. Measure target qubit. + b. Correct measurement result based on Pauli record. + 3. Pauli gates: + a. Update Pauli record of target qubit accordingly (the Pauli gates themselves are + not physically applied to the qubit). + 4. Clifford gates: + a. Update Pauli record(s) of target qubit(s). + b. Apply Clifford gate on target qubit(s). + 5. Non-Clifford gates: + a. Flush Pauli record(s) of target qubit(s). *Flushing* the Pauli record of a qubit + refers to physically applying the Pauli gates stored in the record on that qubit + and then resetting its record to I. + b. Apply non-Clifford gate on target qubit(s). + + References + ---------- + [1] Knill, E. Quantum computing with realistically noisy devices. Nature 434, 39-44 (2005). https://doi.org/10.1038/nature03350. + [2] Riesebos, L., et al. Pauli Frames for Quantum Computer Architectures. + DAC '17: Proceedings of the 54th Annual Design Automation Conference 76, 1-6 (2017). + https://doi.org/10.1145/3061639.3062300. + > [!IMPORTANT] - > The pauli_frame dialect is experimental and and will not maintain API stability between releases. + > The pauli_frame dialect is experimental and will not maintain API stability between releases. > Use at your own risk. }]; diff --git a/mlir/include/PauliFrame/IR/PauliFrameOps.td b/mlir/include/PauliFrame/IR/PauliFrameOps.td index f408cde6a9..bafa640265 100644 --- a/mlir/include/PauliFrame/IR/PauliFrameOps.td +++ b/mlir/include/PauliFrame/IR/PauliFrameOps.td @@ -15,11 +15,7 @@ #ifndef PAULI_FRAME_OPS #define PAULI_FRAME_OPS -include "mlir/IR/AttrTypeBase.td" -include "mlir/IR/EnumAttr.td" - include "Quantum/IR/QuantumDialect.td" - include "PauliFrame/IR/PauliFrameDialect.td" //===----------------------------------------------------------------------===// @@ -41,10 +37,34 @@ include "PauliFrame/IR/PauliFrameDialect.td" // PauliFrame dialect operations. //===----------------------------------------------------------------------===// -def SetRecordOp : PauliFrame_Op<"set_record"> { - let summary = "Set the Pauli record of the target qubit(s)"; +def InitOp : PauliFrame_Op<"init"> { + let summary = "Initialize the Pauli record of the target qubit(s) to I"; + let description = [{ + Initialize the Pauli record of the target qubit(s) to I. If multiple target qubits are given + as input, the Pauli record is initialized to I for all the given qubits. + }]; + + let arguments = (ins + Variadic:$in_qubits + ); + + let results = (outs + Variadic:$out_qubits + ); + + let assemblyFormat = [{ + $in_qubits attr-dict `:` type(results) + }]; + + let hasVerifier = 1; +} + +def UpdateOp : PauliFrame_Op<"update"> { + let summary = "Update the Pauli record of the target qubit(s)"; let description = [{ - Set the Pauli record of the target qubit(s). + Update the Pauli record of the target qubit(s) given the new Pauli record. The Pauli record + is encoded by its X- and Z-parity bits. If multiple target qubits are given as input, the + new Pauli record is used to update the Pauli records of all the given qubits. }]; let arguments = (ins @@ -64,10 +84,11 @@ def SetRecordOp : PauliFrame_Op<"set_record"> { let hasVerifier = 1; } -def ReadRecordOp : PauliFrame_Op<"read_record"> { +def ReadOp : PauliFrame_Op<"read"> { let summary = "Read the Pauli record of the target qubit"; let description = [{ - Read the Pauli record of the target qubit. + Read the Pauli record of the target qubit. The returned Pauli record is encoded as X- and + Z-parity bits. }]; let arguments = (ins @@ -88,7 +109,7 @@ def ReadRecordOp : PauliFrame_Op<"read_record"> { def CorrectMeasurementOp : PauliFrame_Op<"correct_measurement"> { let summary = "Correct the measurement result given the Pauli record"; let description = [{ - Correct the measurement result given the Pauli record. + Correct the measurement result given the Pauli record as encoded by its X- and Z-parity bits. }]; let arguments = (ins @@ -106,10 +127,13 @@ def CorrectMeasurementOp : PauliFrame_Op<"correct_measurement"> { }]; } -def FlushRecordOp : PauliFrame_Op<"flush_record"> { +def FlushOp : PauliFrame_Op<"flush"> { let summary = "Flush the Pauli record(s) of the target qubit(s)"; let description = [{ - Flush the Pauli record(s) of the target qubit(s). + Flush the Pauli record(s) of the target qubit(s). *Flushing* the Pauli record of a qubit + refers to physically applying the Pauli gates stored in the record on that qubit and then + resetting its record to I (X=0, Z=0). If multiple target qubits are given as input, the + Pauli record is flushed on all the given qubits. }]; let arguments = (ins @@ -127,4 +151,33 @@ def FlushRecordOp : PauliFrame_Op<"flush_record"> { let hasVerifier = 1; } +def SetOp : PauliFrame_Op<"set"> { + let summary = "Set the Pauli record of the target qubit(s)"; + let description = [{ + Set the Pauli record of the target qubit(s). The Pauli record is encoded by its X- and + Z-parity bits. If multiple target qubits are given as input, the same Pauli record is + applied to all the given qubits. + + Note that the `pauli_frame.set` operations is generally not needed in the Pauli frame + tracking framework as only the `pauli_frame.init` and `pauli_frame.update` operations should + be used to modify the Pauli record of the target qubit(s). It is included for completeness. + }]; + + let arguments = (ins + Variadic:$in_qubits, + I1:$x_parity, + I1:$z_parity + ); + + let results = (outs + Variadic:$out_qubits + ); + + let assemblyFormat = [{ + `[` $x_parity `,` $z_parity `]` $in_qubits attr-dict `:` type(results) + }]; + + let hasVerifier = 1; +} + #endif // PAULI_FRAME_OPS diff --git a/mlir/lib/PauliFrame/IR/PauliFrameDialect.cpp b/mlir/lib/PauliFrame/IR/PauliFrameDialect.cpp index 7553596b0f..d8ce8e3da5 100644 --- a/mlir/lib/PauliFrame/IR/PauliFrameDialect.cpp +++ b/mlir/lib/PauliFrame/IR/PauliFrameDialect.cpp @@ -13,8 +13,6 @@ // limitations under the License. #include "mlir/IR/Builders.h" -#include "mlir/IR/DialectImplementation.h" // needed for generated type parser -#include "llvm/ADT/TypeSwitch.h" // needed for generated type parser #include "PauliFrame/IR/PauliFrameDialect.h" #include "PauliFrame/IR/PauliFrameOps.h" diff --git a/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp b/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp index 6611c61632..094a7b7acd 100644 --- a/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp +++ b/mlir/lib/PauliFrame/IR/PauliFrameOps.cpp @@ -31,7 +31,7 @@ using namespace catalyst::pauli_frame; // PauliFrame op verifiers. //===----------------------------------------------------------------------===// -LogicalResult SetRecordOp::verify() +LogicalResult InitOp::verify() { if (getInQubits().size() == 0) { return emitOpError("expected to have at least one qubit"); @@ -42,7 +42,29 @@ LogicalResult SetRecordOp::verify() return success(); } -LogicalResult FlushRecordOp::verify() +LogicalResult UpdateOp::verify() +{ + if (getInQubits().size() == 0) { + return emitOpError("expected to have at least one qubit"); + } + if (getInQubits().size() != getOutQubits().size()) { + return emitOpError("expected to consume and return the same number of qubits"); + } + return success(); +} + +LogicalResult FlushOp::verify() +{ + if (getInQubits().size() == 0) { + return emitOpError("expected to have at least one qubit"); + } + if (getInQubits().size() != getOutQubits().size()) { + return emitOpError("expected to consume and return the same number of qubits"); + } + return success(); +} + +LogicalResult SetOp::verify() { if (getInQubits().size() == 0) { return emitOpError("expected to have at least one qubit"); diff --git a/mlir/test/PauliFrame/DialectTest.mlir b/mlir/test/PauliFrame/DialectTest.mlir index f2b1220c0f..ce329a1052 100644 --- a/mlir/test/PauliFrame/DialectTest.mlir +++ b/mlir/test/PauliFrame/DialectTest.mlir @@ -14,38 +14,52 @@ // RUN: quantum-opt --split-input-file --verify-diagnostics %s -func.func @test_set_record_single_qubit(%q0 : !quantum.bit) { +func.func @test_pauli_frame_init_single_qubit(%q0 : !quantum.bit) { + %q1 = pauli_frame.init %q0 : !quantum.bit + func.return +} + +// ----- + +func.func @test_pauli_frame_init_multi_qubit(%q00 : !quantum.bit, %q10 : !quantum.bit) { + %q01, %q11 = pauli_frame.init %q00, %q10 : !quantum.bit, !quantum.bit + func.return +} + +// ----- + +func.func @test_pauli_frame_update_single_qubit(%q0 : !quantum.bit) { %0 = arith.constant 0 : i1 %1 = arith.constant 1 : i1 - %q1 = pauli_frame.set_record [%0, %0] %q0 : !quantum.bit - %q2 = pauli_frame.set_record [%0, %1] %q1 : !quantum.bit - %q3 = pauli_frame.set_record [%1, %0] %q2 : !quantum.bit - %q4 = pauli_frame.set_record [%1, %1] %q3 : !quantum.bit + %q1 = pauli_frame.update [%0, %0] %q0 : !quantum.bit + %q2 = pauli_frame.update [%0, %1] %q1 : !quantum.bit + %q3 = pauli_frame.update [%1, %0] %q2 : !quantum.bit + %q4 = pauli_frame.update [%1, %1] %q3 : !quantum.bit func.return } // ----- -func.func @test_set_record_multi_qubit(%q00 : !quantum.bit, %q10 : !quantum.bit) { +func.func @test_pauli_frame_update_multi_qubit(%q00 : !quantum.bit, %q10 : !quantum.bit) { %0 = arith.constant 0 : i1 %1 = arith.constant 1 : i1 - %q01, %q11 = pauli_frame.set_record [%0, %0] %q00, %q10 : !quantum.bit, !quantum.bit - %q02, %q12 = pauli_frame.set_record [%0, %1] %q01, %q11 : !quantum.bit, !quantum.bit - %q03, %q13 = pauli_frame.set_record [%1, %0] %q02, %q12 : !quantum.bit, !quantum.bit - %q04, %q14 = pauli_frame.set_record [%1, %1] %q03, %q13 : !quantum.bit, !quantum.bit + %q01, %q11 = pauli_frame.update [%0, %0] %q00, %q10 : !quantum.bit, !quantum.bit + %q02, %q12 = pauli_frame.update [%0, %1] %q01, %q11 : !quantum.bit, !quantum.bit + %q03, %q13 = pauli_frame.update [%1, %0] %q02, %q12 : !quantum.bit, !quantum.bit + %q04, %q14 = pauli_frame.update [%1, %1] %q03, %q13 : !quantum.bit, !quantum.bit func.return } // ----- -func.func @test_read_record(%q0 : !quantum.bit) { - %record_x, %record_z, %out_qubit = pauli_frame.read_record %q0 : i1, i1, !quantum.bit +func.func @test_pauli_frame_read(%q0 : !quantum.bit) { + %record_x, %record_z, %out_qubit = pauli_frame.read %q0 : i1, i1, !quantum.bit func.return } // ----- -func.func @test_correct_measurement(%mres : i1) { +func.func @test_pauli_frame_correct_measurement(%mres : i1) { %0 = arith.constant 0 : i1 %1 = arith.constant 1 : i1 %out_mres_0 = pauli_frame.correct_measurement [%0, %0] %mres : i1 @@ -57,14 +71,38 @@ func.func @test_correct_measurement(%mres : i1) { // ----- -func.func @test_flush_record_single_qubit(%q0 : !quantum.bit) { - %q1 = pauli_frame.flush_record %q0 : !quantum.bit +func.func @test_pauli_frame_flush_single_qubit(%q0 : !quantum.bit) { + %q1 = pauli_frame.flush %q0 : !quantum.bit func.return } // ----- -func.func @test_flush_record_multi_qubit(%q00 : !quantum.bit, %q10 : !quantum.bit) { - %q01, %q11 = pauli_frame.flush_record %q00, %q10 : !quantum.bit, !quantum.bit +func.func @test_pauli_frame_flush_multi_qubit(%q00 : !quantum.bit, %q10 : !quantum.bit) { + %q01, %q11 = pauli_frame.flush %q00, %q10 : !quantum.bit, !quantum.bit func.return } + +// ----- + +func.func @test_pauli_frame_set_single_qubit(%q0 : !quantum.bit) { + %0 = arith.constant 0 : i1 + %1 = arith.constant 1 : i1 + %q1 = pauli_frame.set [%0, %0] %q0 : !quantum.bit + %q2 = pauli_frame.set [%0, %1] %q1 : !quantum.bit + %q3 = pauli_frame.set [%1, %0] %q2 : !quantum.bit + %q4 = pauli_frame.set [%1, %1] %q3 : !quantum.bit + func.return +} + +// ----- + +func.func @test_pauli_frame_set_multi_qubit(%q00 : !quantum.bit, %q10 : !quantum.bit) { + %0 = arith.constant 0 : i1 + %1 = arith.constant 1 : i1 + %q01, %q11 = pauli_frame.set [%0, %0] %q00, %q10 : !quantum.bit, !quantum.bit + %q02, %q12 = pauli_frame.set [%0, %1] %q01, %q11 : !quantum.bit, !quantum.bit + %q03, %q13 = pauli_frame.set [%1, %0] %q02, %q12 : !quantum.bit, !quantum.bit + %q04, %q14 = pauli_frame.set [%1, %1] %q03, %q13 : !quantum.bit, !quantum.bit + func.return +} \ No newline at end of file From e28b082faf765ee4f685e8b11675540dafb11395 Mon Sep 17 00:00:00 2001 From: Joey Carter Date: Wed, 12 Nov 2025 16:18:31 -0500 Subject: [PATCH 5/7] Format --- mlir/test/PauliFrame/DialectTest.mlir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/test/PauliFrame/DialectTest.mlir b/mlir/test/PauliFrame/DialectTest.mlir index ce329a1052..585375ffef 100644 --- a/mlir/test/PauliFrame/DialectTest.mlir +++ b/mlir/test/PauliFrame/DialectTest.mlir @@ -105,4 +105,4 @@ func.func @test_pauli_frame_set_multi_qubit(%q00 : !quantum.bit, %q10 : !quantum %q03, %q13 = pauli_frame.set [%1, %0] %q02, %q12 : !quantum.bit, !quantum.bit %q04, %q14 = pauli_frame.set [%1, %1] %q03, %q13 : !quantum.bit, !quantum.bit func.return -} \ No newline at end of file +} From 96aeb0527fa6230473053c9b2863110b8d36d6d7 Mon Sep 17 00:00:00 2001 From: Joey Carter Date: Wed, 12 Nov 2025 16:51:10 -0500 Subject: [PATCH 6/7] Add changelog entry --- doc/releases/changelog-dev.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index 6f2b494010..e8debe938d 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -133,6 +133,10 @@ } ``` +* A new `PauliFrame` dialect has been added. This dialect includes a set of abstractions and + operations for interacting with an external Pauli frame tracking library. + [(#2188)](https://github.com/PennyLaneAI/catalyst/pull/2188) +

Documentation 📝

* A typo in the code example for :func:`~.passes.ppr_to_ppm` has been corrected. @@ -150,6 +154,7 @@ This release contains contributions from (in alphabetical order): Ali Asadi, +Joey Carter, Christina Lee, River McCubbin, Lee J. O'Riordan, From e61ffc63402d747431a60672a6a0a73f58769e01 Mon Sep 17 00:00:00 2001 From: Joey Carter Date: Thu, 13 Nov 2025 17:05:01 -0500 Subject: [PATCH 7/7] Add op pauli_frame.init_qreg --- mlir/include/PauliFrame/IR/PauliFrameOps.td | 19 +++++++++++++++++++ mlir/test/PauliFrame/DialectTest.mlir | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/mlir/include/PauliFrame/IR/PauliFrameOps.td b/mlir/include/PauliFrame/IR/PauliFrameOps.td index bafa640265..9cba327d4c 100644 --- a/mlir/include/PauliFrame/IR/PauliFrameOps.td +++ b/mlir/include/PauliFrame/IR/PauliFrameOps.td @@ -59,6 +59,25 @@ def InitOp : PauliFrame_Op<"init"> { let hasVerifier = 1; } +def InitQregOp : PauliFrame_Op<"init_qreg"> { + let summary = "Initialize the Pauli records of the target qubits in the quantum register to I"; + let description = [{ + Initialize the Pauli records of the target qubits in the quantum register to I. + }]; + + let arguments = (ins + QuregType:$in_qreg + ); + + let results = (outs + QuregType:$out_qreg + ); + + let assemblyFormat = [{ + $in_qreg attr-dict `:` type(results) + }]; +} + def UpdateOp : PauliFrame_Op<"update"> { let summary = "Update the Pauli record of the target qubit(s)"; let description = [{ diff --git a/mlir/test/PauliFrame/DialectTest.mlir b/mlir/test/PauliFrame/DialectTest.mlir index 585375ffef..75281545b8 100644 --- a/mlir/test/PauliFrame/DialectTest.mlir +++ b/mlir/test/PauliFrame/DialectTest.mlir @@ -28,6 +28,13 @@ func.func @test_pauli_frame_init_multi_qubit(%q00 : !quantum.bit, %q10 : !quantu // ----- +func.func @test_pauli_frame_init_qreg(%qreg : !quantum.reg) { + %out_qreg = pauli_frame.init_qreg %qreg : !quantum.reg + func.return +} + +// ----- + func.func @test_pauli_frame_update_single_qubit(%q0 : !quantum.bit) { %0 = arith.constant 0 : i1 %1 = arith.constant 1 : i1