diff --git a/README.md b/README.md index 284c2626..3b811a53 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Running notebooks locally requires additional dependencies located in [notebooks | Quantum Circuit Born Machine | [Quantum_Circuit_Born_Machine.ipynb](notebooks/textbook/Quantum_Circuit_Born_Machine.ipynb) | [Benedetti2019](https://www.nature.com/articles/s41534-019-0157-8), [Liu2018](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.98.062324) | | QFT | [Quantum_Fourier_Transform.ipynb](notebooks/textbook/Quantum_Fourier_Transform.ipynb) | [Coppersmith2002](https://arxiv.org/abs/quant-ph/0201067) | | QPE | [Quantum_Phase_Estimation_Algorithm.ipynb](notebooks/textbook/Quantum_Phase_Estimation_Algorithm.ipynb) | [Kitaev1995](https://arxiv.org/abs/quant-ph/9511026) | +| Quantum Teleportation | [Quantum_Teleportation.ipynb](notebooks/textbook/Quantum_Teleportation.ipynb) | [Bennett1993](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.70.1895) | | Quantum Walk | [Quantum_Walk.ipynb](notebooks/textbook/Quantum_Walk.ipynb) | [Childs2002](https://arxiv.org/abs/quant-ph/0209131) | |Shor's| [Shors_Algorithm.ipynb](notebooks/textbook/Shors_Algorithm.ipynb) | [Shor1998](https://arxiv.org/abs/quant-ph/9508027) | | Simon's | [Simons_Algorithm.ipynb](notebooks/textbook/Simons_Algorithm.ipynb) | [Simon1997](https://epubs.siam.org/doi/10.1137/S0097539796298637) | diff --git a/notebooks/textbook/Quantum_Teleportation.ipynb b/notebooks/textbook/Quantum_Teleportation.ipynb new file mode 100644 index 00000000..f7855d2f --- /dev/null +++ b/notebooks/textbook/Quantum_Teleportation.ipynb @@ -0,0 +1,148 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": "# Quantum Teleportation\n\nThis notebook demonstrates the quantum teleportation protocol using Amazon Braket.\n\nQuantum teleportation transfers an unknown quantum state from one qubit (Alice) to another (Bob) using a shared entangled Bell pair and two bits of classical communication. The original state is destroyed in the process, consistent with the no-cloning theorem.\n\nSince Amazon Braket does not support mid-circuit measurement with classical feedforward, this implementation uses the **deferred measurement** principle: classically-controlled gates are replaced by quantum-controlled gates (CNOT and CZ), which produce equivalent results.\n\n**Note:** This implementation creates the Bell pair $|\\Phi^+\\rangle = (|00\\rangle + |11\\rangle)/\\sqrt{2}$ directly using H and CNOT gates. The algorithm library also provides a `bell_singlet` subroutine (in `bells_inequality`) that prepares the singlet state $|\\psi^-\\rangle$, which is a different Bell state used for inequality tests." + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## References\n", + "\n", + "[1] Bennett, C. H. et al. \"Teleporting an unknown quantum state via dual classical and Einstein-Podolsky-Rosen channels.\" Physical Review Letters 70, 1895 (1993). https://doi.org/10.1103/PhysRevLett.70.1895\n", + "\n", + "[2] Nielsen, M. A. and Chuang, I. L. \"Quantum Computation and Quantum Information.\" Cambridge University Press (2010)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Run on a local simulator" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from braket.circuits import Circuit\n", + "from braket.devices import LocalSimulator\n", + "from braket.tracking import Tracker\n", + "\n", + "from braket.experimental.algorithms.quantum_teleportation import (\n", + " get_quantum_teleportation_results,\n", + " quantum_teleportation_circuit,\n", + " run_quantum_teleportation,\n", + ")\n", + "\n", + "tracker = Tracker().start()\n", + "device = LocalSimulator()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Print the circuit\n", + "\n", + "The teleportation circuit for teleporting $|1\\rangle$ (prepared with an X gate):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "circ = quantum_teleportation_circuit(Circuit().x(0))\n", + "print(circ)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Teleport different states\n", + "\n", + "We teleport $|0\\rangle$, $|1\\rangle$, and $|+\\rangle = \\frac{1}{\\sqrt{2}}(|0\\rangle + |1\\rangle)$, then verify Bob's qubit matches the original state." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "test_cases = [\n (\"|0>\", None),\n (\"|1>\", Circuit().x(0)),\n (\"|+>\", Circuit().h(0)),\n (\"Ry(pi/3)|0>\", Circuit().ry(0, np.pi / 3)),\n]\n\nnames, probs_0, probs_1 = [], [], []\nfor name, prep in test_cases:\n circ = quantum_teleportation_circuit(prep)\n task = run_quantum_teleportation(circ, device, shots=1000)\n result = get_quantum_teleportation_results(task)\n names.append(name)\n probs_0.append(result[\"0\"])\n probs_1.append(result[\"1\"])\n print(f\"Teleport {name}: P(|0>) = {result['0']:.4f}, P(|1>) = {result['1']:.4f}\")" + }, + { + "cell_type": "code", + "source": "import matplotlib.pyplot as plt\n\nx = np.arange(len(names))\nwidth = 0.35\n\nfig, ax = plt.subplots(figsize=(8, 5))\nax.bar(x - width / 2, probs_0, width, label=r\"$P(|0\\rangle)$\", color=\"steelblue\")\nax.bar(x + width / 2, probs_1, width, label=r\"$P(|1\\rangle)$\", color=\"coral\")\nax.set_xticks(x)\nax.set_xticklabels(names)\nax.set_ylabel(\"Probability\")\nax.set_title(\"Quantum Teleportation Results (Bob's qubit)\")\nax.legend()\nax.set_ylim(0, 1.15)\nax.grid(axis=\"y\", alpha=0.3)\nplt.tight_layout()\nplt.show()", + "metadata": {}, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Run on a QPU\n", + "\n", + "To run on a QPU, replace `LocalSimulator()` with an `AwsDevice`. The cost for 4 circuits of 1000 shots on IQM Garnet is approximately $7.00 USD." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# # Uncomment to run on a QPU\n", + "# from braket.aws import AwsDevice\n", + "# qpu = AwsDevice(\"arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet\")\n", + "# circ = quantum_teleportation_circuit(Circuit().x(0))\n", + "# task = run_quantum_teleportation(circ, qpu, shots=1000)\n", + "# result = get_quantum_teleportation_results(task)\n", + "# print(f\"QPU result: {result}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Task Summary\")\n", + "print(f\"{tracker.quantum_tasks_statistics()} \\n\")\n", + "print(\n", + " f\"Estimated cost to run this example: \"\n", + " f\"{tracker.qpu_tasks_cost() + tracker.simulator_tasks_cost():.2f} USD\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage. Estimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits, and you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/src/braket/experimental/algorithms/quantum_teleportation/__init__.py b/src/braket/experimental/algorithms/quantum_teleportation/__init__.py new file mode 100644 index 00000000..7ddd9379 --- /dev/null +++ b/src/braket/experimental/algorithms/quantum_teleportation/__init__.py @@ -0,0 +1,18 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file 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 braket.experimental.algorithms.quantum_teleportation.quantum_teleportation import ( # noqa: F401, E501 + get_quantum_teleportation_results, + quantum_teleportation_circuit, + run_quantum_teleportation, +) diff --git a/src/braket/experimental/algorithms/quantum_teleportation/quantum_teleportation.md b/src/braket/experimental/algorithms/quantum_teleportation/quantum_teleportation.md new file mode 100644 index 00000000..6ad6440c --- /dev/null +++ b/src/braket/experimental/algorithms/quantum_teleportation/quantum_teleportation.md @@ -0,0 +1,7 @@ +Quantum teleportation transfers an arbitrary quantum state from one qubit to another using a shared entangled Bell pair and classical communication. This implementation uses the deferred measurement principle, replacing mid-circuit measurements and classical feedforward with coherent CNOT and CZ corrections, so the circuit runs on any gate-based simulator. + + diff --git a/src/braket/experimental/algorithms/quantum_teleportation/quantum_teleportation.py b/src/braket/experimental/algorithms/quantum_teleportation/quantum_teleportation.py new file mode 100644 index 00000000..35a1a262 --- /dev/null +++ b/src/braket/experimental/algorithms/quantum_teleportation/quantum_teleportation.py @@ -0,0 +1,88 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file 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 typing import Dict, Optional + +import numpy as np + +from braket.circuits import Circuit +from braket.devices import Device +from braket.tasks import QuantumTask + + +def quantum_teleportation_circuit(state_prep_circ: Optional[Circuit] = None) -> Circuit: + """Create a quantum teleportation circuit using deferred measurement. + + Teleports the state of qubit 0 to qubit 2 via a shared Bell pair. + Uses CNOT and CZ gates instead of classical feedforward (deferred measurement + principle), so the circuit can run on any simulator without mid-circuit measurement. + + Qubit layout: + qubit 0: message qubit (Alice's input) + qubit 1: Alice's half of Bell pair + qubit 2: Bob's half of Bell pair (receives teleported state) + + Args: + state_prep_circ (Optional[Circuit]): Circuit to prepare the state on qubit 0. + If None, teleports the |0> state. + + Returns: + Circuit: Quantum teleportation circuit with probability measurement on qubit 2. + """ + circ = Circuit() + + # Prepare the state to teleport on qubit 0 + if state_prep_circ is not None: + circ.add_circuit(state_prep_circ) + + # Create Bell pair between qubit 1 and qubit 2 + circ.h(1) + circ.cnot(1, 2) + + # Bell measurement on qubits 0 and 1 + circ.cnot(0, 1) + circ.h(0) + + # Deferred corrections (equivalent to classical conditional gates) + circ.cnot(1, 2) # if qubit 1 measured |1>: apply X to qubit 2 + circ.cz(0, 2) # if qubit 0 measured |1>: apply Z to qubit 2 + + circ.probability([2]) + return circ + + +def run_quantum_teleportation(circuit: Circuit, device: Device, shots: int = 1000) -> QuantumTask: + """Run a quantum teleportation circuit on a device. + + Args: + circuit (Circuit): Quantum teleportation circuit. + device (Device): Braket device or simulator. + shots (int): Number of shots. Defaults to 1000. + + Returns: + QuantumTask: Quantum task. + """ + return device.run(circuit, shots=shots) + + +def get_quantum_teleportation_results(task: QuantumTask) -> Dict[str, float]: + """Extract teleportation results from a quantum task. + + Args: + task (QuantumTask): Completed quantum task. + + Returns: + Dict[str, float]: Probability of Bob's qubit in {"0": P(|0>), "1": P(|1>)}. + """ + probs = task.result().result_types[0].value + probs = np.round(probs, 10) + return {"0": probs[0], "1": probs[1]} diff --git a/test/unit_tests/braket/experimental/algorithms/quantum_teleportation/test_quantum_teleportation.py b/test/unit_tests/braket/experimental/algorithms/quantum_teleportation/test_quantum_teleportation.py new file mode 100644 index 00000000..4f9cf125 --- /dev/null +++ b/test/unit_tests/braket/experimental/algorithms/quantum_teleportation/test_quantum_teleportation.py @@ -0,0 +1,83 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file 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 numpy as np +import pytest + +from braket.circuits import Circuit +from braket.devices import LocalSimulator +from braket.experimental.algorithms.quantum_teleportation import ( + get_quantum_teleportation_results, + quantum_teleportation_circuit, + run_quantum_teleportation, +) + + +@pytest.fixture +def device(): + return LocalSimulator() + + +# teleport |0>, expect P(|0>)=1 +def test_teleport_zero(device): + circ = quantum_teleportation_circuit() + task = run_quantum_teleportation(circ, device, shots=0) + result = get_quantum_teleportation_results(task) + assert np.isclose(result["0"], 1.0) + assert np.isclose(result["1"], 0.0) + + +# teleport |1>, expect P(|1>)=1 +def test_teleport_one(device): + circ = quantum_teleportation_circuit(Circuit().x(0)) + task = run_quantum_teleportation(circ, device, shots=0) + result = get_quantum_teleportation_results(task) + assert np.isclose(result["0"], 0.0) + assert np.isclose(result["1"], 1.0) + + +# teleport |+>, expect 50/50 +def test_teleport_plus(device): + circ = quantum_teleportation_circuit(Circuit().h(0)) + task = run_quantum_teleportation(circ, device, shots=0) + result = get_quantum_teleportation_results(task) + assert np.isclose(result["0"], 0.5, atol=1e-6) + assert np.isclose(result["1"], 0.5, atol=1e-6) + + +# teleport Ry(pi/3)|0>, verify probabilities match +def test_teleport_arbitrary_state(device): + angle = np.pi / 3 + circ = quantum_teleportation_circuit(Circuit().ry(0, angle)) + task = run_quantum_teleportation(circ, device, shots=0) + result = get_quantum_teleportation_results(task) + # Ry(theta)|0> = cos(theta/2)|0> + sin(theta/2)|1> + assert np.isclose(result["0"], np.cos(angle / 2) ** 2, atol=1e-6) + assert np.isclose(result["1"], np.sin(angle / 2) ** 2, atol=1e-6) + + +# teleport |+i>, verify phase is preserved via S†H readout +def test_teleport_plus_i_phase(device): + # prep |+i> = S H |0> + teleportation_circuit = quantum_teleportation_circuit(Circuit().h(0).s(0)) + + # S†H maps |+i> to |0>, so successful teleportation => P(|0>) ~= 1 + phase_sensitive_circuit = ( + Circuit().add(teleportation_circuit.instructions).si(2).h(2).probability([2]) + ) + + task = run_quantum_teleportation(phase_sensitive_circuit, device, shots=0) + result = get_quantum_teleportation_results(task) + + assert np.isclose(result["0"], 1.0, atol=1e-6) + assert np.isclose(result["1"], 0.0, atol=1e-6)