Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ jobs:
with:
clang-version: 20
files-changed-only: true
install-pkgs: "nanobind==2.15.0"
install-pkgs: "nanobind==3.0.1"
setup-python: true
cpp-linter-extra-args: "-std=c++20"
permissions:
Expand Down
18 changes: 15 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,24 @@ releases may include breaking changes.

### Changed

- ⬆️ Update `mqt-core` to version 3.10.0 ([#995]) ([**@denialhaag**])
- ⬆️ Update `nanobind` to version 3.0.1 ([#995]) ([**@denialhaag**])
- 💥 Require Python 3.11 or newer ([#976]) ([**@denialhaag**])
- 📦 Publish one split-mode `cp311-abi3` wheel for GIL-enabled CPython 3.11 and
newer ([#995]) ([**@denialhaag**])
- 📦 Publish one `cp315-abi3t` wheel for free-threaded CPython 3.15 and newer
([#995]) ([**@denialhaag**])
- 💥 Raise the minimum Qiskit version from 1.1.0 to 2.1.0 ([#995])
([**@denialhaag**])
- ♻️ Own the circuit generators and DD gate matrices used by the command-line
interface, tests, and noise simulation ([#995]) ([**@denialhaag**])
- ♻️ Normalize circuits with `QuantumComputation` member operations ([#995])
([**@simon1hofmann**])
- 💥 Drop support for x86 macOS and stop publishing the respective wheels
([#976]) ([**@denialhaag**])
- ⬆️ Raise the macOS deployment target to 13.3 to enable `std::format` in libc++
([#976]) ([**@denialhaag**])
- 💥 Require Python 3.11 or newer ([#976]) ([**@denialhaag**])
- 🚚 Move recursive unitary construction from MQT Core to MQT DDSIM ([#975])
([**@simon1hofmann**])
- ♻️ Own recursive unitary construction ([#975]) ([**@simon1hofmann**])

## [2.5.0] - 2026-08-20

Expand Down Expand Up @@ -174,6 +185,7 @@ _📚 Refer to the [GitHub Release Notes] for previous changelogs._

<!-- PR links -->

[#995]: https://github.com/munich-quantum-toolkit/ddsim/pull/995
[#976]: https://github.com/munich-quantum-toolkit/ddsim/pull/976
[#975]: https://github.com/munich-quantum-toolkit/ddsim/pull/975
[#966]: https://github.com/munich-quantum-toolkit/ddsim/pull/966
Expand Down
5 changes: 0 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ if(BUILD_MQT_DDSIM_BINDINGS)
ON
CACHE BOOL "Prevent multiple searches for Python and instead cache the results.")

if(DISABLE_GIL)
message(STATUS "Disabling Python GIL")
add_compile_definitions(Py_GIL_DISABLED)
endif()

# top-level call to find Python
find_package(Python 3.11 REQUIRED COMPONENTS Interpreter Development.Module
${SKBUILD_SABI_COMPONENT})
Expand Down
20 changes: 19 additions & 1 deletion UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,34 @@ of changes including minor and patch releases, please refer to the

## [Unreleased]

This release updates the minimum required `mqt-core` version to 3.10.0.

### macOS support

MQT DDSIM no longer supports x86 macOS. Use Apple silicon with macOS 13.3 or
newer. The new deployment target enables `std::format` in libc++.

### Python support
### Qiskit 2.1 minimum

The minimum Qiskit version increases from **1.1.0 to 2.1.0**, dropping support
for all Qiskit 1.x releases and Qiskit 2.0. Upgrade Qiskit to 2.1.0 or newer.

### Python 3.11 and Stable ABI wheels

MQT DDSIM now requires Python 3.11 or newer. Upgrade the Python environment
before installing this release.

MQT DDSIM now publishes one `cp311-abi3` wheel for GIL-enabled CPython 3.11 and
newer. Free-threaded support starts with CPython 3.15 in a separate
`cp315-abi3t` wheel. MQT DDSIM no longer publishes free-threaded CPython 3.13 or
3.14 wheels.

This release updates `nanobind` to 3.0.1, which changes the `nanobind` ABI.

The Python bindings depend on `nanobind-backend`, which supplies the
interpreter-specific `nanobind` runtime. This dependency does not change the C++
API or the Python import paths.

## [2.5.0]

This release updates the minimum required `mqt-core` version to 3.9.0 and
Expand Down
2 changes: 1 addition & 1 deletion apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ macro(ADD_SIM_EXECUTABLE appname)
endmacro()

add_sim_executable(simple cxxopts::cxxopts)
target_link_libraries(mqt-ddsim-simple PRIVATE MQT::CoreAlgorithms)
target_include_directories(mqt-ddsim-simple PRIVATE ${PROJECT_SOURCE_DIR}/src)

if(Threads_FOUND)
add_sim_executable(noise_aware cxxopts::cxxopts)
Expand Down
14 changes: 6 additions & 8 deletions apps/simple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@
* Licensed under the MIT License
*/

#include "CircuitGenerators.hpp"
#include "CircuitSimulator.hpp"
#include "GroverSimulator.hpp"
#include "HybridSchrodingerFeynmanSimulator.hpp"
#include "ShorFastSimulator.hpp"
#include "ShorSimulator.hpp"
#include "Simulator.hpp"
#include "algorithms/GHZState.hpp"
#include "algorithms/Grover.hpp"
#include "algorithms/QFT.hpp"
#include "dd/Export.hpp"
#include "ir/QuantumComputation.hpp"
#include "qasm3/Importer.hpp"
Expand Down Expand Up @@ -135,8 +133,8 @@ int main(int argc, char** argv) { // NOLINT(bugprone-exception-escape)
}
} else if (vm.count("simulate_qft") > 0) {
const unsigned int nQubits = vm["simulate_qft"].as<unsigned int>();
quantumComputation =
std::make_unique<qc::QuantumComputation>(qc::createQFT(nQubits));
quantumComputation = std::make_unique<qc::QuantumComputation>(
ddsim::detail::createQFT(nQubits));
ddsim = std::make_unique<CircuitSimulator>(std::move(quantumComputation),
approximationInfo, seed);
} else if (vm.count("simulate_fast_shor") > 0) {
Expand Down Expand Up @@ -164,7 +162,7 @@ int main(int argc, char** argv) { // NOLINT(bugprone-exception-escape)
} else if (vm.count("simulate_grover") > 0) {
const unsigned int nQubits = vm["simulate_grover"].as<unsigned int>();
quantumComputation = std::make_unique<qc::QuantumComputation>(
qc::createGrover(nQubits, seed));
ddsim::detail::createGrover(nQubits, seed));
ddsim = std::make_unique<CircuitSimulator>(std::move(quantumComputation),
approximationInfo, seed);
} else if (vm.count("simulate_grover_emulated") > 0) {
Expand All @@ -175,8 +173,8 @@ int main(int argc, char** argv) { // NOLINT(bugprone-exception-escape)
vm["simulate_grover_oracle_emulated"].as<std::string>(), seed);
} else if (vm.count("simulate_ghz") > 0) {
const unsigned int nQubits = vm["simulate_ghz"].as<unsigned int>();
quantumComputation =
std::make_unique<qc::QuantumComputation>(qc::createGHZState(nQubits));
quantumComputation = std::make_unique<qc::QuantumComputation>(
ddsim::detail::createGHZState(nQubits));
ddsim = std::make_unique<CircuitSimulator>(std::move(quantumComputation),
approximationInfo, seed);
} else {
Expand Down
6 changes: 3 additions & 3 deletions cmake/ExternalDependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ if(BUILD_MQT_DDSIM_BINDINGS)
endif()

# cmake-format: off
set(MQT_CORE_MINIMUM_VERSION 3.9.0
set(MQT_CORE_MINIMUM_VERSION 3.10.0
CACHE STRING "MQT Core minimum version")
set(MQT_CORE_VERSION 3.9.1
set(MQT_CORE_VERSION 3.10.0
CACHE STRING "MQT Core version")
set(MQT_CORE_REV "24ed6a2ec6a740d54a122be04b634c5ce8c289fd"
set(MQT_CORE_REV "e9e2c959b3c81fda10ea8db34b908b638e61ba49"
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)")
Expand Down
24 changes: 24 additions & 0 deletions include/DensityNode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,30 @@ struct dNode final : dd::NodeBase { // NOLINT(readability-identifier-naming)
/// Getter for the terminal object
static constexpr dNode* getTerminal() noexcept { return nullptr; }

/// Mark flag used for mark-and-sweep garbage collection.
static constexpr std::uint16_t MARK_FLAG = 0b10000U;

/// Check whether the node is marked as used.
[[nodiscard]] bool isMarked() const noexcept {
return (flags & MARK_FLAG) != 0U;
}

/// Mark the node as used.
void mark() noexcept { flags |= MARK_FLAG; }

/// Unmark the node.
void unmark() noexcept { flags &= static_cast<std::uint16_t>(~MARK_FLAG); }

/**
* @brief Check whether a pointer represents a terminal density node.
* @details Density nodes encode temporary state in the three least
* significant pointer bits. These bits do not make a terminal pointer
* non-terminal.
*/
[[nodiscard]] static bool isTerminal(const dNode* p) noexcept {
return (reinterpret_cast<std::uintptr_t>(p) & (~7ULL)) == 0ULL;
}

[[nodiscard]] [[maybe_unused]] static constexpr bool
tempDensityMatrixFlagsEqual(const std::uint8_t a,
const std::uint8_t b) noexcept {
Expand Down
6 changes: 3 additions & 3 deletions include/DensityUniqueTable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class DensityUniqueTable {
// Only normalized nodes shall be stored.
[[nodiscard]] dNode* lookup(dNode* p) {
// there are unique terminal nodes
if (dd::NodeBase::isTerminal(p)) {
if (dNode::isTerminal(p)) {
return p;
}

Expand Down Expand Up @@ -98,7 +98,7 @@ class DensityUniqueTable {
void clear();

private:
using Bucket = dd::NodeBase*;
using Bucket = dNode*;
using Table = std::vector<Bucket>;

UniqueTableConfig cfg;
Expand All @@ -109,7 +109,7 @@ class DensityUniqueTable {

[[nodiscard]] dNode* searchTable(dNode& p, const std::size_t& key) {
const auto v = p.v;
auto* bucket = static_cast<dNode*>(tables[v][key]);
auto* bucket = tables[v][key];
while (bucket != nullptr) {
if (nodesAreEqual(p, *bucket)) {
// Match found
Expand Down
9 changes: 4 additions & 5 deletions include/HybridSchrodingerFeynmanSimulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#pragma once

#include "CircuitSimulator.hpp"
#include "circuit_optimizer/CircuitOptimizer.hpp"
#include "dd/DDDefinitions.hpp"
#include "dd/Node.hpp"
#include "dd/Package.hpp"
Expand All @@ -38,9 +37,9 @@ class HybridSchrodingerFeynmanSimulator final : public CircuitSimulator {
const std::size_t nthreads_ = 2)
: CircuitSimulator(std::move(qc_), approxInfo_), mode(mode_),
nthreads(nthreads_) {
qc::CircuitOptimizer::flattenOperations(*qc);
qc->flattenOperations();
// remove final measurements
qc::CircuitOptimizer::removeFinalMeasurements(*qc);
qc->removeFinalMeasurements();
}

explicit HybridSchrodingerFeynmanSimulator(
Expand All @@ -56,8 +55,8 @@ class HybridSchrodingerFeynmanSimulator final : public CircuitSimulator {
: CircuitSimulator(std::move(qc_), approxInfo_, seed_), mode(mode_),
nthreads(nthreads_) {
// remove final measurements
qc::CircuitOptimizer::flattenOperations(*qc);
qc::CircuitOptimizer::removeFinalMeasurements(*qc);
qc->flattenOperations();
qc->removeFinalMeasurements();
}

std::map<std::string, std::size_t> simulate(std::size_t shots) override;
Expand Down
3 changes: 1 addition & 2 deletions include/PathSimulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

#include "CircuitSimulator.hpp"
#include "Simulator.hpp"
#include "circuit_optimizer/CircuitOptimizer.hpp"
#include "dd/Node.hpp"
#include "ir/QuantumComputation.hpp"

Expand Down Expand Up @@ -167,7 +166,7 @@ class PathSimulator final : public CircuitSimulator {

// remove final measurements implement measurement support for task-based
// simulation
qc::CircuitOptimizer::removeFinalMeasurements(*(CircuitSimulator::qc));
CircuitSimulator::qc->removeFinalMeasurements();

// case distinction for the starting point of the alternating strategy
if (configuration.startingPoint == 0) {
Expand Down
Loading
Loading