{ "cells": [ { "cell_type": "markdown", "id": "pauli-00", "metadata": {}, "source": [ "# Measurement-based Pauli exponentials\n", "\n", "**Download Notebook** - {nb-download}`pauli_phasor_depth1.ipynb`\n", "\n", "- `pauli_exp_depth1` implements the same rotation as `pauli_exp`:\n", "\n", "$$\n", "U_P(\\theta)=e^{-i\\pi\\theta P/2}.\n", "$$\n", "\n", "- It replaces the CX ladder with an ancilla-based parity construction, measurements, and conditional corrections.\n", "- The depth-1 description refers to the parity-extraction construction; the full routine also includes basis changes, a rotation, measurement, and feedback.\n", "- This example checks every measurement branch for $P=X_0Y_1$ on $|00\\rangle$.\n", "- Run from a source checkout with development dependencies installed. The repository default is little endian." ] }, { "cell_type": "code", "execution_count": 1, "id": "pauli-01", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "import itertools\n", "import numpy as np\n", "import pandas as pd\n", "import zixy.qubit.pauli as zqp\n", "from scipy.linalg import expm\n", "from guppylang import guppy\n", "from guppylang.std.angles import angle\n", "from guppylang.std.debug import state_output\n", "from guppylang.std.quantum import discard_array\n", "from selene_sim import QuantumReplay, Quest\n", "from guppyalgos.primitives.pauli.pauli_exp.pauli_exp_depth1 import pauli_exp_depth1\n", "from guppyalgos.utils import qarray\n", "from guppyalgos.tests.helpers import assert_allclose_ignorephase" ] }, { "cell_type": "markdown", "id": "pauli-02", "metadata": {}, "source": [ "## 1. Choose a nontrivial input\n", "\n", "- Use two qubits and `theta = 0.3` half-turns.\n", "- Since $X_0Y_1|00\\rangle=i|11\\rangle$, the expected output has a simple form:\n", "\n", "$$\n", "U_{X_0Y_1}(0.3)|00\\rangle\n", "=\\cos(0.15\\pi)|00\\rangle+\\sin(0.15\\pi)|11\\rangle.\n", "$$\n", "\n", "- Compute the reference directly from the Pauli matrix." ] }, { "cell_type": "code", "execution_count": 2, "id": "pauli-03", "metadata": {}, "outputs": [], "source": [ "n_state_qubits = 2\n", "paulis = zqp.String.from_str(\"X0 Y1\", n_state_qubits)\n", "theta = 0.3\n", "pauli_mat = np.asarray(paulis.to_sparse_matrix(True).todense())\n", "u_mat = expm(-0.5j * np.pi * theta * pauli_mat)\n", "initial_state = np.zeros(2**n_state_qubits)\n", "initial_state[0] = 1\n", "expected_state = u_mat @ initial_state" ] }, { "cell_type": "markdown", "id": "pauli-04", "metadata": {}, "source": [ "## 2. Build the measurement-based gadget\n", "\n", "- The calling circuit supplies only `qreg` and an angle. The gadget manages its ancillas and corrections internally.\n", "- Reserve two ancillas in addition to the two system qubits when simulating this example." ] }, { "cell_type": "code", "execution_count": 3, "id": "pauli-05", "metadata": {}, "outputs": [], "source": [ "pauli_gadget = pauli_exp_depth1(paulis, n_state_qubits)\n", "\n", "\n", "@guppy\n", "def main() -> None:\n", " qreg = qarray(n_state_qubits)\n", " pauli_gadget(qreg, angle(theta))\n", " state_output(\"result_state\", qreg)\n", " discard_array(qreg)" ] }, { "cell_type": "markdown", "id": "pauli-06", "metadata": {}, "source": [ "## 3. Check every measurement branch\n", "\n", "- Two ancilla measurements give four possible bit strings. `QuantumReplay` forces each one so the corrections are exercised explicitly.\n", "- Every corrected branch must produce the same state, up to global phase. The table reports\n", "\n", "$$\n", "F=|\\langle\\psi_{\\mathrm{expected}}|\\psi_{\\mathrm{branch}}\\rangle|^2,\n", "\\qquad F=1\\text{ for an exact match}.\n", "$$\n", "\n", "- These replayed branches are a correctness check, not an estimate of their sampling probabilities." ] }, { "cell_type": "code", "execution_count": 4, "id": "pauli-07", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Measurement branch State fidelity\n", " 00 1.00000000\n", " 01 1.00000000\n", " 10 1.00000000\n", " 11 1.00000000\n" ] } ], "source": [ "branches = [list(bits) for bits in itertools.product([False, True], repeat=n_state_qubits)]\n", "simulator = QuantumReplay(\n", " simulator=Quest(random_seed=17),\n", " resume_with_measurement=True,\n", " measurements=branches,\n", ")\n", "result = (\n", " main.emulator(2 * n_state_qubits).with_simulator(simulator)\n", " .with_shots(len(branches)).run()\n", ")\n", "rows = []\n", "for bits, shot in zip(branches, result.results):\n", " actual_state = Quest.extract_states_dict(shot)[\"result_state\"].get_single_state()\n", " assert_allclose_ignorephase(expected_state, actual_state)\n", " rows.append({\n", " \"Measurement branch\": \"\".join(str(int(bit)) for bit in bits),\n", " \"State fidelity\": abs(np.vdot(expected_state, actual_state))**2,\n", " })\n", "print(pd.DataFrame(rows).to_string(index=False, float_format=lambda value: f\"{value:.8f}\"))\n" ] }, { "cell_type": "markdown", "id": "pauli-08", "metadata": {}, "source": [ "- All four branches match the target state after correction.\n", "- See the {doc}`standard Pauli exponential ` for CX-ladder and replaceable rotation implementations.\n", "\n", "- Construction reference: [Figure 7 of arXiv:2603.17774](https://arxiv.org/abs/2603.17774)." ] } ], "metadata": { "kernelspec": { "display_name": "guppyalgos (3.13.4)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.13" } }, "nbformat": 4, "nbformat_minor": 5 }