{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "44ef87b3",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Simulation de l'hamiltonien d'Ising avec circuits dynamiques\"\n",
        "description: \"Tutoriel illustrant les circuits dynamiques à l'échelle industrielle à l'aide d'une simulation du modèle d'Ising hexagonal avec kick\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore hcords ycords xcords fontsize ncol Krsulich Lishman */}\n",
        "\n",
        "<span id=\"simulation-of-kicked-ising-hamiltonian-with-dynamic-circuits\" />\n",
        "\n",
        "# Simulation de l'hamiltonien d'Ising avec circuits dynamiques\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2ae52bd4",
      "metadata": {},
      "source": [
        "*Estimation d'utilisation : 7.5 minutes sur un processeur Heron r3. (REMARQUE : Il s'agit uniquement d'une estimation. Votre durée d'exécution peut varier.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c76f2627",
      "metadata": {},
      "source": [
        "Les circuits dynamiques sont des circuits à action directe classique. En d'autres termes, il s'agit de mesures effectuées à mi-parcours, suivies d'opérations logiques classiques qui déterminent les opérations quantiques en fonction du résultat classique. Dans ce tutoriel, nous simulons le modèle d'Ising kické sur un réseau hexagonal de spins et utilisons des circuits dynamiques pour réaliser des interactions au-delà de la connectivité physique du matériel.\n",
        "\n",
        "Le modèle d'Ising a fait l'objet de nombreuses études dans différents domaines de la physique. Il modélise les spins qui subissent des interactions d'Ising entre les sites du réseau, ainsi que les impulsions provenant du champ magnétique local sur chaque site. L'évolution temporelle trottisée des spins considérés dans ce tutoriel, tirée de [\\[1\\]](#references), est donnée par l'unité suivante :\n",
        "\n",
        "$$\n",
        "U(\\theta)=\\left(\\prod_{\\langle j, k\\rangle} \\exp \\left(i \\frac{\\pi}{8} Z_j Z_k\\right)\\right)\\left(\\prod_j \\exp \\left(-i \\frac{\\theta}{2} X_j\\right)\\right)\n",
        "$$\n",
        "\n",
        "Pour étudier la dynamique des spins, nous étudions la magnétisation moyenne des spins à chaque site en fonction des étapes de Trotter. Nous construisons donc l'observable suivant :\n",
        "\n",
        "$$\n",
        "\\langle O\\rangle =  \\frac{1}{N} \\sum_i \\langle Z_i \\rangle\n",
        "$$\n",
        "\n",
        "Pour réaliser l'interaction ZZ entre les sites du réseau, nous présentons une solution utilisant la fonctionnalité de circuit dynamique, qui permet d'obtenir une profondeur de deux qubits nettement plus courte par rapport à la méthode de routage standard avec des portes SWAP. D'autre part, les opérations classiques de feedforward dans les circuits dynamiques ont généralement des temps d'exécution plus longs que les portes quantiques; les circuits dynamiques présentent donc des limites et des compromis. Nous présentons également une méthode permettant d'ajouter une séquence de découplage dynamique sur les qubits inactifs pendant l'opération classique de feedforward en utilisant la durée [d'étirement](/docs/guides/stretch).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a6c0af3b",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Exigences\n",
        "\n",
        "Avant de commencer ce tutoriel, assurez-vous que les éléments suivants sont installés :\n",
        "\n",
        "* Qiskit SDK v2.0 ou ultérieurement avec prise en charge de [la visualisation](/docs/api/qiskit/visualization)\n",
        "* Qiskit Runtime v0.37 ou ultérieurement avec prise en charge de la visualisation (`pip install 'qiskit-ibm-runtime[visualization]'`)\n",
        "* Bibliothèque graphique Rustworkx (`pip install rustworkx`)\n",
        "* Qiskit Aer (`pip install qiskit-aer`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "03860584",
      "metadata": {},
      "source": [
        "<span id=\"set-up\" />\n",
        "\n",
        "## Configurer\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "88a21408",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "from typing import List\n",
        "import rustworkx as rx\n",
        "import matplotlib.pyplot as plt\n",
        "from rustworkx.visualization import mpl_draw\n",
        "from qiskit.circuit import (\n",
        "    Parameter,\n",
        "    QuantumCircuit,\n",
        "    QuantumRegister,\n",
        "    ClassicalRegister,\n",
        ")\n",
        "from qiskit.transpiler import CouplingMap\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.circuit.classical import expr\n",
        "from qiskit.transpiler.preset_passmanagers import (\n",
        "    generate_preset_pass_manager,\n",
        ")\n",
        "from qiskit.transpiler import PassManager\n",
        "from qiskit.circuit.library import RZGate, XGate\n",
        "from qiskit.transpiler.passes import (\n",
        "    ALAPScheduleAnalysis,\n",
        "    PadDynamicalDecoupling,\n",
        ")\n",
        "\n",
        "from qiskit.transpiler.basepasses import TransformationPass\n",
        "from qiskit.circuit.measure import Measure\n",
        "from qiskit.transpiler.passes.utils.remove_final_measurements import (\n",
        "    calc_final_ops,\n",
        ")\n",
        "from qiskit.circuit import Instruction\n",
        "\n",
        "from qiskit.visualization import plot_circuit_layout\n",
        "from qiskit.circuit.tools import pi_check\n",
        "\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_aer.primitives import SamplerV2 as Aer_Sampler\n",
        "\n",
        "from qiskit_ibm_runtime import (\n",
        "    QiskitRuntimeService,\n",
        "    Batch,\n",
        "    SamplerV2 as Sampler,\n",
        ")\n",
        "from qiskit.providers.exceptions import QiskitBackendNotFoundError\n",
        "from qiskit_ibm_runtime.visualization import (\n",
        "    draw_circuit_schedule_timing,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "df65631b",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-circuit\" />\n",
        "\n",
        "## Étape 1 : Mapper les entrées classiques à un circuit quantique\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "188f83ae",
      "metadata": {},
      "source": [
        "Nous commençons par définir le réseau à simuler. Nous avons choisi de travailler avec le réseau en nid d'abeille (également appelé hexagonal), qui est un graphe plan avec des nœuds de degré 3. Ici, nous spécifions la taille du réseau, les paramètres de circuit pertinents qui nous intéressent dans la dynamique trotterisée. Nous simulons l'évolution temporelle selon le modèle de Trotter sous le modèle d'Ising avec trois valeurs d' $\\theta$ s différentes du champ magnétique local.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "e8bc54ef",
      "metadata": {},
      "outputs": [],
      "source": [
        "hex_rows = 3  # specify lattice size\n",
        "hex_cols = 5\n",
        "depths = range(9)  # specify Trotter steps\n",
        "zz_angle = np.pi / 8  # parameter for ZZ interaction\n",
        "max_angle = np.pi / 2  # max theta angle\n",
        "points = 3  # number of theta parameters\n",
        "\n",
        "θ = Parameter(\"θ\")\n",
        "params = np.linspace(0, max_angle, points)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "0b12f364",
      "metadata": {},
      "outputs": [],
      "source": [
        "def make_hex_lattice(hex_rows=1, hex_cols=1):\n",
        "    \"\"\"Define hexagon lattice.\"\"\"\n",
        "    hex_cmap = CouplingMap.from_hexagonal_lattice(\n",
        "        hex_rows, hex_cols, bidirectional=False\n",
        "    )\n",
        "    data = list(hex_cmap.physical_qubits)\n",
        "    graph = hex_cmap.graph.to_undirected(multigraph=False)\n",
        "    edge_colors = rx.graph_misra_gries_edge_color(graph)\n",
        "    layer_edges = {color: [] for color in edge_colors.values()}\n",
        "    for edge_index, color in edge_colors.items():\n",
        "        layer_edges[color].append(graph.edge_list()[edge_index])\n",
        "    return data, layer_edges, hex_cmap, graph"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b2286ebb",
      "metadata": {},
      "source": [
        "Commençons par un petit exemple de test :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "c011bc1a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/c011bc1a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "hex_rows_test = 1\n",
        "hex_cols_test = 2\n",
        "\n",
        "data_test, layer_edges_test, hex_cmap_test, graph_test = make_hex_lattice(\n",
        "    hex_rows=hex_rows_test, hex_cols=hex_cols_test\n",
        ")\n",
        "\n",
        "# display a small example for illustration\n",
        "node_colors_test = [\"lightblue\"] * len(graph_test.node_indices())\n",
        "pos = rx.graph_spring_layout(\n",
        "    graph_test,\n",
        "    k=5 / np.sqrt(len(graph_test.nodes())),\n",
        "    repulsive_exponent=1,\n",
        "    num_iter=150,\n",
        ")\n",
        "mpl_draw(graph_test, node_color=node_colors_test, pos=pos)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8e5f862a",
      "metadata": {},
      "source": [
        "Nous utiliserons ce petit exemple à des fins d'illustration et de simulation. Ci-dessous, nous construisons également un exemple à grande échelle afin de montrer que le flux de travail peut être étendu à des tailles importantes.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "ba481bd4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "num_qubits = 46\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/ba481bd4-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "data, layer_edges, hex_cmap, graph = make_hex_lattice(\n",
        "    hex_rows=hex_rows, hex_cols=hex_cols\n",
        ")\n",
        "num_qubits = len(data)\n",
        "print(f\"num_qubits = {num_qubits}\")\n",
        "\n",
        "# display the honeycomb lattice to simulate\n",
        "node_colors = [\"lightblue\"] * len(graph.node_indices())\n",
        "pos = rx.graph_spring_layout(\n",
        "    graph,\n",
        "    k=5 / np.sqrt(num_qubits),\n",
        "    repulsive_exponent=1,\n",
        "    num_iter=150,\n",
        ")\n",
        "mpl_draw(graph, node_color=node_colors, pos=pos)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6eb03e83",
      "metadata": {},
      "source": [
        "<span id=\"build-unitary-circuits\" />\n",
        "\n",
        "### Construire des circuits unitaires\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f4b421fa",
      "metadata": {},
      "source": [
        "Une fois la taille du problème et les paramètres spécifiés, nous sommes désormais prêts à construire le circuit paramétré qui simule l'évolution temporelle de l' $U(\\theta)$, selon la méthode de Trotter, avec différentes étapes de Trotter, spécifiées par `depth` l'argument. Le circuit que nous construisons comporte des couches alternées de portes `Rx` ( $\\theta$ ) et de `Rzz` portes. Les `Rzz` portes réalisent les interactions ZZ entre les spins couplés, qui seront placés entre chaque site du réseau spécifié par `layer_edges` l'argument.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "9e2dc428",
      "metadata": {},
      "outputs": [],
      "source": [
        "def gen_hex_unitary(\n",
        "    num_qubits=6,\n",
        "    zz_angle=np.pi / 8,\n",
        "    layer_edges=[\n",
        "        [(0, 1), (2, 3), (4, 5)],\n",
        "        [(1, 2), (3, 4), (5, 0)],\n",
        "    ],\n",
        "    θ=Parameter(\"θ\"),\n",
        "    depth=1,\n",
        "    measure=False,\n",
        "    final_rot=True,\n",
        "):\n",
        "    \"\"\"Build unitary circuit.\"\"\"\n",
        "    circuit = QuantumCircuit(num_qubits)\n",
        "    # Build trotter layers\n",
        "    for _ in range(depth):\n",
        "        for i in range(num_qubits):\n",
        "            circuit.rx(θ, i)\n",
        "        circuit.barrier()\n",
        "        for coloring in layer_edges.keys():\n",
        "            for e in layer_edges[coloring]:\n",
        "                circuit.rzz(zz_angle, e[0], e[1])\n",
        "        circuit.barrier()\n",
        "    # Optional final rotation, set True to be consistent with Ref. [1]\n",
        "    if final_rot:\n",
        "        for i in range(num_qubits):\n",
        "            circuit.rx(θ, i)\n",
        "    if measure:\n",
        "        circuit.measure_all()\n",
        "\n",
        "    return circuit"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "24235b4a",
      "metadata": {},
      "source": [
        "Visualisez le petit circuit de test :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "268e6999",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/268e6999-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "circ_unitary_test = gen_hex_unitary(\n",
        "    num_qubits=len(data_test),\n",
        "    layer_edges=layer_edges_test,\n",
        "    θ=Parameter(\"θ\"),\n",
        "    depth=1,\n",
        "    measure=True,\n",
        ")\n",
        "circ_unitary_test.draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0a8abb0d",
      "metadata": {},
      "source": [
        "De même, construisez les circuits unitaires du grand exemple à différentes étapes de Trotter et l'observable pour estimer la valeur attendue.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6c9e388a",
      "metadata": {},
      "outputs": [],
      "source": [
        "circuits_unitary = []\n",
        "for depth in depths:\n",
        "    circ = gen_hex_unitary(\n",
        "        num_qubits=num_qubits,\n",
        "        layer_edges=layer_edges,\n",
        "        θ=Parameter(\"θ\"),\n",
        "        depth=depth,\n",
        "        measure=True,\n",
        "    )\n",
        "    circuits_unitary.append(circ)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "695e2bad",
      "metadata": {},
      "outputs": [],
      "source": [
        "observables_unitary = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [i], 1 / num_qubits) for i in range(num_qubits)],\n",
        "    num_qubits=num_qubits,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "84d2cd91",
      "metadata": {},
      "source": [
        "<span id=\"build-dynamic-circuit-implementation\" />\n",
        "\n",
        "### Construire une implémentation de circuit dynamique\n",
        "\n",
        "Cette section présente la mise en œuvre du circuit dynamique principal permettant de simuler la même évolution temporelle trotterisée. Notez que le réseau en nid d'abeille que nous voulons simuler ne correspond pas au réseau lourd des qubits matériels. Une manière simple de mapper le circuit sur le matériel consiste à introduire une série d'opérations SWAP afin de rapprocher les qubits en interaction les uns des autres, afin de réaliser l'interaction ZZ. Nous mettons ici en avant une approche alternative utilisant des circuits dynamiques comme solution, qui montre que nous pouvons utiliser la combinaison du calcul quantique et du calcul classique en temps réel dans un circuit dans Qiskit pour réaliser des interactions au-delà du voisinage immédiat.\n",
        "\n",
        "Dans la mise en œuvre du circuit dynamique, l'interaction ZZ est efficacement mise en œuvre à l'aide de qubits auxiliaires, de mesures à mi-circuit et d'une prédiction. Pour comprendre cela, notez que les rotations ZZ appliquent un facteur de phase $e^{i\\theta}$ à l'état en fonction de sa parité. Pour deux qubits, les états de base computationnelle sont $|00\\rangle$, $|01\\rangle$, $|10\\rangle$ et $|11\\rangle$. La porte de rotation ZZ applique un facteur de phase aux états $|01\\rangle$ et $|10\\rangle$ dont la parité (le nombre de uns dans l'état) est impaire et laisse les états de parité paire inchangés. Ce qui suit décrit comment nous pouvons mettre en œuvre efficacement des interactions ZZ sur deux qubits à l'aide de circuits dynamiques.\n",
        "\n",
        "1. Calculer la parité dans un qubit auxiliaire : au lieu d'appliquer directement ZZ à deux qubits, nous introduisons un troisième qubit, le qubit auxiliaire, pour stocker les informations de parité des deux qubits de données. Nous entrelacons l'ancilla avec chaque qubit de données à l'aide de portes CX allant du qubit de données au qubit ancilla.\n",
        "\n",
        "2. Appliquez une rotation Z à un seul qubit à la qubit auxiliaire : en effet, la qubit auxiliaire contient les informations de parité des deux qubits de données, ce qui permet de mettre en œuvre efficacement la rotation ZZ sur les qubits de données.\n",
        "\n",
        "3. Mesurez le qubit auxiliaire dans la base X : c'est l'étape clé qui fait s'effondrer l'état du qubit auxiliaire, et le résultat de la mesure nous indique ce qui s'est passé :\n",
        "\n",
        "   * Mesure 0 : lorsqu'un résultat 0 est observé, cela signifie que nous avons correctement appliqué une rotation d' $ZZ(\\theta)$ s à nos qubits de données.\n",
        "\n",
        "   * Mesure 1 : lorsqu'un résultat 1 est observé, nous avons appliqué à la place l' $ZZ(\\theta + \\pi)$.\n",
        "\n",
        "4. Appliquer une porte de correction lors de la mesure 1 : si nous avons mesuré 1, nous appliquons des portes Z aux qubits de données pour « corriger » la phase d' $\\pi$ e supplémentaire.\n",
        "\n",
        "Le circuit obtenu est le suivant :\n",
        "\n",
        "![mise en œuvre dynamique](https://quantum.cloud.ibm.com/docs/images/tutorials/dc-hex-ising/circuit-1.avif)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9872fed2",
      "metadata": {},
      "source": [
        "Lorsque nous adoptons cette approche pour simuler un réseau en nid d'abeille, le circuit résultant s'intègre parfaitement dans le matériel avec un réseau hexagonal dense : tous les qubits de données résident sur les sites d' degree-3 s du réseau, qui forme un réseau hexagonal. Chaque paire de qubits de données partage un qubit auxiliaire résidant sur un site d' degree-2. Ci-dessous, nous construisons le réseau de qubits pour la mise en œuvre du circuit dynamique, en introduisant des qubits auxiliaires (représentés par les cercles violets plus foncés).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "c0e7afd2",
      "metadata": {},
      "outputs": [],
      "source": [
        "def make_lattice(hex_rows=1, hex_cols=1):\n",
        "    \"\"\"Define heavy-hex lattice and corresponding lists of data and ancilla nodes.\"\"\"\n",
        "    hex_cmap = CouplingMap.from_hexagonal_lattice(\n",
        "        hex_rows, hex_cols, bidirectional=False\n",
        "    )\n",
        "    data = list(hex_cmap.physical_qubits)\n",
        "\n",
        "    heavyhex_cmap = CouplingMap()\n",
        "    for d in data:\n",
        "        heavyhex_cmap.add_physical_qubit(d)\n",
        "\n",
        "    # make coupling map\n",
        "    a = len(data)\n",
        "    for edge in hex_cmap.get_edges():\n",
        "        heavyhex_cmap.add_physical_qubit(a)\n",
        "        heavyhex_cmap.add_edge(edge[0], a)\n",
        "        heavyhex_cmap.add_edge(edge[1], a)\n",
        "        a += 1\n",
        "    ancilla = list(range(len(data), a))\n",
        "    qubits = data + ancilla\n",
        "\n",
        "    # color edges\n",
        "    graph = heavyhex_cmap.graph.to_undirected(multigraph=False)\n",
        "    edge_colors = rx.graph_misra_gries_edge_color(graph)\n",
        "    layer_edges = {color: [] for color in edge_colors.values()}\n",
        "    for edge_index, color in edge_colors.items():\n",
        "        layer_edges[color].append(graph.edge_list()[edge_index])\n",
        "\n",
        "    # construct observable\n",
        "    obs_hex = SparsePauliOp.from_sparse_list(\n",
        "        [(\"Z\", [i], 1 / len(data)) for i in data],\n",
        "        num_qubits=len(qubits),\n",
        "    )\n",
        "\n",
        "    return (data, qubits, ancilla, layer_edges, heavyhex_cmap, graph, obs_hex)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5c39eeab",
      "metadata": {},
      "source": [
        "Visualisez le réseau hexagonal dense pour les qubits de données et les qubits auxiliaires à petite échelle :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "2d7224ef",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "number of data qubits = 46\n",
            "number of ancilla qubits = 60\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/2d7224ef-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "(data, qubits, ancilla, layer_edges, heavyhex_cmap, graph, obs_hex) = (\n",
        "    make_lattice(hex_rows=hex_rows, hex_cols=hex_cols)\n",
        ")\n",
        "\n",
        "print(f\"number of data qubits = {len(data)}\")\n",
        "print(f\"number of ancilla qubits = {len(ancilla)}\")\n",
        "\n",
        "node_colors = []\n",
        "for node in graph.node_indices():\n",
        "    if node in ancilla:\n",
        "        node_colors.append(\"purple\")\n",
        "    else:\n",
        "        node_colors.append(\"lightblue\")\n",
        "\n",
        "pos = rx.graph_spring_layout(\n",
        "    graph,\n",
        "    k=1 / np.sqrt(len(qubits)),\n",
        "    repulsive_exponent=2,\n",
        "    num_iter=200,\n",
        ")\n",
        "\n",
        "# Visualize the graph, blue circles are data qubits and purple circles are ancillas\n",
        "mpl_draw(graph, node_color=node_colors, pos=pos)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bf9177d2",
      "metadata": {},
      "source": [
        "Ci-dessous, nous construisons le circuit dynamique pour l'évolution temporelle trotterisée. Les `RZZ` portes sont remplacées par la mise en œuvre du circuit dynamique à l'aide des étapes décrites ci-dessus.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "4c98664f",
      "metadata": {},
      "outputs": [],
      "source": [
        "def gen_hex_dynamic(\n",
        "    depth=1,\n",
        "    zz_angle=np.pi / 8,\n",
        "    θ=Parameter(\"θ\"),\n",
        "    hex_rows=1,\n",
        "    hex_cols=1,\n",
        "    measure=False,\n",
        "    add_dd=True,\n",
        "):\n",
        "    \"\"\"Build dynamic circuits.\"\"\"\n",
        "    (data, qubits, ancilla, layer_edges, heavyhex_cmap, graph, obs_hex) = (\n",
        "        make_lattice(hex_rows=hex_rows, hex_cols=hex_cols)\n",
        "    )\n",
        "    # Initialize circuit\n",
        "    qr = QuantumRegister(len(qubits), \"qr\")\n",
        "    cr = ClassicalRegister(len(ancilla), \"cr\")\n",
        "    circuit = QuantumCircuit(qr, cr)\n",
        "\n",
        "    for k in range(depth):\n",
        "        # Single-qubit Rx layer\n",
        "        for d in data:\n",
        "            circuit.rx(θ, d)\n",
        "        circuit.barrier()\n",
        "\n",
        "        # CX gates from data qubits to ancilla qubits\n",
        "        for same_color_edges in layer_edges.values():\n",
        "            for e in same_color_edges:\n",
        "                circuit.cx(e[0], e[1])\n",
        "        circuit.barrier()\n",
        "\n",
        "        # Apply Rz rotation on ancilla qubits and rotate into X basis\n",
        "        for a in ancilla:\n",
        "            circuit.rz(zz_angle, a)\n",
        "            circuit.h(a)\n",
        "        # Add barrier to align terminal measurement\n",
        "        circuit.barrier()\n",
        "\n",
        "        # Measure ancilla qubits\n",
        "        for i, a in enumerate(ancilla):\n",
        "            circuit.measure(a, i)\n",
        "        d2ros = {}\n",
        "        a2ro = {}\n",
        "        # Retrieve ancilla measurement outcomes\n",
        "        for a in ancilla:\n",
        "            a2ro[a] = cr[ancilla.index(a)]\n",
        "\n",
        "        # For each data qubit, retrieve measurement outcomes of neighboring\n",
        "        # ancilla qubits\n",
        "        for d in data:\n",
        "            ros = [a2ro[a] for a in heavyhex_cmap.neighbors(d)]\n",
        "            d2ros[d] = ros\n",
        "\n",
        "        # Build classical feedforward operations (optionally add DD on idling\n",
        "        # data qubits)\n",
        "        for d in data:\n",
        "            if add_dd:\n",
        "                circuit = add_stretch_dd(circuit, d, f\"data_{d}_depth_{k}\")\n",
        "\n",
        "            # # XOR the neighboring readouts of the data qubit;\n",
        "            # if True, apply Z to it\n",
        "            ros = d2ros[d]\n",
        "            parity = ros[0]\n",
        "            for ro in ros[1:]:\n",
        "                parity = expr.bit_xor(parity, ro)\n",
        "            with circuit.if_test(expr.equal(parity, True)):\n",
        "                circuit.z(d)\n",
        "\n",
        "        # Reset the ancilla if its readout is 1\n",
        "        for a in ancilla:\n",
        "            with circuit.if_test(expr.equal(a2ro[a], True)):\n",
        "                circuit.x(a)\n",
        "        circuit.barrier()\n",
        "\n",
        "    # Final single-qubit Rx layer to match the unitary circuits\n",
        "    for d in data:\n",
        "        circuit.rx(θ, d)\n",
        "\n",
        "    if measure:\n",
        "        circuit.measure_all()\n",
        "    return circuit, obs_hex\n",
        "\n",
        "\n",
        "def add_stretch_dd(qc, q, name):\n",
        "    \"\"\"Add XpXm DD sequence.\"\"\"\n",
        "    s = qc.add_stretch(name)\n",
        "    qc.delay(s, q)\n",
        "    qc.x(q)\n",
        "    qc.delay(s, q)\n",
        "    qc.delay(s, q)\n",
        "    qc.rz(np.pi, q)\n",
        "    qc.x(q)\n",
        "    qc.rz(-np.pi, q)\n",
        "    qc.delay(s, q)\n",
        "    return qc"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c8b3b632",
      "metadata": {},
      "source": [
        "<span id=\"dynamical-decoupling-dd-and-support-for-stretch-duration\" />\n",
        "\n",
        "#### Découplage dynamique (DD) et prise en charge de `stretch` la durée\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1f08bda1",
      "metadata": {},
      "source": [
        "Une mise en garde concernant l'utilisation de la mise en œuvre de circuits dynamiques pour réaliser l'interaction ZZ est que la mesure à mi-circuit et les opérations classiques de feedforward prennent généralement plus de temps à exécuter que les portes quantiques. Afin de supprimer la décohérence des qubits pendant le temps d'inactivité nécessaire à la réalisation des opérations classiques, nous avons ajouté une séquence [de découplage dynamique](/docs/guides/error-mitigation-and-suppression-techniques#dynamical-decoupling) (DD) après l'opération de mesure sur les qubits ancilla, et avant l'opération Z conditionnelle sur le qubit de données, avant `if_test` l'instruction.\n",
        "\n",
        "La séquence DD est générée par la fonction `add_stretch_dd()`, qui utilise les [durées `stretch`](/docs/guides/stretch) pour déterminer les intervalles de temps entre les impulsions DD. Une durée `stretch` permet de définir une durée flexible pour l'opération `delay` , de sorte que la durée du délai puisse s'allonger jusqu'à occuper tout le temps d'inactivité du qubit. Les variables de durée spécifiées par `stretch` sont converties, lors de la compilation, en durées souhaitées qui satisfont à une certaine contrainte. Cela s'avère très utile lorsque la synchronisation des séquences DD est essentielle pour obtenir de bonnes performances en matière de suppression des erreurs. Pour plus d'informations sur ce type `stretch` , consultez la documentation de [OpenQASM](https://openqasm.com/language/delays.html#duration-and-stretch-types). À l'heure actuelle, la prise en charge de ce type `stretch` est encore au stade expérimental. Pour plus de détails sur ses contraintes d'utilisation, veuillez vous reporter à [la section « Limitations »](/docs/guides/stretch#qiskit-runtime-limitations) de la documentation `stretch` .\n",
        "\n",
        "À l'aide des fonctions définies ci-dessus, nous construisons les circuits d'évolution temporelle trotterisés, avec et sans DD, ainsi que les observables correspondants.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "997419c8",
      "metadata": {},
      "source": [
        "Nous commençons par visualiser le circuit dynamique d'un petit exemple :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "b6e2e76c",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/b6e2e76c-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "hex_rows_test = 1\n",
        "hex_cols_test = 1\n",
        "\n",
        "(\n",
        "    data_test,\n",
        "    qubits_test,\n",
        "    ancilla_test,\n",
        "    layer_edges_test,\n",
        "    heavyhex_cmap_test,\n",
        "    graph_test,\n",
        "    obs_hex_test,\n",
        ") = make_lattice(hex_rows=hex_rows_test, hex_cols=hex_cols_test)\n",
        "\n",
        "node_colors = []\n",
        "for node in graph_test.node_indices():\n",
        "    if node in ancilla_test:\n",
        "        node_colors.append(\"purple\")\n",
        "    else:\n",
        "        node_colors.append(\"lightblue\")\n",
        "pos = rx.graph_spring_layout(\n",
        "    graph_test,\n",
        "    k=5 / np.sqrt(len(qubits_test)),\n",
        "    repulsive_exponent=2,\n",
        "    num_iter=150,\n",
        ")\n",
        "\n",
        "# display a small example for illustration\n",
        "node_colors_test = [\"lightblue\"] * len(graph_test.node_indices())\n",
        "mpl_draw(graph_test, node_color=node_colors, pos=pos)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "735e590a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/735e590a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 14,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "circuit_dynamic_test, obs_dynamic_test = gen_hex_dynamic(\n",
        "    depth=1,\n",
        "    θ=Parameter(\"θ\"),\n",
        "    hex_rows=hex_rows_test,\n",
        "    hex_cols=hex_cols_test,\n",
        "    measure=False,\n",
        "    add_dd=False,\n",
        ")\n",
        "circuit_dynamic_test.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "5de9381a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/5de9381a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "circuit_dynamic_dd_test, _ = gen_hex_dynamic(\n",
        "    depth=1,\n",
        "    θ=Parameter(\"θ\"),\n",
        "    hex_rows=hex_rows_test,\n",
        "    hex_cols=hex_cols_test,\n",
        "    measure=False,\n",
        "    add_dd=True,\n",
        ")\n",
        "circuit_dynamic_dd_test.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "956dd43e",
      "metadata": {},
      "source": [
        "De même, construisez les circuits dynamiques pour l'exemple de grande taille :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "bd7b2be0",
      "metadata": {},
      "outputs": [],
      "source": [
        "circuits_dynamic = []\n",
        "circuits_dynamic_dd = []\n",
        "observables_dynamic = []\n",
        "for depth in depths:\n",
        "    circuit, obs = gen_hex_dynamic(\n",
        "        depth=depth,\n",
        "        θ=Parameter(\"θ\"),\n",
        "        hex_rows=hex_rows,\n",
        "        hex_cols=hex_cols,\n",
        "        measure=True,\n",
        "        add_dd=False,\n",
        "    )\n",
        "    circuits_dynamic.append(circuit)\n",
        "\n",
        "    circuit_dd, _ = gen_hex_dynamic(\n",
        "        depth=depth,\n",
        "        θ=Parameter(\"θ\"),\n",
        "        hex_rows=hex_rows,\n",
        "        hex_cols=hex_cols,\n",
        "        measure=True,\n",
        "        add_dd=True,\n",
        "    )\n",
        "    circuits_dynamic_dd.append(circuit_dd)\n",
        "    observables_dynamic.append(obs)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0f0fdf70",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-hardware-execution\" />\n",
        "\n",
        "## Étape 2 : Optimiser le problème pour l'exécution matérielle\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "86642d2b",
      "metadata": {},
      "source": [
        "Nous sommes maintenant prêts à transposer le circuit vers le matériel. Nous transposerons à la fois l'implémentation standard unitaire et l'implémentation dynamique du circuit vers le matériel.\n",
        "\n",
        "Pour transcompiler vers le matériel, nous instancions d'abord le backend. Si disponible, nous choisirons un backend prenant en charge l'instruction [`MidCircuitMeasure`](/docs/guides/measure-qubits) (`measure_2`).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "ec904b18",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "try:\n",
        "    backend = service.least_busy(\n",
        "        operational=True,\n",
        "        simulator=False,\n",
        "        use_fractional_gates=True,\n",
        "        filters=lambda b: \"measure_2\" in b.supported_instructions,\n",
        "    )\n",
        "except QiskitBackendNotFoundError:\n",
        "    backend = service.least_busy(\n",
        "        operational=True,\n",
        "        simulator=False,\n",
        "        use_fractional_gates=True,\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "610622b4",
      "metadata": {},
      "source": [
        "<span id=\"transpilation-for-dynamic-circuits\" />\n",
        "\n",
        "### Transpilation pour circuits dynamiques\n",
        "\n",
        "Tout d'abord, nous transpilons les circuits dynamiques, avec et sans ajout de la séquence DD. Afin de garantir l'utilisation du même ensemble de qubits physiques dans tous les circuits pour obtenir des résultats plus cohérents, nous transpilons d'abord le circuit une fois, puis utilisons sa disposition pour tous les circuits suivants, spécifiés par [`initial_layout`](/docs/api/qiskit/qiskit.transpiler.TranspileLayout#initial_layout) dans le gestionnaire de passes. Nous construisons ensuite les [blocs unifiés primitifs](/docs/guides/primitive-input-output) (PUB) comme entrée primitive de l'échantillonneur.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "aa653907",
      "metadata": {},
      "outputs": [],
      "source": [
        "pm_temp = generate_preset_pass_manager(\n",
        "    optimization_level=3,\n",
        "    backend=backend,\n",
        ")\n",
        "isa_temp = pm_temp.run(circuits_dynamic[-1])\n",
        "dynamic_layout = isa_temp.layout.initial_index_layout(filter_ancillas=True)\n",
        "\n",
        "pm = generate_preset_pass_manager(\n",
        "    optimization_level=3, backend=backend, initial_layout=dynamic_layout\n",
        ")\n",
        "\n",
        "dynamic_isa_circuits = [pm.run(circ) for circ in circuits_dynamic]\n",
        "dynamic_pubs = [(circ, params) for circ in dynamic_isa_circuits]\n",
        "\n",
        "dynamic_isa_circuits_dd = [pm.run(circ) for circ in circuits_dynamic_dd]\n",
        "dynamic_pubs_dd = [(circ, params) for circ in dynamic_isa_circuits_dd]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6979ad68",
      "metadata": {},
      "source": [
        "Nous pouvons visualiser la disposition des qubits du circuit transpilé ci-dessous. Les cercles noirs représentent les qubits de données et les qubits auxiliaires utilisés dans la mise en œuvre du circuit dynamique.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "65b2df70",
      "metadata": {},
      "outputs": [],
      "source": [
        "def _heron_coords_r2():\n",
        "    cord_map = np.array(\n",
        "        [\n",
        "            [\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                3,\n",
        "                7,\n",
        "                11,\n",
        "                15,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                1,\n",
        "                5,\n",
        "                9,\n",
        "                13,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                3,\n",
        "                7,\n",
        "                11,\n",
        "                15,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                1,\n",
        "                5,\n",
        "                9,\n",
        "                13,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                3,\n",
        "                7,\n",
        "                11,\n",
        "                15,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                1,\n",
        "                5,\n",
        "                9,\n",
        "                13,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                3,\n",
        "                7,\n",
        "                11,\n",
        "                15,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "            ],\n",
        "            -1\n",
        "            * np.array([j for i in range(15) for j in [i] * [16, 4][i % 2]]),\n",
        "        ],\n",
        "        dtype=int,\n",
        "    )\n",
        "\n",
        "    hcords = []\n",
        "    ycords = cord_map[0]\n",
        "    xcords = cord_map[1]\n",
        "    for i in range(156):\n",
        "        hcords.append([xcords[i] + 1, np.abs(ycords[i]) + 1])\n",
        "\n",
        "    return hcords"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "98d402e0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/98d402e0-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 20,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "plot_circuit_layout(\n",
        "    dynamic_isa_circuits_dd[8],\n",
        "    backend,\n",
        "    qubit_coordinates=_heron_coords_r2(),\n",
        "    view=\"virtual\",\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1bff4d50",
      "metadata": {},
      "source": [
        "<Admonition type=\"note\">\n",
        "  Si vous obtenez des erreurs indiquant que `neato` n'est pas trouvé dans `plot_circuit_layout()`, assurez-vous que le `graphviz` paquet est installé et disponible dans votre PATH. Si l'installation s'effectue dans un emplacement autre que celui par défaut (par exemple, en utilisant `homebrew` sur MacOS ), vous devrez peut-être mettre à jour votre variable `PATH` d'environnement. Cela peut être fait dans ce cahier à l'aide de la commande suivante :\n",
        "\n",
        "  ```python\n",
        "  import os\n",
        "  os.environ['PATH'] = f\"path/to/neato{os.pathsep}{os.environ['PATH']}\"\n",
        "  ```\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "82fb6fa8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/82fb6fa8-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 21,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "dynamic_isa_circuits[1].draw(fold=-1, output=\"mpl\", idle_wires=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "99ad295c",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/99ad295c-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 22,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "dynamic_isa_circuits_dd[1].draw(fold=-1, output=\"mpl\", idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "47d43b9e",
      "metadata": {},
      "source": [
        "<span id=\"transpile-using-midcircuitmeasure\" />\n",
        "\n",
        "#### Transpiler à l'aide de `MidCircuitMeasure`\n",
        "\n",
        "`MidCircuitMeasure` vient compléter les opérations de mesure disponibles; il est spécialement calibré pour effectuer [des mesures en cours de circuit](/docs/guides/execute-dynamic-circuits#midcircuit). L'instruction `MidCircuitMeasure` correspond à `measure_2` l'instruction prise en charge par les backends. Notez que cette `measure_2` fonctionnalité n'est pas prise en charge par tous les backends. Vous pouvez utiliser `service.backends(filters=lambda b: \"measure_2\" in b.supported_instructions)` pour trouver les backends qui le prennent en charge. Nous montrons ici comment transcompiler le circuit de manière à ce que les mesures intermédiaires définies dans le circuit soient exécutées à l'aide de `MidCircuitMeasure` l'opération, si le backend la prend en charge.\n",
        "\n",
        "Ci-dessous, nous imprimons la durée de `measure_2` l'instruction et de l'instruction `measure` standard.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "de870864",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Mid-circuit measurement `measure_2` duration: 1.3800000000000003 μs\n",
            "Terminal measurement `measure` duration: 2.1800000000000006 μs\n"
          ]
        }
      ],
      "source": [
        "print(\n",
        "    f'Mid-circuit measurement `measure_2` duration: '\n",
        "    f'{backend.instruction_durations.get('measure_2',0) * backend.dt * 1e9/1e3} μs'\n",
        ")\n",
        "print(\n",
        "    f'Terminal measurement `measure` duration: '\n",
        "    f'{backend.instruction_durations.get('measure',0) * backend.dt *1e9/1e3} μs'\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "a1bdc9e7",
      "metadata": {},
      "outputs": [],
      "source": [
        "\"\"\"Pass that replaces terminal measures in the middle of the circuit with\n",
        "MidCircuitMeasure instructions.\"\"\"\n",
        "\n",
        "\n",
        "class ConvertToMidCircuitMeasure(TransformationPass):\n",
        "    \"\"\"This pass replaces terminal measures in the middle of the circuit with\n",
        "    MidCircuitMeasure instructions.\n",
        "    \"\"\"\n",
        "\n",
        "    def __init__(self, target):\n",
        "        super().__init__()\n",
        "        self.target = target\n",
        "\n",
        "    def run(self, dag):\n",
        "        \"\"\"Run the pass on a dag.\"\"\"\n",
        "        mid_circ_measure = None\n",
        "        for inst in self.target.instructions:\n",
        "            if isinstance(inst[0], Instruction) and inst[0].name.startswith(\n",
        "                \"measure_\"\n",
        "            ):\n",
        "                mid_circ_measure = inst[0]\n",
        "                break\n",
        "        if not mid_circ_measure:\n",
        "            return dag\n",
        "\n",
        "        final_measure_nodes = calc_final_ops(dag, {\"measure\"})\n",
        "        for node in dag.op_nodes(Measure):\n",
        "            if node not in final_measure_nodes:\n",
        "                dag.substitute_node(node, mid_circ_measure, inplace=True)\n",
        "\n",
        "        return dag\n",
        "\n",
        "\n",
        "pm = PassManager(ConvertToMidCircuitMeasure(backend.target))\n",
        "\n",
        "dynamic_isa_circuits_meas2 = [pm.run(circ) for circ in dynamic_isa_circuits]\n",
        "dynamic_pubs_meas2 = [(circ, params) for circ in dynamic_isa_circuits_meas2]\n",
        "\n",
        "dynamic_isa_circuits_dd_meas2 = [\n",
        "    pm.run(circ) for circ in dynamic_isa_circuits_dd\n",
        "]\n",
        "dynamic_pubs_dd_meas2 = [\n",
        "    (circ, params) for circ in dynamic_isa_circuits_dd_meas2\n",
        "]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a1e982ee",
      "metadata": {},
      "source": [
        "<span id=\"transpilation-for-unitary-circuits\" />\n",
        "\n",
        "### Transpilation pour circuits unitaires\n",
        "\n",
        "Afin d'établir une comparaison équitable entre les circuits dynamiques et leur équivalent unitaire, nous utilisons le même ensemble de qubits physiques que celui utilisé dans les circuits dynamiques pour les qubits de données comme disposition pour la transposition des circuits unitaires.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "87962c09",
      "metadata": {},
      "outputs": [],
      "source": [
        "init_layout = [\n",
        "    dynamic_layout[ind] for ind in range(circuits_unitary[0].num_qubits)\n",
        "]\n",
        "\n",
        "\n",
        "pm = generate_preset_pass_manager(\n",
        "    target=backend.target,\n",
        "    initial_layout=init_layout,\n",
        "    optimization_level=3,\n",
        ")\n",
        "\n",
        "\n",
        "def transpile_minimize(circ: QuantumCircuit, pm: PassManager, iterations=10):\n",
        "    \"\"\"Transpile circuits for specified number of iterations and return the one\n",
        "    with smallest two-qubit gate depth\"\"\"\n",
        "    circs = [pm.run(circ) for i in range(iterations)]\n",
        "    circs_sorted = sorted(\n",
        "        circs,\n",
        "        key=lambda x: x.depth(lambda x: x.operation.num_qubits == 2),\n",
        "    )\n",
        "    return circs_sorted[0]\n",
        "\n",
        "\n",
        "unitary_isa_circuits = []\n",
        "for circ in circuits_unitary:\n",
        "    circ_t = transpile_minimize(circ, pm, iterations=100)\n",
        "    unitary_isa_circuits.append(circ_t)\n",
        "\n",
        "unitary_pubs = [(circ, params) for circ in unitary_isa_circuits]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e7da0161",
      "metadata": {},
      "source": [
        "Nous visualisons la disposition des qubits des circuits unitaires transposés. Les cercles noirs indiquent les qubits physiques utilisés pour transposer les circuits unitaires et leurs indices correspondent aux indices des qubits virtuels. En comparant cela avec la disposition tracée pour les circuits dynamiques, nous pouvons confirmer que les circuits unitaires utilisent le même ensemble de qubits physiques que les qubits de données dans les circuits dynamiques.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "id": "8c3c633f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/8c3c633f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 26,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "plot_circuit_layout(\n",
        "    unitary_isa_circuits[-1],\n",
        "    backend,\n",
        "    qubit_coordinates=_heron_coords_r2(),\n",
        "    view=\"virtual\",\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2fd70904",
      "metadata": {},
      "source": [
        "Nous ajoutons maintenant la séquence DD aux circuits transpilés et construisons les PUB correspondants pour la soumission des tâches.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "383ba663",
      "metadata": {},
      "outputs": [],
      "source": [
        "pm_dd = PassManager(\n",
        "    [\n",
        "        ALAPScheduleAnalysis(target=backend.target),\n",
        "        PadDynamicalDecoupling(\n",
        "            dd_sequence=[\n",
        "                XGate(),\n",
        "                RZGate(np.pi),\n",
        "                XGate(),\n",
        "                RZGate(-np.pi),\n",
        "            ],\n",
        "            spacing=[1 / 4, 1 / 2, 0, 0, 1 / 4],\n",
        "            target=backend.target,\n",
        "        ),\n",
        "    ]\n",
        ")\n",
        "\n",
        "unitary_isa_circuits_dd = pm_dd.run(unitary_isa_circuits)\n",
        "unitary_pubs_dd = [(circ, params) for circ in unitary_isa_circuits_dd]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c4980277",
      "metadata": {},
      "source": [
        "<span id=\"compare-two-qubit-gate-depth-of-unitary-and-dynamic-circuits\" />\n",
        "\n",
        "### Comparer la profondeur de porte à deux qubits des circuits unitaires et dynamiques\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "id": "36f1d72d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x12628b0e0>"
            ]
          },
          "execution_count": 28,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/36f1d72d-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# compare circuit depth of unitary and dynamic circuit implementations\n",
        "unitary_depth = [\n",
        "    unitary_isa_circuits[i].depth(lambda x: x.operation.num_qubits == 2)\n",
        "    for i in range(len(unitary_isa_circuits))\n",
        "]\n",
        "\n",
        "dynamic_depth = [\n",
        "    dynamic_isa_circuits[i].depth(lambda x: x.operation.num_qubits == 2)\n",
        "    for i in range(len(dynamic_isa_circuits))\n",
        "]\n",
        "\n",
        "plt.plot(\n",
        "    list(range(len(unitary_depth))),\n",
        "    unitary_depth,\n",
        "    label=\"unitary circuits\",\n",
        "    color=\"#be95ff\",\n",
        ")\n",
        "plt.plot(\n",
        "    list(range(len(dynamic_depth))),\n",
        "    dynamic_depth,\n",
        "    label=\"dynamic circuits\",\n",
        "    color=\"#ff7eb6\",\n",
        ")\n",
        "plt.xlabel(\"Trotter steps\")\n",
        "plt.ylabel(\"Two-qubit depth\")\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c566243b",
      "metadata": {},
      "source": [
        "Le principal avantage du circuit basé sur la mesure est que, lors de la mise en œuvre de multiples interactions ZZ, les couches CX peuvent être parallélisées et les mesures peuvent être effectuées simultanément. En effet, toutes les interactions ZZ commutent, ce qui permet d'effectuer le calcul avec une profondeur de mesure 1. Après avoir transpilé les circuits, nous observons que l'approche par circuit dynamique produit une profondeur à deux qubits nettement plus courte que l'approche unitaire standard, avec toutefois la réserve que la mesure supplémentaire à mi-circuit et la rétroaction classique prennent elles-mêmes du temps et introduisent leurs propres sources d'erreurs.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "206a7278",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "## Étape 3 : Exécutez à l'aide d' Qiskit primitives\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "53a3e876",
      "metadata": {},
      "source": [
        "<span id=\"local-testing-mode\" />\n",
        "\n",
        "#### Mode de test local\n",
        "\n",
        "Avant de soumettre les tâches au matériel, nous pouvons effectuer une petite simulation test du circuit dynamique à l'aide du [mode de test local](/docs/guides/local-testing-mode).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "cdfd9576",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Simulated average magnetization at trotter step = 1 at three theta values\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "array([ 0.16666667,  0.01529948, -0.14290365])"
            ]
          },
          "execution_count": 29,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "aer_sim = AerSimulator()\n",
        "pm = generate_preset_pass_manager(backend=aer_sim, optimization_level=1)\n",
        "circuit_dynamic_test.measure_all()\n",
        "isa_qc = pm.run(circuit_dynamic_test)\n",
        "with Batch(backend=aer_sim) as batch:\n",
        "    sampler = Sampler(mode=batch)\n",
        "    result = sampler.run([(isa_qc, params)]).result()\n",
        "\n",
        "print(\n",
        "    \"Simulated average magnetization at trotter step = 1 at three theta values\"\n",
        ")\n",
        "result[0].data[\"meas\"].expectation_values(obs_dynamic_test[0])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "59a3a8a0",
      "metadata": {},
      "source": [
        "<span id=\"mps-simulation\" />\n",
        "\n",
        "#### Simulation MPS\n",
        "\n",
        "Pour les circuits de grande taille, nous pouvons utiliser le simulateur `matrix_product_state` (MPS), qui fournit un résultat approximatif de la valeur attendue en fonction de la dimension de liaison choisie. Nous utilisons ensuite les résultats de la simulation MPS comme référence pour comparer les résultats obtenus à partir du matériel.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "6fab4462",
      "metadata": {},
      "outputs": [],
      "source": [
        "# The MPS simulation below took approximately 7 minutes to run on a\n",
        "# laptop with Apple M1 chip\n",
        "\n",
        "mps_backend = AerSimulator(\n",
        "    method=\"matrix_product_state\",\n",
        "    matrix_product_state_truncation_threshold=1e-5,\n",
        "    matrix_product_state_max_bond_dimension=100,\n",
        ")\n",
        "mps_sampler = Aer_Sampler.from_backend(mps_backend)\n",
        "\n",
        "shots = 4096\n",
        "\n",
        "data_sim = []\n",
        "for j in range(points):\n",
        "    circ_list = [\n",
        "        circ.assign_parameters([params[j]]) for circ in circuits_unitary\n",
        "    ]\n",
        "\n",
        "    mps_job = mps_sampler.run(circ_list, shots=shots)\n",
        "    result = mps_job.result()\n",
        "\n",
        "    point_data = [\n",
        "        result[d].data[\"meas\"].expectation_values(observables_unitary)\n",
        "        for d in depths\n",
        "    ]\n",
        "\n",
        "    data_sim.append(point_data)  # data at one theta value\n",
        "\n",
        "data_sim = np.array(data_sim)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ebd28d97",
      "metadata": {},
      "source": [
        "Une fois les circuits et les observables préparés, nous les exécutons désormais sur le matériel à l'aide de la primitive Sampler.\n",
        "\n",
        "Nous soumettons ici trois tâches pour `unitary_pubs`, `dynamic_pubs`, et `dynamic_pubs_dd`. Chacune est une liste de circuits paramétrés correspondant à neuf étapes Trotter différentes avec trois paramètres d' $\\theta$ s différents.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "76b5e07e",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "unitary: d96s4b52su3c739hakrg\n",
            "unitary_dd: d96s4bt2su3c739haksg\n",
            "dynamic: d96s4c0tcv6s73dk55mg\n",
            "dynamic_dd: d96s4ckqp3as739qvid0\n",
            "dynamic_meas2: d96s4csqp3as739qvie0\n",
            "dynamic_dd_meas2: d96s4daf47jc73a5v8s0\n"
          ]
        }
      ],
      "source": [
        "shots = 10000\n",
        "\n",
        "with Batch(backend=backend) as batch:\n",
        "    sampler = Sampler(mode=batch)\n",
        "\n",
        "    sampler.options.experimental = {\n",
        "        \"execution\": {\n",
        "            \"scheduler_timing\": True\n",
        "        },  # set to True to retrieve circuit timing info\n",
        "    }\n",
        "\n",
        "    job_unitary = sampler.run(unitary_pubs, shots=shots)\n",
        "    print(f\"unitary: {job_unitary.job_id()}\")\n",
        "\n",
        "    job_unitary_dd = sampler.run(unitary_pubs_dd, shots=shots)\n",
        "    print(f\"unitary_dd: {job_unitary_dd.job_id()}\")\n",
        "\n",
        "    job_dynamic = sampler.run(dynamic_pubs, shots=shots)\n",
        "    print(f\"dynamic: {job_dynamic.job_id()}\")\n",
        "\n",
        "    job_dynamic_dd = sampler.run(dynamic_pubs_dd, shots=shots)\n",
        "    print(f\"dynamic_dd: {job_dynamic_dd.job_id()}\")\n",
        "\n",
        "    job_dynamic_meas2 = sampler.run(dynamic_pubs_meas2, shots=shots)\n",
        "    print(f\"dynamic_meas2: {job_dynamic_meas2.job_id()}\")\n",
        "\n",
        "    job_dynamic_dd_meas2 = sampler.run(dynamic_pubs_dd_meas2, shots=shots)\n",
        "    print(f\"dynamic_dd_meas2: {job_dynamic_dd_meas2.job_id()}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "273fa3a0",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-results-in-desired-classical-format\" />\n",
        "\n",
        "## Étape 4 : Post-traitement et restitution des résultats dans le format classique souhaité\n",
        "\n",
        "Une fois les tâches terminées, nous pouvons extraire la durée du circuit à partir des métadonnées des résultats des tâches et visualiser les informations relatives au calendrier du circuit. Pour en savoir plus sur la visualisation des informations de planification d'un circuit, consultez [cette page](/docs/guides/qiskit-runtime-circuit-timing).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "bc16418f",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Circuit durations is reported in the unit of `dt`\n",
        "# which can be retrieved from `Backend` object\n",
        "unitary_durations = [\n",
        "    job_unitary.result()[i].metadata[\"compilation\"][\"scheduler_timing\"][\n",
        "        \"circuit_duration\"\n",
        "    ]\n",
        "    for i in depths\n",
        "]\n",
        "\n",
        "dynamic_durations = [\n",
        "    job_dynamic.result()[i].metadata[\"compilation\"][\"scheduler_timing\"][\n",
        "        \"circuit_duration\"\n",
        "    ]\n",
        "    for i in depths\n",
        "]\n",
        "\n",
        "dynamic_durations_meas2 = [\n",
        "    job_dynamic_meas2.result()[i].metadata[\"compilation\"][\"scheduler_timing\"][\n",
        "        \"circuit_duration\"\n",
        "    ]\n",
        "    for i in depths\n",
        "]\n",
        "\n",
        "result_dd = job_dynamic_dd.result()[1]\n",
        "circuit_schedule_dd = result_dd.metadata[\"compilation\"][\"scheduler_timing\"][\n",
        "    \"timing\"\n",
        "]\n",
        "\n",
        "# to visualize the circuit schedule, one can show the figure below\n",
        "fig_dd = draw_circuit_schedule_timing(\n",
        "    circuit_schedule=circuit_schedule_dd,\n",
        "    included_channels=None,\n",
        "    filter_readout_channels=False,\n",
        "    filter_barriers=False,\n",
        "    width=1000,\n",
        ")\n",
        "\n",
        "# Save to a file since the figure is large\n",
        "fig_dd.write_html(\"scheduler_timing_dd.html\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bee08b77",
      "metadata": {},
      "source": [
        "Nous représentons graphiquement les durées des circuits unitaires et des circuits dynamiques. Le graphique ci-dessous montre que, malgré le temps nécessaire pour les mesures à mi-circuit et les opérations classiques, la mise en œuvre dynamique du circuit avec `measure_2` donne des durées de circuit comparables à celles de la mise en œuvre unitaire.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "639221e6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x12bfde270>"
            ]
          },
          "execution_count": 33,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/639221e6-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# visualize circuit durations\n",
        "\n",
        "\n",
        "def convert_dt_to_microseconds(circ_duration: List, backend_dt: float):\n",
        "    dt = backend_dt * 1e6  # dt in microseconds\n",
        "    return list(map(lambda x: x * dt, circ_duration))\n",
        "\n",
        "\n",
        "dt = backend.target.dt\n",
        "plt.plot(\n",
        "    depths,\n",
        "    convert_dt_to_microseconds(unitary_durations, dt),\n",
        "    color=\"#be95ff\",\n",
        "    linestyle=\":\",\n",
        "    label=\"unitary\",\n",
        ")\n",
        "plt.plot(\n",
        "    depths,\n",
        "    convert_dt_to_microseconds(dynamic_durations, dt),\n",
        "    color=\"#ff7eb6\",\n",
        "    linestyle=\"-.\",\n",
        "    label=\"dynamic\",\n",
        ")\n",
        "plt.plot(\n",
        "    depths,\n",
        "    convert_dt_to_microseconds(dynamic_durations_meas2, dt),\n",
        "    color=\"#ff7eb6\",\n",
        "    linestyle=\"-.\",\n",
        "    marker=\"s\",\n",
        "    mfc=\"none\",\n",
        "    label=\"dynamic w/ meas2\",\n",
        ")\n",
        "\n",
        "plt.xlabel(\"Trotter steps\")\n",
        "plt.ylabel(r\"Circuit durations in $\\mu$s\")\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3c2bd06f",
      "metadata": {},
      "source": [
        "Une fois les tâches terminées, nous récupérons les données ci-dessous et calculons la magnétisation moyenne estimée par les observables `observables_unitary` ou que `observables_dynamic` nous avons construits précédemment.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "f4947049",
      "metadata": {},
      "outputs": [],
      "source": [
        "runs = {\n",
        "    \"unitary\": (\n",
        "        job_unitary,\n",
        "        [observables_unitary] * len(circuits_unitary),\n",
        "    ),\n",
        "    \"unitary_dd\": (\n",
        "        job_unitary_dd,\n",
        "        [observables_unitary] * len(circuits_unitary),\n",
        "    ),\n",
        "    # Omitting Dyn w/o DD and Dynamic w/ DD plots for better readability\n",
        "    # \"dynamic\": (job_dynamic, observables_dynamic),\n",
        "    # \"dynamic_dd\": (job_dynamic_dd, observables_dynamic),\n",
        "    \"dynamic_meas2\": (job_dynamic_meas2, observables_dynamic),\n",
        "    \"dynamic_dd_meas2\": (\n",
        "        job_dynamic_dd_meas2,\n",
        "        observables_dynamic,\n",
        "    ),\n",
        "}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "583d417e",
      "metadata": {},
      "outputs": [],
      "source": [
        "data_dict = {}\n",
        "for key, (job, obs) in runs.items():\n",
        "    data = []\n",
        "    for i in range(points):\n",
        "        data.append(\n",
        "            [\n",
        "                job.result()[ind].data[\"meas\"].expectation_values(obs[ind])[i]\n",
        "                for ind in depths\n",
        "            ]\n",
        "        )\n",
        "    data_dict[key] = data"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "507073d9",
      "metadata": {},
      "source": [
        "Ci-dessous, nous représentons graphiquement la magnétisation de spin en fonction des pas de Trotter à différentes valeurs d' $\\theta$, correspondant à différentes intensités du champ magnétique local. Nous représentons graphiquement les résultats précalculés de la simulation MPS pour les circuits idéaux unitaires, ainsi que les résultats expérimentaux suivants :\n",
        "\n",
        "1. Faire fonctionner les circuits unitaires avec DD\n",
        "2. faire fonctionner les circuits dynamiques avec DD et `MidCircuitMeasure`\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "662239cf",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/dc-hex-ising/extracted-outputs/662239cf-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.figure(figsize=(10, 6))\n",
        "\n",
        "colors = [\"#0f62fe\", \"#be95ff\", \"#ff7eb6\"]\n",
        "for i in range(points):\n",
        "    plt.plot(\n",
        "        depths,\n",
        "        data_sim[i],\n",
        "        color=colors[i],\n",
        "        linestyle=\"solid\",\n",
        "        label=f\"θ={pi_check(i*max_angle/(points-1))} (MPS)\",\n",
        "    )\n",
        "    # plt.plot(\n",
        "    #     depths,\n",
        "    #     data_dict[\"unitary\"][i],\n",
        "    #     color=colors[i],\n",
        "    #     linestyle=\":\",\n",
        "    #     label=f\"θ={pi_check(i*max_angle/(points-1))} (Unitary)\",\n",
        "    # )\n",
        "\n",
        "    plt.plot(\n",
        "        depths,\n",
        "        data_dict[\"unitary_dd\"][i],\n",
        "        color=colors[i],\n",
        "        marker=\"o\",\n",
        "        mfc=\"none\",\n",
        "        linestyle=\":\",\n",
        "        label=f\"θ={pi_check(i*max_angle/(points-1))} (Unitary w/DD)\",\n",
        "    )\n",
        "\n",
        "    # Omitting Dyn w/o DD and Dynamic w/ DD plots for better readability\n",
        "    # plt.plot(\n",
        "    #     depths,\n",
        "    #     data_dict[\"dynamic\"][i],\n",
        "    #     color=colors[i],\n",
        "    #     linestyle=\"-.\",\n",
        "    #     label=f\"θ={pi_check(i*max_angle/(points-1))} (Dyn w/o DD)\",\n",
        "    # )\n",
        "    # plt.plot(\n",
        "    #     depths,\n",
        "    #     data_dict[\"dynamic_dd\"][i],\n",
        "    #     marker=\"D\",\n",
        "    #     mfc=\"none\",\n",
        "    #     color=colors[i],\n",
        "    #     linestyle=\"-.\",\n",
        "    #     label=f\"θ={pi_check(i*max_angle/(points-1))} (Dynamic w/ DD)\",\n",
        "    # )\n",
        "\n",
        "    # plt.plot(\n",
        "    #     depths,\n",
        "    #     data_dict[\"dynamic_meas2\"][i],\n",
        "    #     color=colors[i],\n",
        "    #     marker=\"s\",\n",
        "    #     mfc=\"none\",\n",
        "    #     linestyle=':',\n",
        "    #     label=f\"θ={pi_check(i*max_angle/(points-1))} (Dynamic w/ MidCircuitMeas)\",\n",
        "    # )\n",
        "\n",
        "    plt.plot(\n",
        "        depths,\n",
        "        data_dict[\"dynamic_dd_meas2\"][i],\n",
        "        color=colors[i],\n",
        "        marker=\"*\",\n",
        "        markersize=8,\n",
        "        linestyle=\":\",\n",
        "        label=f\"θ={pi_check(i*max_angle/(points-1))} \"\n",
        "        f\"(Dynamic w/ DD & MidCircuitMeas)\",\n",
        "    )\n",
        "\n",
        "\n",
        "plt.xlabel(\"Trotter steps\", fontsize=16)\n",
        "plt.ylabel(\"Average magnetization\", fontsize=16)\n",
        "plt.xticks(rotation=45)\n",
        "handles, labels = plt.gca().get_legend_handles_labels()\n",
        "plt.legend(\n",
        "    handles,\n",
        "    labels,\n",
        "    loc=\"upper right\",\n",
        "    bbox_to_anchor=(1.46, 1.0),\n",
        "    shadow=True,\n",
        "    ncol=1,\n",
        ")\n",
        "plt.title(\n",
        "    f\"{hex_rows}x{hex_cols} hex ring, {num_qubits} data qubits, \"\n",
        "    f\"{len(ancilla)} ancilla qubits \\n{backend.name}: Sampler\"\n",
        ")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "aead1034",
      "metadata": {},
      "source": [
        "Lorsque nous comparons les résultats expérimentaux avec la simulation, nous constatons que la mise en œuvre du circuit dynamique (ligne pointillée avec des étoiles) offre globalement de meilleures performances que la mise en œuvre unitaire standard (ligne pointillée avec des cercles). En résumé, nous présentons les circuits dynamiques comme une solution pour simuler les modèles de spin d'Ising sur un réseau en nid d'abeille, une topologie qui n'est pas native du matériel. La solution de circuit dynamique permet des interactions ZZ entre des qubits qui ne sont pas des voisins immédiats, avec une profondeur de porte à deux qubits plus courte que celle obtenue avec des portes SWAP, au prix de l'introduction de qubits auxiliaires supplémentaires et d'opérations classiques de feedforward.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "52fb43e1",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## Références\n",
        "\n",
        "\\[1] L'informatique quantique avec Qiskit, par Javadi-Abhari, A., Treinish, M., Krsulich, K., Wood, C.J Lishman, J., Gacon, J., Martiel, S., Nation, P.D Évêque, L.S Cross, A.W. et Johnson, B.R., 2024. arXiv prépublication [arXiv:2405.08810 (2024)](https://arxiv.org/abs/2405.08810)\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"
    },
    "hours": 1,
    "qpuSeconds": 450
  },
  "nbformat": 4,
  "nbformat_minor": 5
}