Skip to content

Commit 7c3dc1d

Browse files
✨ Add Dynamic QFT (#946)
## Description Adds the dynamic_qft benchmark, a dynamic-circuit version of QFT using mid-circuit measurements and classically controlled phase gates. The implementation matches the regular QFT benchmark’s decomposed register order, measurement mapping, source/target qubit associations, and phase angles. Fixes #798 Assisted by: GPT 5.5 via Codex ## Checklist: <!--- This checklist serves as a reminder of a couple of things that ensure your pull request will be merged swiftly. --> - [x] The pull request only contains commits that are focused and relevant to this change. - [x] I have added appropriate tests that cover the new/changed functionality. - [x] I have updated the documentation to reflect these changes. - [x] I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals. - [x] I have added migration instructions to the upgrade guide (if needed). - [x] The changes follow the project's style guidelines and introduce no new warnings. - [x] The changes are fully tested and pass the CI checks. - [x] I have reviewed my own code changes.
2 parents fbc80b8 + 91e4a66 commit 7c3dc1d

3 files changed

Lines changed: 75 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1111

1212
### Added
1313

14+
- ✨ Add Dynamic Quantum Fourier Transform benchmark ([#946]) ([**@flowerthrower**])
1415
- ✨ Add Iterative Quantum Phase Estimation (IQPE) benchmark ([#925]) ([**@johanneswittmann9**])
1516

1617
### Fixed
@@ -130,6 +131,7 @@ _📚 Refer to the [GitHub Release Notes] for previous changelogs._
130131

131132
<!-- PR links -->
132133

134+
[#946]: https://github.com/munich-quantum-toolkit/bench/pull/946
133135
[#925]: https://github.com/munich-quantum-toolkit/bench/pull/925
134136
[#914]: https://github.com/munich-quantum-toolkit/bench/pull/914
135137
[#895]: https://github.com/munich-quantum-toolkit/bench/pull/895
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
2+
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
3+
# All rights reserved.
4+
#
5+
# SPDX-License-Identifier: MIT
6+
#
7+
# Licensed under the MIT License
8+
9+
"""Dynamic QFT benchmark definition."""
10+
11+
from __future__ import annotations
12+
13+
import numpy as np
14+
from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister
15+
16+
from ._registry import register_benchmark
17+
18+
19+
@register_benchmark("dynamic_qft", description="Dynamic Quantum Fourier Transformation (QFT)")
20+
def create_circuit(num_qubits: int) -> QuantumCircuit:
21+
"""Returns a quantum circuit implementing the Dynamic Quantum Fourier Transform algorithm.
22+
23+
More details on the “Semiclassical Fourier Transform for Quantum Computation” can be found in https://arxiv.org/abs/quant-ph/9511007
24+
25+
Arguments:
26+
num_qubits: number of qubits of the returned quantum circuit
27+
28+
Returns:
29+
QuantumCircuit: a quantum circuit implementing the Dynamic Quantum Fourier Transform algorithm
30+
"""
31+
q = QuantumRegister(num_qubits, "q")
32+
meas = ClassicalRegister(num_qubits, "meas")
33+
qc = QuantumCircuit(q, meas, name="dynamic_qft")
34+
35+
# Mirror index order of regular "qft" benchmark
36+
for qubit in reversed(range(num_qubits)):
37+
for source in reversed(range(qubit + 1, num_qubits)):
38+
source_bit = num_qubits - source - 1
39+
with qc.if_test((meas[source_bit], 1)):
40+
qc.p(np.pi * (2.0 ** (qubit - source)), q[qubit])
41+
42+
bit = num_qubits - qubit - 1
43+
qc.h(q[qubit])
44+
qc.measure(q[qubit], meas[bit])
45+
46+
return qc

tests/test_bench.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,33 @@ def test_dynamic_ghz_circuit_structure(num_qubits: int) -> None:
308308
assert ops.get("if_else", 0) == expected_if_test
309309

310310

311+
@pytest.mark.parametrize("num_qubits", [1, 2, 3, 7, 10])
312+
def test_dynamic_qft_circuit_structure(num_qubits: int) -> None:
313+
"""Verify the structure of the dynamic QFT circuit for various qubit counts."""
314+
qc = create_circuit("dynamic_qft", num_qubits)
315+
316+
# Check quantum and classical registers
317+
assert [(qreg.name, qreg.size) for qreg in qc.qregs] == [("q", num_qubits)]
318+
assert [(creg.name, creg.size) for creg in qc.cregs] == [("meas", num_qubits)]
319+
320+
ops: OrderedDict[str, int] = qc.count_ops()
321+
322+
# Check gate counts
323+
expected_phase_gates = num_qubits * (num_qubits - 1) // 2
324+
assert ops.get("h", 0) == num_qubits
325+
assert ops.get("measure", 0) == num_qubits
326+
assert ops.get("if_else", 0) == expected_phase_gates
327+
assert (
328+
sum(
329+
inst.operation.name == "p"
330+
for instruction in qc.data
331+
if isinstance(instruction.operation, IfElseOp)
332+
for inst in instruction.operation.blocks[0].data
333+
)
334+
== expected_phase_gates
335+
)
336+
337+
311338
@pytest.mark.parametrize("num_qubits", [17, 34, 51, 68])
312339
def test_shors_nine_qubit_code_circuit_structure(num_qubits: int) -> None:
313340
"""Test that Shor's 9-qubit code circuits have the expected structure.

0 commit comments

Comments
 (0)