Skip to content

Commit 69550c8

Browse files
mqt-app[bot]denialhaagburgholzer
authored
⬆️ Update munich-quantum-toolkit/core (#681)
This pull request updates the [munich-quantum-toolkit/core](https://github.com/munich-quantum-toolkit/core) dependency from munich-quantum-toolkit/core@0425f88 (version v3.2.1) to munich-quantum-toolkit/core@a354ba3 (version v3.3.0). **Full Changelog**: munich-quantum-toolkit/core@0425f88...a354ba3 --------- Signed-off-by: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Co-authored-by: mqt-app[bot] <219534693+mqt-app[bot]@users.noreply.github.com> Co-authored-by: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Co-authored-by: Lukas Burgholzer <burgholzer@me.com>
1 parent db93014 commit 69550c8

11 files changed

Lines changed: 349 additions & 171 deletions

CHANGELOG.md

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ This project adheres to [Semantic Versioning], with the exception that minor rel
1111

1212
### Added
1313

14+
- ✨ Add support for Qiskit's `IfElse` operations ([#681]) ([**@denialhaag**])
1415
- 👷 Enable testing on Python 3.14 ([#674]) ([**@denialhaag**])
1516

17+
### Changed
18+
19+
- ⬆️ Bump minimum required `mqt-core` version to `3.3.1` ([#681]) ([**@denialhaag**])
20+
1621
### Removed
1722

1823
- 🔥 Drop support for Python 3.9 ([#645]) ([**@denialhaag**])
@@ -28,26 +33,26 @@ _If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md#200)._
2833

2934
### Changed
3035

31-
- **Breaking**: ♻️ Streamline names of Python modules and classes ([#614]) ([**@denialhaag**])
32-
- **Breaking**: ⬆️ Bump minimum required `mqt-core` version to `3.2.1` ([#610]) ([**@denialhaag**])
33-
- **Breaking**: ⬆️ Require C++20 ([#610]) ([**@denialhaag**])
34-
- **Breaking**: ✨ Expose enums to Python via `pybind11`'s new (`enum.Enum`-compatible) `py::native_enum` ([#607]) ([**@denialhaag**])
35-
- **Breaking**: ⬆️ Bump minimum required `mqt-core` version to `3.1.0` ([#591]) ([**@denialhaag**])
36-
- **Breaking**: ⬆️ Bump minimum required `pybind11` version to `3.0.0` ([#591]) ([**@denialhaag**])
36+
- ♻️ Streamline names of Python modules and classes ([#614]) ([**@denialhaag**])
37+
- ⬆️ Bump minimum required `mqt-core` version to `3.2.1` ([#610]) ([**@denialhaag**])
38+
- ⬆️ Require C++20 ([#610]) ([**@denialhaag**])
39+
- ✨ Expose enums to Python via `pybind11`'s new (`enum.Enum`-compatible) `py::native_enum` ([#607]) ([**@denialhaag**])
40+
- ⬆️ Bump minimum required `mqt-core` version to `3.1.0` ([#591]) ([**@denialhaag**])
41+
- ⬆️ Bump minimum required `pybind11` version to `3.0.0` ([#591]) ([**@denialhaag**])
3742
- ♻️ Move the C++ code for the Python bindings to the top-level `bindings` directory ([#567]) ([**@denialhaag**])
3843
- ♻️ Move all Python code (no tests) to the top-level `python` directory ([#567]) ([**@denialhaag**])
39-
- **Breaking**: ⬆️ Support Qiskit 2.0 ([#571]) ([**@denialhaag**])
40-
- **Breaking**: 🚚 Move MQT DDSIM to the [munich-quantum-toolkit] GitHub organization
41-
- **Breaking**: ♻️ Use the `mqt-core` Python package for handling circuits ([#336]) ([**@burgholzer**])
42-
- **Breaking**: ⬆️ Bump minimum required CMake version to `3.24.0` ([#538]) ([**@burgholzer**])
44+
- ⬆️ Support Qiskit 2.0 ([#571]) ([**@denialhaag**])
45+
- 🚚 Move MQT DDSIM to the [munich-quantum-toolkit] GitHub organization
46+
- ♻️ Use the `mqt-core` Python package for handling circuits ([#336]) ([**@burgholzer**])
47+
- ⬆️ Bump minimum required CMake version to `3.24.0` ([#538]) ([**@burgholzer**])
4348
- 📝 Rework existing project documentation ([#556]) ([**@burgholzer**])
4449

4550
### Removed
4651

47-
- **Breaking**: 🔥 Remove methods for querying maximum node count ([#591]) ([**@denialhaag**])
48-
- **Breaking**: 🔥 Remove the TN flow from the path simulator ([#336]) ([**@burgholzer**])
49-
- **Breaking**: 🔥 Remove some superfluous C++ executables ([#336]) ([**@burgholzer**])
50-
- **Breaking**: 🔥 Remove support for `.real`, `.qc`, `.tfc`, and `GRCS` files ([#538]) ([**@burgholzer**])
52+
- 🔥 Remove methods for querying maximum node count ([#591]) ([**@denialhaag**])
53+
- 🔥 Remove the TN flow from the path simulator ([#336]) ([**@burgholzer**])
54+
- 🔥 Remove some superfluous C++ executables ([#336]) ([**@burgholzer**])
55+
- 🔥 Remove support for `.real`, `.qc`, `.tfc`, and `GRCS` files ([#538]) ([**@burgholzer**])
5156

5257
### Fixed
5358

@@ -65,6 +70,7 @@ _📚 Refer to the [GitHub Release Notes] for previous changelogs._
6570

6671
<!-- PR links -->
6772

73+
[#681]: https://github.com/munich-quantum-toolkit/ddsim/pull/681
6874
[#674]: https://github.com/munich-quantum-toolkit/ddsim/pull/674
6975
[#645]: https://github.com/munich-quantum-toolkit/ddsim/pull/645
7076
[#640]: https://github.com/munich-quantum-toolkit/ddsim/pull/640

cmake/ExternalDependencies.cmake

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ if(BUILD_MQT_DDSIM_BINDINGS)
4141
endif()
4242

4343
# cmake-format: off
44-
set(MQT_CORE_MINIMUM_VERSION 3.2.1
44+
set(MQT_CORE_MINIMUM_VERSION 3.3.1
4545
CACHE STRING "MQT Core minimum version")
46-
set(MQT_CORE_VERSION 3.2.1
46+
set(MQT_CORE_VERSION 3.3.1
4747
CACHE STRING "MQT Core version")
48-
set(MQT_CORE_REV "0425f88169f573e4505b49703c4cadf3699ccbcd"
48+
set(MQT_CORE_REV "1392d1b70f7331ea1ebb3247587c62cb8fd1d078"
4949
CACHE STRING "MQT Core identifier (tag, branch or commit hash)")
5050
set(MQT_CORE_REPO_OWNER "munich-quantum-toolkit"
5151
CACHE STRING "MQT Core repository owner (change when using a fork)")

pyproject.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ requires = [
1111
"scikit-build-core>=0.11.2",
1212
"setuptools-scm>=8.3.1",
1313
"pybind11>=3.0.0",
14-
"mqt.core~=3.2.1",
14+
"mqt.core~=3.3.1",
1515
]
1616
build-backend = "scikit_build_core.build"
1717

@@ -47,7 +47,7 @@ classifiers = [
4747
]
4848
requires-python = ">=3.10"
4949
dependencies = [
50-
"mqt.core[qiskit]~=3.2.1",
50+
"mqt.core[qiskit]~=3.3.1",
5151
"qiskit>=1.1",
5252
]
5353
dynamic = ["version"]
@@ -286,10 +286,10 @@ test-skip = [
286286
environment = { DEPLOY = "ON" }
287287
# The SOVERSION needs to be updated when the shared libraries are updated.
288288
repair-wheel-command = """auditwheel repair -w {dest_dir} {wheel} \
289-
--exclude libmqt-core-ir.so.3.2 \
290-
--exclude libmqt-core-qasm.so.3.2 \
291-
--exclude libmqt-core-circuit-optimizer.so.3.2 \
292-
--exclude libmqt-core-dd.so.3.2"""
289+
--exclude libmqt-core-ir.so.3.3 \
290+
--exclude libmqt-core-qasm.so.3.3 \
291+
--exclude libmqt-core-circuit-optimizer.so.3.3 \
292+
--exclude libmqt-core-dd.so.3.3"""
293293

294294
[tool.cibuildwheel.macos]
295295
environment = { MACOSX_DEPLOYMENT_TARGET = "11.0" }
@@ -318,7 +318,7 @@ build = [
318318
"pybind11>=3.0.0",
319319
"scikit-build-core>=0.11.2",
320320
"setuptools-scm>=8.3.1",
321-
"mqt.core~=3.2.1",
321+
"mqt.core~=3.3.1",
322322
]
323323
docs = [
324324
"furo>=2024.8.6",

src/CircuitSimulator.cpp

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
#include "dd/Node.hpp"
1616
#include "dd/Operations.hpp"
1717
#include "dd/StateGeneration.hpp"
18-
#include "ir/operations/ClassicControlledOperation.hpp"
18+
#include "ir/Definitions.hpp"
19+
#include "ir/operations/IfElseOperation.hpp"
1920
#include "ir/operations/NonUnitaryOperation.hpp"
2021
#include "ir/operations/OpType.hpp"
2122

@@ -85,7 +86,7 @@ auto CircuitSimulator::analyseCircuit() -> CircuitAnalysis {
8586
auto analysis = CircuitAnalysis{};
8687

8788
for (auto& op : *qc) {
88-
if (op->isClassicControlledOperation() || op->getType() == qc::Reset) {
89+
if (op->isIfElseOperation() || op->getType() == qc::Reset) {
8990
analysis.isDynamic = true;
9091
}
9192
if (const auto* measure = dynamic_cast<qc::NonUnitaryOperation*>(op.get());
@@ -156,7 +157,7 @@ CircuitSimulator::singleShot(const bool ignoreNonUnitaries) {
156157
(static_cast<double>(approximationInfo.stepNumber + 1))));
157158

158159
for (auto& op : *qc) {
159-
if (op->isNonUnitaryOperation()) {
160+
if (op->isNonUnitaryOperation() && !op->isIfElseOperation()) {
160161
if (ignoreNonUnitaries) {
161162
continue;
162163
}
@@ -186,32 +187,61 @@ CircuitSimulator::singleShot(const bool ignoreNonUnitaries) {
186187
}
187188
dd->garbageCollect();
188189
} else {
189-
if (op->isClassicControlledOperation()) {
190-
if (auto* classicallyControlledOp =
191-
dynamic_cast<qc::ClassicControlledOperation*>(op.get())) {
192-
const auto startIndex = static_cast<std::uint16_t>(
193-
classicallyControlledOp->getParameter().at(0));
194-
const auto length = static_cast<std::uint16_t>(
195-
classicallyControlledOp->getParameter().at(1));
196-
const auto expectedValue =
197-
classicallyControlledOp->getExpectedValue();
198-
unsigned int actualValue = 0;
190+
if (op->isIfElseOperation()) {
191+
if (auto* ifElseOp = dynamic_cast<qc::IfElseOperation*>(op.get())) {
192+
const auto& comparisonKind = ifElseOp->getComparisonKind();
193+
194+
std::size_t startIndex = 0;
195+
std::size_t length = 0;
196+
std::uint64_t expectedValue = 0;
197+
if (ifElseOp->getControlBit().has_value()) {
198+
startIndex = ifElseOp->getControlBit().value();
199+
length = 1;
200+
expectedValue = ifElseOp->getExpectedValueBit() ? 1U : 0U;
201+
} else {
202+
startIndex = ifElseOp->getControlRegister()->getStartIndex();
203+
length = ifElseOp->getControlRegister()->getSize();
204+
expectedValue = ifElseOp->getExpectedValueRegister();
205+
}
206+
207+
std::uint64_t actualValue = 0;
199208
for (std::size_t i = 0; i < length; i++) {
200209
actualValue |= (classicValues[startIndex + i] ? 1U : 0U) << i;
201210
}
202211

203-
// std::clog << "expected " << expected_value << " and actual value
204-
// was " << actual_value << "\n";
205-
206-
if (actualValue != expectedValue) {
212+
const auto control = [actualValue, expectedValue, comparisonKind]() {
213+
switch (comparisonKind) {
214+
case qc::ComparisonKind::Eq:
215+
return actualValue == expectedValue;
216+
case qc::ComparisonKind::Neq:
217+
return actualValue != expectedValue;
218+
case qc::ComparisonKind::Lt:
219+
return actualValue < expectedValue;
220+
case qc::ComparisonKind::Leq:
221+
return actualValue <= expectedValue;
222+
case qc::ComparisonKind::Gt:
223+
return actualValue > expectedValue;
224+
case qc::ComparisonKind::Geq:
225+
return actualValue >= expectedValue;
226+
}
227+
qc::unreachable();
228+
}();
229+
230+
if (control) {
231+
auto thenOp = ifElseOp->getThenOp()->clone();
232+
applyOperationToState(thenOp);
233+
} else if (ifElseOp->getElseOp() != nullptr) {
234+
auto elseOp = ifElseOp->getElseOp()->clone();
235+
applyOperationToState(elseOp);
236+
} else {
207237
continue;
208238
}
209239
} else {
210-
throw std::runtime_error(
211-
"Dynamic cast to ClassicControlledOperation failed.");
240+
throw std::runtime_error("Dynamic cast to IfElseOperation failed.");
212241
}
242+
} else {
243+
applyOperationToState(op);
213244
}
214-
applyOperationToState(op);
215245

216246
if (approximationInfo.stepNumber > 0 &&
217247
approximationInfo.stepFidelity < 1.0) {

src/StochasticNoiseSimulator.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include "dd/Package.hpp"
1818
#include "dd/StateGeneration.hpp"
1919
#include "ir/Definitions.hpp"
20-
#include "ir/operations/ClassicControlledOperation.hpp"
20+
#include "ir/operations/IfElseOperation.hpp"
2121
#include "ir/operations/NonUnitaryOperation.hpp"
2222
#include "ir/operations/OpType.hpp"
2323

@@ -107,12 +107,11 @@ void StochasticNoiseSimulator::runStochSimulationForId(
107107
continue;
108108
}
109109
dd::mEdge operation;
110-
if (op->isClassicControlledOperation()) {
110+
if (op->isIfElseOperation()) {
111111
// Check if the operation is controlled by a classical register
112-
const auto& classicOp =
113-
dynamic_cast<const qc::ClassicControlledOperation&>(*op);
114-
localRootEdge = applyClassicControlledOperation(
115-
classicOp, localRootEdge, *localDD, classicValues);
112+
const auto& classicOp = dynamic_cast<const qc::IfElseOperation&>(*op);
113+
localRootEdge = applyIfElseOperation(classicOp, localRootEdge, *localDD,
114+
classicValues);
116115
continue;
117116
}
118117
const auto& targets = op->getTargets();

0 commit comments

Comments
 (0)