diff --git a/dev_tools/qualtran_dev_tools/notebook_specs.py b/dev_tools/qualtran_dev_tools/notebook_specs.py index e5260b455..292f56869 100644 --- a/dev_tools/qualtran_dev_tools/notebook_specs.py +++ b/dev_tools/qualtran_dev_tools/notebook_specs.py @@ -120,6 +120,8 @@ import qualtran.bloqs.rotations.phasing_via_cost_function import qualtran.bloqs.rotations.programmable_rotation_gate_array import qualtran.bloqs.rotations.quantum_variable_rotation +import qualtran.bloqs.rotations.rz_via_phase_gradient +import qualtran.bloqs.rotations.zpow_via_phase_gradient import qualtran.bloqs.state_preparation.black_box_prepare import qualtran.bloqs.state_preparation.prepare_base import qualtran.bloqs.state_preparation.prepare_uniform_superposition @@ -636,6 +638,18 @@ qualtran.bloqs.rotations.hamming_weight_phasing._HAMMING_WEIGHT_PHASING_VIA_PHASE_GRADIENT_DOC, ], ), + NotebookSpecV2( + title='ZPow Rotation via Phase Gradient', + module=qualtran.bloqs.rotations.zpow_via_phase_gradient, + bloq_specs=[ + qualtran.bloqs.rotations.zpow_via_phase_gradient._ZPOW_CONST_VIA_PHASE_GRADIENT_DOC + ], + ), + NotebookSpecV2( + title='Rz Rotation via Phase Gradient', + module=qualtran.bloqs.rotations.rz_via_phase_gradient, + bloq_specs=[qualtran.bloqs.rotations.rz_via_phase_gradient._RZ_VIA_PHASE_GRADIENT_DOC], + ), NotebookSpecV2( title='Programmable Rotation Gate Array', module=qualtran.bloqs.rotations.programmable_rotation_gate_array, diff --git a/docs/bloqs/index.rst b/docs/bloqs/index.rst index d827dfaad..3ed5dfe35 100644 --- a/docs/bloqs/index.rst +++ b/docs/bloqs/index.rst @@ -108,6 +108,8 @@ Bloqs Library rotations/phasing_via_cost_function.ipynb rotations/phase_gradient.ipynb rotations/hamming_weight_phasing.ipynb + rotations/zpow_via_phase_gradient.ipynb + rotations/rz_via_phase_gradient.ipynb rotations/programmable_rotation_gate_array.ipynb qft/two_bit_ffft.ipynb qft/approximate_qft.ipynb diff --git a/qualtran/bloqs/rotations/__init__.py b/qualtran/bloqs/rotations/__init__.py index 48c79d877..e6c63bdf4 100644 --- a/qualtran/bloqs/rotations/__init__.py +++ b/qualtran/bloqs/rotations/__init__.py @@ -24,3 +24,5 @@ from qualtran.bloqs.rotations.phasing_via_cost_function import PhasingViaCostFunction from qualtran.bloqs.rotations.programmable_rotation_gate_array import ProgrammableRotationGateArray from qualtran.bloqs.rotations.quantum_variable_rotation import QvrPhaseGradient, QvrZPow +from qualtran.bloqs.rotations.rz_via_phase_gradient import RzViaPhaseGradient +from qualtran.bloqs.rotations.zpow_via_phase_gradient import ZPowConstViaPhaseGradient diff --git a/qualtran/bloqs/rotations/rz_via_phase_gradient.ipynb b/qualtran/bloqs/rotations/rz_via_phase_gradient.ipynb new file mode 100644 index 000000000..75e37a757 --- /dev/null +++ b/qualtran/bloqs/rotations/rz_via_phase_gradient.ipynb @@ -0,0 +1,168 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "bbc3afcf", + "metadata": { + "cq.autogen": "title_cell" + }, + "source": [ + "# Rz Rotation via Phase Gradient" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6ca3000", + "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": "4d0db53e", + "metadata": { + "cq.autogen": "RzViaPhaseGradient.bloq_doc.md" + }, + "source": [ + "## `RzViaPhaseGradient`\n", + "Apply a controlled-Rz using a phase gradient state.\n", + "\n", + "Implements the following unitary action:\n", + "\n", + "$$\n", + " |\\psi\\rangle \\otimes |x\\rangle \\mapsto \\text{Rz}(4 \\pi x) |\\psi\\rangle \\otimes |x\\rangle\n", + "$$\n", + "\n", + "for every state $|\\psi\\rangle$ and every $x$, or equivalently\n", + "\n", + "$$\n", + " |b\\rangle|x\\rangle \\mapsto |b\\rangle e^{- (-1)^b i x/2} |x\\rangle\n", + "$$\n", + "\n", + "for every $b \\in \\{0, 1\\}$ and every $x$.\n", + "\n", + "To apply an $\\text{Rz}(\\theta) = e^{-i Z \\theta/2}$, the angle register $x$ should store $\\theta/(4\\pi)$.\n", + "\n", + "#### Parameters\n", + " - `angle_dtype`: Data type for the `angle_data` register.\n", + " - `phasegrad_dtype`: Data type for the phase gradient register. \n", + "\n", + "#### Registers\n", + " - `q`: The qubit to apply Rz on.\n", + " - `angle`: The rotation angle in radians.\n", + " - `phase_grad`: The phase gradient register of sufficient width. \n", + "\n", + "#### References\n", + " - [Compilation of Fault-Tolerant Quantum Heuristics for Combinatorial Optimization](https://arxiv.org/abs/2007.07391). Section II-C: Oracles for phasing by cost function. Appendix A: Addition for controlled rotations.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88ae8ba0", + "metadata": { + "cq.autogen": "RzViaPhaseGradient.bloq_doc.py" + }, + "outputs": [], + "source": [ + "from qualtran.bloqs.rotations import RzViaPhaseGradient" + ] + }, + { + "cell_type": "markdown", + "id": "f3d5ab59", + "metadata": { + "cq.autogen": "RzViaPhaseGradient.example_instances.md" + }, + "source": [ + "### Example Instances" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16a874c9", + "metadata": { + "cq.autogen": "RzViaPhaseGradient.rz_via_phase_gradient" + }, + "outputs": [], + "source": [ + "from qualtran import QFxp\n", + "\n", + "rz_via_phase_gradient = RzViaPhaseGradient(angle_dtype=QFxp(4, 4), phasegrad_dtype=QFxp(4, 4))" + ] + }, + { + "cell_type": "markdown", + "id": "ca4ac4bc", + "metadata": { + "cq.autogen": "RzViaPhaseGradient.graphical_signature.md" + }, + "source": [ + "#### Graphical Signature" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92d7b03c", + "metadata": { + "cq.autogen": "RzViaPhaseGradient.graphical_signature.py" + }, + "outputs": [], + "source": [ + "from qualtran.drawing import show_bloqs\n", + "show_bloqs([rz_via_phase_gradient],\n", + " ['`rz_via_phase_gradient`'])" + ] + }, + { + "cell_type": "markdown", + "id": "03999011", + "metadata": { + "cq.autogen": "RzViaPhaseGradient.call_graph.md" + }, + "source": [ + "### Call Graph" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0cc79d3", + "metadata": { + "cq.autogen": "RzViaPhaseGradient.call_graph.py" + }, + "outputs": [], + "source": [ + "from qualtran.resource_counting.generalizers import ignore_split_join\n", + "rz_via_phase_gradient_g, rz_via_phase_gradient_sigma = rz_via_phase_gradient.call_graph(max_depth=1, generalizer=ignore_split_join)\n", + "show_call_graph(rz_via_phase_gradient_g)\n", + "show_counts_sigma(rz_via_phase_gradient_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/rotations/rz_via_phase_gradient.py b/qualtran/bloqs/rotations/rz_via_phase_gradient.py index 00e71e2ee..d3ec380d2 100644 --- a/qualtran/bloqs/rotations/rz_via_phase_gradient.py +++ b/qualtran/bloqs/rotations/rz_via_phase_gradient.py @@ -17,6 +17,7 @@ Bloq, bloq_example, BloqBuilder, + BloqDocSpec, QBit, QDType, QUInt, @@ -109,3 +110,8 @@ def _rz_via_phase_gradient() -> RzViaPhaseGradient: rz_via_phase_gradient = RzViaPhaseGradient(angle_dtype=QFxp(4, 4), phasegrad_dtype=QFxp(4, 4)) return rz_via_phase_gradient + + +_RZ_VIA_PHASE_GRADIENT_DOC = BloqDocSpec( + bloq_cls=RzViaPhaseGradient, examples=[_rz_via_phase_gradient] +) diff --git a/qualtran/bloqs/rotations/rz_via_phase_gradient_test.py b/qualtran/bloqs/rotations/rz_via_phase_gradient_test.py index 110583b25..4fb5e7987 100644 --- a/qualtran/bloqs/rotations/rz_via_phase_gradient_test.py +++ b/qualtran/bloqs/rotations/rz_via_phase_gradient_test.py @@ -16,6 +16,7 @@ import sympy from attrs import frozen +import qualtran.testing as qlt_testing from qualtran import Bloq, BloqBuilder, QBit, QFxp, QUInt, Signature, Soquet, SoquetT from qualtran.bloqs.basic_gates import IntState, Rz from qualtran.bloqs.rotations.phase_gradient import PhaseGradientState @@ -87,3 +88,8 @@ def test_tensor(bitsize: int): expected = Rz(theta).tensor_contract() np.testing.assert_allclose(actual, expected, atol=1 / 2**bitsize) + + +@pytest.mark.notebook +def test_notebook(): + qlt_testing.execute_notebook('rz_via_phase_gradient') diff --git a/qualtran/bloqs/rotations/zpow_via_phase_gradient.ipynb b/qualtran/bloqs/rotations/zpow_via_phase_gradient.ipynb new file mode 100644 index 000000000..fda19c320 --- /dev/null +++ b/qualtran/bloqs/rotations/zpow_via_phase_gradient.ipynb @@ -0,0 +1,188 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7e96cff5", + "metadata": { + "cq.autogen": "title_cell" + }, + "source": [ + "# ZPow Rotation via Phase Gradient" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "197bfd0b", + "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": "a1b0782f", + "metadata": { + "cq.autogen": "ZPowConstViaPhaseGradient.bloq_doc.md" + }, + "source": [ + "## `ZPowConstViaPhaseGradient`\n", + "Apply an $Z**t$ on a qubit using a phase gradient state.\n", + "\n", + "This bloq implements a `Z**t` by conditionally loading `t/2` into a quantum\n", + "register, conditioned on the qubit `q` (rotation target), and then adding\n", + "this value to the phase gradient to get a phase kickback, and uncomputes the load.\n", + "This controlled-load trick is taken from Ref. [2], Fig 2a.\n", + "\n", + "See :class:`PhaseGradientState` for details on phase gradients.\n", + "\n", + "It loads an approximation of `t/2` to `phase_grad_bitsize` bits,\n", + "which is loaded using `phase_grad_bitsize` clean ancilla.\n", + "\n", + "The total Tofolli cost is `phase_grad_bitsize - 2`.\n", + "\n", + "\n", + "#### Parameters\n", + " - `exponent`: value of `t` to apply `Z**t`\n", + " - `phase_grad_bitsize`: number of qubits of the phase gradient state. \n", + "\n", + "#### Registers\n", + " - `q`: qubit to apply rotation on.\n", + " - `phase_grad`: phase gradient state of type `QFxp` with `phase_grad_bitsize` fractional bits. \n", + "\n", + "#### References\n", + " - [Improved quantum circuits for elliptic curve discrete logarithms](https://arxiv.org/abs/2001.09580). Haner et al. 2020. Section 3: Components. \"Integer addition\" and Fig 2a.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9111c04", + "metadata": { + "cq.autogen": "ZPowConstViaPhaseGradient.bloq_doc.py" + }, + "outputs": [], + "source": [ + "from qualtran.bloqs.rotations import ZPowConstViaPhaseGradient" + ] + }, + { + "cell_type": "markdown", + "id": "b09c61b5", + "metadata": { + "cq.autogen": "ZPowConstViaPhaseGradient.example_instances.md" + }, + "source": [ + "### Example Instances" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab048833", + "metadata": { + "cq.autogen": "ZPowConstViaPhaseGradient.zpow_const_via_phase_grad" + }, + "outputs": [], + "source": [ + "zpow_const_via_phase_grad = ZPowConstViaPhaseGradient.from_precision(3 / 8, eps=1e-11)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f61b0a60", + "metadata": { + "cq.autogen": "ZPowConstViaPhaseGradient.zpow_const_via_phase_grad_symb_prec" + }, + "outputs": [], + "source": [ + "eps = sympy.symbols(\"eps\")\n", + "zpow_const_via_phase_grad_symb_prec = ZPowConstViaPhaseGradient.from_precision(3 / 8, eps=eps)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66d60de6", + "metadata": { + "cq.autogen": "ZPowConstViaPhaseGradient.zpow_const_via_phase_grad_symb_angle" + }, + "outputs": [], + "source": [ + "t = sympy.symbols(\"t\")\n", + "zpow_const_via_phase_grad_symb_angle = ZPowConstViaPhaseGradient.from_precision(t, eps=1e-11)" + ] + }, + { + "cell_type": "markdown", + "id": "9b31feb6", + "metadata": { + "cq.autogen": "ZPowConstViaPhaseGradient.graphical_signature.md" + }, + "source": [ + "#### Graphical Signature" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "faa5dba0", + "metadata": { + "cq.autogen": "ZPowConstViaPhaseGradient.graphical_signature.py" + }, + "outputs": [], + "source": [ + "from qualtran.drawing import show_bloqs\n", + "show_bloqs([zpow_const_via_phase_grad, zpow_const_via_phase_grad_symb_prec, zpow_const_via_phase_grad_symb_angle],\n", + " ['`zpow_const_via_phase_grad`', '`zpow_const_via_phase_grad_symb_prec`', '`zpow_const_via_phase_grad_symb_angle`'])" + ] + }, + { + "cell_type": "markdown", + "id": "91234700", + "metadata": { + "cq.autogen": "ZPowConstViaPhaseGradient.call_graph.md" + }, + "source": [ + "### Call Graph" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93ec7137", + "metadata": { + "cq.autogen": "ZPowConstViaPhaseGradient.call_graph.py" + }, + "outputs": [], + "source": [ + "from qualtran.resource_counting.generalizers import ignore_split_join\n", + "zpow_const_via_phase_grad_g, zpow_const_via_phase_grad_sigma = zpow_const_via_phase_grad.call_graph(max_depth=1, generalizer=ignore_split_join)\n", + "show_call_graph(zpow_const_via_phase_grad_g)\n", + "show_counts_sigma(zpow_const_via_phase_grad_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/rotations/zpow_via_phase_gradient.py b/qualtran/bloqs/rotations/zpow_via_phase_gradient.py index c1b5ff1d2..b7d7d605d 100644 --- a/qualtran/bloqs/rotations/zpow_via_phase_gradient.py +++ b/qualtran/bloqs/rotations/zpow_via_phase_gradient.py @@ -21,6 +21,7 @@ Bloq, bloq_example, BloqBuilder, + BloqDocSpec, DecomposeTypeError, QBit, QFxp, @@ -142,13 +143,23 @@ def _zpow_const_via_phase_grad() -> ZPowConstViaPhaseGradient: @bloq_example(generalizer=ignore_alloc_free) def _zpow_const_via_phase_grad_symb_prec() -> ZPowConstViaPhaseGradient: - eps = sympy.symbols(r"\epsilon") + eps = sympy.symbols("eps") zpow_const_via_phase_grad_symb_prec = ZPowConstViaPhaseGradient.from_precision(3 / 8, eps=eps) return zpow_const_via_phase_grad_symb_prec @bloq_example(generalizer=ignore_alloc_free) def _zpow_const_via_phase_grad_symb_angle() -> ZPowConstViaPhaseGradient: - t = sympy.symbols(r"t") + t = sympy.symbols("t") zpow_const_via_phase_grad_symb_angle = ZPowConstViaPhaseGradient.from_precision(t, eps=1e-11) return zpow_const_via_phase_grad_symb_angle + + +_ZPOW_CONST_VIA_PHASE_GRADIENT_DOC = BloqDocSpec( + bloq_cls=ZPowConstViaPhaseGradient, + examples=[ + _zpow_const_via_phase_grad, + _zpow_const_via_phase_grad_symb_prec, + _zpow_const_via_phase_grad_symb_angle, + ], +) diff --git a/qualtran/bloqs/rotations/zpow_via_phase_gradient_test.py b/qualtran/bloqs/rotations/zpow_via_phase_gradient_test.py index 10d5cec75..17fa1e59b 100644 --- a/qualtran/bloqs/rotations/zpow_via_phase_gradient_test.py +++ b/qualtran/bloqs/rotations/zpow_via_phase_gradient_test.py @@ -14,6 +14,7 @@ import pytest from attrs import frozen +import qualtran.testing as qlt_testing from qualtran import Bloq, BloqBuilder, Signature, Soquet, SoquetT from qualtran.bloqs.basic_gates import ZPowGate from qualtran.bloqs.rotations.phase_gradient import PhaseGradientState @@ -36,9 +37,6 @@ ], ) def test_examples(bloq_autotester, bloq): - if bloq_autotester.check_name == 'serialize': - pytest.skip() - bloq_autotester(bloq) @@ -95,3 +93,8 @@ def test_unitary(exponent: float, phase_grad_bitsize: int): actual = bloq.tensor_contract() expected = ZPowGate(exponent).tensor_contract() assert_unitaries_equivalent_upto_global_phase(actual, expected, atol=2**-phase_grad_bitsize) + + +@pytest.mark.notebook +def test_notebook(): + qlt_testing.execute_notebook('zpow_via_phase_gradient') diff --git a/qualtran/serialization/resolver_dict.py b/qualtran/serialization/resolver_dict.py index cd01026fb..d81f9030a 100644 --- a/qualtran/serialization/resolver_dict.py +++ b/qualtran/serialization/resolver_dict.py @@ -147,6 +147,7 @@ import qualtran.bloqs.rotations.programmable_rotation_gate_array import qualtran.bloqs.rotations.quantum_variable_rotation import qualtran.bloqs.rotations.rz_via_phase_gradient +import qualtran.bloqs.rotations.zpow_via_phase_gradient import qualtran.bloqs.state_preparation.black_box_prepare import qualtran.bloqs.state_preparation.prepare_base import qualtran.bloqs.state_preparation.prepare_uniform_superposition @@ -427,6 +428,7 @@ "qualtran.bloqs.rotations.quantum_variable_rotation.QvrPhaseGradient": qualtran.bloqs.rotations.quantum_variable_rotation.QvrPhaseGradient, "qualtran.bloqs.rotations.quantum_variable_rotation.QvrZPow": qualtran.bloqs.rotations.quantum_variable_rotation.QvrZPow, "qualtran.bloqs.rotations.rz_via_phase_gradient.RzViaPhaseGradient": qualtran.bloqs.rotations.rz_via_phase_gradient.RzViaPhaseGradient, + "qualtran.bloqs.rotations.zpow_via_phase_gradient.ZPowConstViaPhaseGradient": qualtran.bloqs.rotations.zpow_via_phase_gradient.ZPowConstViaPhaseGradient, "qualtran.bloqs.state_preparation.prepare_uniform_superposition.PrepareUniformSuperposition": qualtran.bloqs.state_preparation.prepare_uniform_superposition.PrepareUniformSuperposition, "qualtran.bloqs.state_preparation.black_box_prepare.BlackBoxPrepare": qualtran.bloqs.state_preparation.black_box_prepare.BlackBoxPrepare, "qualtran.bloqs.state_preparation.prepare_base.PrepareOracle": qualtran.bloqs.state_preparation.prepare_base.PrepareOracle,