mqt-core 3.0.2__cp313-cp313-win_amd64.whl → 3.2.0__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mqt-core might be problematic. Click here for more details.

Files changed (111) hide show
  1. mqt/core/__init__.py +3 -3
  2. mqt/core/_version.py +2 -2
  3. mqt/core/bin/mqt-core-algorithms.dll +0 -0
  4. mqt/core/bin/mqt-core-circuit-optimizer.dll +0 -0
  5. mqt/core/bin/mqt-core-dd.dll +0 -0
  6. mqt/core/bin/mqt-core-ds.dll +0 -0
  7. mqt/core/bin/mqt-core-ir.dll +0 -0
  8. mqt/core/bin/mqt-core-na.dll +0 -0
  9. mqt/core/bin/mqt-core-qasm.dll +0 -0
  10. mqt/core/bin/mqt-core-zx.dll +0 -0
  11. mqt/core/dd.cp313-win_amd64.pyd +0 -0
  12. mqt/core/dd.pyi +9 -22
  13. mqt/core/include/mqt-core/datastructures/DirectedAcyclicGraph.hpp +4 -4
  14. mqt/core/include/mqt-core/datastructures/DirectedGraph.hpp +7 -7
  15. mqt/core/include/mqt-core/datastructures/UndirectedGraph.hpp +8 -8
  16. mqt/core/include/mqt-core/dd/Approximation.hpp +45 -0
  17. mqt/core/include/mqt-core/dd/Complex.hpp +6 -0
  18. mqt/core/include/mqt-core/dd/ComplexNumbers.hpp +0 -18
  19. mqt/core/include/mqt-core/dd/ComputeTable.hpp +4 -1
  20. mqt/core/include/mqt-core/dd/DDDefinitions.hpp +0 -7
  21. mqt/core/include/mqt-core/dd/Edge.hpp +16 -0
  22. mqt/core/include/mqt-core/dd/Export.hpp +1 -2
  23. mqt/core/include/mqt-core/dd/Node.hpp +26 -49
  24. mqt/core/include/mqt-core/dd/Operations.hpp +27 -0
  25. mqt/core/include/mqt-core/dd/Package.hpp +141 -123
  26. mqt/core/include/mqt-core/dd/RealNumber.hpp +49 -66
  27. mqt/core/include/mqt-core/dd/RealNumberUniqueTable.hpp +14 -25
  28. mqt/core/include/mqt-core/dd/StateGeneration.hpp +143 -0
  29. mqt/core/include/mqt-core/dd/UnaryComputeTable.hpp +6 -4
  30. mqt/core/include/mqt-core/dd/UniqueTable.hpp +13 -39
  31. mqt/core/include/mqt-core/dd/statistics/PackageStatistics.hpp +8 -7
  32. mqt/core/include/mqt-core/dd/statistics/UniqueTableStatistics.hpp +0 -10
  33. mqt/core/include/mqt-core/ir/QuantumComputation.hpp +3 -0
  34. mqt/core/include/mqt-core/ir/operations/CompoundOperation.hpp +2 -0
  35. mqt/core/include/mqt-core/ir/operations/Expression.hpp +1 -1
  36. mqt/core/include/mqt-core/ir/operations/Operation.hpp +2 -2
  37. mqt/core/ir/operations.pyi +58 -86
  38. mqt/core/ir.cp313-win_amd64.pyd +0 -0
  39. mqt/core/lib/mqt-core-algorithms.lib +0 -0
  40. mqt/core/lib/mqt-core-circuit-optimizer.lib +0 -0
  41. mqt/core/lib/mqt-core-dd.lib +0 -0
  42. mqt/core/lib/mqt-core-ds.lib +0 -0
  43. mqt/core/lib/mqt-core-ir.lib +0 -0
  44. mqt/core/lib/mqt-core-na.lib +0 -0
  45. mqt/core/lib/mqt-core-qasm.lib +0 -0
  46. mqt/core/lib/mqt-core-zx.lib +0 -0
  47. mqt/core/plugins/__init__.py +0 -8
  48. mqt/core/plugins/qiskit/qiskit_to_mqt.py +6 -0
  49. mqt/core/share/cmake/mqt-core/AddMQTPythonBinding.cmake +52 -0
  50. mqt/core/share/cmake/mqt-core/PackageAddTest.cmake +4 -4
  51. mqt/core/share/cmake/mqt-core/mqt-core-config-version.cmake +3 -3
  52. mqt/core/share/cmake/mqt-core/mqt-core-config.cmake +1 -0
  53. mqt/core/share/cmake/mqt-core/mqt-core-targets.cmake +2 -2
  54. mqt_core-3.2.0.dist-info/DELVEWHEEL +2 -0
  55. {mqt_core-3.0.2.dist-info → mqt_core-3.2.0.dist-info}/METADATA +49 -23
  56. {mqt_core-3.0.2.dist-info → mqt_core-3.2.0.dist-info}/RECORD +60 -107
  57. {mqt_core-3.0.2.dist-info → mqt_core-3.2.0.dist-info}/WHEEL +1 -1
  58. mqt_core.libs/msvcp140.dll +0 -0
  59. mqt/core/include/nlohmann/adl_serializer.hpp +0 -55
  60. mqt/core/include/nlohmann/byte_container_with_subtype.hpp +0 -103
  61. mqt/core/include/nlohmann/detail/abi_macros.hpp +0 -100
  62. mqt/core/include/nlohmann/detail/conversions/from_json.hpp +0 -497
  63. mqt/core/include/nlohmann/detail/conversions/to_chars.hpp +0 -1118
  64. mqt/core/include/nlohmann/detail/conversions/to_json.hpp +0 -446
  65. mqt/core/include/nlohmann/detail/exceptions.hpp +0 -257
  66. mqt/core/include/nlohmann/detail/hash.hpp +0 -129
  67. mqt/core/include/nlohmann/detail/input/binary_reader.hpp +0 -3009
  68. mqt/core/include/nlohmann/detail/input/input_adapters.hpp +0 -492
  69. mqt/core/include/nlohmann/detail/input/json_sax.hpp +0 -727
  70. mqt/core/include/nlohmann/detail/input/lexer.hpp +0 -1633
  71. mqt/core/include/nlohmann/detail/input/parser.hpp +0 -519
  72. mqt/core/include/nlohmann/detail/input/position_t.hpp +0 -37
  73. mqt/core/include/nlohmann/detail/iterators/internal_iterator.hpp +0 -35
  74. mqt/core/include/nlohmann/detail/iterators/iter_impl.hpp +0 -751
  75. mqt/core/include/nlohmann/detail/iterators/iteration_proxy.hpp +0 -242
  76. mqt/core/include/nlohmann/detail/iterators/iterator_traits.hpp +0 -61
  77. mqt/core/include/nlohmann/detail/iterators/json_reverse_iterator.hpp +0 -130
  78. mqt/core/include/nlohmann/detail/iterators/primitive_iterator.hpp +0 -132
  79. mqt/core/include/nlohmann/detail/json_custom_base_class.hpp +0 -39
  80. mqt/core/include/nlohmann/detail/json_pointer.hpp +0 -988
  81. mqt/core/include/nlohmann/detail/json_ref.hpp +0 -78
  82. mqt/core/include/nlohmann/detail/macro_scope.hpp +0 -482
  83. mqt/core/include/nlohmann/detail/macro_unscope.hpp +0 -45
  84. mqt/core/include/nlohmann/detail/meta/call_std/begin.hpp +0 -17
  85. mqt/core/include/nlohmann/detail/meta/call_std/end.hpp +0 -17
  86. mqt/core/include/nlohmann/detail/meta/cpp_future.hpp +0 -171
  87. mqt/core/include/nlohmann/detail/meta/detected.hpp +0 -70
  88. mqt/core/include/nlohmann/detail/meta/identity_tag.hpp +0 -21
  89. mqt/core/include/nlohmann/detail/meta/is_sax.hpp +0 -159
  90. mqt/core/include/nlohmann/detail/meta/std_fs.hpp +0 -29
  91. mqt/core/include/nlohmann/detail/meta/type_traits.hpp +0 -795
  92. mqt/core/include/nlohmann/detail/meta/void_t.hpp +0 -24
  93. mqt/core/include/nlohmann/detail/output/binary_writer.hpp +0 -1838
  94. mqt/core/include/nlohmann/detail/output/output_adapters.hpp +0 -147
  95. mqt/core/include/nlohmann/detail/output/serializer.hpp +0 -988
  96. mqt/core/include/nlohmann/detail/string_concat.hpp +0 -146
  97. mqt/core/include/nlohmann/detail/string_escape.hpp +0 -72
  98. mqt/core/include/nlohmann/detail/value_t.hpp +0 -118
  99. mqt/core/include/nlohmann/json.hpp +0 -5258
  100. mqt/core/include/nlohmann/json_fwd.hpp +0 -75
  101. mqt/core/include/nlohmann/ordered_map.hpp +0 -359
  102. mqt/core/include/nlohmann/thirdparty/hedley/hedley.hpp +0 -2045
  103. mqt/core/include/nlohmann/thirdparty/hedley/hedley_undef.hpp +0 -158
  104. mqt/core/nlohmann_json.natvis +0 -278
  105. mqt/core/share/cmake/nlohmann_json/nlohmann_jsonConfig.cmake +0 -15
  106. mqt/core/share/cmake/nlohmann_json/nlohmann_jsonConfigVersion.cmake +0 -20
  107. mqt/core/share/cmake/nlohmann_json/nlohmann_jsonTargets.cmake +0 -110
  108. mqt/core/share/pkgconfig/nlohmann_json.pc +0 -4
  109. mqt_core-3.0.2.dist-info/DELVEWHEEL +0 -2
  110. {mqt_core-3.0.2.dist-info → mqt_core-3.2.0.dist-info}/entry_points.txt +0 -0
  111. {mqt_core-3.0.2.dist-info → mqt_core-3.2.0.dist-info}/licenses/LICENSE.md +0 -0
