{ "cells": [ { "cell_type": "markdown", "id": "c06f42bd", "metadata": {}, "source": [ "# Positive Register-Incremented and Phase-Gradient Rotations\n", "\n", "**Download Notebook** - {nb-download}`register_incremented_rotation.ipynb`\n", "\n", "This notebook demonstrates the positive-angle convention used by the `RotationRegisterIncremented` and `RotationPhaseGradient` Guppy structs for a fixed computational-basis data register.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "908462a0", "metadata": {}, "outputs": [], "source": [ "from typing import no_type_check\n", "\n", "import numpy as np\n", "import pandas as pd\n", "from guppylang import comptime, guppy\n", "from guppylang.std.debug import state_result\n", "from guppylang.std.quantum import discard, discard_array, qubit, x\n", "from selene_sim import Quest\n", "\n", "from guppyalgos.primitives.rotations import (\n", " RotationAxisY,\n", " RotationPhaseGradient,\n", " RotationRegisterIncremented,\n", ")\n", "from guppyalgos.primitives.state_preparation.phase_gradient import Convention, phase_gradient\n", "from guppyalgos.utils import qarray\n", "from guppyalgos.tests.helpers import assert_allclose_ignorephase" ] }, { "cell_type": "markdown", "id": "c14dab38", "metadata": {}, "source": [ "For a little-endian $n$-qubit data register with bits $b_i \\in \\{0, 1\\}$, the positive register-incremented per-bit controlled angles are\n", "\n", "$$\\theta_i = 2^{i+1-n}$$\n", "\n", "and the total positive angle applied to the ancilla is\n", "\n", "$$\\theta_{\\mathrm{total}} = \\sum_{i=0}^{n-1} b_i \\theta_i = \\frac{2}{2^n}\\sum_{i=0}^{n-1} b_i 2^i.$$\n", "\n", "This is the unscaled full-range fixed-point convention shared with phase-gradient kickback.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "87da8c99", "metadata": {}, "outputs": [], "source": [ "bits = [True, False, True, False, True]\n", "n_phase_qubits = len(bits)\n", "\n", "@guppy\n", "@no_type_check\n", "def main() -> None:\n", " idx = comptime(bits)\n", " phase_qreg = qarray(comptime(n_phase_qubits))\n", " rotation_target = qubit()\n", "\n", " for bit in range(comptime(n_phase_qubits)):\n", " if idx[bit]:\n", " x(phase_qreg[bit])\n", "\n", " rotation = RotationRegisterIncremented[\n", " comptime(n_phase_qubits), RotationAxisY\n", " ](RotationAxisY())\n", " rotation.compose(phase_qreg, rotation_target)\n", "\n", " state_result(\"ancilla\", rotation_target)\n", " discard_array(phase_qreg)\n", " discard(rotation_target)\n", "\n", "res = main.emulator(n_qubits=n_phase_qubits + 1).run()\n", "states = Quest.extract_states_dict(res.results[0].entries)\n", "ancilla_state = states[\"ancilla\"].get_single_state()" ] }, { "cell_type": "code", "execution_count": null, "id": "9c644ec8", "metadata": {}, "outputs": [], "source": [ "per_bit = [2.0 ** (i + 1 - n_phase_qubits) for i in range(n_phase_qubits)]\n", "contrib = [float(per_bit[i]) if bit else 0.0 for i, bit in enumerate(bits)]\n", "\n", "pd.DataFrame(\n", " {\n", " \"i\": list(range(n_phase_qubits)),\n", " \"bit b_i\": bits,\n", " \"theta_i = 2^(i+1-n)\": per_bit,\n", " \"contribution b_i * theta_i\": contrib,\n", " }\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "0e94aa9a", "metadata": {}, "outputs": [], "source": [ "expected_theta = sum(contrib)\n", "print(contrib)\n", "phase = np.pi * expected_theta / 2.0\n", "expected_state = np.array([np.cos(phase), np.sin(phase)], dtype=np.complex128)\n", "\n", "print(f\"bits={bits}, axis=Y\")\n", "print(f\"expected theta_total = {expected_theta}\")\n", "print(\"simulated ancilla state:\", ancilla_state)\n", "print(\"expected ancilla state :\", expected_state)\n", "\n", "assert_allclose_ignorephase(ancilla_state, expected_state)\n", "print(\"Passed: ancilla state matches expected axis rotation up to global phase.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A positive rotation can also be synthesized by the `RotationPhaseGradient` struct using a phase-gradient register prepared before initialization. It applies `X` to the target before and after the controlled Gidney adder. This makes addition happen on the target's original $|0\\rangle$ branch, so the phase-gradient eigenphase $\\exp(-2\\pi i x / 2^d)$ appears on $|0\\rangle$ rather than $|1\\rangle$. Up to global phase, this is a positive rotation with half-turn angle `theta = 2 * x / 2**d` for the standard-convention integer $x$ encoded by the same little-endian bits.\n" ], "id": "phase-gradient-note" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "phase_gradient_prep = phase_gradient(\n", " n_phase_qubits,\n", " convention=Convention.Standard,\n", ")\n", "\n", "@guppy\n", "@no_type_check\n", "def phase_gradient_main() -> None:\n", " idx = comptime(bits)\n", " phase_qreg = qarray(comptime(n_phase_qubits))\n", " phase_gradient_state = qarray(comptime(n_phase_qubits))\n", " rotation_target = qubit()\n", "\n", " for bit in range(comptime(n_phase_qubits)):\n", " if idx[bit]:\n", " x(phase_qreg[bit])\n", "\n", " phase_gradient_prep(phase_gradient_state)\n", " rotation = RotationPhaseGradient(phase_gradient_state, RotationAxisY())\n", " rotation.compose(phase_qreg, rotation_target)\n", "\n", " state_result(\"phase_gradient_ancilla\", rotation_target)\n", " discard_array(phase_qreg)\n", " discard_array(rotation.phase_gradient)\n", " discard(rotation_target)\n", "\n", "phase_gradient_res = phase_gradient_main.emulator(n_qubits=(3 * n_phase_qubits) + 1).run()\n", "phase_gradient_states = Quest.extract_states_dict(phase_gradient_res.results[0].entries)\n", "phase_gradient_ancilla_state = phase_gradient_states[\"phase_gradient_ancilla\"].get_single_state()\n", "\n", "encoded_integer = sum((2**i) for i, bit in enumerate(bits) if bit)\n", "expected_phase_gradient_theta = 2.0 * encoded_integer / (2**n_phase_qubits)\n", "phase_gradient_phase = np.pi * expected_phase_gradient_theta / 2.0\n", "expected_phase_gradient_state = np.array(\n", " [np.cos(phase_gradient_phase), np.sin(phase_gradient_phase)],\n", " dtype=np.complex128,\n", ")\n", "\n", "print(f\"phase-gradient theta_total = {expected_phase_gradient_theta}\")\n", "print(\"phase-gradient ancilla state:\", phase_gradient_ancilla_state)\n", "print(\"expected ancilla state :\", expected_phase_gradient_state)\n", "\n", "assert_allclose_ignorephase(\n", " phase_gradient_ancilla_state,\n", " expected_phase_gradient_state,\n", ")\n", "print(\"Passed: phase-gradient kickback matches the positive axis rotation convention.\")\n" ], "id": "phase-gradient-check" } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }