{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "c6bf54e5-ec4e-4029-a341-2dcef8574ebb",
      "metadata": {},
      "source": [
        "---\n",
        "title: Building noise models\n",
        "description: Build custom noise models for noisy simulation with Qiskit Aer\n",
        "---\n",
        "\n",
        "# Build noise models\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "633591c5-42ba-49a1-b3e5-d9b5ef5305f2",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Package versions\">\n",
        "    The code on this page was developed using the following requirements.\n",
        "    We recommend using these versions or newer.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.3.0\n",
        "    qiskit-ibm-runtime~=0.43.1\n",
        "    qiskit-aer~=0.17\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3b5705bc-d978-464b-9257-82f87b5b3491",
      "metadata": {},
      "source": [
        "This page shows how to use the Qiskit Aer [`noise`](https://qiskit.org/ecosystem/aer/apidocs/aer_noise.html) module to build noise models for simulating quantum circuits in the presence of errors. This is useful for emulating noisy quantum processors and for studying the effects of noise on the execution of quantum algorithms.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "4f0d2b6f-2567-450b-95fb-cc1d7983f4ed",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:43.403378Z",
          "start_time": "2019-08-19T17:00:41.139269Z"
        }
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.quantum_info import Kraus, SuperOp\n",
        "from qiskit.visualization import plot_histogram\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit_aer import AerSimulator\n",
        "\n",
        "# Import from Qiskit Aer noise module\n",
        "from qiskit_aer.noise import (\n",
        "    NoiseModel,\n",
        "    QuantumError,\n",
        "    ReadoutError,\n",
        "    depolarizing_error,\n",
        "    pauli_error,\n",
        "    thermal_relaxation_error,\n",
        ")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "54898138-a2e2-4f4d-9219-be0d23d75435",
      "metadata": {
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "source": [
        "## Qiskit Aer `noise` module\n",
        "\n",
        "The Qiskit Aer `noise` module contains Python classes to build customized noise models for simulation. There are three key classes:\n",
        "\n",
        "1. The `NoiseModel` class which stores a noise model used for noisy simulation.\n",
        "\n",
        "2. The `QuantumError` class which describes CPTP gate errors. These can be applied:\n",
        "   * After *gate* or *reset* instructions\n",
        "   * Before *measure* instructions.\n",
        "\n",
        "3. The `ReadoutError` class which describes classical readout errors.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4f936882-6e86-40a9-a65b-5a27a7d6986d",
      "metadata": {},
      "source": [
        "## Initializing a noise model from a backend\n",
        "\n",
        "You can initialize a noise model with parameters set from the latest calibration data for a physical backend:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "3c114909-aa2a-4638-b945-e31dcdbaf248",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.backend(\"ibm_fez\")\n",
        "noise_model = NoiseModel.from_backend(backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "68d4eea9-b185-4508-ae4d-5c3ff3798a48",
      "metadata": {},
      "source": [
        "This will yield a noise model that roughly approximates the errors one would encounter when using that backend. If you want to have more detailed control over the parameters of the noise model, then you'll need to create your own noise model, as described in the rest of this page.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "191dc0e5-2a79-4167-9cca-b74163da21f6",
      "metadata": {},
      "source": [
        "## Quantum errors\n",
        "\n",
        "Rather than deal with the `QuantumError` object directly, many helper functions exist to automatically generate a specific type of parameterized quantum error. These are contained in the `noise` module and include functions for many common error types used in quantum computing research. The function names and the type of error they return are:\n",
        "\n",
        "| Standard error function         | Details                                                                                                                                                                                                             |\n",
        "| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n",
        "| `kraus_error`                   | a general n-qubit CPTP error channel given as a list of Kraus matrices $[K_0, ...]$.                                                                                                                                |\n",
        "| `mixed_unitary_error`           | an n-qubit mixed unitary error given as a list of unitary matrices and probabilities $[(U_0, p_0),...]$.                                                                                                            |\n",
        "| `coherent_unitary_error`        | an n-qubit coherent unitary error given as a single unitary matrix $U$.                                                                                                                                             |\n",
        "| `pauli_error`                   | an n-qubit Pauli error channel (mixed unitary) given as a list of Pauli's and probabilities $[(P_0, p_0),...]$                                                                                                      |\n",
        "| `depolarizing_error`            | an n-qubit depolarizing error channel parameterized by a depolarization probability $p$.                                                                                                                            |\n",
        "| `reset_error`                   | a single-qubit reset error parameterized by probabilities $p_0, p_1$ of resetting to the $\\vert0\\rangle$, $\\vert1\\rangle$ state.                                                                                    |\n",
        "| `thermal_relaxation_error`      | a single qubit thermal relaxation channel parameterized by relaxation time constants $T_1$, $T_2$, gate time $t$, and excited state thermal population $p_1$.                                                       |\n",
        "| `phase_amplitude_damping_error` | A single-qubit generalized combined phase and amplitude damping error channel given by an amplitude damping parameter $\\lambda$, a phase damping parameter $\\gamma$, and an excited state thermal population $p_1$. |\n",
        "| `amplitude_damping_error`       | A single-qubit generalized amplitude damping error channel given by an amplitude damping parameter $\\lambda$, and an excited state thermal population $p_1$.                                                        |\n",
        "| `phase_damping_error`           | A single-qubit phase damping error channel given by a phase damping parameter $\\gamma$.                                                                                                                             |\n",
        "\n",
        "### Combining quantum errors\n",
        "\n",
        "`QuantumError` instances can be combined by using composition, tensor product, and tensor expansion (reversed order tensor product) to produce new `QuantumErrors` as:\n",
        "\n",
        "* Composition: $\\cal{E}(\\rho)=\\cal{E_2}(\\cal{E_1}(\\rho))$ as `error = error1.compose(error2)`\n",
        "* Tensor product: $\\cal{E}(\\rho) =(\\cal{E_1}\\otimes\\cal{E_2})(\\rho)$ as `error = error1.tensor(error2)`\n",
        "* Expand product: $\\cal{E}(\\rho) =(\\cal{E_2}\\otimes\\cal{E_1})(\\rho)$ as `error = error1.expand(error2)`\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "58d63841-a2be-4efd-932b-ec9e20bf2589",
      "metadata": {},
      "source": [
        "### Example\n",
        "\n",
        "To construct a 5% single-qubit bit-flip error:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "987429c9-091f-4297-bec2-64b36c498e82",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:43.420358Z",
          "start_time": "2019-08-19T17:00:43.416062Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "QuantumError on 1 qubits. Noise circuits:\n",
            "  P(0) = 0.05, Circuit = \n",
            "   ┌───┐\n",
            "q: ┤ X ├\n",
            "   └───┘\n",
            "  P(1) = 0.95, Circuit = \n",
            "   ┌───┐\n",
            "q: ┤ I ├\n",
            "   └───┘\n",
            "QuantumError on 1 qubits. Noise circuits:\n",
            "  P(0) = 0.05, Circuit = \n",
            "   ┌───┐\n",
            "q: ┤ Z ├\n",
            "   └───┘\n",
            "  P(1) = 0.95, Circuit = \n",
            "   ┌───┐\n",
            "q: ┤ I ├\n",
            "   └───┘\n"
          ]
        }
      ],
      "source": [
        "# Construct a 1-qubit bit-flip and phase-flip errors\n",
        "p_error = 0.05\n",
        "bit_flip = pauli_error([(\"X\", p_error), (\"I\", 1 - p_error)])\n",
        "phase_flip = pauli_error([(\"Z\", p_error), (\"I\", 1 - p_error)])\n",
        "print(bit_flip)\n",
        "print(phase_flip)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "14b78d47-420a-4476-b3f4-e6a58ffdb264",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:43.435843Z",
          "start_time": "2019-08-19T17:00:43.432211Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "QuantumError on 1 qubits. Noise circuits:\n",
            "  P(0) = 0.0025000000000000005, Circuit = \n",
            "   ┌───┐┌───┐\n",
            "q: ┤ X ├┤ Z ├\n",
            "   └───┘└───┘\n",
            "  P(1) = 0.0475, Circuit = \n",
            "   ┌───┐┌───┐\n",
            "q: ┤ X ├┤ I ├\n",
            "   └───┘└───┘\n",
            "  P(2) = 0.0475, Circuit = \n",
            "   ┌───┐┌───┐\n",
            "q: ┤ I ├┤ Z ├\n",
            "   └───┘└───┘\n",
            "  P(3) = 0.9025, Circuit = \n",
            "   ┌───┐┌───┐\n",
            "q: ┤ I ├┤ I ├\n",
            "   └───┘└───┘\n"
          ]
        }
      ],
      "source": [
        "# Compose two bit-flip and phase-flip errors\n",
        "bitphase_flip = bit_flip.compose(phase_flip)\n",
        "print(bitphase_flip)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "7133fddd-9dbe-4861-90e4-fda9ae07200e",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:43.460191Z",
          "start_time": "2019-08-19T17:00:43.456782Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "QuantumError on 2 qubits. Noise circuits:\n",
            "  P(0) = 0.0025000000000000005, Circuit = \n",
            "     ┌───┐\n",
            "q_0: ┤ X ├\n",
            "     ├───┤\n",
            "q_1: ┤ Z ├\n",
            "     └───┘\n",
            "  P(1) = 0.0475, Circuit = \n",
            "     ┌───┐\n",
            "q_0: ┤ I ├\n",
            "     ├───┤\n",
            "q_1: ┤ Z ├\n",
            "     └───┘\n",
            "  P(2) = 0.0475, Circuit = \n",
            "     ┌───┐\n",
            "q_0: ┤ X ├\n",
            "     ├───┤\n",
            "q_1: ┤ I ├\n",
            "     └───┘\n",
            "  P(3) = 0.9025, Circuit = \n",
            "     ┌───┐\n",
            "q_0: ┤ I ├\n",
            "     ├───┤\n",
            "q_1: ┤ I ├\n",
            "     └───┘\n"
          ]
        }
      ],
      "source": [
        "# Tensor product two bit-flip and phase-flip errors with\n",
        "# bit-flip on qubit-0, phase-flip on qubit-1\n",
        "error2 = phase_flip.tensor(bit_flip)\n",
        "print(error2)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "048f05a2-71a6-4f3a-8adf-2e49942a2404",
      "metadata": {},
      "source": [
        "### Converting to and from QuantumChannel operators\n",
        "\n",
        "We can also convert back and forth between `QuantumError` objects in Qiskit Aer and `QuantumChannel` objects in Qiskit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "98626eb1-a25b-45af-b765-7ed059eaecb3",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:43.482424Z",
          "start_time": "2019-08-19T17:00:43.473779Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Kraus([[[-9.74679434e-01+0.j,  0.00000000e+00+0.j],\n",
            "        [ 0.00000000e+00+0.j, -9.74679434e-01+0.j]],\n",
            "\n",
            "       [[ 0.00000000e+00+0.j,  2.23606798e-01+0.j],\n",
            "        [ 2.23606798e-01+0.j, -4.96506831e-17+0.j]]],\n",
            "      input_dims=(2,), output_dims=(2,))\n"
          ]
        }
      ],
      "source": [
        "# Convert to Kraus operator\n",
        "bit_flip_kraus = Kraus(bit_flip)\n",
        "print(bit_flip_kraus)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "8b059cb7-2242-4c0c-bd6e-9e4421b3f87c",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:43.509521Z",
          "start_time": "2019-08-19T17:00:43.503976Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "SuperOp([[1. +0.j, 0. +0.j, 0. +0.j, 0. +0.j],\n",
            "         [0. +0.j, 0.9+0.j, 0. +0.j, 0. +0.j],\n",
            "         [0. +0.j, 0. +0.j, 0.9+0.j, 0. +0.j],\n",
            "         [0. +0.j, 0. +0.j, 0. +0.j, 1. +0.j]],\n",
            "        input_dims=(2,), output_dims=(2,))\n"
          ]
        }
      ],
      "source": [
        "# Convert to Superoperator\n",
        "phase_flip_sop = SuperOp(phase_flip)\n",
        "print(phase_flip_sop)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6c8b72d9-80fb-440e-82da-ecabc148aa5c",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:43.794037Z",
          "start_time": "2019-08-19T17:00:43.778223Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "QuantumError on 1 qubits. Noise circuits:\n",
            "  P(0) = 1.0, Circuit = \n",
            "   ┌───────┐\n",
            "q: ┤ kraus ├\n",
            "   └───────┘\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "True"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Convert back to a quantum error\n",
        "print(QuantumError(bit_flip_kraus))\n",
        "\n",
        "# Check conversion is equivalent to original error\n",
        "QuantumError(bit_flip_kraus) == bit_flip"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "f1b2ceed-5e84-480a-a22b-6910f57aa054",
      "metadata": {},
      "source": [
        "### Readout error\n",
        "\n",
        "Classical readout errors are specified by a list of assignment probability vectors $P(A|B)$:\n",
        "\n",
        "* $A$ is the *recorded* classical bit value\n",
        "* $B$ is the *true* bit value returned from the measurement\n",
        "\n",
        "For example, for one qubit: $ P(A|B) = [P(A|0), P(A|1)]$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "17424858-2c15-4902-b9ee-e23608e3fbf7",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:44.659598Z",
          "start_time": "2019-08-19T17:00:44.654818Z"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "ReadoutError([[0.95 0.05]\n",
              " [0.1  0.9 ]])"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Measurement misassignment probabilities\n",
        "p0given1 = 0.1\n",
        "p1given0 = 0.05\n",
        "\n",
        "ReadoutError([[1 - p1given0, p1given0], [p0given1, 1 - p0given1]])"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "b8365fab-f9b1-4969-ae05-be18470b0ccc",
      "metadata": {},
      "source": [
        "Readout errors may also be combined using `compose`, `tensor` and `expand`, like with quantum errors.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "55bda2dd-4a01-4287-b3bb-c183c30b31cc",
      "metadata": {},
      "source": [
        "## Add errors to a noise model\n",
        "\n",
        "When adding a quantum error to a noise model, we must specify the type of *instruction* that it acts on and what qubits to apply it to. There are two cases of quantum errors:\n",
        "\n",
        "1. All-qubit quantum error\n",
        "2. Specific qubit quantum error\n",
        "\n",
        "### 1. All-qubit quantum error\n",
        "\n",
        "This applies the same error to any occurrence of an instruction, regardless of which qubits it acts on.\n",
        "\n",
        "It is added as `noise_model.add_all_qubit_quantum_error(error, instructions)`:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "38d51e41-9088-4216-89ae-8fc05656bc11",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:45.882254Z",
          "start_time": "2019-08-19T17:00:45.877630Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "NoiseModel:\n",
            "  Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']\n",
            "  Instructions with noise: ['u2', 'u1', 'u3']\n",
            "  All-qubits errors: ['u1', 'u2', 'u3']\n"
          ]
        }
      ],
      "source": [
        "# Create an empty noise model\n",
        "noise_model = NoiseModel()\n",
        "\n",
        "# Add depolarizing error to all single qubit u1, u2, u3 gates\n",
        "error = depolarizing_error(0.05, 1)\n",
        "noise_model.add_all_qubit_quantum_error(error, [\"u1\", \"u2\", \"u3\"])\n",
        "\n",
        "# Print noise model info\n",
        "print(noise_model)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "f49cc32d-a189-4585-8a2b-0f1ed0ea492e",
      "metadata": {},
      "source": [
        "### 2. Specific qubit quantum error\n",
        "\n",
        "This applies the error to any occurrence of an instruction acting on a specified list of qubits. Note that the order of the qubit matters: for example, an error applied to qubits \\[0, 1] for a two-qubit gate is different to one applied to qubits \\[1, 0].\n",
        "\n",
        "It is added as `noise_model.add_quantum_error(error, instructions, qubits)`:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "b83e4e67-2ffb-40d9-a41a-d7a2aad3d223",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:46.615959Z",
          "start_time": "2019-08-19T17:00:46.612055Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "NoiseModel:\n",
            "  Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']\n",
            "  Instructions with noise: ['u2', 'u1', 'u3']\n",
            "  Qubits with noise: [0]\n",
            "  Specific qubit errors: [('u1', (0,)), ('u2', (0,)), ('u3', (0,))]\n"
          ]
        }
      ],
      "source": [
        "# Create an empty noise model\n",
        "noise_model = NoiseModel()\n",
        "\n",
        "# Add depolarizing error to all single qubit u1, u2, u3 gates on qubit 0 only\n",
        "error = depolarizing_error(0.05, 1)\n",
        "noise_model.add_quantum_error(error, [\"u1\", \"u2\", \"u3\"], [0])\n",
        "\n",
        "# Print noise model info\n",
        "print(noise_model)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "d6896131-b6e7-42fb-b96e-7554b64dc9b5",
      "metadata": {},
      "source": [
        "### Note on non-local qubit quantum error\n",
        "\n",
        "`NoiseModel` does not support addition of non-local qubit quantum errors. They should be handled outside of `NoiseModel`. That suggests you should [write your own transpiler pass](./custom-transpiler-pass) (`TransformationPass`) and run the pass just before running the simulator if you need to insert your quantum errors into your circuit under your own conditions.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "3b2621ab-c894-487a-b773-a742e18476f1",
      "metadata": {},
      "source": [
        "### Execute a noisy simulation with a noise model\n",
        "\n",
        "The command `AerSimulator(noise_model=noise_model)` returns a simulator configured to the given noise model. In addition to setting the simulator's noise model, it also overrides the simulator's basis gates, according to the gates of the noise model.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "71749280-7266-46ae-ab61-e1b3a5a345b3",
      "metadata": {
        "slideshow": {
          "slide_type": "subslide"
        }
      },
      "source": [
        "## Noise model examples\n",
        "\n",
        "We will now give some examples of noise models. For our demonstrations we use a simple test circuit generating an n-qubit GHZ state:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "41bad6bd-c69d-4024-a3a4-1c6fede88c9e",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:48.817405Z",
          "start_time": "2019-08-19T17:00:48.806966Z"
        },
        "slideshow": {
          "slide_type": "fragment"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "        ┌───┐                ░ ┌─┐         \n",
            "   q_0: ┤ H ├──■─────────────░─┤M├─────────\n",
            "        └───┘┌─┴─┐           ░ └╥┘┌─┐      \n",
            "   q_1: ─────┤ X ├──■────────░──╫─┤M├──────\n",
            "             └───┘┌─┴─┐      ░  ║ └╥┘┌─┐   \n",
            "   q_2: ──────────┤ X ├──■───░──╫──╫─┤M├───\n",
            "                  └───┘┌─┴─┐ ░  ║  ║ └╥┘┌─┐\n",
            "   q_3: ───────────────┤ X ├─░──╫──╫──╫─┤M├\n",
            "                       └───┘ ░  ║  ║  ║ └╥┘\n",
            "meas: 4/════════════════════════╩══╩══╩══╩═\n",
            "                                0  1  2  3 \n"
          ]
        }
      ],
      "source": [
        "# System Specification\n",
        "n_qubits = 4\n",
        "circ = QuantumCircuit(n_qubits)\n",
        "\n",
        "# Test Circuit\n",
        "circ.h(0)\n",
        "for qubit in range(n_qubits - 1):\n",
        "    circ.cx(qubit, qubit + 1)\n",
        "circ.measure_all()\n",
        "print(circ)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "2b945a56-d136-4c1d-8b02-e8ea962329b9",
      "metadata": {},
      "source": [
        "### Ideal simulation\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "6fe5c53d-3536-471f-aceb-b4b48a8a5889",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:50.560988Z",
          "start_time": "2019-08-19T17:00:50.415545Z"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/build-noise-models/extracted-outputs/6fe5c53d-3536-471f-aceb-b4b48a8a5889-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Ideal simulator and execution\n",
        "sim_ideal = AerSimulator()\n",
        "result_ideal = sim_ideal.run(circ).result()\n",
        "plot_histogram(result_ideal.get_counts(0))"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "dd61a153-cb72-40db-8673-fd3c323c3ab0",
      "metadata": {
        "slideshow": {
          "slide_type": "subslide"
        }
      },
      "source": [
        "## Noise example 1: Basic bit-flip error noise model\n",
        "\n",
        "Let's consider a simple toy noise model example common in quantum information theory research:\n",
        "\n",
        "* When applying a single-qubit gate, flip the state of the qubit with probability `p_gate1`.\n",
        "* When applying a two-qubit gate, apply single-qubit errors to each qubit.\n",
        "* When resetting a qubit, reset to 1 instead of 0 with probability `p_reset`.\n",
        "* When measuring a qubit, flip the state of the qubit with probability `p_meas`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "dbea22f5-4c5d-4727-b5cf-f8c3f488ef59",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:51.543615Z",
          "start_time": "2019-08-19T17:00:51.536564Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "NoiseModel:\n",
            "  Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']\n",
            "  Instructions with noise: ['cx', 'u2', 'measure', 'reset', 'u1', 'u3']\n",
            "  All-qubits errors: ['reset', 'measure', 'u1', 'u2', 'u3', 'cx']\n"
          ]
        }
      ],
      "source": [
        "# Example error probabilities\n",
        "p_reset = 0.03\n",
        "p_meas = 0.1\n",
        "p_gate1 = 0.05\n",
        "\n",
        "# QuantumError objects\n",
        "error_reset = pauli_error([(\"X\", p_reset), (\"I\", 1 - p_reset)])\n",
        "error_meas = pauli_error([(\"X\", p_meas), (\"I\", 1 - p_meas)])\n",
        "error_gate1 = pauli_error([(\"X\", p_gate1), (\"I\", 1 - p_gate1)])\n",
        "error_gate2 = error_gate1.tensor(error_gate1)\n",
        "\n",
        "# Add errors to noise model\n",
        "noise_bit_flip = NoiseModel()\n",
        "noise_bit_flip.add_all_qubit_quantum_error(error_reset, \"reset\")\n",
        "noise_bit_flip.add_all_qubit_quantum_error(error_meas, \"measure\")\n",
        "noise_bit_flip.add_all_qubit_quantum_error(error_gate1, [\"u1\", \"u2\", \"u3\"])\n",
        "noise_bit_flip.add_all_qubit_quantum_error(error_gate2, [\"cx\"])\n",
        "\n",
        "print(noise_bit_flip)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "15112a49-4353-46b8-8ddc-7060d01761a6",
      "metadata": {},
      "source": [
        "### Execute the noisy simulation\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "e38e4581-7718-4dc0-a550-e6b3168bd400",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:52.951874Z",
          "start_time": "2019-08-19T17:00:52.687440Z"
        },
        "slideshow": {
          "slide_type": "-"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/build-noise-models/extracted-outputs/e38e4581-7718-4dc0-a550-e6b3168bd400-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Create noisy simulator backend\n",
        "sim_noise = AerSimulator(noise_model=noise_bit_flip)\n",
        "\n",
        "# Transpile circuit for noisy basis gates\n",
        "passmanager = generate_preset_pass_manager(\n",
        "    optimization_level=3, backend=sim_noise\n",
        ")\n",
        "circ_tnoise = passmanager.run(circ)\n",
        "\n",
        "# Run and get counts\n",
        "result_bit_flip = sim_noise.run(circ_tnoise).result()\n",
        "counts_bit_flip = result_bit_flip.get_counts(0)\n",
        "\n",
        "# Plot noisy output\n",
        "plot_histogram(counts_bit_flip)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "cb0c808d-4988-4106-ba40-9205b78ebe5d",
      "metadata": {},
      "source": [
        "## Example 2: T1/T2 thermal relaxation\n",
        "\n",
        "Now consider a more realistic error model based on thermal relaxation with the qubit environment:\n",
        "\n",
        "* Each qubit is parameterized by a thermal relaxation time constant $T_1$ and a dephasing time constant $T_2$.\n",
        "* Note that we must have $T_2 \\le 2 T_1$.\n",
        "* Error rates on instructions are determined by gate times and qubit $T_1$, $T_2$ values.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "992aefee-7d14-43bb-986a-ecaf20d35fb8",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:54.577456Z",
          "start_time": "2019-08-19T17:00:54.491018Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "NoiseModel:\n",
            "  Basis gates: ['cx', 'id', 'rz', 'sx', 'u2', 'u3']\n",
            "  Instructions with noise: ['cx', 'u2', 'measure', 'reset', 'u3']\n",
            "  Qubits with noise: [0, 1, 2, 3]\n",
            "  Specific qubit errors: [('reset', (0,)), ('reset', (1,)), ('reset', (2,)), ('reset', (3,)), ('measure', (0,)), ('measure', (1,)), ('measure', (2,)), ('measure', (3,)), ('u2', (0,)), ('u2', (1,)), ('u2', (2,)), ('u2', (3,)), ('u3', (0,)), ('u3', (1,)), ('u3', (2,)), ('u3', (3,)), ('cx', (0, 0)), ('cx', (0, 1)), ('cx', (0, 2)), ('cx', (0, 3)), ('cx', (1, 0)), ('cx', (1, 1)), ('cx', (1, 2)), ('cx', (1, 3)), ('cx', (2, 0)), ('cx', (2, 1)), ('cx', (2, 2)), ('cx', (2, 3)), ('cx', (3, 0)), ('cx', (3, 1)), ('cx', (3, 2)), ('cx', (3, 3))]\n"
          ]
        }
      ],
      "source": [
        "# T1 and T2 values for qubits 0-3\n",
        "T1s = np.random.normal(\n",
        "    50e3, 10e3, 4\n",
        ")  # Sampled from normal distribution mean 50 microsec\n",
        "T2s = np.random.normal(\n",
        "    70e3, 10e3, 4\n",
        ")  # Sampled from normal distribution mean 50 microsec\n",
        "\n",
        "# Truncate random T2s <= T1s\n",
        "T2s = np.array([min(T2s[j], 2 * T1s[j]) for j in range(4)])\n",
        "\n",
        "# Instruction times (in nanoseconds)\n",
        "time_u1 = 0  # virtual gate\n",
        "time_u2 = 50  # (single X90 pulse)\n",
        "time_u3 = 100  # (two X90 pulses)\n",
        "time_cx = 300\n",
        "time_reset = 1000  # 1 microsecond\n",
        "time_measure = 1000  # 1 microsecond\n",
        "\n",
        "# QuantumError objects\n",
        "errors_reset = [\n",
        "    thermal_relaxation_error(t1, t2, time_reset) for t1, t2 in zip(T1s, T2s)\n",
        "]\n",
        "errors_measure = [\n",
        "    thermal_relaxation_error(t1, t2, time_measure) for t1, t2 in zip(T1s, T2s)\n",
        "]\n",
        "errors_u1 = [\n",
        "    thermal_relaxation_error(t1, t2, time_u1) for t1, t2 in zip(T1s, T2s)\n",
        "]\n",
        "errors_u2 = [\n",
        "    thermal_relaxation_error(t1, t2, time_u2) for t1, t2 in zip(T1s, T2s)\n",
        "]\n",
        "errors_u3 = [\n",
        "    thermal_relaxation_error(t1, t2, time_u3) for t1, t2 in zip(T1s, T2s)\n",
        "]\n",
        "errors_cx = [\n",
        "    [\n",
        "        thermal_relaxation_error(t1a, t2a, time_cx).expand(\n",
        "            thermal_relaxation_error(t1b, t2b, time_cx)\n",
        "        )\n",
        "        for t1a, t2a in zip(T1s, T2s)\n",
        "    ]\n",
        "    for t1b, t2b in zip(T1s, T2s)\n",
        "]\n",
        "\n",
        "# Add errors to noise model\n",
        "noise_thermal = NoiseModel()\n",
        "for j in range(4):\n",
        "    noise_thermal.add_quantum_error(errors_reset[j], \"reset\", [j])\n",
        "    noise_thermal.add_quantum_error(errors_measure[j], \"measure\", [j])\n",
        "    noise_thermal.add_quantum_error(errors_u1[j], \"u1\", [j])\n",
        "    noise_thermal.add_quantum_error(errors_u2[j], \"u2\", [j])\n",
        "    noise_thermal.add_quantum_error(errors_u3[j], \"u3\", [j])\n",
        "    for k in range(4):\n",
        "        noise_thermal.add_quantum_error(errors_cx[j][k], \"cx\", [j, k])\n",
        "\n",
        "print(noise_thermal)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "95144ee3-fe32-407a-94a1-f24e325f1ebb",
      "metadata": {},
      "source": [
        "### Execute the noisy simulation\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "284e4fb1-726e-4ecf-a200-cbfae8baaef7",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2019-08-19T17:00:55.689241Z",
          "start_time": "2019-08-19T17:00:55.515394Z"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/build-noise-models/extracted-outputs/284e4fb1-726e-4ecf-a200-cbfae8baaef7-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 17,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Run the noisy simulation\n",
        "sim_thermal = AerSimulator(noise_model=noise_thermal)\n",
        "\n",
        "# Transpile circuit for noisy basis gates\n",
        "passmanager = generate_preset_pass_manager(\n",
        "    optimization_level=3, backend=sim_thermal\n",
        ")\n",
        "circ_tthermal = passmanager.run(circ)\n",
        "\n",
        "# Run and get counts\n",
        "result_thermal = sim_thermal.run(circ_tthermal).result()\n",
        "counts_thermal = result_thermal.get_counts(0)\n",
        "\n",
        "# Plot noisy output\n",
        "plot_histogram(counts_thermal)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fcb3baa7-36a7-423b-8d32-6f2ed2ecd5d2",
      "metadata": {},
      "source": [
        "## Next steps\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommendations\">\n",
        "  * To simulate noisy circuits, see [Exact and noisy simulation with Qiskit Aer primitives](./simulate-with-qiskit-sdk-primitives).\n",
        "  * Review the [Qiskit Aer noise module](https://qiskit.org/ecosystem/aer/apidocs/aer_noise.html) reference.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}