mqt/core/__init__.py CHANGED
@@ -12,14 +12,14 @@ from __future__ import annotations
12
12
 
13
13
 
14
14
  # start delvewheel patch
15
- def _delvewheel_patch_1_10_0():
15
+ def _delvewheel_patch_1_11_0():
16
16
  import os
17
17
  if os.path.isdir(libs_dir := os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, 'mqt_core.libs'))):
18
18
  os.add_dll_directory(libs_dir)
19
19
 
20
20
 
21
- _delvewheel_patch_1_10_0()
22
- del _delvewheel_patch_1_10_0
21
+ _delvewheel_patch_1_11_0()
22
+ del _delvewheel_patch_1_11_0
23
23
  # end delvewheel patch
24
24
 
25
25
  import os
mqt/core/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '3.0.2'
21
- __version_tuple__ = version_tuple = (3, 0, 2)
20
+ __version__ = version = '3.2.0'
21
+ __version_tuple__ = version_tuple = (3, 2, 0)
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
mqt/core/dd.pyi CHANGED
@@ -9,7 +9,8 @@
9
9
  """MQT Core DD - The MQT Decision Diagram Package."""
10
10
 
11
11
  from collections.abc import Iterable
12
- from typing import Any, ClassVar
12
+ from enum import Enum
13
+ from typing import Any
13
14
 
