Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
17490ad
Add IQPE benchmark
carlareciofdz Jan 23, 2026
ca383f2
🎨 pre-commit fixes
pre-commit-ci[bot] Jan 23, 2026
87789d5
added a docstring
carlareciofdz Jan 23, 2026
4a7bfbd
typo
carlareciofdz Jan 23, 2026
8438b0d
register benchmark
carlareciofdz Jan 23, 2026
97e019e
Qiskit 2.0
carlareciofdz Jan 23, 2026
187de1a
🎨 pre-commit fixes
pre-commit-ci[bot] Jan 23, 2026
f3d3131
code errors
carlareciofdz Jan 23, 2026
b177dcf
Merge branch 'carla-IQPE' of https://github.com/carlareciofdz/bench i…
carlareciofdz Jan 23, 2026
2706122
🎨 pre-commit fixes
pre-commit-ci[bot] Jan 23, 2026
79374b4
code errors
carlareciofdz Jan 24, 2026
d0b186d
Merge branch 'carla-IQPE' of https://github.com/carlareciofdz/bench i…
carlareciofdz Jan 28, 2026
27082ba
🎨 pre-commit fixes
pre-commit-ci[bot] Jan 28, 2026
86f7c39
code errors
carlareciofdz Jan 28, 2026
3e1bfaf
Merge branch 'carla-IQPE' of https://github.com/carlareciofdz/bench i…
carlareciofdz Jan 28, 2026
6d5d2c8
🎨 pre-commit fixes
pre-commit-ci[bot] Jan 28, 2026
aab071e
erase file
carlareciofdz Jan 28, 2026
3d5b92c
Merge branch 'carla-IQPE' of https://github.com/carlareciofdz/bench i…
carlareciofdz Jan 28, 2026
1724210
test
carlareciofdz Jan 28, 2026
9202b77
🎨 pre-commit fixes
pre-commit-ci[bot] Jan 28, 2026
c7b7e01
code errors
carlareciofdz Jan 29, 2026
fb0604b
Merge branch 'carla-IQPE' of https://github.com/carlareciofdz/bench i…
carlareciofdz Jan 29, 2026
d68cbbc
code errors
carlareciofdz Jan 30, 2026
f799bb5
test errors
carlareciofdz Jan 30, 2026
78e84f4
codecov
carlareciofdz Jan 31, 2026
a96e74a
coderabbit correction
carlareciofdz Jan 31, 2026
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 pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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'",
Expand Down
89 changes: 89 additions & 0 deletions src/mqt/bench/benchmarks/iqpe_exact.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This algorithm will probably need a safeguard to limit it to something like 60 qubits because otherwise the shift operations are no longer well defined and will cause issues.
A corresponding check should be added, the docstrings should mention this limitation, and a test is probably also in order.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only covering the exact version of iQPE. Is there any particular reason for that?
It could make sense to add one more parameter to the create_circuit function that controls whether the phase is exactly representable or not.
Then, the naming and docstrings can also be adjusted accordingly to refer to this benchmark as IQPE (without the exact or inexact).

Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# 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

"""Iterative Quantum Phase Estimation (IQPE)."""

from __future__ import annotations

import random
from fractions import Fraction

import numpy as np
from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister

from ._registry import register_benchmark


@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.

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.
if num_qubits < 2:
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")
qc = QuantumCircuit(q, c, name="iqpe_exact")

# Generate a random n-bit integer as a target phase "theta". The phase can be exactly
# estimated
rng = random.Random(10)
theta = 0
while theta == 0:
theta = rng.getrandbits(num_bits)
lam = Fraction(0, 1)
for i in range(num_bits):
if theta & (1 << (num_bits - i - 1)):
lam += Fraction(1, (1 << i))

# 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_bits):
index = num_bits - 1 - k
# We reset the ancillary qubit in order to reuse in each iteration
qc.measure(q[0], c[0])
with qc.if_test((c[0], 1)):
qc.x(q[0])
Comment on lines +63 to +65
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Qiskit has a dedicated reset instruction that can be used here.
Furthermore, the first reset can be avoided as the qubit will be initialized in |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
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_bits - 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[index])

return qc
28 changes: 28 additions & 0 deletions tests/test_bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,34 @@ def test_adder_circuits(benchmark_name: str, input_value: int, kind: str) -> Non
assert qc.num_qubits == input_value


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):
- Quantum registers: 4 target qubits and 1 ancillary qubit
- Classical register: num_qubits - 1 (4 bits)
- 8 measurements (4 resets + 4 final measurements)
- 10 conditional operations (4 reset conditionals + 6 correction conditionals)
"""
qc = create_circuit("iqpe_exact", 5)

assert qc.num_qubits == 5
assert qc.num_clbits == 4

ops = qc.count_ops()
ops = dict(ops) # type: dict[str, int]
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 10 conditional operations, found {if_else_count}"
Comment on lines +148 to +167
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels a bit hard-coded to be honest. Can we generalize this slightly to cover a few more cases?



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"),
[
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading