From 063683a0f8d5b4043076b3371aec2e830c814fff Mon Sep 17 00:00:00 2001 From: paul0403 Date: Sun, 21 Dec 2025 16:33:54 -0500 Subject: [PATCH 01/25] init dialect boilerplate --- mlir/include/CMakeLists.txt | 1 + mlir/include/RefQuantum/CMakeLists.txt | 2 + mlir/include/RefQuantum/IR/CMakeLists.txt | 10 +++ .../include/RefQuantum/IR/RefQuantumDialect.h | 33 +++++++++ .../RefQuantum/IR/RefQuantumDialect.td | 72 +++++++++++++++++++ mlir/include/RefQuantum/IR/RefQuantumOps.h | 32 +++++++++ mlir/include/RefQuantum/IR/RefQuantumOps.td | 57 +++++++++++++++ .../RefQuantum/Transforms/CMakeLists.txt | 4 ++ mlir/include/RefQuantum/Transforms/Passes.h | 27 +++++++ mlir/include/RefQuantum/Transforms/Passes.td | 29 ++++++++ mlir/include/RefQuantum/Transforms/Patterns.h | 25 +++++++ mlir/include/RegisterAllPasses.h | 2 + mlir/lib/CMakeLists.txt | 1 + mlir/lib/Driver/CMakeLists.txt | 2 + mlir/lib/RefQuantum/CMakeLists.txt | 2 + mlir/lib/RefQuantum/IR/CMakeLists.txt | 11 +++ mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp | 59 +++++++++++++++ mlir/lib/RefQuantum/IR/RefQuantumOps.cpp | 38 ++++++++++ mlir/lib/RefQuantum/Transforms/CMakeLists.txt | 27 +++++++ .../Transforms/HelloWorldPatterns.cpp | 51 +++++++++++++ .../lib/RefQuantum/Transforms/hello_world.cpp | 51 +++++++++++++ mlir/test/CMakeLists.txt | 1 + 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 + 27 files changed, 546 insertions(+) create mode 100644 mlir/include/RefQuantum/CMakeLists.txt create mode 100644 mlir/include/RefQuantum/IR/CMakeLists.txt create mode 100644 mlir/include/RefQuantum/IR/RefQuantumDialect.h create mode 100644 mlir/include/RefQuantum/IR/RefQuantumDialect.td create mode 100644 mlir/include/RefQuantum/IR/RefQuantumOps.h create mode 100644 mlir/include/RefQuantum/IR/RefQuantumOps.td create mode 100644 mlir/include/RefQuantum/Transforms/CMakeLists.txt create mode 100644 mlir/include/RefQuantum/Transforms/Passes.h create mode 100644 mlir/include/RefQuantum/Transforms/Passes.td create mode 100644 mlir/include/RefQuantum/Transforms/Patterns.h create mode 100644 mlir/lib/RefQuantum/CMakeLists.txt create mode 100644 mlir/lib/RefQuantum/IR/CMakeLists.txt create mode 100644 mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp create mode 100644 mlir/lib/RefQuantum/IR/RefQuantumOps.cpp create mode 100644 mlir/lib/RefQuantum/Transforms/CMakeLists.txt create mode 100644 mlir/lib/RefQuantum/Transforms/HelloWorldPatterns.cpp create mode 100644 mlir/lib/RefQuantum/Transforms/hello_world.cpp diff --git a/mlir/include/CMakeLists.txt b/mlir/include/CMakeLists.txt index d211bbd77e..32e440502a 100644 --- a/mlir/include/CMakeLists.txt +++ b/mlir/include/CMakeLists.txt @@ -7,5 +7,6 @@ add_subdirectory(Mitigation) add_subdirectory(PauliFrame) add_subdirectory(QEC) add_subdirectory(Quantum) +add_subdirectory(RefQuantum) add_subdirectory(RTIO) add_subdirectory(Test) diff --git a/mlir/include/RefQuantum/CMakeLists.txt b/mlir/include/RefQuantum/CMakeLists.txt new file mode 100644 index 0000000000..9f57627c32 --- /dev/null +++ b/mlir/include/RefQuantum/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(IR) +add_subdirectory(Transforms) diff --git a/mlir/include/RefQuantum/IR/CMakeLists.txt b/mlir/include/RefQuantum/IR/CMakeLists.txt new file mode 100644 index 0000000000..ac777cf119 --- /dev/null +++ b/mlir/include/RefQuantum/IR/CMakeLists.txt @@ -0,0 +1,10 @@ +add_mlir_dialect(RefQuantumOps ref_quantum) +add_mlir_doc(RefQuantumDialect RefQuantumDialect RefQuantum/ -gen-dialect-doc -gen-op-doc) +add_mlir_doc(RefQuantumOps RefQuantumOps RefQuantum/ -gen-op-doc) + +set(LLVM_TARGET_DEFINITIONS RefQuantumOps.td) +mlir_tablegen(RefQuantumEnums.h.inc -gen-enum-decls) +mlir_tablegen(RefQuantumEnums.cpp.inc -gen-enum-defs) +mlir_tablegen(RefQuantumAttributes.h.inc -gen-attrdef-decls -attrdefs-dialect=ref_quantum) +mlir_tablegen(RefQuantumAttributes.cpp.inc -gen-attrdef-defs -attrdefs-dialect=ref_quantum) +add_public_tablegen_target(MLIRRefQuantumEnumsIncGen) diff --git a/mlir/include/RefQuantum/IR/RefQuantumDialect.h b/mlir/include/RefQuantum/IR/RefQuantumDialect.h new file mode 100644 index 0000000000..a2c1cf747c --- /dev/null +++ b/mlir/include/RefQuantum/IR/RefQuantumDialect.h @@ -0,0 +1,33 @@ +// 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" + +//===----------------------------------------------------------------------===// +// RefQuantum dialect declarations. +//===----------------------------------------------------------------------===// + +#include "RefQuantum/IR/RefQuantumOpsDialect.h.inc" + +//===----------------------------------------------------------------------===// +// RefQuantum type declarations. +//===----------------------------------------------------------------------===// + +// Uncomment the lines below if defining custom types for the RefQuantum dialect +// For now, I don't see a need, since plxpr does not have "qubit type" or "qreg type". + +// #define GET_TYPEDEF_CLASSES +// #include "RefQuantum/IR/RefQuantumOpsTypes.h.inc" diff --git a/mlir/include/RefQuantum/IR/RefQuantumDialect.td b/mlir/include/RefQuantum/IR/RefQuantumDialect.td new file mode 100644 index 0000000000..08ded44790 --- /dev/null +++ b/mlir/include/RefQuantum/IR/RefQuantumDialect.td @@ -0,0 +1,72 @@ +// 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 REF_QUANTUM_DIALECT +#define REF_QUANTUM_DIALECT + +include "mlir/IR/DialectBase.td" +include "mlir/IR/OpBase.td" + +//===----------------------------------------------------------------------===// +// RefQuantum dialect definition. +//===----------------------------------------------------------------------===// + +def RefQuantum_Dialect : Dialect { + let summary = "Reference semantics quantum dialect."; + let description = [{ + Here are words + }]; + + /// This is the namespace of the dialect in MLIR, which is used as a prefix for types and ops. + let name = "ref_quantum"; + + /// This is the C++ namespace in which the dialect and all of its sub-components are placed. + let cppNamespace = "::catalyst::ref_quantum"; + + // TODO: does it depend? + // let dependentDialects = [ + // "quantum::QuantumDialect" + // ]; + + /// Use the default type printing/parsing hooks, otherwise we would have to explicitly define them. + // Do I even need attributes? + // The only attr in regular quantum dialect is the named observable. + // I probably also need it.... + let useDefaultAttributePrinterParser = 1; + + /// Uncomment the line below if defining types for the RefQuantum dialect + // let useDefaultTypePrinterParser = 1; +} + + +//===----------------------------------------------------------------------===// +// RefQuantum dialect types. +//===----------------------------------------------------------------------===// + +/// Uncomment the lines below if defining types for the RefQuantum dialect +// class RefQuantum_Type traits = []> +// : TypeDef { +// let mnemonic = typeMnemonic; +// } + + +//===----------------------------------------------------------------------===// +// RefQuantum dialect base operation. +//===----------------------------------------------------------------------===// + +class RefQuantum_Op traits = []> : + Op; + + +#endif // REF_QUANTUM_DIALECT diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.h b/mlir/include/RefQuantum/IR/RefQuantumOps.h new file mode 100644 index 0000000000..6f325ef26d --- /dev/null +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.h @@ -0,0 +1,32 @@ +// 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 + +// TODO: is it dependent on the regular quantum dialect? +// #include "Quantum/IR/QuantumDialect.h" + +#include "RefQuantum/IR/RefQuantumDialect.h" + +//===----------------------------------------------------------------------===// +// RefQuantum ops declarations. +//===----------------------------------------------------------------------===// + +#include "RefQuantum/IR/RefQuantumEnums.h.inc" + +#define GET_ATTRDEF_CLASSES +#include "RefQuantum/IR/RefQuantumAttributes.h.inc" + +#define GET_OP_CLASSES +#include "RefQuantum/IR/RefQuantumOps.h.inc" diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td new file mode 100644 index 0000000000..9543306dff --- /dev/null +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -0,0 +1,57 @@ +// 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 REF_QUANTUM_OPS +#define REF_QUANTUM_OPS + +include "mlir/IR/EnumAttr.td" + +// TODO: does it depend? +// include "Quantum/IR/QuantumDialect.td" +include "RefQuantum/IR/RefQuantumDialect.td" + +//===----------------------------------------------------------------------===// +// RefQuantum dialect enums. +//===----------------------------------------------------------------------===// + +def NamedObservable : I32EnumAttr<"NamedObservable", + "Known named observables", + [ + I32EnumAttrCase<"Identity", 0>, + I32EnumAttrCase<"PauliX", 1>, + I32EnumAttrCase<"PauliY", 2>, + I32EnumAttrCase<"PauliZ", 3>, + I32EnumAttrCase<"Hadamard", 4>, + ]> { + let cppNamespace = "catalyst::ref_quantum"; + let genSpecializedAttr = 0; +} + +//===----------------------------------------------------------------------===// +// RefQuantum dialect traits. +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// RefQuantum dialect attributes. +//===----------------------------------------------------------------------===// + +def NamedObservableAttr : EnumAttr; + +//===----------------------------------------------------------------------===// +// RefQuantum dialect operations. +//===----------------------------------------------------------------------===// + + +#endif // REF_QUANTUM_OPS diff --git a/mlir/include/RefQuantum/Transforms/CMakeLists.txt b/mlir/include/RefQuantum/Transforms/CMakeLists.txt new file mode 100644 index 0000000000..d597f46814 --- /dev/null +++ b/mlir/include/RefQuantum/Transforms/CMakeLists.txt @@ -0,0 +1,4 @@ +set(LLVM_TARGET_DEFINITIONS Passes.td) +mlir_tablegen(Passes.h.inc -gen-pass-decls -name RefQuantum) +add_public_tablegen_target(MLIRRefQuantumPassIncGen) +add_mlir_doc(Passes RefQuantumPasses ./ -gen-pass-doc) diff --git a/mlir/include/RefQuantum/Transforms/Passes.h b/mlir/include/RefQuantum/Transforms/Passes.h new file mode 100644 index 0000000000..74031d0161 --- /dev/null +++ b/mlir/include/RefQuantum/Transforms/Passes.h @@ -0,0 +1,27 @@ +// 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/Pass/Pass.h" + +namespace catalyst { +namespace ref_quantum { + +#define GEN_PASS_DECL +#define GEN_PASS_REGISTRATION +#include "RefQuantum/Transforms/Passes.h.inc" + +} // namespace ref_quantum +} // namespace catalyst diff --git a/mlir/include/RefQuantum/Transforms/Passes.td b/mlir/include/RefQuantum/Transforms/Passes.td new file mode 100644 index 0000000000..3da6ec7b89 --- /dev/null +++ b/mlir/include/RefQuantum/Transforms/Passes.td @@ -0,0 +1,29 @@ +// 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 REF_QUANTUM_PASSES +#define REF_QUANTUM_PASSES + +include "mlir/Pass/PassBase.td" + +def RQHelloWorldPass : Pass<"rq-hw"> { + let summary = "RefQuantum Hello world!"; + + // let dependentDialects = [ + // "scf::SCFDialect", + // "catalyst::quantum::QuantumDialect" + // ]; +} + +#endif // REF_QUANTUM_PASSES diff --git a/mlir/include/RefQuantum/Transforms/Patterns.h b/mlir/include/RefQuantum/Transforms/Patterns.h new file mode 100644 index 0000000000..92a5ceaf26 --- /dev/null +++ b/mlir/include/RefQuantum/Transforms/Patterns.h @@ -0,0 +1,25 @@ +// 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/PatternMatch.h" + +namespace catalyst { +namespace ref_quantum { + +void populateRQHelloWorldPatterns(mlir::RewritePatternSet &patterns); + +} // namespace ref_quantum +} // namespace catalyst diff --git a/mlir/include/RegisterAllPasses.h b/mlir/include/RegisterAllPasses.h index 1ff2397b0b..ed9fc6c0eb 100644 --- a/mlir/include/RegisterAllPasses.h +++ b/mlir/include/RegisterAllPasses.h @@ -22,6 +22,7 @@ #include "PauliFrame/Transforms/Passes.h" #include "QEC/Transforms/Passes.h" #include "Quantum/Transforms/Passes.h" +#include "RefQuantum/Transforms/Passes.h" #include "RTIO/Transforms/Passes.h" #include "Test/Transforms/Passes.h" #include "hlo-extensions/Transforms/Passes.h" @@ -39,6 +40,7 @@ inline void registerAllPasses() pauli_frame::registerPauliFramePasses(); qec::registerQECPasses(); quantum::registerQuantumPasses(); + ref_quantum::registerRefQuantumPasses(); rtio::registerRTIOPasses(); test::registerTestPasses(); } diff --git a/mlir/lib/CMakeLists.txt b/mlir/lib/CMakeLists.txt index 6f874d8502..96d352f957 100644 --- a/mlir/lib/CMakeLists.txt +++ b/mlir/lib/CMakeLists.txt @@ -9,5 +9,6 @@ add_subdirectory(Mitigation) add_subdirectory(PauliFrame) add_subdirectory(QEC) add_subdirectory(Quantum) +add_subdirectory(RefQuantum) add_subdirectory(RTIO) add_subdirectory(Test) diff --git a/mlir/lib/Driver/CMakeLists.txt b/mlir/lib/Driver/CMakeLists.txt index 9147c10f78..6a211f625d 100644 --- a/mlir/lib/Driver/CMakeLists.txt +++ b/mlir/lib/Driver/CMakeLists.txt @@ -34,6 +34,8 @@ set(LIBS catalyst-transforms MLIRQuantum quantum-transforms + MLIRRefQuantum + ref-quantum-transforms MLIRQEC qec-transforms MLIRGradient diff --git a/mlir/lib/RefQuantum/CMakeLists.txt b/mlir/lib/RefQuantum/CMakeLists.txt new file mode 100644 index 0000000000..9f57627c32 --- /dev/null +++ b/mlir/lib/RefQuantum/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(IR) +add_subdirectory(Transforms) diff --git a/mlir/lib/RefQuantum/IR/CMakeLists.txt b/mlir/lib/RefQuantum/IR/CMakeLists.txt new file mode 100644 index 0000000000..6b35e11689 --- /dev/null +++ b/mlir/lib/RefQuantum/IR/CMakeLists.txt @@ -0,0 +1,11 @@ +add_mlir_library(MLIRRefQuantum + RefQuantumDialect.cpp + RefQuantumOps.cpp + + ADDITIONAL_HEADER_DIRS + ${PROJECT_SOURCE_DIR}/include/RefQuantum + + DEPENDS + MLIRRefQuantumOpsIncGen + MLIRRefQuantumEnumsIncGen +) diff --git a/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp b/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp new file mode 100644 index 0000000000..cd22c54a39 --- /dev/null +++ b/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp @@ -0,0 +1,59 @@ +// 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 "RefQuantum/IR/RefQuantumDialect.h" +#include "RefQuantum/IR/RefQuantumOps.h" + +using namespace mlir; +using namespace catalyst::ref_quantum; + +//===----------------------------------------------------------------------===// +// RefQuantum dialect definitions. +//===----------------------------------------------------------------------===// + +#include "RefQuantum/IR/RefQuantumOpsDialect.cpp.inc" + +void RefQuantumDialect::initialize() +{ + /// Uncomment the lines below if defining types for the RefQuantum dialect + // addTypes< + // #define GET_TYPEDEF_LIST + // #include "RefQuantum/IR/RefQuantumOpsTypes.cpp.inc" + // >(); + + addAttributes< +#define GET_ATTRDEF_LIST +#include "RefQuantum/IR/RefQuantumAttributes.cpp.inc" + >(); + + addOperations< +#define GET_OP_LIST +#include "RefQuantum/IR/RefQuantumOps.cpp.inc" + >(); +} + +//===----------------------------------------------------------------------===// +// RefQuantum type definitions. +//===----------------------------------------------------------------------===// + +/// Uncomment the lines below if defining types +// #define GET_TYPEDEF_CLASSES +// #include "RefQuantum/IR/RefQuantumOpsTypes.cpp.inc" + +#define GET_ATTRDEF_CLASSES +#include "RefQuantum/IR/RefQuantumAttributes.cpp.inc" diff --git a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp new file mode 100644 index 0000000000..f0cb7e806f --- /dev/null +++ b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp @@ -0,0 +1,38 @@ +// 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 "RefQuantum/IR/RefQuantumDialect.h" +#include "RefQuantum/IR/RefQuantumOps.h" + +using namespace mlir; +using namespace catalyst::ref_quantum; + +//===----------------------------------------------------------------------===// +// RefQuantum op definitions. +//===----------------------------------------------------------------------===// + +#include "RefQuantum/IR/RefQuantumEnums.cpp.inc" + +#define GET_OP_CLASSES +#include "RefQuantum/IR/RefQuantumOps.cpp.inc" + +//===----------------------------------------------------------------------===// +// RefQuantum op verifiers. +//===----------------------------------------------------------------------===// + +namespace catalyst::ref_quantum { + +} // namespace catalyst::ref_quantum diff --git a/mlir/lib/RefQuantum/Transforms/CMakeLists.txt b/mlir/lib/RefQuantum/Transforms/CMakeLists.txt new file mode 100644 index 0000000000..2b3c3ffcb6 --- /dev/null +++ b/mlir/lib/RefQuantum/Transforms/CMakeLists.txt @@ -0,0 +1,27 @@ +set(LIBRARY_NAME ref-quantum-transforms) + + +file(GLOB SRC + HelloWorldPatterns.cpp + hello_world.cpp +) + +get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) +get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS) +set(LIBS + ${dialect_libs} + ${conversion_libs} + MLIRRefQuantum +) + +set(DEPENDS + MLIRRefQuantumPassIncGen +) + +add_mlir_library(${LIBRARY_NAME} STATIC ${SRC} LINK_LIBS PRIVATE ${LIBS} DEPENDS ${DEPENDS}) +target_compile_features(${LIBRARY_NAME} PUBLIC cxx_std_20) + +target_include_directories(${LIBRARY_NAME} PUBLIC + . + ${PROJECT_SOURCE_DIR}/include + ${CMAKE_BINARY_DIR}/include) diff --git a/mlir/lib/RefQuantum/Transforms/HelloWorldPatterns.cpp b/mlir/lib/RefQuantum/Transforms/HelloWorldPatterns.cpp new file mode 100644 index 0000000000..a153c16de0 --- /dev/null +++ b/mlir/lib/RefQuantum/Transforms/HelloWorldPatterns.cpp @@ -0,0 +1,51 @@ +// 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. + +#define DEBUG_TYPE "rq-hello-world" + +#include "mlir/IR/Operation.h" +#include "mlir/IR/PatternMatch.h" + +// #include "RefQuantum/IR/RefQuantumOps.h" +#include "RefQuantum/Transforms/Patterns.h" +#include "Quantum/IR/QuantumDialect.h" +#include "Quantum/IR/QuantumOps.h" + +using namespace mlir; + +namespace { + +struct RQHelloWorldPattern : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(catalyst::quantum::CustomOp op, PatternRewriter &rewriter) const override + { + llvm::errs() << "hello world! Visiting " << op << "\n"; + return success(); + } +}; + + +} // namespace + +namespace catalyst { +namespace ref_quantum { + +void populateRQHelloWorldPatterns(RewritePatternSet &patterns) +{ + patterns.add(patterns.getContext()); +} + +} // namespace ref_quantum +} // namespace catalyst diff --git a/mlir/lib/RefQuantum/Transforms/hello_world.cpp b/mlir/lib/RefQuantum/Transforms/hello_world.cpp new file mode 100644 index 0000000000..60d9c8a45d --- /dev/null +++ b/mlir/lib/RefQuantum/Transforms/hello_world.cpp @@ -0,0 +1,51 @@ +// 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. + +#define DEBUG_TYPE "rq-hello-world" + +#include "mlir/IR/Operation.h" +#include "mlir/IR/PatternMatch.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/GreedyPatternRewriteDriver.h" + +#include "RefQuantum/IR/RefQuantumOps.h" +#include "RefQuantum/Transforms/Patterns.h" + +using namespace mlir; + +namespace catalyst { +namespace ref_quantum { + +#define GEN_PASS_DECL_RQHELLOWORLDPASS +#define GEN_PASS_DEF_RQHELLOWORLDPASS +#include "RefQuantum/Transforms/Passes.h.inc" + +struct RQHelloWorldPass : impl::RQHelloWorldPassBase { + using RQHelloWorldPassBase::RQHelloWorldPassBase; + + void runOnOperation() final + { + Operation *mod = getOperation(); + + RewritePatternSet patterns(&getContext()); + populateRQHelloWorldPatterns(patterns); + + if (failed(applyPatternsGreedily(mod, std::move(patterns)))) { + return signalPassFailure(); + } + } +}; + +} // namespace ref_quantum +} // namespace catalyst diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt index b4519ab273..4f52d7acdb 100644 --- a/mlir/test/CMakeLists.txt +++ b/mlir/test/CMakeLists.txt @@ -20,6 +20,7 @@ set(DIALECT_TESTS_DEPEND set(TEST_SUITES Quantum + RefQuantum Gradient Mitigation Catalyst diff --git a/mlir/tools/catalyst-cli/CMakeLists.txt b/mlir/tools/catalyst-cli/CMakeLists.txt index 39bd44ecf4..c51a720e17 100644 --- a/mlir/tools/catalyst-cli/CMakeLists.txt +++ b/mlir/tools/catalyst-cli/CMakeLists.txt @@ -30,6 +30,8 @@ set(LIBS catalyst-stablehlo-transforms MLIRQuantum quantum-transforms + MLIRRefQuantum + ref-quantum-transforms MLIRQEC qec-transforms MLIRGradient diff --git a/mlir/tools/quantum-lsp-server/CMakeLists.txt b/mlir/tools/quantum-lsp-server/CMakeLists.txt index 517fc8a1d9..26e693f3b6 100644 --- a/mlir/tools/quantum-lsp-server/CMakeLists.txt +++ b/mlir/tools/quantum-lsp-server/CMakeLists.txt @@ -8,6 +8,7 @@ set(LIBS MLIRRegisterAllDialects MLIRCatalyst MLIRQuantum + MLIRRefQuantum MLIRQEC MLIRGradient MLIRMBQC diff --git a/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp b/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp index d29335b392..9cd818cb8c 100644 --- a/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp +++ b/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp @@ -24,6 +24,7 @@ #include "PauliFrame/IR/PauliFrameDialect.h" #include "QEC/IR/QECDialect.h" #include "Quantum/IR/QuantumDialect.h" +#include "RefQuantum/IR/RefQuantumDialect.h" #include "RTIO/IR/RTIODialect.h" #include "stablehlo/dialect/Register.h" @@ -34,6 +35,7 @@ int main(int argc, char **argv) mlir::registerAllDialects(registry); registry.insert(); registry.insert(); + registry.insert(); registry.insert(); registry.insert(); registry.insert(); diff --git a/mlir/tools/quantum-opt/CMakeLists.txt b/mlir/tools/quantum-opt/CMakeLists.txt index c3057fe4c5..5376c961a8 100644 --- a/mlir/tools/quantum-opt/CMakeLists.txt +++ b/mlir/tools/quantum-opt/CMakeLists.txt @@ -14,6 +14,8 @@ set(LIBS catalyst-stablehlo-transforms MLIRQuantum quantum-transforms + MLIRRefQuantum + ref-quantum-transforms MLIRQEC qec-transforms MLIRGradient diff --git a/mlir/tools/quantum-opt/quantum-opt.cpp b/mlir/tools/quantum-opt/quantum-opt.cpp index bacdd4ccab..811f402f59 100644 --- a/mlir/tools/quantum-opt/quantum-opt.cpp +++ b/mlir/tools/quantum-opt/quantum-opt.cpp @@ -44,6 +44,7 @@ #include "QEC/IR/QECDialect.h" #include "Quantum/IR/QuantumDialect.h" #include "Quantum/Transforms/BufferizableOpInterfaceImpl.h" +#include "RefQuantum/IR/RefQuantumDialect.h" #include "RTIO/IR/RTIODialect.h" #include "RegisterAllPasses.h" @@ -66,6 +67,7 @@ int main(int argc, char **argv) mlir::func::registerAllExtensions(registry); registry.insert(); registry.insert(); + registry.insert(); registry.insert(); registry.insert(); registry.insert(); From 3c0eb80d6064fd0dae1e364d79cc8ca51fea12a4 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Mon, 22 Dec 2025 18:21:39 -0500 Subject: [PATCH 02/25] Add basic gate class and interfaces, and add some of the methods. Add custom op. --- mlir/include/RefQuantum/IR/CMakeLists.txt | 2 + .../RefQuantum/IR/RefQuantumDialect.td | 8 +- .../RefQuantum/IR/RefQuantumInterfaces.h | 25 +++ .../RefQuantum/IR/RefQuantumInterfaces.td | 144 ++++++++++++++++++ mlir/include/RefQuantum/IR/RefQuantumOps.h | 29 ++++ mlir/include/RefQuantum/IR/RefQuantumOps.td | 110 ++++++++++++- mlir/lib/RefQuantum/IR/CMakeLists.txt | 2 + .../RefQuantum/IR/RefQuantumInterfaces.cpp | 24 +++ mlir/lib/RefQuantum/IR/RefQuantumOps.cpp | 3 + .../RefQuantum/DialectTest/UnitTests.mlir | 44 ++++++ .../RefQuantum/DialectTest/VerifierTests.mlir | 61 ++++++++ 11 files changed, 447 insertions(+), 5 deletions(-) create mode 100644 mlir/include/RefQuantum/IR/RefQuantumInterfaces.h create mode 100644 mlir/include/RefQuantum/IR/RefQuantumInterfaces.td create mode 100644 mlir/lib/RefQuantum/IR/RefQuantumInterfaces.cpp create mode 100644 mlir/test/RefQuantum/DialectTest/UnitTests.mlir create mode 100644 mlir/test/RefQuantum/DialectTest/VerifierTests.mlir diff --git a/mlir/include/RefQuantum/IR/CMakeLists.txt b/mlir/include/RefQuantum/IR/CMakeLists.txt index ac777cf119..38e04414a1 100644 --- a/mlir/include/RefQuantum/IR/CMakeLists.txt +++ b/mlir/include/RefQuantum/IR/CMakeLists.txt @@ -1,6 +1,8 @@ add_mlir_dialect(RefQuantumOps ref_quantum) +add_mlir_interface(RefQuantumInterfaces) add_mlir_doc(RefQuantumDialect RefQuantumDialect RefQuantum/ -gen-dialect-doc -gen-op-doc) add_mlir_doc(RefQuantumOps RefQuantumOps RefQuantum/ -gen-op-doc) +add_mlir_doc(RefQuantumInterfaces RefQuantumInterfaces RefQuantum/ -gen-op-interface-docs) set(LLVM_TARGET_DEFINITIONS RefQuantumOps.td) mlir_tablegen(RefQuantumEnums.h.inc -gen-enum-decls) diff --git a/mlir/include/RefQuantum/IR/RefQuantumDialect.td b/mlir/include/RefQuantum/IR/RefQuantumDialect.td index 08ded44790..b82318a32a 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumDialect.td +++ b/mlir/include/RefQuantum/IR/RefQuantumDialect.td @@ -17,12 +17,14 @@ include "mlir/IR/DialectBase.td" include "mlir/IR/OpBase.td" +include "mlir/IR/AttrTypeBase.td" +include "mlir/Interfaces/SideEffectInterfaces.td" //===----------------------------------------------------------------------===// // RefQuantum dialect definition. //===----------------------------------------------------------------------===// -def RefQuantum_Dialect : Dialect { +def RefQuantumDialect : Dialect { let summary = "Reference semantics quantum dialect."; let description = [{ Here are words @@ -56,7 +58,7 @@ def RefQuantum_Dialect : Dialect { /// Uncomment the lines below if defining types for the RefQuantum dialect // class RefQuantum_Type traits = []> -// : TypeDef { +// : TypeDef { // let mnemonic = typeMnemonic; // } @@ -66,7 +68,7 @@ def RefQuantum_Dialect : Dialect { //===----------------------------------------------------------------------===// class RefQuantum_Op traits = []> : - Op; + Op; #endif // REF_QUANTUM_DIALECT diff --git a/mlir/include/RefQuantum/IR/RefQuantumInterfaces.h b/mlir/include/RefQuantum/IR/RefQuantumInterfaces.h new file mode 100644 index 0000000000..1b80f0edd9 --- /dev/null +++ b/mlir/include/RefQuantum/IR/RefQuantumInterfaces.h @@ -0,0 +1,25 @@ +// 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 + +#include "mlir/IR/OpDefinition.h" + +//===----------------------------------------------------------------------===// +// RefQuantum interface declarations. +//===----------------------------------------------------------------------===// + +#include "RefQuantum/IR/RefQuantumInterfaces.h.inc" diff --git a/mlir/include/RefQuantum/IR/RefQuantumInterfaces.td b/mlir/include/RefQuantum/IR/RefQuantumInterfaces.td new file mode 100644 index 0000000000..b12b83a717 --- /dev/null +++ b/mlir/include/RefQuantum/IR/RefQuantumInterfaces.td @@ -0,0 +1,144 @@ +// 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 REFQUANTUM_INTERFACES +#define REFQUANTUM_INTERFACES + +include "mlir/IR/OpBase.td" + +def QuantumOperation : OpInterface<"QuantumOperation"> { + let description = [{ + A base class for all quantum operations that can be considered actions on wires. + The actions do not have to be unitary. For example, the SetState operations also falls + under this class. + }]; + + let cppNamespace = "::catalyst::ref_quantum"; + + let methods = [ + InterfaceMethod< + "Return all operands which are considered input wires (including controls).", + "std::vector", "getWireOperands" + >, + InterfaceMethod< + "Set all operands which are considered input wires (including controls).", + "void", "setWireOperands", (ins "mlir::ValueRange":$replacements) + > + ]; +} + +def QuantumGate : OpInterface<"QuantumGate", [QuantumOperation]> { + let description = [{ + A base class for all unitary quantum operations. + These operations can be inverted and controlled. + }]; + + let cppNamespace = "::catalyst::ref_quantum"; + + let methods = [ + InterfaceMethod< + "Return operands which are considered non-controlled input wire values.", + "mlir::ValueRange", "getNonCtrlWireOperands" + >, + // InterfaceMethod< + // "Set all operands which are considered non-controlled input qubit values.", + // "void", "setNonCtrlQubitOperands", (ins "mlir::ValueRange":$replacements) + // >, + // InterfaceMethod< + // "Return results which are considered non-controlled output qubit values.", + // "mlir::ResultRange", "getNonCtrlQubitResults" + // >, + InterfaceMethod< + "Return all operands which are considered controlling input wire values.", + "mlir::ValueRange", "getCtrlWireOperands" + >, + // InterfaceMethod< + // "Set all operands which are considered controlling input qubit values.", + // "void", "setCtrlQubitOperands", (ins "mlir::ValueRange":$replacements) + // >, + InterfaceMethod< + "Return all operands which are considered controlling input boolean values.", + "mlir::ValueRange", "getCtrlValueOperands" + >, + // InterfaceMethod< + // "Set all operands which are considered controlling input boolean values.", + // "void", "setCtrlValueOperands", (ins "mlir::ValueRange":$replacements) + // >, + // InterfaceMethod< + // "Return all operands which are considered controlling output qubit values.", + // "mlir::ResultRange", "getCtrlQubitResults" + // >, + // InterfaceMethod< + // "Return adjoint flag.", + // "bool", "getAdjointFlag" + // >, + // InterfaceMethod< + // "Set adjoint flag.", + // "void", "setAdjointFlag", (ins "bool":$adjoint) + // > + ]; + + let verify = [{ + auto gate = mlir::cast($_op); + + if (gate.getCtrlValueOperands().size() != gate.getCtrlWireOperands().size()) { + return $_op->emitError() << + "number of controlling wires in input (" << + gate.getCtrlWireOperands().size() << ") " << + "and controlling values (" << + gate.getCtrlValueOperands().size() << + ") must be the same"; + } + + // STL methods to check duplicates will all complain about `mlir::Value` not having a + // comparison method defined, since they all use map/set, which is hash-based + // So we just do it manually + std::vector wireOperands = gate.getWireOperands(); + for (size_t i=0; i < wireOperands.size(); i++) { + for (size_t j=i+1; j < wireOperands.size(); j++) { + if (wireOperands[i] == wireOperands[j]) { + return $_op->emitError() << "all wires on a quantum gate must be " << + "distinct (including controls)"; + } + } + } + + return mlir::success(); + }]; +} + +def ParametrizedGate : OpInterface<"ParametrizedGate", [QuantumGate]> { + let description = [{ + This interface provides a generic way to interact with parametrized + quantum instructions. These are quantum operations with arbitrary + classical gate parameters. + }]; + + let cppNamespace = "::catalyst::ref_quantum"; + + let methods = [ + InterfaceMethod< + "Return all operands which are considered gate parameters.", + "mlir::ValueRange", "getAllParams" + >, + InterfaceMethod< + "Return the param operand at the requested index.", + "mlir::Value", "getParam", (ins "size_t":$idx), /*methodBody=*/[{}], + /*defaultImplementation=*/[{ return mlir::cast($_op).getAllParams()[idx]; }] + >, + ]; +} + + +#endif // REFQUANTUM_INTERFACES diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.h b/mlir/include/RefQuantum/IR/RefQuantumOps.h index 6f325ef26d..5e431b52ec 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.h +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.h @@ -14,10 +14,39 @@ #pragma once +#include + +#include "llvm/ADT/StringRef.h" + +// #include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.h" +#include "mlir/IR/BuiltinTypes.h" +#include "mlir/IR/Dialect.h" +#include "mlir/IR/OpDefinition.h" +#include "mlir/IR/PatternMatch.h" +// #include "mlir/Interfaces/ControlFlowInterfaces.h" +#include "mlir/Support/LogicalResult.h" + // TODO: is it dependent on the regular quantum dialect? // #include "Quantum/IR/QuantumDialect.h" #include "RefQuantum/IR/RefQuantumDialect.h" +#include "RefQuantum/IR/RefQuantumInterfaces.h" + +//===----------------------------------------------------------------------===// +// RefQuantum trait declarations. +//===----------------------------------------------------------------------===// + +namespace mlir { +namespace OpTrait { + +template +class UnitaryTrait : public TraitBase {}; + +template +class HermitianTrait : public TraitBase {}; + +} // namespace OpTrait +} // namespace mlir //===----------------------------------------------------------------------===// // RefQuantum ops declarations. diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 9543306dff..4a2a2b9415 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -16,10 +16,17 @@ #define REF_QUANTUM_OPS include "mlir/IR/EnumAttr.td" +include "mlir/IR/OpBase.td" +// TODO: I probably need bufferization. Remove if ended up not using it. +// Or do I? If this dialect is only supposed to be at a high level, +// i.e. connection to lower parts of the pipeline are done via +// ref dialect ---> value dialect ---> bufferization ---> .... +include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.td" // TODO: does it depend? // include "Quantum/IR/QuantumDialect.td" include "RefQuantum/IR/RefQuantumDialect.td" +include "RefQuantum/IR/RefQuantumInterfaces.td" //===----------------------------------------------------------------------===// // RefQuantum dialect enums. @@ -32,7 +39,7 @@ def NamedObservable : I32EnumAttr<"NamedObservable", I32EnumAttrCase<"PauliX", 1>, I32EnumAttrCase<"PauliY", 2>, I32EnumAttrCase<"PauliZ", 3>, - I32EnumAttrCase<"Hadamard", 4>, + I32EnumAttrCase<"Hadamard", 4>, // Is this ever used from frontend? ]> { let cppNamespace = "catalyst::ref_quantum"; let genSpecializedAttr = 0; @@ -42,16 +49,115 @@ def NamedObservable : I32EnumAttr<"NamedObservable", // RefQuantum dialect traits. //===----------------------------------------------------------------------===// +def Unitary : NativeOpTrait<"UnitaryTrait">; +def Hermitian : NativeOpTrait<"HermitianTrait">; //===----------------------------------------------------------------------===// // RefQuantum dialect attributes. //===----------------------------------------------------------------------===// -def NamedObservableAttr : EnumAttr; +def NamedObservableAttr : EnumAttr; //===----------------------------------------------------------------------===// // RefQuantum dialect operations. //===----------------------------------------------------------------------===// +// ----- + +class Memory_Op traits = []> : RefQuantum_Op; + +// TODO: (dynamic) alloc and deallocs +// Note that extracts and inserts are not a thing in reference semantics + +// ----- + +class Gate_Op traits = []> : + RefQuantum_Op { + + code extraBaseClassDeclaration = [{ + std::vector getWireOperands() { + std::vector values; + values.insert(values.end(), getWires().begin(), getWires().end()); + return values; + } + + void setWireOperands(mlir::ValueRange replacements) { + mlir::MutableOperandRange wires = getWiresMutable(); + assert(wires.size() == replacements.size() && "must provide values for all wires"); + wires.assign(replacements); + } + }]; + + let extraClassDeclaration = extraBaseClassDeclaration; +} + +class UnitaryGate_Op traits = []> : + Gate_Op { + + code extraBaseClassDeclaration = [{ + std::vector getWireOperands() { + std::vector values; + values.insert(values.end(), getWires().begin(), getWires().end()); + values.insert(values.end(), getCtrlWires().begin(), getCtrlWires().end()); + return values; + } + + void setWireOperands(mlir::ValueRange replacements) { + mlir::MutableOperandRange wires = getWiresMutable(); + mlir::MutableOperandRange ctrls = getCtrlWiresMutable(); + assert(wires.size() + ctrls.size() == replacements.size() && + "must provide values for all wires (including controls)"); + + wires.assign(replacements.take_front(wires.size())); + ctrls.assign(replacements.take_back(ctrls.size())); + } + + mlir::ValueRange getNonCtrlWireOperands() { + return getWires(); + } + + mlir::ValueRange getCtrlWireOperands() { + return getCtrlWires(); + } + + mlir::ValueRange getCtrlValueOperands() { + return getCtrlValues(); + } + + }]; + + let extraClassDeclaration = extraBaseClassDeclaration; +} + +def CustomOp : UnitaryGate_Op<"custom", [ParametrizedGate, AttrSizedOperandSegments]> { + let summary = "A generic quantum gate on n qubits with m floating point parameters."; + let description = [{ + }]; + + let arguments = (ins + Variadic:$params, + Variadic:$wires, // Perhaps add a static version? But not super high priority on my list. We have arith.constant. + StrAttr:$gate_name, + UnitAttr:$adjoint, + Variadic:$ctrl_wires, // Ditto regarding static. + Variadic:$ctrl_values + ); + + // TODO: add convenience builders + + let assemblyFormat = [{ + $gate_name `(` $params `)` $wires (`adj` $adjoint^)? attr-dict ( `ctrls` `(` $ctrl_wires^ `)` )? ( `ctrlvals` `(` $ctrl_values^ `)` )? `:` type($wires) (`ctrls` type($ctrl_wires)^ )? + }]; + + let extraClassDeclaration = extraBaseClassDeclaration # [{ + mlir::ValueRange getAllParams() { + return getParams(); + } + }]; + + // TODO: anything needed here? + // let hasCanonicalizeMethod = 1; + // let hasVerifier = 1; +} #endif // REF_QUANTUM_OPS diff --git a/mlir/lib/RefQuantum/IR/CMakeLists.txt b/mlir/lib/RefQuantum/IR/CMakeLists.txt index 6b35e11689..fe8690b0b1 100644 --- a/mlir/lib/RefQuantum/IR/CMakeLists.txt +++ b/mlir/lib/RefQuantum/IR/CMakeLists.txt @@ -1,11 +1,13 @@ add_mlir_library(MLIRRefQuantum RefQuantumDialect.cpp + RefQuantumInterfaces.cpp RefQuantumOps.cpp ADDITIONAL_HEADER_DIRS ${PROJECT_SOURCE_DIR}/include/RefQuantum DEPENDS + MLIRQuantumInterfacesIncGen MLIRRefQuantumOpsIncGen MLIRRefQuantumEnumsIncGen ) diff --git a/mlir/lib/RefQuantum/IR/RefQuantumInterfaces.cpp b/mlir/lib/RefQuantum/IR/RefQuantumInterfaces.cpp new file mode 100644 index 0000000000..9a7a858218 --- /dev/null +++ b/mlir/lib/RefQuantum/IR/RefQuantumInterfaces.cpp @@ -0,0 +1,24 @@ +// 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 "RefQuantum/IR/RefQuantumInterfaces.h" + +using namespace mlir; +using namespace catalyst::ref_quantum; + +//===----------------------------------------------------------------------===// +// RefQuantum interface definitions. +//===----------------------------------------------------------------------===// + +#include "RefQuantum/IR/RefQuantumInterfaces.cpp.inc" diff --git a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp index f0cb7e806f..a2b97ed8a7 100644 --- a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp +++ b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp @@ -13,6 +13,9 @@ // limitations under the License. #include "mlir/IR/Builders.h" +#include "mlir/IR/OpImplementation.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/TypeSwitch.h" #include "RefQuantum/IR/RefQuantumDialect.h" #include "RefQuantum/IR/RefQuantumOps.h" diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir new file mode 100644 index 0000000000..be6c6a0330 --- /dev/null +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -0,0 +1,44 @@ +// 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. + +// Test basic parsing. +// +// RUN: quantum-opt --split-input-file --verify-diagnostics %s + +func.func @test_custom_op(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %param0: f64, %param1: f64) { + + // Basic + ref_quantum.custom "Hadamard"() %w0 : i64 + ref_quantum.custom "CNOT"() %w0, %w1 : i64, i64 + + // With params + ref_quantum.custom "RX"(%param0) %w0 : i64 + ref_quantum.custom "Rot"(%param0, %param1, %param1) %w0 : i64 + + // With adjoint + ref_quantum.custom "PauliX"() %w0 adj : i64 + ref_quantum.custom "CNOT"() %w0, %w1 adj : i64, i64 + + // With control + %true = llvm.mlir.constant (1 : i1) :i1 + %false = llvm.mlir.constant (0 : i1) :i1 + ref_quantum.custom "PauliZ"() %w0 ctrls (%w1) ctrlvals (%true) : i64 ctrls i64 + ref_quantum.custom "RY"(%param0) %w0 ctrls (%w1) ctrlvals (%true) : i64 ctrls i64 + ref_quantum.custom "SWAP"() %w0, %w1 ctrls (%w2, %w3) ctrlvals (%true, %false) : i64, i64 ctrls i64, i64 + + // With params, control and adjoint altogether + ref_quantum.custom "Rot"(%param0, %param1, %param1) %w0, %w1 adj ctrls (%w2, %w3) ctrlvals (%true, %false) : i64, i64 ctrls i64, i64 + + return +} diff --git a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir new file mode 100644 index 0000000000..01a8dd081b --- /dev/null +++ b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir @@ -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. + +// Test verifiers. +// +// RUN: quantum-opt --split-input-file --verify-diagnostics %s + +// ----- + +func.func @test_controlled1(%w0: i64, %w1: i64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{number of controlling wires in input (1) and controlling values (2) must be the same}} + ref_quantum.custom "PauliZ"() %w0 ctrls (%w1) ctrlvals (%true, %true) : i64 ctrls i64 + return +} + +// ----- + +func.func @test_controlled2(%w0: i64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{number of controlling wires in input (0) and controlling values (1) must be the same}} + ref_quantum.custom "PauliZ"() %w0 ctrls () ctrlvals (%true) : i64 + return +} + +// ----- + +func.func @test_controlled3(%w0: i64, %w1: i64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{number of controlling wires in input (1) and controlling values (0) must be the same}} + ref_quantum.custom "PauliZ"() %w0 ctrls (%w1) ctrlvals () : i64 ctrls i64 + return +} + +// ----- + +func.func @test_duplicate_wires1(%w0: i64) { + // expected-error@+1 {{all wires on a quantum gate must be distinct (including controls)}} + ref_quantum.custom "CNOT"() %w0, %w0 : i64, i64 + return +} + +// ----- + +func.func @test_duplicate_wires2(%w0: i64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{all wires on a quantum gate must be distinct (including controls)}} + ref_quantum.custom "PauliX"() %w0 ctrls (%w0) ctrlvals (%true) : i64 ctrls i64 + return +} From b3b42e4ed488f4dcdb640f05c94f178d86550eac Mon Sep 17 00:00:00 2001 From: paul0403 Date: Tue, 30 Dec 2025 15:27:28 -0500 Subject: [PATCH 03/25] finish interface methods; unit test for interface methods --- .../RefQuantum/IR/RefQuantumInterfaces.td | 48 ++-- mlir/include/RefQuantum/IR/RefQuantumOps.td | 32 +++ mlir/unittests/CMakeLists.txt | 1 + mlir/unittests/RefQuantum/CMakeLists.txt | 11 + mlir/unittests/RefQuantum/InterfaceTest.cpp | 225 ++++++++++++++++++ 5 files changed, 289 insertions(+), 28 deletions(-) create mode 100644 mlir/unittests/RefQuantum/CMakeLists.txt create mode 100644 mlir/unittests/RefQuantum/InterfaceTest.cpp diff --git a/mlir/include/RefQuantum/IR/RefQuantumInterfaces.td b/mlir/include/RefQuantum/IR/RefQuantumInterfaces.td index b12b83a717..84604186f8 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumInterfaces.td +++ b/mlir/include/RefQuantum/IR/RefQuantumInterfaces.td @@ -51,42 +51,34 @@ def QuantumGate : OpInterface<"QuantumGate", [QuantumOperation]> { "Return operands which are considered non-controlled input wire values.", "mlir::ValueRange", "getNonCtrlWireOperands" >, - // InterfaceMethod< - // "Set all operands which are considered non-controlled input qubit values.", - // "void", "setNonCtrlQubitOperands", (ins "mlir::ValueRange":$replacements) - // >, - // InterfaceMethod< - // "Return results which are considered non-controlled output qubit values.", - // "mlir::ResultRange", "getNonCtrlQubitResults" - // >, + InterfaceMethod< + "Set all operands which are considered non-controlled input wire values.", + "void", "setNonCtrlWireOperands", (ins "mlir::ValueRange":$replacements) + >, InterfaceMethod< "Return all operands which are considered controlling input wire values.", "mlir::ValueRange", "getCtrlWireOperands" >, - // InterfaceMethod< - // "Set all operands which are considered controlling input qubit values.", - // "void", "setCtrlQubitOperands", (ins "mlir::ValueRange":$replacements) - // >, + InterfaceMethod< + "Set all operands which are considered controlling input wire values.", + "void", "setCtrlWireOperands", (ins "mlir::ValueRange":$replacements) + >, InterfaceMethod< "Return all operands which are considered controlling input boolean values.", "mlir::ValueRange", "getCtrlValueOperands" >, - // InterfaceMethod< - // "Set all operands which are considered controlling input boolean values.", - // "void", "setCtrlValueOperands", (ins "mlir::ValueRange":$replacements) - // >, - // InterfaceMethod< - // "Return all operands which are considered controlling output qubit values.", - // "mlir::ResultRange", "getCtrlQubitResults" - // >, - // InterfaceMethod< - // "Return adjoint flag.", - // "bool", "getAdjointFlag" - // >, - // InterfaceMethod< - // "Set adjoint flag.", - // "void", "setAdjointFlag", (ins "bool":$adjoint) - // > + InterfaceMethod< + "Set all operands which are considered controlling input boolean values.", + "void", "setCtrlValueOperands", (ins "mlir::ValueRange":$replacements) + >, + InterfaceMethod< + "Return adjoint flag.", + "bool", "getAdjointFlag" + >, + InterfaceMethod< + "Set adjoint flag.", + "void", "setAdjointFlag", (ins "bool":$adjoint) + > ]; let verify = [{ diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 4a2a2b9415..983317afca 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -116,14 +116,46 @@ class UnitaryGate_Op traits = []> : return getWires(); } + void setNonCtrlWireOperands(mlir::ValueRange replacements) { + mlir::MutableOperandRange wires = getWiresMutable(); + assert(wires.size() == replacements.size() && + "must provide values for all non-ctrl wire values"); + wires.assign(replacements); + } + mlir::ValueRange getCtrlWireOperands() { return getCtrlWires(); } + void setCtrlWireOperands(mlir::ValueRange replacements) { + mlir::MutableOperandRange ctrlWires = getCtrlWiresMutable(); + assert(ctrlWires.size() == replacements.size() && + "must provide values for all ctrl wire values"); + ctrlWires.assign(replacements); + } + mlir::ValueRange getCtrlValueOperands() { return getCtrlValues(); } + void setCtrlValueOperands(mlir::ValueRange replacements) { + mlir::MutableOperandRange ctrlValues = getCtrlValuesMutable(); + assert(ctrlValues.size() == replacements.size() && + "must provide values for all control values"); + ctrlValues.assign(replacements); + } + + bool getAdjointFlag() { + return getAdjoint(); + } + + void setAdjointFlag(bool adjoint) { + if (adjoint) { + (*this)->setAttr("adjoint", mlir::UnitAttr::get(this->getContext())); + } else { + (*this)->removeAttr("adjoint"); + } + }; }]; let extraClassDeclaration = extraBaseClassDeclaration; diff --git a/mlir/unittests/CMakeLists.txt b/mlir/unittests/CMakeLists.txt index b0ad6d5de1..ff88fe21c2 100644 --- a/mlir/unittests/CMakeLists.txt +++ b/mlir/unittests/CMakeLists.txt @@ -10,4 +10,5 @@ function(add_catalyst_unittest test_dirname) endfunction() add_subdirectory(Example) +add_subdirectory(RefQuantum) add_subdirectory(Utils) diff --git a/mlir/unittests/RefQuantum/CMakeLists.txt b/mlir/unittests/RefQuantum/CMakeLists.txt new file mode 100644 index 0000000000..28d3273879 --- /dev/null +++ b/mlir/unittests/RefQuantum/CMakeLists.txt @@ -0,0 +1,11 @@ +add_catalyst_unittest(CatalystRefQuantumUnitTests + InterfaceTest.cpp +) + +target_link_libraries(CatalystRefQuantumUnitTests PRIVATE + MLIRArithDialect + MLIRFuncDialect + MLIRRefQuantum + MLIRIR + MLIRParser +) diff --git a/mlir/unittests/RefQuantum/InterfaceTest.cpp b/mlir/unittests/RefQuantum/InterfaceTest.cpp new file mode 100644 index 0000000000..1ba3c315a8 --- /dev/null +++ b/mlir/unittests/RefQuantum/InterfaceTest.cpp @@ -0,0 +1,225 @@ +// 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 + +#include "gtest/gtest.h" + +#include "mlir/AsmParser/AsmParser.h" +#include "mlir/AsmParser/AsmParserState.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/IR/BuiltinOps.h" +#include "mlir/IR/Verifier.h" +#include "mlir/Parser/Parser.h" +#include "llvm/Support/SourceMgr.h" + +#include "RefQuantum/IR/RefQuantumInterfaces.h" +#include "RefQuantum/IR/RefQuantumOps.h" + +using namespace mlir; + +namespace { + +TEST(InterfaceTests, Getters) +{ + std::string moduleStr = R"mlir( +func.func @f(%w0: i64, %w1: i64, %param: f64, %bool: i1) { + ref_quantum.custom "Rot"(%param, %param) %w0 adj ctrls (%w1) ctrlvals (%bool) : i64 ctrls i64 + return +} + )mlir"; + + // Parsing boilerplate + DialectRegistry registry; + registry.insert(); + MLIRContext context(registry); + ParserConfig config(&context, /*verifyAfterParse=*/false); + OwningOpRef mod = parseSourceString(moduleStr, config); + + // Parse ops + func::FuncOp f = *(*mod).getOps().begin(); + catalyst::ref_quantum::CustomOp customOp = *f.getOps().begin(); + + Block &bb = f.getCallableRegion()->front(); + auto args = bb.getArguments(); + + // Run checks + std::vector wireOperands = customOp.getWireOperands(); + ASSERT_TRUE(wireOperands.size() == 2 && wireOperands[0] == args[0] && + wireOperands[1] == args[1]); + + ValueRange nonCtrlWireOperands = customOp.getNonCtrlWireOperands(); + ASSERT_TRUE(nonCtrlWireOperands.size() == 1 && nonCtrlWireOperands[0] == args[0]); + + ValueRange ctrlWireOperands = customOp.getCtrlWireOperands(); + ASSERT_TRUE(ctrlWireOperands.size() == 1 && ctrlWireOperands[0] == args[1]); + + ValueRange ctrlValueOperands = customOp.getCtrlValueOperands(); + ASSERT_TRUE(ctrlValueOperands.size() == 1 && ctrlValueOperands[0] == args[3]); + + ASSERT_TRUE(customOp.getAdjointFlag()); + + ValueRange allParams = customOp.getAllParams(); + ASSERT_TRUE(allParams.size() == 2 && allParams[0] == args[2] && allParams[1] == args[2]); + + ASSERT_TRUE(customOp.getParam(0) == args[2]); + ASSERT_TRUE(customOp.getParam(1) == args[2]); +} + +TEST(InterfaceTests, setWireOperands) +{ + std::string moduleStr = R"mlir( +func.func @f(%w0: i64, %w1: i64, %bool: i1) { + ref_quantum.custom "Rot"() %w0 ctrls (%w1) ctrlvals (%bool) : i64 ctrls i64 + return +} + )mlir"; + + // Parsing boilerplate + DialectRegistry registry; + registry.insert(); + MLIRContext context(registry); + ParserConfig config(&context, /*verifyAfterParse=*/false); + OwningOpRef mod = parseSourceString(moduleStr, config); + + // Parse ops + func::FuncOp f = *(*mod).getOps().begin(); + catalyst::ref_quantum::CustomOp customOp = *f.getOps().begin(); + + Block &bb = f.getCallableRegion()->front(); + auto args = bb.getArguments(); + + // Run checks + customOp.setWireOperands({args[1], args[0]}); + std::vector wireOperands = customOp.getWireOperands(); + ASSERT_TRUE(wireOperands.size() == 2 && wireOperands[0] == args[1] && + wireOperands[1] == args[0]); +} + +TEST(InterfaceTests, setNonCtrlWireOperands) +{ + std::string moduleStr = R"mlir( +func.func @f(%w0: i64, %w1: i64, %w2: i64, %bool: i1) { + ref_quantum.custom "Rot"() %w0 ctrls (%w1) ctrlvals (%bool) : i64 ctrls i64 + return +} + )mlir"; + + // Parsing boilerplate + DialectRegistry registry; + registry.insert(); + MLIRContext context(registry); + ParserConfig config(&context, /*verifyAfterParse=*/false); + OwningOpRef mod = parseSourceString(moduleStr, config); + + // Parse ops + func::FuncOp f = *(*mod).getOps().begin(); + catalyst::ref_quantum::CustomOp customOp = *f.getOps().begin(); + + Block &bb = f.getCallableRegion()->front(); + auto args = bb.getArguments(); + + // Run checks + customOp.setNonCtrlWireOperands({args[2]}); + ValueRange nonCtrlWireOperands = customOp.getNonCtrlWireOperands(); + ASSERT_TRUE(nonCtrlWireOperands.size() == 1 && nonCtrlWireOperands[0] == args[2]); +} + +TEST(InterfaceTests, setCtrlWireOperands) +{ + std::string moduleStr = R"mlir( +func.func @f(%w0: i64, %w1: i64, %w2: i64, %bool: i1) { + ref_quantum.custom "Rot"() %w0 ctrls (%w1) ctrlvals (%bool) : i64 ctrls i64 + return +} + )mlir"; + + // Parsing boilerplate + DialectRegistry registry; + registry.insert(); + MLIRContext context(registry); + ParserConfig config(&context, /*verifyAfterParse=*/false); + OwningOpRef mod = parseSourceString(moduleStr, config); + + // Parse ops + func::FuncOp f = *(*mod).getOps().begin(); + catalyst::ref_quantum::CustomOp customOp = *f.getOps().begin(); + + Block &bb = f.getCallableRegion()->front(); + auto args = bb.getArguments(); + + // Run checks + customOp.setCtrlWireOperands({args[2]}); + ValueRange ctrlWireOperands = customOp.getCtrlWireOperands(); + ASSERT_TRUE(ctrlWireOperands.size() == 1 && ctrlWireOperands[0] == args[2]); +} + +TEST(InterfaceTests, setCtrlValueOperands) +{ + std::string moduleStr = R"mlir( +func.func @f(%w0: i64, %w1: i64, %bool: i1, %other_bool: i1) { + ref_quantum.custom "Rot"() %w0 ctrls (%w1) ctrlvals (%bool) : i64 ctrls i64 + return +} + )mlir"; + + // Parsing boilerplate + DialectRegistry registry; + registry.insert(); + MLIRContext context(registry); + ParserConfig config(&context, /*verifyAfterParse=*/false); + OwningOpRef mod = parseSourceString(moduleStr, config); + + // Parse ops + func::FuncOp f = *(*mod).getOps().begin(); + catalyst::ref_quantum::CustomOp customOp = *f.getOps().begin(); + + Block &bb = f.getCallableRegion()->front(); + auto args = bb.getArguments(); + + // Run checks + customOp.setCtrlValueOperands({args[3]}); + ValueRange ctrlValueOperands = customOp.getCtrlValueOperands(); + ASSERT_TRUE(ctrlValueOperands.size() == 1 && ctrlValueOperands[0] == args[3]); +} + +TEST(InterfaceTests, setAdjointFlag) +{ + std::string moduleStr = R"mlir( +func.func @f(%w0: i64) { + ref_quantum.custom "PauliX"() %w0 : i64 + return +} + )mlir"; + + // Parsing boilerplate + DialectRegistry registry; + registry.insert(); + MLIRContext context(registry); + ParserConfig config(&context, /*verifyAfterParse=*/false); + OwningOpRef mod = parseSourceString(moduleStr, config); + + // Parse ops + func::FuncOp f = *(*mod).getOps().begin(); + catalyst::ref_quantum::CustomOp customOp = *f.getOps().begin(); + + // Run checks + customOp.setAdjointFlag(true); + ASSERT_TRUE(customOp.getAdjointFlag()); + + customOp.setAdjointFlag(false); + ASSERT_TRUE(!customOp.getAdjointFlag()); +} + +} // namespace From 686a6a4f185e608207e91d524b4c7da0f4548f91 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 31 Dec 2025 13:08:48 -0500 Subject: [PATCH 04/25] save --- mlir/include/RefQuantum/IR/RefQuantumDialect.td | 6 +++++- mlir/include/RefQuantum/IR/RefQuantumOps.td | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mlir/include/RefQuantum/IR/RefQuantumDialect.td b/mlir/include/RefQuantum/IR/RefQuantumDialect.td index b82318a32a..d06b4ec33d 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumDialect.td +++ b/mlir/include/RefQuantum/IR/RefQuantumDialect.td @@ -27,7 +27,11 @@ include "mlir/Interfaces/SideEffectInterfaces.td" def RefQuantumDialect : Dialect { let summary = "Reference semantics quantum dialect."; let description = [{ - Here are words + A supplemental dialect to the core quantum dialect. + + Quantum operations in this dialect follow reference semantics (as opposed to qubit value + semantics in the core quantum dialect): the targets of quantum operations in this dialect + are all integer wire indices. }]; /// This is the namespace of the dialect in MLIR, which is used as a prefix for types and ops. diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 983317afca..66b522a7b8 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -178,7 +178,10 @@ def CustomOp : UnitaryGate_Op<"custom", [ParametrizedGate, AttrSizedOperandSegme // TODO: add convenience builders let assemblyFormat = [{ - $gate_name `(` $params `)` $wires (`adj` $adjoint^)? attr-dict ( `ctrls` `(` $ctrl_wires^ `)` )? ( `ctrlvals` `(` $ctrl_values^ `)` )? `:` type($wires) (`ctrls` type($ctrl_wires)^ )? + $gate_name `(` $params `)` $wires (`adj` $adjoint^)? attr-dict + ( `ctrls` `(` $ctrl_wires^ `)` )? + ( `ctrlvals` `(` $ctrl_values^ `)` )? + `:` type($wires) (`ctrls` type($ctrl_wires)^ )? }]; let extraClassDeclaration = extraBaseClassDeclaration # [{ From 2a500a21f21ef7aa017cfab2feb9cc19c1b0be5a Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 10:27:19 -0500 Subject: [PATCH 05/25] add observable type; add namedobs op --- .../include/RefQuantum/IR/RefQuantumDialect.h | 7 +-- .../RefQuantum/IR/RefQuantumDialect.td | 20 ++++----- mlir/include/RefQuantum/IR/RefQuantumOps.td | 45 ++++++++++++++++++- mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp | 14 +++--- .../RefQuantum/DialectTest/UnitTests.mlir | 13 ++++++ 5 files changed, 74 insertions(+), 25 deletions(-) diff --git a/mlir/include/RefQuantum/IR/RefQuantumDialect.h b/mlir/include/RefQuantum/IR/RefQuantumDialect.h index a2c1cf747c..cf96c2b2c2 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumDialect.h +++ b/mlir/include/RefQuantum/IR/RefQuantumDialect.h @@ -26,8 +26,5 @@ // RefQuantum type declarations. //===----------------------------------------------------------------------===// -// Uncomment the lines below if defining custom types for the RefQuantum dialect -// For now, I don't see a need, since plxpr does not have "qubit type" or "qreg type". - -// #define GET_TYPEDEF_CLASSES -// #include "RefQuantum/IR/RefQuantumOpsTypes.h.inc" +#define GET_TYPEDEF_CLASSES +#include "RefQuantum/IR/RefQuantumOpsTypes.h.inc" diff --git a/mlir/include/RefQuantum/IR/RefQuantumDialect.td b/mlir/include/RefQuantum/IR/RefQuantumDialect.td index d06b4ec33d..bd4b60c555 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumDialect.td +++ b/mlir/include/RefQuantum/IR/RefQuantumDialect.td @@ -46,13 +46,8 @@ def RefQuantumDialect : Dialect { // ]; /// Use the default type printing/parsing hooks, otherwise we would have to explicitly define them. - // Do I even need attributes? - // The only attr in regular quantum dialect is the named observable. - // I probably also need it.... let useDefaultAttributePrinterParser = 1; - - /// Uncomment the line below if defining types for the RefQuantum dialect - // let useDefaultTypePrinterParser = 1; + let useDefaultTypePrinterParser = 1; } @@ -60,11 +55,14 @@ def RefQuantumDialect : Dialect { // RefQuantum dialect types. //===----------------------------------------------------------------------===// -/// Uncomment the lines below if defining types for the RefQuantum dialect -// class RefQuantum_Type traits = []> -// : TypeDef { -// let mnemonic = typeMnemonic; -// } +class RefQuantum_Type traits = []> + : TypeDef { + let mnemonic = typeMnemonic; +} + +def ObservableType : RefQuantum_Type<"Observable", "obs"> { + let summary = "A quantum observable for use in measurements."; +} //===----------------------------------------------------------------------===// diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 66b522a7b8..27e3f7606f 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -24,7 +24,9 @@ include "mlir/IR/OpBase.td" include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.td" // TODO: does it depend? +// Ideally, I want the two dialects to be cleanly separated. // include "Quantum/IR/QuantumDialect.td" +// include "Quantum/IR/QuantumOps.td" include "RefQuantum/IR/RefQuantumDialect.td" include "RefQuantum/IR/RefQuantumInterfaces.td" @@ -32,6 +34,11 @@ include "RefQuantum/IR/RefQuantumInterfaces.td" // RefQuantum dialect enums. //===----------------------------------------------------------------------===// +// I do not like this duplication. +// Ideally, I want to reuse the observable types from regular quantum dialect. +// But also, I want the definition of the two dialects to compeltely decouple. +// I couldn't find a way to just include parts of the quantum dialect. + def NamedObservable : I32EnumAttr<"NamedObservable", "Known named observables", [ @@ -39,7 +46,7 @@ def NamedObservable : I32EnumAttr<"NamedObservable", I32EnumAttrCase<"PauliX", 1>, I32EnumAttrCase<"PauliY", 2>, I32EnumAttrCase<"PauliZ", 3>, - I32EnumAttrCase<"Hadamard", 4>, // Is this ever used from frontend? + I32EnumAttrCase<"Hadamard", 4>, ]> { let cppNamespace = "catalyst::ref_quantum"; let genSpecializedAttr = 0; @@ -195,4 +202,40 @@ def CustomOp : UnitaryGate_Op<"custom", [ParametrizedGate, AttrSizedOperandSegme // let hasVerifier = 1; } +// ----- + +// Observable ops are not meaningful on their own: their purpose is to be sent into a measurement +// Hence they are Pure, i.e. removable if no users + +class Observable_Op traits = []> : + RefQuantum_Op; + +def NamedObsOp : Observable_Op<"namedobs"> { + let summary = "Define a Named observable for use in measurements"; + let description = [{ + The `ref_quantum.namedobs` operation defines a quantum observable to be used by measurement + processes. The specific observable defined here represents one of 5 named observables + {Identity, PauliX, PauliY, PauliZ, Hadamard} on a qubit. The arguments are a wire to + measure as well as an encoding operator for the qubit as an integer between 0-4. + }]; + + let arguments = (ins + I64:$wire, + NamedObservableAttr:$type + ); + + let results = (outs + ObservableType:$obs + ); + + let assemblyFormat = [{ + $wire `[` $type `]` attr-dict `:` type(results) + }]; +} + +// ----- + +// class Measurement_Op traits = []> : +// Quantum_Op; + #endif // REF_QUANTUM_OPS diff --git a/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp b/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp index cd22c54a39..e810e40018 100644 --- a/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp +++ b/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp @@ -30,11 +30,10 @@ using namespace catalyst::ref_quantum; void RefQuantumDialect::initialize() { - /// Uncomment the lines below if defining types for the RefQuantum dialect - // addTypes< - // #define GET_TYPEDEF_LIST - // #include "RefQuantum/IR/RefQuantumOpsTypes.cpp.inc" - // >(); + addTypes< +#define GET_TYPEDEF_LIST +#include "RefQuantum/IR/RefQuantumOpsTypes.cpp.inc" + >(); addAttributes< #define GET_ATTRDEF_LIST @@ -51,9 +50,8 @@ void RefQuantumDialect::initialize() // RefQuantum type definitions. //===----------------------------------------------------------------------===// -/// Uncomment the lines below if defining types -// #define GET_TYPEDEF_CLASSES -// #include "RefQuantum/IR/RefQuantumOpsTypes.cpp.inc" +#define GET_TYPEDEF_CLASSES +#include "RefQuantum/IR/RefQuantumOpsTypes.cpp.inc" #define GET_ATTRDEF_CLASSES #include "RefQuantum/IR/RefQuantumAttributes.cpp.inc" diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index be6c6a0330..f7bcb3c352 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -42,3 +42,16 @@ func.func @test_custom_op(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %param0: f64, return } + +// ----- + +func.func @test_namedobs_op(%w0: i64) { + + %ox = ref_quantum.namedobs %w0 [ PauliX] : !ref_quantum.obs + %oy = ref_quantum.namedobs %w0 [ PauliY] : !ref_quantum.obs + %oz = ref_quantum.namedobs %w0 [ PauliZ] : !ref_quantum.obs + %oi = ref_quantum.namedobs %w0 [ Identity] : !ref_quantum.obs + %oh = ref_quantum.namedobs %w0 [ Hadamard] : !ref_quantum.obs + + return +} From 1d2978696e6c4dd59a41f7c112e5154f11f64ee2 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 11:27:17 -0500 Subject: [PATCH 06/25] Isolate quantum dialect enum definitions into its own file --- mlir/include/Quantum/IR/QuantumDialect.td | 7 +++ mlir/include/Quantum/IR/QuantumEnums.td | 44 ++++++++++++++++++ mlir/include/Quantum/IR/QuantumOps.td | 55 ++++++++++------------- 3 files changed, 75 insertions(+), 31 deletions(-) create mode 100644 mlir/include/Quantum/IR/QuantumEnums.td diff --git a/mlir/include/Quantum/IR/QuantumDialect.td b/mlir/include/Quantum/IR/QuantumDialect.td index c6368eceff..925374b6d8 100644 --- a/mlir/include/Quantum/IR/QuantumDialect.td +++ b/mlir/include/Quantum/IR/QuantumDialect.td @@ -73,6 +73,13 @@ def ResultType : Quantum_Type<"Result", "res"> { let summary = "A quantum measurement result."; } +//===----------------------------------------------------------------------===// +// Quantum dialect traits. +//===----------------------------------------------------------------------===// + +def Unitary : NativeOpTrait<"UnitaryTrait">; +def Hermitian : NativeOpTrait<"HermitianTrait">; + //===----------------------------------------------------------------------===// // Quantum resource abstractions. //===----------------------------------------------------------------------===// diff --git a/mlir/include/Quantum/IR/QuantumEnums.td b/mlir/include/Quantum/IR/QuantumEnums.td new file mode 100644 index 0000000000..70cc2c2836 --- /dev/null +++ b/mlir/include/Quantum/IR/QuantumEnums.td @@ -0,0 +1,44 @@ +// 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 QUANTUM_ENUMS +#define QUANTUM_ENUMS + +include "mlir/IR/EnumAttr.td" + +//===----------------------------------------------------------------------===// +// Quantum dialect enums. +//===----------------------------------------------------------------------===// + +def NamedObservable : I32EnumAttr<"NamedObservable", + "Known named observables", + [ + I32EnumAttrCase<"Identity", 0>, + I32EnumAttrCase<"PauliX", 1>, + I32EnumAttrCase<"PauliY", 2>, + I32EnumAttrCase<"PauliZ", 3>, + I32EnumAttrCase<"Hadamard", 4>, + ]> { + let cppNamespace = "catalyst::quantum"; + let genSpecializedAttr = 0; +} + +//===----------------------------------------------------------------------===// +// Quantum dialect attributes. +//===----------------------------------------------------------------------===// + +def NamedObservableAttr : EnumAttr; + + +#endif // QUANTUM_OPS diff --git a/mlir/include/Quantum/IR/QuantumOps.td b/mlir/include/Quantum/IR/QuantumOps.td index 9ec5c16c41..78f07f7916 100644 --- a/mlir/include/Quantum/IR/QuantumOps.td +++ b/mlir/include/Quantum/IR/QuantumOps.td @@ -15,44 +15,37 @@ #ifndef QUANTUM_OPS #define QUANTUM_OPS -include "mlir/IR/EnumAttr.td" +// include "mlir/IR/EnumAttr.td" include "mlir/IR/OpBase.td" include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.td" include "mlir/Interfaces/ControlFlowInterfaces.td" include "Quantum/IR/QuantumDialect.td" +include "Quantum/IR/QuantumEnums.td" include "Quantum/IR/QuantumInterfaces.td" -//===----------------------------------------------------------------------===// -// Quantum dialect enums. -//===----------------------------------------------------------------------===// - -def NamedObservable : I32EnumAttr<"NamedObservable", - "Known named observables", - [ - I32EnumAttrCase<"Identity", 0>, - I32EnumAttrCase<"PauliX", 1>, - I32EnumAttrCase<"PauliY", 2>, - I32EnumAttrCase<"PauliZ", 3>, - I32EnumAttrCase<"Hadamard", 4>, - ]> { - let cppNamespace = "catalyst::quantum"; - let genSpecializedAttr = 0; -} - - -//===----------------------------------------------------------------------===// -// Quantum dialect traits. -//===----------------------------------------------------------------------===// - -def Unitary : NativeOpTrait<"UnitaryTrait">; -def Hermitian : NativeOpTrait<"HermitianTrait">; - -//===----------------------------------------------------------------------===// -// Quantum dialect attributes. -//===----------------------------------------------------------------------===// - -def NamedObservableAttr : EnumAttr; +// //===----------------------------------------------------------------------===// +// // Quantum dialect enums. +// //===----------------------------------------------------------------------===// + +// def NamedObservable : I32EnumAttr<"NamedObservable", +// "Known named observables", +// [ +// I32EnumAttrCase<"Identity", 0>, +// I32EnumAttrCase<"PauliX", 1>, +// I32EnumAttrCase<"PauliY", 2>, +// I32EnumAttrCase<"PauliZ", 3>, +// I32EnumAttrCase<"Hadamard", 4>, +// ]> { +// let cppNamespace = "catalyst::quantum"; +// let genSpecializedAttr = 0; +// } + +// //===----------------------------------------------------------------------===// +// // Quantum dialect attributes. +// //===----------------------------------------------------------------------===// + +// def NamedObservableAttr : EnumAttr; //===----------------------------------------------------------------------===// // Quantum dialect operations. From 448e7baf1e5f38b77b7cf48d764132b138feed19 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 12:01:44 -0500 Subject: [PATCH 07/25] burn all types and enums in ref quantum dialect --- mlir/include/RefQuantum/IR/CMakeLists.txt | 3 - .../include/RefQuantum/IR/RefQuantumDialect.h | 7 -- .../RefQuantum/IR/RefQuantumDialect.td | 18 ----- mlir/include/RefQuantum/IR/RefQuantumOps.h | 5 -- mlir/include/RefQuantum/IR/RefQuantumOps.td | 74 ++++++------------- mlir/lib/RefQuantum/IR/CMakeLists.txt | 1 - mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp | 20 ----- mlir/lib/RefQuantum/IR/RefQuantumOps.cpp | 2 - .../RefQuantum/DialectTest/UnitTests.mlir | 16 ++-- 9 files changed, 32 insertions(+), 114 deletions(-) diff --git a/mlir/include/RefQuantum/IR/CMakeLists.txt b/mlir/include/RefQuantum/IR/CMakeLists.txt index 38e04414a1..0e0146a8bf 100644 --- a/mlir/include/RefQuantum/IR/CMakeLists.txt +++ b/mlir/include/RefQuantum/IR/CMakeLists.txt @@ -5,8 +5,5 @@ add_mlir_doc(RefQuantumOps RefQuantumOps RefQuantum/ -gen-op-doc) add_mlir_doc(RefQuantumInterfaces RefQuantumInterfaces RefQuantum/ -gen-op-interface-docs) set(LLVM_TARGET_DEFINITIONS RefQuantumOps.td) -mlir_tablegen(RefQuantumEnums.h.inc -gen-enum-decls) -mlir_tablegen(RefQuantumEnums.cpp.inc -gen-enum-defs) mlir_tablegen(RefQuantumAttributes.h.inc -gen-attrdef-decls -attrdefs-dialect=ref_quantum) mlir_tablegen(RefQuantumAttributes.cpp.inc -gen-attrdef-defs -attrdefs-dialect=ref_quantum) -add_public_tablegen_target(MLIRRefQuantumEnumsIncGen) diff --git a/mlir/include/RefQuantum/IR/RefQuantumDialect.h b/mlir/include/RefQuantum/IR/RefQuantumDialect.h index cf96c2b2c2..bb0787e090 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumDialect.h +++ b/mlir/include/RefQuantum/IR/RefQuantumDialect.h @@ -21,10 +21,3 @@ //===----------------------------------------------------------------------===// #include "RefQuantum/IR/RefQuantumOpsDialect.h.inc" - -//===----------------------------------------------------------------------===// -// RefQuantum type declarations. -//===----------------------------------------------------------------------===// - -#define GET_TYPEDEF_CLASSES -#include "RefQuantum/IR/RefQuantumOpsTypes.h.inc" diff --git a/mlir/include/RefQuantum/IR/RefQuantumDialect.td b/mlir/include/RefQuantum/IR/RefQuantumDialect.td index bd4b60c555..e92adc52ed 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumDialect.td +++ b/mlir/include/RefQuantum/IR/RefQuantumDialect.td @@ -44,24 +44,6 @@ def RefQuantumDialect : Dialect { // let dependentDialects = [ // "quantum::QuantumDialect" // ]; - - /// Use the default type printing/parsing hooks, otherwise we would have to explicitly define them. - let useDefaultAttributePrinterParser = 1; - let useDefaultTypePrinterParser = 1; -} - - -//===----------------------------------------------------------------------===// -// RefQuantum dialect types. -//===----------------------------------------------------------------------===// - -class RefQuantum_Type traits = []> - : TypeDef { - let mnemonic = typeMnemonic; -} - -def ObservableType : RefQuantum_Type<"Observable", "obs"> { - let summary = "A quantum observable for use in measurements."; } diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.h b/mlir/include/RefQuantum/IR/RefQuantumOps.h index 5e431b52ec..be1b2ccfa7 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.h +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.h @@ -52,10 +52,5 @@ class HermitianTrait : public TraitBase {}; // RefQuantum ops declarations. //===----------------------------------------------------------------------===// -#include "RefQuantum/IR/RefQuantumEnums.h.inc" - -#define GET_ATTRDEF_CLASSES -#include "RefQuantum/IR/RefQuantumAttributes.h.inc" - #define GET_OP_CLASSES #include "RefQuantum/IR/RefQuantumOps.h.inc" diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 27e3f7606f..e6bc070f95 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -30,27 +30,6 @@ include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.td" include "RefQuantum/IR/RefQuantumDialect.td" include "RefQuantum/IR/RefQuantumInterfaces.td" -//===----------------------------------------------------------------------===// -// RefQuantum dialect enums. -//===----------------------------------------------------------------------===// - -// I do not like this duplication. -// Ideally, I want to reuse the observable types from regular quantum dialect. -// But also, I want the definition of the two dialects to compeltely decouple. -// I couldn't find a way to just include parts of the quantum dialect. - -def NamedObservable : I32EnumAttr<"NamedObservable", - "Known named observables", - [ - I32EnumAttrCase<"Identity", 0>, - I32EnumAttrCase<"PauliX", 1>, - I32EnumAttrCase<"PauliY", 2>, - I32EnumAttrCase<"PauliZ", 3>, - I32EnumAttrCase<"Hadamard", 4>, - ]> { - let cppNamespace = "catalyst::ref_quantum"; - let genSpecializedAttr = 0; -} //===----------------------------------------------------------------------===// // RefQuantum dialect traits. @@ -59,11 +38,6 @@ def NamedObservable : I32EnumAttr<"NamedObservable", def Unitary : NativeOpTrait<"UnitaryTrait">; def Hermitian : NativeOpTrait<"HermitianTrait">; -//===----------------------------------------------------------------------===// -// RefQuantum dialect attributes. -//===----------------------------------------------------------------------===// - -def NamedObservableAttr : EnumAttr; //===----------------------------------------------------------------------===// // RefQuantum dialect operations. @@ -202,36 +176,36 @@ def CustomOp : UnitaryGate_Op<"custom", [ParametrizedGate, AttrSizedOperandSegme // let hasVerifier = 1; } -// ----- +// // ----- -// Observable ops are not meaningful on their own: their purpose is to be sent into a measurement -// Hence they are Pure, i.e. removable if no users +// // Observable ops are not meaningful on their own: their purpose is to be sent into a measurement +// // Hence they are Pure, i.e. removable if no users -class Observable_Op traits = []> : - RefQuantum_Op; +// class Observable_Op traits = []> : +// RefQuantum_Op; -def NamedObsOp : Observable_Op<"namedobs"> { - let summary = "Define a Named observable for use in measurements"; - let description = [{ - The `ref_quantum.namedobs` operation defines a quantum observable to be used by measurement - processes. The specific observable defined here represents one of 5 named observables - {Identity, PauliX, PauliY, PauliZ, Hadamard} on a qubit. The arguments are a wire to - measure as well as an encoding operator for the qubit as an integer between 0-4. - }]; +// def NamedObsOp : Observable_Op<"namedobs"> { +// let summary = "Define a Named observable for use in measurements"; +// let description = [{ +// The `ref_quantum.namedobs` operation defines a quantum observable to be used by measurement +// processes. The specific observable defined here represents one of 5 named observables +// {Identity, PauliX, PauliY, PauliZ, Hadamard} on a qubit. The arguments are a wire to +// measure as well as an encoding operator for the qubit as an integer between 0-4. +// }]; - let arguments = (ins - I64:$wire, - NamedObservableAttr:$type - ); +// let arguments = (ins +// I64:$wire, +// NamedObservableAttr:$type +// ); - let results = (outs - ObservableType:$obs - ); +// let results = (outs +// ObservableType:$obs +// ); - let assemblyFormat = [{ - $wire `[` $type `]` attr-dict `:` type(results) - }]; -} +// let assemblyFormat = [{ +// $wire `[` $type `]` attr-dict `:` type(results) +// }]; +// } // ----- diff --git a/mlir/lib/RefQuantum/IR/CMakeLists.txt b/mlir/lib/RefQuantum/IR/CMakeLists.txt index fe8690b0b1..f4600de447 100644 --- a/mlir/lib/RefQuantum/IR/CMakeLists.txt +++ b/mlir/lib/RefQuantum/IR/CMakeLists.txt @@ -9,5 +9,4 @@ add_mlir_library(MLIRRefQuantum DEPENDS MLIRQuantumInterfacesIncGen MLIRRefQuantumOpsIncGen - MLIRRefQuantumEnumsIncGen ) diff --git a/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp b/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp index e810e40018..3256870a7f 100644 --- a/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp +++ b/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp @@ -30,28 +30,8 @@ using namespace catalyst::ref_quantum; void RefQuantumDialect::initialize() { - addTypes< -#define GET_TYPEDEF_LIST -#include "RefQuantum/IR/RefQuantumOpsTypes.cpp.inc" - >(); - - addAttributes< -#define GET_ATTRDEF_LIST -#include "RefQuantum/IR/RefQuantumAttributes.cpp.inc" - >(); - addOperations< #define GET_OP_LIST #include "RefQuantum/IR/RefQuantumOps.cpp.inc" >(); } - -//===----------------------------------------------------------------------===// -// RefQuantum type definitions. -//===----------------------------------------------------------------------===// - -#define GET_TYPEDEF_CLASSES -#include "RefQuantum/IR/RefQuantumOpsTypes.cpp.inc" - -#define GET_ATTRDEF_CLASSES -#include "RefQuantum/IR/RefQuantumAttributes.cpp.inc" diff --git a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp index a2b97ed8a7..64ea1a83e8 100644 --- a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp +++ b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp @@ -27,8 +27,6 @@ using namespace catalyst::ref_quantum; // RefQuantum op definitions. //===----------------------------------------------------------------------===// -#include "RefQuantum/IR/RefQuantumEnums.cpp.inc" - #define GET_OP_CLASSES #include "RefQuantum/IR/RefQuantumOps.cpp.inc" diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index f7bcb3c352..42533f91a2 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -45,13 +45,13 @@ func.func @test_custom_op(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %param0: f64, // ----- -func.func @test_namedobs_op(%w0: i64) { +// func.func @test_namedobs_op(%w0: i64) { - %ox = ref_quantum.namedobs %w0 [ PauliX] : !ref_quantum.obs - %oy = ref_quantum.namedobs %w0 [ PauliY] : !ref_quantum.obs - %oz = ref_quantum.namedobs %w0 [ PauliZ] : !ref_quantum.obs - %oi = ref_quantum.namedobs %w0 [ Identity] : !ref_quantum.obs - %oh = ref_quantum.namedobs %w0 [ Hadamard] : !ref_quantum.obs +// %ox = ref_quantum.namedobs %w0 [ PauliX] : !ref_quantum.obs +// %oy = ref_quantum.namedobs %w0 [ PauliY] : !ref_quantum.obs +// %oz = ref_quantum.namedobs %w0 [ PauliZ] : !ref_quantum.obs +// %oi = ref_quantum.namedobs %w0 [ Identity] : !ref_quantum.obs +// %oh = ref_quantum.namedobs %w0 [ Hadamard] : !ref_quantum.obs - return -} +// return +// } From 80bdd3c88d8def04b1497f7c96adaddf65b6a9ee Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 12:17:11 -0500 Subject: [PATCH 08/25] Isolate quantum dialect's enums and traits into "include" files --- mlir/include/Quantum/IR/QuantumEnums.td | 2 ++ mlir/include/Quantum/IR/QuantumOps.h | 17 +------------ mlir/include/Quantum/IR/QuantumOps.td | 23 ----------------- mlir/include/Quantum/IR/QuantumTraits.h | 33 +++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 39 deletions(-) create mode 100644 mlir/include/Quantum/IR/QuantumTraits.h diff --git a/mlir/include/Quantum/IR/QuantumEnums.td b/mlir/include/Quantum/IR/QuantumEnums.td index 70cc2c2836..e568f94910 100644 --- a/mlir/include/Quantum/IR/QuantumEnums.td +++ b/mlir/include/Quantum/IR/QuantumEnums.td @@ -17,6 +17,8 @@ include "mlir/IR/EnumAttr.td" +include "Quantum/IR/QuantumDialect.td" + //===----------------------------------------------------------------------===// // Quantum dialect enums. //===----------------------------------------------------------------------===// diff --git a/mlir/include/Quantum/IR/QuantumOps.h b/mlir/include/Quantum/IR/QuantumOps.h index 67dde7ddca..823b4d3e68 100644 --- a/mlir/include/Quantum/IR/QuantumOps.h +++ b/mlir/include/Quantum/IR/QuantumOps.h @@ -28,22 +28,7 @@ #include "mlir/Support/LogicalResult.h" #include "Quantum/IR/QuantumInterfaces.h" - -//===----------------------------------------------------------------------===// -// Quantum trait declarations. -//===----------------------------------------------------------------------===// - -namespace mlir { -namespace OpTrait { - -template -class UnitaryTrait : public TraitBase {}; - -template -class HermitianTrait : public TraitBase {}; - -} // namespace OpTrait -} // namespace mlir +#include "Quantum/IR/QuantumTraits.h" //===----------------------------------------------------------------------===// // Quantum ops declarations. diff --git a/mlir/include/Quantum/IR/QuantumOps.td b/mlir/include/Quantum/IR/QuantumOps.td index 78f07f7916..b418042608 100644 --- a/mlir/include/Quantum/IR/QuantumOps.td +++ b/mlir/include/Quantum/IR/QuantumOps.td @@ -24,29 +24,6 @@ include "Quantum/IR/QuantumDialect.td" include "Quantum/IR/QuantumEnums.td" include "Quantum/IR/QuantumInterfaces.td" -// //===----------------------------------------------------------------------===// -// // Quantum dialect enums. -// //===----------------------------------------------------------------------===// - -// def NamedObservable : I32EnumAttr<"NamedObservable", -// "Known named observables", -// [ -// I32EnumAttrCase<"Identity", 0>, -// I32EnumAttrCase<"PauliX", 1>, -// I32EnumAttrCase<"PauliY", 2>, -// I32EnumAttrCase<"PauliZ", 3>, -// I32EnumAttrCase<"Hadamard", 4>, -// ]> { -// let cppNamespace = "catalyst::quantum"; -// let genSpecializedAttr = 0; -// } - -// //===----------------------------------------------------------------------===// -// // Quantum dialect attributes. -// //===----------------------------------------------------------------------===// - -// def NamedObservableAttr : EnumAttr; - //===----------------------------------------------------------------------===// // Quantum dialect operations. //===----------------------------------------------------------------------===// diff --git a/mlir/include/Quantum/IR/QuantumTraits.h b/mlir/include/Quantum/IR/QuantumTraits.h new file mode 100644 index 0000000000..141f791a6e --- /dev/null +++ b/mlir/include/Quantum/IR/QuantumTraits.h @@ -0,0 +1,33 @@ +// 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/OpDefinition.h" + +//===----------------------------------------------------------------------===// +// Quantum trait declarations. +//===----------------------------------------------------------------------===// + +namespace mlir { +namespace OpTrait { + +template +class UnitaryTrait : public TraitBase {}; + +template +class HermitianTrait : public TraitBase {}; + +} // namespace OpTrait +} // namespace mlir From e2a84c185de9405a5738dde5537d07c8632eab85 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 12:25:44 -0500 Subject: [PATCH 09/25] traits --- mlir/include/RefQuantum/IR/RefQuantumOps.h | 16 +--------------- mlir/include/RefQuantum/IR/RefQuantumOps.td | 12 +----------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.h b/mlir/include/RefQuantum/IR/RefQuantumOps.h index be1b2ccfa7..eb6f8e4478 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.h +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.h @@ -29,24 +29,10 @@ // TODO: is it dependent on the regular quantum dialect? // #include "Quantum/IR/QuantumDialect.h" +#include "Quantum/IR/QuantumTraits.h" #include "RefQuantum/IR/RefQuantumDialect.h" #include "RefQuantum/IR/RefQuantumInterfaces.h" -//===----------------------------------------------------------------------===// -// RefQuantum trait declarations. -//===----------------------------------------------------------------------===// - -namespace mlir { -namespace OpTrait { - -template -class UnitaryTrait : public TraitBase {}; - -template -class HermitianTrait : public TraitBase {}; - -} // namespace OpTrait -} // namespace mlir //===----------------------------------------------------------------------===// // RefQuantum ops declarations. diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index e6bc070f95..cafe9fbef0 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -25,20 +25,10 @@ include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.td" // TODO: does it depend? // Ideally, I want the two dialects to be cleanly separated. -// include "Quantum/IR/QuantumDialect.td" -// include "Quantum/IR/QuantumOps.td" +include "Quantum/IR/QuantumDialect.td" include "RefQuantum/IR/RefQuantumDialect.td" include "RefQuantum/IR/RefQuantumInterfaces.td" - -//===----------------------------------------------------------------------===// -// RefQuantum dialect traits. -//===----------------------------------------------------------------------===// - -def Unitary : NativeOpTrait<"UnitaryTrait">; -def Hermitian : NativeOpTrait<"HermitianTrait">; - - //===----------------------------------------------------------------------===// // RefQuantum dialect operations. //===----------------------------------------------------------------------===// From 5dde1c31afa6f89a327fa80a4a0e23ae91d8d586 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 12:46:25 -0500 Subject: [PATCH 10/25] add Quantum as dependent dialect --- mlir/include/RefQuantum/IR/RefQuantumDialect.td | 7 +++---- mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp | 1 + mlir/unittests/RefQuantum/CMakeLists.txt | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mlir/include/RefQuantum/IR/RefQuantumDialect.td b/mlir/include/RefQuantum/IR/RefQuantumDialect.td index e92adc52ed..205e6f7fed 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumDialect.td +++ b/mlir/include/RefQuantum/IR/RefQuantumDialect.td @@ -40,10 +40,9 @@ def RefQuantumDialect : Dialect { /// This is the C++ namespace in which the dialect and all of its sub-components are placed. let cppNamespace = "::catalyst::ref_quantum"; - // TODO: does it depend? - // let dependentDialects = [ - // "quantum::QuantumDialect" - // ]; + let dependentDialects = [ + "quantum::QuantumDialect" + ]; } diff --git a/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp b/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp index 3256870a7f..4a5bc12100 100644 --- a/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp +++ b/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp @@ -16,6 +16,7 @@ #include "mlir/IR/DialectImplementation.h" // needed for generated type parser #include "llvm/ADT/TypeSwitch.h" // needed for generated type parser +#include "Quantum/IR/QuantumDialect.h" #include "RefQuantum/IR/RefQuantumDialect.h" #include "RefQuantum/IR/RefQuantumOps.h" diff --git a/mlir/unittests/RefQuantum/CMakeLists.txt b/mlir/unittests/RefQuantum/CMakeLists.txt index 28d3273879..bb95d17fac 100644 --- a/mlir/unittests/RefQuantum/CMakeLists.txt +++ b/mlir/unittests/RefQuantum/CMakeLists.txt @@ -6,6 +6,7 @@ target_link_libraries(CatalystRefQuantumUnitTests PRIVATE MLIRArithDialect MLIRFuncDialect MLIRRefQuantum + MLIRQuantum MLIRIR MLIRParser ) From 2e8275df6a59c91cf709a644a7a83cd927718ce3 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 12:49:24 -0500 Subject: [PATCH 11/25] can use quantum dialect observable type --- mlir/include/RefQuantum/IR/RefQuantumOps.h | 6 +-- mlir/include/RefQuantum/IR/RefQuantumOps.td | 54 ++++++++++--------- .../RefQuantum/DialectTest/UnitTests.mlir | 18 ++++--- 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.h b/mlir/include/RefQuantum/IR/RefQuantumOps.h index eb6f8e4478..258271dc40 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.h +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.h @@ -18,17 +18,13 @@ #include "llvm/ADT/StringRef.h" -// #include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/Dialect.h" #include "mlir/IR/OpDefinition.h" #include "mlir/IR/PatternMatch.h" -// #include "mlir/Interfaces/ControlFlowInterfaces.h" #include "mlir/Support/LogicalResult.h" -// TODO: is it dependent on the regular quantum dialect? -// #include "Quantum/IR/QuantumDialect.h" - +#include "Quantum/IR/QuantumDialect.h" #include "Quantum/IR/QuantumTraits.h" #include "RefQuantum/IR/RefQuantumDialect.h" #include "RefQuantum/IR/RefQuantumInterfaces.h" diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index cafe9fbef0..7b06dad536 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -26,6 +26,7 @@ include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.td" // TODO: does it depend? // Ideally, I want the two dialects to be cleanly separated. include "Quantum/IR/QuantumDialect.td" +include "Quantum/IR/QuantumEnums.td" include "RefQuantum/IR/RefQuantumDialect.td" include "RefQuantum/IR/RefQuantumInterfaces.td" @@ -171,31 +172,34 @@ def CustomOp : UnitaryGate_Op<"custom", [ParametrizedGate, AttrSizedOperandSegme // // Observable ops are not meaningful on their own: their purpose is to be sent into a measurement // // Hence they are Pure, i.e. removable if no users -// class Observable_Op traits = []> : -// RefQuantum_Op; - -// def NamedObsOp : Observable_Op<"namedobs"> { -// let summary = "Define a Named observable for use in measurements"; -// let description = [{ -// The `ref_quantum.namedobs` operation defines a quantum observable to be used by measurement -// processes. The specific observable defined here represents one of 5 named observables -// {Identity, PauliX, PauliY, PauliZ, Hadamard} on a qubit. The arguments are a wire to -// measure as well as an encoding operator for the qubit as an integer between 0-4. -// }]; - -// let arguments = (ins -// I64:$wire, -// NamedObservableAttr:$type -// ); - -// let results = (outs -// ObservableType:$obs -// ); - -// let assemblyFormat = [{ -// $wire `[` $type `]` attr-dict `:` type(results) -// }]; -// } +class Observable_Op traits = []> : + RefQuantum_Op; + +def NamedObsOp : Observable_Op<"namedobs"> { + let summary = "Define a Named observable for use in measurements"; + let description = [{ + The `ref_quantum.namedobs` operation defines a quantum observable to be used by measurement + processes. The specific observable defined here represents one of 5 named observables + {Identity, PauliX, PauliY, PauliZ, Hadamard} on a qubit. The arguments are a wire to + measure as well as an encoding operator for the qubit as an integer between 0-4. + }]; + + let arguments = (ins + I64:$wire + //NamedObservableAttr:$type + ); + + let results = (outs + ObservableType:$obs + ); + + // let assemblyFormat = [{ + // $wire `[` $type `]` attr-dict `:` type(results) + // }]; + let assemblyFormat = [{ + $wire attr-dict `:` type(results) + }]; +} // ----- diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index 42533f91a2..7172e1ad5b 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -45,13 +45,15 @@ func.func @test_custom_op(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %param0: f64, // ----- -// func.func @test_namedobs_op(%w0: i64) { +func.func @test_namedobs_op(%w0: i64) { -// %ox = ref_quantum.namedobs %w0 [ PauliX] : !ref_quantum.obs -// %oy = ref_quantum.namedobs %w0 [ PauliY] : !ref_quantum.obs -// %oz = ref_quantum.namedobs %w0 [ PauliZ] : !ref_quantum.obs -// %oi = ref_quantum.namedobs %w0 [ Identity] : !ref_quantum.obs -// %oh = ref_quantum.namedobs %w0 [ Hadamard] : !ref_quantum.obs + //%ox = ref_quantum.namedobs %w0 [ PauliX] : !ref_quantum.obs + //%oy = ref_quantum.namedobs %w0 [ PauliY] : !ref_quantum.obs + //%oz = ref_quantum.namedobs %w0 [ PauliZ] : !ref_quantum.obs + //%oi = ref_quantum.namedobs %w0 [ Identity] : !ref_quantum.obs + //%oh = ref_quantum.namedobs %w0 [ Hadamard] : !ref_quantum.obs -// return -// } + %oh = ref_quantum.namedobs %w0 : !quantum.obs + + return +} From c739adda1370bff5f3276ad2f856ec19fbfc2960 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 14:21:40 -0500 Subject: [PATCH 12/25] use NamedObservable enum and attr from core quantum dialect --- mlir/include/RefQuantum/IR/RefQuantumOps.h | 4 ++++ mlir/include/RefQuantum/IR/RefQuantumOps.td | 9 +++------ mlir/test/RefQuantum/DialectTest/UnitTests.mlir | 12 +++++------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.h b/mlir/include/RefQuantum/IR/RefQuantumOps.h index 258271dc40..fb24058d49 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.h +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.h @@ -34,5 +34,9 @@ // RefQuantum ops declarations. //===----------------------------------------------------------------------===// +#include "Quantum/IR/QuantumEnums.h.inc" +#define GET_ATTRDEF_CLASSES +#include "Quantum/IR/QuantumAttributes.h.inc" + #define GET_OP_CLASSES #include "RefQuantum/IR/RefQuantumOps.h.inc" diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 7b06dad536..8c96f9c821 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -185,19 +185,16 @@ def NamedObsOp : Observable_Op<"namedobs"> { }]; let arguments = (ins - I64:$wire - //NamedObservableAttr:$type + I64:$wire, + NamedObservableAttr:$type ); let results = (outs ObservableType:$obs ); - // let assemblyFormat = [{ - // $wire `[` $type `]` attr-dict `:` type(results) - // }]; let assemblyFormat = [{ - $wire attr-dict `:` type(results) + $wire `[` $type `]` attr-dict `:` type(results) }]; } diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index 7172e1ad5b..6e52ddb76c 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -47,13 +47,11 @@ func.func @test_custom_op(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %param0: f64, func.func @test_namedobs_op(%w0: i64) { - //%ox = ref_quantum.namedobs %w0 [ PauliX] : !ref_quantum.obs - //%oy = ref_quantum.namedobs %w0 [ PauliY] : !ref_quantum.obs - //%oz = ref_quantum.namedobs %w0 [ PauliZ] : !ref_quantum.obs - //%oi = ref_quantum.namedobs %w0 [ Identity] : !ref_quantum.obs - //%oh = ref_quantum.namedobs %w0 [ Hadamard] : !ref_quantum.obs - - %oh = ref_quantum.namedobs %w0 : !quantum.obs + %ox = ref_quantum.namedobs %w0 [ PauliX] : !quantum.obs + %oy = ref_quantum.namedobs %w0 [ PauliY] : !quantum.obs + %oz = ref_quantum.namedobs %w0 [ PauliZ] : !quantum.obs + %oi = ref_quantum.namedobs %w0 [ Identity] : !quantum.obs + %oh = ref_quantum.namedobs %w0 [ Hadamard] : !quantum.obs return } From 8515954c076bb45cf54ce4b249c7523adffe527b Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 14:28:32 -0500 Subject: [PATCH 13/25] verifier test for bad attribute on namedobs --- mlir/test/RefQuantum/DialectTest/VerifierTests.mlir | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir index 01a8dd081b..439a2027ee 100644 --- a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir @@ -59,3 +59,12 @@ func.func @test_duplicate_wires2(%w0: i64) { ref_quantum.custom "PauliX"() %w0 ctrls (%w0) ctrlvals (%true) : i64 ctrls i64 return } + +// ----- + +func.func @test_namedobs_op_bad_attribute(%w0: i64) { + // expected-error@+2 {{expected catalyst::quantum::NamedObservable to be one of: Identity, PauliX, PauliY, PauliZ, Hadamard}} + // expected-error@+1 {{failed to parse NamedObservableAttr parameter 'value' which is to be a `catalyst::quantum::NamedObservable`}} + %0 = ref_quantum.namedobs %w0 [ bad] : !quantum.obs + return +} From 1da57b16b17be2d078dc9b8cc803e63e9ec8411f Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 14:49:49 -0500 Subject: [PATCH 14/25] burn unnecessary stuff --- mlir/include/RefQuantum/IR/RefQuantumOps.td | 2 -- mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp | 3 --- 2 files changed, 5 deletions(-) diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 8c96f9c821..b287146d5a 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -23,8 +23,6 @@ include "mlir/IR/OpBase.td" // ref dialect ---> value dialect ---> bufferization ---> .... include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.td" -// TODO: does it depend? -// Ideally, I want the two dialects to be cleanly separated. include "Quantum/IR/QuantumDialect.td" include "Quantum/IR/QuantumEnums.td" include "RefQuantum/IR/RefQuantumDialect.td" diff --git a/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp b/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp index 4a5bc12100..0378038357 100644 --- a/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp +++ b/mlir/lib/RefQuantum/IR/RefQuantumDialect.cpp @@ -13,10 +13,7 @@ // 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 "Quantum/IR/QuantumDialect.h" #include "RefQuantum/IR/RefQuantumDialect.h" #include "RefQuantum/IR/RefQuantumOps.h" From 843c9394fef8faa886cd3e11dda3559cb00990de Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 2 Jan 2026 15:04:36 -0500 Subject: [PATCH 15/25] add a small end-to-end unit test on hadamard(0)-expval(X(0)) --- mlir/test/RefQuantum/DialectTest/UnitTests.mlir | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index 6e52ddb76c..8d4053d3ea 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -55,3 +55,13 @@ func.func @test_namedobs_op(%w0: i64) { return } + +// ----- + +func.func @test_expval_circuit() -> f64 { + %0 = arith.constant 0 : i64 + ref_quantum.custom "Hadamard"() %0 : i64 + %obs = ref_quantum.namedobs %0 [ PauliX] : !quantum.obs + %expval = quantum.expval %obs : f64 + return %expval : f64 +} From 1c9100c01f4268b7be471efd58924ae6357d6e46 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Thu, 15 Jan 2026 10:22:51 -0500 Subject: [PATCH 16/25] migrate to Joey's new system --- mlir/include/Quantum/IR/QuantumDialect.td | 7 ---- mlir/include/Quantum/IR/QuantumEnums.td | 46 --------------------- mlir/include/Quantum/IR/QuantumOps.h | 1 - mlir/include/Quantum/IR/QuantumOps.td | 1 - mlir/include/Quantum/IR/QuantumTraits.h | 33 --------------- mlir/include/RefQuantum/IR/RefQuantumOps.h | 6 --- mlir/include/RefQuantum/IR/RefQuantumOps.td | 3 +- 7 files changed, 2 insertions(+), 95 deletions(-) delete mode 100644 mlir/include/Quantum/IR/QuantumEnums.td delete mode 100644 mlir/include/Quantum/IR/QuantumTraits.h diff --git a/mlir/include/Quantum/IR/QuantumDialect.td b/mlir/include/Quantum/IR/QuantumDialect.td index b5113bf660..64c98859a9 100644 --- a/mlir/include/Quantum/IR/QuantumDialect.td +++ b/mlir/include/Quantum/IR/QuantumDialect.td @@ -57,13 +57,6 @@ def QuantumDialect : Dialect { def Unitary : NativeOpTrait<"UnitaryTrait">; def Hermitian : NativeOpTrait<"HermitianTrait">; -//===----------------------------------------------------------------------===// -// Quantum dialect traits. -//===----------------------------------------------------------------------===// - -def Unitary : NativeOpTrait<"UnitaryTrait">; -def Hermitian : NativeOpTrait<"HermitianTrait">; - //===----------------------------------------------------------------------===// // Quantum resource abstractions. //===----------------------------------------------------------------------===// diff --git a/mlir/include/Quantum/IR/QuantumEnums.td b/mlir/include/Quantum/IR/QuantumEnums.td deleted file mode 100644 index e568f94910..0000000000 --- a/mlir/include/Quantum/IR/QuantumEnums.td +++ /dev/null @@ -1,46 +0,0 @@ -// 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 QUANTUM_ENUMS -#define QUANTUM_ENUMS - -include "mlir/IR/EnumAttr.td" - -include "Quantum/IR/QuantumDialect.td" - -//===----------------------------------------------------------------------===// -// Quantum dialect enums. -//===----------------------------------------------------------------------===// - -def NamedObservable : I32EnumAttr<"NamedObservable", - "Known named observables", - [ - I32EnumAttrCase<"Identity", 0>, - I32EnumAttrCase<"PauliX", 1>, - I32EnumAttrCase<"PauliY", 2>, - I32EnumAttrCase<"PauliZ", 3>, - I32EnumAttrCase<"Hadamard", 4>, - ]> { - let cppNamespace = "catalyst::quantum"; - let genSpecializedAttr = 0; -} - -//===----------------------------------------------------------------------===// -// Quantum dialect attributes. -//===----------------------------------------------------------------------===// - -def NamedObservableAttr : EnumAttr; - - -#endif // QUANTUM_OPS diff --git a/mlir/include/Quantum/IR/QuantumOps.h b/mlir/include/Quantum/IR/QuantumOps.h index 45f08de26e..3a14dd605b 100644 --- a/mlir/include/Quantum/IR/QuantumOps.h +++ b/mlir/include/Quantum/IR/QuantumOps.h @@ -29,7 +29,6 @@ #include "Quantum/IR/QuantumDialect.h" #include "Quantum/IR/QuantumInterfaces.h" -#include "Quantum/IR/QuantumTraits.h" //===----------------------------------------------------------------------===// // Quantum ops declarations. diff --git a/mlir/include/Quantum/IR/QuantumOps.td b/mlir/include/Quantum/IR/QuantumOps.td index c76e284b58..165aa880d1 100644 --- a/mlir/include/Quantum/IR/QuantumOps.td +++ b/mlir/include/Quantum/IR/QuantumOps.td @@ -21,7 +21,6 @@ include "mlir/Interfaces/ControlFlowInterfaces.td" include "Quantum/IR/QuantumAttrDefs.td" include "Quantum/IR/QuantumDialect.td" -include "Quantum/IR/QuantumEnums.td" include "Quantum/IR/QuantumInterfaces.td" include "Quantum/IR/QuantumTypes.td" diff --git a/mlir/include/Quantum/IR/QuantumTraits.h b/mlir/include/Quantum/IR/QuantumTraits.h deleted file mode 100644 index 141f791a6e..0000000000 --- a/mlir/include/Quantum/IR/QuantumTraits.h +++ /dev/null @@ -1,33 +0,0 @@ -// 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/OpDefinition.h" - -//===----------------------------------------------------------------------===// -// Quantum trait declarations. -//===----------------------------------------------------------------------===// - -namespace mlir { -namespace OpTrait { - -template -class UnitaryTrait : public TraitBase {}; - -template -class HermitianTrait : public TraitBase {}; - -} // namespace OpTrait -} // namespace mlir diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.h b/mlir/include/RefQuantum/IR/RefQuantumOps.h index fb24058d49..389f6288b1 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.h +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.h @@ -25,18 +25,12 @@ #include "mlir/Support/LogicalResult.h" #include "Quantum/IR/QuantumDialect.h" -#include "Quantum/IR/QuantumTraits.h" #include "RefQuantum/IR/RefQuantumDialect.h" #include "RefQuantum/IR/RefQuantumInterfaces.h" - //===----------------------------------------------------------------------===// // RefQuantum ops declarations. //===----------------------------------------------------------------------===// -#include "Quantum/IR/QuantumEnums.h.inc" -#define GET_ATTRDEF_CLASSES -#include "Quantum/IR/QuantumAttributes.h.inc" - #define GET_OP_CLASSES #include "RefQuantum/IR/RefQuantumOps.h.inc" diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index b287146d5a..d85975f43d 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -23,8 +23,9 @@ include "mlir/IR/OpBase.td" // ref dialect ---> value dialect ---> bufferization ---> .... include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.td" +include "Quantum/IR/QuantumAttrDefs.td" include "Quantum/IR/QuantumDialect.td" -include "Quantum/IR/QuantumEnums.td" +include "Quantum/IR/QuantumTypes.td" include "RefQuantum/IR/RefQuantumDialect.td" include "RefQuantum/IR/RefQuantumInterfaces.td" From 56e6377523a27e39017ccab4fef36e398e473612 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Thu, 15 Jan 2026 11:24:17 -0500 Subject: [PATCH 17/25] set state and basis state --- mlir/include/RefQuantum/IR/RefQuantumOps.td | 41 +++++++++++++++++++ .../RefQuantum/DialectTest/UnitTests.mlir | 15 +++++++ 2 files changed, 56 insertions(+) diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index d85975f43d..09cdd27f87 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -132,6 +132,47 @@ class UnitaryGate_Op traits = []> : let extraClassDeclaration = extraBaseClassDeclaration; } +def SetStateOp : Gate_Op<"set_state"> { + let summary = "Set state to a complex vector."; + let description = [{ + This operation is useful for simulators implementing state preparation. + Instead of decomposing state preparation into multiple operations, this + operation shortcuts all of that into a single operation. + }]; + + let arguments = (ins + 1DTensorOf<[Complex]>:$in_state, + Variadic:$wires + ); + + let assemblyFormat = [{ + `(` $in_state `)` $wires attr-dict `:` type(operands) + }]; + +} + + +def SetBasisStateOp : Gate_Op<"set_basis_state"> { + let summary = "Set basis state."; + let description = [{ + This operation is useful for simulators implementing set basis state. + Instead of decomposing basis state into multiple operations, this + operation shortcuts all of that into a single operation. + This signature matches the one in pennylane-lightning which expects + only a single integer as opposed to a binary digit. + }]; + + let arguments = (ins + 1DTensorOf<[I1]>:$basis_state, + Variadic:$wires + ); + + let assemblyFormat = [{ + `(` $basis_state`)` $wires attr-dict `:` type(operands) + }]; +} + + def CustomOp : UnitaryGate_Op<"custom", [ParametrizedGate, AttrSizedOperandSegments]> { let summary = "A generic quantum gate on n qubits with m floating point parameters."; let description = [{ diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index 8d4053d3ea..de67340b0f 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -16,6 +16,21 @@ // // RUN: quantum-opt --split-input-file --verify-diagnostics %s + +func.func @test_set_state(%arg0 : tensor<2xcomplex>, %w0: i64) { + ref_quantum.set_state(%arg0) %w0 : tensor<2xcomplex>, i64 + return +} + +// ----- + +func.func @test_basis_state(%arg0 : tensor<1xi1>, %w0: i64) { + ref_quantum.set_basis_state(%arg0) %w0 : tensor<1xi1>, i64 + return +} + +// ----- + func.func @test_custom_op(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %param0: f64, %param1: f64) { // Basic From 85cda40036e1dba46f5de07cf10ef4f84527b3de Mon Sep 17 00:00:00 2001 From: paul0403 Date: Thu, 15 Jan 2026 13:37:54 -0500 Subject: [PATCH 18/25] gphase op --- mlir/include/RefQuantum/IR/RefQuantumOps.td | 36 ++++++++++++++++++ .../RefQuantum/DialectTest/UnitTests.mlir | 19 ++++++++++ .../RefQuantum/DialectTest/VerifierTests.mlir | 9 +++++ mlir/unittests/RefQuantum/InterfaceTest.cpp | 37 +++++++++++++++++++ 4 files changed, 101 insertions(+) diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 09cdd27f87..20d7c3e095 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -207,6 +207,42 @@ def CustomOp : UnitaryGate_Op<"custom", [ParametrizedGate, AttrSizedOperandSegme // let hasVerifier = 1; } +def GlobalPhaseOp : UnitaryGate_Op<"gphase", [ParametrizedGate, AttrSizedOperandSegments]> { + let summary = "Global Phase."; + + let description = [{ + Applies global phase to the current system. + }]; + + let arguments = (ins + F64:$params, + UnitAttr:$adjoint, + Variadic:$ctrl_wires, + Variadic:$ctrl_values + ); + + let assemblyFormat = [{ + `(` $params `)` (`adj` $adjoint^)? attr-dict + ( `ctrls` `(` $ctrl_wires^ `)` )? + ( `ctrlvals` `(` $ctrl_values^ `)` )? + `:` type($params) (`ctrls` type($ctrl_wires)^ )? + }]; + + let extraClassDeclaration = extraBaseClassDeclaration # [{ + mlir::ValueRange getAllParams() { + return getODSOperands(0); // `params` is the 0-th operand + } + + // Simulate missing operands and results for the default impl of the quantum gate interface. + mlir::OperandRange getWires() { + return {getOperands().begin(), getOperands().begin()}; + } + mlir::MutableOperandRange getWiresMutable() { + return mlir::MutableOperandRange(getOperation(), 0, 0); + } + }]; +} + // // ----- // // Observable ops are not meaningful on their own: their purpose is to be sent into a measurement diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index de67340b0f..90b10cf957 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -60,6 +60,25 @@ func.func @test_custom_op(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %param0: f64, // ----- +func.func @test_global_phase(%w0: i64, %cv: i1, %param: f64) { + + // Basic + ref_quantum.gphase(%param) : f64 + + // With adjoint + ref_quantum.gphase(%param) adj : f64 + + // With control + ref_quantum.gphase(%param) ctrls (%w0) ctrlvals (%cv) : f64 ctrls i64 + + // With control and adjoint + ref_quantum.gphase(%param) adj ctrls (%w0) ctrlvals (%cv) : f64 ctrls i64 + + return +} + +// ----- + func.func @test_namedobs_op(%w0: i64) { %ox = ref_quantum.namedobs %w0 [ PauliX] : !quantum.obs diff --git a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir index 439a2027ee..8c7d1baf02 100644 --- a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir @@ -62,6 +62,15 @@ func.func @test_duplicate_wires2(%w0: i64) { // ----- +func.func @test_gphase_control(%w0: i64, %param: f64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{number of controlling wires in input (1) and controlling values (2) must be the same}} + ref_quantum.gphase(%param) ctrls (%w0) ctrlvals (%true, %true) : f64 ctrls i64 + return +} + +// ----- + func.func @test_namedobs_op_bad_attribute(%w0: i64) { // expected-error@+2 {{expected catalyst::quantum::NamedObservable to be one of: Identity, PauliX, PauliY, PauliZ, Hadamard}} // expected-error@+1 {{failed to parse NamedObservableAttr parameter 'value' which is to be a `catalyst::quantum::NamedObservable`}} diff --git a/mlir/unittests/RefQuantum/InterfaceTest.cpp b/mlir/unittests/RefQuantum/InterfaceTest.cpp index 1ba3c315a8..8fb263a6e6 100644 --- a/mlir/unittests/RefQuantum/InterfaceTest.cpp +++ b/mlir/unittests/RefQuantum/InterfaceTest.cpp @@ -222,4 +222,41 @@ func.func @f(%w0: i64) { ASSERT_TRUE(!customOp.getAdjointFlag()); } +TEST(InterfaceTests, globalPhase) +{ + std::string moduleStr = R"mlir( +func.func @f(%w0: i64, %cv: i1, %param: f64) { + ref_quantum.gphase(%param) adj ctrls (%w0) ctrlvals (%cv) : f64 ctrls i64 + return +} + )mlir"; + + // Parsing boilerplate + DialectRegistry registry; + registry.insert(); + MLIRContext context(registry); + ParserConfig config(&context, /*verifyAfterParse=*/false); + OwningOpRef mod = parseSourceString(moduleStr, config); + + // Parse ops + func::FuncOp f = *(*mod).getOps().begin(); + catalyst::ref_quantum::GlobalPhaseOp gphaseOp = + *f.getOps().begin(); + + Block &bb = f.getCallableRegion()->front(); + auto args = bb.getArguments(); + + // Run checks + ValueRange allParams = gphaseOp.getAllParams(); + ASSERT_TRUE(allParams.size() == 1 && allParams[0] == args[2]); + + ASSERT_TRUE(gphaseOp.getAdjointFlag()); + + ValueRange ctrlWireOperands = gphaseOp.getCtrlWireOperands(); + ASSERT_TRUE(ctrlWireOperands.size() == 1 && ctrlWireOperands[0] == args[0]); + + ValueRange ctrlValueOperands = gphaseOp.getCtrlValueOperands(); + ASSERT_TRUE(ctrlValueOperands.size() == 1 && ctrlValueOperands[0] == args[1]); +} + } // namespace From b68e2a239e18130e417a6dc4874edd98e93763d5 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Thu, 15 Jan 2026 16:15:45 -0500 Subject: [PATCH 19/25] multirzop --- mlir/include/RefQuantum/IR/RefQuantumOps.td | 38 +++++++++++++++++++ .../RefQuantum/DialectTest/UnitTests.mlir | 23 +++++++++++ .../RefQuantum/DialectTest/VerifierTests.mlir | 9 +++++ 3 files changed, 70 insertions(+) diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 20d7c3e095..3317a279b2 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -243,6 +243,44 @@ def GlobalPhaseOp : UnitaryGate_Op<"gphase", [ParametrizedGate, AttrSizedOperand }]; } +def MultiRZOp : UnitaryGate_Op<"multirz", [ParametrizedGate, AttrSizedOperandSegments]> { + let summary = "Apply an arbitrary multi Z rotation"; + let description = [{ + The `ref_quantum.multirz` operation applies an arbitrary multi Z rotation to the state-vector. + The arguments are the rotation angle `theta` and a set of wires the operation acts on. + + .. note:: + This operation is one of the few quantum operations that is not applied via + ``ref_quantum.custom``. The reason for this is that its quantum dialect counterpart + needs to be handled in a special way during the lowering due to its C function being + variadic on the number of qubits. + }]; + + let arguments = (ins + F64:$theta, + Variadic:$wires, + UnitAttr:$adjoint, + Variadic:$ctrl_wires, + Variadic:$ctrl_values + ); + + let assemblyFormat = [{ + `(` $theta `)` $wires (`adj` $adjoint^)? attr-dict + ( `ctrls` `(` $ctrl_wires^ `)` )? + ( `ctrlvals` `(` $ctrl_values^ `)` )? + `:` type($wires) (`ctrls` type($ctrl_wires)^ )? + }]; + + let extraClassDeclaration = extraBaseClassDeclaration # [{ + mlir::ValueRange getAllParams() { + return getODSOperands(0); // `theta` is the 0-th operand + } + }]; + + // TODO + // let hasCanonicalizeMethod = 1; +} + // // ----- // // Observable ops are not meaningful on their own: their purpose is to be sent into a measurement diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index 90b10cf957..294d13cf4e 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -79,6 +79,29 @@ func.func @test_global_phase(%w0: i64, %cv: i1, %param: f64) { // ----- +func.func @test_multirz(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %theta: f64) { + + // Basic + ref_quantum.multirz (%theta) %w0 : i64 + ref_quantum.multirz (%theta) %w0, %w1 : i64, i64 + + // With adjoint + ref_quantum.multirz (%theta) %w0, %w1, %w2 adj : i64, i64, i64 + + // With control + %true = llvm.mlir.constant (1 : i1) :i1 + %false = llvm.mlir.constant (0 : i1) :i1 + ref_quantum.multirz (%theta) %w0 ctrls (%w1) ctrlvals (%true) : i64 ctrls i64 + ref_quantum.multirz (%theta) %w0, %w1 ctrls (%w2, %w3) ctrlvals (%true, %false) : i64, i64 ctrls i64, i64 + + // With control and adjoint + ref_quantum.multirz (%theta) %w0, %w1 adj ctrls (%w2, %w3) ctrlvals (%true, %false) : i64, i64 ctrls i64, i64 + + return +} + +// ----- + func.func @test_namedobs_op(%w0: i64) { %ox = ref_quantum.namedobs %w0 [ PauliX] : !quantum.obs diff --git a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir index 8c7d1baf02..1243adee19 100644 --- a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir @@ -71,6 +71,15 @@ func.func @test_gphase_control(%w0: i64, %param: f64) { // ----- +func.func @test_multirz_control(%w0: i64, %w1: i64, %theta: f64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{number of controlling wires in input (1) and controlling values (2) must be the same}} + ref_quantum.multirz(%theta) %w0 ctrls (%w1) ctrlvals (%true, %true) : i64 ctrls i64 + return +} + +// ----- + func.func @test_namedobs_op_bad_attribute(%w0: i64) { // expected-error@+2 {{expected catalyst::quantum::NamedObservable to be one of: Identity, PauliX, PauliY, PauliZ, Hadamard}} // expected-error@+1 {{failed to parse NamedObservableAttr parameter 'value' which is to be a `catalyst::quantum::NamedObservable`}} From e8c569e0ff052625ebfc3c0db78df9f9948dd7cf Mon Sep 17 00:00:00 2001 From: paul0403 Date: Thu, 15 Jan 2026 16:18:29 -0500 Subject: [PATCH 20/25] add duplicate wire verifier test for multirz --- mlir/test/RefQuantum/DialectTest/VerifierTests.mlir | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir index 1243adee19..9708db6818 100644 --- a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir @@ -80,6 +80,15 @@ func.func @test_multirz_control(%w0: i64, %w1: i64, %theta: f64) { // ----- +func.func @test_multirz_duplicate_wires(%w0: i64, %theta: f64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{all wires on a quantum gate must be distinct (including controls)}} + ref_quantum.multirz(%theta) %w0, %w0 : i64, i64 + return +} + +// ----- + func.func @test_namedobs_op_bad_attribute(%w0: i64) { // expected-error@+2 {{expected catalyst::quantum::NamedObservable to be one of: Identity, PauliX, PauliY, PauliZ, Hadamard}} // expected-error@+1 {{failed to parse NamedObservableAttr parameter 'value' which is to be a `catalyst::quantum::NamedObservable`}} From 18d6a4c118ad55c1e1b72ec1579fc68872a88394 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 16 Jan 2026 10:41:23 -0500 Subject: [PATCH 21/25] pcphase op --- mlir/include/RefQuantum/IR/RefQuantumOps.td | 48 +++++++++++++++++++ .../RefQuantum/DialectTest/UnitTests.mlir | 23 +++++++++ .../RefQuantum/DialectTest/VerifierTests.mlir | 18 +++++++ 3 files changed, 89 insertions(+) diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 3317a279b2..c961a90c82 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -281,6 +281,54 @@ def MultiRZOp : UnitaryGate_Op<"multirz", [ParametrizedGate, AttrSizedOperandSeg // let hasCanonicalizeMethod = 1; } +def PCPhaseOp : UnitaryGate_Op<"pcphase", [ParametrizedGate, AttrSizedOperandSegments]> { + let summary = "Apply a projector-controlled phase gate"; + let description = [{ + This gate is built from simpler gates like `PhaseShift` and `PauliX` and acts on a group + of wires and takes a rotation angle. + It also takes another number, an integer called `dim`, which defines a specific part + of the quantum state. The gate then applies a positive phase shift to a portion of the + state defined by `dim`. At the same time, it applies a negative phase shift to the rest + of the state. + + .. note:: + This operation is one of the few quantum operations that is not applied via + ``quantum.custom``. The reason for this is that its quantum dialect counterpart needs + to be handled in a special way during the lowering due to its C function being variadic + on the number of qubits. + + .. note:: + `dim` is currently captured as a float number for compatibility with + runtime and device integration. + + }]; + + let arguments = (ins + F64:$theta, + F64:$dim, + Variadic:$wires, + UnitAttr:$adjoint, + Variadic:$ctrl_wires, + Variadic:$ctrl_values + ); + + let assemblyFormat = [{ + `(` $theta `,` $dim `)` $wires (`adj` $adjoint^)? attr-dict + ( `ctrls` `(` $ctrl_wires^ `)` )? + ( `ctrlvals` `(` $ctrl_values^ `)` )? + `:` type($wires) (`ctrls` type($ctrl_wires)^ )? + }]; + + let extraClassDeclaration = extraBaseClassDeclaration # [{ + mlir::ValueRange getAllParams() { + return getODSOperands(0); // `theta` is the 0-th operand + } + }]; + + // TODO + // let hasCanonicalizeMethod = 1; +} + // // ----- // // Observable ops are not meaningful on their own: their purpose is to be sent into a measurement diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index 294d13cf4e..74495dd551 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -102,6 +102,29 @@ func.func @test_multirz(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %theta: f64) { // ----- +func.func @test_pcphase(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %theta: f64, %dim: f64) { + + // Basic + ref_quantum.pcphase (%theta, %dim) %w0 : i64 + ref_quantum.pcphase (%theta, %dim) %w0, %w1, %w2 : i64, i64, i64 + + // With adjoint + ref_quantum.pcphase (%theta, %dim) %w0, %w1 adj : i64, i64 + + // With control + %true = llvm.mlir.constant (1 : i1) :i1 + %false = llvm.mlir.constant (0 : i1) :i1 + ref_quantum.pcphase (%theta, %dim) %w0 ctrls (%w1) ctrlvals (%true) : i64 ctrls i64 + ref_quantum.pcphase (%theta, %dim) %w0, %w1 ctrls (%w2, %w3) ctrlvals (%true, %false) : i64, i64 ctrls i64, i64 + + // With control and adjoint + ref_quantum.pcphase (%theta, %dim) %w0, %w1 adj ctrls (%w2, %w3) ctrlvals (%true, %false) : i64, i64 ctrls i64, i64 + + return +} + +// ----- + func.func @test_namedobs_op(%w0: i64) { %ox = ref_quantum.namedobs %w0 [ PauliX] : !quantum.obs diff --git a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir index 9708db6818..8406c7e42c 100644 --- a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir @@ -89,6 +89,24 @@ func.func @test_multirz_duplicate_wires(%w0: i64, %theta: f64) { // ----- +func.func @test_pcphase_control(%w0: i64, %w1: i64, %theta: f64, %dim: f64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{number of controlling wires in input (1) and controlling values (2) must be the same}} + ref_quantum.pcphase(%theta, %dim) %w0 ctrls (%w1) ctrlvals (%true, %true) : i64 ctrls i64 + return +} + +// ----- + +func.func @test_pcphase_duplicate_wires(%w0: i64, %theta: f64, %dim: f64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{all wires on a quantum gate must be distinct (including controls)}} + ref_quantum.pcphase(%theta, %dim) %w0, %w0 : i64, i64 + return +} + +// ----- + func.func @test_namedobs_op_bad_attribute(%w0: i64) { // expected-error@+2 {{expected catalyst::quantum::NamedObservable to be one of: Identity, PauliX, PauliY, PauliZ, Hadamard}} // expected-error@+1 {{failed to parse NamedObservableAttr parameter 'value' which is to be a `catalyst::quantum::NamedObservable`}} From 614c6034a1c44cc8de7c2d34fca52bd3f9b26632 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 16 Jan 2026 11:17:09 -0500 Subject: [PATCH 22/25] unitary op --- mlir/include/RefQuantum/IR/RefQuantumOps.td | 55 ++++++++++++++++++- mlir/lib/RefQuantum/IR/RefQuantumOps.cpp | 29 ++++++++-- .../RefQuantum/DialectTest/UnitTests.mlir | 26 +++++++++ .../RefQuantum/DialectTest/VerifierTests.mlir | 26 +++++++++ 4 files changed, 129 insertions(+), 7 deletions(-) diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index c961a90c82..0b4fe2300f 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -138,6 +138,12 @@ def SetStateOp : Gate_Op<"set_state"> { This operation is useful for simulators implementing state preparation. Instead of decomposing state preparation into multiple operations, this operation shortcuts all of that into a single operation. + + .. note:: + This op is not bufferizable at the moment, and must take in the state as a tensor + instead of a memref. To execute reference semantics quantum dialect, please convert + to the value semantics quantum dialect, where ops are bufferizable and lowerable to + LLVM IR. }]; let arguments = (ins @@ -160,6 +166,12 @@ def SetBasisStateOp : Gate_Op<"set_basis_state"> { operation shortcuts all of that into a single operation. This signature matches the one in pennylane-lightning which expects only a single integer as opposed to a binary digit. + + .. note:: + This op is not bufferizable at the moment, and must take in the basis state as a tensor + instead of a memref. To execute reference semantics quantum dialect, please convert + to the value semantics quantum dialect, where ops are bufferizable and lowerable to + LLVM IR. }]; let arguments = (ins @@ -329,10 +341,47 @@ def PCPhaseOp : UnitaryGate_Op<"pcphase", [ParametrizedGate, AttrSizedOperandSeg // let hasCanonicalizeMethod = 1; } -// // ----- +def QubitUnitaryOp : UnitaryGate_Op<"unitary", [ParametrizedGate, AttrSizedOperandSegments]> { + let summary = "Apply an arbitrary fixed unitary matrix"; + let description = [{ + The `ref_quantum.unitary` operation applies an arbitrary fixed unitary matrix to the + state-vector. The arguments are a set of qubits and a 2-dim matrix of complex numbers + that represents a Unitary matrix of size 2^(number of qubits) * 2^(number of qubits). + + .. note:: + This op is not bufferizable at the moment, and must take in the matrix as a tensor + instead of a memref. To execute reference semantics quantum dialect, please convert + to the value semantics quantum dialect, where ops are bufferizable and lowerable to + LLVM IR. + }]; + + let arguments = (ins + 2DTensorOf<[Complex]>:$matrix, + Variadic:$wires, + UnitAttr:$adjoint, + Variadic:$ctrl_wires, + Variadic:$ctrl_values + ); + + let assemblyFormat = [{ + `(` $matrix `:` type($matrix) `)` $wires (`adj` $adjoint^)? attr-dict + ( `ctrls` `(` $ctrl_wires^ `)` )? + ( `ctrlvals` `(` $ctrl_values^ `)` )? + `:` type($wires) (`ctrls` type($ctrl_wires)^ )? + }]; + + let extraClassDeclaration = extraBaseClassDeclaration # [{ + mlir::ValueRange getAllParams() { + return getODSOperands(0); // `matrix` is the first operand + } + }]; + + let hasVerifier = 1; +} +// ----- -// // Observable ops are not meaningful on their own: their purpose is to be sent into a measurement -// // Hence they are Pure, i.e. removable if no users +// Observable ops are not meaningful on their own: their purpose is to be sent into a measurement +// Hence they are Pure, i.e. removable if no users class Observable_Op traits = []> : RefQuantum_Op; diff --git a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp index 64ea1a83e8..44e8288bb7 100644 --- a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp +++ b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp @@ -12,10 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "mlir/IR/Builders.h" +#include // std::pow + #include "mlir/IR/OpImplementation.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/ADT/TypeSwitch.h" #include "RefQuantum/IR/RefQuantumDialect.h" #include "RefQuantum/IR/RefQuantumOps.h" @@ -30,10 +29,32 @@ using namespace catalyst::ref_quantum; #define GET_OP_CLASSES #include "RefQuantum/IR/RefQuantumOps.cpp.inc" +namespace catalyst::ref_quantum { + +// Utils +static LogicalResult verifyTensorResult(Type ty, int64_t length0, int64_t length1) +{ + ShapedType tensor = cast(ty); + if (!tensor.hasStaticShape() || tensor.getShape().size() != 2 || + tensor.getShape()[0] != length0 || tensor.getShape()[1] != length1) { + return failure(); + } + + return success(); +} + //===----------------------------------------------------------------------===// // RefQuantum op verifiers. //===----------------------------------------------------------------------===// -namespace catalyst::ref_quantum { +LogicalResult QubitUnitaryOp::verify() +{ + size_t dim = std::pow(2, getWires().size()); + if (failed(verifyTensorResult(cast(getMatrix().getType()), dim, dim))) { + return emitOpError("The Unitary matrix must be of size 2^(num_wires) * 2^(num_wires)"); + } + + return success(); +} } // namespace catalyst::ref_quantum diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index 74495dd551..0cc635c735 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -125,6 +125,32 @@ func.func @test_pcphase(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %theta: f64, %di // ----- +func.func @test_qubit_unitary(%w0: i64, %w1: i64, %w2: i64, %w3: i64) { + + // Basic + %matrix22 = tensor.empty() : tensor<2x2xcomplex> + %matrix44 = tensor.empty() : tensor<4x4xcomplex> + + ref_quantum.unitary (%matrix22 : tensor<2x2xcomplex>) %w0 : i64 + ref_quantum.unitary (%matrix44 : tensor<4x4xcomplex>) %w0, %w1 : i64, i64 + + // With adjoint + ref_quantum.unitary (%matrix22 : tensor<2x2xcomplex>) %w0 adj : i64 + + // With control + %true = llvm.mlir.constant (1 : i1) :i1 + %false = llvm.mlir.constant (0 : i1) :i1 + ref_quantum.unitary (%matrix22 : tensor<2x2xcomplex>) %w0 ctrls (%w1) ctrlvals (%true) : i64 ctrls i64 + ref_quantum.unitary (%matrix44 : tensor<4x4xcomplex>) %w0, %w1 ctrls (%w2, %w3) ctrlvals (%true, %false) : i64, i64 ctrls i64, i64 + + // With control and adjoint + ref_quantum.unitary (%matrix44 : tensor<4x4xcomplex>) %w0, %w1 adj ctrls (%w2, %w3) ctrlvals (%true, %false) : i64, i64 ctrls i64, i64 + + return +} + +// ----- + func.func @test_namedobs_op(%w0: i64) { %ox = ref_quantum.namedobs %w0 [ PauliX] : !quantum.obs diff --git a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir index 8406c7e42c..b40f9f2838 100644 --- a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir @@ -107,6 +107,32 @@ func.func @test_pcphase_duplicate_wires(%w0: i64, %theta: f64, %dim: f64) { // ----- +func.func @test_unitary_bad_matrix_shape(%w0: i64, %matrix: tensor<37x42xcomplex>) { + // expected-error@+1 {{The Unitary matrix must be of size 2^(num_wires) * 2^(num_wires)}} + ref_quantum.unitary (%matrix : tensor<37x42xcomplex>) %w0 : i64 + return +} + +// ----- + +func.func @test_unitary_control(%w0: i64, %w1: i64, %matrix: tensor<2x2xcomplex>) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{number of controlling wires in input (1) and controlling values (2) must be the same}} + ref_quantum.unitary(%matrix: tensor<2x2xcomplex>) %w0 ctrls (%w1) ctrlvals (%true, %true) : i64 ctrls i64 + return +} + +// ----- + +func.func @test_unitary_duplicate_wires(%w0: i64, %matrix: tensor<4x4xcomplex>) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{all wires on a quantum gate must be distinct (including controls)}} + ref_quantum.unitary(%matrix: tensor<4x4xcomplex>) %w0, %w0 : i64, i64 + return +} + +// ----- + func.func @test_namedobs_op_bad_attribute(%w0: i64) { // expected-error@+2 {{expected catalyst::quantum::NamedObservable to be one of: Identity, PauliX, PauliY, PauliZ, Hadamard}} // expected-error@+1 {{failed to parse NamedObservableAttr parameter 'value' which is to be a `catalyst::quantum::NamedObservable`}} From e28114c392a59d7a3dc37351e927b4a3df4da9e3 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 16 Jan 2026 11:29:50 -0500 Subject: [PATCH 23/25] left shift instead of std::pow(2, N) --- mlir/lib/RefQuantum/IR/RefQuantumOps.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp index 44e8288bb7..aabf0a0b88 100644 --- a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp +++ b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include // std::pow - #include "mlir/IR/OpImplementation.h" #include "RefQuantum/IR/RefQuantumDialect.h" @@ -49,7 +47,7 @@ static LogicalResult verifyTensorResult(Type ty, int64_t length0, int64_t length LogicalResult QubitUnitaryOp::verify() { - size_t dim = std::pow(2, getWires().size()); + size_t dim = 1 << getWires().size(); if (failed(verifyTensorResult(cast(getMatrix().getType()), dim, dim))) { return emitOpError("The Unitary matrix must be of size 2^(num_wires) * 2^(num_wires)"); } From 3c71fc7bda9021653798c72cdce7ef3fd4679028 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 16 Jan 2026 13:38:16 -0500 Subject: [PATCH 24/25] format --- mlir/include/RegisterAllPasses.h | 2 +- mlir/lib/RefQuantum/Transforms/HelloWorldPatterns.cpp | 6 +++--- mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp | 2 +- mlir/tools/quantum-opt/quantum-opt.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mlir/include/RegisterAllPasses.h b/mlir/include/RegisterAllPasses.h index ed9fc6c0eb..966ed90b6f 100644 --- a/mlir/include/RegisterAllPasses.h +++ b/mlir/include/RegisterAllPasses.h @@ -22,8 +22,8 @@ #include "PauliFrame/Transforms/Passes.h" #include "QEC/Transforms/Passes.h" #include "Quantum/Transforms/Passes.h" -#include "RefQuantum/Transforms/Passes.h" #include "RTIO/Transforms/Passes.h" +#include "RefQuantum/Transforms/Passes.h" #include "Test/Transforms/Passes.h" #include "hlo-extensions/Transforms/Passes.h" diff --git a/mlir/lib/RefQuantum/Transforms/HelloWorldPatterns.cpp b/mlir/lib/RefQuantum/Transforms/HelloWorldPatterns.cpp index a153c16de0..382f9a7aad 100644 --- a/mlir/lib/RefQuantum/Transforms/HelloWorldPatterns.cpp +++ b/mlir/lib/RefQuantum/Transforms/HelloWorldPatterns.cpp @@ -18,9 +18,9 @@ #include "mlir/IR/PatternMatch.h" // #include "RefQuantum/IR/RefQuantumOps.h" -#include "RefQuantum/Transforms/Patterns.h" #include "Quantum/IR/QuantumDialect.h" #include "Quantum/IR/QuantumOps.h" +#include "RefQuantum/Transforms/Patterns.h" using namespace mlir; @@ -29,14 +29,14 @@ namespace { struct RQHelloWorldPattern : public OpRewritePattern { using OpRewritePattern::OpRewritePattern; - LogicalResult matchAndRewrite(catalyst::quantum::CustomOp op, PatternRewriter &rewriter) const override + LogicalResult matchAndRewrite(catalyst::quantum::CustomOp op, + PatternRewriter &rewriter) const override { llvm::errs() << "hello world! Visiting " << op << "\n"; return success(); } }; - } // namespace namespace catalyst { diff --git a/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp b/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp index 9cd818cb8c..871e354196 100644 --- a/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp +++ b/mlir/tools/quantum-lsp-server/quantum-lsp-server.cpp @@ -24,8 +24,8 @@ #include "PauliFrame/IR/PauliFrameDialect.h" #include "QEC/IR/QECDialect.h" #include "Quantum/IR/QuantumDialect.h" -#include "RefQuantum/IR/RefQuantumDialect.h" #include "RTIO/IR/RTIODialect.h" +#include "RefQuantum/IR/RefQuantumDialect.h" #include "stablehlo/dialect/Register.h" diff --git a/mlir/tools/quantum-opt/quantum-opt.cpp b/mlir/tools/quantum-opt/quantum-opt.cpp index 811f402f59..8d370cec4c 100644 --- a/mlir/tools/quantum-opt/quantum-opt.cpp +++ b/mlir/tools/quantum-opt/quantum-opt.cpp @@ -44,8 +44,8 @@ #include "QEC/IR/QECDialect.h" #include "Quantum/IR/QuantumDialect.h" #include "Quantum/Transforms/BufferizableOpInterfaceImpl.h" -#include "RefQuantum/IR/RefQuantumDialect.h" #include "RTIO/IR/RTIODialect.h" +#include "RefQuantum/IR/RefQuantumDialect.h" #include "RegisterAllPasses.h" namespace test { From 249b764f0b1e5bf9352b07d2336715366a3ee7c9 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Fri, 16 Jan 2026 14:24:23 -0500 Subject: [PATCH 25/25] paulirot op --- mlir/include/Quantum/IR/QuantumAttrDefs.td | 1 + mlir/include/Quantum/IR/QuantumOps.td | 2 -- mlir/include/RefQuantum/IR/RefQuantumOps.td | 36 +++++++++++++++++++ mlir/lib/RefQuantum/IR/RefQuantumOps.cpp | 22 ++++++++++++ .../RefQuantum/DialectTest/UnitTests.mlir | 23 ++++++++++++ .../RefQuantum/DialectTest/VerifierTests.mlir | 34 ++++++++++++++++++ 6 files changed, 116 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..8b6029207a 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"; diff --git a/mlir/include/RefQuantum/IR/RefQuantumOps.td b/mlir/include/RefQuantum/IR/RefQuantumOps.td index 0b4fe2300f..408bd516df 100644 --- a/mlir/include/RefQuantum/IR/RefQuantumOps.td +++ b/mlir/include/RefQuantum/IR/RefQuantumOps.td @@ -219,6 +219,42 @@ def CustomOp : UnitaryGate_Op<"custom", [ParametrizedGate, AttrSizedOperandSegme // let hasVerifier = 1; } +def PauliRotOp : UnitaryGate_Op<"paulirot", [ParametrizedGate, AttrSizedOperandSegments]> { + let summary = "Apply a Pauli Product Rotation"; + let description = [{ + The `ref_quantum.paulirot` operation applies a rotation around a Pauli product + operator to the state-vector. + The arguments are the rotation angle `angle`, a string representing the + Pauli product operator, and a set of qubits the operation acts on. + Note that this operation is currently not excutable. There isn't a valid + lowering path to the LLVM IR. + }]; + + let arguments = (ins + F64:$angle, + PauliWord:$pauli_product, + Variadic:$wires, + UnitAttr:$adjoint, + Variadic:$ctrl_wires, + Variadic:$ctrl_values + ); + + let assemblyFormat = [{ + $pauli_product `(` $angle `)` $wires (`adj` $adjoint^)? attr-dict + ( `ctrls` `(` $ctrl_wires^ `)` )? + ( `ctrlvals` `(` $ctrl_values^ `)` )? + `:` type($wires) (`ctrls` type($ctrl_wires)^ )? + }]; + + let extraClassDeclaration = extraBaseClassDeclaration # [{ + mlir::ValueRange getAllParams() { + return getODSOperands(0); // `angle` is the 0th operand + } + }]; + + let hasVerifier = 1; +} + def GlobalPhaseOp : UnitaryGate_Op<"gphase", [ParametrizedGate, AttrSizedOperandSegments]> { let summary = "Global Phase."; diff --git a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp index aabf0a0b88..6019cad6b4 100644 --- a/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp +++ b/mlir/lib/RefQuantum/IR/RefQuantumOps.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include "mlir/IR/OpImplementation.h" +#include "llvm/ADT/StringSet.h" #include "RefQuantum/IR/RefQuantumDialect.h" #include "RefQuantum/IR/RefQuantumOps.h" @@ -45,6 +46,27 @@ static LogicalResult verifyTensorResult(Type ty, int64_t length0, int64_t length // RefQuantum op verifiers. //===----------------------------------------------------------------------===// +static const mlir::StringSet<> validPauliWords = {"X", "Y", "Z", "I"}; + +LogicalResult PauliRotOp::verify() +{ + size_t pauliWordLength = getPauliProduct().size(); + size_t numWires = getWires().size(); + if (pauliWordLength != numWires) { + return emitOpError() << "length of Pauli word (" << pauliWordLength + << ") and number of wires (" << numWires << ") 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 = 1 << getWires().size(); diff --git a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir index 0cc635c735..ad34a034a0 100644 --- a/mlir/test/RefQuantum/DialectTest/UnitTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/UnitTests.mlir @@ -58,6 +58,29 @@ func.func @test_custom_op(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %param0: f64, return } + +// ----- + +func.func @test_paulirot_op(%w0: i64, %w1: i64, %w2: i64, %w3: i64, %angle: f64) { + + // Basic + ref_quantum.paulirot ["Z"](%angle) %w0 : i64 + ref_quantum.paulirot ["Z", "X"](%angle) %w0, %w1 : i64, i64 + + // With adjoint + ref_quantum.paulirot ["Z", "X", "I"](%angle) %w0, %w1, %w2 adj : i64, i64, i64 + + // With control + %true = llvm.mlir.constant (1 : i1) :i1 + %false = llvm.mlir.constant (0 : i1) :i1 + ref_quantum.paulirot ["Y", "I"](%angle) %w0, %w1 ctrls (%w2, %w3) ctrlvals (%true, %false) : i64, i64 ctrls i64, i64 + + // With params, control and adjoint altogether + ref_quantum.paulirot ["I", "X"](%angle) %w0, %w1 adj ctrls (%w2, %w3) ctrlvals (%true, %false) : i64, i64 ctrls i64, i64 + + return +} + // ----- func.func @test_global_phase(%w0: i64, %cv: i1, %param: f64) { diff --git a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir index b40f9f2838..953c25e346 100644 --- a/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir +++ b/mlir/test/RefQuantum/DialectTest/VerifierTests.mlir @@ -62,6 +62,40 @@ func.func @test_duplicate_wires2(%w0: i64) { // ----- +func.func @test_paulirot_length_mismatch(%w0: i64, %angle: f64) { + // expected-error@+1 {{length of Pauli word (2) and number of wires (1) must be the same}} + ref_quantum.paulirot ["Z", "X"](%angle) %w0 : i64 + return +} + +// ----- + +func.func @test_paulirot_bad_pauli_word(%w0: i64, %angle: f64) { + // expected-error@+1 {{Only "X", "Y", "Z", and "I" are valid Pauli words.}} + ref_quantum.paulirot ["bad"](%angle) %w0 : i64 + return +} + +// ----- + +func.func @test_paulirot_control(%w0: i64, %w1: i64, %angle: f64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{number of controlling wires in input (1) and controlling values (2) must be the same}} + ref_quantum.paulirot ["Z"](%angle) %w0 ctrls (%w1) ctrlvals (%true, %true) : i64 ctrls i64 + return +} + +// ----- + +func.func @test_paulirot_duplicate_wires(%w0: i64, %angle: f64) { + %true = llvm.mlir.constant (1 : i1) :i1 + // expected-error@+1 {{all wires on a quantum gate must be distinct (including controls)}} + ref_quantum.paulirot ["Z", "I"](%angle) %w0, %w0 : i64, i64 + return +} + +// ----- + func.func @test_gphase_control(%w0: i64, %param: f64) { %true = llvm.mlir.constant (1 : i1) :i1 // expected-error@+1 {{number of controlling wires in input (1) and controlling values (2) must be the same}}