{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "frontmatter",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Inicio rápido\"\n",
        "description: \"Guía de inicio rápido para la última versión de Qiskit: absorción de ruido propagado\"\n",
        "---\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0b3182b6",
      "metadata": {},
      "source": [
        "<span id=\"quickstart\" />\n",
        "\n",
        "# Inicio rápido\n",
        "\n",
        "Esta guía muestra un ejemplo mínimo y funcional del paquete `qiskit-addon-pna` . Utilizamos la absorción de ruido propagada (PNA) para construir un observable que mitigue el ruido. Dado un circuito y un modelo de ruido de Pauli-Lindblad, el PNA propaga clásicamente la observable a través del canal de ruido inverso. La medición de la magnitud observable resultante en la QPU con ruido atenúa el ruido de las puertas aprendidas.\n",
        "\n",
        "Para ver cómo crear un flujo de trabajo realista y ejecutarlo en hardware cuántico con el [modelo de ejecución dirigida](/docs/guides/directed-execution-model), incluido el aprendizaje del modelo de ruido con `NoiseLearnerV3`, consulta el [tutorial](/docs/tutorials/propagated-noise-absorption) de PNA en IBM Quantum Platform.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4068f26",
      "metadata": {},
      "source": [
        "<span id=\"1-prepare-the-inputs-for-pna\" />\n",
        "\n",
        "## 1. Preparar los datos de entrada para PNA\n",
        "\n",
        "El PNA toma como entradas un circuito, un modelo de ruido y una variable observable. Aquí construimos un modelo de Ising de campo transversal «trotterizado» de 10 qubits en una cadena de tipo « 1D ». Generamos un modelo aleatorio de ruido de Pauli-Lindblad de 2 locales para cada puerta de entrelazamiento y lo incorporamos como una instrucción de Qiskit Aer `PauliLindbladError` justo antes de dicha puerta. Elegimos un observable de Pauli-Z weight-4 para medirlo.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "4a9a3ced",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-pna/guides/quickstart/extracted-outputs/4a9a3ced-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import numpy as np\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.quantum_info import SparsePauliOp, pauli_basis\n",
        "from qiskit_aer.noise import PauliLindbladError\n",
        "\n",
        "\n",
        "def random_pauli_lindblad_noise(generators, seed, noise_scale=2e-3):\n",
        "    rates = np.random.default_rng(seed).random(len(generators)) * noise_scale\n",
        "    return PauliLindbladError(generators, rates)\n",
        "\n",
        "\n",
        "def ising_circuit(\n",
        "    num_qubits,\n",
        "    layers,\n",
        "    edge_noise=None,\n",
        "    *,\n",
        "    num_steps=3,\n",
        "    rx_angle=np.pi / 8,\n",
        "    rzz_angle=-np.pi / 2,\n",
        "):\n",
        "    \"\"\"Trotterized transverse-field Ising model; edge_noise=None gives the noiseless circuit.\"\"\"\n",
        "    qc = QuantumCircuit(num_qubits)\n",
        "    for _ in range(num_steps):\n",
        "        qc.rx(rx_angle, range(num_qubits))\n",
        "        for layer in layers:\n",
        "            for edge in layer:\n",
        "                if edge_noise is not None:\n",
        "                    qc.append(\n",
        "                        edge_noise[edge], edge\n",
        "                    )  # inject synthetic gate noise\n",
        "                qc.rzz(rzz_angle, *edge)\n",
        "    return qc\n",
        "\n",
        "\n",
        "num_qubits = 10\n",
        "\n",
        "# Two entangling layers per Trotter step: even and odd bonds of a 1D chain\n",
        "layers = [\n",
        "    [(i, i + 1) for i in range(0, num_qubits - 1, 2)],\n",
        "    [(i, i + 1) for i in range(1, num_qubits - 1, 2)],\n",
        "]\n",
        "edges = [edge for layer in layers for edge in layer]\n",
        "\n",
        "# Random 2-local Pauli-Lindblad noise, one instance per entangling gate\n",
        "two_qubit_paulis = SparsePauliOp(\n",
        "    [p for p in pauli_basis(2) if np.sum(p.x + p.z)]\n",
        ").paulis\n",
        "edge_noise = {\n",
        "    edge: random_pauli_lindblad_noise(two_qubit_paulis, seed=1234 + j)\n",
        "    for j, edge in enumerate(edges)\n",
        "}\n",
        "\n",
        "noisy_circuit = ising_circuit(num_qubits, layers, edge_noise)\n",
        "\n",
        "# A single weight-4 observable: <Z3 Z4 Z5 Z6>\n",
        "observable = SparsePauliOp.from_sparse_list(\n",
        "    [(\"ZZZZ\", [3, 4, 5, 6], 1.0)], num_qubits=num_qubits\n",
        ")\n",
        "\n",
        "noisy_circuit.draw(\"mpl\", fold=-1, scale=0.6)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b99617c3",
      "metadata": {},
      "source": [
        "<span id=\"2-generate-the-noise-mitigating-observable\" />\n",
        "\n",
        "## 2. Generar la observable de mitigación del ruido\n",
        "\n",
        "[«generate\\_noise\\_mitigating\\_observable»](/docs/api/qiskit-addon-pna/qiskit-addon-pna#generate_noise_mitigating_observable) propaga cada generador de Pauli del canal de ruido inverso hacia adelante hasta el final del circuito. A continuación, la observable se propaga hacia atrás a través del canal de ruido inverso, lo que devuelve una nueva observable $\\tilde{O}$. Hay tres parámetros clave que influyen en el coste computacional:\n",
        "\n",
        "* `max_err_terms`: el número de términos que se conservan en cada generador antirruido a medida que se propaga hacia adelante.\n",
        "* `max_obs_terms`: el número de términos que se conservan en $\\tilde{O}$.\n",
        "* `atol`: los términos cuyo coeficiente sea inferior a este umbral se descartan.\n",
        "\n",
        "`atol`Para este pequeño circuito cercano a Clifford, fijamos los límites de los términos en valores elevados y utilizamos un valor modesto, de modo que $\\tilde{O}$ sigue siendo pequeño y podemos medir todos sus términos.\n",
        "\n",
        "***Nota: Esta función utiliza Python `multiprocessing`. Si lo ejecutas como script, llámalo dentro de un `if __name__ == \"__main__\":` `guard`.***\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "39891ec7",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Original observable:         1 term\n",
            "Noise-mitigating observable: 207 terms\n"
          ]
        }
      ],
      "source": [
        "from qiskit_addon_pna import generate_noise_mitigating_observable\n",
        "\n",
        "mitigating_observable = generate_noise_mitigating_observable(\n",
        "    noisy_circuit,\n",
        "    observable,\n",
        "    max_err_terms=100_000,\n",
        "    max_obs_terms=100_000,\n",
        "    atol=1e-5,\n",
        "    num_processes=4,\n",
        ")\n",
        "\n",
        "print(f\"Original observable:         {len(observable)} term\")\n",
        "print(f\"Noise-mitigating observable: {len(mitigating_observable)} terms\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f7881a9e",
      "metadata": {},
      "source": [
        "<span id=\"3-mitigate-gate-errors-by-measuring-the-noise-mitigating-observable\" />\n",
        "\n",
        "## 3. Mitigar los errores de puerta midiendo el observable de mitigación del ruido\n",
        "\n",
        "Aquí vemos que el nuevo observable mitiga de forma efectiva el ruido de la puerta que afecta al experimento.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "a56dd204",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Ideal (noiseless):   0.8073\n",
            "Noisy (unmitigated): 0.6431\n",
            "Mitigated (PNA):     0.8071\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-pna/guides/quickstart/extracted-outputs/a56dd204-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "from qiskit_aer.primitives import EstimatorV2\n",
        "\n",
        "noiseless_circuit = ising_circuit(num_qubits, layers)\n",
        "\n",
        "# density_matrix method at zero precision -> exact expectation values (no shot noise)\n",
        "estimator = EstimatorV2(\n",
        "    options={\n",
        "        \"backend_options\": {\"method\": \"density_matrix\"},\n",
        "        \"default_precision\": 0.0,\n",
        "    }\n",
        ")\n",
        "\n",
        "ideal, noisy, mitigated = (\n",
        "    result.data.evs\n",
        "    for result in estimator.run(\n",
        "        [\n",
        "            (noiseless_circuit, observable),\n",
        "            (noisy_circuit, observable),\n",
        "            (noisy_circuit, mitigating_observable),\n",
        "        ]\n",
        "    ).result()\n",
        ")\n",
        "\n",
        "print(f\"Ideal (noiseless):   {ideal:.4f}\")\n",
        "print(f\"Noisy (unmitigated): {noisy:.4f}\")\n",
        "print(f\"Mitigated (PNA):     {mitigated:.4f}\")\n",
        "\n",
        "fig, ax = plt.subplots()\n",
        "ax.bar(\n",
        "    [\"Noisy\", \"Mitigated\"],\n",
        "    [noisy, mitigated],\n",
        "    width=0.6,\n",
        "    color=[\"#b0b0b0\", \"#4c4c4c\"],\n",
        ")\n",
        "ax.axhline(ideal, color=\"green\", linestyle=\"--\", label=\"Ideal (noiseless)\")\n",
        "ax.set_ylabel(r\"$\\langle Z_3 Z_4 Z_5 Z_6 \\rangle$\")\n",
        "ax.legend()\n",
        "plt.show()"
      ]
    },
    {
      "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": 5
}