{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "frontmatter",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Démarrage rapide\"\n",
        "description: \"Guide de démarrage rapide pour la dernière version de Pauli Propagation\"\n",
        "---\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a9320fa8-31c5-4248-96b0-3549a13dda6f",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Démarrage rapide\"\n",
        "description: \"Guide de démarrage rapide pour le package d'extensions pauli-prop de Qiskit\"\n",
        "---\n",
        "\n",
        "<span id=\"quickstart\" />\n",
        "\n",
        "# Démarrage rapide\n",
        "\n",
        "Dans ce guide, nous utilisons le package `pauli-prop` pour simuler de manière classique la dynamique temporelle d’un modèle d’Ising à 10 qubits avec effet de « kick » sur une chaîne de spins de type « 1D ».\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3b5bf7dc-1cd8-41d3-b8ce-cc75a66fed8d",
      "metadata": {},
      "source": [
        "<span id=\"prepare-the-inputs-for-pauli-propagation\" />\n",
        "\n",
        "## Préparez les données d'entrée pour la propagation de Pauli\n",
        "\n",
        "L'hamiltonien considéré est le suivant :\n",
        "\n",
        "$H = -J\\sum\\limits_{\\langle i,j \\rangle} Z_iZ_j + h\\sum\\limits_iX_i$\n",
        "\n",
        "où $J>0$ décrit le couplage entre les spins voisins les plus proches, $i<j$, et $h$ représente le champ transversal global. Une décomposition de Trotter du premier ordre de l'opérateur évolué dans le temps sera mise en œuvre sous la forme d'un circuit quantique, $U$, sur $20$ étapes de Trotter. La constante de couplage, $J$, sera fixée à $J=-\\frac{\\pi}{2}$, et $h$ sera fixée à $\\frac{\\pi}{6}$. Les interactions $ZZ$ seront mises en œuvre à l'aide de portes de Clifford ( $CX$, $Sdg$, $\\sqrt{Y}$ ).\n",
        "\n",
        "Nous mettons en œuvre l'évolution temporelle « trotterisée » sous la forme d'un circuit quantique et utilisons l' $\\frac{\\pi}{6}$ e pour les rotations non-Clifford autour de l'axe x. Plus ces angles s'éloignent des angles de Clifford (par exemple, $\\theta=n\\frac{\\pi}{2}, n \\in \\mathbb{Z}$ ), plus la simulation du système sera difficile à réaliser avec les méthodes de propagation de Pauli.\n",
        "\n",
        "Pour le choix de la grandeur observable, nous considérons la magnétisation moyenne d'un site unique, $\\frac{1}{N} \\sum_{i=1}^{N} \\langle z_i \\rangle$, où $N$ est le nombre de spins.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "15d5eccf-eef0-4435-b67a-98a8038c400e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/pauli-prop/guides/quickstart/extracted-outputs/15d5eccf-eef0-4435-b67a-98a8038c400e-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\n",
        "from qiskit.transpiler import CouplingMap\n",
        "\n",
        "num_qubits = 10\n",
        "coupling_map = CouplingMap.from_line(num_qubits, bidirectional=False)\n",
        "\n",
        "# Num Trotter steps\n",
        "num_steps = 20\n",
        "theta_rx = np.pi / 6\n",
        "\n",
        "# Average single-site magnetization\n",
        "observable = (\n",
        "    SparsePauliOp(\n",
        "        [\n",
        "            \"I\" * iq + \"Z\" + \"I\" * (num_qubits - iq - 1)\n",
        "            for iq in range(num_qubits)\n",
        "        ]\n",
        "    )\n",
        "    / num_qubits\n",
        ")\n",
        "\n",
        "# Create the Trotter circuit\n",
        "num_qubits = 10\n",
        "num_steps = 20\n",
        "theta_rx = np.pi / 6\n",
        "circuit = QuantumCircuit(num_qubits)\n",
        "edges = CouplingMap.from_line(num_qubits, bidirectional=False).get_edges()\n",
        "for _ in range(num_steps):\n",
        "    circuit.rx(theta_rx, [i for i in range(num_qubits)])\n",
        "    for edge in edges:\n",
        "        circuit.sdg(edge)\n",
        "        circuit.ry(np.pi / 2, edge[1])\n",
        "        circuit.cx(edge[0], edge[1])\n",
        "        circuit.ry(-np.pi / 2, edge[1])\n",
        "circuit.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c05fa0f8-605e-4172-8880-0de89360f27d",
      "metadata": {},
      "source": [
        "<span id=\"simulate-the-time-evolution-of-the-system-with-pauli-propagation\" />\n",
        "\n",
        "## Simuler l'évolution temporelle du système à l'aide de la propagation de Pauli\n",
        "\n",
        "Une fois que nous disposons de notre circuit ( $U$ ) et de notre observable ( $O$ ), nous pouvons facilement simuler le système en quelques étapes :\n",
        "\n",
        "* Décomposez l' $U$ en ses parties « Clifford » ( $C$ ) et « non-Clifford » ( $P$ ) de telle sorte que $U=PC$ en utilisant `evolve_through_cliffords`\n",
        "* Appliquer la fonction « $O$ » à « $P$ », ce qui donne un nouvel opérateur, « $O^\\prime$ », en utilisant `pauli_prop.propagate_through_circuit`\n",
        "* Faites évoluer l' $O^\\prime$ e sur la partie Clifford du circuit à l'aide du support d'évolution Clifford intégré à Qiskit\n",
        "* On peut approximer la valeur attendue par $\\langle0|O^\\prime|0\\rangle \\approx \\langle0|U^\\dagger OU|0\\rangle$ en additionnant les coefficients de $O^\\prime$ associés aux termes de Pauli entièrement diagonaux (termes de Pauli contenant soit `I` soit `Z` sur tous les qubits). N'oubliez pas qu'il s'agit d'une approximation, car nous avons tronqué des termes de l' $O^\\prime$ e lors de sa propagation à travers la partie non-Clifford du circuit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "c8a27469-ab72-4d50-9544-d446af847da5",
      "metadata": {},
      "outputs": [],
      "source": [
        "import time\n",
        "\n",
        "from pauli_prop import evolve_through_cliffords, propagate_through_circuit\n",
        "\n",
        "cliff, non_cliff = evolve_through_cliffords(circuit)\n",
        "\n",
        "max_terms_list = [10**i for i in range(8)]\n",
        "approx_evs = []\n",
        "durations = []\n",
        "for max_terms in max_terms_list:\n",
        "    st = time.perf_counter()\n",
        "    evolved_obs = propagate_through_circuit(\n",
        "        observable, non_cliff, max_terms=max_terms, atol=1e-12, frame=\"h\"\n",
        "    )[0]\n",
        "    evolved_obs.paulis = evolved_obs.paulis.evolve(cliff, frame=\"h\")\n",
        "    durations.append(time.perf_counter() - st)\n",
        "    approx_evs.append(\n",
        "        float(evolved_obs.coeffs[~evolved_obs.paulis.x.any(axis=1)].sum())\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7fb3e72f-20fb-4fd0-a301-2fcc6c0ddad5",
      "metadata": {},
      "source": [
        "À mesure que nous effectuons des calculs de plus grande envergure, les approximations de la valeur attendue gagnent en précision. Dans cet exemple, nous saturons l'espace de Pauli complet aux alentours de $4^{10}\\approx10^6$, ce qui se traduit par un aplatissement de la courbe entre les deux derniers points.\n",
        "\n",
        "Bien que le graphique ci-dessous montre une convergence monotone, les simulations de propagation de Pauli ne convergent généralement pas de manière monotone. Il n'est pas rare d'observer un tracé « irrégulier » sur ce type de graphiques.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "f12410aa-ef3b-4ee6-ab35-f7e9001a92b8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "Text(0.5, 1.0, 'Simulating 20-step 1D Ising Model')"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/pauli-prop/guides/quickstart/extracted-outputs/f12410aa-ef3b-4ee6-ab35-f7e9001a92b8-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "from qiskit_aer import AerSimulator\n",
        "\n",
        "sim_circ = circuit.copy()\n",
        "sim_circ.save_statevector()\n",
        "backend = AerSimulator(method=\"statevector\")\n",
        "psi = backend.run(sim_circ).result().data()[\"statevector\"]\n",
        "exact_ev = psi.expectation_value(observable)\n",
        "\n",
        "ax1 = plt.gca()\n",
        "ax1.plot(max_terms_list, approx_evs, marker=\"o\", label=\"Approximate\")\n",
        "ax1.axhline(exact_ev, linestyle=\"--\", color=\"green\", label=\"Exact\")\n",
        "ax1.set_xscale(\"log\")\n",
        "ax1.set_xlabel(\"# terms kept\")\n",
        "ax1.set_ylabel(r\"$\\frac{1}{N} \\sum_{i=1}^{N} \\langle z_i \\rangle$\")\n",
        "\n",
        "ax2 = ax1.twinx()\n",
        "ax2.plot(\n",
        "    max_terms_list, durations, marker=\".\", label=\"Runtime\", color=\"orange\"\n",
        ")\n",
        "ax2.set_ylabel(\"Runtime (s)\", color=\"orange\")\n",
        "ax2.set_yscale(\"log\")\n",
        "\n",
        "handles1, labels1 = ax1.get_legend_handles_labels()\n",
        "handles2, labels2 = ax2.get_legend_handles_labels()\n",
        "ax1.legend(handles1 + handles2, labels1 + labels2, loc=\"lower right\")\n",
        "\n",
        "plt.title(f\"Simulating {num_steps}-step 1D Ising Model\")"
      ]
    },
    {
      "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
}