Source code for uniqc.algorithms.core.circuits.qft
"""Quantum Fourier Transform (QFT) circuit fragment.
This module follows the *circuit fragment* design (see
the design notes in the project README):
- ``qft_circuit(n_qubits, qubits=None, swaps=True) -> Circuit``
is the canonical fragment-style API and returns a fresh
:class:`uniqc.circuit_builder.qcircuit.Circuit`.
"""
__all__ = ["qft_circuit"]
import math
from uniqc._error_hints import format_enriched_message
from uniqc.circuit_builder import Circuit
def _build_qft_fragment(
*,
n_qubits: int,
qubits: list[int] | None = None,
swaps: bool = True,
) -> Circuit:
"""Pure fragment builder: returns a fresh ``Circuit`` containing QFT."""
if qubits is None:
qubits = list(range(n_qubits))
n = len(qubits)
if n < 1:
raise ValueError(format_enriched_message("qft_circuit requires at least 1 qubit", "circuit_validation"))
fragment = Circuit()
for j in range(n):
fragment.h(qubits[j])
for k in range(j + 1, n):
angle = math.pi / (2 ** (k - j))
# Controlled-Rz emulated with CNOT decomposition
fragment.rz(qubits[k], angle / 2)
fragment.cnot(qubits[j], qubits[k])
fragment.rz(qubits[k], -angle / 2)
fragment.cnot(qubits[j], qubits[k])
if swaps:
for i in range(n // 2):
fragment.swap(qubits[i], qubits[n - 1 - i])
return fragment
[docs]
def qft_circuit(
n_qubits: int | None = None,
qubits: list[int] | None = None,
swaps: bool = True,
) -> Circuit:
r"""Build a Quantum Fourier Transform fragment.
.. code-block:: python
qft = qft_circuit(n_qubits=3) # returns a fresh Circuit
qft = qft_circuit(3, qubits=[2, 3, 4]) # explicit qubit layout
The QFT maps :math:`|j\rangle` to
:math:`\frac{1}{\sqrt{N}} \sum_{k=0}^{N-1} e^{2\pi i jk / N} |k\rangle`.
Args:
n_qubits: Number of qubits. May be ``None`` if ``qubits`` is given,
in which case it is inferred as ``max(qubits) + 1``.
qubits: Qubit indices to operate on. ``None`` defaults to
``range(n_qubits)``.
swaps: Whether to append the SWAP layer that reverses qubit order
so the output follows the standard big-endian convention.
Returns:
A fresh :class:`Circuit` containing the QFT fragment.
Raises:
ValueError: Fewer than 1 qubit specified.
"""
if n_qubits is None:
if not qubits:
raise ValueError("qft_circuit(...) requires either an integer n_qubits or a non-empty qubits list.")
n_qubits = max(qubits) + 1
return _build_qft_fragment(n_qubits=n_qubits, qubits=qubits, swaps=swaps)
[docs]
def qft_example() -> Circuit:
"""Return a 3-qubit QFT circuit, used by docs and tests as a smoke example."""
return qft_circuit(3)