{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "fad91a68",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Mitigación de errores\"\n",
        "description: \"A lo largo de esta lección, examinaremos el ruido y cómo se puede mitigar en los ordenadores cuánticos.\"\n",
        "---\n",
        "\n",
        "<span id=\"quantum-noise-and-error-mitigation\" />\n",
        "\n",
        "# Ruido cuántico y mitigación de errores\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Toshinari Itoko (28 de junio de 2024)\n",
        "\n",
        "  [Descargue el pdf](https://ibm.ent.box.com/public/static/a0zgies7bh91hm2lwev9o0bfeybxc6n6.zip) de la conferencia original. Tenga en cuenta que algunos fragmentos de código podrían quedar obsoletos, ya que se trata de imágenes estáticas.\n",
        "\n",
        "  *El tiempo aproximado de QPU para ejecutar este experimento es de 1 m 40 s.*\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e936adb0-bc31-41a8-b988-02ce7e68b902",
      "metadata": {},
      "source": [
        "<span id=\"1-introduction\" />\n",
        "\n",
        "## 1. Introducción\n",
        "\n",
        "A lo largo de esta lección, examinaremos el ruido y cómo puede mitigarse en los ordenadores cuánticos. Empezaremos analizando los efectos del ruido con un simulador que puede simular el ruido de varias formas, incluyendo el uso de perfiles de ruido de ordenadores cuánticos reales. Después pasaremos a los ordenadores cuánticos reales, en los que el ruido es inherente. Examinaremos los efectos de la mitigación de errores, incluidas combinaciones de elementos como la extrapolación de ruido cero (ZNE) y el gate-twirling.\n",
        "\n",
        "Empezaremos cargando algunos paquetes.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "38cf024b",
      "metadata": {},
      "outputs": [],
      "source": [
        "# !pip install qiskit qiskit_aer qiskit_ibm_runtime\n",
        "# !pip install jupyter\n",
        "# !pip install matplotlib pylatexenc"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "897008ea",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'2.0.2'"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit\n",
        "\n",
        "qiskit.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "486b4d35",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'0.17.1'"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit_aer\n",
        "\n",
        "qiskit_aer.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "994c44e5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'0.40.1'"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit_ibm_runtime\n",
        "\n",
        "qiskit_ibm_runtime.__version__"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ee48a826-fda3-4fb4-b50b-d69c38eb887f",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": "slide"
        },
        "tags": []
      },
      "source": [
        "<span id=\"2-noisy-simulation-without-error-mitigation\" />\n",
        "\n",
        "## 2. Simulación ruidosa sin mitigación de errores\n",
        "\n",
        "Qiskit Aer es un simulador clásico de computación cuántica. Puede simular no sólo la ejecución ideal, sino también la ejecución ruidosa de circuitos cuánticos. Este cuaderno muestra cómo ejecutar una simulación ruidosa utilizando Qiskit Aer:\n",
        "\n",
        "1. Construir un modelo de ruido\n",
        "2. Construir un muestreador ruidoso (simulador) con el modelo de ruido\n",
        "3. Ejecuta un circuito cuántico en el muestreador ruidoso\n",
        "\n",
        "```\n",
        "noise_model = NoiseModel()\n",
        "...\n",
        "noisy_sampler = Sampler(options={\"backend_options\": {\"noise_model\": noise_model}})\n",
        "job = noisy_sampler.run([circuit])\n",
        "```\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d1490ab8",
      "metadata": {},
      "source": [
        "<span id=\"21-build-a-test-circuit\" />\n",
        "\n",
        "### 2.1 Construir un circuito de prueba\n",
        "\n",
        "Consideramos circuitos de juguete de 1 qubit que simplemente repiten X puertas `d` veces (`d`=0... 100) y medir el observable `Z` .\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "b4863c66",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/b4863c66-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from qiskit.circuit import QuantumCircuit\n",
        "\n",
        "MAX_DEPTH = 100\n",
        "circuits = []\n",
        "for d in range(MAX_DEPTH + 1):\n",
        "    circ = QuantumCircuit(1)\n",
        "    for _ in range(d):\n",
        "        circ.x(0)\n",
        "        circ.barrier(0)\n",
        "    circ.measure_all()\n",
        "    circuits.append(circ)\n",
        "\n",
        "display(circuits[3].draw(output=\"mpl\"))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "a366502c",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "SparsePauliOp(['Z'],\n",
              "              coeffs=[1.+0.j])"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "obs = SparsePauliOp.from_list([(\"Z\", 1.0)])\n",
        "obs"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6200c2ed",
      "metadata": {},
      "source": [
        "<span id=\"22-build-a-noise-model\" />\n",
        "\n",
        "### 2.2 Construir un modelo de ruido\n",
        "\n",
        "Para realizar una simulación ruidosa, debemos especificar `NoiseModel`. En esta sección mostramos cómo construir `NoiseModel` .\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dae0c070",
      "metadata": {},
      "source": [
        "Primero tenemos que definir los errores cuánticos (o de lectura) para añadirlos a un modelo de ruido.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "1e0f1c12",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_aer.noise.errors import (\n",
        "    coherent_unitary_error,\n",
        "    amplitude_damping_error,\n",
        "    ReadoutError,\n",
        ")\n",
        "from qiskit.circuit.library import RXGate\n",
        "\n",
        "# Coherent (unitary) error: Over X-rotation error\n",
        "# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.coherent_unitary_error.html#qiskit_aer.noise.coherent_unitary_error\n",
        "OVER_ROTATION_ANGLE = 0.05\n",
        "coherent_error = coherent_unitary_error(RXGate(OVER_ROTATION_ANGLE).to_matrix())\n",
        "\n",
        "# Incoherent error: Amplitude dumping error\n",
        "# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.amplitude_damping_error.html#qiskit_aer.noise.amplitude_damping_error\n",
        "AMPLITUDE_DAMPING_PARAM = 0.02  # in [0, 1] (0: no error)\n",
        "incoherent_error = amplitude_damping_error(AMPLITUDE_DAMPING_PARAM)\n",
        "\n",
        "# Readout (measurement) error: Readout error\n",
        "# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.ReadoutError.html#qiskit_aer.noise.ReadoutError\n",
        "PREP0_MEAS1 = 0.03  # P(1|0): Probability of preparing 0 and measuring 1\n",
        "PREP1_MEAS0 = 0.08  # P(0|1): Probability of preparing 1 and measuring 0\n",
        "readout_error = ReadoutError(\n",
        "    [[1 - PREP0_MEAS1, PREP0_MEAS1], [PREP1_MEAS0, 1 - PREP1_MEAS0]]\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "e23c26ba",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_aer.noise import NoiseModel\n",
        "\n",
        "noise_model = NoiseModel()\n",
        "noise_model.add_quantum_error(coherent_error.compose(incoherent_error), \"x\", (0,))\n",
        "noise_model.add_readout_error(readout_error, (0,))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a786224",
      "metadata": {},
      "source": [
        "<span id=\"23-build-a-noisy-sampler-with-the-noise-model\" />\n",
        "\n",
        "### 2.3 Construye un muestreador ruidoso con el modelo de ruido\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "f8aded6f",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_aer.primitives import SamplerV2 as Sampler\n",
        "\n",
        "noisy_sampler = Sampler(options={\"backend_options\": {\"noise_model\": noise_model}})"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "922ba1ac",
      "metadata": {},
      "source": [
        "<span id=\"24-run-quantum-circuits-on-the-noisy-sampler\" />\n",
        "\n",
        "### 2.4 Ejecutar circuitos cuánticos en el muestreador ruidoso\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "4ae504e7",
      "metadata": {},
      "outputs": [],
      "source": [
        "job = noisy_sampler.run(circuits, shots=400)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "3b2fff25",
      "metadata": {},
      "outputs": [],
      "source": [
        "result = job.result()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "4dc12337",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'0': 389, '1': 11}"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result[0].data.meas.get_counts()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e654c5e",
      "metadata": {},
      "source": [
        "<span id=\"25-plot-results\" />\n",
        "\n",
        "### 2.5 Resultados de la trama\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1a25e394",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "plt.title(\"Noisy simulation\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    color=\"gray\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.scatter(ds, [result[d].data.meas.expectation_values([\"Z\"]) for d in ds], marker=\"o\")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.ylim(-1, 1)\n",
        "plt.xlabel(\"Circuit depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "09ef68bb",
      "metadata": {},
      "source": [
        "<span id=\"26-ideal-simulation\" />\n",
        "\n",
        "### 2.6 Simulación ideal\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "041abc81",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/041abc81-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "ideal_sampler = Sampler()\n",
        "job_ideal = ideal_sampler.run(circuits)\n",
        "result_ideal = job_ideal.result()\n",
        "plt.title(\"Ideal simulation\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result_ideal[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    color=\"gray\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.scatter(\n",
        "    ds, [result_ideal[d].data.meas.expectation_values([\"Z\"]) for d in ds], marker=\"o\"\n",
        ")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.xlabel(\"Circuit depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a1e1b6e6",
      "metadata": {},
      "source": [
        "<span id=\"27-exercise\" />\n",
        "\n",
        "### 2.7 Ejercicio\n",
        "\n",
        "Modificando el código siguiente,\n",
        "\n",
        "* [ ] Pruebe 25x número de disparos (= 10\\_000 disparos) y asegúrese de que se obtiene un gráfico más suave\n",
        "* [ ] Cambie los parámetros de ruido (OVER\\_ROTATION\\_ANGLE, AMPLITUDE\\_DAMPING\\_PARAM, PREP0\\_MEAS1, o PREP1\\_MEAS0 ) y vea cómo cambia el gráfico\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "502b9cfe",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/502b9cfe-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "OVER_ROTATION_ANGLE = 0.05\n",
        "coherent_error = coherent_unitary_error(RXGate(OVER_ROTATION_ANGLE).to_matrix())\n",
        "AMPLITUDE_DAMPING_PARAM = 0.02  # in [0, 1] (0: no error)\n",
        "incoherent_error = amplitude_damping_error(AMPLITUDE_DAMPING_PARAM)\n",
        "PREP0_MEAS1 = 0.1  # P(1|0): Probability of preparing 0 and measuring 1\n",
        "PREP1_MEAS0 = 0.05  # P(0|1): Probability of preparing 1 and measuring 0\n",
        "readout_error = ReadoutError(\n",
        "    [[1 - PREP0_MEAS1, PREP0_MEAS1], [PREP1_MEAS0, 1 - PREP1_MEAS0]]\n",
        ")\n",
        "noise_model = NoiseModel()\n",
        "noise_model.add_quantum_error(coherent_error.compose(incoherent_error), \"x\", (0,))\n",
        "noise_model.add_readout_error(readout_error, (0,))\n",
        "options = {\n",
        "    \"backend_options\": {\"noise_model\": noise_model},\n",
        "}\n",
        "noisy_sampler = Sampler(options=options)\n",
        "job = noisy_sampler.run(circuits, shots=400)\n",
        "result = job.result()\n",
        "plt.title(\"Noisy simulation\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    marker=\"o\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.ylim(-1, 1)\n",
        "plt.xlabel(\"Depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3cfe1a93",
      "metadata": {},
      "source": [
        "<span id=\"28-more-realistic-noisy-simulation\" />\n",
        "\n",
        "### 2.8 Simulación ruidosa más realista\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8d607bb5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<IBMBackend('ibm_strasbourg')>"
            ]
          },
          "execution_count": 17,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler, QiskitRuntimeService\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "real_backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")  # Eagle"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "81a67f2f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/81a67f2f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "aer = AerSimulator.from_backend(real_backend)\n",
        "noisy_sampler = Sampler(mode=aer)\n",
        "job = noisy_sampler.run(circuits)\n",
        "result = job.result()\n",
        "plt.title(\"Noisy simulation with noise model from real backend\")\n",
        "ds = list(range(MAX_DEPTH + 1))\n",
        "plt.plot(\n",
        "    ds,\n",
        "    [result[d].data.meas.expectation_values([\"Z\"]) for d in ds],\n",
        "    marker=\"o\",\n",
        "    linestyle=\"-\",\n",
        ")\n",
        "plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors=\"black\")\n",
        "plt.ylim(-1, 1)\n",
        "plt.xlabel(\"Depth\")\n",
        "plt.ylabel(\"Measured <Z>\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "567d30e9",
      "metadata": {},
      "source": [
        "<span id=\"3-real-quantum-computation-with-error-mitigation\" />\n",
        "\n",
        "## 3. Computación cuántica real con mitigación de errores\n",
        "\n",
        "En esta parte, demostramos cómo obtener resultados con error mitigado (valores de expectativa) utilizando el Estimador Qiskit.\n",
        "Consideramos circuitos trotterizados de 6 qubits para simular la evolución temporal de un modelo de Ising unidimensional y vemos cómo el error escala con respecto al número de pasos temporales.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "2d301499",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<IBMBackend('ibm_strasbourg')>"
            ]
          },
          "execution_count": 20,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")  # Eagle\n",
        "backend"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "6c90b89c",
      "metadata": {},
      "outputs": [],
      "source": [
        "NUM_QUBITS = 6\n",
        "NUM_TIME_STEPS = list(range(8))\n",
        "RX_ANGLE = 0.1\n",
        "RZZ_ANGLE = 0.1"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b1489739",
      "metadata": {},
      "source": [
        "<span id=\"31-build-circuits\" />\n",
        "\n",
        "### 3.1 Construir circuitos\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "1a77956e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Build circuits with different number of time steps\n",
        "circuits = []\n",
        "for n_steps in NUM_TIME_STEPS:\n",
        "    circ = QuantumCircuit(NUM_QUBITS)\n",
        "    for i in range(n_steps):\n",
        "        # rx layer\n",
        "        for q in range(NUM_QUBITS):\n",
        "            circ.rx(RX_ANGLE, q)\n",
        "        # 1st rzz layer\n",
        "        for q in range(1, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(RZZ_ANGLE, q, q + 1)\n",
        "        # 2nd rzz layer\n",
        "        for q in range(0, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(RZZ_ANGLE, q, q + 1)\n",
        "    circ.barrier()  # need not to optimize the circuit\n",
        "    # Uncompute stage\n",
        "    for i in range(n_steps):\n",
        "        for q in range(0, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(-RZZ_ANGLE, q, q + 1)\n",
        "        for q in range(1, NUM_QUBITS - 1, 2):\n",
        "            circ.rzz(-RZZ_ANGLE, q, q + 1)\n",
        "        for q in range(NUM_QUBITS):\n",
        "            circ.rx(-RX_ANGLE, q)\n",
        "    circuits.append(circ)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "94eb9062",
      "metadata": {},
      "source": [
        "Para conocer de antemano el resultado ideal, utilizamos circuitos de computación-descomputación que constan de una primera etapa en la que se aplica el circuito original $U$, y una segunda etapa en la que se invierte $U^\\dagger$. Nótese que el resultado ideal de tales circuitos será trivialmente el estado de entrada $|000000\\rangle$, que tiene los valores de expectativa triviales para cualquier observable de Pauli, por ejemplo, $\\langle IIIIIZ \\rangle = 1$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "20296b5a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/20296b5a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 23,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Print the circuit with 2 time steps\n",
        "circuits[2].draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cde8d3ea",
      "metadata": {},
      "source": [
        "Nota: Como se muestra arriba, el circuito con $k$ pasos de tiempo tendrá $4k$ capas de puerta de dos qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "af0d03e9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "SparsePauliOp(['IIIIIZ'],\n",
              "              coeffs=[1.+0.j])"
            ]
          },
          "execution_count": 24,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "obs = SparsePauliOp.from_sparse_list([(\"Z\", [0], 1.0)], num_qubits=NUM_QUBITS)\n",
        "obs"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ebd6ea9b",
      "metadata": {},
      "source": [
        "<span id=\"32-transpile-the-circuits\" />\n",
        "\n",
        "### 3.2 Transpilar los circuitos\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8eaa552e",
      "metadata": {},
      "source": [
        "Transpilamos los circuitos para el backend con optimización (`optimization_level=1`).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "87b861e2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/87b861e2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
        "isa_circuits = pm.run(circuits)\n",
        "display(isa_circuits[2].draw(\"mpl\", idle_wires=False, fold=-1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "743ad427",
      "metadata": {},
      "source": [
        "<span id=\"33-execute-using-estimator-with-different-resilience-levels\" />\n",
        "\n",
        "### 3.3 Ejecutar utilizando Estimator (con diferentes niveles de resiliencia)\n",
        "\n",
        "Configurar el nivel de resiliencia (`estimator.options.resilience_level`) es la forma más sencilla de aplicar la mitigación de errores al utilizar Qiskit Estimator. Estimator admite los siguientes niveles de resiliencia (a fecha de 28 de junio de 2024). Consulte más detalles en la guía [de configuración de la mitigación de errores](/docs/guides/error-mitigation-and-suppression-techniques).\n",
        "\n",
        "![image.png](https://eu-de.quantum.cloud.ibm.com/learning/images/courses/utility-scale-quantum-computing/error-mitigation/res_level.avif)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "328f71f2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID (rl=0): d146vcnmya70008emprg\n",
            "Job ID (rl=1): d146vdnqf56g0081sva0\n",
            "Job ID (rl=2): d146ven5z6q00087c61g\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import Batch\n",
        "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n",
        "\n",
        "jobs = []\n",
        "job_ids = []\n",
        "with Batch(backend=backend):\n",
        "    for resilience_level in [0, 1, 2]:\n",
        "        estimator = Estimator()\n",
        "        estimator.options.resilience_level = resilience_level\n",
        "        job = estimator.run(\n",
        "            [(circ, obs.apply_layout(circ.layout)) for circ in isa_circuits]\n",
        "        )\n",
        "        job_ids.append(job.job_id())\n",
        "        print(f\"Job ID (rl={resilience_level}): {job.job_id()}\")\n",
        "        jobs.append(job)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "1dd804e4-0d7d-4782-9559-7b3796cab121",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE\n",
            "DONE\n",
            "DONE\n"
          ]
        }
      ],
      "source": [
        "# check job status\n",
        "for job in jobs:\n",
        "    print(job.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "d138e1e9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# REPLACE WITH YOUR OWN JOB IDS\n",
        "jobs = [service.job(job_id) for job_id in job_ids]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "ea820e98",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Get results\n",
        "results = [job.result() for job in jobs]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e3691462",
      "metadata": {},
      "source": [
        "<span id=\"34-plot-results\" />\n",
        "\n",
        "### 3.4 Resultados de la trama\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "7527976e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/error-mitigation/extracted-outputs/7527976e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.title(\"Error mitigation with different resilience levels\")\n",
        "labels = [\"0 (No mitigation)\", \"1 (TREX)\", \"2 (ZNE + Gate twirling)\"]\n",
        "steps = NUM_TIME_STEPS\n",
        "for result, label in zip(results, labels):\n",
        "    plt.errorbar(\n",
        "        x=steps,\n",
        "        y=[result[s].data.evs for s in steps],\n",
        "        yerr=[result[s].data.stds for s in steps],\n",
        "        marker=\"o\",\n",
        "        linestyle=\"-\",\n",
        "        capsize=4,\n",
        "        label=label,\n",
        "    )\n",
        "plt.hlines(\n",
        "    1.0, min(steps), max(steps), linestyle=\"dashed\", label=\"Ideal\", colors=\"black\"\n",
        ")\n",
        "plt.xlabel(\"Time steps\")\n",
        "plt.ylabel(\"Mitigated <IIIIIZ>\")\n",
        "plt.legend()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e4def30b",
      "metadata": {},
      "source": [
        "<span id=\"4-optional-customize-error-mitigation-options\" />\n",
        "\n",
        "## 5. (Opcional) Personalizar las opciones de mitigación de errores\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f099e16c",
      "metadata": {},
      "source": [
        "Podemos personalizar la aplicación de las técnicas de mitigación de errores mediante las opciones que se muestran a continuación.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "a22e6b8c",
      "metadata": {},
      "outputs": [],
      "source": [
        "# TREX\n",
        "estimator.options.twirling.enable_measure = True\n",
        "estimator.options.twirling.num_randomizations = \"auto\"\n",
        "estimator.options.twirling.shots_per_randomization = \"auto\"\n",
        "\n",
        "# Gate twirling\n",
        "estimator.options.twirling.enable_gates = True\n",
        "# ZNE\n",
        "estimator.options.resilience.zne_mitigation = True\n",
        "estimator.options.resilience.zne.noise_factors = [1, 3, 5]\n",
        "estimator.options.resilience.zne.extrapolator = (\"exponential\", \"linear\")\n",
        "\n",
        "# Dynamical decoupling\n",
        "estimator.options.dynamical_decoupling.enable = True  # Default: False\n",
        "estimator.options.dynamical_decoupling.sequence_type = \"XX\"\n",
        "\n",
        "# Other options\n",
        "estimator.options.default_shots = 10_000"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "79dd06fb",
      "metadata": {},
      "source": [
        "Consulte las siguientes guías y la referencia API para conocer los detalles de las opciones de mitigación de errores.\n",
        "\n",
        "* [Configurar la mitigación de errores](/docs/guides/error-mitigation-and-suppression-techniques)\n",
        "* [Introducción a las opciones](/docs/guides/runtime-options-overview)\n",
        "* [EstimatorOptions](/docs/api/qiskit-ibm-runtime/options-estimator-options)\n",
        "* [SamplerOptions](/docs/api/qiskit-ibm-runtime/options-sampler-options)\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"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}