14
15
  import numpy as np
15
16
  import numpy.typing as npt
@@ -954,36 +955,22 @@ class MatrixDD:
954
955
  format_as_polar: Whether to format the edge weights in polar coordinates.
955
956
  """
956
957
 
957
- class BasisStates:
958
+ class BasisStates(Enum):
958
959
  """Enumeration of basis states."""
959
960
 
960
- __members__: ClassVar[dict[str, BasisStates]]
961
- zero: ClassVar[BasisStates]
961
+ zero = ...
962
962
  r"""The computational basis state :math:`|0\rangle`."""
963
- one: ClassVar[BasisStates]
963
+ one = ...
964
964
  r"""The computational basis state :math:`|1\rangle`."""
965
- plus: ClassVar[BasisStates]
965
+ plus = ...
966
966
  r"""The superposition state :math:`|+\rangle = \frac{1}{\sqrt{2}}(|0\rangle + |1\rangle)`."""
967
- minus: ClassVar[BasisStates]
967
+ minus = ...
968
968
  r"""The superposition state :math:`|-\rangle = \frac{1}{\sqrt{2}}(|0\rangle - |1\rangle)`."""
969
- left: ClassVar[BasisStates]
969
+ left = ...
970
970
  r"""The rotational superposition state :math:`|L\rangle = \frac{1}{\sqrt{2}}(|0\rangle + i|1\rangle)`."""
971
- right: ClassVar[BasisStates]
971
+ right = ...
972
972
  r"""The rotational superposition state :math:`|R\rangle = \frac{1}{\sqrt{2}}(|0\rangle - i|1\rangle)`."""
973
973
 
974
- def __eq__(self, other: object) -> bool: ...
975
- def __getstate__(self) -> int: ...
976
- def __hash__(self) -> int: ...
977
- def __index__(self) -> int: ...
978
- def __init__(self, value: int) -> None: ...
979
- def __int__(self) -> int: ...
980
- def __ne__(self, other: object) -> bool: ...
981
- def __setstate__(self, state: int) -> None: ...
982
- @property
983
- def name(self) -> str: ...
984
- @property
985
- def value(self) -> int: ...
986
-
987
974
  class Vector:
988
975
  """A class representing a vector of complex numbers.
