From 47961ff843f64aadb2450243431447f731282825 Mon Sep 17 00:00:00 2001 From: Tianyi Wang Date: Thu, 4 May 2023 17:27:05 +0200 Subject: [PATCH 01/11] Updated .gitmodules --- .gitmodules | 2 +- extern/qfr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 57b3509d..3b21da21 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "extern/qfr"] path = extern/qfr url = https://github.com/cda-tum/qfr.git - branch = main + branch = mem-opt-qfr-tw diff --git a/extern/qfr b/extern/qfr index faa00f13..904fba8a 160000 --- a/extern/qfr +++ b/extern/qfr @@ -1 +1 @@ -Subproject commit faa00f1346368ebb10be8f1b22fff5327ab1ecee +Subproject commit 904fba8a8fa6947a531a987354c3aabcdd1358d3 From 6a7eabc1ab1efa17f02c91393ad51725ada7d6c9 Mon Sep 17 00:00:00 2001 From: Tianyi Wang Date: Thu, 4 May 2023 18:29:45 +0200 Subject: [PATCH 02/11] Updated qfr to contain my branch's dd package --- extern/qfr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/qfr b/extern/qfr index 904fba8a..9b200102 160000 --- a/extern/qfr +++ b/extern/qfr @@ -1 +1 @@ -Subproject commit 904fba8a8fa6947a531a987354c3aabcdd1358d3 +Subproject commit 9b200102865de209493896ca88cdfc240ad0034e From 04bc63ee928c5c2d09b501ad56d6bdd9f893665b Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sun, 7 May 2023 16:55:22 +0200 Subject: [PATCH 03/11] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20update=20QFR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extern/qfr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/qfr b/extern/qfr index 9b200102..74ec1fbf 160000 --- a/extern/qfr +++ b/extern/qfr @@ -1 +1 @@ -Subproject commit 9b200102865de209493896ca88cdfc240ad0034e +Subproject commit 74ec1fbfae9445e5cd899cebe5cae75e695143cf From a79fef85ea53b361216d36a379a67dfceae7e726 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sun, 7 May 2023 17:06:05 +0200 Subject: [PATCH 04/11] =?UTF-8?q?=F0=9F=A9=B9=20fix=20missing=20CMake=20ta?= =?UTF-8?q?rget=20checks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extern/qfr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/qfr b/extern/qfr index 74ec1fbf..e9ba1806 160000 --- a/extern/qfr +++ b/extern/qfr @@ -1 +1 @@ -Subproject commit 74ec1fbfae9445e5cd899cebe5cae75e695143cf +Subproject commit e9ba18061510a0c152033d0a360511c0bda13271 From bbb15a36fca59fe64c238c0ed3f0a69f9d24dc17 Mon Sep 17 00:00:00 2001 From: Tianyi Wang Date: Tue, 8 Aug 2023 22:38:23 +0200 Subject: [PATCH 05/11] Delete QFR --- .gitmodules | 4 ---- extern/qfr | 1 - 2 files changed, 5 deletions(-) delete mode 100644 .gitmodules delete mode 160000 extern/qfr diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 3b21da21..00000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "extern/qfr"] - path = extern/qfr - url = https://github.com/cda-tum/qfr.git - branch = mem-opt-qfr-tw diff --git a/extern/qfr b/extern/qfr deleted file mode 160000 index 9b200102..00000000 --- a/extern/qfr +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9b200102865de209493896ca88cdfc240ad0034e From 375405afb71512a86ec9810d71dabc520bc65120 Mon Sep 17 00:00:00 2001 From: Tianyi Wang Date: Tue, 8 Aug 2023 22:41:19 +0200 Subject: [PATCH 06/11] Merge branch 'main' into mem-opt-qcec-tw --- .cirrus.yml | 12 ++--- .clang-tidy | 1 + .github/workflows/ci.yml | 2 +- .github/workflows/deploy.yml | 2 +- .github/workflows/emulated-wheels.yml | 2 +- .github/workflows/python-ci.yml | 4 +- .gitmodules | 4 ++ .pre-commit-config.yaml | 20 +++---- .readthedocs.yaml | 4 +- CMakeLists.txt | 2 +- MANIFEST.in | 19 ++++--- docs/source/_static/custom.css | 50 ------------------ docs/source/conf.py | 22 +++++--- docs/source/index.rst | 2 +- docs/source/library/Configuration.rst | 14 ++--- .../library/EquivalenceCheckingManager.rst | 6 +-- docs/source/library/VerifyCompilation.rst | 12 ++--- .../library/configuration/Application.rst | 6 +-- .../library/configuration/Execution.rst | 6 +-- .../library/configuration/Functionality.rst | 6 +-- .../library/configuration/Optimizations.rst | 6 +-- .../library/configuration/Parameterized.rst | 6 +-- .../library/configuration/Simulation.rst | 6 +-- extern/mqt-core | 1 + include/Configuration.hpp | 3 +- include/EquivalenceCheckingManager.hpp | 2 +- include/checker/dd/DDConstructionChecker.hpp | 2 +- .../GateCostApplicationScheme.hpp | 8 +-- .../checker/dd/simulation/StateGenerator.hpp | 24 ++++----- include/checker/zx/ZXChecker.hpp | 4 +- mqt/qcec/CMakeLists.txt | 2 +- mqt/qcec/__init__.py | 1 + mqt/qcec/bindings.cpp | 6 +-- mqt/qcec/compilation_flow_profiles.py | 39 +++++++++----- mqt/qcec/parameterized.py | 10 ++-- mqt/qcec/pyqcec.pyi | 14 ++--- mqt/qcec/types.py | 1 + mqt/qcec/verify.py | 1 - mqt/qcec/verify_compilation_flow.py | 1 - pyproject.toml | 52 +++++++------------ setup.py | 6 ++- src/CMakeLists.txt | 4 +- src/EquivalenceCheckingManager.cpp | 1 - src/checker/dd/DDAlternatingChecker.cpp | 4 +- src/checker/dd/DDEquivalenceChecker.cpp | 4 +- src/checker/dd/DDSimulationChecker.cpp | 11 ++-- src/checker/zx/ZXChecker.cpp | 5 +- test/python/test_compilation_flow_profiles.py | 10 +++- test/python/test_verify.py | 12 ----- test/test_equality.cpp | 15 +----- test/test_gate_cost_application_scheme.cpp | 2 +- test/test_zx.cpp | 5 +- 52 files changed, 198 insertions(+), 266 deletions(-) create mode 100644 .gitmodules delete mode 100644 docs/source/_static/custom.css create mode 160000 extern/mqt-core diff --git a/.cirrus.yml b/.cirrus.yml index 910c9ee4..7e64908f 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,6 +1,6 @@ build_and_store_wheels: &BUILD_AND_STORE_WHEELS install_cibuildwheel_script: - - python -m pip install cibuildwheel==2.11.2 + - python -m pip install cibuildwheel~=2.14.0 run_cibuildwheel_script: - cibuildwheel wheels_artifacts: @@ -8,13 +8,13 @@ build_and_store_wheels: &BUILD_AND_STORE_WHEELS .clone_script: &clone | if [ -z "$CIRRUS_PR" ]; then - git clone --recursive --branch=$CIRRUS_BRANCH https://x-access-token:${CIRRUS_REPO_CLONE_TOKEN}@github.com/${CIRRUS_REPO_FULL_NAME}.git $CIRRUS_WORKING_DIR - git reset --hard $CIRRUS_CHANGE_IN_REPO + git clone --branch=$CIRRUS_BRANCH https://x-access-token:${CIRRUS_REPO_CLONE_TOKEN}@github.com/${CIRRUS_REPO_FULL_NAME}.git $CIRRUS_WORKING_DIR else - git clone --recursive https://x-access-token:${CIRRUS_REPO_CLONE_TOKEN}@github.com/${CIRRUS_REPO_FULL_NAME}.git $CIRRUS_WORKING_DIR + git clone https://x-access-token:${CIRRUS_REPO_CLONE_TOKEN}@github.com/${CIRRUS_REPO_FULL_NAME}.git $CIRRUS_WORKING_DIR git fetch origin pull/$CIRRUS_PR/head:pull/$CIRRUS_PR - git reset --hard $CIRRUS_CHANGE_IN_REPO fi + git reset --hard $CIRRUS_CHANGE_IN_REPO + git submodule update --init --recursive linux_aarch64_task: name: Build Linux aarch64 wheels. @@ -36,7 +36,7 @@ macos_arm64_task: name: Build macOS arm64 wheels. clone_script: *clone macos_instance: - image: ghcr.io/cirruslabs/macos-monterey-xcode + image: ghcr.io/cirruslabs/macos-monterey-xcode:latest env: PATH: /opt/homebrew/opt/python@3.10/bin:$PATH diff --git a/.clang-tidy b/.clang-tidy index 8f00f503..4ebeab16 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,6 +3,7 @@ FormatStyle: file Checks: | clang-diagnostic-*, clang-analyzer-*, + -clang-analyzer-core.NullDereference, boost-*, bugprone-*, -bugprone-easily-swappable-parameters, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc7157ed..a5ac5dd4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: ctest -C Debug --output-on-failure --test-dir buildCov --repeat until-pass:3 --timeout 300 - if: runner.os == 'Linux' name: Upload coverage to Codecov - uses: codecov/codecov-action@v3.1.3 + uses: codecov/codecov-action@v3.1.4 with: fail_ci_if_error: true flags: cpp diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index cd70d290..f39a6ea0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -28,7 +28,7 @@ jobs: submodules: recursive - uses: ilammy/msvc-dev-cmd@v1 - name: Build wheels - uses: pypa/cibuildwheel@v2.12.3 + uses: pypa/cibuildwheel@v2.14 - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl diff --git a/.github/workflows/emulated-wheels.yml b/.github/workflows/emulated-wheels.yml index 30712344..96228e00 100644 --- a/.github/workflows/emulated-wheels.yml +++ b/.github/workflows/emulated-wheels.yml @@ -26,7 +26,7 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v2 - name: Build wheels - uses: pypa/cibuildwheel@v2.12.3 + uses: pypa/cibuildwheel@v2.14 env: CIBW_ARCHS_LINUX: ${{ matrix.arch }} CIBW_BUILD: ${{ matrix.python }} diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index 72eea28b..765e0abb 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -56,7 +56,7 @@ jobs: - name: Run session run: nox -s min_qiskit_version -- --cov-report=xml - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v3.1.3 + uses: codecov/codecov-action@v3.1.4 with: fail_ci_if_error: true flags: python @@ -83,7 +83,7 @@ jobs: - name: Run session run: nox -s coverage-${{ matrix.python-version }} -- --cov-report=xml - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v3.1.3 + uses: codecov/codecov-action@v3.1.4 with: fail_ci_if_error: true flags: python diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..b40a6f71 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "extern/mqt-core"] + path = extern/mqt-core + url = https://github.com/cda-tum/mqt-core.git + branch = main diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2ebb0a12..d8ac162f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -49,25 +49,25 @@ repos: - id: rst-inline-touching-normal # Run ruff (subsumes pyupgrade, isort, flake8+plugins, and more) - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.263 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.282 hooks: - id: ruff - args: ["--fix"] + args: ["--fix", "--show-fixes"] # Run code formatting with Black - repo: https://github.com/psf/black - rev: 23.3.0 # Keep in sync with blacken-docs + rev: 23.7.0 # Keep in sync with blacken-docs hooks: - id: black-jupyter # Also run Black on examples in the documentation - repo: https://github.com/asottile/blacken-docs - rev: 1.13.0 + rev: 1.15.0 hooks: - id: blacken-docs additional_dependencies: - - black==23.3.0 # keep in sync with black hook + - black==23.7.0 # keep in sync with black hook # CMake format and lint the CMakeLists.txt files - repo: https://github.com/cheshirekow/cmake-format-precommit @@ -80,21 +80,21 @@ repos: # Clang-format the C++ part of the code base automatically - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v16.0.2 + rev: v16.0.6 hooks: - id: clang-format types_or: [c++, c, cuda] # Format configuration files with prettier - repo: https://github.com/pre-commit/mirrors-prettier - rev: "v3.0.0-alpha.9-for-vscode" + rev: "v3.0.1" hooks: - id: prettier types_or: [yaml, markdown, html, css, scss, javascript, json] # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.2.0 + rev: v1.4.1 hooks: - id: mypy files: ^(mqt/qcec|test/python|setup.py) @@ -107,7 +107,7 @@ repos: # Check for spelling - repo: https://github.com/codespell-project/codespell - rev: v2.2.4 + rev: v2.2.5 hooks: - id: codespell args: ["-L", "wille,linz", "--skip", "*.ipynb"] diff --git a/.readthedocs.yaml b/.readthedocs.yaml index f5fbc871..c43c13fe 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -5,9 +5,9 @@ submodules: recursive: true build: - os: ubuntu-20.04 + os: ubuntu-22.04 tools: - python: "3.9" + python: "3.11" apt_packages: - cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index aef82cb2..8442cd82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ macro(CHECK_SUBMODULE_PRESENT modulename) endif() endmacro() -check_submodule_present(qfr) +check_submodule_present(mqt-core) # add main library code add_subdirectory(src) diff --git a/MANIFEST.in b/MANIFEST.in index 388e954e..837d28a8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,7 +2,7 @@ prune docs prune test prune .idea -graft extern/qfr +graft extern/mqt-core prune **/.github prune **/apps prune **/doc @@ -12,12 +12,11 @@ prune **/plots prune **/test prune **/tests -prune extern/qfr/extern/json/include -prune extern/qfr/extern/dd_package/extern -prune extern/qfr/extern/zx/extern/googletest -prune extern/qfr/extern/zx/extern/boost/config/checks -prune extern/qfr/extern/zx/extern/boost/config/tools -prune extern/qfr/extern/zx/extern/boost/multiprecision/config -prune extern/qfr/extern/zx/extern/boost/multiprecision/example -prune extern/qfr/extern/zx/extern/boost/multiprecision/performance -prune extern/qfr/extern/zx/extern/boost/multiprecision/tools +prune extern/mqt-core/extern/json/include +prune extern/mqt-core/extern/googletest +prune extern/mqt-core/extern/boost/config/checks +prune extern/mqt-core/extern/boost/config/tools +prune extern/mqt-core/extern/boost/multiprecision/config +prune extern/mqt-core/extern/boost/multiprecision/example +prune extern/mqt-core/extern/boost/multiprecision/performance +prune extern/mqt-core/extern/boost/multiprecision/tools diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css deleted file mode 100644 index d44a185b..00000000 --- a/docs/source/_static/custom.css +++ /dev/null @@ -1,50 +0,0 @@ -.wy-side-nav-search { - background-color: #0b152d; -} - -html[data-theme="dark"].writer-html4 - .rst-content - dl:not(.docutils) - .descclassname, -html[data-theme="dark"].writer-html4 .rst-content dl:not(.docutils) .descname, -html[data-theme="dark"].writer-html4 .rst-content dl:not(.docutils) .sig-name, -html[data-theme="dark"].writer-html5 - .rst-content - dl[class]:not(.option-list):not(.field-list):not(.footnote):not( - .citation - ):not(.glossary):not(.simple) - .descclassname, -html[data-theme="dark"].writer-html5 - .rst-content - dl[class]:not(.option-list):not(.field-list):not(.footnote):not( - .citation - ):not(.glossary):not(.simple) - .descname, -html[data-theme="dark"].writer-html5 - .rst-content - dl[class]:not(.option-list):not(.field-list):not(.footnote):not( - .citation - ):not(.glossary):not(.simple) - .sig-name { - color: #bfbfbf; -} - -html[data-theme="dark"].writer-html4 - .rst-content - dl:not(.docutils) - dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not( - .glossary - ):not(.simple) - > dt, -html[data-theme="dark"].writer-html5 - .rst-content - dl[class]:not(.option-list):not(.field-list):not(.footnote):not( - .citation - ):not(.glossary):not(.simple) - dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not( - .glossary - ):not(.simple) - > dt { - background-color: #0b0b0b; - border-left: 3px solid #555; -} diff --git a/docs/source/conf.py b/docs/source/conf.py index bc64ae66..886aeb9b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,4 +1,5 @@ """Sphinx configuration file.""" +from __future__ import annotations import sys @@ -7,12 +8,16 @@ else: from importlib import metadata +from typing import TYPE_CHECKING + import pybtex.plugin -from pybtex.database import Entry -from pybtex.richtext import HRef from pybtex.style.formatting.unsrt import Style as UnsrtStyle from pybtex.style.template import field, href +if TYPE_CHECKING: + from pybtex.database import Entry + from pybtex.richtext import HRef + # -- Project information ----------------------------------------------------- project = "QCEC" author = "Lukas Burgholzer" @@ -37,7 +42,6 @@ "hoverxref.extension", "nbsphinx", "sphinxext.opengraph", - "sphinx_rtd_dark_mode", "sphinx_autodoc_typehints", ] @@ -94,8 +98,14 @@ def format_url(self, _e: Entry) -> HRef: autosummary_generate = True # -- Options for HTML output ------------------------------------------------- -html_theme = "sphinx_rtd_theme" +html_theme = "furo" html_baseurl = "https://qcec.readthedocs.io/en/latest/" -html_logo = "_static/mqt_light.png" html_static_path = ["_static"] -html_css_files = ["custom.css"] +html_theme_options = { + "light_logo": "mqt_dark.png", + "dark_logo": "mqt_light.png", + "source_repository": "https://github.com/cda-tum/qcec/", + "source_branch": "main", + "source_directory": "docs/source", + "navigation_with_keys": True, +} diff --git a/docs/source/index.rst b/docs/source/index.rst index 7aa1b02d..7ace1fca 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -7,7 +7,7 @@ We recommend you to start with the :doc:`installation instructions ` and read the :doc:`reference documentation `. If you are interested in the theory behind QCEC, have a look at the publications in the :doc:`publication list `. -We appreciate any feedback and contributions to the project. If you want to contribute, you can find more information in the :doc:`Contribution ` guide. If you are having trouble with the installation or the usage of QCEC, please let us know at our :doc:`Support ` page or by reaching out to us at `quantum.cda@xcit.tum.de `_. +We appreciate any feedback and contributions to the project. If you want to contribute, you can find more information in the :doc:`Contribution ` guide. If you are having trouble with the installation or the usage of QCEC, please let us know at our :doc:`Support ` page. ---- diff --git a/docs/source/library/Configuration.rst b/docs/source/library/Configuration.rst index dc468785..a06f660a 100644 --- a/docs/source/library/Configuration.rst +++ b/docs/source/library/Configuration.rst @@ -1,8 +1,8 @@ Configuration ============= -.. currentmodule:: mqt.qcec -.. autoclass:: Configuration + .. currentmodule:: mqt.qcec + .. autoclass:: Configuration The :class:`Configuration` class provides all the means to configure QCEC. All of the options are split into the following categories: @@ -18,11 +18,11 @@ The :class:`Configuration` class provides all the means to configure QCEC. All o All of these options can be passed to the :meth:`~mqt.qcec.verify` and :meth:`~mqt.qcec.verify_compilation` methods as keyword arguments. -.. currentmodule:: mqt.qcec.configuration -.. autoclass:: ConfigurationOptions - :members: - :undoc-members: + .. currentmodule:: mqt.qcec.configuration + .. autoclass:: ConfigurationOptions + :members: + :undoc-members: There, they are incorporated into the :class:`Configuration` using the :func:`~mqt.qcec.configuration.augment_config_from_kwargs` function. -.. autofunction:: augment_config_from_kwargs + .. autofunction:: augment_config_from_kwargs diff --git a/docs/source/library/EquivalenceCheckingManager.rst b/docs/source/library/EquivalenceCheckingManager.rst index 3c940419..f269580e 100644 --- a/docs/source/library/EquivalenceCheckingManager.rst +++ b/docs/source/library/EquivalenceCheckingManager.rst @@ -29,7 +29,7 @@ This constructs the manager using all the default options. The circuits to be ve It can be further configured by passing a :class:`~.Configuration` object to the constructor. -.. automethod:: EquivalenceCheckingManager.__init__ + .. automethod:: EquivalenceCheckingManager.__init__ Configuration after instantiation ################################# @@ -89,10 +89,6 @@ Running the equivalence check ############################## Once the manager has been constructed and (optionally) configured, the equivalence check can be started by calling :func:`~EquivalenceCheckingManager.run`. - .. code-block:: python - - ecm.run() - .. automethod:: EquivalenceCheckingManager.run Obtaining the results diff --git a/docs/source/library/VerifyCompilation.rst b/docs/source/library/VerifyCompilation.rst index 328e87bd..3dcbe032 100644 --- a/docs/source/library/VerifyCompilation.rst +++ b/docs/source/library/VerifyCompilation.rst @@ -3,8 +3,8 @@ Verify Compilation QCEC provides a dedicated :func:`.verify_compilation` method for verifying that a quantum circuit has been compiled correctly based on the methods proposed in :cite:p:`burgholzer2020verifyingResultsIBM`. -.. currentmodule:: mqt.qcec -.. autofunction:: verify_compilation + .. currentmodule:: mqt.qcec + .. autofunction:: verify_compilation .. note:: @@ -12,9 +12,9 @@ QCEC provides a dedicated :func:`.verify_compilation` method for verifying that Failing to do so may result in incorrect results because the checker will then simply assume that the logical qubits are mapped to the physical qubits in the same order as they appear in the circuit. Make sure to insert measurements *before* the circuit is compiled to the target architecture. -.. autoclass:: AncillaMode - :undoc-members: - :members: + .. autoclass:: AncillaMode + :undoc-members: + :members: Compilation Flow Profile Generation ################################### @@ -22,4 +22,4 @@ Compilation Flow Profile Generation QCEC provides dedicated compilation flow profiles for IBM Qiskit which can be used to efficiently verify the results of compilation flow results :cite:p:`burgholzer2020verifyingResultsIBM`. These profiles are generated from IBM Qiskit using the :func:`.generate_profile` method. -.. autofunction:: generate_profile + .. autofunction:: generate_profile diff --git a/docs/source/library/configuration/Application.rst b/docs/source/library/configuration/Application.rst index 72f75594..8e222846 100644 --- a/docs/source/library/configuration/Application.rst +++ b/docs/source/library/configuration/Application.rst @@ -1,6 +1,6 @@ Application =========== -.. autoclass:: mqt.qcec::Configuration.Application - :members: - :undoc-members: + .. autoclass:: mqt.qcec::Configuration.Application + :members: + :undoc-members: diff --git a/docs/source/library/configuration/Execution.rst b/docs/source/library/configuration/Execution.rst index 9a372e72..5f4c7579 100644 --- a/docs/source/library/configuration/Execution.rst +++ b/docs/source/library/configuration/Execution.rst @@ -1,6 +1,6 @@ Execution ========= -.. autoclass:: mqt.qcec::Configuration.Execution - :members: - :undoc-members: + .. autoclass:: mqt.qcec::Configuration.Execution + :members: + :undoc-members: diff --git a/docs/source/library/configuration/Functionality.rst b/docs/source/library/configuration/Functionality.rst index 705c1e09..126a4a25 100644 --- a/docs/source/library/configuration/Functionality.rst +++ b/docs/source/library/configuration/Functionality.rst @@ -1,6 +1,6 @@ Functionality ============= -.. autoclass:: mqt.qcec::Configuration.Functionality - :members: - :undoc-members: + .. autoclass:: mqt.qcec::Configuration.Functionality + :members: + :undoc-members: diff --git a/docs/source/library/configuration/Optimizations.rst b/docs/source/library/configuration/Optimizations.rst index e55d2964..510b1133 100644 --- a/docs/source/library/configuration/Optimizations.rst +++ b/docs/source/library/configuration/Optimizations.rst @@ -1,6 +1,6 @@ Optimizations ============= -.. autoclass:: mqt.qcec::Configuration.Optimizations - :members: - :undoc-members: + .. autoclass:: mqt.qcec::Configuration.Optimizations + :members: + :undoc-members: diff --git a/docs/source/library/configuration/Parameterized.rst b/docs/source/library/configuration/Parameterized.rst index 05cbe293..ce735ed7 100644 --- a/docs/source/library/configuration/Parameterized.rst +++ b/docs/source/library/configuration/Parameterized.rst @@ -1,6 +1,6 @@ Parameterized ============= -.. autoclass:: mqt.qcec::Configuration.Parameterized - :members: - :undoc-members: + .. autoclass:: mqt.qcec::Configuration.Parameterized + :members: + :undoc-members: diff --git a/docs/source/library/configuration/Simulation.rst b/docs/source/library/configuration/Simulation.rst index 03ba9f7f..61199918 100644 --- a/docs/source/library/configuration/Simulation.rst +++ b/docs/source/library/configuration/Simulation.rst @@ -1,6 +1,6 @@ Simulation ========== -.. autoclass:: mqt.qcec::Configuration.Simulation - :members: - :undoc-members: + .. autoclass:: mqt.qcec::Configuration.Simulation + :members: + :undoc-members: diff --git a/extern/mqt-core b/extern/mqt-core new file mode 160000 index 00000000..a50af79e --- /dev/null +++ b/extern/mqt-core @@ -0,0 +1 @@ +Subproject commit a50af79e85c18993342a55b4eaea7a18eff49fdf diff --git a/include/Configuration.hpp b/include/Configuration.hpp index 5cd78c37..25dc4ac8 100644 --- a/include/Configuration.hpp +++ b/include/Configuration.hpp @@ -8,7 +8,6 @@ #include "checker/dd/applicationscheme/ApplicationScheme.hpp" #include "checker/dd/applicationscheme/GateCostApplicationScheme.hpp" #include "checker/dd/simulation/StateGenerator.hpp" -#include "dd/Package.hpp" #include "nlohmann/json.hpp" #include @@ -20,7 +19,7 @@ class Configuration { public: // configuration options for execution struct Execution { - dd::fp numericalTolerance = dd::ComplexTable<>::tolerance(); + dd::fp numericalTolerance = dd::RealNumber::eps; bool parallel = true; std::size_t nthreads = std::max(2U, std::thread::hardware_concurrency()); diff --git a/include/EquivalenceCheckingManager.hpp b/include/EquivalenceCheckingManager.hpp index b071b460..b90357eb 100644 --- a/include/EquivalenceCheckingManager.hpp +++ b/include/EquivalenceCheckingManager.hpp @@ -95,7 +95,7 @@ class EquivalenceCheckingManager { // what is executed during `run` void setTolerance(dd::fp tol) { configuration.execution.numericalTolerance = tol; - dd::ComplexTable<>::setTolerance(tol); + dd::ComplexNumbers::setTolerance(tol); } void setParallel(bool parallel) { configuration.execution.parallel = parallel; diff --git a/include/checker/dd/DDConstructionChecker.hpp b/include/checker/dd/DDConstructionChecker.hpp index 0bfc27c4..a5df34fd 100644 --- a/include/checker/dd/DDConstructionChecker.hpp +++ b/include/checker/dd/DDConstructionChecker.hpp @@ -30,7 +30,7 @@ class DDConstructionChecker final private: void initializeTask(TaskManager& taskManager) override { - const auto initial = dd->makeIdent(static_cast(nqubits)); + const auto initial = dd->makeIdent(nqubits); taskManager.setInternalState(initial); taskManager.incRef(); taskManager.reduceAncillae(); diff --git a/include/checker/dd/applicationscheme/GateCostApplicationScheme.hpp b/include/checker/dd/applicationscheme/GateCostApplicationScheme.hpp index 4f919b10..e9c8d9bc 100644 --- a/include/checker/dd/applicationscheme/GateCostApplicationScheme.hpp +++ b/include/checker/dd/applicationscheme/GateCostApplicationScheme.hpp @@ -6,18 +6,18 @@ #pragma once #include "ApplicationScheme.hpp" -#include "dd/Definitions.hpp" #include "operations/OpType.hpp" +#include #include #include #include #include namespace std { -template <> struct hash> { +template <> struct hash> { std::size_t - operator()(pair const& key) const noexcept { + operator()(pair const& key) const noexcept { const std::size_t h1 = hash{}(key.first); const std::size_t h2 = hash{}(key.second); return h1 ^ (h2 << 1); @@ -26,7 +26,7 @@ template <> struct hash> { } // namespace std namespace ec { -using GateCostLookupTableKeyType = std::pair; +using GateCostLookupTableKeyType = std::pair; using GateCostLookupTable = std::unordered_map; using CostFunction = diff --git a/include/checker/dd/simulation/StateGenerator.hpp b/include/checker/dd/simulation/StateGenerator.hpp index 7e25bac4..75525863 100644 --- a/include/checker/dd/simulation/StateGenerator.hpp +++ b/include/checker/dd/simulation/StateGenerator.hpp @@ -25,8 +25,8 @@ class StateGenerator { template > qc::VectorDD generateRandomState(std::unique_ptr& dd, - const dd::QubitCount totalQubits, - const dd::QubitCount ancillaryQubits = 0U, + const std::size_t totalQubits, + const std::size_t ancillaryQubits = 0U, const StateType type = StateType::ComputationalBasis) { switch (type) { case ec::StateType::Random1QBasis: @@ -41,8 +41,8 @@ class StateGenerator { template > qc::VectorDD generateRandomComputationalBasisState( - std::unique_ptr& dd, const dd::QubitCount totalQubits, - const dd::QubitCount ancillaryQubits = 0U) { + std::unique_ptr& dd, const std::size_t totalQubits, + const std::size_t ancillaryQubits = 0U) { // determine how many qubits truly are random const std::size_t randomQubits = totalQubits - ancillaryQubits; std::vector stimulusBits(totalQubits, false); @@ -93,15 +93,15 @@ class StateGenerator { template > qc::VectorDD generateRandom1QBasisState(std::unique_ptr& dd, - const dd::QubitCount totalQubits, - const dd::QubitCount ancillaryQubits = 0U) { + const std::size_t totalQubits, + const std::size_t ancillaryQubits = 0U) { // determine how many qubits truly are random - const dd::QubitCount randomQubits = totalQubits - ancillaryQubits; + const std::size_t randomQubits = totalQubits - ancillaryQubits; // choose a random basis state for each qubit auto randomBasisState = std::vector(totalQubits, dd::BasisStates::zero); - for (dd::QubitCount i = 0U; i < randomQubits; ++i) { + for (std::size_t i = 0U; i < randomQubits; ++i) { switch (random1QBasisDistribution(mt)) { case static_cast(dd::BasisStates::zero): randomBasisState[i] = dd::BasisStates::zero; @@ -133,10 +133,10 @@ class StateGenerator { template > qc::VectorDD generateRandomStabilizerState(std::unique_ptr& dd, - const dd::QubitCount totalQubits, - const dd::QubitCount ancillaryQubits = 0U) { + const std::size_t totalQubits, + const std::size_t ancillaryQubits = 0U) { // determine how many qubits truly are random - const dd::QubitCount randomQubits = totalQubits - ancillaryQubits; + const std::size_t randomQubits = totalQubits - ancillaryQubits; // generate a random Clifford circuit with appropriate depth auto rcs = qc::RandomCliffordCircuit( @@ -152,7 +152,7 @@ class StateGenerator { // add |0> edges for all the ancillary qubits auto initial = stabilizer; - for (dd::QubitCount p = randomQubits; p < totalQubits; ++p) { + for (std::size_t p = randomQubits; p < totalQubits; ++p) { initial = dd->makeDDNode(static_cast(p), std::array{initial, qc::VectorDD::zero}); } diff --git a/include/checker/zx/ZXChecker.hpp b/include/checker/zx/ZXChecker.hpp index d1623f08..12209d4a 100644 --- a/include/checker/zx/ZXChecker.hpp +++ b/include/checker/zx/ZXChecker.hpp @@ -9,10 +9,10 @@ #include "Definitions.hpp" #include "EquivalenceCriterion.hpp" #include "QuantumComputation.hpp" -#include "Simplify.hpp" -#include "ZXDiagram.hpp" #include "checker/EquivalenceChecker.hpp" #include "nlohmann/json.hpp" +#include "zx/Simplify.hpp" +#include "zx/ZXDiagram.hpp" namespace ec { class ZXEquivalenceChecker : public EquivalenceChecker { diff --git a/mqt/qcec/CMakeLists.txt b/mqt/qcec/CMakeLists.txt index f8bde351..6249847b 100644 --- a/mqt/qcec/CMakeLists.txt +++ b/mqt/qcec/CMakeLists.txt @@ -1,4 +1,4 @@ pybind11_add_module(py${PROJECT_NAME} bindings.cpp) -target_link_libraries(py${PROJECT_NAME} PRIVATE ${PROJECT_NAME} MQT::qfr_python) +target_link_libraries(py${PROJECT_NAME} PRIVATE ${PROJECT_NAME} MQT::CorePython) target_compile_definitions(py${PROJECT_NAME} PRIVATE VERSION_INFO=${QCEC_VERSION_INFO}) diff --git a/mqt/qcec/__init__.py b/mqt/qcec/__init__.py index 9c1ef030..dca67581 100644 --- a/mqt/qcec/__init__.py +++ b/mqt/qcec/__init__.py @@ -3,6 +3,7 @@ This file is part of the MQT QCEC library released under the MIT license. See README.md or go to https://github.com/cda-tum/qcec for more information. """ +from __future__ import annotations from mqt.qcec.compilation_flow_profiles import AncillaMode, generate_profile from mqt.qcec.pyqcec import ( diff --git a/mqt/qcec/bindings.cpp b/mqt/qcec/bindings.cpp index 6e7253f7..cc509720 100644 --- a/mqt/qcec/bindings.cpp +++ b/mqt/qcec/bindings.cpp @@ -8,8 +8,8 @@ #include "pybind11/pybind11.h" #include "pybind11/stl.h" #include "pybind11_json/pybind11_json.hpp" -#include "qiskit/QasmQobjExperiment.hpp" -#include "qiskit/QuantumCircuit.hpp" +#include "python/qiskit/QasmQobjExperiment.hpp" +#include "python/qiskit/QuantumCircuit.hpp" #include #include @@ -192,7 +192,7 @@ PYBIND11_MODULE(pyqcec, m) { // Convenience functions // Execution .def("set_tolerance", &EquivalenceCheckingManager::setTolerance, - "tolerance"_a = dd::ComplexTable<>::tolerance(), + "tolerance"_a = dd::RealNumber::eps, "Set the :attr:`numerical tolerance " "<.Configuration.Execution.numerical_tolerance>` of the underlying " "decision diagram package.") diff --git a/mqt/qcec/compilation_flow_profiles.py b/mqt/qcec/compilation_flow_profiles.py index 9ca8d612..3e3d421b 100644 --- a/mqt/qcec/compilation_flow_profiles.py +++ b/mqt/qcec/compilation_flow_profiles.py @@ -2,8 +2,7 @@ from __future__ import annotations -import random -from enum import Enum +from enum import Enum, unique from pathlib import Path from typing import Any @@ -11,13 +10,30 @@ from qiskit import QuantumCircuit, transpile -class AncillaMode(str, Enum): +@unique +class AncillaMode(Enum): """Enum for the ancilla mode.""" NO_ANCILLA = "noancilla" RECURSION = "recursion" V_CHAIN = "v-chain" + def __eq__(self, other: object) -> bool: + """Check if two AncillaMode objects are equal. Supports string comparison.""" + if isinstance(other, str): + return self.value == other + if isinstance(other, self.__class__): + return self.value == other.value + return False + + def __hash__(self) -> int: + """Return the hash of the AncillaMode.""" + return hash(self.value) + + def __str__(self) -> str: + """Return the string representation of the AncillaMode.""" + return self.value + single_qubit_gates_no_params = { "qubits": 1, @@ -132,9 +148,8 @@ def create_general_gate(qubits: int, params: int, controls: int, identifier: str qc = QuantumCircuit(required_qubits) gate_identifier = "c" * controls + identifier - parameter_list = [] - for _ in range(params): - parameter_list.append(random.uniform(-np.pi, np.pi)) + rng = np.random.default_rng() + parameter_list = [rng.uniform(-np.pi, np.pi) for _ in range(params)] getattr(qc, gate_identifier)(*parameter_list, *range(required_qubits)) return qc @@ -165,9 +180,8 @@ def create_multi_controlled_gate( qc = QuantumCircuit(required_qubits) gate_identifier = "mc" + identifier - parameter_list = [] - for _ in range(params): - parameter_list.append(random.uniform(-np.pi, np.pi)) + rng = np.random.default_rng() + parameter_list = [rng.uniform(-np.pi, np.pi) for _ in range(params)] if mode is not None: getattr(qc, gate_identifier)( @@ -268,7 +282,7 @@ def add_special_case_data( def generate_profile_name(optimization_level: int = 1, mode: AncillaMode = AncillaMode.NO_ANCILLA) -> str: """Generate a profile name based on the given optimization level and ancilla mode.""" - return "qiskit_O" + str(optimization_level) + "_" + mode + ".profile" + return "qiskit_O" + str(optimization_level) + "_" + str(mode) + ".profile" def write_profile_data_to_file(profile_data: dict[tuple[str, int], int], filename: Path) -> None: @@ -311,10 +325,7 @@ def find_continuation( prediction_cutoff: float = 1e6, ) -> None: """Extrapolate from the given profile data by finding recurrence relations.""" - sequence = [] - for (g, _), cost in profile_data.items(): - if g is gate: - sequence.append(cost) + sequence = [cost for (g, _), cost in profile_data.items() if g == gate] # sort the sequence sequence = sorted(sequence) diff --git a/mqt/qcec/parameterized.py b/mqt/qcec/parameterized.py index 3ee89218..2b10884b 100644 --- a/mqt/qcec/parameterized.py +++ b/mqt/qcec/parameterized.py @@ -58,7 +58,7 @@ def is_expr(x: float | Parameter | ParameterExpression) -> bool: return isinstance(x, (Parameter, ParameterExpression)) symb_params: list[Parameter | ParameterExpression] = [param for param in p if is_expr(param)] - symb_params.sort(key=lambda param: param.name) # type: ignore[no-any-return] + symb_params.sort(key=lambda param: param.name) symb_exprs = list(filter(is_expr, exprs)) offsets = np.zeros(len(symb_exprs)) @@ -96,8 +96,9 @@ def check_instantiated_random( ) -> EquivalenceCheckingManager.Results: """Check whether circuits are equivalent for random instantiation of symbolic parameters.""" param_map = {} + rng = np.random.default_rng() for p in params: - param_map[p] = np.random.rand() * 2 * np.pi + param_map[p] = rng.random() * 2 * np.pi circ1_inst = circ1.bind_parameters(param_map) circ2_inst = circ2.bind_parameters(param_map) @@ -105,7 +106,7 @@ def check_instantiated_random( return check_instantiated(circ1_inst, circ2_inst, configuration) -def check_parameterized( # noqa: PLR0915 +def check_parameterized( circ1: QuantumCircuit | str, circ2: QuantumCircuit | str, configuration: Configuration ) -> EquivalenceCheckingManager.Results: """Equivalence checking flow for parameterized circuit.""" @@ -178,7 +179,8 @@ def instantiate_params_phases( qc1: QuantumCircuit, qc2: QuantumCircuit ) -> tuple[QuantumCircuit, QuantumCircuit, float]: phases = [0, np.pi, np.pi / 2, -np.pi / 2, np.pi / 4, -np.pi / 4] - b = np.random.choice(phases, size=len(offsets)) + offsets + rng = np.random.default_rng() + b = rng.choice(phases, size=len(offsets)) + offsets return instantiate_params(qc1, qc2, b) circ1_inst, circ2_inst, runtime = instantiate_params_zero(circ1, circ2) diff --git a/mqt/qcec/pyqcec.pyi b/mqt/qcec/pyqcec.pyi index 888f419c..79c3486d 100644 --- a/mqt/qcec/pyqcec.pyi +++ b/mqt/qcec/pyqcec.pyi @@ -1,11 +1,8 @@ -from __future__ import annotations +from typing import Any, ClassVar, overload -from typing import TYPE_CHECKING, Any, ClassVar, overload +from qiskit import QuantumCircuit -if TYPE_CHECKING: - from qiskit import QuantumCircuit - - from mqt.qcec.types import ApplicationSchemeName, EquivalenceCriterionName, StateTypeName +from mqt.qcec.types import ApplicationSchemeName, EquivalenceCriterionName, StateTypeName class ApplicationScheme: __members__: ClassVar[dict[ApplicationScheme, int]] = ... # read-only @@ -25,7 +22,6 @@ class ApplicationScheme: def __index__(self) -> int: ... def __int__(self) -> int: ... def __ne__(self, other: object) -> bool: ... - def __repr__(self) -> str: ... def __setstate__(self, state: int) -> None: ... def __str__(self) -> ApplicationSchemeName: ... @property @@ -99,7 +95,6 @@ class EquivalenceCheckingManager: def __init__(self) -> None: ... def considered_equivalent(self) -> bool: ... def json(self) -> dict[str, Any]: ... - def __repr__(self) -> str: ... def __init__( self, circ1: QuantumCircuit | str, circ2: QuantumCircuit | str, config: Configuration = ... @@ -137,7 +132,6 @@ class EquivalenceCheckingManager: def set_zx_checker(self, enable: bool = ...) -> None: ... def store_cex_input(self, enable: bool = ...) -> None: ... def store_cex_output(self, enable: bool = ...) -> None: ... - def __repr__(self) -> str: ... class EquivalenceCriterion: __members__: ClassVar[dict[EquivalenceCriterion, int]] = ... # read-only @@ -159,7 +153,6 @@ class EquivalenceCriterion: def __index__(self) -> int: ... def __int__(self) -> int: ... def __ne__(self, other: object) -> bool: ... - def __repr__(self) -> str: ... def __setstate__(self, state: int) -> None: ... def __str__(self) -> EquivalenceCriterionName: ... @property @@ -181,7 +174,6 @@ class StateType: def __index__(self) -> int: ... def __int__(self) -> int: ... def __ne__(self, other: object) -> bool: ... - def __repr__(self) -> str: ... def __setstate__(self, state: int) -> None: ... def __str__(self) -> StateTypeName: ... @property diff --git a/mqt/qcec/types.py b/mqt/qcec/types.py index 2c030e77..0ff60201 100644 --- a/mqt/qcec/types.py +++ b/mqt/qcec/types.py @@ -1,4 +1,5 @@ """Types for the QCEC module.""" +from __future__ import annotations from typing import Literal diff --git a/mqt/qcec/verify.py b/mqt/qcec/verify.py index 8223d950..3b0ffacd 100644 --- a/mqt/qcec/verify.py +++ b/mqt/qcec/verify.py @@ -41,7 +41,6 @@ def verify( **kwargs: Keyword arguments to configure the equivalence checking process. Returns: - ------- The results of the equivalence checking process. """ if configuration is None: diff --git a/mqt/qcec/verify_compilation_flow.py b/mqt/qcec/verify_compilation_flow.py index 627dd6ac..2d5032fe 100644 --- a/mqt/qcec/verify_compilation_flow.py +++ b/mqt/qcec/verify_compilation_flow.py @@ -77,7 +77,6 @@ def verify_compilation( **kwargs: Keyword arguments to configure the equivalence checking process. Returns: - ------- The results of the equivalence checking process. """ if configuration is None: diff --git a/pyproject.toml b/pyproject.toml index 6dbb0655..1627626c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,8 +47,7 @@ test = ["pytest>=7.2"] coverage = ["mqt.qcec[test]", "pytest-cov[toml]"] docs = [ "sphinx>=5", - "sphinx-rtd-theme", - "sphinx-rtd-dark-mode", + "furo", "sphinxcontrib-bibtex>=2.4.2", "sphinx-copybutton", "sphinx-hoverxref", @@ -102,8 +101,8 @@ log_cli_level = "INFO" xfail_strict = true filterwarnings = [ "error", - # See https://github.com/Qiskit/rustworkx/pull/728 - 'ignore:RetworkxLoader.exec_module\(\) not found; falling back to load_module\(\):ImportWarning', + 'ignore:.*`product` is deprecated.*:DeprecationWarning:qiskit:', + 'ignore:.*qiskit.__qiskit_version__.*:DeprecationWarning:qiskit:', ] [tool.coverage.run] @@ -145,20 +144,25 @@ module = ["qiskit.*"] ignore_missing_imports = true [tool.ruff] +include = ["*.py", "*.pyi", "**/pyproject.toml", "*.ipynb"] select = [ "E", "F", "W", # flake8 "A", # flake8-builtins "ANN", # flake8-annotations "ARG", # flake8-unused-arguments + "ASYNC", # flake8-async "B", "B904", # flake8-bugbear "C4", # flake8-comprehensions "D", # pydocstyle "EM", # flake8-errmsg "EXE", # flake8-executable + "FA", # flake8-future-annotations "I", # isort "ICN", # flake8-import-conventions "ISC", # flake8-implicit-str-concat "N", # flake8-naming + "NPY", # numpy + "PERF", # perflint "PGH", # pygrep-hooks "PIE", # flake8-pie "PL", # pylint @@ -170,6 +174,7 @@ select = [ "RSE", # flake8-raise "RUF", # Ruff-specific "SLF", # flake8-self + "SLOT", # flake8-slots "SIM", # flake8-simplify "TCH", # flake8-type-checking "TID", # flake8-tidy-imports @@ -177,41 +182,22 @@ select = [ "UP", # pyupgrade "YTT", # flake8-2020 ] -ignore = [ +extend-ignore = [ "ANN101", # Missing type annotation for self in method "ANN102", # Missing type annotation for cls in classmethod "E501", # Line too long (Black is enough) - "PLR2004", # Magic values - "PLR0913", # Too many arguments -] - -# Exclude a variety of commonly ignored directories. -exclude = [ - ".bzr", - ".direnv", - ".eggs", - ".git", - ".hg", - ".mypy_cache", - ".nox", - ".pants.d", - ".ruff_cache", - ".svn", - ".tox", - ".venv", - "__pypackages__", - "_build", - "buck-out", - "build", - "dist", - "node_modules", - "venv", + "PLR", # Design related pylint codes ] - +flake8-unused-arguments.ignore-variadic-names = true +isort.required-imports = ["from __future__ import annotations"] line-length = 120 + [tool.ruff.per-file-ignores] -"*.pyi" = [ - "D", # pydocstyle +"*.pyi" = ["D"] # pydocstyle +"*.ipynb" = [ + "D", # pydocstyle + "E402", # Allow imports to appear anywhere in Jupyter notebooks + "I002", # Allow missing `from __future__ import annotations` import ] [tool.ruff.pydocstyle] diff --git a/setup.py b/setup.py index c41d6121..f27ba5a7 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,5 @@ """Setup script for the MQT QCEC package.""" +from __future__ import annotations import os import re @@ -49,6 +50,7 @@ def build_extension(self, ext: CMakeExtension) -> None: f"-DPYTHON_EXECUTABLE={sys.executable}", f"-DQCEC_VERSION_INFO={version}", f"-DCMAKE_BUILD_TYPE={cfg}", + "-DBUILD_MQT_CORE_TESTS=OFF", "-DBINDINGS=ON", ] build_args = [] @@ -58,9 +60,9 @@ def build_extension(self, ext: CMakeExtension) -> None: cmake_args += ["-GNinja"] else: # Single config generators are handled "normally" - single_config = any(x in cmake_generator for x in {"NMake", "Ninja"}) + single_config = any(x in cmake_generator for x in ("NMake", "Ninja")) # CMake allows an arch-in-generator style for backward compatibility - contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"}) + contains_arch = any(x in cmake_generator for x in ("ARM", "Win64")) # Convert distutils Windows platform specifiers to CMake -A arguments plat_to_cmake = { "win32": "Win32", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 62882d3d..da065308 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ # add MQT::qfr library -add_subdirectory("${PROJECT_SOURCE_DIR}/extern/qfr" "extern/qfr" +add_subdirectory("${PROJECT_SOURCE_DIR}/extern/mqt-core" "extern/mqt-core" EXCLUDE_FROM_ALL) add_library( @@ -24,7 +24,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include ${PROJECT_BINARY_DIR}/include) # link to the MQT::qfr libraries -target_link_libraries(${PROJECT_NAME} PUBLIC MQT::qfr_dd MQT::qfr_zx) +target_link_libraries(${PROJECT_NAME} PUBLIC MQT::CoreDD MQT::CoreZX) # add MQT alias add_library(MQT::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) diff --git a/src/EquivalenceCheckingManager.cpp b/src/EquivalenceCheckingManager.cpp index 1d073119..ef25e53e 100644 --- a/src/EquivalenceCheckingManager.cpp +++ b/src/EquivalenceCheckingManager.cpp @@ -6,7 +6,6 @@ #include "EquivalenceCheckingManager.hpp" #include "EquivalenceCriterion.hpp" -#include "Expression.hpp" #include "zx/FunctionalityConstruction.hpp" #include diff --git a/src/checker/dd/DDAlternatingChecker.cpp b/src/checker/dd/DDAlternatingChecker.cpp index f6c3afa9..c5699ac3 100644 --- a/src/checker/dd/DDAlternatingChecker.cpp +++ b/src/checker/dd/DDAlternatingChecker.cpp @@ -9,7 +9,7 @@ namespace ec { void DDAlternatingChecker::initialize() { DDEquivalenceChecker::initialize(); // create the full identity matrix - functionality = dd->makeIdent(static_cast(nqubits)); + functionality = dd->makeIdent(nqubits); dd->incRef(functionality); // Only count ancillaries that are present in but not acted upon in both of @@ -107,7 +107,7 @@ void DDAlternatingChecker::postprocess() { EquivalenceCriterion DDAlternatingChecker::checkEquivalence() { // create the full identity matrix - auto goalMatrix = dd->makeIdent(static_cast(nqubits)); + auto goalMatrix = dd->makeIdent(nqubits); dd->incRef(goalMatrix); // account for any garbage diff --git a/src/checker/dd/DDEquivalenceChecker.cpp b/src/checker/dd/DDEquivalenceChecker.cpp index 1f426ec4..7d3d1892 100644 --- a/src/checker/dd/DDEquivalenceChecker.cpp +++ b/src/checker/dd/DDEquivalenceChecker.cpp @@ -130,11 +130,11 @@ EquivalenceCriterion DDEquivalenceChecker::run() { // determine maximum number of nodes used if constexpr (std::is_same_v) { - maxActiveNodes = dd->mUniqueTable.getMaxActiveNodes(); + maxActiveNodes = dd->mUniqueTable.getStats().peakActiveEntryCount; } if constexpr (std::is_same_v) { - maxActiveNodes = dd->vUniqueTable.getMaxActiveNodes(); + maxActiveNodes = dd->vUniqueTable.getStats().peakActiveEntryCount; } const auto end = std::chrono::steady_clock::now(); diff --git a/src/checker/dd/DDSimulationChecker.cpp b/src/checker/dd/DDSimulationChecker.cpp index 1c9bd5d6..f1e8c3e0 100644 --- a/src/checker/dd/DDSimulationChecker.cpp +++ b/src/checker/dd/DDSimulationChecker.cpp @@ -10,7 +10,7 @@ DDSimulationChecker::DDSimulationChecker(const qc::QuantumComputation& circ1, const qc::QuantumComputation& circ2, Configuration config) : DDEquivalenceChecker(circ1, circ2, std::move(config)) { - initialState = dd->makeZeroState(static_cast(nqubits)); + initialState = dd->makeZeroState(nqubits); initializeApplicationScheme(configuration.application.simulationScheme); } @@ -31,12 +31,11 @@ EquivalenceCriterion DDSimulationChecker::checkEquivalence() { } void DDSimulationChecker::setRandomInitialState(StateGenerator& generator) { - const auto nancillary = - static_cast(nqubits - qc1.getNqubitsWithoutAncillae()); - const auto stateType = configuration.simulation.stateType; + const auto nancillary = nqubits - qc1.getNqubitsWithoutAncillae(); + const auto stateType = configuration.simulation.stateType; - initialState = generator.generateRandomState( - dd, static_cast(nqubits), nancillary, stateType); + initialState = + generator.generateRandomState(dd, nqubits, nancillary, stateType); } } // namespace ec diff --git a/src/checker/zx/ZXChecker.cpp b/src/checker/zx/ZXChecker.cpp index dac29e94..4fb0d8b6 100644 --- a/src/checker/zx/ZXChecker.cpp +++ b/src/checker/zx/ZXChecker.cpp @@ -7,10 +7,9 @@ #include "Definitions.hpp" #include "QuantumComputation.hpp" -#include "Simplify.hpp" -#include "ZXDiagram.hpp" -#include "dd/Definitions.hpp" #include "zx/FunctionalityConstruction.hpp" +#include "zx/Simplify.hpp" +#include "zx/ZXDiagram.hpp" #include #include diff --git a/test/python/test_compilation_flow_profiles.py b/test/python/test_compilation_flow_profiles.py index 8b16f108..a1109f0b 100644 --- a/test/python/test_compilation_flow_profiles.py +++ b/test/python/test_compilation_flow_profiles.py @@ -30,6 +30,14 @@ def ancilla_mode(request: Any) -> qcec.AncillaMode: # noqa: ANN401 return cast(qcec.AncillaMode, request.param) +def test_ancilla_mode_conversion(ancilla_mode: qcec.AncillaMode) -> None: + """Test conversion and equality of ancilla modes.""" + ancilla_str = str(ancilla_mode) + assert qcec.AncillaMode(ancilla_str) == ancilla_mode + assert ancilla_str == ancilla_mode + assert ancilla_mode == ancilla_str + + @pytest.mark.skipif( sys.version_info < (3, 11, 0) or sys.platform != "linux", reason="Since this check takes quite some time, it is only executed if the current platform is Linux and the Python version is 3.11 or higher.", @@ -40,7 +48,7 @@ def test_generated_profiles_are_still_valid(optimization_level: int, ancilla_mod The main intention of this check is to catch cases where an update in Qiskit changes the respective costs. """ # generate the profile - qcec.generate_profile(optimization_level=optimization_level, mode=ancilla_mode, filepath=Path(".")) + qcec.generate_profile(optimization_level=optimization_level, mode=ancilla_mode, filepath=Path()) # get path to the profile from the package resources profile_name = generate_profile_name(optimization_level=optimization_level, mode=ancilla_mode) diff --git a/test/python/test_verify.py b/test/python/test_verify.py index 9f43a2e3..fd80d221 100644 --- a/test/python/test_verify.py +++ b/test/python/test_verify.py @@ -92,15 +92,3 @@ def test_cpp_exception_propagation_internal() -> None: with pytest.raises(ValueError, match="Lookahead application scheme can only be used for matrices."): qcec.verify(qc, qc, configuration=config) - - -def test_cpp_exception_propagation_external() -> None: - """Test that C++ exceptions caused by code outside of QCEC are propagated correctly.""" - qc = QuantumCircuit(129) - qc.x(range(129)) - - config = qcec.Configuration() - config.execution.run_zx_checker = False - - with pytest.raises(ValueError, match="Requested too many qubits from package."): - qcec.verify(qc, qc, configuration=config) diff --git a/test/test_equality.cpp b/test/test_equality.cpp index bfa66bb4..28a82d1f 100644 --- a/test/test_equality.cpp +++ b/test/test_equality.cpp @@ -25,7 +25,7 @@ class EqualityTest : public testing::Test { } protected: - dd::QubitCount nqubits = 1U; + std::size_t nqubits = 1U; qc::QuantumComputation qc1; qc::QuantumComputation qc2; ec::Configuration config{}; @@ -179,16 +179,3 @@ TEST_F(EqualityTest, ExceptionInParallelThread) { ec::EquivalenceCheckingManager ecm(qc1, qc1, config); EXPECT_THROW(ecm.run(), std::invalid_argument); } - -TEST_F(EqualityTest, ExceptionInParallelThread2) { - qc1.addQubitRegister(128U); - for (auto i = 0U; i <= 128U; ++i) { - qc1.x(i); - } - - config = ec::Configuration{}; - config.execution.runZXChecker = false; - - ec::EquivalenceCheckingManager ecm(qc1, qc1, config); - EXPECT_THROW(ecm.run(), std::invalid_argument); -} diff --git a/test/test_gate_cost_application_scheme.cpp b/test/test_gate_cost_application_scheme.cpp index 7affa11f..31a2eae8 100644 --- a/test/test_gate_cost_application_scheme.cpp +++ b/test/test_gate_cost_application_scheme.cpp @@ -18,7 +18,7 @@ class GateCostApplicationSchemeTest : public testing::Test { } protected: - dd::QubitCount nqubits = 3U; + std::size_t nqubits = 3U; std::unique_ptr> dd; qc::QuantumComputation qc; }; diff --git a/test/test_zx.cpp b/test/test_zx.cpp index 2029147f..351860f5 100644 --- a/test/test_zx.cpp +++ b/test/test_zx.cpp @@ -6,7 +6,6 @@ #include "Definitions.hpp" #include "EquivalenceCheckingManager.hpp" #include "QuantumComputation.hpp" -#include "dd/Control.hpp" #include "gtest/gtest.h" #include @@ -108,7 +107,7 @@ TEST_F(ZXTest, CloseButNotEqual) { qcAlternative = qc::QuantumComputation(1); qcAlternative.x(0); - qcAlternative.phase(0, dd::PI / 1024.); + qcAlternative.phase(0, qc::PI / 1024.); config.functionality.traceThreshold = 1e-2; @@ -125,7 +124,7 @@ TEST_F(ZXTest, NotEqual) { qcAlternative = qc::QuantumComputation(1); qcAlternative.x(0); - qcAlternative.phase(0, dd::PI / 1024.); + qcAlternative.phase(0, qc::PI / 1024.); config.functionality.traceThreshold = 1e-9; From 8f183001de73c885c7c47498fa5a1a9608240cc6 Mon Sep 17 00:00:00 2001 From: Tianyi Wang Date: Tue, 8 Aug 2023 22:41:50 +0200 Subject: [PATCH 07/11] Modify .gitmodules --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index b40a6f71..c7e6602f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "extern/mqt-core"] path = extern/mqt-core url = https://github.com/cda-tum/mqt-core.git - branch = main + branch = mem-opt-qfr-tw From 79a704f1540356b1a079d060258694ba24c67061 Mon Sep 17 00:00:00 2001 From: Tianyi Wang Date: Tue, 8 Aug 2023 22:45:28 +0200 Subject: [PATCH 08/11] Update mqt-core --- extern/mqt-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/mqt-core b/extern/mqt-core index a50af79e..21706673 160000 --- a/extern/mqt-core +++ b/extern/mqt-core @@ -1 +1 @@ -Subproject commit a50af79e85c18993342a55b4eaea7a18eff49fdf +Subproject commit 217066738aaa7845473fa9f353a006eddbd33f5e From f520f6a4cbcc810b6ce5309e5c4a9049a95bc8b4 Mon Sep 17 00:00:00 2001 From: Tianyi Wang Date: Wed, 9 Aug 2023 12:33:03 +0200 Subject: [PATCH 09/11] Rebase mqt-core with implemented wstate --- extern/mqt-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/mqt-core b/extern/mqt-core index 21706673..3ea94709 160000 --- a/extern/mqt-core +++ b/extern/mqt-core @@ -1 +1 @@ -Subproject commit 217066738aaa7845473fa9f353a006eddbd33f5e +Subproject commit 3ea94709c1f2d38301db2faa2372a3dabaee86ff From 84684965456afdf5f89c599b053bf313aaf328ea Mon Sep 17 00:00:00 2001 From: Tianyi Wang Date: Sat, 14 Oct 2023 16:17:25 +0200 Subject: [PATCH 10/11] mqt rebase --- extern/mqt-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/mqt-core b/extern/mqt-core index c6eb0673..09f7d3d2 160000 --- a/extern/mqt-core +++ b/extern/mqt-core @@ -1 +1 @@ -Subproject commit c6eb0673bd7e9aa5a1297bd81925e9e7a50aed3f +Subproject commit 09f7d3d26ae3c767dcd06d8dde1e9ae36b1b6752 From e6a74a55c928295eacf0c02932ecf5506f34d5cf Mon Sep 17 00:00:00 2001 From: Tianyi Wang Date: Sat, 14 Oct 2023 17:22:52 +0200 Subject: [PATCH 11/11] mqt rebase --- extern/mqt-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/mqt-core b/extern/mqt-core index 09f7d3d2..2cd9ecfd 160000 --- a/extern/mqt-core +++ b/extern/mqt-core @@ -1 +1 @@ -Subproject commit 09f7d3d26ae3c767dcd06d8dde1e9ae36b1b6752 +Subproject commit 2cd9ecfdd02ed9755995497395e5ed5a8cc97dfd