{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Interleaved Randomized Benchmarking (IRB)\n" ] }, { "attachments": {}, "cell_type": "markdown", "id": "approximate-aurora", "metadata": {}, "source": [ "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Infleqtion/client-superstaq/blob/main/docs/source/apps/supermarq/qcvv/qcvv_irb_css.ipynb)\n", "[![Launch Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/Infleqtion/client-superstaq/HEAD?labpath=docs/source/apps/supermarq/qcvv/qcvv_irb_css.ipynb)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The interleaved randomized benchmarking routine allows us to estimate the fidelity of single and two\n", "qubit Clifford operations. To demonstrate this routine, consider device noise modelled by an\n", "amplitude damping channel with decay probability $\\gamma=0.05$. We want to estimate the fidelity of\n", "the single-qubit $Z$ gate.\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import cirq\n", "import numpy as np\n", "import supermarq" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "decay_prob = 0.05\n", "noise = cirq.AmplitudeDampingChannel(gamma=decay_prob)\n", "simulator = cirq.DensityMatrixSimulator(noise=noise, seed=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can calculate the average fidelity of this channel\n", "[as](https://quantumcomputing.stackexchange.com/questions/16074/how-to-calculate-the-average-fidelity-of-an-amplitude-damping-channel):\n", "\n", "$$\n", "\\begin{align}\n", "\\overline{F} &= \\int\\langle\\psi|\\mathcal{N_\\gamma}(|\\psi\\rangle\\langle\\psi|)|\\psi\\rangle d\\psi\\\\\n", "&=\\int\\langle\\psi|K_0|\\psi\\rangle\\langle\\psi|K_0^\\dagger|\\psi\\rangle + \\langle\\psi|K_1|\\psi\\rangle\\langle\\psi|K_1^\\dagger|\\psi\\rangle d\\psi\\\\\n", "& =\\frac{1}{4\\pi}\\int_0^\\pi\\int_0^{2\\pi}\\left|\\begin{pmatrix}\\cos\\frac{\\theta}{2}&e^{-i\\phi}\\sin\\frac{\\theta}{2}\\end{pmatrix}\\begin{pmatrix}1 & 0 \\\\0 & \\sqrt{1 - \\gamma}\\end{pmatrix}\\begin{pmatrix}\\cos\\frac{\\theta}{2}\\\\e^{i\\phi}\\sin\\frac{\\theta}{2}\\end{pmatrix}\\right|^2\\sin\\theta \\\\\n", "& + \\left|\\begin{pmatrix}\\cos\\frac{\\theta}{2}&e^{-i\\phi}\\sin\\frac{\\theta}{2}\\end{pmatrix}\\begin{pmatrix}0 & \\sqrt{\\gamma} \\\\0 & 0\\end{pmatrix}\\begin{pmatrix}\\cos\\frac{\\theta}{2}\\\\e^{i\\phi}\\sin\\frac{\\theta}{2}\\end{pmatrix}\\right|^2\\sin\\theta d\\phi d\\theta \\\\\n", "&=\\frac{1}{4\\pi}\\int_0^\\pi\\int_0^{2\\pi}\\left|\\cos^2\\frac{\\theta}{2}+\\sqrt{1-\\gamma}\\sin^2\\frac{\\theta}{2}\\right|^2\\sin\\theta + \\left|\\sqrt{\\gamma}e^{i\\phi}\\sin\\frac{\\theta}{2}\\cos\\frac{\\theta}{2}\\right|^2\\sin\\theta d\\phi d\\theta \\\\\n", "&=\\frac{1}{2}\\int_0^\\pi\\left(\\cos^4\\frac{\\theta}{2}+(1-\\gamma)\\sin^4\\frac{\\theta}{2}+\\frac{\\sqrt{1-\\gamma}}{2}\\sin^2\\theta + \\frac{\\gamma}{4}\\sin^2\\theta\\right)\\sin\\theta d\\theta \\\\\n", "&=\\frac{1}{2}\\int_0^\\pi\\sin\\theta\\cos^4\\frac{\\theta}{2}+(1-\\gamma)\\sin\\theta\\sin^4\\frac{\\theta}{2}+\\frac{\\gamma+2\\sqrt{1-\\gamma}}{4}\\sin^3\\theta d\\theta \\\\\n", "&=\\frac{1}{2}\\left(\\frac{2}{3} + (1-\\gamma)\\frac{2}{3} + \\frac{\\gamma+2\\sqrt{1-\\gamma}}{4}\\frac{4}{3}\\right) \\\\\n", "&=\\frac{1}{2}\\left(\\frac{4}{3} - \\frac{\\gamma}{3} + \\frac{2\\sqrt{1-\\gamma}}{3}\\right) \\\\\n", "&=\\frac{2}{3}-\\frac{\\gamma}{6} + \\frac{\\sqrt{1-\\gamma}}{3}.\n", "\\end{align}\n", "$$\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Thus we have a gate error $$\\frac{1}{3}+\\frac{\\gamma}{6} - \\frac{\\sqrt{1-\\gamma}}{3}$$\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "expected_gate_error = 1 / 3 + decay_prob / 6 - np.sqrt(1 - decay_prob) / 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we run the experiments and analyse the results.\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "b1ff2f9a0e7b46d2bee16aa1d4448098", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Building circuits: 0%| | 0/750 [00:00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "result.analyze()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Expected gate error: 0.016774\n", "Measured gate error: 0.013100 +/- 0.003058\n" ] } ], "source": [ "print(f\"Expected gate error: {expected_gate_error:.6f}\")\n", "print(\n", " f\"Measured gate error: {result.average_interleaved_gate_error:.6f} +/- {result.average_interleaved_gate_error_std:.6f}\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So our estimate is in good agreement with the expected result.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Two Qubit RB\n", "\n", "The `IRB()` routine can also perform vanilla Randomised Benchmarking (RB) by instead passing\n", "`interleaved_gate=None`. We demonstrate this with a two qubit depolarising noise model with an error\n", "of $0.02$.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First we have to define a custom noise model.\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "class TwoQubitDepolariseNoiseModel(cirq.NoiseModel):\n", " \"\"\"Applies two qubit depolarising channels.\"\"\"\n", "\n", " def __init__(self, average_qubit_error: float) -> None:\n", " \"\"\"Args:\n", " average_qubit_error: The average two qubit error rate.\n", " \"\"\"\n", " super().__init__()\n", " # Note the conversion from average error to pauli error which is used by the cirq channel.\n", " self.two_qubit_pauli_error = 15 / 16 * 4 / 3 * average_qubit_error\n", " self.two_qubit_depolarise = cirq.DepolarizingChannel(\n", " p=self.two_qubit_pauli_error, n_qubits=2\n", " )\n", "\n", " def noisy_operation(self, operation: cirq.Operation) -> list[cirq.OP_TREE]:\n", " \"\"\"Produces a list of operations by applying each noise model\n", " to the provided operation depending on the number of qubits it acts on.\n", " \"\"\"\n", " if len(operation.qubits) == 2:\n", " return [operation, self.two_qubit_depolarise(*operation.qubits)]\n", "\n", " return [operation]\n", "\n", "\n", "two_qubit_noise = TwoQubitDepolariseNoiseModel(two_qubit_error := 0.02)\n", "two_qubit_simulator = cirq.DensityMatrixSimulator(noise=two_qubit_noise, seed=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now run the experiment and analyse the results\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "9db9ec94df184f898a40613b35d33506", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Building circuits: 0%| | 0/250 [00:00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "results2.analyze()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "6d9cc8f375a144b395eb3accc42c6ba6", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Sampling Clifford operations: 0%| | 0/500 [00:00