{
  "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 la retropropagación del operador (OBP)\"\n",
        "---\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "intro",
      "metadata": {},
      "source": [
        "<span id=\"quick-start\" />\n",
        "\n",
        "# Inicio rápido\n",
        "\n",
        "Esta guía muestra un ejemplo mínimo y funcional del paquete `qiskit-addon-obp` . Utilizamos la retropropagación de operadores (OBP) para reducir la profundidad de un circuito cuántico mediante la absorción de las puertas finales en el observable.\n",
        "\n",
        "El valor esperado $\\langle O \\rangle = \\langle \\psi | U^\\dagger O U | \\psi \\rangle$ no varía si eliminamos un bloque de puertas situado al final del circuito $U$ y conjugamos el observable con él de forma clásica. OBP aplica este proceso repetidamente, evaluando parte del circuito de forma clásica para que solo se ejecute en el hardware una parte más superficial del mismo. El precio a pagar es que cada puerta absorbida puede ampliar el observable a más términos de Pauli, por lo que la profundidad que se ahorra debe sopesarse con el aumento del observable.\n",
        "\n",
        "Para ver ejemplos de cómo crear flujos de trabajo realistas con esta herramienta y ejecutarlos en hardware cuántico, consulta los tutoriales de la Plataforma de Búsqueda de Órdenes ( IBM Quantum Platform, [OBP Tutorial](/docs/tutorials/operator-back-propagation) ).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "inputs-header",
      "metadata": {},
      "source": [
        "<span id=\"prepare-inputs-for-obp\" />\n",
        "\n",
        "## Preparar los datos para el OBP\n",
        "\n",
        "OBP toma como entrada una lista de segmentos de circuito y una variable observable. Realiza una retropropagación de las secciones una a una, desde el final del circuito hasta el observable, lo que reduce la profundidad del circuito a costa de la aparición de términos de Pauli adicionales en el observable. Aquí generamos un circuito de evolución temporal para un modelo de Heisenberg de 10 qubits y lo dividimos por tipo de puerta.\n",
        "\n",
        "A continuación dibujamos el circuito original y, a continuación, el mismo circuito recombinado con barreras que marcan los límites de los segmentos; cada segmento es una unidad que puede integrarse en el observable en un único paso de retropropagación.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "setup-inputs",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Original circuit depth: 18\n",
            "Number of slices: 18\n",
            "Observable terms: 1\n"
          ]
        }
      ],
      "source": [
        "import numpy as np\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.synthesis import LieTrotter\n",
        "from qiskit.transpiler import CouplingMap\n",
        "from qiskit_addon_utils.problem_generators import (\n",
        "    generate_time_evolution_circuit,\n",
        "    generate_xyz_hamiltonian,\n",
        ")\n",
        "from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types\n",
        "\n",
        "# Generate a circuit to reduce\n",
        "coupling_map = CouplingMap.from_heavy_hex(3, bidirectional=False)\n",
        "reduced_coupling_map = coupling_map.reduce(\n",
        "    [0, 13, 1, 14, 10, 16, 5, 12, 8, 18]\n",
        ")\n",
        "\n",
        "hamiltonian = generate_xyz_hamiltonian(\n",
        "    reduced_coupling_map,\n",
        "    coupling_constants=(np.pi / 8, np.pi / 4, np.pi / 2),\n",
        "    ext_magnetic_field=(np.pi / 3, np.pi / 6, np.pi / 9),\n",
        ")\n",
        "\n",
        "circuit = generate_time_evolution_circuit(\n",
        "    hamiltonian,\n",
        "    time=0.2,\n",
        "    synthesis=LieTrotter(reps=2),\n",
        ")\n",
        "\n",
        "# Slice the circuit and define an observable\n",
        "slices = slice_by_gate_types(circuit)\n",
        "observable = SparsePauliOp(\"IIIIIIIIIZ\")\n",
        "\n",
        "print(f\"Original circuit depth: {circuit.depth()}\")\n",
        "print(f\"Number of slices: {len(slices)}\")\n",
        "print(f\"Observable terms: {len(observable)}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "46efdcfc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Original circuit:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-obp/guides/quickstart/extracted-outputs/46efdcfc-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Sliced circuit (recombined with barriers for visualization)\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-obp/guides/quickstart/extracted-outputs/46efdcfc-3.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Recombine the slices with barriers to make the slice boundaries visible\n",
        "sliced_circuit = combine_slices(slices, include_barriers=True)\n",
        "\n",
        "print(\"Original circuit:\")\n",
        "display(circuit.draw(\"mpl\", scale=0.6, fold=-1))\n",
        "print(\"Sliced circuit (recombined with barriers for visualization)\")\n",
        "sliced_circuit.draw(\"mpl\", scale=0.6, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "obp-header",
      "metadata": {},
      "source": [
        "<span id=\"reduce-circuit-depth-with-obp\" />\n",
        "\n",
        "## Reducir la profundidad del circuito con OBP\n",
        "\n",
        "Llamamos a esta función `backpropagate` para incorporar segmentos al observable. La función devuelve el observable expandido, los segmentos del circuito por los que no se ha propagado la señal y los metadatos sobre el procedimiento.\n",
        "\n",
        "Si no se controla, la magnitud observable puede crecer hasta alcanzar términos de Pauli de tipo « $2^n$ ». Esto limita `operator_budget` dicho crecimiento: en este caso permitimos como máximo 8 grupos conmutativos en términos de qubits, lo que establece, a grandes rasgos, el número de intentos necesarios para evaluar el observable en la QPU. La retropropagación se detiene en cuanto la absorción del siguiente segmento superaría el presupuesto, que es precisamente lo que ocurre a continuación: solo se absorben 7 de los 18 segmentos antes de que el observable llene los 8 grupos de conmutación y el procedimiento se detenga.\n",
        "\n",
        "Para profundizar aún más en el circuito, se `backpropagate` puede utilizar el argumento de `truncation_error_budget` palabra clave de para eliminar los términos de Pauli con coeficientes pequeños del observable a medida que este crece. Esto atenúa el crecimiento de la magnitud observable a cambio de un error proporcional a la magnitud de los términos de Pauli que se truncan. Los dos presupuestos son complementarios y pueden utilizarse conjuntamente: `operator_budget` controla el *tamaño* de la variable observable, mientras que `truncation_error_budget` controla el *error* que se produce al descartar términos.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "run-obp",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Backpropagated 7 of 18 slices.\n",
            "Reduced circuit depth: 11 (was 18)\n",
            "Observable grew from 1 to 18 Pauli terms.\n",
            "Filled 8 of 8 commuting groups, exhausting the budget.\n"
          ]
        }
      ],
      "source": [
        "from qiskit_addon_obp import backpropagate\n",
        "from qiskit_addon_obp.utils.simplify import OperatorBudget\n",
        "\n",
        "max_qwc_groups = 8\n",
        "bp_obs, remaining_slices, metadata = backpropagate(\n",
        "    observable,\n",
        "    slices,\n",
        "    operator_budget=OperatorBudget(max_qwc_groups=max_qwc_groups),\n",
        ")\n",
        "\n",
        "reduced_circuit = combine_slices(remaining_slices)\n",
        "num_groups = len(bp_obs.group_commuting(qubit_wise=True))\n",
        "\n",
        "print(\n",
        "    f\"Backpropagated {metadata.num_backpropagated_slices} of {len(slices)} slices.\"\n",
        ")\n",
        "print(\n",
        "    f\"Reduced circuit depth: {reduced_circuit.depth()} (was {circuit.depth()})\"\n",
        ")\n",
        "print(f\"Observable grew from {len(observable)} to {len(bp_obs)} Pauli terms.\")\n",
        "print(\n",
        "    f\"Filled {num_groups} of {max_qwc_groups} commuting groups, exhausting the budget.\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "b006625e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-obp/guides/quickstart/extracted-outputs/b006625e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "reduced_circuit.draw(\"mpl\", scale=0.6, fold=-1)"
      ]
    },
    {
      "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
}