-
-
Notifications
You must be signed in to change notification settings - Fork 63
Add python bindings for the mlir QASM→QC→QCO pipeline #1783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
24569a5
839ff42
e3b654f
6054f69
6090949
c2a964c
e23f253
69f9621
b4e9f32
756880e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -11,6 +11,7 @@ cmake-build-* | |||
| # Distribution / packaging | ||||
| .Python | ||||
| /build/ | ||||
| /build_*/ | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change shouldn't be necessary.
Suggested change
|
||||
| /test/*/build | ||||
| develop-eggs/ | ||||
| dist/ | ||||
|
|
||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # This binding module uses the NB_MODULE macro and the MLIR C-API type-casters | ||
| # from NanobindAdaptors.h. The include-cleaner, internal-linkage, | ||
| # identifier-naming, named-parameter, value-parameter, and unused-alias checks | ||
| # cannot reason about the macro expansion and the templated casters, so they | ||
| # report false positives here. Disable them for this binding glue. | ||
| InheritParentConfig: true | ||
| Checks: | | ||
| -misc-include-cleaner, | ||
| -misc-unused-alias-decls, | ||
| -misc-use-internal-linkage, | ||
| -performance-unnecessary-value-param, | ||
| -readability-identifier-naming, | ||
| -readability-named-parameter |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Copyright (c) 2023 - 2026 Chair for Design Automation, TUM | ||
| # Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH | ||
| # All rights reserved. | ||
| # | ||
| # SPDX-License-Identifier: MIT | ||
| # | ||
| # Licensed under the MIT License | ||
|
|
||
| if(NOT TARGET ${MQT_CORE_TARGET_NAME}-mlir-bindings) | ||
| # collect source files | ||
| file(GLOB_RECURSE MLIR_BINDINGS_SOURCES **.cpp) | ||
|
|
||
| # declare the Python module | ||
| add_mqt_python_binding_nanobind( | ||
| CORE | ||
| ${MQT_CORE_TARGET_NAME}-mlir-bindings | ||
| ${MLIR_BINDINGS_SOURCES} | ||
| MODULE_NAME | ||
| _mlir | ||
| INSTALL_DIR | ||
| ./mlir | ||
| LINK_LIBS | ||
| MQTCoreCAPI | ||
| MLIRIR) | ||
|
|
||
| # install the Python stub files in editable mode for better IDE support | ||
| if(SKBUILD_STATE STREQUAL "editable") | ||
| file(GLOB_RECURSE MLIR_PYI_FILES ${PROJECT_SOURCE_DIR}/python/mqt/core/mlir/*.pyi) | ||
| install( | ||
| FILES ${MLIR_PYI_FILES} | ||
| DESTINATION ./mlir | ||
| COMPONENT ${MQT_CORE_TARGET_NAME}_Python) | ||
| endif() | ||
| endif() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| /* | ||
| * Copyright (c) 2023 - 2026 Chair for Design Automation, TUM | ||
| * Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH | ||
| * All rights reserved. | ||
| * | ||
| * SPDX-License-Identifier: MIT | ||
| * | ||
| * Licensed under the MIT License | ||
| */ | ||
|
|
||
| #include "mqt-core-c/Registration.h" | ||
|
|
||
| #include <mlir-c/IR.h> | ||
| #include <mlir-c/Support.h> | ||
| #include <mlir/Bindings/Python/NanobindAdaptors.h> | ||
| #include <nanobind/nanobind.h> | ||
|
|
||
| #include <stdexcept> | ||
| #include <string> | ||
|
|
||
| namespace mqt { | ||
|
|
||
| namespace nb = nanobind; | ||
|
|
||
| NB_MODULE(MQT_CORE_MODULE_NAME, m) { | ||
| m.doc() = | ||
| R"pb(MQT Core MLIR - Python bindings for the MQT Compiler Collection. | ||
|
|
||
| This module exposes the dialects and passes of the MQT Compiler Collection so | ||
| that quantum programs can be compiled from Python using MLIR's Python bindings.)pb"; | ||
|
|
||
| m.def( | ||
| "register_dialects", | ||
| [](MlirContext context) { mqtRegisterAllDialects(context); }, | ||
| nb::arg("context"), | ||
| "Register and load all MQT Compiler Collection dialects with the given " | ||
| "context."); | ||
|
|
||
| m.def( | ||
| "register_passes", []() { mqtRegisterAllPasses(); }, | ||
| "Register all MQT Compiler Collection passes with MLIR's global pass " | ||
| "registry."); | ||
|
|
||
| m.def( | ||
| "import_qasm3_to_qc", | ||
| [](MlirContext context, const std::string& qasm) { | ||
| const MlirModule module = mqtImportQASM3ToQC( | ||
| context, mlirStringRefCreate(qasm.data(), qasm.size())); | ||
| if (mlirModuleIsNull(module)) { | ||
| throw std::runtime_error( | ||
| "Failed to import OpenQASM 3 program into the QC dialect"); | ||
| } | ||
| return module; | ||
| }, | ||
| nb::arg("context"), nb::arg("qasm"), | ||
| "Import an OpenQASM 3 program into a QC-dialect module."); | ||
| } | ||
|
|
||
| } // namespace mqt |
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For consistency, the path should probably be |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /* | ||
| * Copyright (c) 2023 - 2026 Chair for Design Automation, TUM | ||
| * Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH | ||
| * All rights reserved. | ||
| * | ||
| * SPDX-License-Identifier: MIT | ||
| * | ||
| * Licensed under the MIT License | ||
| */ | ||
|
|
||
| #ifndef MQT_CORE_C_REGISTRATION_H | ||
| #define MQT_CORE_C_REGISTRATION_H | ||
|
|
||
| #include "mlir-c/IR.h" | ||
| #include "mlir-c/Support.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @brief Register and load all dialects of the MQT Compiler Collection with the | ||
| * given context. | ||
| * | ||
| * @details Registers the QC, QCO, QTensor, and Jeff dialects together with the | ||
| * upstream dialects (arith, func, scf, cf, memref, llvm) that the dialects, | ||
| * conversions, and transformations depend on, and loads them so that modules | ||
| * and passes can use them. | ||
| * | ||
| * @param ctx The MLIR context to populate. | ||
| */ | ||
| MLIR_CAPI_EXPORTED void mqtRegisterAllDialects(MlirContext ctx); | ||
|
|
||
| /** | ||
| * @brief Register all conversion and transformation passes of the MQT Compiler | ||
| * Collection with MLIR's global pass registry. | ||
| * | ||
| * @details After this call, every MQT pass can be instantiated by name (e.g. | ||
| * via a textual pass pipeline) from Python through the standard MLIR | ||
| * PassManager API. | ||
| */ | ||
| MLIR_CAPI_EXPORTED void mqtRegisterAllPasses(void); | ||
|
|
||
| /** | ||
| * @brief Import an OpenQASM 3 program into a module of the QC dialect. | ||
| * | ||
| * @param ctx The MLIR context that owns the resulting module. The QC dialect | ||
| * must be registered with this context. | ||
| * @param qasm The OpenQASM 3 source program. | ||
| * @return The resulting QC-dialect module, or a null module on error. The | ||
| * caller owns the returned module. | ||
| */ | ||
| MLIR_CAPI_EXPORTED MlirModule mqtImportQASM3ToQC(MlirContext ctx, | ||
| MlirStringRef qasm); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif // MQT_CORE_C_REGISTRATION_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # The C-API registration translation unit includes the dialect, conversion, and | ||
| # transformation headers solely to invoke their registration entry points. The | ||
| # include-cleaner check cannot trace these uses through the registration | ||
| # functions and reports false positives, so it is disabled here. | ||
| InheritParentConfig: true | ||
| Checks: | | ||
| -misc-include-cleaner |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # Copyright (c) 2023 - 2026 Chair for Design Automation, TUM | ||
| # Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH | ||
| # All rights reserved. | ||
| # | ||
| # SPDX-License-Identifier: MIT | ||
| # | ||
| # Licensed under the MIT License | ||
|
|
||
| add_mlir_public_c_api_library( | ||
| MQTCoreCAPI | ||
| Registration.cpp | ||
| LINK_LIBS | ||
| PUBLIC | ||
| # Dialects | ||
| MLIRQCDialect | ||
| MLIRQCODialect | ||
| MLIRQTensorDialect | ||
| MLIRJeff | ||
| # Conversions | ||
| MLIRQCToQCO | ||
| MLIRQCOToQC | ||
| MLIRQCToQIRBase | ||
| MLIRQCToQIRAdaptive | ||
| MLIRJeffToQCO | ||
| MLIRQCOToJeff | ||
| # Transformations | ||
| MLIRQCTransforms | ||
| MLIRQCOTransforms | ||
| MLIRQIRTransforms | ||
| MLIRQTensorTransforms | ||
| # OpenQASM 3 import | ||
| MLIRQCTranslation | ||
| MQT::CoreQASM | ||
| MQT::CoreIR | ||
| # Upstream | ||
| MLIRIR | ||
| MLIRPass | ||
| MLIRTransforms | ||
| MLIRArithDialect | ||
| MLIRControlFlowDialect | ||
| MLIRFuncDialect | ||
| MLIRLLVMDialect | ||
| MLIRMemRefDialect | ||
| MLIRSCFDialect) | ||
|
|
||
| mqt_mlir_target_use_project_options(MQTCoreCAPI) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| /* | ||
| * Copyright (c) 2023 - 2026 Chair for Design Automation, TUM | ||
| * Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH | ||
| * All rights reserved. | ||
| * | ||
| * SPDX-License-Identifier: MIT | ||
| * | ||
| * Licensed under the MIT License | ||
| */ | ||
|
|
||
| #include "mqt-core-c/Registration.h" | ||
|
|
||
| #include "ir/QuantumComputation.hpp" | ||
| #include "mlir/Conversion/JeffToQCO/JeffToQCO.h" | ||
| #include "mlir/Conversion/QCOToJeff/QCOToJeff.h" | ||
| #include "mlir/Conversion/QCOToQC/QCOToQC.h" | ||
| #include "mlir/Conversion/QCToQCO/QCToQCO.h" | ||
| #include "mlir/Conversion/QCToQIR/QIRAdaptive/QCToQIRAdaptive.h" | ||
| #include "mlir/Conversion/QCToQIR/QIRBase/QCToQIRBase.h" | ||
| #include "mlir/Dialect/QC/IR/QCDialect.h" | ||
| #include "mlir/Dialect/QC/Transforms/Passes.h" | ||
| #include "mlir/Dialect/QC/Translation/TranslateQuantumComputationToQC.h" | ||
| #include "mlir/Dialect/QCO/IR/QCODialect.h" | ||
| #include "mlir/Dialect/QCO/Transforms/Passes.h" | ||
| #include "mlir/Dialect/QIR/Transforms/Passes.h" | ||
| #include "mlir/Dialect/QTensor/IR/QTensorDialect.h" | ||
| #include "mlir/Dialect/QTensor/Transforms/Passes.h" | ||
| #include "qasm3/Importer.hpp" | ||
|
|
||
| #include <jeff/IR/JeffDialect.h> | ||
| #include <mlir/CAPI/IR.h> | ||
| #include <mlir/Dialect/Arith/IR/Arith.h> | ||
| #include <mlir/Dialect/ControlFlow/IR/ControlFlow.h> | ||
| #include <mlir/Dialect/Func/IR/FuncOps.h> | ||
| #include <mlir/Dialect/LLVMIR/LLVMDialect.h> | ||
| #include <mlir/Dialect/MemRef/IR/MemRef.h> | ||
| #include <mlir/Dialect/SCF/IR/SCF.h> | ||
| #include <mlir/IR/BuiltinOps.h> | ||
| #include <mlir/IR/DialectRegistry.h> | ||
| #include <mlir/IR/MLIRContext.h> | ||
| #include <mlir/IR/OwningOpRef.h> | ||
| #include <mlir/Transforms/Passes.h> | ||
|
|
||
| #include <exception> | ||
| #include <string> | ||
|
|
||
| void mqtRegisterAllDialects(MlirContext ctx) { | ||
| mlir::MLIRContext* context = unwrap(ctx); | ||
| mlir::DialectRegistry registry; | ||
| registry.insert<mlir::qc::QCDialect, mlir::qco::QCODialect, | ||
| mlir::qtensor::QTensorDialect, mlir::jeff::JeffDialect, | ||
| mlir::arith::ArithDialect, mlir::cf::ControlFlowDialect, | ||
| mlir::func::FuncDialect, mlir::LLVM::LLVMDialect, | ||
| mlir::memref::MemRefDialect, mlir::scf::SCFDialect>(); | ||
| context->appendDialectRegistry(registry); | ||
| context->loadAllAvailableDialects(); | ||
| } | ||
|
|
||
| void mqtRegisterAllPasses() { | ||
| // Common upstream transformations (canonicalization, CSE, ...) used by the | ||
| // MQT cleanup pipelines. | ||
| mlir::registerTransformsPasses(); | ||
|
|
||
| // Conversions between the MQT dialects. | ||
| mlir::registerQCToQCOPasses(); | ||
| mlir::registerQCOToQCPasses(); | ||
| mlir::registerQCToQIRBasePasses(); | ||
| mlir::registerQCToQIRAdaptivePasses(); | ||
| mlir::registerJeffToQCOPasses(); | ||
| mlir::registerQCOToJeffPasses(); | ||
|
|
||
| // Dialect-specific transformations. | ||
| mlir::qc::registerQCPasses(); | ||
| mlir::qco::registerQCOPasses(); | ||
| mlir::qir::registerQIRPasses(); | ||
| mlir::qtensor::registerQTensorPasses(); | ||
| } | ||
|
|
||
| MlirModule mqtImportQASM3ToQC(MlirContext ctx, MlirStringRef qasm) { | ||
| mlir::MLIRContext* context = unwrap(ctx); | ||
| try { | ||
| const ::qc::QuantumComputation qc = | ||
| qasm3::Importer::imports(std::string(qasm.data, qasm.length)); | ||
| mlir::OwningOpRef<mlir::ModuleOp> module = | ||
| mlir::translateQuantumComputationToQC(context, qc); | ||
| if (!module) { | ||
| return MlirModule{nullptr}; | ||
| } | ||
| return wrap(module.release()); | ||
| } catch (const std::exception&) { | ||
| return MlirModule{nullptr}; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -180,6 +180,8 @@ testpaths = ["test/python"] | |
| run.source = ["mqt.core"] | ||
| run.omit = [ | ||
| '*/_compat/*', | ||
| # The MLIR bindings require an MLIR toolchain built with Python bindings. | ||
| '*/mqt/core/mlir/*', | ||
|
Comment on lines
+183
to
+184
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See my general point above. |
||
| ] | ||
| run.disable_warnings = [ | ||
| "no-sysmon", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # Copyright (c) 2023 - 2026 Chair for Design Automation, TUM | ||
| # Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH | ||
| # All rights reserved. | ||
| # | ||
| # SPDX-License-Identifier: MIT | ||
| # | ||
| # Licensed under the MIT License | ||
|
|
||
| """Python bindings for the MQT Compiler Collection. | ||
|
|
||
| Exposes the dialects and passes of the MQT Compiler Collection to Python via | ||
| MLIR's Python bindings. OpenQASM 3 programs are imported into the QC dialect and | ||
| returned as native :class:`mlir.ir.Module` objects, which can then be run | ||
| through any MQT pass pipeline. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from .pipeline import ( | ||
| QASMProgram, | ||
| create_context, | ||
| read_qasm, | ||
| run_pipeline, | ||
| transform_to_qco, | ||
| translate_to_qc, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "QASMProgram", | ||
| "create_context", | ||
| "read_qasm", | ||
| "run_pipeline", | ||
| "transform_to_qco", | ||
| "translate_to_qc", | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my general point above.