989
976
 
@@ -38,10 +38,10 @@ public:
38
38
  closureMatrix[i][i] = true;
39
39
  }
40
40
  auto addEdge(const V& u, const V& v) -> void override {
41
- if (this->mapping.find(u) == this->mapping.end()) {
41
+ if (!this->mapping.contains(u)) {
42
42
  addVertex(u);
43
43
  }
44
- if (this->mapping.find(v) == this->mapping.end()) {
44
+ if (!this->mapping.contains(v)) {
45
45
  addVertex(v);
46
46
  }
47
47
  std::size_t const i = this->mapping.at(u);
@@ -62,10 +62,10 @@ public:
62
62
  }
63
63
  }
64
64
  [[nodiscard]] auto isReachable(const V& u, const V& v) const -> bool {
65
- if (this->mapping.find(u) == this->mapping.end()) {
65
+ if (!this->mapping.contains(u)) {
66
66
  throw std::invalid_argument("Vertex u not in graph.");
67
67
  }
68
- if (this->mapping.find(v) == this->mapping.end()) {
68
+ if (!this->mapping.contains(v)) {
69
69
  throw std::invalid_argument("Vertex v not in graph.");
70
70
  }
71
71
  return closureMatrix[this->mapping.at(u)][this->mapping.at(v)];
@@ -59,7 +59,7 @@ public:
59
59
  virtual ~DirectedGraph() = default;
60
60
  virtual auto addVertex(const V& v) -> void {
61
61
  // check whether the vertex is already in the graph, if so do nothing
62
- if (mapping.find(v) != mapping.end()) {
62
+ if (mapping.contains(v)) {
63
63
  std::stringstream ss;
64
64
  ss << "The vertex " << v << " is already in the graph.";
65
65
  throw std::invalid_argument(ss.str());
@@ -75,10 +75,10 @@ public:
75
75
  outDegrees.emplace_back(0);
76
76
  }
77
77
  virtual auto addEdge(const V& u, const V& v) -> void {
78
- if (mapping.find(u) == mapping.end()) {
78
+ if (!mapping.contains(u)) {
79
79
  addVertex(u);
80
80
  }
81
- if (mapping.find(v) == mapping.end()) {
81
+ if (!mapping.contains(v)) {
82
82
  addVertex(v);
83
83
  }
84
84
  const auto i = mapping.at(u);
@@ -93,7 +93,7 @@ public:
93
93
  [[nodiscard]] auto getNVertices() const -> std::size_t { return nVertices; }
94
94
  [[nodiscard]] auto getNEdges() const -> std::size_t { return nEdges; }
95
95
  [[nodiscard]] auto getInDegree(const V& v) const -> std::size_t {
96
- if (mapping.find(v) == mapping.end()) {
96
+ if (!mapping.contains(v)) {
97
97
  std::stringstream ss;
98
98
  ss << "The vertex " << v << " is not in the graph.";
99
99
  throw std::invalid_argument(ss.str());
@@ -102,7 +102,7 @@ public:
102
102
  return inDegrees[i];
103
103
  }
104
104
  [[nodiscard]] auto getOutDegree(const V& v) const -> std::size_t {
105
- if (mapping.find(v) == mapping.end()) {
105
+ if (!mapping.contains(v)) {
106
106
  std::stringstream ss;
107
107
  ss << "The vertex " << v << " is not in the graph.";
108
108
  throw std::invalid_argument(ss.str());
@@ -119,12 +119,12 @@ public:
119
119
  });
120
120
  }
121
121
  [[nodiscard]] auto isEdge(const V& u, const V& v) const -> bool {
122
- if (mapping.find(u) == mapping.end()) {
122
+ if (!mapping.contains(u)) {
123
123
  std::stringstream ss;
124
124
  ss << "The vertex " << u << " is not in the graph.";
125
125
  throw std::invalid_argument(ss.str());
126
126
  }
127
- if (mapping.find(v) == mapping.end()) {
127
+ if (!mapping.contains(v)) {
128
128
  std::stringstream ss;
129
129
  ss << "The vertex " << v << " is not in the graph.";
130
130
  throw std::invalid_argument(ss.str());
@@ -62,7 +62,7 @@ protected:
62
62
  public:
63
63
  auto addVertex(const V& v) -> void {
64
64
  // check whether the vertex is already in the graph, if so do nothing
65
- if (mapping.find(v) == mapping.end()) {
65
+ if (!mapping.contains(v)) {
66
66
  mapping[v] = nVertices;
67
67
  invMapping.emplace_back(v);
68
68
  ++nVertices;
@@ -80,10 +80,10 @@ public:
80
80
  }
81
81
  }
82
82
  auto addEdge(const V& u, const V& v, const E& e) -> void {
83
- if (mapping.find(u) == mapping.end()) {
83
+ if (!mapping.contains(u)) {
84
84
  addVertex(u);
85
85
  }
86
- if (mapping.find(v) == mapping.end()) {
86
+ if (!mapping.contains(v)) {
87
87
  addVertex(v);
88
88
  }
89
89
  const auto i = mapping.at(u);
@@ -132,7 +132,7 @@ public:
132
132
  }
133
133
  [[nodiscard]] auto getAdjacentEdges(const V& v) const
134
134
  -> std::unordered_set<std::pair<V, V>, PairHash<V, V>> {
135
- if (mapping.find(v) == mapping.end()) {
135
+ if (!mapping.contains(v)) {
136
136
  std::stringstream ss;
137
137
  ss << "The vertex " << v << " is not in the graph.";
138
138
  throw std::invalid_argument(ss.str());
@@ -149,7 +149,7 @@ public:
149
149
  return result;
150
150
  }
151
151
  [[nodiscard]] auto getNeighbours(const V& v) const -> std::unordered_set<V> {
152
- if (mapping.find(v) == mapping.end()) {
152
+ if (!mapping.contains(v)) {
153
153
  std::stringstream ss;
154
154
  ss << "The vertex " << v << " is not in the graph.";
155
155
  throw std::invalid_argument(ss.str());
@@ -165,7 +165,7 @@ public:
165
165
  return result;
166
166
  }
167
167
  [[nodiscard]] auto getDegree(const V& v) const -> std::size_t {
168
- if (mapping.find(v) == mapping.end()) {
168
+ if (!mapping.contains(v)) {
169
169
  std::stringstream ss;
170
170
  ss << "The vertex " << v << " is not in the graph.";
171
171
  throw std::invalid_argument(ss.str());
@@ -182,12 +182,12 @@ public:
182
182
  });
183
183
  }
184
184
  [[nodiscard]] auto isAdjacent(const V& u, const V& v) const -> bool {
185
- if (mapping.find(u) == mapping.end()) {
185
+ if (!mapping.contains(u)) {
186
186
  std::stringstream ss;
187
187
  ss << "The vertex " << u << " is not in the graph.";
188
188
  throw std::invalid_argument(ss.str());
189
189
  }
190
- if (mapping.find(v) == mapping.end()) {
190
+ if (!mapping.contains(v)) {
191
191
  std::stringstream ss;
192
192
  ss << "The vertex " << v << " is not in the graph.";
193
193
  throw std::invalid_argument(ss.str());
@@ -0,0 +1,45 @@
1
+ /*
2
+ * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM
3
+ * Copyright (c) 2025 Munich Quantum Software Company GmbH
4
+ * All rights reserved.
5
+ *
6
+ * SPDX-License-Identifier: MIT
7
+ *
8
+ * Licensed under the MIT License
9
+ */
10
+
11
+ #pragma once
12
+
13
+ #include "dd/Node.hpp"
14
+ #include "dd/Package.hpp"
15
+
16
+ namespace dd {
17
+
18
+ /**
19
+ * @brief Useful metadata of an approximation run.
20
+ */
21
+ struct ApproximationMetadata {
22
+ /// @brief The fidelity between the source and the approximated state.
23
+ double fidelity;
24
+ /// @brief The number of nodes visited during the mark stage.
25
+ std::size_t nodesVisited;
26
+ /// @brief The lowest qubit number that requires rebuilding.
27
+ Qubit min;
28
+ };
29
+
30
+ /**
31
+ * @brief Approximate the @p state based on fidelity. The fidelity of the
32
+ * approximated state will be at least @p fidelity.
33
+ * @details Traverses the decision diagram layer by layer in a breadth-first
34
+ * manner (iterative deepening algorithm) and eliminates edges greedily until
35
+ * the budget (1 - @p fidelity) is exhausted.
36
+ *
37
+ * @param state The DD to approximate.
38
+ * @param fidelity The desired minimum fidelity after approximation.
39
+ * @param dd The DD package to use for the approximation.
40
+ * @return Metadata about the approximation.
41
+ */
42
+ ApproximationMetadata approximate(VectorDD& state, double fidelity,
43
+ Package& dd);
44
+
45
+ } // namespace dd
@@ -88,6 +88,12 @@ struct Complex {
88
88
  */
89
89
  [[nodiscard]] bool approximatelyZero() const noexcept;
90
90
 
91
+ /// @brief Mark the complex number as used.
92
+ void mark() const noexcept;
93
+
94
+ /// @brief Unmark the complex number.
95
+ void unmark() const noexcept;
96
+
91
97
  /**
92
98
  * @brief Convert the complex number to a string.
93
99
  * @param formatted Whether to apply special formatting to the numbers.
@@ -128,24 +128,6 @@ public:
128
128
  return e;
129
129
  }
130
130
 
131
- /**
132
- * @brief Increment the reference count of a complex number.
133
- * @details This is a pass-through function that increments the reference
134
- * count of the real and imaginary parts of the given complex number.
135
- * @param c The complex number
136
- * @see RealNumberUniqueTable::incRef(RealNumber*)
137
- */
138
- void incRef(const Complex& c) const noexcept;
139
-
140
- /**
141
- * @brief Decrement the reference count of a complex number.
142
- * @details This is a pass-through function that decrements the reference
143
- * count of the real and imaginary parts of the given complex number.
144
- * @param c The complex number
145
- * @see RealNumberUniqueTable::decRef(RealNumber*)
146
- */
147
- void decRef(const Complex& c) const noexcept;
148
-
149
131
  /**
150
132
  * @brief Check whether a complex number is one of the static ones.
151
133
  * @param c The complex number.
@@ -36,11 +36,14 @@ namespace dd {
36
36
  template <class LeftOperandType, class RightOperandType, class ResultType>
37
37
  class ComputeTable {
38
38
  public:
39
+ /// Default number of buckets for the compute table
40
+ static constexpr std::size_t DEFAULT_NUM_BUCKETS = 16384U;
41
+
39
42
  /**
40
43
  * Default constructor
41
44
  * @param numBuckets Number of hash table buckets. Must be a power of two.
42
45
  */
43
- explicit ComputeTable(const size_t numBuckets = 16384U) {
46
+ explicit ComputeTable(const size_t numBuckets = DEFAULT_NUM_BUCKETS) {
44
47
  // numBuckets must be a power of two
45
48
  if ((numBuckets & (numBuckets - 1)) != 0) {
46
49
  throw std::invalid_argument("Number of buckets must be a power of two.");
@@ -32,13 +32,6 @@ namespace dd {
32
32
  */
33
33
  using Qubit = std::uint16_t;
34
34
 
35
- /**
36
- * @brief Integer type used for reference counting
37
- * @details Allows a maximum reference count of roughly 4 billion.
38
- */
39
- using RefCount = std::uint32_t;
40
- static_assert(std::is_unsigned_v<RefCount>, "RefCount should be unsigned.");
41
-
42
35
  /**
43
36
  * @brief Floating point type to use for computations
44
37
  * @note Adjusting the precision might lead to unexpected results.
@@ -88,6 +88,16 @@ template <class Node> struct Edge {
88
88
  return Edge{Node::getTerminal(), w};
89
89
  }
90
90
 
91
+ /**
92
+ * @brief Check whether an edge requires tracking.
93
+ * @param e The edge to check.
94
+ * @return Whether the edge requires tracking.
95
+ */
96
+ [[nodiscard]] static constexpr bool trackingRequired(const Edge& e) {
97
+ return !e.isTerminal() || !constants::isStaticNumber(e.w.r) ||
98
+ !constants::isStaticNumber(e.w.i);
99
+ }
100
+
91
101
  /**
92
102
  * @brief Check whether this is a terminal
93
103
  * @return whether this is a terminal
@@ -131,6 +141,12 @@ template <class Node> struct Edge {
131
141
  */
132
142
  [[nodiscard]] std::size_t size() const;
133
143
 
144
+ /// @brief Mark the edge as used.
145
+ void mark() const noexcept;
146
+
147
+ /// @brief Unmark the edge.
148
+ void unmark() const noexcept;
149
+
134
150
  private:
135
151
  /**
136
152
  * @brief Recursively traverse the DD and count the number of nodes
@@ -163,8 +163,7 @@ static std::ostream& memoryNode(const Edge<Node>& e, std::ostream& os) {
163
163
  os << nodelabel << "[label=<";
164
164
  os << R"(<font point-size="10"><table border="1" cellspacing="0" cellpadding="2" style="rounded">)";
165
165
  os << R"(<tr><td colspan=")" << n << R"(" border="1" sides="B">)" << std::hex
166
- << reinterpret_cast<std::uintptr_t>(e.p) << std::dec
167
- << " ref: " << e.p->ref << "</td></tr>";
166
+ << reinterpret_cast<std::uintptr_t>(e.p) << std::dec << "</td></tr>";
168
167
  os << "<tr>";
169
168
  for (std::size_t i = 0; i < n; ++i) {
170
169
  os << "<td port=\"" << i << R"(" href="javascript:;" border="0" tooltip=")"
@@ -18,7 +18,6 @@
18
18
  #include <array>
19
19
  #include <cassert>
20
20
  #include <cstdint>
21
- #include <limits>
22
21
 
23
22
  namespace dd {
24
23
 
@@ -27,11 +26,9 @@ namespace dd {
27
26
  * @details This class is used to store common information for all DD nodes.
28
27
  * The `flags` makes the implicit padding explicit and can be used for storing
29
28
  * node properties.
30
- * Data Layout (8)|(4|2|2) = 16B.
29
+ * Data Layout (8)|(2|2|4) = 16B.
31
30
  */
32
31
  struct NodeBase : LLBase {
33
- /// Reference count
34
- RefCount ref = 0;
35
32
  /// Variable index
36
33
  Qubit v{};
37
34
 
@@ -40,13 +37,28 @@ struct NodeBase : LLBase {
40
37
  * @details Not required for all node types, but padding is required either
41
38
  * way.
42
39
  *
43
- * 0b1000 = marks a reduced dm node,
44
- * 0b100 = marks a dm (tmp flag),
45
- * 0b10 = mark first path edge (tmp flag),
46
- * 0b1 = mark path is conjugated (tmp flag)
40
+ * 0b10000 = mark flag used for mark-and-sweep garbage collection,
41
+ * 0b1000 = marks a reduced dm node,
42
+ * 0b100 = marks a dm (tmp flag),
43
+ * 0b10 = mark first path edge (tmp flag),
44
+ * 0b1 = mark path is conjugated (tmp flag)
47
45
  */
48
46
  std::uint16_t flags = 0;
49
47
 
48
+ /// Mark flag used for mark-and-sweep garbage collection
49
+ static constexpr std::uint16_t MARK_FLAG = 0b10000U;
50
+
51
+ /// @brief Whether a node is marked as used.
52
+ [[nodiscard]] bool isMarked() const noexcept {
53
+ return (flags & MARK_FLAG) != 0U;
54
+ }
55
+
56
+ /// @brief Mark the node as used.
57
+ void mark() noexcept { flags |= MARK_FLAG; }
58
+
59
+ /// @brief Unmark the node.
60
+ void unmark() noexcept { flags &= static_cast<uint16_t>(~MARK_FLAG); }
61
+
50
62
  /// Getter for the next object.
51
63
  [[nodiscard]] NodeBase* next() const noexcept {
52
64
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
@@ -68,9 +80,12 @@ struct NodeBase : LLBase {
68
80
  static constexpr NodeBase* getTerminal() noexcept { return nullptr; }
69
81
  };
70
82
 
83
+ static_assert(sizeof(NodeBase) == 16);
84
+ static_assert(alignof(NodeBase) == 8);
85
+
71
86
  /**
72
87
  * @brief A vector DD node
73
- * @details Data Layout (8)|(4|2|2)|(24|24) = 64B
88
+ * @details Data Layout (8)|(2|2|4)|(24|24) = 64B
74
89
  */
75
90
  struct vNode final : NodeBase { // NOLINT(readability-identifier-naming)
76
91
  std::array<Edge<vNode>, RADIX> e{}; // edges out of this node
@@ -89,7 +104,7 @@ using VectorDD = vEdge;
89
104
 
90
105
  /**
91
106
  * @brief A matrix DD node
92
- * @details Data Layout (8)|(4|2|2)|(24|24|24|24) = 112B
107
+ * @details Data Layout (8)|(2|2|4)|(24|24|24|24) = 112B
93
108
  */
94
109
  struct mNode final : NodeBase { // NOLINT(readability-identifier-naming)
95
110
  std::array<Edge<mNode>, NEDGE> e{}; // edges out of this node
@@ -108,7 +123,7 @@ using MatrixDD = mEdge;
108
123
 
109
124
  /**
110
125
  * @brief A density matrix DD node
111
- * @details Data Layout (8)|(4|2|2)|(24|24|24|24) = 112B
126
+ * @details Data Layout (8)|(2|2|4)|(24|24|24|24) = 112B
112
127
  */
113
128
  struct dNode final : NodeBase { // NOLINT(readability-identifier-naming)
114
129
  std::array<Edge<dNode>, NEDGE> e{}; // edges out of this node
@@ -205,42 +220,4 @@ static inline dEdge densityFromMatrixEdge(const mEdge& e) {
205
220
  return dEdge{reinterpret_cast<dNode*>(e.p), e.w};
206
221
  }
207
222
 
208
- /**
209
- * @brief Increment the reference count of a node.
210
- * @details This function increments the reference count of a node. If the
211
- * reference count has saturated (i.e. reached the maximum value of RefCount)
212
- * the reference count is not incremented.
213
- * @param p A pointer to the node to increment the reference count of.
214
- * @returns Whether the reference count was incremented.
215
- * @note Typically, you do not want to call this function directly. Instead,
216
- * use the UniqueTable::incRef(Node*) function.
217
- */
218
- [[nodiscard]] static constexpr bool incRef(NodeBase* p) noexcept {
219
- if (p == nullptr || p->ref == std::numeric_limits<RefCount>::max()) {
220
- return false;
221
- }
222
- ++p->ref;
223
- return true;
224
- }
225
-
226
- /**
227
- * @brief Decrement the reference count of a node.
228
- * @details This function decrements the reference count of a node. If the
229
- * reference count has saturated (i.e. reached the maximum value of RefCount)
230
- * the reference count is not decremented.
231
- * @param p A pointer to the node to decrement the reference count of.
232
- * @returns Whether the reference count was decremented.
233
- * @note Typically, you do not want to call this function directly. Instead,
234
- * use the UniqueTable::decRef(Node*) function.
235
- */
236
- [[nodiscard]] static constexpr bool decRef(NodeBase* p) noexcept {
237
- if (p == nullptr || p->ref == std::numeric_limits<RefCount>::max()) {
238
- return false;
239
- }
240
- assert(p->ref != 0 &&
241
- "Reference count of Node must not be zero before decrement");
242
- --p->ref;
243
- return true;
244
- }
245
-
246
223
  } // namespace dd
@@ -204,6 +204,33 @@ applyClassicControlledOperation(const qc::ClassicControlledOperation& op,
204
204
  const std::vector<bool>& measurements,
205
205
  const qc::Permutation& permutation = {});
206
206
 
207
+ /**
208
+ * @brief Check whether @p op is virtually executable.
209
+ *
210
+ * @param op The operation in question.
211
+ * @return Whether @p op is virtually executable.
212
+ */
213
+ bool isExecutableVirtually(const qc::Operation& op) noexcept;
214
+
215
+ /**
216
+ * @brief Apply virtual operation @p op.
217
+ *
218
+ * @param op The virtual operation to apply.
219
+ * @param permutation If suitable, the to be updated permutation.
220
+ */
221
+ void applyVirtualOperation(const qc::Operation& op,
222
+ qc::Permutation& permutation) noexcept;
223
+
224
+ /**
225
+ * @brief Apply global phase to a given DD.
226
+ *
227
+ * @param in The input DD
228
+ * @param phase The phase to apply
229
+ * @param dd The DD package to use
230
+ * @return The output DD
231
+ */
232
+ VectorDD applyGlobalPhase(VectorDD& in, const fp& phase, Package& dd);
233
+
207
234
  /**
208
235
  * @brief Change the permutation of a given DD.
209
236
  *