From 17490ade3eff7a2e1c602cd8ad39d0d4e8740277 Mon Sep 17 00:00:00 2001 From: Carla Date: Fri, 23 Jan 2026 13:56:03 +0100 Subject: [PATCH 01/21] Add IQPE benchmark --- src/mqt/bench/benchmarks/iqpe_exact.py | 75 ++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/mqt/bench/benchmarks/iqpe_exact.py diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py new file mode 100644 index 000000000..12d19e409 --- /dev/null +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +import random +from fractions import Fraction + +import numpy as np +from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister, IfElseOp + + +def create_circuit(num_qubits: int) -> QuantumCircuit: + """ + Returns a dynamic quantum circuit implementing the Iterative Quantum Phase Estimation algorithm. + + Arguments: + num_qubits: total number of qubits. + + Returns: + QuantumCircuit: a dynamic quantum circuit implementing the Iterative Quantum Phase Estimation algorithm for a phase which can be exactly estimated + + """ + # We just use 2 quantum registers: q[1] is the main register where + # the eigenstate will be encoded, q[0] is the ancillary qubit where the phase + # will be encoded. Only the ancillary qubit is measured, and the result will + # be stored in "c", the classical register. + num_qubits = num_qubits - 1 # because of ancilla qubit + q = QuantumRegister(2, "q") + c = ClassicalRegister(num_qubits, "c") + qc = QuantumCircuit(q, c, name="iqpeexact") + + # Generate a random n-bit integer as a target phase "theta". The phase can be exactly + # estimated + random.seed(10) + theta = 0 + while theta == 0: + theta = random.getrandbits(num_qubits) + lam = Fraction(0, 1) + for i in range(num_qubits): + if theta & (1 << (num_qubits - i - 1)): + lam += Fraction(1, (1 << i)) + + # print(f"Debug: theta = {theta}, lam = {float(lam)}") + + # We apply an X gate to the q[1] qubit, to prepare the target qubit in the + # |1> state + qc.x(q[1]) + + for k in range(num_qubits): + index = num_qubits - 1 - k + # We reset the ancillary qubit in order to reuse in each interation + qc.reset(q[0]) + qc.h(q[0]) + + # Controlled unitary. The angle is normalized from + # [0, 2] to [-1, 1], which minimize teh errors because uses shortest rotations + angle = float((lam * (1 << index)) % 2) + if angle > 1: + angle -= 2 + + # We use pi convention for simplicity + qc.cp(angle * np.pi, q[0], q[1]) + + # We apply phase corrections based on previous measurements. + for i in range(k): + m_index = num_qubits -1 -i + true_angle = -1.0 / (1 << (k-i)) + + with qc.if_test((c[m_index], 1)): + qc.p(true_angle * np.pi, q[0]) + + qc.h(q[0]) + # We measure and store the result for future corrections + qc.measure(q[0], c[k]) + + return qc + From ca383f23486a74a65f7a009ad9e3a0d2d0364741 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:57:05 +0000 Subject: [PATCH 02/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mqt/bench/benchmarks/iqpe_exact.py | 58 ++++++++++++++------------ 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index 12d19e409..aadcd5acb 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -1,34 +1,41 @@ +# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM +# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH +# All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# Licensed under the MIT License + from __future__ import annotations import random from fractions import Fraction import numpy as np -from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister, IfElseOp +from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister def create_circuit(num_qubits: int) -> QuantumCircuit: - """ - Returns a dynamic quantum circuit implementing the Iterative Quantum Phase Estimation algorithm. - + """Returns a dynamic quantum circuit implementing the Iterative Quantum Phase Estimation algorithm. + Arguments: num_qubits: total number of qubits. - - Returns: + + Returns: QuantumCircuit: a dynamic quantum circuit implementing the Iterative Quantum Phase Estimation algorithm for a phase which can be exactly estimated """ # We just use 2 quantum registers: q[1] is the main register where - # the eigenstate will be encoded, q[0] is the ancillary qubit where the phase + # the eigenstate will be encoded, q[0] is the ancillary qubit where the phase # will be encoded. Only the ancillary qubit is measured, and the result will # be stored in "c", the classical register. num_qubits = num_qubits - 1 # because of ancilla qubit q = QuantumRegister(2, "q") c = ClassicalRegister(num_qubits, "c") - qc = QuantumCircuit(q, c, name="iqpeexact") - + qc = QuantumCircuit(q, c, name="iqpeexact") + # Generate a random n-bit integer as a target phase "theta". The phase can be exactly - # estimated + # estimated random.seed(10) theta = 0 while theta == 0: @@ -36,40 +43,39 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: lam = Fraction(0, 1) for i in range(num_qubits): if theta & (1 << (num_qubits - i - 1)): - lam += Fraction(1, (1 << i)) - + lam += Fraction(1, (1 << i)) + # print(f"Debug: theta = {theta}, lam = {float(lam)}") - - # We apply an X gate to the q[1] qubit, to prepare the target qubit in the + + # We apply an X gate to the q[1] qubit, to prepare the target qubit in the # |1> state qc.x(q[1]) - + for k in range(num_qubits): index = num_qubits - 1 - k # We reset the ancillary qubit in order to reuse in each interation qc.reset(q[0]) - qc.h(q[0]) - + qc.h(q[0]) + # Controlled unitary. The angle is normalized from - # [0, 2] to [-1, 1], which minimize teh errors because uses shortest rotations + # [0, 2] to [-1, 1], which minimize the errors because uses shortest rotations angle = float((lam * (1 << index)) % 2) if angle > 1: angle -= 2 - + # We use pi convention for simplicity qc.cp(angle * np.pi, q[0], q[1]) - + # We apply phase corrections based on previous measurements. for i in range(k): - m_index = num_qubits -1 -i - true_angle = -1.0 / (1 << (k-i)) - + m_index = num_qubits - 1 - i + true_angle = -1.0 / (1 << (k - i)) + with qc.if_test((c[m_index], 1)): qc.p(true_angle * np.pi, q[0]) - + qc.h(q[0]) # We measure and store the result for future corrections qc.measure(q[0], c[k]) - - return qc + return qc From 87789d540e6dd9942a309cf3f6a4c7106bc27f22 Mon Sep 17 00:00:00 2001 From: Carla Date: Fri, 23 Jan 2026 14:00:25 +0100 Subject: [PATCH 03/21] added a docstring --- src/mqt/bench/benchmarks/iqpe_exact.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index aadcd5acb..67ed19d00 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -6,6 +6,8 @@ # # Licensed under the MIT License +"""Iterative Quantum Phase Estimation (IQPE).""" + from __future__ import annotations import random From 4a7bfbd67a4c5914085f0f2f26a269cce99833ec Mon Sep 17 00:00:00 2001 From: Carla Date: Fri, 23 Jan 2026 14:02:13 +0100 Subject: [PATCH 04/21] typo --- src/mqt/bench/benchmarks/iqpe_exact.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index 67ed19d00..5418b125e 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -55,7 +55,7 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: for k in range(num_qubits): index = num_qubits - 1 - k - # We reset the ancillary qubit in order to reuse in each interation + # We reset the ancillary qubit in order to reuse in each iteration qc.reset(q[0]) qc.h(q[0]) From 8438b0df3bc85e0bf37385b1cd5e16e9e73fd43b Mon Sep 17 00:00:00 2001 From: Carla Date: Fri, 23 Jan 2026 14:21:31 +0100 Subject: [PATCH 05/21] register benchmark --- src/mqt/bench/benchmarks/iqpe_exact.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index 5418b125e..7c85e13f7 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -15,8 +15,10 @@ import numpy as np from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister +from ._registry import register_benchmark +@register_benchmark("iqpeexact", description="Iterative Quantum Phase Estimation (IQPE)") def create_circuit(num_qubits: int) -> QuantumCircuit: """Returns a dynamic quantum circuit implementing the Iterative Quantum Phase Estimation algorithm. From 97e019e6c310a3a179bacc9a95ada3494cc25608 Mon Sep 17 00:00:00 2001 From: Carla Date: Fri, 23 Jan 2026 14:40:41 +0100 Subject: [PATCH 06/21] Qiskit 2.0 --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index cd8c051e1..a6a347181 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ dynamic = ["version"] dependencies = [ # Qiskit 1.3.2 contains some fixes for exporting OpenQASM 3 files - "qiskit[qasm3-import]>=1.3.2", + "qiskit[qasm3-import]>=2.0.0", "networkx>=2.8.8", "numpy>=1.22", "numpy>=1.24; python_version >= '3.11'", diff --git a/uv.lock b/uv.lock index 9e4114d99..6d6de626c 100644 --- a/uv.lock +++ b/uv.lock @@ -1529,7 +1529,7 @@ requires-dist = [ { name = "numpy", marker = "python_full_version >= '3.12'", specifier = ">=1.26" }, { name = "numpy", marker = "python_full_version >= '3.13'", specifier = ">=2.1" }, { name = "numpy", marker = "python_full_version >= '3.14'", specifier = ">=2.3.2" }, - { name = "qiskit", extras = ["qasm3-import"], specifier = ">=1.3.2" }, + { name = "qiskit", extras = ["qasm3-import"], specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.2" }, { name = "scikit-learn", marker = "python_full_version >= '3.14'", specifier = ">=1.7.2" }, ] From 187de1a4b77ce00a945f8e61d5fa0075df4aebeb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 13:43:46 +0000 Subject: [PATCH 07/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mqt/bench/benchmarks/iqpe_exact.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index 7c85e13f7..83f6f6858 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -15,6 +15,7 @@ import numpy as np from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister + from ._registry import register_benchmark From f3d31316ad933959229e65397c6ecc4c96b3472b Mon Sep 17 00:00:00 2001 From: Carla Date: Fri, 23 Jan 2026 16:21:01 +0100 Subject: [PATCH 08/21] code errors --- src/mqt/bench/benchmarks/iqpe_exact.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index 7c85e13f7..e3b1a9e8c 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -33,17 +33,20 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: # the eigenstate will be encoded, q[0] is the ancillary qubit where the phase # will be encoded. Only the ancillary qubit is measured, and the result will # be stored in "c", the classical register. + if num_qubits < 2: + raise ValueError("num_qubits must be >= 2 (1 ancilla + at least 1 phase bit)") num_qubits = num_qubits - 1 # because of ancilla qubit - q = QuantumRegister(2, "q") + q0 = QuantumRegister(1, "q0") + q1 = QuantumRegister(num_qubits, "q1") c = ClassicalRegister(num_qubits, "c") - qc = QuantumCircuit(q, c, name="iqpeexact") + qc = QuantumCircuit(q0, q1, c, name="iqpeexact") # Generate a random n-bit integer as a target phase "theta". The phase can be exactly # estimated - random.seed(10) + rng = random.seed(10) theta = 0 while theta == 0: - theta = random.getrandbits(num_qubits) + theta = rng.getrandbits(num_qubits) lam = Fraction(0, 1) for i in range(num_qubits): if theta & (1 << (num_qubits - i - 1)): @@ -53,13 +56,13 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: # We apply an X gate to the q[1] qubit, to prepare the target qubit in the # |1> state - qc.x(q[1]) + qc.x(q1[0]) for k in range(num_qubits): index = num_qubits - 1 - k # We reset the ancillary qubit in order to reuse in each iteration - qc.reset(q[0]) - qc.h(q[0]) + qc.reset(q0[0]) + qc.h(q0[0]) # Controlled unitary. The angle is normalized from # [0, 2] to [-1, 1], which minimize the errors because uses shortest rotations @@ -68,7 +71,7 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: angle -= 2 # We use pi convention for simplicity - qc.cp(angle * np.pi, q[0], q[1]) + qc.cp(angle * np.pi, q0[0], q1[0]) # We apply phase corrections based on previous measurements. for i in range(k): @@ -76,10 +79,10 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: true_angle = -1.0 / (1 << (k - i)) with qc.if_test((c[m_index], 1)): - qc.p(true_angle * np.pi, q[0]) + qc.p(true_angle * np.pi, q0[0]) - qc.h(q[0]) + qc.h(q0[0]) # We measure and store the result for future corrections - qc.measure(q[0], c[k]) + qc.measure(q0[0], c[index]) return qc From 27061228820a714057682df966e1cbb469f36e32 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 15:22:52 +0000 Subject: [PATCH 09/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mqt/bench/benchmarks/iqpe_exact.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index e88018a46..e45012616 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -35,7 +35,8 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: # will be encoded. Only the ancillary qubit is measured, and the result will # be stored in "c", the classical register. if num_qubits < 2: - raise ValueError("num_qubits must be >= 2 (1 ancilla + at least 1 phase bit)") + msg = "num_qubits must be >= 2 (1 ancilla + at least 1 phase bit)" + raise ValueError(msg) num_qubits = num_qubits - 1 # because of ancilla qubit q0 = QuantumRegister(1, "q0") q1 = QuantumRegister(num_qubits, "q1") From 79374b43416dd47413c1542d6823b596c0639993 Mon Sep 17 00:00:00 2001 From: Carla Date: Sat, 24 Jan 2026 12:10:02 +0100 Subject: [PATCH 10/21] code errors --- src/mqt/bench/benchmarks/iqpe_exact.py | 41 ++++++++++++-------------- src/mqt/bench/benchmarks/test_iqpe.py | 32 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 22 deletions(-) create mode 100644 src/mqt/bench/benchmarks/test_iqpe.py diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index e88018a46..1b6a28025 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -14,7 +14,7 @@ from fractions import Fraction import numpy as np -from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister +from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister, IfElseOp from ._registry import register_benchmark @@ -36,34 +36,31 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: # be stored in "c", the classical register. if num_qubits < 2: raise ValueError("num_qubits must be >= 2 (1 ancilla + at least 1 phase bit)") - num_qubits = num_qubits - 1 # because of ancilla qubit - q0 = QuantumRegister(1, "q0") - q1 = QuantumRegister(num_qubits, "q1") - c = ClassicalRegister(num_qubits, "c") - qc = QuantumCircuit(q0, q1, c, name="iqpeexact") + num_bits = num_qubits - 1 # because of ancilla qubit + q = QuantumRegister(num_qubits, "q") + c = ClassicalRegister(num_bits, "c") + qc = QuantumCircuit(q, c, name="iqpeexact") # Generate a random n-bit integer as a target phase "theta". The phase can be exactly # estimated - rng = random.seed(10) + rng = random.Random(10) theta = 0 while theta == 0: - theta = rng.getrandbits(num_qubits) + theta = rng.getrandbits(num_bits) lam = Fraction(0, 1) - for i in range(num_qubits): - if theta & (1 << (num_qubits - i - 1)): + for i in range(num_bits): + if theta & (1 << (num_bits - i - 1)): lam += Fraction(1, (1 << i)) - # print(f"Debug: theta = {theta}, lam = {float(lam)}") - # We apply an X gate to the q[1] qubit, to prepare the target qubit in the # |1> state - qc.x(q1[0]) + qc.x(q[0]) - for k in range(num_qubits): - index = num_qubits - 1 - k + for k in range(num_bits): + index = num_bits - 1 - k # We reset the ancillary qubit in order to reuse in each iteration - qc.reset(q0[0]) - qc.h(q0[0]) + qc.reset(q[0]) + qc.h(q[0]) # Controlled unitary. The angle is normalized from # [0, 2] to [-1, 1], which minimize the errors because uses shortest rotations @@ -72,18 +69,18 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: angle -= 2 # We use pi convention for simplicity - qc.cp(angle * np.pi, q0[0], q1[0]) + qc.cp(angle * np.pi, q[0], q[1]) # We apply phase corrections based on previous measurements. for i in range(k): - m_index = num_qubits - 1 - i + m_index = num_bits - 1 - i true_angle = -1.0 / (1 << (k - i)) with qc.if_test((c[m_index], 1)): - qc.p(true_angle * np.pi, q0[0]) + qc.p(true_angle * np.pi, q[0]) - qc.h(q0[0]) + qc.h(q[0]) # We measure and store the result for future corrections - qc.measure(q0[0], c[index]) + qc.measure(q[0], c[index]) return qc diff --git a/src/mqt/bench/benchmarks/test_iqpe.py b/src/mqt/bench/benchmarks/test_iqpe.py new file mode 100644 index 000000000..68794dabc --- /dev/null +++ b/src/mqt/bench/benchmarks/test_iqpe.py @@ -0,0 +1,32 @@ + +def test_iqpeexact_structure() -> None: + """ + Test that the Iterative Quantum Phase Estimation code circuit has the expected structure. + + Verifies: + - Quantum registers: 1 target qubit and 1 ancillary qubit (2 qubits) + - Classical register: num_qubits - 1 (for a 5 qubit input) + - 4 resets and 6 conditional operations + """ + + qc = create_circuit(5) + + assert len(qc.qubits) == 2 + assert qc.cregs[0].size == 4 + + assert qc.count_ops().get('reset') == 4 + if_else_count = sum(1 for inst in qc.data if isinstance(inst.operation, IfElseOp)) + assert if_else_count == 6, f"Expected 6 conditional operations, found {if_else_count}" + + assert qc.count_ops().get('measure') == 4 + + + + +if __name__ == "__main__": + print("\nRunning structural test...") + try: + test_iqpeexact_structure() + print("Test finished successfully") + except AssertionError as e: + print(f"Test failed: {e}") \ No newline at end of file From 27082babb2e538111e0b58e81f2f53c7d3ae6ad7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 17:58:53 +0000 Subject: [PATCH 11/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mqt/bench/benchmarks/iqpe_exact.py | 2 +- src/mqt/bench/benchmarks/test_iqpe.py | 32 +++++++++++++++----------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index 3e7e62217..ce8fb69ed 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -93,4 +93,4 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: # We measure and store the result for future corrections qc.measure(q[0], c[index]) - return qc \ No newline at end of file + return qc diff --git a/src/mqt/bench/benchmarks/test_iqpe.py b/src/mqt/bench/benchmarks/test_iqpe.py index 68794dabc..f0dd1f1f9 100644 --- a/src/mqt/bench/benchmarks/test_iqpe.py +++ b/src/mqt/bench/benchmarks/test_iqpe.py @@ -1,32 +1,36 @@ +# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM +# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH +# All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# Licensed under the MIT License + def test_iqpeexact_structure() -> None: - """ - Test that the Iterative Quantum Phase Estimation code circuit has the expected structure. - + """Test that the Iterative Quantum Phase Estimation code circuit has the expected structure. + Verifies: - Quantum registers: 1 target qubit and 1 ancillary qubit (2 qubits) - Classical register: num_qubits - 1 (for a 5 qubit input) - 4 resets and 6 conditional operations """ - qc = create_circuit(5) - + assert len(qc.qubits) == 2 assert qc.cregs[0].size == 4 - - assert qc.count_ops().get('reset') == 4 + + assert qc.count_ops().get("reset") == 4 if_else_count = sum(1 for inst in qc.data if isinstance(inst.operation, IfElseOp)) assert if_else_count == 6, f"Expected 6 conditional operations, found {if_else_count}" - - assert qc.count_ops().get('measure') == 4 - - - - + + assert qc.count_ops().get("measure") == 4 + + if __name__ == "__main__": print("\nRunning structural test...") try: test_iqpeexact_structure() print("Test finished successfully") except AssertionError as e: - print(f"Test failed: {e}") \ No newline at end of file + print(f"Test failed: {e}") From 86f7c395f48b6b0cea24a8ec156dab02cdc88dbc Mon Sep 17 00:00:00 2001 From: Carla Date: Wed, 28 Jan 2026 19:30:00 +0100 Subject: [PATCH 12/21] code errors --- src/mqt/bench/benchmarks/iqpe_exact.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index 3e7e62217..f049db4ae 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -35,21 +35,11 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: # will be encoded. Only the ancillary qubit is measured, and the result will # be stored in "c", the classical register. if num_qubits < 2: -<<<<<<< HEAD raise ValueError("num_qubits must be >= 2 (1 ancilla + at least 1 phase bit)") num_bits = num_qubits - 1 # because of ancilla qubit q = QuantumRegister(num_qubits, "q") c = ClassicalRegister(num_bits, "c") qc = QuantumCircuit(q, c, name="iqpeexact") -======= - msg = "num_qubits must be >= 2 (1 ancilla + at least 1 phase bit)" - raise ValueError(msg) - num_qubits = num_qubits - 1 # because of ancilla qubit - q0 = QuantumRegister(1, "q0") - q1 = QuantumRegister(num_qubits, "q1") - c = ClassicalRegister(num_qubits, "c") - qc = QuantumCircuit(q0, q1, c, name="iqpeexact") ->>>>>>> 27061228820a714057682df966e1cbb469f36e32 # Generate a random n-bit integer as a target phase "theta". The phase can be exactly # estimated From 6d5d2c87c2ef8a6ab37ca0d1d04bd4cb59cf4c0f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 18:31:24 +0000 Subject: [PATCH 13/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mqt/bench/benchmarks/iqpe_exact.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index 1b6a28025..27a8f23b1 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -14,7 +14,7 @@ from fractions import Fraction import numpy as np -from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister, IfElseOp +from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister from ._registry import register_benchmark @@ -35,7 +35,8 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: # will be encoded. Only the ancillary qubit is measured, and the result will # be stored in "c", the classical register. if num_qubits < 2: - raise ValueError("num_qubits must be >= 2 (1 ancilla + at least 1 phase bit)") + msg = "num_qubits must be >= 2 (1 ancilla + at least 1 phase bit)" + raise ValueError(msg) num_bits = num_qubits - 1 # because of ancilla qubit q = QuantumRegister(num_qubits, "q") c = ClassicalRegister(num_bits, "c") From aab071ef72ba28427cb9c08fe763e035d528271f Mon Sep 17 00:00:00 2001 From: Carla Date: Wed, 28 Jan 2026 21:13:28 +0100 Subject: [PATCH 14/21] erase file --- src/mqt/bench/benchmarks/test_iqpe.py | 36 --------------------------- 1 file changed, 36 deletions(-) delete mode 100644 src/mqt/bench/benchmarks/test_iqpe.py diff --git a/src/mqt/bench/benchmarks/test_iqpe.py b/src/mqt/bench/benchmarks/test_iqpe.py deleted file mode 100644 index f0dd1f1f9..000000000 --- a/src/mqt/bench/benchmarks/test_iqpe.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM -# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH -# All rights reserved. -# -# SPDX-License-Identifier: MIT -# -# Licensed under the MIT License - - -def test_iqpeexact_structure() -> None: - """Test that the Iterative Quantum Phase Estimation code circuit has the expected structure. - - Verifies: - - Quantum registers: 1 target qubit and 1 ancillary qubit (2 qubits) - - Classical register: num_qubits - 1 (for a 5 qubit input) - - 4 resets and 6 conditional operations - """ - qc = create_circuit(5) - - assert len(qc.qubits) == 2 - assert qc.cregs[0].size == 4 - - assert qc.count_ops().get("reset") == 4 - if_else_count = sum(1 for inst in qc.data if isinstance(inst.operation, IfElseOp)) - assert if_else_count == 6, f"Expected 6 conditional operations, found {if_else_count}" - - assert qc.count_ops().get("measure") == 4 - - -if __name__ == "__main__": - print("\nRunning structural test...") - try: - test_iqpeexact_structure() - print("Test finished successfully") - except AssertionError as e: - print(f"Test failed: {e}") From 1724210a631b1e4ae49a4227f4b716410729051f Mon Sep 17 00:00:00 2001 From: Carla Date: Wed, 28 Jan 2026 23:01:11 +0100 Subject: [PATCH 15/21] test --- tests/test_bench.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/test_bench.py b/tests/test_bench.py index ea46dba1a..0baacbc40 100644 --- a/tests/test_bench.py +++ b/tests/test_bench.py @@ -144,6 +144,26 @@ def test_adder_circuits(benchmark_name: str, input_value: int, kind: str) -> Non qc = create_circuit(benchmark_name, input_value, kind) assert qc.num_qubits == input_value +def test_iqpeexact_structure() -> None: + """Test that the Iterative Quantum Phase Estimation code circuit has the expected structure. + + Verifies (for a 5-qubit input): + - Quantum registers: 4 target qubits and 1 ancillary qubit + - Classical register: num_qubits - 1 (4 bits) + - 4 resets and 6 conditional operations + - 4 measurements + """ + qc = create_circuit("iqpeexact", 5) + + assert qc.num_qubits == 5 + assert qc.num_clbits == 4 + + ops = qc.count_ops() + assert ops.get("reset") == 4 + assert ops.get("measure") == 4 + + if_else_count = sum(1 for inst in qc.data if isinstance(inst.operation, IfElseOp)) + assert if_else_count == 6, f"Expected 6 conditional operations, found {if_else_count}" @pytest.mark.parametrize( ("benchmark_name", "input_value", "kind", "msg"), From 9202b773bbd68ef1344aff74353651400767f542 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 22:01:59 +0000 Subject: [PATCH 16/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_bench.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_bench.py b/tests/test_bench.py index 0baacbc40..f6f15180f 100644 --- a/tests/test_bench.py +++ b/tests/test_bench.py @@ -144,6 +144,7 @@ def test_adder_circuits(benchmark_name: str, input_value: int, kind: str) -> Non qc = create_circuit(benchmark_name, input_value, kind) assert qc.num_qubits == input_value + def test_iqpeexact_structure() -> None: """Test that the Iterative Quantum Phase Estimation code circuit has the expected structure. @@ -154,7 +155,7 @@ def test_iqpeexact_structure() -> None: - 4 measurements """ qc = create_circuit("iqpeexact", 5) - + assert qc.num_qubits == 5 assert qc.num_clbits == 4 @@ -165,6 +166,7 @@ def test_iqpeexact_structure() -> None: if_else_count = sum(1 for inst in qc.data if isinstance(inst.operation, IfElseOp)) assert if_else_count == 6, f"Expected 6 conditional operations, found {if_else_count}" + @pytest.mark.parametrize( ("benchmark_name", "input_value", "kind", "msg"), [ From c7b7e014e6b2ecbd1b8cc095eaeb4d7e7667a19b Mon Sep 17 00:00:00 2001 From: Carla Date: Thu, 29 Jan 2026 18:06:57 +0100 Subject: [PATCH 17/21] code errors --- src/mqt/bench/benchmarks/iqpe_exact.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index 27a8f23b1..a499e6c4e 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -19,7 +19,7 @@ from ._registry import register_benchmark -@register_benchmark("iqpeexact", description="Iterative Quantum Phase Estimation (IQPE)") +@register_benchmark("iqpe_exact", description="Iterative Quantum Phase Estimation (IQPE)") def create_circuit(num_qubits: int) -> QuantumCircuit: """Returns a dynamic quantum circuit implementing the Iterative Quantum Phase Estimation algorithm. @@ -55,7 +55,7 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: # We apply an X gate to the q[1] qubit, to prepare the target qubit in the # |1> state - qc.x(q[0]) + qc.x(q[1]) for k in range(num_bits): index = num_bits - 1 - k From d68cbbc0c0438de686abd5e723548101b76c20a0 Mon Sep 17 00:00:00 2001 From: Carla Date: Fri, 30 Jan 2026 18:05:24 +0100 Subject: [PATCH 18/21] code errors --- src/mqt/bench/benchmarks/iqpe_exact.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mqt/bench/benchmarks/iqpe_exact.py b/src/mqt/bench/benchmarks/iqpe_exact.py index a499e6c4e..229378dc6 100644 --- a/src/mqt/bench/benchmarks/iqpe_exact.py +++ b/src/mqt/bench/benchmarks/iqpe_exact.py @@ -40,7 +40,7 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: num_bits = num_qubits - 1 # because of ancilla qubit q = QuantumRegister(num_qubits, "q") c = ClassicalRegister(num_bits, "c") - qc = QuantumCircuit(q, c, name="iqpeexact") + qc = QuantumCircuit(q, c, name="iqpe_exact") # Generate a random n-bit integer as a target phase "theta". The phase can be exactly # estimated @@ -60,7 +60,9 @@ def create_circuit(num_qubits: int) -> QuantumCircuit: for k in range(num_bits): index = num_bits - 1 - k # We reset the ancillary qubit in order to reuse in each iteration - qc.reset(q[0]) + qc.measure(q[0], c[0]) + with qc.if_test((c[0], 1)): + qc.x(q[0]) qc.h(q[0]) # Controlled unitary. The angle is normalized from From f799bb585bde4a12857469fbffe1b870af67df7d Mon Sep 17 00:00:00 2001 From: Carla Date: Fri, 30 Jan 2026 18:17:41 +0100 Subject: [PATCH 19/21] test errors --- tests/test_bench.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_bench.py b/tests/test_bench.py index f6f15180f..1959cab18 100644 --- a/tests/test_bench.py +++ b/tests/test_bench.py @@ -145,7 +145,7 @@ def test_adder_circuits(benchmark_name: str, input_value: int, kind: str) -> Non assert qc.num_qubits == input_value -def test_iqpeexact_structure() -> None: +def test_iqpe_exact_structure() -> None: """Test that the Iterative Quantum Phase Estimation code circuit has the expected structure. Verifies (for a 5-qubit input): @@ -154,17 +154,17 @@ def test_iqpeexact_structure() -> None: - 4 resets and 6 conditional operations - 4 measurements """ - qc = create_circuit("iqpeexact", 5) + qc = create_circuit("iqpe_exact", 5) assert qc.num_qubits == 5 assert qc.num_clbits == 4 ops = qc.count_ops() - assert ops.get("reset") == 4 - assert ops.get("measure") == 4 + ops = dict(ops) # type: dict[str, int] + assert ops.get("measure") == 8 - if_else_count = sum(1 for inst in qc.data if isinstance(inst.operation, IfElseOp)) - assert if_else_count == 6, f"Expected 6 conditional operations, found {if_else_count}" + if_else_count = sum(1 for inst in qc.data if inst.operation.name == "if_else") + assert if_else_count == 10, f"Expected 6 conditional operations, found {if_else_count}" @pytest.mark.parametrize( From 78e84f4ce4c6008a48e9336c7809736e5237bb7b Mon Sep 17 00:00:00 2001 From: Carla Date: Sat, 31 Jan 2026 13:26:18 +0100 Subject: [PATCH 20/21] codecov --- tests/test_bench.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_bench.py b/tests/test_bench.py index 1959cab18..bbcb98927 100644 --- a/tests/test_bench.py +++ b/tests/test_bench.py @@ -167,6 +167,12 @@ def test_iqpe_exact_structure() -> None: assert if_else_count == 10, f"Expected 6 conditional operations, found {if_else_count}" +def test_iqpe_exact_invalid_qubit_number() -> None: + """Test that the Iterative Quantum Phase Estimation code circuit raises an error for invalid qubit numbers.""" + with pytest.raises(ValueError, match=r"num_qubits must be >= 2"): + create_circuit("iqpe_exact", 1) + + @pytest.mark.parametrize( ("benchmark_name", "input_value", "kind", "msg"), [ From a96e74a454f50cc18c61f3af7b41c315d749304b Mon Sep 17 00:00:00 2001 From: Carla Date: Sat, 31 Jan 2026 14:14:45 +0100 Subject: [PATCH 21/21] coderabbit correction --- tests/test_bench.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_bench.py b/tests/test_bench.py index bbcb98927..c0dd92793 100644 --- a/tests/test_bench.py +++ b/tests/test_bench.py @@ -151,8 +151,8 @@ def test_iqpe_exact_structure() -> None: Verifies (for a 5-qubit input): - Quantum registers: 4 target qubits and 1 ancillary qubit - Classical register: num_qubits - 1 (4 bits) - - 4 resets and 6 conditional operations - - 4 measurements + - 8 measurements (4 resets + 4 final measurements) + - 10 conditional operations (4 reset conditionals + 6 correction conditionals) """ qc = create_circuit("iqpe_exact", 5) @@ -164,7 +164,7 @@ def test_iqpe_exact_structure() -> None: assert ops.get("measure") == 8 if_else_count = sum(1 for inst in qc.data if inst.operation.name == "if_else") - assert if_else_count == 10, f"Expected 6 conditional operations, found {if_else_count}" + assert if_else_count == 10, f"Expected 10 conditional operations, found {if_else_count}" def test_iqpe_exact_invalid_qubit_number() -> None: