diff --git a/.github/workflows/reusable-code-ql-python.yml b/.github/workflows/reusable-code-ql-python.yml index 51dd641a6..2a6652c3e 100644 --- a/.github/workflows/reusable-code-ql-python.yml +++ b/.github/workflows/reusable-code-ql-python.yml @@ -10,10 +10,6 @@ on: description: "The version of Z3 to set up" default: "4.11.2" type: string - build-time-dependencies: - description: "The build-time dependencies to install" - default: "scikit-build-core[pyproject] setuptools_scm pybind11" - type: string jobs: analyze: @@ -43,22 +39,10 @@ jobs: override_cache_key: codeql-python - name: Set up mold as linker uses: rui314/setup-mold@v1 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - cache: "pip" - - name: Install dependencies - run: | - python -m pip install --upgrade pip wheel setuptools - pip install ${{ inputs.build-time-dependencies }} - pip install --no-build-isolation -ve . - echo "CODEQL_PYTHON=$(which python)" >> $GITHUB_ENV - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: python - setup-python-dependencies: false config: | queries: - uses: security-and-quality diff --git a/.github/workflows/reusable-code-ql.yml b/.github/workflows/reusable-code-ql.yml index 8cd6b6555..8b488f477 100644 --- a/.github/workflows/reusable-code-ql.yml +++ b/.github/workflows/reusable-code-ql.yml @@ -15,10 +15,6 @@ on: description: "The version of Z3 to set up" default: "4.11.2" type: string - build-time-dependencies: - description: "The build-time dependencies to install" - default: "scikit-build-core[pyproject] setuptools_scm pybind11" - type: string enable-cpp: description: "Whether to enable C++ analysis" default: true @@ -45,4 +41,3 @@ jobs: with: setup-z3: ${{ inputs.setup-z3 }} z3-version: ${{ inputs.z3-version }} - build-time-dependencies: ${{ inputs.build-time-dependencies }} diff --git a/.github/workflows/reusable-cpp-coverage.yml b/.github/workflows/reusable-cpp-coverage.yml index e73b15bac..e7b13d098 100644 --- a/.github/workflows/reusable-cpp-coverage.yml +++ b/.github/workflows/reusable-cpp-coverage.yml @@ -31,6 +31,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive + fetch-depth: 0 - if: ${{ inputs.setup-z3 }} name: Setup Z3 uses: cda-tum/setup-z3@v1 diff --git a/.github/workflows/reusable-cpp-tests-macos.yml b/.github/workflows/reusable-cpp-tests-macos.yml index 215769c91..55ebefe14 100644 --- a/.github/workflows/reusable-cpp-tests-macos.yml +++ b/.github/workflows/reusable-cpp-tests-macos.yml @@ -31,6 +31,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive + fetch-depth: 0 - if: ${{ inputs.setup-z3 }} name: Setup Z3 uses: cda-tum/setup-z3@v1 diff --git a/.github/workflows/reusable-cpp-tests-ubuntu.yml b/.github/workflows/reusable-cpp-tests-ubuntu.yml index 6ca637570..5360226f0 100644 --- a/.github/workflows/reusable-cpp-tests-ubuntu.yml +++ b/.github/workflows/reusable-cpp-tests-ubuntu.yml @@ -31,6 +31,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive + fetch-depth: 0 - if: ${{ inputs.setup-z3 }} name: Setup Z3 uses: cda-tum/setup-z3@v1 diff --git a/.github/workflows/reusable-cpp-tests-windows.yml b/.github/workflows/reusable-cpp-tests-windows.yml index 2cba2106c..6453437bc 100644 --- a/.github/workflows/reusable-cpp-tests-windows.yml +++ b/.github/workflows/reusable-cpp-tests-windows.yml @@ -35,6 +35,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive + fetch-depth: 0 - uses: ilammy/msvc-dev-cmd@v1 - if: ${{ inputs.setup-z3 }} name: Setup Z3 diff --git a/.github/workflows/reusable-python-ci.yml b/.github/workflows/reusable-python-ci.yml index 721c1e486..fcbb96c62 100644 --- a/.github/workflows/reusable-python-ci.yml +++ b/.github/workflows/reusable-python-ci.yml @@ -29,7 +29,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] uses: ./.github/workflows/reusable-python-tests.yml with: runs-on: ubuntu-latest @@ -42,7 +42,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.11"] + python-version: ["3.8", "3.12"] uses: ./.github/workflows/reusable-python-tests.yml with: runs-on: macos-latest @@ -55,7 +55,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.11"] + python-version: ["3.8", "3.12"] uses: ./.github/workflows/reusable-python-tests.yml with: runs-on: windows-latest @@ -68,7 +68,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.11"] + python-version: ["3.8", "3.12"] uses: ./.github/workflows/reusable-python-coverage.yml with: python-version: ${{ matrix.python-version }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1568ac4f3..a1edb05cb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -92,6 +92,8 @@ repos: hooks: - id: cmake-format additional_dependencies: [pyyaml] + types: [file] + files: (\.cmake|CMakeLists.txt)(.in)?$ # Format configuration files with prettier - repo: https://github.com/pre-commit/mirrors-prettier diff --git a/CMakeLists.txt b/CMakeLists.txt index a594c34c5..1a4c17202 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ include(cmake/StandardProjectSettings.cmake) include(cmake/PreventInSourceBuilds.cmake) include(cmake/PackageAddTest.cmake) include(cmake/Cache.cmake) +include(cmake/Python.cmake) option(BUILD_MQT_CORE_BINDINGS "Build the MQT Core Python bindings" OFF) if(BUILD_MQT_CORE_BINDINGS) @@ -19,24 +20,9 @@ if(BUILD_MQT_CORE_BINDINGS) set(BINDINGS ON CACHE INTERNAL "Enable settings related to Python bindings") - - # top-level call to find Python - find_package( - Python 3.8 REQUIRED - COMPONENTS Interpreter Development.Module - OPTIONAL_COMPONENTS Development.SABIModule) + find_python() endif() -# try to determine the version from either git or the Python package -include(cmake/GetVersion.cmake) -get_version() - -project( - mqt-core - LANGUAGES CXX - VERSION ${MQT_CORE_VERSION} - DESCRIPTION "MQT Core - The Backbone of the Munich Quantum Toolkit") - # check if this is the master project or used via add_subdirectory if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(MQT_CORE_MASTER_PROJECT ON) @@ -48,10 +34,20 @@ option(MQT_CORE_INSTALL "Generate installation instructions for MQT Core" ${MQT_CORE_MASTER_PROJECT}) option(BUILD_MQT_CORE_TESTS "Also build tests for the MQT Core project" ${MQT_CORE_MASTER_PROJECT}) +# try to determine the project version +include(cmake/GetVersion.cmake) +get_mqt_core_version() + +project( + mqt-core + LANGUAGES CXX + VERSION ${MQT_CORE_VERSION} + DESCRIPTION "MQT Core - The Backbone of the Munich Quantum Toolkit") + include(cmake/ExternalDependencies.cmake) # set the include directory for the build tree -set(MQT_CORE_INCLUDE_BUILD_DIR "${PROJECT_SOURCE_DIR}/include") +set(MQT_CORE_INCLUDE_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/mqt-core") # add main library code add_subdirectory(src) @@ -68,7 +64,12 @@ if(BUILD_MQT_CORE_BENCHMARKS) add_subdirectory(eval) endif() -if(NOT MQT_CORE_MASTER_PROJECT) +if(MQT_CORE_MASTER_PROJECT) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake IMMEDIATE @ONLY) + add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) +else() set(mqt-core_FOUND TRUE CACHE INTERNAL "True if mqt-core is found on the system") diff --git a/cmake/CompilerOptions.cmake b/cmake/CompilerOptions.cmake index 49b0778d8..47630ecd2 100644 --- a/cmake/CompilerOptions.cmake +++ b/cmake/CompilerOptions.cmake @@ -41,8 +41,9 @@ function(enable_project_options target_name) endif() # enable some more optimizations in release mode - target_compile_options(${target_name} INTERFACE $<$:-fno-math-errno - -ffinite-math-only -fno-trapping-math>) + target_compile_options( + ${target_name} INTERFACE $<$:-fno-math-errno -ffinite-math-only + -fno-trapping-math -fno-stack-protector>) # enable some more options for better debugging target_compile_options( diff --git a/cmake/ExternalDependencies.cmake b/cmake/ExternalDependencies.cmake index d03cf128b..c5e65d95d 100644 --- a/cmake/ExternalDependencies.cmake +++ b/cmake/ExternalDependencies.cmake @@ -1,121 +1,76 @@ # Declare all external dependencies and make sure that they are available. include(FetchContent) +include(CMakeDependentOption) set(FETCH_PACKAGES "") -# A macro to declare a dependency that takes into account the different CMake versions and the -# features that they make available. In particular: - CMake 3.24 introduced the `FIND_PACKAGE_ARGS` -# option to `FetchContent` which allows to combine `FetchContent_Declare` and `find_package` in a -# single call. - CMake 3.25 introduced the `SYSTEM` option to `FetchContent_Declare` which marks the -# dependency as a system dependency. This is useful to avoid compiler warnings from external header -# only libraries. - CMake 3.28 introduced the `EXCLUDE_FROM_ALL` option to `FetchContent_Declare` -# which allows to exclude all targets from the dependency from the `all` target. -macro(DECLARE_DEPENDENCY) - cmake_parse_arguments(DEPENDENCY "SYSTEM;EXCLUDE_FROM_ALL" "NAME;URL;MD5;MIN_VERSION;ALT_NAME" "" - ${ARGN}) - set(ADDITIONAL_OPTIONS "") - if(DEPENDENCY_SYSTEM AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.25) - list(APPEND ADDITIONAL_OPTIONS SYSTEM) - endif() - if(DEPENDENCY_EXCLUDE_FROM_ALL AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.28) - list(APPEND ADDITIONAL_OPTIONS EXCLUDE_FROM_ALL) +set(JSON_VERSION + 3.11.3 + CACHE STRING "nlohmann_json version") +set(JSON_URL https://github.com/nlohmann/json/releases/download/v${JSON_VERSION}/json.tar.xz) +set(JSON_SystemInclude + ON + CACHE INTERNAL "Treat the library headers like system headers") +cmake_dependent_option(JSON_Install "Install nlohmann_json library" ON "MQT_CORE_INSTALL" OFF) +if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24) + FetchContent_Declare(nlohmann_json URL ${JSON_URL} FIND_PACKAGE_ARGS ${JSON_VERSION}) + list(APPEND FETCH_PACKAGES nlohmann_json) +else() + find_package(nlohmann_json ${JSON_VERSION} QUIET) + if(NOT nlohmann_json_FOUND) + FetchContent_Declare(nlohmann_json URL ${JSON_URL}) + list(APPEND FETCH_PACKAGES nlohmann_json) endif() - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.28) - FetchContent_Declare( - ${DEPENDENCY_NAME} - URL ${DEPENDENCY_URL} - URL_MD5 ${DEPENDENCY_MD5} - ${ADDITIONAL_OPTIONS} FIND_PACKAGE_ARGS ${DEPENDENCY_MIN_VERSION} NAMES - ${DEPENDENCY_ALT_NAME}) - list(APPEND FETCH_PACKAGES ${DEPENDENCY_NAME}) - elseif(CMAKE_VERSION VERSION_GREATER_EQUAL 3.25) - FetchContent_Declare( - ${DEPENDENCY_NAME} - URL ${DEPENDENCY_URL} - URL_MD5 ${DEPENDENCY_MD5} - ${ADDITIONAL_OPTIONS} FIND_PACKAGE_ARGS ${DEPENDENCY_MIN_VERSION} NAMES - ${DEPENDENCY_ALT_NAME}) - list(APPEND FETCH_PACKAGES ${DEPENDENCY_NAME}) - elseif(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24) - FetchContent_Declare( - ${DEPENDENCY_NAME} - URL ${DEPENDENCY_URL} - URL_MD5 ${DEPENDENCY_MD5} - ${ADDITIONAL_OPTIONS} FIND_PACKAGE_ARGS ${DEPENDENCY_MIN_VERSION} NAMES - ${DEPENDENCY_ALT_NAME}) - list(APPEND FETCH_PACKAGES ${DEPENDENCY_NAME}) +endif() + +option(USE_SYSTEM_BOOST "Whether to try to use the system Boost installation" ON) +set(BOOST_MIN_VERSION + 1.80.0 + CACHE STRING "Minimum required Boost version") +find_package(Boost ${BOOST_MIN_VERSION} CONFIG QUIET) +if(NOT Boost_FOUND OR NOT USE_SYSTEM_BOOST) + set(BOOST_MP_STANDALONE + ON + CACHE INTERNAL "Use standalone boost multiprecision") + set(BOOST_VERSION + 1_84_0 + CACHE INTERNAL "Boost version") + set(BOOST_URL + https://github.com/boostorg/multiprecision/archive/refs/tags/Boost_${BOOST_VERSION}.tar.gz) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24) + FetchContent_Declare(boost_multiprecision URL ${BOOST_URL} FIND_PACKAGE_ARGS + ${BOOST_MIN_VERSION} CONFIG) + list(APPEND FETCH_PACKAGES boost_multiprecision) else() - # try to get the system installed version - find_package(${DEPENDENCY_NAME} ${DEPENDENCY_MIN_VERSION} QUIET NAMES ${DEPENDENCY_ALT_NAME}) - if(NOT ${DEPENDENCY_NAME}_FOUND) - FetchContent_Declare( - ${DEPENDENCY_NAME} - URL ${DEPENDENCY_URL} - URL_MD5 ${DEPENDENCY_MD5}) - list(APPEND FETCH_PACKAGES ${DEPENDENCY_NAME}) + find_package(boost_multiprecision ${BOOST_MIN_VERSION} QUIET CONFIG) + if(NOT boost_multiprecision_FOUND) + FetchContent_Declare(boost_multiprecision URL ${BOOST_URL}) + list(APPEND FETCH_PACKAGES boost_multiprecision) endif() endif() -endmacro() - -set(JSON_BuildTests - OFF - CACHE INTERNAL "") -set(JSON_MultipleHeaders - OFF - CACHE INTERNAL "") -if(MQT_CORE_INSTALL) - set(JSON_Install - ON - CACHE INTERNAL "") endif() -declare_dependency( - NAME - nlohmann_json - URL - https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz - MD5 - c23a33f04786d85c29fda8d16b5f0efd - MIN_VERSION - 3.11.3 - SYSTEM) - -set(BOOST_MP_STANDALONE - ON - CACHE INTERNAL "Use standalone boost multiprecision") -declare_dependency( - NAME - boost_multiprecision - URL - https://github.com/boostorg/multiprecision/archive/refs/tags/Boost_1_84_0.tar.gz - MD5 - b829378c90f4b268c79a796025c43eee - MIN_VERSION - 1.80.0 - ALT_NAME - Boost - SYSTEM - EXCLUDE_FROM_ALL) if(BUILD_MQT_CORE_TESTS) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - declare_dependency( - NAME - googletest - URL - https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz - MD5 - c8340a482851ef6a3fe618a082304cfc - MIN_VERSION - 1.14.0 - ALT_NAME - GTest - SYSTEM - EXCLUDE_FROM_ALL) + set(GTEST_VERSION + 1.14.0 + CACHE STRING "Google Test version") + set(GTEST_URL https://github.com/google/googletest/archive/refs/tags/v${GTEST_VERSION}.tar.gz) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24) + FetchContent_Declare(googletest URL ${GTEST_URL} FIND_PACKAGE_ARGS ${GTEST_VERSION} NAMES GTest) + list(APPEND FETCH_PACKAGES googletest) + else() + find_package(googletest ${GTEST_VERSION} QUIET NAMES GTest) + if(NOT googletest_FOUND) + FetchContent_Declare(googletest URL ${GTEST_URL}) + list(APPEND FETCH_PACKAGES googletest) + endif() + endif() endif() -if(BINDINGS) +if(BUILD_MQT_CORE_BINDINGS) if(NOT SKBUILD) # Manually detect the installed pybind11 package and import it into CMake. execute_process( @@ -127,17 +82,6 @@ if(BINDINGS) # add pybind11 library find_package(pybind11 CONFIG REQUIRED) - - declare_dependency( - NAME - pybind11_json - URL - https://github.com/pybind/pybind11_json/archive/refs/tags/0.2.13.tar.gz - MD5 - 93ebbea2bb69f71febe0f83c8f88ced2 - MIN_VERSION - 0.2.13 - SYSTEM) endif() # Make all declared dependencies available. diff --git a/cmake/GetVersion.cmake b/cmake/GetVersion.cmake index be62276d7..3a4d0c47d 100644 --- a/cmake/GetVersion.cmake +++ b/cmake/GetVersion.cmake @@ -11,6 +11,12 @@ # * MQT_CORE_VERSION_FOUND (TRUE if version was found, FALSE otherwise) function(version_from_skbuild) + if(NOT MQT_CORE_MASTER_PROJECT) + message(VERBOSE + "Not the master project. Cannot determine project version from scikit-build-core.") + return() + endif() + if(NOT DEFINED SKBUILD_PROJECT_VERSION) message( VERBOSE @@ -150,7 +156,7 @@ function(version_from_package) OUTPUT_VARIABLE MQT_CORE_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) - if(${MQT_CORE_VERSION_STRING} STREQUAL "") + if("${MQT_CORE_VERSION_STRING}" STREQUAL "") message( VERBOSE "Python package version not found. Cannot determine project version from Python package.") @@ -185,19 +191,21 @@ function(version_from_package) CACHE INTERNAL "MQT_CORE_VERSION_FOUND") endfunction() -function(get_version) +function(get_mqt_core_version) # Initialize as not found set(MQT_CORE_VERSION_FOUND FALSE CACHE INTERNAL "MQT_CORE_VERSION_FOUND") - version_from_skbuild() - if(MQT_CORE_VERSION_FOUND) - message( - STATUS - "Found project version ${MQT_CORE_VERSION} from scikit-build-core (full version: ${MQT_CORE_VERSION_STRING})" - ) - return() + if(MQT_CORE_MASTER_PROJECT) + version_from_skbuild() + if(MQT_CORE_VERSION_FOUND) + message( + STATUS + "Found project version ${MQT_CORE_VERSION} from scikit-build-core (full version: ${MQT_CORE_VERSION_STRING})" + ) + return() + endif() endif() version_from_git() diff --git a/cmake/PackageAddTest.cmake b/cmake/PackageAddTest.cmake index 492ffcc51..3423dda20 100644 --- a/cmake/PackageAddTest.cmake +++ b/cmake/PackageAddTest.cmake @@ -4,7 +4,8 @@ macro(PACKAGE_ADD_TEST testname linklibs) # create an executable in which the tests will be stored add_executable(${testname} ${ARGN}) # link the Google test infrastructure and a default main function to the test executable. - target_link_libraries(${testname} PRIVATE ${linklibs} gmock gtest_main) + target_link_libraries(${testname} PRIVATE ${linklibs} gmock gtest_main MQT::ProjectOptions + MQT::ProjectWarnings) # discover tests gtest_discover_tests( ${testname} diff --git a/cmake/Python.cmake b/cmake/Python.cmake new file mode 100644 index 000000000..f240896b1 --- /dev/null +++ b/cmake/Python.cmake @@ -0,0 +1,19 @@ +# a function that sets up some cache variables and tries to find Python +function(find_python) + # Some common settings for finding Python + set(Python_FIND_VIRTUALENV + FIRST + CACHE STRING "Give precedence to virtualenvs when searching for Python") + set(Python_FIND_FRAMEWORK + LAST + CACHE STRING "Prefer Brew/Conda to Apple framework Python") + set(Python_ARTIFACTS_INTERACTIVE + ON + CACHE BOOL "Prevent multiple searches for Python and instead cache the results.") + + # top-level call to find Python + find_package( + Python 3.8 REQUIRED + COMPONENTS Interpreter Development.Module + OPTIONAL_COMPONENTS Development.SABIModule) +endfunction() diff --git a/cmake/StandardProjectSettings.cmake b/cmake/StandardProjectSettings.cmake index bad106663..e7bdf1f47 100644 --- a/cmake/StandardProjectSettings.cmake +++ b/cmake/StandardProjectSettings.cmake @@ -63,11 +63,3 @@ if(DEPLOY) "10.15" CACHE STRING "" FORCE) endif() - -# Some common settings for finding Python -set(Python_FIND_VIRTUALENV - FIRST - CACHE STRING "Give precedence to virtualenvs when searching for Python") -set(Python_ARTIFACTS_INTERACTIVE - ON - CACHE BOOL "Prevent multiple searches for Python and instead cache the results.") diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in new file mode 100644 index 000000000..1e5d2bb87 --- /dev/null +++ b/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,23 @@ +# Source: https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake + +if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") +endif() + +file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS + "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif() + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif() +endforeach() diff --git a/cmake/mqt-core-config.cmake.in b/cmake/mqt-core-config.cmake.in index b8801d93d..55575a49c 100644 --- a/cmake/mqt-core-config.cmake.in +++ b/cmake/mqt-core-config.cmake.in @@ -2,13 +2,22 @@ @PACKAGE_INIT@ -check_required_components(mqt-core) - list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") include(CMakeFindDependencyMacro) -find_dependency(GMP) -find_dependency(pybind11_json) +find_dependency(nlohmann_json) +option(MQT_CORE_ZX_WITH_GMP "Library is configured to use GMP for ZX calculations" + @MQT_CORE_ZX_WITH_GMP@) +if(MQT_CORE_ZX_WITH_GMP) + find_dependency(GMP) +endif() + +option(MQT_CORE_ZX_SYSTEM_BOOST + "Library is configured to use system Boost instead of the bundled Boost::multiprecision" + @MQT_CORE_ZX_SYSTEM_BOOST@) +if(MQT_CORE_ZX_SYSTEM_BOOST) + find_dependency(Boost @BOOST_MIN_VERSION@) +endif() if(TARGET MQT::Core) return() @@ -17,7 +26,6 @@ endif() include("${CMAKE_CURRENT_LIST_DIR}/Cache.cmake") include("${CMAKE_CURRENT_LIST_DIR}/CompilerOptions.cmake") include("${CMAKE_CURRENT_LIST_DIR}/CompilerWarnings.cmake") -include("${CMAKE_CURRENT_LIST_DIR}/GetVersion.cmake") include("${CMAKE_CURRENT_LIST_DIR}/PackageAddTest.cmake") include("${CMAKE_CURRENT_LIST_DIR}/PreventInSourceBuilds.cmake") include("${CMAKE_CURRENT_LIST_DIR}/Sanitizers.cmake") diff --git a/include/CircuitOptimizer.hpp b/include/mqt-core/CircuitOptimizer.hpp similarity index 100% rename from include/CircuitOptimizer.hpp rename to include/mqt-core/CircuitOptimizer.hpp diff --git a/include/Definitions.hpp b/include/mqt-core/Definitions.hpp similarity index 100% rename from include/Definitions.hpp rename to include/mqt-core/Definitions.hpp diff --git a/include/Permutation.hpp b/include/mqt-core/Permutation.hpp similarity index 100% rename from include/Permutation.hpp rename to include/mqt-core/Permutation.hpp diff --git a/include/QuantumComputation.hpp b/include/mqt-core/QuantumComputation.hpp similarity index 100% rename from include/QuantumComputation.hpp rename to include/mqt-core/QuantumComputation.hpp diff --git a/include/algorithms/BernsteinVazirani.hpp b/include/mqt-core/algorithms/BernsteinVazirani.hpp similarity index 96% rename from include/algorithms/BernsteinVazirani.hpp rename to include/mqt-core/algorithms/BernsteinVazirani.hpp index 2e31c175d..4ccc4c54c 100644 --- a/include/algorithms/BernsteinVazirani.hpp +++ b/include/mqt-core/algorithms/BernsteinVazirani.hpp @@ -1,24 +1,24 @@ -#pragma once - -#include -#include - -namespace qc { -class BernsteinVazirani : public QuantumComputation { -public: - BitString s = 0; - std::size_t bitwidth = 1; - bool dynamic = false; - std::string expected{}; - - explicit BernsteinVazirani(const BitString& hiddenString, bool dyn = false); - explicit BernsteinVazirani(std::size_t nq, bool dyn = false); - BernsteinVazirani(const BitString& hiddenString, std::size_t nq, - bool dyn = false); - - std::ostream& printStatistics(std::ostream& os) const override; - -protected: - void createCircuit(); -}; -} // namespace qc +#pragma once + +#include +#include + +namespace qc { +class BernsteinVazirani : public QuantumComputation { +public: + BitString s = 0; + std::size_t bitwidth = 1; + bool dynamic = false; + std::string expected{}; + + explicit BernsteinVazirani(const BitString& hiddenString, bool dyn = false); + explicit BernsteinVazirani(std::size_t nq, bool dyn = false); + BernsteinVazirani(const BitString& hiddenString, std::size_t nq, + bool dyn = false); + + std::ostream& printStatistics(std::ostream& os) const override; + +protected: + void createCircuit(); +}; +} // namespace qc diff --git a/include/algorithms/Entanglement.hpp b/include/mqt-core/algorithms/Entanglement.hpp similarity index 100% rename from include/algorithms/Entanglement.hpp rename to include/mqt-core/algorithms/Entanglement.hpp diff --git a/include/algorithms/GoogleRandomCircuitSampling.hpp b/include/mqt-core/algorithms/GoogleRandomCircuitSampling.hpp similarity index 100% rename from include/algorithms/GoogleRandomCircuitSampling.hpp rename to include/mqt-core/algorithms/GoogleRandomCircuitSampling.hpp diff --git a/include/algorithms/Grover.hpp b/include/mqt-core/algorithms/Grover.hpp similarity index 100% rename from include/algorithms/Grover.hpp rename to include/mqt-core/algorithms/Grover.hpp diff --git a/include/algorithms/QFT.hpp b/include/mqt-core/algorithms/QFT.hpp similarity index 100% rename from include/algorithms/QFT.hpp rename to include/mqt-core/algorithms/QFT.hpp diff --git a/include/algorithms/QPE.hpp b/include/mqt-core/algorithms/QPE.hpp similarity index 100% rename from include/algorithms/QPE.hpp rename to include/mqt-core/algorithms/QPE.hpp diff --git a/include/algorithms/RandomCliffordCircuit.hpp b/include/mqt-core/algorithms/RandomCliffordCircuit.hpp similarity index 100% rename from include/algorithms/RandomCliffordCircuit.hpp rename to include/mqt-core/algorithms/RandomCliffordCircuit.hpp diff --git a/include/algorithms/WState.hpp b/include/mqt-core/algorithms/WState.hpp similarity index 100% rename from include/algorithms/WState.hpp rename to include/mqt-core/algorithms/WState.hpp diff --git a/include/dd/Benchmark.hpp b/include/mqt-core/dd/Benchmark.hpp similarity index 100% rename from include/dd/Benchmark.hpp rename to include/mqt-core/dd/Benchmark.hpp diff --git a/include/dd/CachedEdge.hpp b/include/mqt-core/dd/CachedEdge.hpp similarity index 100% rename from include/dd/CachedEdge.hpp rename to include/mqt-core/dd/CachedEdge.hpp diff --git a/include/dd/Complex.hpp b/include/mqt-core/dd/Complex.hpp similarity index 100% rename from include/dd/Complex.hpp rename to include/mqt-core/dd/Complex.hpp diff --git a/include/dd/ComplexNumbers.hpp b/include/mqt-core/dd/ComplexNumbers.hpp similarity index 100% rename from include/dd/ComplexNumbers.hpp rename to include/mqt-core/dd/ComplexNumbers.hpp diff --git a/include/dd/ComplexValue.hpp b/include/mqt-core/dd/ComplexValue.hpp similarity index 100% rename from include/dd/ComplexValue.hpp rename to include/mqt-core/dd/ComplexValue.hpp diff --git a/include/dd/ComputeTable.hpp b/include/mqt-core/dd/ComputeTable.hpp similarity index 100% rename from include/dd/ComputeTable.hpp rename to include/mqt-core/dd/ComputeTable.hpp diff --git a/include/dd/DDDefinitions.hpp b/include/mqt-core/dd/DDDefinitions.hpp similarity index 100% rename from include/dd/DDDefinitions.hpp rename to include/mqt-core/dd/DDDefinitions.hpp diff --git a/include/dd/DDpackageConfig.hpp b/include/mqt-core/dd/DDpackageConfig.hpp similarity index 100% rename from include/dd/DDpackageConfig.hpp rename to include/mqt-core/dd/DDpackageConfig.hpp diff --git a/include/dd/DensityNoiseTable.hpp b/include/mqt-core/dd/DensityNoiseTable.hpp similarity index 100% rename from include/dd/DensityNoiseTable.hpp rename to include/mqt-core/dd/DensityNoiseTable.hpp diff --git a/include/dd/Edge.hpp b/include/mqt-core/dd/Edge.hpp similarity index 100% rename from include/dd/Edge.hpp rename to include/mqt-core/dd/Edge.hpp diff --git a/include/dd/Export.hpp b/include/mqt-core/dd/Export.hpp similarity index 100% rename from include/dd/Export.hpp rename to include/mqt-core/dd/Export.hpp diff --git a/include/dd/FunctionalityConstruction.hpp b/include/mqt-core/dd/FunctionalityConstruction.hpp similarity index 100% rename from include/dd/FunctionalityConstruction.hpp rename to include/mqt-core/dd/FunctionalityConstruction.hpp diff --git a/include/dd/GateMatrixDefinitions.hpp b/include/mqt-core/dd/GateMatrixDefinitions.hpp similarity index 100% rename from include/dd/GateMatrixDefinitions.hpp rename to include/mqt-core/dd/GateMatrixDefinitions.hpp diff --git a/include/dd/MemoryManager.hpp b/include/mqt-core/dd/MemoryManager.hpp similarity index 100% rename from include/dd/MemoryManager.hpp rename to include/mqt-core/dd/MemoryManager.hpp diff --git a/include/dd/Node.hpp b/include/mqt-core/dd/Node.hpp similarity index 100% rename from include/dd/Node.hpp rename to include/mqt-core/dd/Node.hpp diff --git a/include/dd/NoiseFunctionality.hpp b/include/mqt-core/dd/NoiseFunctionality.hpp similarity index 100% rename from include/dd/NoiseFunctionality.hpp rename to include/mqt-core/dd/NoiseFunctionality.hpp diff --git a/include/dd/Operations.hpp b/include/mqt-core/dd/Operations.hpp similarity index 100% rename from include/dd/Operations.hpp rename to include/mqt-core/dd/Operations.hpp diff --git a/include/dd/Package.hpp b/include/mqt-core/dd/Package.hpp similarity index 100% rename from include/dd/Package.hpp rename to include/mqt-core/dd/Package.hpp diff --git a/include/dd/Package_fwd.hpp b/include/mqt-core/dd/Package_fwd.hpp similarity index 100% rename from include/dd/Package_fwd.hpp rename to include/mqt-core/dd/Package_fwd.hpp diff --git a/include/dd/RealNumber.hpp b/include/mqt-core/dd/RealNumber.hpp similarity index 100% rename from include/dd/RealNumber.hpp rename to include/mqt-core/dd/RealNumber.hpp diff --git a/include/dd/RealNumberUniqueTable.hpp b/include/mqt-core/dd/RealNumberUniqueTable.hpp similarity index 100% rename from include/dd/RealNumberUniqueTable.hpp rename to include/mqt-core/dd/RealNumberUniqueTable.hpp diff --git a/include/dd/Simulation.hpp b/include/mqt-core/dd/Simulation.hpp similarity index 100% rename from include/dd/Simulation.hpp rename to include/mqt-core/dd/Simulation.hpp diff --git a/include/dd/StochasticNoiseOperationTable.hpp b/include/mqt-core/dd/StochasticNoiseOperationTable.hpp similarity index 100% rename from include/dd/StochasticNoiseOperationTable.hpp rename to include/mqt-core/dd/StochasticNoiseOperationTable.hpp diff --git a/include/dd/UnaryComputeTable.hpp b/include/mqt-core/dd/UnaryComputeTable.hpp similarity index 100% rename from include/dd/UnaryComputeTable.hpp rename to include/mqt-core/dd/UnaryComputeTable.hpp diff --git a/include/dd/UniqueTable.hpp b/include/mqt-core/dd/UniqueTable.hpp similarity index 100% rename from include/dd/UniqueTable.hpp rename to include/mqt-core/dd/UniqueTable.hpp diff --git a/include/dd/statistics/MemoryManagerStatistics.hpp b/include/mqt-core/dd/statistics/MemoryManagerStatistics.hpp similarity index 100% rename from include/dd/statistics/MemoryManagerStatistics.hpp rename to include/mqt-core/dd/statistics/MemoryManagerStatistics.hpp diff --git a/include/dd/statistics/PackageStatistics.hpp b/include/mqt-core/dd/statistics/PackageStatistics.hpp similarity index 100% rename from include/dd/statistics/PackageStatistics.hpp rename to include/mqt-core/dd/statistics/PackageStatistics.hpp diff --git a/include/dd/statistics/Statistics.hpp b/include/mqt-core/dd/statistics/Statistics.hpp similarity index 100% rename from include/dd/statistics/Statistics.hpp rename to include/mqt-core/dd/statistics/Statistics.hpp diff --git a/include/dd/statistics/TableStatistics.hpp b/include/mqt-core/dd/statistics/TableStatistics.hpp similarity index 100% rename from include/dd/statistics/TableStatistics.hpp rename to include/mqt-core/dd/statistics/TableStatistics.hpp diff --git a/include/dd/statistics/UniqueTableStatistics.hpp b/include/mqt-core/dd/statistics/UniqueTableStatistics.hpp similarity index 100% rename from include/dd/statistics/UniqueTableStatistics.hpp rename to include/mqt-core/dd/statistics/UniqueTableStatistics.hpp diff --git a/include/ecc/Ecc.hpp b/include/mqt-core/ecc/Ecc.hpp similarity index 100% rename from include/ecc/Ecc.hpp rename to include/mqt-core/ecc/Ecc.hpp diff --git a/include/ecc/Id.hpp b/include/mqt-core/ecc/Id.hpp similarity index 100% rename from include/ecc/Id.hpp rename to include/mqt-core/ecc/Id.hpp diff --git a/include/ecc/Q18Surface.hpp b/include/mqt-core/ecc/Q18Surface.hpp similarity index 100% rename from include/ecc/Q18Surface.hpp rename to include/mqt-core/ecc/Q18Surface.hpp diff --git a/include/ecc/Q3Shor.hpp b/include/mqt-core/ecc/Q3Shor.hpp similarity index 100% rename from include/ecc/Q3Shor.hpp rename to include/mqt-core/ecc/Q3Shor.hpp diff --git a/include/ecc/Q5Laflamme.hpp b/include/mqt-core/ecc/Q5Laflamme.hpp similarity index 100% rename from include/ecc/Q5Laflamme.hpp rename to include/mqt-core/ecc/Q5Laflamme.hpp diff --git a/include/ecc/Q7Steane.hpp b/include/mqt-core/ecc/Q7Steane.hpp similarity index 100% rename from include/ecc/Q7Steane.hpp rename to include/mqt-core/ecc/Q7Steane.hpp diff --git a/include/ecc/Q9Shor.hpp b/include/mqt-core/ecc/Q9Shor.hpp similarity index 100% rename from include/ecc/Q9Shor.hpp rename to include/mqt-core/ecc/Q9Shor.hpp diff --git a/include/ecc/Q9Surface.hpp b/include/mqt-core/ecc/Q9Surface.hpp similarity index 100% rename from include/ecc/Q9Surface.hpp rename to include/mqt-core/ecc/Q9Surface.hpp diff --git a/include/operations/ClassicControlledOperation.hpp b/include/mqt-core/operations/ClassicControlledOperation.hpp similarity index 100% rename from include/operations/ClassicControlledOperation.hpp rename to include/mqt-core/operations/ClassicControlledOperation.hpp diff --git a/include/operations/CompoundOperation.hpp b/include/mqt-core/operations/CompoundOperation.hpp similarity index 100% rename from include/operations/CompoundOperation.hpp rename to include/mqt-core/operations/CompoundOperation.hpp diff --git a/include/operations/Control.hpp b/include/mqt-core/operations/Control.hpp similarity index 100% rename from include/operations/Control.hpp rename to include/mqt-core/operations/Control.hpp diff --git a/include/operations/Expression.hpp b/include/mqt-core/operations/Expression.hpp similarity index 100% rename from include/operations/Expression.hpp rename to include/mqt-core/operations/Expression.hpp diff --git a/include/operations/NonUnitaryOperation.hpp b/include/mqt-core/operations/NonUnitaryOperation.hpp similarity index 100% rename from include/operations/NonUnitaryOperation.hpp rename to include/mqt-core/operations/NonUnitaryOperation.hpp diff --git a/include/operations/OpType.hpp b/include/mqt-core/operations/OpType.hpp similarity index 100% rename from include/operations/OpType.hpp rename to include/mqt-core/operations/OpType.hpp diff --git a/include/operations/Operation.hpp b/include/mqt-core/operations/Operation.hpp similarity index 100% rename from include/operations/Operation.hpp rename to include/mqt-core/operations/Operation.hpp diff --git a/include/operations/StandardOperation.hpp b/include/mqt-core/operations/StandardOperation.hpp similarity index 100% rename from include/operations/StandardOperation.hpp rename to include/mqt-core/operations/StandardOperation.hpp diff --git a/include/operations/SymbolicOperation.hpp b/include/mqt-core/operations/SymbolicOperation.hpp similarity index 100% rename from include/operations/SymbolicOperation.hpp rename to include/mqt-core/operations/SymbolicOperation.hpp diff --git a/include/parsers/qasm3_parser/Exception.hpp b/include/mqt-core/parsers/qasm3_parser/Exception.hpp similarity index 100% rename from include/parsers/qasm3_parser/Exception.hpp rename to include/mqt-core/parsers/qasm3_parser/Exception.hpp diff --git a/include/parsers/qasm3_parser/Gate.hpp b/include/mqt-core/parsers/qasm3_parser/Gate.hpp similarity index 100% rename from include/parsers/qasm3_parser/Gate.hpp rename to include/mqt-core/parsers/qasm3_parser/Gate.hpp diff --git a/include/parsers/qasm3_parser/InstVisitor.hpp b/include/mqt-core/parsers/qasm3_parser/InstVisitor.hpp similarity index 100% rename from include/parsers/qasm3_parser/InstVisitor.hpp rename to include/mqt-core/parsers/qasm3_parser/InstVisitor.hpp diff --git a/include/parsers/qasm3_parser/NestedEnvironment.hpp b/include/mqt-core/parsers/qasm3_parser/NestedEnvironment.hpp similarity index 100% rename from include/parsers/qasm3_parser/NestedEnvironment.hpp rename to include/mqt-core/parsers/qasm3_parser/NestedEnvironment.hpp diff --git a/include/parsers/qasm3_parser/Parser.hpp b/include/mqt-core/parsers/qasm3_parser/Parser.hpp similarity index 100% rename from include/parsers/qasm3_parser/Parser.hpp rename to include/mqt-core/parsers/qasm3_parser/Parser.hpp diff --git a/include/parsers/qasm3_parser/Scanner.hpp b/include/mqt-core/parsers/qasm3_parser/Scanner.hpp similarity index 100% rename from include/parsers/qasm3_parser/Scanner.hpp rename to include/mqt-core/parsers/qasm3_parser/Scanner.hpp diff --git a/include/parsers/qasm3_parser/Statement.hpp b/include/mqt-core/parsers/qasm3_parser/Statement.hpp similarity index 100% rename from include/parsers/qasm3_parser/Statement.hpp rename to include/mqt-core/parsers/qasm3_parser/Statement.hpp diff --git a/include/parsers/qasm3_parser/StdGates.hpp b/include/mqt-core/parsers/qasm3_parser/StdGates.hpp similarity index 100% rename from include/parsers/qasm3_parser/StdGates.hpp rename to include/mqt-core/parsers/qasm3_parser/StdGates.hpp diff --git a/include/parsers/qasm3_parser/Token.hpp b/include/mqt-core/parsers/qasm3_parser/Token.hpp similarity index 100% rename from include/parsers/qasm3_parser/Token.hpp rename to include/mqt-core/parsers/qasm3_parser/Token.hpp diff --git a/include/parsers/qasm3_parser/Types.hpp b/include/mqt-core/parsers/qasm3_parser/Types.hpp similarity index 100% rename from include/parsers/qasm3_parser/Types.hpp rename to include/mqt-core/parsers/qasm3_parser/Types.hpp diff --git a/include/parsers/qasm3_parser/passes/CompilerPass.hpp b/include/mqt-core/parsers/qasm3_parser/passes/CompilerPass.hpp similarity index 100% rename from include/parsers/qasm3_parser/passes/CompilerPass.hpp rename to include/mqt-core/parsers/qasm3_parser/passes/CompilerPass.hpp diff --git a/include/parsers/qasm3_parser/passes/ConstEvalPass.hpp b/include/mqt-core/parsers/qasm3_parser/passes/ConstEvalPass.hpp similarity index 100% rename from include/parsers/qasm3_parser/passes/ConstEvalPass.hpp rename to include/mqt-core/parsers/qasm3_parser/passes/ConstEvalPass.hpp diff --git a/include/parsers/qasm3_parser/passes/TypeCheckPass.hpp b/include/mqt-core/parsers/qasm3_parser/passes/TypeCheckPass.hpp similarity index 100% rename from include/parsers/qasm3_parser/passes/TypeCheckPass.hpp rename to include/mqt-core/parsers/qasm3_parser/passes/TypeCheckPass.hpp diff --git a/include/python/pybind11.hpp b/include/mqt-core/python/pybind11.hpp similarity index 100% rename from include/python/pybind11.hpp rename to include/mqt-core/python/pybind11.hpp diff --git a/include/zx/FunctionalityConstruction.hpp b/include/mqt-core/zx/FunctionalityConstruction.hpp similarity index 100% rename from include/zx/FunctionalityConstruction.hpp rename to include/mqt-core/zx/FunctionalityConstruction.hpp diff --git a/include/zx/Rational.hpp b/include/mqt-core/zx/Rational.hpp similarity index 100% rename from include/zx/Rational.hpp rename to include/mqt-core/zx/Rational.hpp diff --git a/include/zx/Rules.hpp b/include/mqt-core/zx/Rules.hpp similarity index 100% rename from include/zx/Rules.hpp rename to include/mqt-core/zx/Rules.hpp diff --git a/include/zx/Simplify.hpp b/include/mqt-core/zx/Simplify.hpp similarity index 100% rename from include/zx/Simplify.hpp rename to include/mqt-core/zx/Simplify.hpp diff --git a/include/zx/Utils.hpp b/include/mqt-core/zx/Utils.hpp similarity index 100% rename from include/zx/Utils.hpp rename to include/mqt-core/zx/Utils.hpp diff --git a/include/zx/ZXDefinitions.hpp b/include/mqt-core/zx/ZXDefinitions.hpp similarity index 100% rename from include/zx/ZXDefinitions.hpp rename to include/mqt-core/zx/ZXDefinitions.hpp diff --git a/include/zx/ZXDiagram.hpp b/include/mqt-core/zx/ZXDiagram.hpp similarity index 100% rename from include/zx/ZXDiagram.hpp rename to include/mqt-core/zx/ZXDiagram.hpp diff --git a/include/python/qiskit/QuantumCircuit.hpp b/include/python/qiskit/QuantumCircuit.hpp deleted file mode 100644 index 7a135ded2..000000000 --- a/include/python/qiskit/QuantumCircuit.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "pybind11/pybind11.h" -#include "pybind11/pytypes.h" - -#include -#include -#include - -namespace py = pybind11; - -#include "QuantumComputation.hpp" - -namespace qc::qiskit { -using namespace pybind11::literals; - -class QuantumCircuit { -public: - static void import(QuantumComputation& qc, const py::object& circ); - -protected: - static void emplaceOperation(QuantumComputation& qc, - const py::object& instruction, - const py::list& qargs, const py::list& cargs, - const py::list& params, const py::dict& qubitMap, - const py::dict& clbitMap); - - static SymbolOrNumber parseSymbolicExpr(const py::object& pyExpr); - - static SymbolOrNumber parseParam(const py::object& param); - - static void addOperation(QuantumComputation& qc, OpType type, - const py::list& qargs, const py::list& params, - const py::dict& qubitMap); - - static void addTwoTargetOperation(QuantumComputation& qc, OpType type, - const py::list& qargs, - const py::list& params, - const py::dict& qubitMap); - - static void importDefinition(QuantumComputation& qc, const py::object& circ, - const py::list& qargs, const py::list& cargs, - const py::dict& qubitMap, - const py::dict& clbitMap); - - static void importInitialLayout(QuantumComputation& qc, - const py::object& circ); -}; -} // namespace qc::qiskit diff --git a/noxfile.py b/noxfile.py index e36492e91..bff15701a 100644 --- a/noxfile.py +++ b/noxfile.py @@ -12,7 +12,7 @@ if TYPE_CHECKING: from collections.abc import Sequence -nox.options.sessions = ["lint", "pylint", "tests"] +nox.options.sessions = ["lint", "tests"] PYTHON_ALL_VERSIONS = ["3.8", "3.9", "3.10", "3.11", "3.12"] diff --git a/pyproject.toml b/pyproject.toml index 687cf1cf8..bd43a50ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,11 +57,11 @@ docs = [ "nbsphinx", "sphinx-autodoc-typehints", "sphinx-autoapi", - "qiskit-terra[visualization]", + "qiskit[visualization]", "mqt.core[evaluation]" ] qiskit = [ - "qiskit-terra>=0.22.0", + "qiskit[qasm3-import]>=0.45.0", ] dev = ["mqt.core[coverage, docs]",] @@ -90,9 +90,6 @@ ninja.minimum-version = "1.10" # Setuptools-style build caching in a local directory build-dir = "build/{wheel_tag}" -# Build stable ABI wheels for CPython 3.12+ -wheel.py-api = "cp312" - # Explicitly set the package directory wheel.packages = ["src/mqt"] @@ -118,7 +115,6 @@ git-only = [ [tool.scikit-build.cmake.define] BUILD_MQT_CORE_BINDINGS = "ON" BUILD_MQT_CORE_TESTS = "OFF" -ENABLE_IPO = "ON" [tool.setuptools_scm] @@ -135,6 +131,7 @@ filterwarnings = [ 'ignore:.*qiskit.utils.algorithm_globals.QiskitAlgorithmGlobals*:DeprecationWarning:qiskit', 'ignore:.*Building a flow controller with keyword arguments is going to be deprecated*:PendingDeprecationWarning:qiskit', 'ignore:\s.*Pyarrow.*:DeprecationWarning:', + 'ignore:.*datetime\.datetime\.utcfromtimestamp.*:DeprecationWarning:', ] log_cli_level = "info" testpaths = ["test/python"] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 96e892143..e6b5952df 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,11 +3,8 @@ set(MQT_CORE_TARGETS "") if(MQT_CORE_INSTALL) include(GNUInstallDirs) - if(NOT APPLE) - set(basePoint $ORIGIN) - endif() set(MQT_CORE_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/cmake/mqt-core") - set(MQT_CORE_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") + set(MQT_CORE_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/mqt-core") set(MQT_CORE_TARGETS_EXPORT_NAME "mqt-core-targets") set(MQT_CORE_CMAKE_CONFIG_TEMPLATE "${PROJECT_SOURCE_DIR}/cmake/mqt-core-config.cmake.in") set(MQT_CORE_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}") @@ -15,6 +12,14 @@ if(MQT_CORE_INSTALL) "${MQT_CORE_CMAKE_CONFIG_DIR}/mqt-core-config-version.cmake") set(MQT_CORE_CMAKE_PROJECT_CONFIG_FILE "${MQT_CORE_CMAKE_CONFIG_DIR}/mqt-core-config.cmake") set(MQT_CORE_CMAKE_PROJECT_TARGETS_FILE "${MQT_CORE_CMAKE_CONFIG_DIR}/mqt-core-targets.cmake") + + if(APPLE) + set(BASEPOINT @loader_path) + else() + set(BASEPOINT $ORIGIN) + endif() + set(CMAKE_INSTALL_RPATH ${BASEPOINT} ${BASEPOINT}/${CMAKE_INSTALL_LIBDIR}) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) endif() if(NOT TARGET project_warnings) @@ -117,14 +122,16 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME}) ${MQT_CORE_TARGET_NAME} PUBLIC $ $) - target_link_libraries(${MQT_CORE_TARGET_NAME} PUBLIC nlohmann_json) - # add options and warnings to the library - target_link_libraries(${MQT_CORE_TARGET_NAME} PUBLIC MQT::ProjectOptions MQT::ProjectWarnings) + target_link_libraries(${MQT_CORE_TARGET_NAME} PRIVATE MQT::ProjectOptions MQT::ProjectWarnings) # add MQT alias add_library(MQT::Core ALIAS ${MQT_CORE_TARGET_NAME}) - set_target_properties(${MQT_CORE_TARGET_NAME} PROPERTIES EXPORT_NAME Core) + set_target_properties( + ${MQT_CORE_TARGET_NAME} + PROPERTIES VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + EXPORT_NAME Core) list(APPEND MQT_CORE_TARGETS ${MQT_CORE_TARGET_NAME}) endif() @@ -137,24 +144,6 @@ add_subdirectory(zx) # add ECC library add_subdirectory(ecc) -# ** Note ** The following target will soon be removed from the project. All top-level projects -# should switch to using the mqt-core Python package. -if(BINDINGS AND NOT TARGET mqt-core-python) - # add Python interface library - add_library( - ${MQT_CORE_TARGET_NAME}-python ${MQT_CORE_INCLUDE_BUILD_DIR}/python/qiskit/QuantumCircuit.hpp - python/qiskit/QuantumCircuit.cpp) - - # link with main project library and pybind11 libraries - target_link_libraries(${MQT_CORE_TARGET_NAME}-python PUBLIC MQT::Core pybind11::pybind11 - pybind11_json) - - # add MQT alias - add_library(MQT::CorePython ALIAS ${MQT_CORE_TARGET_NAME}-python) - set_target_properties(${MQT_CORE_TARGET_NAME}-python PROPERTIES EXPORT_NAME CorePython) - list(APPEND MQT_CORE_TARGETS ${MQT_CORE_TARGET_NAME}-python) -endif() - if(BUILD_MQT_CORE_BINDINGS) add_subdirectory(python) endif() @@ -164,7 +153,9 @@ if(MQT_CORE_INSTALL) include(CMakePackageConfigHelpers) configure_package_config_file( ${MQT_CORE_CMAKE_CONFIG_TEMPLATE} ${MQT_CORE_CMAKE_PROJECT_CONFIG_FILE} - INSTALL_DESTINATION ${MQT_CORE_CONFIG_INSTALL_DIR}) + INSTALL_DESTINATION ${MQT_CORE_CONFIG_INSTALL_DIR} + PATH_VARS MQT_CORE_ZX_WITH_GMP + NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO) write_basic_package_version_file( ${MQT_CORE_CMAKE_VERSION_CONFIG_FILE} VERSION ${PROJECT_VERSION} @@ -176,6 +167,11 @@ if(MQT_CORE_INSTALL) install( TARGETS ${MQT_CORE_TARGETS} project_warnings project_options EXPORT ${MQT_CORE_TARGETS_EXPORT_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${MQT_CORE_TARGET_NAME}_Runtime + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT ${MQT_CORE_TARGET_NAME}_Runtime + NAMELINK_COMPONENT ${MQT_CORE_TARGET_NAME}_Development + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${MQT_CORE_TARGET_NAME}_Development INCLUDES DESTINATION ${MQT_CORE_INCLUDE_INSTALL_DIR}) @@ -185,14 +181,14 @@ if(MQT_CORE_INSTALL) EXPORT ${MQT_CORE_TARGETS_EXPORT_NAME} FILE ${MQT_CORE_PROJECT_TARGETS_FILE} NAMESPACE MQT:: - DESTINATION ${MQT_CORE_CONFIG_INSTALL_DIR}) + DESTINATION ${MQT_CORE_CONFIG_INSTALL_DIR} + COMPONENT ${MQT_CORE_TARGET_NAME}_Development) install( FILES ${PROJECT_SOURCE_DIR}/cmake/Cache.cmake ${PROJECT_SOURCE_DIR}/cmake/CompilerOptions.cmake ${PROJECT_SOURCE_DIR}/cmake/CompilerWarnings.cmake ${PROJECT_SOURCE_DIR}/cmake/FindGMP.cmake - ${PROJECT_SOURCE_DIR}/cmake/GetVersion.cmake ${PROJECT_SOURCE_DIR}/cmake/PackageAddTest.cmake ${PROJECT_SOURCE_DIR}/cmake/PreventInSourceBuilds.cmake ${PROJECT_SOURCE_DIR}/cmake/Sanitizers.cmake diff --git a/src/dd/CMakeLists.txt b/src/dd/CMakeLists.txt index 618fb124d..a9d70ccf1 100644 --- a/src/dd/CMakeLists.txt +++ b/src/dd/CMakeLists.txt @@ -23,9 +23,14 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME}-dd) statistics/Statistics.cpp statistics/TableStatistics.cpp statistics/UniqueTableStatistics.cpp) - target_link_libraries(${MQT_CORE_TARGET_NAME}-dd PUBLIC MQT::Core) + target_link_libraries(${MQT_CORE_TARGET_NAME}-dd PUBLIC MQT::Core nlohmann_json::nlohmann_json) + target_link_libraries(${MQT_CORE_TARGET_NAME}-dd PRIVATE MQT::ProjectOptions MQT::ProjectWarnings) add_library(MQT::CoreDD ALIAS ${MQT_CORE_TARGET_NAME}-dd) - set_target_properties(mqt-core-dd PROPERTIES EXPORT_NAME CoreDD) + set_target_properties( + mqt-core-dd + PROPERTIES VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + EXPORT_NAME CoreDD) set(MQT_CORE_TARGETS ${MQT_CORE_TARGETS} ${MQT_CORE_TARGET_NAME}-dd PARENT_SCOPE) diff --git a/src/ecc/CMakeLists.txt b/src/ecc/CMakeLists.txt index e5add2ecb..ad39034ac 100644 --- a/src/ecc/CMakeLists.txt +++ b/src/ecc/CMakeLists.txt @@ -14,10 +14,16 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME}-ecc) Q18Surface.cpp) target_link_libraries(${MQT_CORE_TARGET_NAME}-ecc PUBLIC MQT::Core) + target_link_libraries(${MQT_CORE_TARGET_NAME}-ecc PRIVATE MQT::ProjectOptions + MQT::ProjectWarnings) # add MQT alias add_library(MQT::CoreECC ALIAS ${MQT_CORE_TARGET_NAME}-ecc) - set_target_properties(${MQT_CORE_TARGET_NAME}-ecc PROPERTIES EXPORT_NAME CoreECC) + set_target_properties( + ${MQT_CORE_TARGET_NAME}-ecc + PROPERTIES VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + EXPORT_NAME CoreECC) set(MQT_CORE_TARGETS ${MQT_CORE_TARGETS} ${MQT_CORE_TARGET_NAME}-ecc PARENT_SCOPE) diff --git a/src/mqt/core/__main__.py b/src/mqt/core/__main__.py index 6916295d2..8a7a96cbe 100644 --- a/src/mqt/core/__main__.py +++ b/src/mqt/core/__main__.py @@ -24,9 +24,9 @@ def main() -> None: if not sys.argv[1:]: parser.print_help() if args.include_dir: - print(include_dir()) + print(include_dir().resolve()) if args.cmake_dir: - print(cmake_dir()) + print(cmake_dir().resolve()) if __name__ == "__main__": diff --git a/src/mqt/core/commands.py b/src/mqt/core/commands.py index 68314ab4c..8499d3ce7 100644 --- a/src/mqt/core/commands.py +++ b/src/mqt/core/commands.py @@ -10,7 +10,7 @@ def include_dir() -> Path: """Return the path to the mqt-core include directory.""" try: dist = distribution("mqt-core") - located_include_dir = Path(dist.locate_file("mqt/core/include")) + located_include_dir = Path(dist.locate_file("mqt/core/include/mqt-core")) if located_include_dir.exists() and located_include_dir.is_dir(): return located_include_dir msg = "mqt-core include files not found." diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 3d6a3be8c..875419898 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -1,9 +1,10 @@ pybind11_add_module( # Name of the extension _core - # Target the stable ABI for Python 3.12+, which reduces the number of binary wheels that must be - # built. This does nothing on older Python versions - WITH_SOABI + # Prefer thin LTO if available + THIN_LTO + # Optimize the bindings for size + OPT_SIZE # Source code goes here ${MQT_CORE_INCLUDE_BUILD_DIR}/python/pybind11.hpp module.cpp @@ -22,7 +23,7 @@ pybind11_add_module( symbolic/register_variable.cpp symbolic/register_term.cpp symbolic/register_expression.cpp) -target_link_libraries(_core PRIVATE MQT::Core) +target_link_libraries(_core PRIVATE MQT::Core MQT::ProjectOptions MQT::ProjectWarnings) # Install directive for scikit-build-core install( diff --git a/src/python/qiskit/QuantumCircuit.cpp b/src/python/qiskit/QuantumCircuit.cpp deleted file mode 100644 index 54fba1b2a..000000000 --- a/src/python/qiskit/QuantumCircuit.cpp +++ /dev/null @@ -1,480 +0,0 @@ -#include "python/qiskit/QuantumCircuit.hpp" - -void qc::qiskit::QuantumCircuit::import(qc::QuantumComputation& qc, - const py::object& circ) { - qc.reset(); - - const py::object quantumCircuit = - py::module::import("qiskit").attr("QuantumCircuit"); - - if (!py::isinstance(circ, quantumCircuit)) { - throw QFRException( - "[import] Python object needs to be a Qiskit QuantumCircuit"); - } - - if (!circ.attr("name").is_none()) { - qc.setName(circ.attr("name").cast()); - } - - // handle qubit registers - const py::object qubit = py::module::import("qiskit.circuit").attr("Qubit"); - const py::object ancillaQubit = - py::module::import("qiskit.circuit").attr("AncillaQubit"); - const py::object ancillaRegister = - py::module::import("qiskit.circuit").attr("AncillaRegister"); - int qubitIndex = 0; - const py::dict qubitMap{}; - auto&& circQregs = circ.attr("qregs"); - for (const auto qreg : circQregs) { - // create corresponding register in quantum computation - auto size = qreg.attr("size").cast(); - auto name = qreg.attr("name").cast(); - if (py::isinstance(qreg, ancillaRegister)) { - qc.addAncillaryRegister(size, name); - // add ancillas to qubit map - for (std::size_t i = 0; i < size; ++i) { - qubitMap[ancillaQubit(qreg, i)] = qubitIndex; - qubitIndex++; - } - } else { - qc.addQubitRegister(size, name); - // add qubits to qubit map - for (std::size_t i = 0; i < size; ++i) { - qubitMap[qubit(qreg, i)] = qubitIndex; - qubitIndex++; - } - } - } - - // handle classical registers - const py::object clbit = py::module::import("qiskit.circuit").attr("Clbit"); - int clbitIndex = 0; - const py::dict clbitMap{}; - auto&& circCregs = circ.attr("cregs"); - for (const auto creg : circCregs) { - // create corresponding register in quantum computation - auto size = creg.attr("size").cast(); - auto name = creg.attr("name").cast(); - qc.addClassicalRegister(size, name); - - // add clbits to clbit map - for (std::size_t i = 0; i < size; ++i) { - clbitMap[clbit(creg, i)] = clbitIndex; - clbitIndex++; - } - } - - try { - qc.gphase(circ.attr("global_phase").cast()); - } catch (const py::cast_error& e) { - std::clog << e.what() << "\n"; - std::clog << "[import] Warning: Symbolic global phase values are not " - "supported yet. Ignoring global phase.\n"; - } - - // iterate over instructions - auto&& data = circ.attr("data"); - for (const auto pyinst : data) { - auto&& inst = pyinst.cast>(); - auto&& instruction = std::get<0>(inst); - auto&& qargs = std::get<1>(inst); - auto&& cargs = std::get<2>(inst); - auto&& params = instruction.attr("params"); - - emplaceOperation(qc, instruction, qargs, cargs, params, qubitMap, clbitMap); - } - - // import initial layout in case it is available - if (!circ.attr("_layout").is_none()) { - importInitialLayout(qc, circ); - } - qc.initializeIOMapping(); -} - -void qc::qiskit::QuantumCircuit::emplaceOperation( - qc::QuantumComputation& qc, const py::object& instruction, - const py::list& qargs, const py::list& cargs, const py::list& params, - const py::dict& qubitMap, const py::dict& clbitMap) { - static const auto NATIVELY_SUPPORTED_GATES = - std::set{"i", "id", "iden", - "x", "y", "z", - "h", "s", "sdg", - "t", "tdg", "p", - "u1", "rx", "ry", - "rz", "u2", "u", - "u3", "cx", "cy", - "cz", "cp", "cu1", - "ch", "crx", "cry", - "crz", "cu3", "ccx", - "swap", "cswap", "iswap", - "sx", "sxdg", "csx", - "mcx", "mcx_gray", "mcx_recursive", - "mcx_vchain", "mcphase", "mcrx", - "mcry", "mcrz", "dcx", - "ecr", "rxx", "ryy", - "rzx", "rzz", "xx_minus_yy", - "xx_plus_yy"}; - - auto instructionName = instruction.attr("name").cast(); - if (instructionName == "measure") { - auto control = qubitMap[qargs[0]].cast(); - auto target = clbitMap[cargs[0]].cast(); - qc.emplace_back(qc.getNqubits(), control, target); - } else if (instructionName == "barrier") { - Targets targets{}; - for (const auto qubit : qargs) { - auto target = qubitMap[qubit].cast(); - targets.emplace_back(target); - } - qc.emplace_back(qc.getNqubits(), targets, Barrier); - } else if (instructionName == "reset") { - Targets targets{}; - for (const auto qubit : qargs) { - auto target = qubitMap[qubit].cast(); - targets.emplace_back(target); - } - qc.reset(targets); - } else if (NATIVELY_SUPPORTED_GATES.count(instructionName) != 0) { - // natively supported operations - if (instructionName == "i" || instructionName == "id" || - instructionName == "iden") { - addOperation(qc, I, qargs, params, qubitMap); - } else if (instructionName == "x" || instructionName == "cx" || - instructionName == "ccx" || instructionName == "mcx_gray" || - instructionName == "mcx") { - addOperation(qc, X, qargs, params, qubitMap); - } else if (instructionName == "y" || instructionName == "cy") { - addOperation(qc, Y, qargs, params, qubitMap); - } else if (instructionName == "z" || instructionName == "cz") { - addOperation(qc, Z, qargs, params, qubitMap); - } else if (instructionName == "h" || instructionName == "ch") { - addOperation(qc, H, qargs, params, qubitMap); - } else if (instructionName == "s") { - addOperation(qc, S, qargs, params, qubitMap); - } else if (instructionName == "sdg") { - addOperation(qc, Sdg, qargs, params, qubitMap); - } else if (instructionName == "t") { - addOperation(qc, T, qargs, params, qubitMap); - } else if (instructionName == "tdg") { - addOperation(qc, Tdg, qargs, params, qubitMap); - } else if (instructionName == "rx" || instructionName == "crx" || - instructionName == "mcrx") { - addOperation(qc, RX, qargs, params, qubitMap); - } else if (instructionName == "ry" || instructionName == "cry" || - instructionName == "mcry") { - addOperation(qc, RY, qargs, params, qubitMap); - } else if (instructionName == "rz" || instructionName == "crz" || - instructionName == "mcrz") { - addOperation(qc, RZ, qargs, params, qubitMap); - } else if (instructionName == "p" || instructionName == "u1" || - instructionName == "cp" || instructionName == "cu1" || - instructionName == "mcphase") { - addOperation(qc, P, qargs, params, qubitMap); - } else if (instructionName == "sx" || instructionName == "csx") { - addOperation(qc, SX, qargs, params, qubitMap); - } else if (instructionName == "sxdg") { - addOperation(qc, SXdg, qargs, params, qubitMap); - } else if (instructionName == "u2") { - addOperation(qc, U2, qargs, params, qubitMap); - } else if (instructionName == "u" || instructionName == "u3" || - instructionName == "cu3") { - addOperation(qc, U, qargs, params, qubitMap); - } else if (instructionName == "swap" || instructionName == "cswap") { - addTwoTargetOperation(qc, SWAP, qargs, params, qubitMap); - } else if (instructionName == "iswap") { - addTwoTargetOperation(qc, iSWAP, qargs, params, qubitMap); - } else if (instructionName == "dcx") { - addTwoTargetOperation(qc, DCX, qargs, params, qubitMap); - } else if (instructionName == "ecr") { - addTwoTargetOperation(qc, ECR, qargs, params, qubitMap); - } else if (instructionName == "rxx") { - addTwoTargetOperation(qc, RXX, qargs, params, qubitMap); - } else if (instructionName == "ryy") { - addTwoTargetOperation(qc, RYY, qargs, params, qubitMap); - } else if (instructionName == "rzx") { - addTwoTargetOperation(qc, RZX, qargs, params, qubitMap); - } else if (instructionName == "rzz") { - addTwoTargetOperation(qc, RZZ, qargs, params, qubitMap); - } else if (instructionName == "xx_minus_yy") { - addTwoTargetOperation(qc, XXminusYY, qargs, params, qubitMap); - } else if (instructionName == "xx_plus_yy") { - addTwoTargetOperation(qc, XXplusYY, qargs, params, qubitMap); - } else if (instructionName == "mcx_recursive") { - if (qargs.size() <= 5) { - addOperation(qc, X, qargs, params, qubitMap); - } else { - auto qargsCopy = qargs.attr("copy")(); - qargsCopy.attr("pop")(); // discard ancillaries - addOperation(qc, X, qargsCopy, params, qubitMap); - } - } else if (instructionName == "mcx_vchain") { - auto size = qargs.size(); - const std::size_t ncontrols = (size + 1) / 2; - auto qargsCopy = qargs.attr("copy")(); - // discard ancillaries - for (std::size_t i = 0; i < ncontrols - 2; ++i) { - qargsCopy.attr("pop")(); - } - addOperation(qc, X, qargsCopy, params, qubitMap); - } - } else { - try { - importDefinition(qc, instruction.attr("definition"), qargs, cargs, - qubitMap, clbitMap); - } catch (py::error_already_set& e) { - std::cerr << "Failed to import instruction " << instructionName - << " from Qiskit QuantumCircuit" << std::endl; - std::cerr << e.what() << std::endl; - } - } -} - -qc::SymbolOrNumber -qc::qiskit::QuantumCircuit::parseSymbolicExpr(const py::object& pyExpr) { - static const std::regex SUMMANDS("[+|-]?[^+-]+"); - static const std::regex PRODUCTS("[\\*/]?[^\\*/]+"); - - auto exprStr = pyExpr.attr("__str__")().cast(); - exprStr.erase(std::remove(exprStr.begin(), exprStr.end(), ' '), - exprStr.end()); // strip whitespace - - auto sumIt = std::sregex_iterator(exprStr.begin(), exprStr.end(), SUMMANDS); - const auto sumEnd = std::sregex_iterator(); - - qc::Symbolic sym; - bool isConst = true; - - while (sumIt != sumEnd) { - auto match = *sumIt; - auto matchStr = match.str(); - const int sign = matchStr[0] == '-' ? -1 : 1; - if (matchStr[0] == '+' || matchStr[0] == '-') { - matchStr.erase(0, 1); - } - - auto prodIt = - std::sregex_iterator(matchStr.begin(), matchStr.end(), PRODUCTS); - auto prodEnd = std::sregex_iterator(); - - fp coeff = 1.0; - std::string var; - while (prodIt != prodEnd) { - auto prodMatch = *prodIt; - auto prodStr = prodMatch.str(); - - const bool isDiv = prodStr[0] == '/'; - if (prodStr[0] == '*' || prodStr[0] == '/') { - prodStr.erase(0, 1); - } - - std::istringstream iss(prodStr); - fp f{}; - iss >> f; - - if (iss.eof() && !iss.fail()) { - coeff *= isDiv ? 1.0 / f : f; - } else { - var = prodStr; - } - - ++prodIt; - } - if (var.empty()) { - sym += coeff; - } else { - isConst = false; - sym += sym::Term(sym::Variable{var}, sign * coeff); - } - ++sumIt; - } - - if (isConst) { - return {sym.getConst()}; - } - return {sym}; -} - -qc::SymbolOrNumber -qc::qiskit::QuantumCircuit::parseParam(const py::object& param) { - try { - return param.cast(); - } catch ([[maybe_unused]] py::cast_error& e) { - return parseSymbolicExpr(param); - } -} - -void qc::qiskit::QuantumCircuit::addOperation(qc::QuantumComputation& qc, - qc::OpType type, - const py::list& qargs, - const py::list& params, - const py::dict& qubitMap) { - std::vector qubits{}; - for (const auto qubit : qargs) { - auto target = qubitMap[qubit].cast(); - qubits.emplace_back(Control{target}); - } - auto target = qubits.back().qubit; - qubits.pop_back(); - std::vector parameters{}; - for (const auto& param : params) { - parameters.emplace_back( - parseParam(py::reinterpret_borrow(param))); - } - const Controls controls(qubits.cbegin(), qubits.cend()); - if (std::all_of(parameters.cbegin(), parameters.cend(), [](const auto& p) { - return std::holds_alternative(p); - })) { - std::vector fpParams{}; - std::transform(parameters.cbegin(), parameters.cend(), - std::back_inserter(fpParams), - [](const auto& p) { return std::get(p); }); - qc.emplace_back(qc.getNqubits(), controls, target, type, - fpParams); - } else { - qc.emplace_back(qc.getNqubits(), controls, target, type, - parameters); - for (const auto& p : parameters) { - qc.addVariables(p); - } - } -} - -void qc::qiskit::QuantumCircuit::addTwoTargetOperation( - qc::QuantumComputation& qc, qc::OpType type, const py::list& qargs, - const py::list& params, const py::dict& qubitMap) { - std::vector qubits{}; - for (const auto qubit : qargs) { - auto target = qubitMap[qubit].cast(); - qubits.emplace_back(Control{target}); - } - auto target1 = qubits.back().qubit; - qubits.pop_back(); - auto target0 = qubits.back().qubit; - qubits.pop_back(); - std::vector parameters{}; - for (const auto& param : params) { - parameters.emplace_back( - parseParam(py::reinterpret_borrow(param))); - } - const Controls controls(qubits.cbegin(), qubits.cend()); - if (std::all_of(parameters.cbegin(), parameters.cend(), [](const auto& p) { - return std::holds_alternative(p); - })) { - std::vector fpParams{}; - std::transform(parameters.cbegin(), parameters.cend(), - std::back_inserter(fpParams), - [](const auto& p) { return std::get(p); }); - qc.emplace_back(qc.getNqubits(), controls, target0, - target1, type, fpParams); - } else { - qc.emplace_back(qc.getNqubits(), controls, target0, - target1, type, parameters); - for (const auto& p : parameters) { - qc.addVariables(p); - } - } -} - -void qc::qiskit::QuantumCircuit::importDefinition( - qc::QuantumComputation& qc, const py::object& circ, const py::list& qargs, - const py::list& cargs, const py::dict& qubitMap, const py::dict& clbitMap) { - const py::dict qargMap{}; - py::list&& defQubits = circ.attr("qubits"); - for (size_t i = 0; i < qargs.size(); ++i) { - qargMap[defQubits[i]] = qargs[i]; - } - - const py::dict cargMap{}; - py::list&& defClbits = circ.attr("clbits"); - for (size_t i = 0; i < cargs.size(); ++i) { - cargMap[defClbits[i]] = cargs[i]; - } - - auto&& data = circ.attr("data"); - for (const auto pyinst : data) { - auto&& inst = pyinst.cast>(); - auto&& instruction = std::get<0>(inst); - - const py::list& instQargs = std::get<1>(inst); - py::list mappedQargs{}; - for (auto&& instQarg : instQargs) { - mappedQargs.append(qargMap[instQarg]); - } - - const py::list& instCargs = std::get<2>(inst); - py::list mappedCargs{}; - for (auto&& instCarg : instCargs) { - mappedCargs.append(cargMap[instCarg]); - } - - auto&& instParams = instruction.attr("params"); - - emplaceOperation(qc, instruction, mappedQargs, mappedCargs, instParams, - qubitMap, clbitMap); - } -} - -void qc::qiskit::QuantumCircuit::importInitialLayout(qc::QuantumComputation& qc, - const py::object& circ) { - const py::object qubit = py::module::import("qiskit.circuit").attr("Qubit"); - - // get layout - auto layout = circ.attr("_layout"); - - // qiskit-terra 0.22.0 changed the `_layout` attribute to a - // `TranspileLayout` dataclass object that contains the initial layout as a - // `Layout` object in the `initial_layout` attribute. - if (py::hasattr(layout, "initial_layout")) { - layout = layout.attr("initial_layout"); - } - - // create map between registers used in the layout and logical qubit indices - // NOTE: this only works correctly if the registers were originally declared - // in alphabetical order! - const auto registers = layout.attr("get_registers")().cast(); - std::size_t logicalQubitIndex = 0U; - const py::dict logicalQubitIndices{}; - - // the ancilla register - decltype(registers.get_type()) ancillaRegister = py::none(); - - for (const auto qreg : registers) { - // skip ancillary register since it is handled as the very last qubit - // register - if (const auto qregName = qreg.attr("name").cast(); - qregName == "ancilla") { - ancillaRegister = qreg; - continue; - } - - const auto size = qreg.attr("size").cast(); - for (std::size_t i = 0U; i < size; ++i) { - logicalQubitIndices[qubit(qreg, i)] = logicalQubitIndex; - ++logicalQubitIndex; - } - } - - // handle ancillary register, if there is one - if (!ancillaRegister.is_none()) { - const auto size = ancillaRegister.attr("size").cast(); - for (std::size_t i = 0U; i < size; ++i) { - logicalQubitIndices[qubit(ancillaRegister, i)] = logicalQubitIndex; - qc.setLogicalQubitAncillary(static_cast(logicalQubitIndex)); - ++logicalQubitIndex; - } - } - - // get a map of physical to logical qubits - const auto physicalQubits = - layout.attr("get_physical_bits")().cast(); - - // create initial layout (and assume identical output permutation) - for (const auto& [physicalQubit, logicalQubit] : physicalQubits) { - if (logicalQubitIndices.contains(logicalQubit)) { - qc.initialLayout[physicalQubit.cast()] = - logicalQubitIndices[logicalQubit].cast(); - qc.outputPermutation[physicalQubit.cast()] = - logicalQubitIndices[logicalQubit].cast(); - } - } -} diff --git a/src/zx/CMakeLists.txt b/src/zx/CMakeLists.txt index aff31aee7..290a78ecc 100644 --- a/src/zx/CMakeLists.txt +++ b/src/zx/CMakeLists.txt @@ -6,6 +6,9 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME}-zx) add_library(multiprecision INTERFACE) target_link_libraries(multiprecision INTERFACE Boost::headers) add_library(MQT::Multiprecision ALIAS multiprecision) + set(MQT_CORE_ZX_SYSTEM_BOOST + TRUE + CACHE BOOL "Whether a system version of Boost was used") else() # Boost::multiprecision does not provide its own installation instructions. As a consequence, # this needs a workaround. @@ -26,6 +29,10 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME}-zx) install(DIRECTORY ${MULTIPRECISION_INCLUDE_DIR}/boost DESTINATION ${MQT_CORE_INCLUDE_INSTALL_DIR}) endif() + + set(MQT_CORE_ZX_SYSTEM_BOOST + FALSE + CACHE BOOL "Whether a system version of Boost was used") endif() endif() @@ -42,6 +49,7 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME}-zx) Utils.cpp FunctionalityConstruction.cpp) target_link_libraries(${MQT_CORE_TARGET_NAME}-zx PUBLIC MQT::Core MQT::Multiprecision) + target_link_libraries(${MQT_CORE_TARGET_NAME}-zx PRIVATE MQT::ProjectOptions MQT::ProjectWarnings) find_package(GMP) if(NOT GMP_FOUND) @@ -52,10 +60,17 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME}-zx) target_compile_definitions(${MQT_CORE_TARGET_NAME}-zx PUBLIC GMP) target_link_libraries(${MQT_CORE_TARGET_NAME}-zx PUBLIC GMP::gmp GMP::gmpxx) endif() + set(MQT_CORE_ZX_WITH_GMP + ${GMP_FOUND} + CACHE BOOL "Whether to use GMP for multiprecision arithmetic") # add MQT alias add_library(MQT::CoreZX ALIAS ${MQT_CORE_TARGET_NAME}-zx) - set_target_properties(${MQT_CORE_TARGET_NAME}-zx PROPERTIES EXPORT_NAME CoreZX) + set_target_properties( + ${MQT_CORE_TARGET_NAME}-zx + PROPERTIES VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + EXPORT_NAME CoreZX) set(MQT_CORE_TARGETS ${MQT_CORE_TARGETS} ${MQT_CORE_TARGET_NAME}-zx multiprecision PARENT_SCOPE) diff --git a/test/python/constraints.txt b/test/python/constraints.txt index b0c606904..6dd822116 100644 --- a/test/python/constraints.txt +++ b/test/python/constraints.txt @@ -3,6 +3,6 @@ pandas==2.1.2; python_version >= "3.9" pybind11==2.11.0 pytest==7.0.0 pytest-console-scripts==1.4 -qiskit-terra==0.22.0 +qiskit==0.45.0 scikit-build-core==0.6.1 setuptools-scm==7.0.0