From c816c9cb788fc3f67bd99393a46af631bbeb5441 Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 17:24:36 +0100 Subject: [PATCH 01/11] Switch to nanobind --- .github/workflows/ci.yml | 2 +- CMakeLists.txt | 8 +- bindings/CMakeLists.txt | 5 +- bindings/application_scheme.cpp | 17 +-- bindings/bindings.cpp | 29 ++--- bindings/configuration.cpp | 150 +++++++++++----------- bindings/equivalence_checking_manager.cpp | 83 ++++++------ bindings/equivalence_criterion.cpp | 18 +-- bindings/state_type.cpp | 17 +-- cmake/ExternalDependencies.cmake | 33 ++--- pyproject.toml | 13 +- uv.lock | 106 +++++++-------- 12 files changed, 216 insertions(+), 265 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a017448..68e258c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,7 +148,7 @@ jobs: clang-version: 20 cmake-args: -DBUILD_MQT_QCEC_BINDINGS=ON files-changed-only: true - install-pkgs: "pybind11==3.0.1" + install-pkgs: "nanobind==2.10.2" setup-python: true cpp-linter-extra-args: "-std=c++20" diff --git a/CMakeLists.txt b/CMakeLists.txt index 11d8f977..5b58ddc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ # Licensed under the MIT License # set required cmake version -cmake_minimum_required(VERSION 3.24...4.0) +cmake_minimum_required(VERSION 3.24...4.2) project( mqt-qcec @@ -37,10 +37,8 @@ if(BUILD_MQT_QCEC_BINDINGS) endif() # top-level call to find Python - find_package( - Python 3.10 REQUIRED - COMPONENTS Interpreter Development.Module - OPTIONAL_COMPONENTS Development.SABIModule) + find_package(Python 3.10 REQUIRED COMPONENTS Interpreter Development.Module + ${SKBUILD_SABI_COMPONENT}) endif() # check if this is the master project or used via add_subdirectory diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index a9a72736..3202349c 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -27,7 +27,7 @@ list( file(GLOB_RECURSE QCEC_SOURCES **.cpp) -add_mqt_python_binding( +add_mqt_python_binding_nanobind( QCEC ${MQT_QCEC_TARGET_NAME}-bindings ${QCEC_SOURCES} @@ -36,8 +36,7 @@ add_mqt_python_binding( INSTALL_DIR . LINK_LIBS - MQT::QCEC - pybind11_json) + MQT::QCEC) # install the Python stub files in editable mode for better IDE support if(SKBUILD_STATE STREQUAL "editable") diff --git a/bindings/application_scheme.cpp b/bindings/application_scheme.cpp index 3d65ff36..2715a736 100644 --- a/bindings/application_scheme.cpp +++ b/bindings/application_scheme.cpp @@ -10,20 +10,16 @@ #include "checker/dd/applicationscheme/ApplicationScheme.hpp" -#include -#include -#include // NOLINT(misc-include-cleaner) +#include namespace ec { -namespace py = pybind11; -using namespace pybind11::literals; +namespace nb = nanobind; +using namespace nb::literals; // NOLINTNEXTLINE(misc-use-internal-linkage) -void registerApplicationSchema(const py::module& mod) { - py::native_enum( - mod, "ApplicationScheme", "enum.Enum", - "Enumeration describing the application order of operations.") +void registerApplicationSchema(const nb::module_& m) { + nb::enum_(m, "ApplicationScheme", nb::is_arithmetic()) .value("sequential", ApplicationSchemeType::Sequential) .value("reference", ApplicationSchemeType::Sequential) .value("one_to_one", ApplicationSchemeType::OneToOne) @@ -37,8 +33,7 @@ void registerApplicationSchema(const py::module& mod) { "second circuit. Referred to as *compilation_flow* in " ":cite:p:`burgholzer2020verifyingResultsIBM`.") .value("compilation_flow", ApplicationSchemeType::GateCost) - .value("proportional", ApplicationSchemeType::Proportional) - .finalize(); + .value("proportional", ApplicationSchemeType::Proportional); } } // namespace ec diff --git a/bindings/bindings.cpp b/bindings/bindings.cpp index 396f3f3f..de8a08ad 100644 --- a/bindings/bindings.cpp +++ b/bindings/bindings.cpp @@ -8,28 +8,27 @@ * Licensed under the MIT License */ -#include -#include // NOLINT(misc-include-cleaner) +#include namespace ec { -namespace py = pybind11; -using namespace pybind11::literals; +namespace nb = nanobind; +using namespace nb::literals; // forward declarations -void registerApplicationSchema(const py::module& mod); -void registerConfiguration(const py::module& mod); -void registerEquivalenceCheckingManager(const py::module& mod); -void registerEquivalenceCriterion(const py::module& mod); -void registerStateType(const py::module& mod); +void registerApplicationSchema(const nb::module_& m); +void registerConfiguration(const nb::module_& m); +void registerEquivalenceCheckingManager(const nb::module_& m); +void registerEquivalenceCriterion(const nb::module_& m); +void registerStateType(const nb::module_& m); // NOLINTNEXTLINE(misc-include-cleaner) -PYBIND11_MODULE(MQT_QCEC_MODULE_NAME, mod, py::mod_gil_not_used()) { - registerApplicationSchema(mod); - registerConfiguration(mod); - registerEquivalenceCheckingManager(mod); - registerEquivalenceCriterion(mod); - registerStateType(mod); +NB_MODULE(MQT_QCEC_MODULE_NAME, m) { + registerApplicationSchema(m); + registerConfiguration(m); + registerEquivalenceCheckingManager(m); + registerEquivalenceCriterion(m); + registerStateType(m); } } // namespace ec diff --git a/bindings/configuration.cpp b/bindings/configuration.cpp index 1cd834eb..ca60518f 100644 --- a/bindings/configuration.cpp +++ b/bindings/configuration.cpp @@ -10,109 +10,107 @@ #include "Configuration.hpp" -#include -#include // NOLINT(misc-include-cleaner) +#include +#include // NOLINT(misc-include-cleaner) namespace ec { -namespace py = pybind11; -using namespace pybind11::literals; +namespace nb = nanobind; +using namespace nb::literals; // NOLINTNEXTLINE(misc-use-internal-linkage) -void registerConfiguration(const py::module& mod) { +void registerConfiguration(const nb::module_& m) { // Class definitions - auto configuration = py::class_(mod, "Configuration"); + auto configuration = nb::class_(m, "Configuration"); auto execution = - py::class_(configuration, "Execution"); + nb::class_(configuration, "Execution"); auto optimizations = - py::class_(configuration, "Optimizations"); + nb::class_(configuration, "Optimizations"); auto application = - py::class_(configuration, "Application"); + nb::class_(configuration, "Application"); auto functionality = - py::class_(configuration, "Functionality"); + nb::class_(configuration, "Functionality"); auto simulation = - py::class_(configuration, "Simulation"); + nb::class_(configuration, "Simulation"); auto parameterized = - py::class_(configuration, "Parameterized"); + nb::class_(configuration, "Parameterized"); // Configuration - configuration.def(py::init<>()) - .def_readwrite("execution", &Configuration::execution) - .def_readwrite("optimizations", &Configuration::optimizations) - .def_readwrite("application", &Configuration::application) - .def_readwrite("functionality", &Configuration::functionality) - .def_readwrite("simulation", &Configuration::simulation) - .def_readwrite("parameterized", &Configuration::parameterized) - .def("json", &Configuration::json) + configuration.def(nb::init<>()) + .def_rw("execution", &Configuration::execution) + .def_rw("optimizations", &Configuration::optimizations) + .def_rw("application", &Configuration::application) + .def_rw("functionality", &Configuration::functionality) + .def_rw("simulation", &Configuration::simulation) + .def_rw("parameterized", &Configuration::parameterized) + .def("json", + [](const Configuration& config) { return nb::cast(config.json()); }) .def("__repr__", &Configuration::toString); // execution options - execution.def(py::init<>()) - .def_readwrite("parallel", &Configuration::Execution::parallel) - .def_readwrite("nthreads", &Configuration::Execution::nthreads) - .def_readwrite("timeout", &Configuration::Execution::timeout) - .def_readwrite("run_construction_checker", - &Configuration::Execution::runConstructionChecker) - .def_readwrite("run_simulation_checker", - &Configuration::Execution::runSimulationChecker) - .def_readwrite("run_alternating_checker", - &Configuration::Execution::runAlternatingChecker) - .def_readwrite("run_zx_checker", &Configuration::Execution::runZXChecker) - .def_readwrite("numerical_tolerance", - &Configuration::Execution::numericalTolerance) - .def_readwrite("set_all_ancillae_garbage", - &Configuration::Execution::setAllAncillaeGarbage); + execution.def(nb::init<>()) + .def_rw("parallel", &Configuration::Execution::parallel) + .def_rw("nthreads", &Configuration::Execution::nthreads) + .def_rw("timeout", &Configuration::Execution::timeout) + .def_rw("run_construction_checker", + &Configuration::Execution::runConstructionChecker) + .def_rw("run_simulation_checker", + &Configuration::Execution::runSimulationChecker) + .def_rw("run_alternating_checker", + &Configuration::Execution::runAlternatingChecker) + .def_rw("run_zx_checker", &Configuration::Execution::runZXChecker) + .def_rw("numerical_tolerance", + &Configuration::Execution::numericalTolerance) + .def_rw("set_all_ancillae_garbage", + &Configuration::Execution::setAllAncillaeGarbage); // optimization options - optimizations.def(py::init<>()) - .def_readwrite("fuse_single_qubit_gates", - &Configuration::Optimizations::fuseSingleQubitGates) - .def_readwrite("reconstruct_swaps", - &Configuration::Optimizations::reconstructSWAPs) - .def_readwrite( - "remove_diagonal_gates_before_measure", - &Configuration::Optimizations::removeDiagonalGatesBeforeMeasure) - .def_readwrite("transform_dynamic_circuit", - &Configuration::Optimizations::transformDynamicCircuit) - .def_readwrite("reorder_operations", - &Configuration::Optimizations::reorderOperations) - .def_readwrite( - "backpropagate_output_permutation", - &Configuration::Optimizations::backpropagateOutputPermutation) - .def_readwrite("elide_permutations", - &Configuration::Optimizations::elidePermutations); + optimizations.def(nb::init<>()) + .def_rw("fuse_single_qubit_gates", + &Configuration::Optimizations::fuseSingleQubitGates) + .def_rw("reconstruct_swaps", + &Configuration::Optimizations::reconstructSWAPs) + .def_rw("remove_diagonal_gates_before_measure", + &Configuration::Optimizations::removeDiagonalGatesBeforeMeasure) + .def_rw("transform_dynamic_circuit", + &Configuration::Optimizations::transformDynamicCircuit) + .def_rw("reorder_operations", + &Configuration::Optimizations::reorderOperations) + .def_rw("backpropagate_output_permutation", + &Configuration::Optimizations::backpropagateOutputPermutation) + .def_rw("elide_permutations", + &Configuration::Optimizations::elidePermutations); // application options - application.def(py::init<>()) - .def_readwrite("construction_scheme", - &Configuration::Application::constructionScheme) - .def_readwrite("simulation_scheme", - &Configuration::Application::simulationScheme) - .def_readwrite("alternating_scheme", - &Configuration::Application::alternatingScheme) - .def_readwrite("profile", &Configuration::Application::profile); + application.def(nb::init<>()) + .def_rw("construction_scheme", + &Configuration::Application::constructionScheme) + .def_rw("simulation_scheme", + &Configuration::Application::simulationScheme) + .def_rw("alternating_scheme", + &Configuration::Application::alternatingScheme) + .def_rw("profile", &Configuration::Application::profile); // functionality options - functionality.def(py::init<>()) - .def_readwrite("trace_threshold", - &Configuration::Functionality::traceThreshold) - .def_readwrite("check_partial_equivalence", - &Configuration::Functionality::checkPartialEquivalence); + functionality.def(nb::init<>()) + .def_rw("trace_threshold", &Configuration::Functionality::traceThreshold) + .def_rw("check_partial_equivalence", + &Configuration::Functionality::checkPartialEquivalence); // simulation options - simulation.def(py::init<>()) - .def_readwrite("fidelity_threshold", - &Configuration::Simulation::fidelityThreshold) - .def_readwrite("max_sims", &Configuration::Simulation::maxSims) - .def_readwrite("state_type", &Configuration::Simulation::stateType) - .def_readwrite("seed", &Configuration::Simulation::seed); + simulation.def(nb::init<>()) + .def_rw("fidelity_threshold", + &Configuration::Simulation::fidelityThreshold) + .def_rw("max_sims", &Configuration::Simulation::maxSims) + .def_rw("state_type", &Configuration::Simulation::stateType) + .def_rw("seed", &Configuration::Simulation::seed); // parameterized options - parameterized.def(py::init<>()) - .def_readwrite("parameterized_tolerance", - &Configuration::Parameterized::parameterizedTol) - .def_readwrite("additional_instantiations", - &Configuration::Parameterized::nAdditionalInstantiations); + parameterized.def(nb::init<>()) + .def_rw("parameterized_tolerance", + &Configuration::Parameterized::parameterizedTol) + .def_rw("additional_instantiations", + &Configuration::Parameterized::nAdditionalInstantiations); } } // namespace ec diff --git a/bindings/equivalence_checking_manager.cpp b/bindings/equivalence_checking_manager.cpp index 3ac689a5..2a916ee0 100644 --- a/bindings/equivalence_checking_manager.cpp +++ b/bindings/equivalence_checking_manager.cpp @@ -13,36 +13,35 @@ #include "EquivalenceCriterion.hpp" #include "ir/QuantumComputation.hpp" -#include -#include -#include // NOLINT(misc-include-cleaner) +#include +#include // NOLINT(misc-include-cleaner) +#include // NOLINT(misc-include-cleaner) +#include namespace ec { -namespace py = pybind11; -using namespace pybind11::literals; +namespace nb = nanobind; +using namespace nb::literals; // NOLINTNEXTLINE(misc-use-internal-linkage) -void registerEquivalenceCheckingManager(const py::module& mod) { +void registerEquivalenceCheckingManager(const nb::module_& m) { // Class definitions auto ecm = - py::class_(mod, "EquivalenceCheckingManager"); + nb::class_(m, "EquivalenceCheckingManager"); auto results = - py::class_(ecm, "Results"); + nb::class_(ecm, "Results"); // Constructors - ecm.def(py::init(), "circ1"_a, "circ2"_a, "config"_a = Configuration()); // Access to circuits - ecm.def_property_readonly("qc1", - &EquivalenceCheckingManager::getFirstCircuit); - ecm.def_property_readonly("qc2", - &EquivalenceCheckingManager::getSecondCircuit); + ecm.def_prop_ro("qc1", &EquivalenceCheckingManager::getFirstCircuit); + ecm.def_prop_ro("qc2", &EquivalenceCheckingManager::getSecondCircuit); // Access to configuration - ecm.def_property( + ecm.def_prop_rw( "configuration", &EquivalenceCheckingManager::getConfiguration, [](EquivalenceCheckingManager& manager, const Configuration& config) { manager.getConfiguration() = config; @@ -52,9 +51,8 @@ void registerEquivalenceCheckingManager(const py::module& mod) { ecm.def("run", &EquivalenceCheckingManager::run); // Results - ecm.def_property_readonly("results", &EquivalenceCheckingManager::getResults); - ecm.def_property_readonly("equivalence", - &EquivalenceCheckingManager::equivalence); + ecm.def_prop_ro("results", &EquivalenceCheckingManager::getResults); + ecm.def_prop_ro("equivalence", &EquivalenceCheckingManager::equivalence); // Convenience functions // Execution @@ -72,31 +70,36 @@ void registerEquivalenceCheckingManager(const py::module& mod) { }); // EquivalenceCheckingManager::Results bindings - results.def(py::init<>()) - .def_readwrite("preprocessing_time", - &EquivalenceCheckingManager::Results::preprocessingTime) - .def_readwrite("check_time", - &EquivalenceCheckingManager::Results::checkTime) - .def_readwrite("equivalence", - &EquivalenceCheckingManager::Results::equivalence) - .def_readwrite("started_simulations", - &EquivalenceCheckingManager::Results::startedSimulations) - .def_readwrite("performed_simulations", - &EquivalenceCheckingManager::Results::performedSimulations) - .def_readwrite("cex_input", - &EquivalenceCheckingManager::Results::cexInput) - .def_readwrite("cex_output1", - &EquivalenceCheckingManager::Results::cexOutput1) - .def_readwrite("cex_output2", - &EquivalenceCheckingManager::Results::cexOutput2) - .def_readwrite( - "performed_instantiations", - &EquivalenceCheckingManager::Results::performedInstantiations) - .def_readwrite("checker_results", - &EquivalenceCheckingManager::Results::checkerResults) + results.def(nb::init<>()) + .def_rw("preprocessing_time", + &EquivalenceCheckingManager::Results::preprocessingTime) + .def_rw("check_time", &EquivalenceCheckingManager::Results::checkTime) + .def_rw("equivalence", &EquivalenceCheckingManager::Results::equivalence) + .def_rw("started_simulations", + &EquivalenceCheckingManager::Results::startedSimulations) + .def_rw("performed_simulations", + &EquivalenceCheckingManager::Results::performedSimulations) + .def_rw("cex_input", &EquivalenceCheckingManager::Results::cexInput) + .def_rw("cex_output1", &EquivalenceCheckingManager::Results::cexOutput1) + .def_rw("cex_output2", &EquivalenceCheckingManager::Results::cexOutput2) + .def_rw("performed_instantiations", + &EquivalenceCheckingManager::Results::performedInstantiations) + .def_prop_rw( + "checker_results", + [](const EquivalenceCheckingManager::Results& results) { + return nb::cast(results.checkerResults); + }, + [](EquivalenceCheckingManager::Results& results, + const nb::dict& obj) { + std::string jsonString = nb::cast(nb::str(obj)); + results.checkerResults = nlohmann::json::parse(jsonString); + }) .def("considered_equivalent", &EquivalenceCheckingManager::Results::consideredEquivalent) - .def("json", &EquivalenceCheckingManager::Results::json) + .def("json", + [](const EquivalenceCheckingManager::Results& results) { + return nb::cast(results.json()); + }) .def("__str__", &EquivalenceCheckingManager::Results::toString) .def("__repr__", [](const EquivalenceCheckingManager::Results& res) { return " -#include -#include // NOLINT(misc-include-cleaner) +#include namespace ec { -namespace py = pybind11; -using namespace pybind11::literals; +namespace nb = nanobind; +using namespace nb::literals; // NOLINTNEXTLINE(misc-use-internal-linkage) -void registerEquivalenceCriterion(const py::module& mod) { - py::native_enum( - mod, "EquivalenceCriterion", "enum.Enum", - "Enumeration of notions of equivalence.") +void registerEquivalenceCriterion(const nb::module_& m) { + nb::enum_(m, "EquivalenceCriterion", + nb::is_arithmetic()) .value("no_information", EquivalenceCriterion::NoInformation) .value("not_equivalent", EquivalenceCriterion::NotEquivalent) .value("equivalent", EquivalenceCriterion::Equivalent) @@ -33,8 +30,7 @@ void registerEquivalenceCriterion(const py::module& mod) { EquivalenceCriterion::EquivalentUpToGlobalPhase) .value("probably_equivalent", EquivalenceCriterion::ProbablyEquivalent) .value("probably_not_equivalent", - EquivalenceCriterion::ProbablyNotEquivalent) - .finalize(); + EquivalenceCriterion::ProbablyNotEquivalent); } } // namespace ec diff --git a/bindings/state_type.cpp b/bindings/state_type.cpp index 36fb9fea..d097d709 100644 --- a/bindings/state_type.cpp +++ b/bindings/state_type.cpp @@ -10,27 +10,22 @@ #include "checker/dd/simulation/StateType.hpp" -#include -#include -#include // NOLINT(misc-include-cleaner) +#include namespace ec { -namespace py = pybind11; -using namespace pybind11::literals; +namespace nb = nanobind; +using namespace nb::literals; // NOLINTNEXTLINE(misc-use-internal-linkage) -void registerStateType(const py::module& mod) { - py::native_enum( - mod, "StateType", "enum.Enum", - "Enumeration of state types for the simulation checker.") +void registerStateType(const nb::module_& m) { + nb::enum_(m, "StateType", nb::is_arithmetic()) .value("computational_basis", StateType::ComputationalBasis) .value("classical", StateType::ComputationalBasis) .value("random_1Q_basis", StateType::Random1QBasis) .value("local_quantum", StateType::Random1QBasis) .value("stabilizer", StateType::Stabilizer) - .value("global_quantum", StateType::Stabilizer) - .finalize(); + .value("global_quantum", StateType::Stabilizer); } } // namespace ec diff --git a/cmake/ExternalDependencies.cmake b/cmake/ExternalDependencies.cmake index b122ea2f..f0eb519b 100644 --- a/cmake/ExternalDependencies.cmake +++ b/cmake/ExternalDependencies.cmake @@ -25,27 +25,19 @@ if(BUILD_MQT_QCEC_BINDINGS) message(STATUS "Found mqt-core package: ${mqt-core_DIR}") endif() - if(NOT SKBUILD) - # Manually detect the installed pybind11 package. - execute_process( - COMMAND "${Python_EXECUTABLE}" -m pybind11 --cmakedir - OUTPUT_STRIP_TRAILING_WHITESPACE - OUTPUT_VARIABLE pybind11_DIR) - - # Add the detected directory to the CMake prefix path. - list(APPEND CMAKE_PREFIX_PATH "${pybind11_DIR}") - endif() - - # add pybind11 library - find_package(pybind11 3.0.1 CONFIG REQUIRED) + execute_process( + COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir + OUTPUT_STRIP_TRAILING_WHITESPACE + OUTPUT_VARIABLE nanobind_ROOT) + find_package(nanobind CONFIG REQUIRED) endif() # cmake-format: off -set(MQT_CORE_MINIMUM_VERSION 3.3.1 +set(MQT_CORE_MINIMUM_VERSION 3.4.0 CACHE STRING "MQT Core minimum version") -set(MQT_CORE_VERSION 3.3.3 +set(MQT_CORE_VERSION 3.4.0 CACHE STRING "MQT Core version") -set(MQT_CORE_REV "8c9f6ab24968401e450812fc0ff7d05b5ae07a63" +set(MQT_CORE_REV "6bcc01e7d135058c6439c64fdd5f14b65ab88816" CACHE STRING "MQT Core identifier (tag, branch or commit hash)") set(MQT_CORE_REPO_OWNER "munich-quantum-toolkit" CACHE STRING "MQT Core repository owner (change when using a fork)") @@ -69,14 +61,5 @@ if(BUILD_MQT_QCEC_TESTS) list(APPEND FETCH_PACKAGES googletest) endif() -if(BUILD_MQT_QCEC_BINDINGS) - # add pybind11_json library - FetchContent_Declare( - pybind11_json - GIT_REPOSITORY https://github.com/pybind/pybind11_json - FIND_PACKAGE_ARGS) - list(APPEND FETCH_PACKAGES pybind11_json) -endif() - # Make all declared dependencies available. FetchContent_MakeAvailable(${FETCH_PACKAGES}) diff --git a/pyproject.toml b/pyproject.toml index e2baf21e..e0d2d4a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,10 +8,10 @@ [build-system] requires = [ - "pybind11>=3.0.1", + "nanobind>=2.10.2", "scikit-build-core>=0.11.6", "setuptools-scm>=9.2.2", - "mqt.core~=3.3.1", + "mqt.core~=3.4.0", ] build-backend = "scikit_build_core.build" @@ -48,7 +48,7 @@ classifiers = [ ] requires-python = ">=3.10" dependencies = [ - "mqt.core~=3.3.1", + "mqt.core~=3.4.0", "typing_extensions>=4.2; python_version < '3.11'", # used for typing.Unpack "numpy>=1.22", "numpy>=1.24; python_version >= '3.11'", @@ -78,6 +78,9 @@ wheel.install-dir = "mqt/qcec" # Explicitly set the package directory wheel.packages = ["python/mqt"] +# Enable Stable ABI builds for CPython 3.12+ +wheel.py-api = "cp312" + # Set required Ninja version ninja.version = ">=1.10" @@ -366,10 +369,10 @@ mqt-qcec = { workspace = true } [dependency-groups] build = [ - "pybind11>=3.0.1", + "nanobind>=2.10.2", "scikit-build-core>=0.11.6", "setuptools-scm>=9.2.2", - "mqt.core~=3.3.1", + "mqt.core~=3.4.0", ] docs = [ "furo>=2025.09.25", diff --git a/uv.lock b/uv.lock index 39441307..c2d33ffc 100644 --- a/uv.lock +++ b/uv.lock @@ -1445,52 +1445,34 @@ wheels = [ [[package]] name = "mqt-core" -version = "3.3.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/b9/52f64b0bf94496d2b5bb59e0ebd3b185b8f962448995e3ddf33381b60c91/mqt_core-3.3.3.tar.gz", hash = "sha256:019039e3643f3e3c02bd3cd4cdc71769e1682280382a2753a7f80781991af4ab", size = 573713, upload-time = "2025-11-10T23:18:35.186Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/0d/1880eb0ad2e01eabebe23fae0c3c27fffbb6feba8a7cd89b92a038f8a9fe/mqt_core-3.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde7f0082fe37af2fc00357644bf92c2c0f97b1d931ddaebbee3c238788acb46", size = 6040209, upload-time = "2025-11-10T23:17:14.024Z" }, - { url = "https://files.pythonhosted.org/packages/e8/8c/b3892f6ab7b530ffc779d1bce7cf599bf49ecf6648ea94f5d2423c2a7f8b/mqt_core-3.3.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:bafd36247ab70e1162f5cc855250f6ab9dcb6d3527714f76d7dcc3d57540d6b5", size = 6381139, upload-time = "2025-11-10T23:17:16.184Z" }, - { url = "https://files.pythonhosted.org/packages/b6/04/55e7527fac3c7f0764e63e69749da219109093c0af6357d3dacb5e6b381c/mqt_core-3.3.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b68d14e3120c1b181ab7c80794197ae58130a3f944f51487e31a7feed7bfdf73", size = 8152582, upload-time = "2025-11-10T23:17:18.431Z" }, - { url = "https://files.pythonhosted.org/packages/93/4d/51641842862ee482161c3acc4b800f846e3828f45c0df6a9ebdeed981f4f/mqt_core-3.3.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ab5f113b8d28063cc2b6bc37dee8f81cb29f9ee863577c9fe36bd0ff01355cab", size = 8557442, upload-time = "2025-11-10T23:17:20.249Z" }, - { url = "https://files.pythonhosted.org/packages/30/1b/d1f4dbe7423b9c3bf88f7ec1cc94bc2474c30f93074a4094dd73aa66d29f/mqt_core-3.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4989544d7c6e545a6976d97351d113e37526e05a1c826107965f2c74acf847d", size = 4308521, upload-time = "2025-11-10T23:17:22.173Z" }, - { url = "https://files.pythonhosted.org/packages/2c/16/329cf09d804ba211bbe1808fffb34d172f092aa53d896f3880efbafbc519/mqt_core-3.3.3-cp310-cp310-win_arm64.whl", hash = "sha256:b18b89039d5cc4f8656413af25aff33516ee90247e979832e62cb8297732a16e", size = 4432160, upload-time = "2025-11-10T23:17:24.612Z" }, - { url = "https://files.pythonhosted.org/packages/9f/df/2c342969af601ce0d58826f59681ce123c936c55e68d6b6ecd1b51c424e8/mqt_core-3.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:83154e0c739c29e48c8d999a64b3c843d92f3319518b0efeff91b554a5138021", size = 6044138, upload-time = "2025-11-10T23:17:26.45Z" }, - { url = "https://files.pythonhosted.org/packages/76/92/a1912510e6b4f5e1f6839117a3b9b265e522fa4626aaebc1e875c7439f9d/mqt_core-3.3.3-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:9f4016b6e24c0685acbfa2ea7284eeb2d6a527b3dfb81f08a14498ad6b9edfbe", size = 6386057, upload-time = "2025-11-10T23:17:28.433Z" }, - { url = "https://files.pythonhosted.org/packages/6f/d2/66b5b108176591cadb20f632ecfc76cb4771c6fb6528c4ecc7f20595fcd4/mqt_core-3.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56899315ee2fc28ee66431e51258ad372384167d7046670e0d478d57bdf8f130", size = 8154908, upload-time = "2025-11-10T23:17:30.266Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0b/9f317439d986f59805912ce432cab8a5dd71636a783ecd191687eb2fb51f/mqt_core-3.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:170a65554e2e969ac1d8868dc6d66dc9f6fa56558980001e55e98b45af72c902", size = 8559256, upload-time = "2025-11-10T23:17:32.495Z" }, - { url = "https://files.pythonhosted.org/packages/69/c7/fa22c7eead964ea35366001c48eed2d8f0321ae8e3d065a1dcc4100b4c14/mqt_core-3.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:7690ab2ae876ad53eb0fcf4679b2a8d7ac0373f9f16243f392d6d2c74b9e82f1", size = 4311202, upload-time = "2025-11-10T23:17:35.004Z" }, - { url = "https://files.pythonhosted.org/packages/0e/c2/6c17d6e0bb179281c1673ced4697b71a72b944c5248689f3260713cce9bd/mqt_core-3.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:ceb462aecfc92faa8c3bb27bb668ddc2ee09d33d0315dc7b3ac5b2e8f4d6d53a", size = 4436130, upload-time = "2025-11-10T23:17:36.658Z" }, - { url = "https://files.pythonhosted.org/packages/7c/09/0499c783b008a22c6a6cc8d4b8a3c558129c1a42bb54cde08bf7432c38b6/mqt_core-3.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:95d4d75ae1f8a8d8efef859a83aa300ab3a9607ba1bc7e6ad9d3c1c5a6fa77f4", size = 6097127, upload-time = "2025-11-10T23:17:38.615Z" }, - { url = "https://files.pythonhosted.org/packages/d7/07/ed7c402ca76e63ad03fa839da989972f1d8db6bf92bfe01c7731fd7dcdd3/mqt_core-3.3.3-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:9b5d2b95276c2e6df67d324d0f2b23b6d3cea6be9d95535c0b1e49ffeec82d57", size = 6445438, upload-time = "2025-11-10T23:17:40.488Z" }, - { url = "https://files.pythonhosted.org/packages/29/6b/d13deb36be8f1600b107eec65ea94a039af4f135aaf414bb8fa227bae46d/mqt_core-3.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:406fc83525a1ca07a28830c3a97d243c18b74725f55bd40f0712a048be61dba4", size = 8156427, upload-time = "2025-11-10T23:17:42.329Z" }, - { url = "https://files.pythonhosted.org/packages/e3/62/b053d11b5725850f0959e5ad4b7e4234e8c97ab8a848dbce3f63371b5f3d/mqt_core-3.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4376d114dba2d74d08ca908074a307ef1e2e80b0c7b1c50f938d446eede0f116", size = 8561379, upload-time = "2025-11-10T23:17:44.718Z" }, - { url = "https://files.pythonhosted.org/packages/98/62/f62c6cca399c65096daa5b5212d76af25517012bd56d1fdc6eff25ea98c7/mqt_core-3.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:5d4af39f82efb0c29773ae4ae21a338aefc8db30dc4ef97835bc7e6f929c91d2", size = 4317083, upload-time = "2025-11-10T23:17:47.118Z" }, - { url = "https://files.pythonhosted.org/packages/1c/bd/0a7d3b40d5f4c7049ed626ec8e78c2cad01957e8bc00619ac825007205ec/mqt_core-3.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:7ffb61ae1ceb12060fb1dfefb7082c63af807caf5ff23e955dc4f12089e24bee", size = 4438407, upload-time = "2025-11-10T23:17:48.937Z" }, - { url = "https://files.pythonhosted.org/packages/a9/81/2d5137461b05495392d5675e009a47040dec38d0a9fc38d3f2221393959c/mqt_core-3.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a83471adb84c1976b0e3ff15f6c8e0384972d7e313b42c66ac3a3848551d3a6f", size = 6097200, upload-time = "2025-11-10T23:17:50.951Z" }, - { url = "https://files.pythonhosted.org/packages/83/9b/0c0f34c4433f518134e32675f03d80545dcf8da37740949319ec4fe50ce0/mqt_core-3.3.3-cp313-cp313-macosx_11_0_x86_64.whl", hash = "sha256:6c4b57623ed88ec331069a7af8dcfba204868480d3e87032cc65da01e135e900", size = 6445754, upload-time = "2025-11-10T23:17:52.735Z" }, - { url = "https://files.pythonhosted.org/packages/12/1b/c46710d10df4332615c6e224db8958b042d5bd6bf81b09ec1c8fcc68770a/mqt_core-3.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3e5cb758d9919a9941ee538af6642cb8ca6cb49a692f996b895f602462821fb3", size = 8156529, upload-time = "2025-11-10T23:17:54.533Z" }, - { url = "https://files.pythonhosted.org/packages/23/e4/42690d370f232274ccb8965ef81e7aa432e4b59687da5f04224d2368a18e/mqt_core-3.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:16ebe8683b11c7cbeaed37972c4c1d740f47becee6a41586fab186e74e41c319", size = 8561593, upload-time = "2025-11-10T23:17:56.752Z" }, - { url = "https://files.pythonhosted.org/packages/83/48/39d2b7a952a063a07b575365c1575cc899a6c2d0f0ea6b7708475724db8c/mqt_core-3.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:99530d5c87623dbd9d7942578998439594a1e8230374f46b4aac2e6fc379882e", size = 4317075, upload-time = "2025-11-10T23:17:58.68Z" }, - { url = "https://files.pythonhosted.org/packages/8c/4a/2410e50861c8318698c6b65fcf2a120f2a851aaa991e286382ea80107ed9/mqt_core-3.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:6190b176172e0e11259ad74e98ab3ab5b78fea710c49260f542f458e3ab1bef9", size = 4438384, upload-time = "2025-11-10T23:18:00.346Z" }, - { url = "https://files.pythonhosted.org/packages/4f/85/1618dbae0128645a6a2a18e1195eaf3c69ed1ffc2a526539cbbb59a04f55/mqt_core-3.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:94d76c9a2a2802243cda29e90ec4260715f4e971d34dba9b5e92aa03931f6f8e", size = 6115519, upload-time = "2025-11-10T23:18:02.023Z" }, - { url = "https://files.pythonhosted.org/packages/9e/78/cad40e452e3770b68bb0f0ac0f6ecbf9453e3898b1463dfffa63f5534094/mqt_core-3.3.3-cp313-cp313t-macosx_11_0_x86_64.whl", hash = "sha256:ae7fc758f209e0925378ce308de32922eadf73e1d8e9c02c05fff2be2268aca4", size = 6472221, upload-time = "2025-11-10T23:18:04.26Z" }, - { url = "https://files.pythonhosted.org/packages/82/05/820fb315976cf3b23b2bd3399f4c0f0dd36e6ea06bc4087242ba00e8cd5e/mqt_core-3.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:14cdf40be95933f26c342e7f3ecbe389a96d85875f116b8af02388a9b845697d", size = 8165519, upload-time = "2025-11-10T23:18:05.966Z" }, - { url = "https://files.pythonhosted.org/packages/23/77/bd7afbe5755870914cabd795ce6fcb1fbcbb6a24f4a81fc3b2adc2d4099f/mqt_core-3.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b23f5845dd966315557ab9d56a249e2269bd211053bcff1f521a76ce8543adc", size = 8570617, upload-time = "2025-11-10T23:18:07.689Z" }, - { url = "https://files.pythonhosted.org/packages/5c/9b/4bfcdee654ef11345705c6b6dd909a89872685203d0d5ff4aeefd60c52d3/mqt_core-3.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:16d4aba78a246eb40e27dddd1b740d175591ee83daaea7fbe1359f5fd237fece", size = 4366876, upload-time = "2025-11-10T23:18:09.715Z" }, - { url = "https://files.pythonhosted.org/packages/b0/3a/72544dec851e0c8540998c24274933d02df2b9ab7bba000358bb27813e79/mqt_core-3.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75ba22ba8061bd404098e4ad0b90d3cb9d866e0e7946e37c7997602632775804", size = 4464509, upload-time = "2025-11-10T23:18:11.715Z" }, - { url = "https://files.pythonhosted.org/packages/5a/02/1d94f921b6d84268b8a33095bbbff8c5220610be2ce419f5b0a6c759e7dd/mqt_core-3.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9c08ee6253af6f56c60c23ddd907eb6abce1d9620c06b8916682038389984d86", size = 6098681, upload-time = "2025-11-10T23:18:13.733Z" }, - { url = "https://files.pythonhosted.org/packages/c4/57/967bf7c971b2820fa30924c605497502fd549e68d6ddbd5dea90784d93f8/mqt_core-3.3.3-cp314-cp314-macosx_11_0_x86_64.whl", hash = "sha256:45fa41bb2c60ebc25337631bd556360fff6ede410796048ea067d8011cff2976", size = 6448267, upload-time = "2025-11-10T23:18:15.412Z" }, - { url = "https://files.pythonhosted.org/packages/2f/25/bbd13143d2bb3b2b7ba7bfbfa7fd82e044d3df30347fc979e93c4fea163d/mqt_core-3.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f290acbb492710debf175cea0106ec1fefcad39c38575cb78ed6d3ecae658207", size = 8156649, upload-time = "2025-11-10T23:18:17.014Z" }, - { url = "https://files.pythonhosted.org/packages/c9/87/4fb270039ac3f98b17e8603e3fd1456b55c73d59f9f588fb6d24f7398494/mqt_core-3.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:084b08dca96d631db7913dbf787677bf82707756436ba21a78c0af96c50631be", size = 8561701, upload-time = "2025-11-10T23:18:19.283Z" }, - { url = "https://files.pythonhosted.org/packages/64/55/785af2b4767497104f70cb0096cc07edc870442edaa90a88fad8e57a61ea/mqt_core-3.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:6ea8d568e92d6767ca72f9ecda2f3e9c0ceb7e9c3eed18b009ac8844bdb0dd32", size = 4377634, upload-time = "2025-11-10T23:18:21.67Z" }, - { url = "https://files.pythonhosted.org/packages/8c/98/a9ff5139b674e3161a838cd4b980111ef162dbe5810d23d98c53fa35db73/mqt_core-3.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:f9726936062c2dd1b975a6172e7065eed2224a814a40f5e72dc2d62dbae45730", size = 4502319, upload-time = "2025-11-10T23:18:23.301Z" }, - { url = "https://files.pythonhosted.org/packages/a3/80/36ffcd92ed7ef2bafd69e2ccef6d4856dc4585dcdd5a3a2029ea5692a86d/mqt_core-3.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:46c5cf993b77aa96fc1e58bd305bb32caeae0d3785cf40a8f5c0dde1c279d9ed", size = 6115514, upload-time = "2025-11-10T23:18:24.961Z" }, - { url = "https://files.pythonhosted.org/packages/d6/47/63a1a8550b9fd89b7f888a493a29dac3edd2aa591c3c17a41bec6f2d35e8/mqt_core-3.3.3-cp314-cp314t-macosx_11_0_x86_64.whl", hash = "sha256:b9b95fb3bb66c4d40423a4803534334e79890d481b5d4633295c9aceebf4610b", size = 6472251, upload-time = "2025-11-10T23:18:26.626Z" }, - { url = "https://files.pythonhosted.org/packages/7a/fb/3c0076d1700a2e9b3ac2d7ebc726bdb6b0b8eb767e3dc594b8de340f3417/mqt_core-3.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1872ed53ba11c583d0e79b476c16c135cd4dda930f7c41933a198514fa790ec", size = 8165472, upload-time = "2025-11-10T23:18:28.48Z" }, - { url = "https://files.pythonhosted.org/packages/dc/5f/2e76b3e4692a804a125a3bc36bb8cc4808a2ee474d953231c2ca35960c1a/mqt_core-3.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b40f0caab3489aa718f9e1ad95f66f76d43c28aa8b8fa1ff0181d5bfb2dc2e85", size = 8570635, upload-time = "2025-11-10T23:18:30.209Z" }, - { url = "https://files.pythonhosted.org/packages/f8/4c/50064cb72bd8f3602090bc4fd4d4516d2c992b3a6610cb6e43a6affaa9f7/mqt_core-3.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:22277b27c865b5aceee792b7a43a4a860459df613034187948226a916426c198", size = 4440028, upload-time = "2025-11-10T23:18:32.145Z" }, - { url = "https://files.pythonhosted.org/packages/55/5f/e9f70f6ffdae5788f67d2b28bcc5f91551400a7ccb9d22bd8c8145ff5077/mqt_core-3.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c62ccd3f1b777a846521a574d8aa85f60b484318df445147342bea4ca67af490", size = 4525130, upload-time = "2025-11-10T23:18:33.734Z" }, +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/6d/c3b4f17a8e695d715379ad298d0e51790ad7e2a60f0f68f1c08703ca8beb/mqt_core-3.4.0.tar.gz", hash = "sha256:daa752050e1001cb72e7cc1fd0c0aeff8a526aefae29e414b26920739a4aa681", size = 633636, upload-time = "2026-01-08T22:08:41.588Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/9b/960d498f34f88df402a7b76a18eec8113c86f8c233eba7313a9e1530dff6/mqt_core-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c58e5d223d2f59ff9146970b8a5202e07718dd3ce2191291469b347019ced674", size = 5114257, upload-time = "2026-01-08T22:08:01.23Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f0/8bbf1160a26f99799556a73a150873522ccb824cc45f3e9fdac44ecbd6a2/mqt_core-3.4.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30176b938ae76544cf70be31cdddbf2de8c83d8035af7f39ce11d5dd46c77b4c", size = 5547616, upload-time = "2026-01-08T22:08:03.399Z" }, + { url = "https://files.pythonhosted.org/packages/c7/78/19b0395b9568dc2d76056a998516adeed3775f98750a7a9bd988851be194/mqt_core-3.4.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:59fcd0711f49517c612946225c3b588448f8e0683f2a7aca596e7bc0eb48ed03", size = 6572454, upload-time = "2026-01-08T22:08:06.308Z" }, + { url = "https://files.pythonhosted.org/packages/c4/08/ae8859715f9eb6c16b707064fc0ea1171f3bc7804175b642b85571e4ef01/mqt_core-3.4.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bd27347bfd1310e4496c4f79a72076bb2638425968efd0724a3a2cbf0025b9b", size = 6991090, upload-time = "2026-01-08T22:08:08.201Z" }, + { url = "https://files.pythonhosted.org/packages/68/7a/4e413df061c1fa788205abeaff27ec5f40cb786403145fc505bc5a1b8d47/mqt_core-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:e49fd8f7b9ef12e4ebeed98a4bf8347559e938a0caec2f0b952e8a760cc4c60b", size = 3972046, upload-time = "2026-01-08T22:08:10.118Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d7/8b5b7cd47df3bd1191bc58ce78dee23f0b6ac594e499121a984643ea9b55/mqt_core-3.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:e1edc694f169b0f7b2a79b397efa6268349cddf94cbc396586c2cd68457bacfa", size = 3973622, upload-time = "2026-01-08T22:08:11.665Z" }, + { url = "https://files.pythonhosted.org/packages/40/16/4a82f02632d4cc22070490399f37f5a0019d0e669c9c0f610283e0a54b29/mqt_core-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:33cf21ad638892fa2fc6913840dca1e50cc531776c7f6b2fdb3cee0bad6004f1", size = 5115319, upload-time = "2026-01-08T22:08:13.483Z" }, + { url = "https://files.pythonhosted.org/packages/60/d9/3bdb720b99764a7ab3da8f103ccdb5d20cc069c893503d11f018716b7d06/mqt_core-3.4.0-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:226eab23b0b53a0018a435001a5d34b362bed8f7659939155e3ec58042b333d4", size = 5548833, upload-time = "2026-01-08T22:08:15.518Z" }, + { url = "https://files.pythonhosted.org/packages/90/df/e3b6ef95b7181c9455689325da68e5befb7faa1f01cc19106435909ee9a6/mqt_core-3.4.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:31846c555f23b9f7a710f9a70fc1882bd63d3bd19430488912f543debc4e646a", size = 6573090, upload-time = "2026-01-08T22:08:16.992Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/484b9d559263301412bb7da49b5939b15fcef27f3c6c7a743f61ed2fbeb2/mqt_core-3.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10d2c477c74fc873d442df27434586011d4749a159cb388bb49daf4f89ac4ca5", size = 6991703, upload-time = "2026-01-08T22:08:18.806Z" }, + { url = "https://files.pythonhosted.org/packages/fc/67/4b7929ff1c8d7c127fd2aac0d2d51580a8c177d066d6b7288bedfdaea03e/mqt_core-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d759f38cf09dfdd822f170262b395b76bdd4da2144dc5fd8a4a1d8346f5c0cc2", size = 3972643, upload-time = "2026-01-08T22:08:20.2Z" }, + { url = "https://files.pythonhosted.org/packages/d8/e4/2640e3ae0e1eab43aaf0fca2fc4fdcd098059cf1f86b9b6ddd7a3044c72a/mqt_core-3.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:ba9f687a96f6e42fd019e6098a7e54867d0173727613fbce92a893dd1f8f6950", size = 3974154, upload-time = "2026-01-08T22:08:21.596Z" }, + { url = "https://files.pythonhosted.org/packages/e1/86/0973049ec3f15ae9e47bb3a5d0222110c26ef86da336932575403fe63f77/mqt_core-3.4.0-cp312-abi3-macosx_11_0_arm64.whl", hash = "sha256:df2d6cb96de949d90d5051dd8c85354cce308207d655ee2365c92f5adcea135d", size = 5111559, upload-time = "2026-01-08T22:08:23.068Z" }, + { url = "https://files.pythonhosted.org/packages/23/da/eabcece4479a59753ab51a9a259146419d5cb2a7547de7f7fde7214c5900/mqt_core-3.4.0-cp312-abi3-macosx_11_0_x86_64.whl", hash = "sha256:bad7520308ea3dc528305b5e0610bc2053b67a6c7526a69bf69bda62551c4ef9", size = 5545608, upload-time = "2026-01-08T22:08:24.578Z" }, + { url = "https://files.pythonhosted.org/packages/6e/28/39d9bf7563c48a1bb77fc1f489cc757e92fe25dffd931c909ff31dfcecaa/mqt_core-3.4.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f86da5c06dd16e90ecfed2e328e655153e0cf336a6bb75effa74071a85d16f2f", size = 6559438, upload-time = "2026-01-08T22:08:26.058Z" }, + { url = "https://files.pythonhosted.org/packages/ff/a4/c61d64b69d5801d4cd4da23bb20042828e78d4ce9274f13032a5ca838981/mqt_core-3.4.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b0b37033ac2a1e8325257d649f7014ccbbe516a2004541008cfca18f89124ff4", size = 6975946, upload-time = "2026-01-08T22:08:27.679Z" }, + { url = "https://files.pythonhosted.org/packages/a3/47/aa597c38630ddcfed4482f381bb7970c3186fe189fdd6463d2171c55554d/mqt_core-3.4.0-cp312-abi3-win_amd64.whl", hash = "sha256:3c67121831eb9a6a82fb857148220d792463893063a6145f347a73d208d2b63c", size = 3965527, upload-time = "2026-01-08T22:08:29.246Z" }, + { url = "https://files.pythonhosted.org/packages/d7/3f/b5970789acb4ac81efbf584c0e71341c61fec6a1fba8a37dffd8fdc6c37e/mqt_core-3.4.0-cp312-abi3-win_arm64.whl", hash = "sha256:dcd597ff11027bdccecb243b9bf9055e7a8bc5f92af51349bd9a3051f6bd3c89", size = 3967823, upload-time = "2026-01-08T22:08:30.593Z" }, + { url = "https://files.pythonhosted.org/packages/84/e5/5f7c5e760446ee0f820425de983c3f3476a5c6ab2fd8909f19941f808895/mqt_core-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:545b8fe227d07d9c7c80868392dc9bb5c8902734809c3dafc565fd684dd785b2", size = 5125079, upload-time = "2026-01-08T22:08:32.107Z" }, + { url = "https://files.pythonhosted.org/packages/8a/fb/bafce65cbb74013df50b8c841bcefda9ab436965f7f7257c3c90c69c0b90/mqt_core-3.4.0-cp314-cp314t-macosx_11_0_x86_64.whl", hash = "sha256:3068fadbf7512d11f9ecb18e1e1785658657cd7b00759f1bfc67948d4af311fc", size = 5560107, upload-time = "2026-01-08T22:08:33.759Z" }, + { url = "https://files.pythonhosted.org/packages/90/a7/736986cfdc0ebe3a74f2c732156484a6349a02dc389e0b6f7e997dcfbdee/mqt_core-3.4.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8dbf325a30580cf2951774b3ab7fa539b7272a5a173ba25b98c753aac4faff66", size = 6584391, upload-time = "2026-01-08T22:08:35.16Z" }, + { url = "https://files.pythonhosted.org/packages/fc/9b/d16f996c915b23d8a58d74433dc1fbee55dbe0b40515c4a8e70a3c7f64f7/mqt_core-3.4.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:485a5133698c70c02430170bab46b88d24dd4188d6c63ebb3c91bdd3ccd7f782", size = 7000710, upload-time = "2026-01-08T22:08:36.735Z" }, + { url = "https://files.pythonhosted.org/packages/b6/38/232705301ea975356e06bed18e152424b5f48919961aa862275627689b1c/mqt_core-3.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2f51451a78b8fd4cb55c4a4d9b23f97c806305e699d313178fa3c8b9952fe558", size = 4061549, upload-time = "2026-01-08T22:08:38.884Z" }, + { url = "https://files.pythonhosted.org/packages/24/61/2b6e1ce9f3747d8cd336ff73a084ac1b5771111889467de214dbca3af8c0/mqt_core-3.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e6f1765f3569a533af790fbaee2c7a21a0a4b34611ff914b17a6c4dfdea08120", size = 4048399, upload-time = "2026-01-08T22:08:40.279Z" }, ] [[package]] @@ -1511,14 +1493,14 @@ qiskit = [ [package.dev-dependencies] build = [ { name = "mqt-core" }, - { name = "pybind11" }, + { name = "nanobind" }, { name = "scikit-build-core" }, { name = "setuptools-scm" }, ] dev = [ { name = "mqt-core" }, + { name = "nanobind" }, { name = "nox" }, - { name = "pybind11" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "pytest-sugar" }, @@ -1552,7 +1534,7 @@ test = [ [package.metadata] requires-dist = [ - { name = "mqt-core", specifier = "~=3.3.1" }, + { name = "mqt-core", specifier = "~=3.4.0" }, { name = "numpy", specifier = ">=1.22" }, { name = "numpy", marker = "python_full_version >= '3.11'", specifier = ">=1.24" }, { name = "numpy", marker = "python_full_version >= '3.12'", specifier = ">=1.26" }, @@ -1565,15 +1547,15 @@ provides-extras = ["qiskit"] [package.metadata.requires-dev] build = [ - { name = "mqt-core", specifier = "~=3.3.1" }, - { name = "pybind11", specifier = ">=3.0.1" }, + { name = "mqt-core", specifier = "~=3.4.0" }, + { name = "nanobind", specifier = ">=2.10.2" }, { name = "scikit-build-core", specifier = ">=0.11.6" }, { name = "setuptools-scm", specifier = ">=9.2.2" }, ] dev = [ - { name = "mqt-core", specifier = "~=3.3.1" }, + { name = "mqt-core", specifier = "~=3.4.0" }, + { name = "nanobind", specifier = ">=2.10.2" }, { name = "nox", specifier = ">=2025.11.12" }, - { name = "pybind11", specifier = ">=3.0.1" }, { name = "pytest", specifier = ">=9.0.1" }, { name = "pytest-cov", specifier = ">=7.0.0" }, { name = "pytest-sugar", specifier = ">=1.1.1" }, @@ -1646,6 +1628,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5f/df/76d0321c3797b54b60fef9ec3bd6f4cfd124b9e422182156a1dd418722cf/myst_parser-4.0.1-py3-none-any.whl", hash = "sha256:9134e88959ec3b5780aedf8a99680ea242869d012e8821db3126d427edc9c95d", size = 84579, upload-time = "2025-02-12T10:53:02.078Z" }, ] +[[package]] +name = "nanobind" +version = "2.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/7b/818fe4f6d1fdd516a14386ba86f2cbbac1b7304930da0f029724e9001658/nanobind-2.10.2.tar.gz", hash = "sha256:08509910ce6d1fadeed69cb0880d4d4fcb77739c6af9bd8fb4419391a3ca4c6b", size = 993651, upload-time = "2025-12-10T10:55:32.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/06/cb08965f985a5e1b9cb55ed96337c1f6daaa6b9cbdaeabe6bb3f7a1a11df/nanobind-2.10.2-py3-none-any.whl", hash = "sha256:6976c1b04b90481d2612b346485a3063818c6faa5077fe9d8bbc9b5fbe29c380", size = 246514, upload-time = "2025-12-10T10:55:30.741Z" }, +] + [[package]] name = "nbclient" version = "0.10.4" @@ -2143,15 +2134,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, ] -[[package]] -name = "pybind11" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2f/7b/a6d8dcb83c457e24a9df1e4d8fd5fb8034d4bbc62f3c324681e8a9ba57c2/pybind11-3.0.1.tar.gz", hash = "sha256:9c0f40056a016da59bab516efb523089139fcc6f2ba7e4930854c61efb932051", size = 546914, upload-time = "2025-08-22T20:09:27.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/8a/37362fc2b949d5f733a8b0f2ff51ba423914cabefe69f1d1b6aab710f5fe/pybind11-3.0.1-py3-none-any.whl", hash = "sha256:aa8f0aa6e0a94d3b64adfc38f560f33f15e589be2175e103c0a33c6bce55ee89", size = 293611, upload-time = "2025-08-22T20:09:25.235Z" }, -] - [[package]] name = "pybtex" version = "0.25.1" From e1dd22755737cb3aa0e0b2a79aff5fb0f83b3323 Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 18:05:54 +0100 Subject: [PATCH 02/11] Update changelog and upgrade guide --- CHANGELOG.md | 4 ++++ UPGRADING.md | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1321f313..dcf26ef5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Changed +- ♻️ Migrate Python bindings from `pybind11` to `nanobind` ([#817]) ([**@denialhaag**]) +- 📦️ Provide Stable ABI wheels for Python 3.12+ ([#817]) ([**@denialhaag**]) +- ⬆️ Bump minimum required `mqt-core` version to `3.4.0` ([#817]) ([**@denialhaag**]) - 👷 Stop testing on `ubuntu-22.04` and `ubuntu-22.04-arm` runners ([#796]) ([**@denialhaag**]) - 👷 Stop testing with `clang-19` and start testing with `clang-21` ([#796]) ([**@denialhaag**]) - 👷 Fix macOS tests with Homebrew Clang via new `munich-quantum-toolkit/workflows` version ([#796]) ([**@denialhaag**]) @@ -112,6 +115,7 @@ _📚 Refer to the [GitHub Release Notes] for previous changelogs._ +[#817]: https://github.com/munich-quantum-toolkit/qcec/pull/817 [#796]: https://github.com/munich-quantum-toolkit/qcec/pull/796 [#735]: https://github.com/munich-quantum-toolkit/qcec/pull/735 [#730]: https://github.com/munich-quantum-toolkit/qcec/pull/730 diff --git a/UPGRADING.md b/UPGRADING.md index 128c8c28..b07493ff 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -4,12 +4,24 @@ This document describes breaking changes and how to upgrade. For a complete list ## [Unreleased] -### Removal of Python 3.13t wheels +### Python wheels +This release contains two changes to the distributed wheels. + +First, we have removed all wheels for Python 3.13t. Free-threading Python was introduced as an experimental feature in Python 3.13. It became stable in Python 3.14. -To conserve space on PyPI and to reduce the CD build times, we have removed all wheels for Python 3.13t from our CI. -We continue to provide wheels for the regular Python versions 3.10 to 3.14, as well as 3.14t. + +Second, for Python 3.12+, we are now providing Stable ABI wheels instead of separate version-specific wheels. +This was enabled by migrating our Python bindings from `pybind11` to `nanobind`. + +Both of these changes were made in the interest of conserving PyPI space and reducing CI/CD build times. +The full list of wheels now reads: + +- 3.10 +- 3.11 +- 3.12+ Stable ABI +- 3.14t ## [3.3.0] From a443ce4a973fd1899a935eb1d63cde084e8ecf7f Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 18:13:34 +0100 Subject: [PATCH 03/11] Use json.dumps() --- bindings/equivalence_checking_manager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bindings/equivalence_checking_manager.cpp b/bindings/equivalence_checking_manager.cpp index 2a916ee0..d9a3f0b0 100644 --- a/bindings/equivalence_checking_manager.cpp +++ b/bindings/equivalence_checking_manager.cpp @@ -90,8 +90,10 @@ void registerEquivalenceCheckingManager(const nb::module_& m) { return nb::cast(results.checkerResults); }, [](EquivalenceCheckingManager::Results& results, - const nb::dict& obj) { - std::string jsonString = nb::cast(nb::str(obj)); + const nb::dict& value) { + nb::module_ json = nb::module_::import_("json"); + nb::object dumps = json.attr("dumps"); + const auto jsonString = nb::cast(dumps(value)); results.checkerResults = nlohmann::json::parse(jsonString); }) .def("considered_equivalent", From fc56c87b805890990ad9f353bbb3bd71e573b07a Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 18:18:07 +0100 Subject: [PATCH 04/11] Fix linter errors --- bindings/bindings.cpp | 4 ++-- bindings/equivalence_checking_manager.cpp | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bindings/bindings.cpp b/bindings/bindings.cpp index de8a08ad..84d89458 100644 --- a/bindings/bindings.cpp +++ b/bindings/bindings.cpp @@ -22,8 +22,8 @@ void registerEquivalenceCheckingManager(const nb::module_& m); void registerEquivalenceCriterion(const nb::module_& m); void registerStateType(const nb::module_& m); -// NOLINTNEXTLINE(misc-include-cleaner) -NB_MODULE(MQT_QCEC_MODULE_NAME, m) { +NB_MODULE(MQT_QCEC_MODULE_NAME, module_) { + const nb::module_& m = module_; registerApplicationSchema(m); registerConfiguration(m); registerEquivalenceCheckingManager(m); diff --git a/bindings/equivalence_checking_manager.cpp b/bindings/equivalence_checking_manager.cpp index d9a3f0b0..793139bb 100644 --- a/bindings/equivalence_checking_manager.cpp +++ b/bindings/equivalence_checking_manager.cpp @@ -16,7 +16,6 @@ #include #include // NOLINT(misc-include-cleaner) #include // NOLINT(misc-include-cleaner) -#include namespace ec { From b3ba8393ec52e1372ccaa38ba21bb807b3098035 Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 18:19:46 +0100 Subject: [PATCH 05/11] Streamline classifiers --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e0d2d4a1..1958749a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,12 +28,12 @@ license = "MIT" license-files = ["LICENSE.md"] classifiers = [ - "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Science/Research", "Natural Language :: English", - "Operating System :: POSIX :: Linux", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", "Programming Language :: C++", "Programming Language :: Python", "Programming Language :: Python :: 3", @@ -43,7 +43,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", - "Development Status :: 5 - Production/Stable", + "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", "Typing :: Typed", ] requires-python = ">=3.10" From 22b946c850435fa5c05b54e4e1e2561ccf789fe0 Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 18:32:20 +0100 Subject: [PATCH 06/11] Fix repair command --- pyproject.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1958749a..9fdd0c96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -332,12 +332,12 @@ test-skip = [ environment = { DEPLOY="ON" } # The SOVERSION needs to be updated when the shared libraries are updated. repair-wheel-command = """auditwheel repair -w {dest_dir} {wheel} \ ---exclude libmqt-core-ir.so.3.3 \ ---exclude libmqt-core-qasm.so.3.3 \ ---exclude libmqt-core-circuit-optimizer.so.3.3 \ ---exclude libmqt-core-algorithms.so.3.3 \ ---exclude libmqt-core-dd.so.3.3 \ ---exclude libmqt-core-zx.so.3.3""" +--exclude libmqt-core-ir.so.3.4 \ +--exclude libmqt-core-qasm.so.3.4 \ +--exclude libmqt-core-circuit-optimizer.so.3.4 \ +--exclude libmqt-core-algorithms.so.3.4 \ +--exclude libmqt-core-dd.so.3.4 \ +--exclude libmqt-core-zx.so.3.4""" [tool.cibuildwheel.macos] environment = { MACOSX_DEPLOYMENT_TARGET = "11.0" } From dbe593a6f74428823efb833b6f74d54339be6438 Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 18:35:23 +0100 Subject: [PATCH 07/11] Fix linter errors --- bindings/bindings.cpp | 4 ++-- bindings/equivalence_checking_manager.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bindings/bindings.cpp b/bindings/bindings.cpp index 84d89458..bfb2ff78 100644 --- a/bindings/bindings.cpp +++ b/bindings/bindings.cpp @@ -22,8 +22,8 @@ void registerEquivalenceCheckingManager(const nb::module_& m); void registerEquivalenceCriterion(const nb::module_& m); void registerStateType(const nb::module_& m); -NB_MODULE(MQT_QCEC_MODULE_NAME, module_) { - const nb::module_& m = module_; +// NOLINTNEXTLINE(performance-unnecessary-value-param) +NB_MODULE(MQT_QCEC_MODULE_NAME, m) { registerApplicationSchema(m); registerConfiguration(m); registerEquivalenceCheckingManager(m); diff --git a/bindings/equivalence_checking_manager.cpp b/bindings/equivalence_checking_manager.cpp index 793139bb..d7d768f1 100644 --- a/bindings/equivalence_checking_manager.cpp +++ b/bindings/equivalence_checking_manager.cpp @@ -16,6 +16,7 @@ #include #include // NOLINT(misc-include-cleaner) #include // NOLINT(misc-include-cleaner) +#include namespace ec { @@ -90,8 +91,8 @@ void registerEquivalenceCheckingManager(const nb::module_& m) { }, [](EquivalenceCheckingManager::Results& results, const nb::dict& value) { - nb::module_ json = nb::module_::import_("json"); - nb::object dumps = json.attr("dumps"); + const nb::module_ json = nb::module_::import_("json"); + const nb::object dumps = json.attr("dumps"); const auto jsonString = nb::cast(dumps(value)); results.checkerResults = nlohmann::json::parse(jsonString); }) From 8fb440e6ba82affb1de6d9c3d31216fc1f265ab1 Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 19:10:45 +0100 Subject: [PATCH 08/11] Specify return-values policies --- bindings/equivalence_checking_manager.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bindings/equivalence_checking_manager.cpp b/bindings/equivalence_checking_manager.cpp index d7d768f1..f437b4a4 100644 --- a/bindings/equivalence_checking_manager.cpp +++ b/bindings/equivalence_checking_manager.cpp @@ -37,8 +37,10 @@ void registerEquivalenceCheckingManager(const nb::module_& m) { "circ1"_a, "circ2"_a, "config"_a = Configuration()); // Access to circuits - ecm.def_prop_ro("qc1", &EquivalenceCheckingManager::getFirstCircuit); - ecm.def_prop_ro("qc2", &EquivalenceCheckingManager::getSecondCircuit); + ecm.def_prop_ro("qc1", &EquivalenceCheckingManager::getFirstCircuit, + nb::rv_policy::reference_internal); + ecm.def_prop_ro("qc2", &EquivalenceCheckingManager::getSecondCircuit, + nb::rv_policy::reference_internal); // Access to configuration ecm.def_prop_rw( @@ -51,7 +53,8 @@ void registerEquivalenceCheckingManager(const nb::module_& m) { ecm.def("run", &EquivalenceCheckingManager::run); // Results - ecm.def_prop_ro("results", &EquivalenceCheckingManager::getResults); + ecm.def_prop_ro("results", &EquivalenceCheckingManager::getResults, + nb::rv_policy::reference_internal); ecm.def_prop_ro("equivalence", &EquivalenceCheckingManager::equivalence); // Convenience functions From dbd9db816369ceb87293dfd43fac4bdda867670b Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 19:36:20 +0100 Subject: [PATCH 09/11] Address the Rabbit's out-of-range comments --- bindings/configuration.cpp | 6 +++++- bindings/equivalence_checking_manager.cpp | 11 ++++++++--- python/mqt/qcec/_compat/optional.py | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/bindings/configuration.cpp b/bindings/configuration.cpp index ca60518f..d4f86df2 100644 --- a/bindings/configuration.cpp +++ b/bindings/configuration.cpp @@ -44,7 +44,11 @@ void registerConfiguration(const nb::module_& m) { .def_rw("simulation", &Configuration::simulation) .def_rw("parameterized", &Configuration::parameterized) .def("json", - [](const Configuration& config) { return nb::cast(config.json()); }) + [](const Configuration& config) { + nb::module_ json = nb::module_::import_("json"); + nb::object loads = json.attr("loads"); + return loads(config.json().dump()); + }) .def("__repr__", &Configuration::toString); // execution options diff --git a/bindings/equivalence_checking_manager.cpp b/bindings/equivalence_checking_manager.cpp index f437b4a4..d889810f 100644 --- a/bindings/equivalence_checking_manager.cpp +++ b/bindings/equivalence_checking_manager.cpp @@ -47,7 +47,8 @@ void registerEquivalenceCheckingManager(const nb::module_& m) { "configuration", &EquivalenceCheckingManager::getConfiguration, [](EquivalenceCheckingManager& manager, const Configuration& config) { manager.getConfiguration() = config; - }); + }, + nb::rv_policy::reference_internal); // Run ecm.def("run", &EquivalenceCheckingManager::run); @@ -90,7 +91,9 @@ void registerEquivalenceCheckingManager(const nb::module_& m) { .def_prop_rw( "checker_results", [](const EquivalenceCheckingManager::Results& results) { - return nb::cast(results.checkerResults); + nb::module_ json = nb::module_::import_("json"); + nb::object loads = json.attr("loads"); + return loads(results.checkerResults.dump()); }, [](EquivalenceCheckingManager::Results& results, const nb::dict& value) { @@ -103,7 +106,9 @@ void registerEquivalenceCheckingManager(const nb::module_& m) { &EquivalenceCheckingManager::Results::consideredEquivalent) .def("json", [](const EquivalenceCheckingManager::Results& results) { - return nb::cast(results.json()); + nb::module_ json = nb::module_::import_("json"); + nb::object loads = json.attr("loads"); + return loads(results.json().dump()); }) .def("__str__", &EquivalenceCheckingManager::Results::toString) .def("__repr__", [](const EquivalenceCheckingManager::Results& res) { diff --git a/python/mqt/qcec/_compat/optional.py b/python/mqt/qcec/_compat/optional.py index c3f0a50a..cdfae4ab 100644 --- a/python/mqt/qcec/_compat/optional.py +++ b/python/mqt/qcec/_compat/optional.py @@ -104,5 +104,5 @@ def disable_locally(self) -> typing.Generator[None, None, None]: HAS_QISKIT = OptionalDependencyTester( "qiskit", - msg="Please install the `mqt.qcec[qiskit]` extra or a compatible version of Qiskit to use functionality related to its functionality.", + msg="Please install the `mqt.qcec[qiskit]` extra or a compatible version of Qiskit.", ) From 2b23f8eac41947d77459b524b4e686633477c252 Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 19:43:16 +0100 Subject: [PATCH 10/11] Remove redundant period --- python/mqt/qcec/_compat/optional.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/mqt/qcec/_compat/optional.py b/python/mqt/qcec/_compat/optional.py index cdfae4ab..90d6cedd 100644 --- a/python/mqt/qcec/_compat/optional.py +++ b/python/mqt/qcec/_compat/optional.py @@ -84,7 +84,7 @@ def require_now(self, feature: str) -> None: return message = f"The '{self._module}' library is required to {feature}." if self._msg: - message += f" {self._msg}." + message += f" {self._msg}" raise ImportError(message) @contextlib.contextmanager From c8ac66128fd9f47a47ae98242c840662e1916407 Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 9 Jan 2026 19:44:49 +0100 Subject: [PATCH 11/11] Fix linter errors --- bindings/configuration.cpp | 4 ++-- bindings/equivalence_checking_manager.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bindings/configuration.cpp b/bindings/configuration.cpp index d4f86df2..1f99f173 100644 --- a/bindings/configuration.cpp +++ b/bindings/configuration.cpp @@ -45,8 +45,8 @@ void registerConfiguration(const nb::module_& m) { .def_rw("parameterized", &Configuration::parameterized) .def("json", [](const Configuration& config) { - nb::module_ json = nb::module_::import_("json"); - nb::object loads = json.attr("loads"); + const nb::module_ json = nb::module_::import_("json"); + const nb::object loads = json.attr("loads"); return loads(config.json().dump()); }) .def("__repr__", &Configuration::toString); diff --git a/bindings/equivalence_checking_manager.cpp b/bindings/equivalence_checking_manager.cpp index d889810f..b189f6a1 100644 --- a/bindings/equivalence_checking_manager.cpp +++ b/bindings/equivalence_checking_manager.cpp @@ -91,8 +91,8 @@ void registerEquivalenceCheckingManager(const nb::module_& m) { .def_prop_rw( "checker_results", [](const EquivalenceCheckingManager::Results& results) { - nb::module_ json = nb::module_::import_("json"); - nb::object loads = json.attr("loads"); + const nb::module_ json = nb::module_::import_("json"); + const nb::object loads = json.attr("loads"); return loads(results.checkerResults.dump()); }, [](EquivalenceCheckingManager::Results& results, @@ -106,8 +106,8 @@ void registerEquivalenceCheckingManager(const nb::module_& m) { &EquivalenceCheckingManager::Results::consideredEquivalent) .def("json", [](const EquivalenceCheckingManager::Results& results) { - nb::module_ json = nb::module_::import_("json"); - nb::object loads = json.attr("loads"); + const nb::module_ json = nb::module_::import_("json"); + const nb::object loads = json.attr("loads"); return loads(results.json().dump()); }) .def("__str__", &EquivalenceCheckingManager::Results::toString)