Development Guide¶
Ready to contribute to the Quantum Compilation Suite of the MQSS? This guide will help you get started.
Development Environment¶
It is recommended to use a docker container to ensure consistent, stable development environment.
The required
DockerFileanddevcontainer.jsonare provided in.devcontainerdirectory. Build and RUN the docker container using the following commands:
docker build -t mqss-pass-dev -f .devcontainer/Dockerfile .
docker run --rm -it \
-v "$PWD":/workspaces/MQSS-Passes-Suite \
-w /workspaces/MQSS-Passes-Suite \
mqss-pass-dev \
bash
Building the tool¶
The driver is the
Makefilewithin the project root.The Makefile invokes build scripts within
scripts/.build.sh: Main script for configuring the build for all targets includingmqss-optThe ``make` commands to build the targets remain the same as in the README. Ensure the sequence of commands is followed.
Project structure (for Current Release)¶
MQSS-Quantum-Compilation-Suite/
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .github/
│ └── workflows/
│ ├── ci.yml
│ └── docs.yml
├── cmake/
│ ├── FindCUDAQ.cmake
│ ├── FindCatalyst.cmake
│ ├── FindZ3.cmake
│ ├── Findboost.cmake
│ ├── Findmqt-qcec.cmake
│ ├── Findmqt-qmap.cmake
│ ├── Findqdmi.cmake
│ ├── Findqinfo.cmake
│ └── try_z3.cpp
├── docs/
│ ├── _static/
│ ├── develop-guide/
│ │ ├── develop-guide.md
│ │ ├── index.md
│ │ ├── integrate.md
│ │ └── templates.md
│ ├── faqs/
│ │ ├── index.md
│ │ ├── mlir-faq.md
│ │ └── mqss-faq.md
│ ├── user_guide/
│ │ ├── build.md
│ │ ├── index.md
│ │ ├── passes.md
│ │ ├── running.md
│ │ └── transpiler.md
│ ├── .nojekyll
│ ├── conf.py
│ ├── dependencies.md
│ ├── header.html
│ ├── index.md
│ ├── layout.xml
│ ├── style.css
│ └── support.md
├── include/
│ ├── Passes/
│ │ ├── CodeGen/
│ │ │ ├── Patterns.h
│ │ │ └── StaticAllocas.h
│ │ ├── analysis/
│ │ │ ├── CatalystExtractor.h
│ │ │ ├── DialectAnalysisSelector.h
│ │ │ ├── Extractor.h
│ │ │ └── QuakeExtractor.h
│ │ ├── transforms/
│ │ │ ├── CMakeLists.txt
│ │ │ ├── Decomposition.h
│ │ │ ├── DecompositionPatterns.h
│ │ │ ├── Error.h
│ │ │ ├── PassIncludes.h
│ │ │ ├── PassUtils.h
│ │ │ ├── Pipelines.h
│ │ │ ├── Transforms.h
│ │ │ ├── Transforms.td
│ │ │ └── TranspilationPassUtils.h
│ │ └── CMakeLists.txt
│ ├── Utils/
│ │ └── dialectutils.h
│ └── CMakeLists.txt
├── lib/
│ ├── Passes/
│ │ ├── CodeGen/
│ │ │ ├── BasisConversion.cpp
│ │ │ ├── ConversionPatterns.cpp
│ │ │ ├── GlobalizeArrayValues.cpp
│ │ │ ├── LLVMDialectToLLVMIR.cpp
│ │ │ ├── QuakeToQASM2.cpp
│ │ │ ├── QuantumToLLVMDialect.cpp
│ │ │ └── StaticAllocas.cpp
│ │ ├── Transforms/
│ │ │ ├── CommonCNOTReversalPass.cpp
│ │ │ ├── CommonCommuteAndSwitchPass.cpp
│ │ │ ├── CommonDecompositionPass.cpp
│ │ │ ├── CommonGateCancellationPass.cpp
│ │ │ ├── CommonGateCommutationPass.cpp
│ │ │ ├── CommonMappingPass.cpp
│ │ │ ├── CommonNormalizeArgAnglePass.cpp
│ │ │ ├── CommonPatternReductionPass.cpp
│ │ │ └── pipeline.cpp
│ │ └── CMakeLists.txt
│ └── CMakeLists.txt
├── scripts/
│ ├── conversion/
│ │ ├── catalyst-to-qir.sh
│ │ └── cudaq-to-qir.sh
│ ├── build.sh*
│ ├── build_docs.sh*
│ ├── download_toolchains.sh
│ ├── mqss-cc*
│ ├── resolve_python_input.py
│ └── setup-env.sh*
├── tests/
│ ├── code/
│ │ ├── catalyst/
│ │ │ ├── tests/ # 19 .test lit files
│ │ │ └── *.py # 19 matching Python drivers
│ │ └── cudaq/
│ │ ├── tests/ # 24 .test lit files
│ │ └── *.cpp # 25 matching C++ pass sources
│ ├── dialects/
│ │ ├── catalyst-quantum/ # 29 .mlir files + cxx_qdmi.conf
│ │ └── quake/ # 30 .qke files + cxx_qdmi.conf
│ ├── input/
│ │ ├── cxx_qdmi.conf
│ │ ├── mqt_qdmi.conf
│ │ └── qmap.json
│ └── lit.cfg.py
├── .clang-format
├── .clang-tidy
├── .clangd
├── .cmake-format.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── CMakeLists.txt
├── LICENSE
├── Makefile
├── README.md
└── mqss-cc.cpp
The Dialect Agnostic MLIR optimization passes can be found in
lib/Passes/Transforms.CUDAQ and Catalyst are included as external dependencies and are downloaded and installed as
cmakemodules. Following targets are built for each of these modules:CUDAQ:
QuakeDialect CCDialect QECDialect OptimBuilder OptCodeGenCatalyst :
MLIRMBQC MLIRQRef MLIRQuantumThese targets incorporate all dialect related headers and API implementations.
CMakeLists.txt¶
Two CMakeLists.txt are of importance: root/CMakeLists.txt and lib/Passes/CMakeLists.txt. CUDAQ,
Catalyst, QDMI, MQT-QMAP etc. are linked as external dependencies in each of these CMakeLists as
follows: For e.g. in Root/CMakeLists.txt:
target_link_libraries(mqss-opt
PUBLIC
# QDMI
qdmi::qdmi
qdmi::example_driver
#
# CUDAQ
CUDAQ::CC
CUDAQ::Quake
CUDAQ::QEC
#
#Catalyst
CATALYST::MBQC
CATALYST::QRef
CATALYST::Quantum
#
MLIRLLVMDialect
MLIROptLib
MLIRIR
MLIRFuncDialect
MLIRFuncInlinerExtension
MLIRArithDialect
# MQSS Passes Library
MQSSCIPasses
#
CUDAQ::CodeGen
MLIRTransforms
# MQT
MQT::CoreIR
MQT::CoreNA
MQT::QMapSC
MQT::QMapSCHeuristic
#
MLIROptLib # Provides MlirOptMain engine
# Conversions
MLIRArithToLLVM
MLIRComplexToLibm
MLIRComplexToLLVM
MLIRControlFlowToLLVM
MLIRFuncToLLVM
MLIRMathToFuncs
MLIRMathToLLVM
# Translation
MLIRTargetLLVMIRExport
)
Testing¶
We use python-lit along-with ninja and FileCheck to perform dialect-level (input: MLIR dialect; output: MLIR dialect) and optionally end-to-end (input:c++/python code; output: MLIR dialect) testing. In the end, what is tested for correctness is the output optimized/transformed MLIR dialect. In a select few cases, especially the
CodeGenpasses, the backend exchange formats e.g. QIR or OpenQasm2 are tested for correctness.The tests can be found in directories :
tests/dialectsandtests/code.Dialect-level testing
The input dialect is annotated with the RUN command, for e.g.:
// RUN: %mqss-opt %s --CommonCommutePass=mode=CX-X 2>&1 | FileCheck %swhich runs the target/executablemqss-optalong-with the passCommonCommutePass. FileCheck looks for strings to match, specified using theCHECK:keyword, for e.g.// CHECK: %out_qubits = quantum.custom "PauliX"() %2 : !quantum.bit // CHECK: %out_qubits_0:2 = quantum.custom "CNOT"() %1, %2 : !quantum.bit, !quantum.bit
If an exact match is found in the output dialect, the test succeeds, otherwise the test fails.
End-to-End testing (Optional) In this testing, the input is a c++/python code, which is then translated to the input MLIR dialect. The testing then proceeds as in (1). The emphasis here is on testing the front-end translation pipeline as well as the transformed dialects. A wrapper script
mqss-ccis used to invoke the necessary tools to translate the c++/python code to the input quake or catalyst-quantum dialect. If the input code to MLIR dialect translation fails, then the test itself will fail. An example test file performing such a test is shown below:// RUN: %mqss-cc %S/../CommuteCNotRxPass.cpp --passes=CommonCommutePass=mode=CX-RX | FileCheck %s // CHECK: quake.rx (%cst_1) %4 : (f64, !quake.ref) -> () // CHECK-NEXT: quake.x [%1] %2 : (!quake.ref, !quake.ref) -> ()
The test proceeds as follows:
mqss-cc parses the command-line arguments
%S/../CommuteCNotRxPass.cpp --passes=CommonCommutePass=mode=CX-RXSince, a c++ code is the input, it is assumed that the code contains a quantum circuit defined using cudaq (will be updated in the future).
The c++ to quake dialect translation pipeline is invoked via the tool
cudaq-quakeOnce the input dialect is generated,
mqss-opttool is used to apply MQSS optimization/translation passes defined using the--passesflag.Finally, the optimized/transformed dialect is emitted which is checked by FileCheck.
Note: Make sure that the path to
cudaq-quakeandmqss-optare appended to the$PATHenvironment variable of your shell via the command :eval "$(make set-target-paths)".
Enabling Pass Debug Information¶
The Pass debug information can be enabled by passing in the flag --debug to the DEBUG_FLAG
variable within the Makefile. Simply remove the flag if no debug information is needed.