diff --git a/dev_tools/qualtran_dev_tools/notebook_specs.py b/dev_tools/qualtran_dev_tools/notebook_specs.py index 542bcfe41..186240510 100644 --- a/dev_tools/qualtran_dev_tools/notebook_specs.py +++ b/dev_tools/qualtran_dev_tools/notebook_specs.py @@ -701,6 +701,11 @@ module=qualtran.bloqs.qft.qft_phase_gradient, bloq_specs=[qualtran.bloqs.qft.qft_phase_gradient._QFT_PHASE_GRADIENT_DOC], ), + NotebookSpecV2( + title='Semi-Classical QFT', + module=qualtran.bloqs.qft.semi_classical_qft, + bloq_specs=[qualtran.bloqs.qft.semi_classical_qft._SEMI_CLASSICAL_QFT_DOC], + ), # -------------------------------------------------------------------------- # ----- Phase Estimation ---------------------------------------- # -------------------------------------------------------------------------- diff --git a/docs/bloqs/index.rst b/docs/bloqs/index.rst index 3f0dbbac0..ba9bc752c 100644 --- a/docs/bloqs/index.rst +++ b/docs/bloqs/index.rst @@ -122,6 +122,7 @@ Bloqs Library qft/approximate_qft.ipynb qft/qft_text_book.ipynb qft/qft_phase_gradient.ipynb + qft/semi_classical_qft.ipynb phase_estimation/lp_resource_state.ipynb phase_estimation/text_book_qpe.ipynb phase_estimation/kaiser_window_state.ipynb diff --git a/qualtran/bloqs/qft/__init__.py b/qualtran/bloqs/qft/__init__.py index cf1da7994..9a53092be 100644 --- a/qualtran/bloqs/qft/__init__.py +++ b/qualtran/bloqs/qft/__init__.py @@ -14,4 +14,5 @@ from .approximate_qft import ApproximateQFT from .qft_phase_gradient import QFTPhaseGradient from .qft_text_book import QFTTextBook +from .semi_classical_qft import SemiClassicalQFT from .two_bit_ffft import TwoBitFFFT diff --git a/qualtran/bloqs/qft/semi_classical_qft.ipynb b/qualtran/bloqs/qft/semi_classical_qft.ipynb new file mode 100644 index 000000000..0ea1013ba --- /dev/null +++ b/qualtran/bloqs/qft/semi_classical_qft.ipynb @@ -0,0 +1,155 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "de9c5ff4", + "metadata": { + "cq.autogen": "title_cell" + }, + "source": [ + "# Semi-Classical QFT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70368002", + "metadata": { + "cq.autogen": "top_imports" + }, + "outputs": [], + "source": [ + "from qualtran import Bloq, CompositeBloq, BloqBuilder, Signature, Register\n", + "from qualtran import QBit, QInt, QUInt, QAny\n", + "from qualtran.drawing import show_bloq, show_call_graph, show_counts_sigma\n", + "from typing import *\n", + "import numpy as np\n", + "import sympy\n", + "import cirq" + ] + }, + { + "cell_type": "markdown", + "id": "f7a1c4c5", + "metadata": { + "cq.autogen": "SemiClassicalQFT.bloq_doc.md" + }, + "source": [ + "## `SemiClassicalQFT`\n", + "Represents QFT followed by measurement.\n", + "\n", + "When QFT is followed by measurement, we can replace all two qubit gates with classically\n", + "controlled Rz rotations (at most $n-1$ Rz rotations). The two structures (QFT + Measurement)\n", + "and SemiClassicaQFT behave statistically the same.\n", + "\n", + "\n", + "#### Registers\n", + " - `q`: A `QUInt` of `bitsize` qubits on which the QFT is performed and then measured. \n", + "\n", + "#### Parameters\n", + " - `bitsize`: Size of the input register to apply QFT on.\n", + " - `is_adjoint`: Whether to apply QFT or QFT†. \n", + "\n", + "#### References\n", + " - [Semiclassical Fourier Transform for Quantum Computation, Griffiths & Niu](https://arxiv.org/abs/quant-ph/9511007). \n", + " - [Implementation of the Semiclassical Quantum Fourier Transform in a Scalable System](https://www.science.org/doi/10.1126/science.1110335). \n", + " - [stackexchange answer, Gidney](https://quantumcomputing.stackexchange.com/a/23712). \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6da027d2", + "metadata": { + "cq.autogen": "SemiClassicalQFT.bloq_doc.py" + }, + "outputs": [], + "source": [ + "from qualtran.bloqs.qft import SemiClassicalQFT" + ] + }, + { + "cell_type": "markdown", + "id": "649aaa69", + "metadata": { + "cq.autogen": "SemiClassicalQFT.example_instances.md" + }, + "source": [ + "### Example Instances" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d39d25c", + "metadata": { + "cq.autogen": "SemiClassicalQFT.semi_classical_qft" + }, + "outputs": [], + "source": [ + "semi_classical_qft = SemiClassicalQFT(3)" + ] + }, + { + "cell_type": "markdown", + "id": "c2f31d47", + "metadata": { + "cq.autogen": "SemiClassicalQFT.graphical_signature.md" + }, + "source": [ + "#### Graphical Signature" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ac8fb19", + "metadata": { + "cq.autogen": "SemiClassicalQFT.graphical_signature.py" + }, + "outputs": [], + "source": [ + "from qualtran.drawing import show_bloqs\n", + "show_bloqs([semi_classical_qft],\n", + " ['`semi_classical_qft`'])" + ] + }, + { + "cell_type": "markdown", + "id": "bd0754a1", + "metadata": { + "cq.autogen": "SemiClassicalQFT.call_graph.md" + }, + "source": [ + "### Call Graph" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44d351d0", + "metadata": { + "cq.autogen": "SemiClassicalQFT.call_graph.py" + }, + "outputs": [], + "source": [ + "from qualtran.resource_counting.generalizers import ignore_split_join\n", + "semi_classical_qft_g, semi_classical_qft_sigma = semi_classical_qft.call_graph(max_depth=1, generalizer=ignore_split_join)\n", + "show_call_graph(semi_classical_qft_g)\n", + "show_counts_sigma(semi_classical_qft_sigma)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/qualtran/bloqs/qft/semi_classical_qft.py b/qualtran/bloqs/qft/semi_classical_qft.py new file mode 100644 index 000000000..6ae5ae45c --- /dev/null +++ b/qualtran/bloqs/qft/semi_classical_qft.py @@ -0,0 +1,71 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from functools import cached_property +from typing import TYPE_CHECKING + +import attrs + +from qualtran import Bloq, bloq_example, BloqDocSpec, QUInt, Register, Side, Signature +from qualtran.bloqs.basic_gates import Hadamard, Rz +from qualtran.bloqs.basic_gates._shims import Measure +from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator + +if TYPE_CHECKING: + from qualtran.symbolics import SymbolicInt + + +@attrs.frozen +class SemiClassicalQFT(Bloq): + r"""Represents QFT followed by measurement. + + When QFT is followed by measurement, we can replace all two qubit gates with classically + controlled Rz rotations (at most $n-1$ Rz rotations). The two structures (QFT + Measurement) + and SemiClassicaQFT behave statistically the same. + + + Registers: + q: A `QUInt` of `bitsize` qubits on which the QFT is performed and then measured. + + Args: + bitsize: Size of the input register to apply QFT on. + is_adjoint: Whether to apply QFT or QFT†. + + References: + [Semiclassical Fourier Transform for Quantum Computation, Griffiths & Niu](https://arxiv.org/abs/quant-ph/9511007) + + [Implementation of the Semiclassical Quantum Fourier Transform in a Scalable System](https://www.science.org/doi/10.1126/science.1110335) + + [stackexchange answer, Gidney](https://quantumcomputing.stackexchange.com/a/23712) + """ + + bitsize: 'SymbolicInt' + is_adjoint: bool = False + + @cached_property + def signature(self) -> 'Signature': + return Signature([Register('q', QUInt(self.bitsize), side=Side.LEFT)]) + + def build_call_graph(self, ssa: SympySymbolAllocator) -> 'BloqCountDictT': + t = ssa.new_symbol('t') + return {Hadamard(): self.bitsize, Measure(): self.bitsize, Rz(t): self.bitsize - 1} + + +@bloq_example +def _semi_classical_qft() -> SemiClassicalQFT: + semi_classical_qft = SemiClassicalQFT(3) + return semi_classical_qft + + +_SEMI_CLASSICAL_QFT_DOC = BloqDocSpec(bloq_cls=SemiClassicalQFT, examples=(_semi_classical_qft,)) diff --git a/qualtran/bloqs/qft/semi_classical_qft_test.py b/qualtran/bloqs/qft/semi_classical_qft_test.py new file mode 100644 index 000000000..faefb8e8d --- /dev/null +++ b/qualtran/bloqs/qft/semi_classical_qft_test.py @@ -0,0 +1,28 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +import sympy + +from qualtran.bloqs.qft import semi_classical_qft +from qualtran.resource_counting import get_cost_value, QECGatesCost + + +@pytest.mark.parametrize('n', [*range(1, 10), sympy.Symbol('n')]) +def test_semi_classical_qft_cost(n): + blq = semi_classical_qft.SemiClassicalQFT(n) + cost = get_cost_value(blq, QECGatesCost()) + assert cost.rotation == n - 1 + assert cost.clifford == n + assert cost.measurement == n diff --git a/qualtran/serialization/resolver_dict.py b/qualtran/serialization/resolver_dict.py index e455324b7..4de044480 100644 --- a/qualtran/serialization/resolver_dict.py +++ b/qualtran/serialization/resolver_dict.py @@ -413,6 +413,7 @@ "qualtran.bloqs.qft.approximate_qft.ApproximateQFT": qualtran.bloqs.qft.approximate_qft.ApproximateQFT, "qualtran.bloqs.qft.qft_phase_gradient.QFTPhaseGradient": qualtran.bloqs.qft.qft_phase_gradient.QFTPhaseGradient, "qualtran.bloqs.qft.qft_text_book.QFTTextBook": qualtran.bloqs.qft.qft_text_book.QFTTextBook, + "qualtran.bloqs.qft.semi_classical_qft.SemiClassicalQFT": qualtran.bloqs.qft.semi_classical_qft.SemiClassicalQFT, "qualtran.bloqs.qft.two_bit_ffft.TwoBitFFFT": qualtran.bloqs.qft.two_bit_ffft.TwoBitFFFT, "qualtran.bloqs.qsp.generalized_qsp.GeneralizedQSP": qualtran.bloqs.qsp.generalized_qsp.GeneralizedQSP, "qualtran.bloqs.qubitization.qubitization_walk_operator.QubitizationWalkOperator": qualtran.bloqs.qubitization.qubitization_walk_operator.QubitizationWalkOperator,