{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "b793601b-95bc-4d36-adfc-c9fc34ce45cd",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Fasi del transpiler\"\n",
        "description: \"Le fasi predefinite della pipeline di transpilazione del circuito quantistico in Qiskit.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore fontsize */}\n",
        "\n",
        "<span id=\"transpiler-stages\" />\n",
        "\n",
        "# Fasi del transpiler\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4a38c84a-eed2-4fa4-9823-3d544e572398",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Versioni del pacchetto\">\n",
        "    Il codice di questa pagina è stato sviluppato in base ai seguenti requisiti.\n",
        "    Si consiglia di utilizzare queste versioni o versioni più recenti.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.1\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f2ecc4b-e6a3-418c-8a65-a9f3ac98c3dc",
      "metadata": {},
      "source": [
        "Questa pagina descrive le fasi della pipeline di transpilazione precostituita nell'SDK Qiskit. Le fasi sono sei:\n",
        "\n",
        "1. `init`\n",
        "2. `layout`\n",
        "3. `routing`\n",
        "4. `translation`\n",
        "5. `optimization`\n",
        "6. `scheduling`\n",
        "\n",
        "La funzione [`generate_preset_pass_manager`](/docs/api/qiskit/qiskit.transpiler.generate_preset_pass_manager#qiskit.transpiler.generate_preset_pass_manager) crea un [gestore di passaggi](/docs/api/qiskit/qiskit.transpiler.StagedPassManager) preimpostato composto da questi stadi. I passaggi specifici che compongono ogni fase dipendono dagli argomenti passati a `generate_preset_pass_manager`. Il parametro `optimization_level` è un argomento posizionale che deve essere specificato; è un numero intero che può essere 0, 1, 2 o 3. Valori più alti indicano un'ottimizzazione più pesante ma più costosa (vedere [Valori predefiniti e opzioni di configurazione della transpilazione](defaults-and-configuration-options) ).\n",
        "\n",
        "Il modo consigliato per transpilare un circuito è quello di creare un gestore di passaggi preimpostato e poi eseguirlo sul circuito, come descritto in [Transpilare con i gestori di passaggi](transpile-with-pass-managers). Tuttavia, un'alternativa più semplice ma meno personalizzabile è quella di utilizzare la funzione [`transpile`](/docs/api/qiskit/compiler#qiskit.compiler.transpile) funzione. Questa funzione accetta il circuito direttamente come argomento. Come per `generate_preset_pass_manager`, gli specifici passaggi di transpiler utilizzati dipendono dagli argomenti, come `optimization_level`, passati a `transpile`. Infatti, internamente la funzione `transpile` chiama `generate_preset_pass_manager` per creare un gestore di passaggi preimpostato ed eseguirlo sul circuito.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "18140654-10ff-40c5-ab75-4d19b8a7f5dd",
      "metadata": {},
      "source": [
        "<span id=\"init-stage\" />\n",
        "\n",
        "## Fase iniziale\n",
        "\n",
        "Questo primo stadio fa ben poco per impostazione predefinita ed è utile soprattutto se si vogliono includere le proprie ottimizzazioni iniziali.  Poiché la maggior parte degli algoritmi di layout e routing sono progettati per funzionare solo con porte a uno o due qubit, questa fase viene utilizzata anche per tradurre le porte che operano su più di due qubit in porte che operano solo su uno o due qubit.\n",
        "\n",
        "Per ulteriori informazioni sull'implementazione delle ottimizzazioni iniziali per questa fase, vedere la sezione sui plugin e sulla personalizzazione dei gestori di passaggi.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "506a831f-b317-4335-8124-20ed994292cd",
      "metadata": {},
      "source": [
        "<span id=\"layout-stage\" />\n",
        "\n",
        "## Fase di layout\n",
        "\n",
        "La fase successiva riguarda la configurazione o la connettività del backend a cui verrà inviato il circuito.  In generale, i circuiti quantistici sono entità astratte i cui qubit sono rappresentazioni \"virtuali\" o \"logiche\" dei qubit reali utilizzati nei calcoli.  Per eseguire una sequenza di porte, è necessaria una corrispondenza biunivoca tra i qubit \"virtuali\" e quelli \"fisici\" in un dispositivo quantistico reale.  Questa mappatura è memorizzata come oggetto `Layout` e fa parte dei vincoli definiti [nell'architettura del set di istruzioni (ISA)](/docs/guides/transpile#instruction-set-architecture) di un backend.\n",
        "\n",
        "![Questa immagine mostra la mappatura dei qubit dalla rappresentazione schematica a un diagramma che illustra come i qubit sono collegati sulla QPU. Mappatura](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/layout-mapping.svg \" dei qubit\")\n",
        "\n",
        "La scelta della mappatura è estremamente importante per ridurre al minimo il numero di operazioni SWAP necessarie per mappare il circuito di ingresso sulla topologia del dispositivo e garantire l'utilizzo dei qubit più ben calibrati.  Data l'importanza di questa fase, i gestori dei passaggi preimpostati provano alcuni metodi diversi per trovare il layout migliore.  In genere si tratta di due fasi: prima si cerca di trovare un layout \"perfetto\" (un layout che non richieda alcuna operazione di SWAP) e poi si effettua un passaggio euristico che cerca di trovare il layout migliore da utilizzare se non è possibile trovare un layout perfetto.  Per questa prima fase si utilizzano in genere due `Passes` :\n",
        "\n",
        "* `TrivialLayout`: Mappa ingenuamente ogni qubit virtuale sullo stesso qubit fisico numerato sul dispositivo (ad esempio, \\[`0`,`1`,`1`,`3`] -> \\[`0`,`1`,`1`,`3`] ). Questo è un comportamento storico utilizzato solo in `optimzation_level=1` per cercare di trovare un layout perfetto.  Se non riesce, il tentativo successivo è `VF2Layout` .\n",
        "* `VF2Layout`: Si tratta di un `AnalysisPass` che seleziona un layout ideale trattando questa fase come un problema di isomorfismo dei sottografi, risolto dall'algoritmo VF2++.  Se viene trovato più di un layout, viene eseguita un'euristica di punteggio per selezionare la mappatura con l'errore medio più basso.\n",
        "\n",
        "Poi, per la fase euristica, vengono utilizzati due passaggi per impostazione predefinita:\n",
        "\n",
        "* `DenseLayout`: Trova il sottografo del dispositivo con la maggiore connettività e che ha lo stesso numero di qubit del circuito (usato per il livello di ottimizzazione 1 se nel circuito sono presenti operazioni di flusso di controllo (come IfElseOp )).\n",
        "* `SabreLayout`: Questo passaggio seleziona un layout partendo da un layout casuale iniziale ed eseguendo ripetutamente `SabreSwap` l'algoritmo.  Questo passaggio viene utilizzato solo nei livelli di ottimizzazione 1, 2 e 3 se non viene trovato un layout perfetto tramite il `VF2Layout` passaggio.  Per ulteriori dettagli su questo algoritmo, consultare il documento \" [arXiv:1809.02573](https://arxiv.org/abs/1809.02573) \" (Analisi delle prestazioni di un algoritmo di ottimizzazione basato su una rete neurale artificiale).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cf772b6c-2578-455d-8014-9a7de2f9db19",
      "metadata": {},
      "source": [
        "<span id=\"routing-stage\" />\n",
        "\n",
        "## Fase di instradamento\n",
        "\n",
        "Per implementare un gate a due qubit tra qubit non direttamente connessi su un dispositivo quantistico, è necessario inserire nel circuito una o più porte SWAP per spostare gli stati dei qubit fino a renderli adiacenti sulla mappa dei gate del dispositivo.  Ogni porta SWAP rappresenta un'operazione costosa e rumorosa da eseguire.  Pertanto, trovare il numero minimo di porte SWAP necessarie per mappare un circuito su un determinato dispositivo è un passo importante nel processo di transpilazione.  Per motivi di efficienza, questa fase viene in genere calcolata insieme alla fase di layout per impostazione predefinita, ma sono logicamente distinte l'una dall'altra.  Lo stadio *Layout* seleziona i qubit hardware da utilizzare, mentre lo stadio *Routing* inserisce la quantità appropriata di porte SWAP per eseguire i circuiti utilizzando il layout selezionato.\n",
        "\n",
        "Tuttavia, trovare la mappatura SWAP ottimale è difficile.  In effetti, si tratta di un problema NP-hard, quindi proibitivamente costoso da calcolare per tutti i dispositivi quantistici e i circuiti di input, tranne quelli più piccoli.  Per ovviare a questo problema, Qiskit utilizza un algoritmo euristico stocastico chiamato `SabreSwap` per calcolare una mappatura SWAP buona, ma non necessariamente ottimale. L'uso di un metodo stocastico significa che i circuiti generati non sono garantiti come uguali in caso di esecuzioni ripetute.  Infatti, eseguendo ripetutamente lo stesso circuito, si ottiene una distribuzione delle profondità del circuito e dei numeri di porte in uscita.  Per questo motivo molti utenti scelgono di eseguire più volte la funzione di instradamento (o l'intero `StagedPassManager`) e di selezionare i circuiti a più bassa profondità dalla distribuzione delle uscite.\n",
        "\n",
        "Ad esempio, prendiamo un circuito GHZ a 15 qubit eseguito 100 volte, utilizzando un \"cattivo\" (disconnesso) `initial_layout`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "62479697-cef1-4a89-ac2a-20051dd294f4",
      "metadata": {
        "tags": []
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "Text(0, 0.5, 'Counts')"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/62479697-cef1-4a89-ac2a-20051dd294f4-1.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.providers.fake_provider import GenericBackendV2\n",
        "\n",
        "backend = GenericBackendV2(15)\n",
        "\n",
        "\n",
        "ghz = QuantumCircuit(15)\n",
        "ghz.h(0)\n",
        "ghz.cx(0, range(1, 15))\n",
        "\n",
        "depths = []\n",
        "for seed in range(100):\n",
        "    pass_manager = generate_preset_pass_manager(\n",
        "        optimization_level=1,\n",
        "        backend=backend,\n",
        "        layout_method=\"trivial\",  # Fixed layout mapped in circuit order\n",
        "        seed_transpiler=seed,  # For reproducible results\n",
        "    )\n",
        "    depths.append(pass_manager.run(ghz).depth())\n",
        "\n",
        "plt.figure(figsize=(8, 6))\n",
        "plt.hist(depths, align=\"left\", color=\"#AC557C\")\n",
        "plt.xlabel(\"Depth\", fontsize=14)\n",
        "plt.ylabel(\"Counts\", fontsize=14)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ff31f484-a816-4479-8827-d56641501319",
      "metadata": {},
      "source": [
        "Questa ampia distribuzione dimostra quanto sia difficile per il mappatore SWAP calcolare la mappatura migliore.  Per capire meglio, analizziamo sia il circuito in esecuzione sia i qubit scelti nell'hardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "ab89c4ea-06c4-4320-b493-feb691b3570d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/ab89c4ea-06c4-4320-b493-feb691b3570d-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz.draw(\"mpl\", idle_wires=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "f6a3a92a-8656-4518-ba2c-c3b0b038f507",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/f6a3a92a-8656-4518-ba2c-c3b0b038f507-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.visualization import plot_circuit_layout\n",
        "\n",
        "# Plot the hardware graph and indicate which hardware qubits were chosen to run the circuit\n",
        "transpiled_circ = pass_manager.run(ghz)\n",
        "plot_circuit_layout(transpiled_circ, backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ec2818a-8087-42ba-990d-b3c1258dbf35",
      "metadata": {},
      "source": [
        "Come si può vedere, questo circuito deve eseguire un gate a due qubit tra i qubit 0 e 14, che sono molto distanti tra loro nel grafo di connettività.  L'esecuzione di questo circuito richiede quindi l'inserimento di porte SWAP per eseguire tutte le porte a due qubit utilizzando il passaggio `SabreSwap` .\n",
        "\n",
        "Si noti inoltre che l'algoritmo `SabreSwap` è diverso dal metodo `SabreLayout` più ampio della fase precedente.  Per impostazione predefinita, `SabreLayout` esegue sia il layout che il routing e restituisce il circuito trasformato.  Questo viene fatto per alcune particolari ragioni tecniche specificate nella [pagina di riferimento dell'API](../api/qiskit/qiskit.transpiler.passes.SabreLayout) del pass.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "650f978b-d992-4d67-a356-5bf73902f212",
      "metadata": {},
      "source": [
        "<span id=\"translation-stage\" />\n",
        "\n",
        "## Fase di traduzione\n",
        "\n",
        "Quando si scrive un circuito quantistico, si è liberi di utilizzare qualsiasi porta quantistica (operazione unitaria) si desideri, insieme a una serie di operazioni non legate alle porte, come la misurazione dei qubit o le istruzioni di reset.  Tuttavia, la maggior parte dei dispositivi quantistici supporta nativamente solo una manciata di operazioni quantistiche, sia che si tratti di porte quantistiche che di operazioni diverse dalle porte.  Questi gate nativi fanno parte della definizione [dell'ISA](/docs/guides/transpile#instruction-set-architecture) di un target e questa fase del preset `PassManagers` traduce (o *srotola* ) i gate specificati in un circuito nei gate nativi di un backend specificato.  Si tratta di un passo importante, poiché consente l'esecuzione del circuito da parte del backend, ma comporta solitamente un aumento della profondità e del numero di porte logiche.\n",
        "\n",
        "Due casi speciali sono particolarmente importanti da sottolineare e aiutano a illustrare le funzioni di questa fase.\n",
        "\n",
        "1. Se un gate SWAP non è un gate nativo del backend di destinazione, sono necessari tre gate CNOT:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "d4d1f65a-3336-4d70-9189-65ba010f2366",
      "metadata": {
        "tags": []
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "native gates:['cx', 'delay', 'id', 'measure', 'reset', 'rz', 'sx', 'x']\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/d4d1f65a-3336-4d70-9189-65ba010f2366-1.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "print(\"native gates:\" + str(sorted(backend.operation_names)))\n",
        "qc = QuantumCircuit(2)\n",
        "qc.swap(0, 1)\n",
        "qc.decompose().draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "56347603-8766-4165-af18-1f6fe4c61d4f",
      "metadata": {},
      "source": [
        "Essendo il prodotto di tre porte CNOT, uno SWAP è un'operazione costosa da eseguire su dispositivi quantistici rumorosi.  Tuttavia, tali operazioni sono solitamente necessarie per incorporare un circuito nelle limitate connettività dei gate di molti dispositivi.  Pertanto, la minimizzazione del numero di porte SWAP in un circuito è un obiettivo primario del processo di transpilazione.\n",
        "\n",
        "2. Una porta Toffoli, o porta controllata-non controllata (`ccx`), è una porta a tre qubit.  Dato che il nostro set di porte di base comprende solo porte a uno o due qubit, questa operazione deve essere scomposta.  Tuttavia, è piuttosto costoso:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "4552b367-75e9-4faa-a59d-8317e25ac145",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/4552b367-75e9-4faa-a59d-8317e25ac145-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(3)\n",
        "qc.ccx(0, 1, 2)\n",
        "qc.decompose().draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "70af8d85-84c2-43cf-96fa-37bcf68f89c9",
      "metadata": {},
      "source": [
        "Per ogni porta Toffoli in un circuito quantistico, l'hardware può eseguire fino a sei porte CNOT e una manciata di porte a singolo qubit.  Questo esempio dimostra che qualsiasi algoritmo che faccia uso di più porte di Toffoli finirà per essere un circuito con una grande profondità e sarà quindi sensibilmente influenzato dal rumore.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8b396526-b14b-48a3-93ed-37e590b06caf",
      "metadata": {},
      "source": [
        "<span id=\"optimization-stage\" />\n",
        "\n",
        "## Fase di ottimizzazione\n",
        "\n",
        "Questa fase è incentrata sulla scomposizione dei circuiti quantistici nel set di porte di base del dispositivo di destinazione e deve contrastare l'aumento della profondità dovuto alle fasi di layout e routing.  Fortunatamente, esistono molte routine per ottimizzare i circuiti combinando o eliminando le porte.  In alcuni casi, questi metodi sono così efficaci che i circuiti di uscita hanno una profondità inferiore a quella degli ingressi, anche dopo il layout e l'instradamento nella topologia hardware.  In altri casi, non si può fare molto e il calcolo può essere difficile da eseguire su dispositivi rumorosi.  In questa fase i vari livelli di ottimizzazione iniziano a differenziarsi.\n",
        "\n",
        "* Per `optimization_level=1`, questa fase prepara [`Optimize1qGatesDecomposition`](../api/qiskit/qiskit.transpiler.passes.Optimize1qGatesDecomposition) e [`CXCancellation`](/docs/api/qiskit/1.4/qiskit.transpiler.passes.CXCancellation)che combinano catene di porte a singolo qubit e annullano qualsiasi porta CNOT retrostante.\n",
        "* Per `optimization_level=2`, questo stadio utilizza il [`CommutativeCancellation`](../api/qiskit/qiskit.transpiler.passes.CommutativeCancellation) invece di `CXCancellation`, che elimina le porte ridondanti sfruttando le relazioni di commutazione.\n",
        "* Per `optimization_level=3`, questa fase prepara i seguenti passaggi:\n",
        "  * [`Collect2qBlocks`](../api/qiskit/qiskit.transpiler.passes.Collect2qBlocks)\n",
        "  * [`ConsolidateBlocks`](../api/qiskit/qiskit.transpiler.passes.ConsolidateBlocks)\n",
        "  * [`UnitarySynthesis`](../api/qiskit/qiskit.transpiler.passes.UnitarySynthesis)\n",
        "  * [`Optimize1qGateDecomposition`](../api/qiskit/qiskit.transpiler.passes.Optimize1qGatesDecomposition)\n",
        "  * [`CommutativeCancellation`](../api/qiskit/qiskit.transpiler.passes.CommutativeCancellation)\n",
        "\n",
        "Inoltre, questa fase esegue anche alcuni controlli finali per assicurarsi che tutte le istruzioni del circuito siano composte dalle porte di base disponibili sul backend di destinazione.\n",
        "\n",
        "L'esempio seguente, che utilizza uno stato GHZ, mostra gli effetti di diverse impostazioni del livello di ottimizzazione sulla profondità del circuito e sul numero di gate.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  L'output della transpilazione varia a causa del mappatore stocastico SWAP. Pertanto, è probabile che i numeri riportati di seguito cambino ogni volta che si esegue il codice.\n",
        "</Admonition>\n",
        "\n",
        "![stato GHZ a 15-qubit](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-11.avif \"Stato GHZ a 15-qubit prima della transpilazione\")\n",
        "\n",
        "Il codice seguente costruisce uno stato GHZ a 15-qubit e confronta il `optimization_levels` della transpilazione in termini di profondità del circuito risultante, numero di porte e numero di porte multi-qubit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "2700405a-f559-45d3-99a9-5b4447621743",
      "metadata": {
        "tags": []
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/2700405a-f559-45d3-99a9-5b4447621743-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "ghz = QuantumCircuit(15)\n",
        "ghz.h(0)\n",
        "ghz.cx(0, range(1, 15))\n",
        "\n",
        "depths = []\n",
        "gate_counts = []\n",
        "multiqubit_gate_counts = []\n",
        "levels = [str(x) for x in range(4)]\n",
        "for level in range(4):\n",
        "    pass_manager = generate_preset_pass_manager(\n",
        "        optimization_level=level,\n",
        "        backend=backend,\n",
        "        seed_transpiler=1234,\n",
        "    )\n",
        "    circ = pass_manager.run(ghz)\n",
        "    depths.append(circ.depth())\n",
        "    gate_counts.append(sum(circ.count_ops().values()))\n",
        "    multiqubit_gate_counts.append(circ.count_ops()[\"cx\"])\n",
        "\n",
        "fig, (ax1, ax2) = plt.subplots(2, 1)\n",
        "ax1.bar(levels, depths, label=\"Depth\")\n",
        "ax1.set_xlabel(\"Optimization Level\")\n",
        "ax1.set_ylabel(\"Depth\")\n",
        "ax1.set_title(\"Output Circuit Depth\")\n",
        "ax2.bar(levels, gate_counts, label=\"Number of Circuit Operations\")\n",
        "ax2.bar(levels, multiqubit_gate_counts, label=\"Number of CX gates\")\n",
        "ax2.set_xlabel(\"Optimization Level\")\n",
        "ax2.set_ylabel(\"Number of gates\")\n",
        "ax2.legend()\n",
        "ax2.set_title(\"Number of output circuit gates\")\n",
        "fig.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c870a48f-2bc4-4150-83ff-857a06e42ffb",
      "metadata": {},
      "source": [
        "<span id=\"scheduling\" />\n",
        "\n",
        "## Pianificazione\n",
        "\n",
        "Quest'ultimo stadio viene eseguito solo se viene richiesto esplicitamente (come lo stadio Init) e non viene eseguito per impostazione predefinita (anche se è possibile specificare un metodo impostando l'argomento `scheduling_method` quando si chiama `generate_preset_pass_manager`).  La fase di schedulazione viene utilizzata in genere una volta che il circuito è stato tradotto nella base di destinazione, mappato sul dispositivo e ottimizzato.  Questi passaggi si concentrano sulla considerazione di tutto il tempo di inattività di un circuito.  Ad alto livello, il passaggio di schedulazione può essere pensato come l'inserimento esplicito di istruzioni di ritardo per tenere conto del tempo di inattività tra le esecuzioni dei gate e per controllare quanto tempo il circuito rimarrà in esecuzione sul backend.\n",
        "\n",
        "Di seguito è riportato un esempio:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "ae2d9390-5c26-46f3-9418-a684ba8a406a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/ae2d9390-5c26-46f3-9418-a684ba8a406a-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz = QuantumCircuit(5)\n",
        "ghz.h(0)\n",
        "ghz.cx(0, range(1, 5))\n",
        "\n",
        "\n",
        "# Use fake backend\n",
        "backend = GenericBackendV2(5)\n",
        "\n",
        "# Run with optimization level 3 and 'asap' scheduling pass\n",
        "pass_manager = generate_preset_pass_manager(\n",
        "    optimization_level=3,\n",
        "    backend=backend,\n",
        "    scheduling_method=\"asap\",\n",
        "    seed_transpiler=1234,\n",
        ")\n",
        "\n",
        "\n",
        "circ = pass_manager.run(ghz)\n",
        "circ.draw(output=\"mpl\", idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "442cb546-3463-4044-8406-1c68d371a2c9",
      "metadata": {},
      "source": [
        "![Circuito con istruzioni di ritardo](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-16.avif)\n",
        "\n",
        "Il transpiler ha inserito le istruzioni `Delay` per tenere conto del tempo di inattività di ciascun qubit. Per avere un'idea più precisa della tempistica del circuito, possiamo anche osservarlo con la funzione `timeline.draw()` :\n",
        "\n",
        "![timeline.draw (): vista dello stesso circuito](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-17.svg)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0b214bba-1f0e-49fc-be7e-29ccb57fff8a",
      "metadata": {},
      "source": [
        "La programmazione di un circuito prevede due parti: l'analisi e la mappatura dei vincoli, seguite da un passaggio di imbottitura.  La prima parte richiede l'esecuzione di un passaggio di analisi dello scheduling (per impostazione predefinita questo è [`ALAPSchedulingAnalysis`](../api/qiskit/qiskit.transpiler.passes.ALAPScheduleAnalysis)), che analizza il circuito e registra l'ora di inizio di ogni istruzione del circuito in una schedulazione.  Una volta che il circuito ha una programmazione iniziale, è possibile eseguire ulteriori passaggi per tenere conto di eventuali vincoli temporali sul backend di destinazione.  Infine, un passaggio di imbottitura come [`PadDelay`](../api/qiskit/qiskit.transpiler.passes.PadDelay) o [`PadDynamicalDecoupling`](../api/qiskit/qiskit.transpiler.passes.PadDynamicalDecoupling) può essere eseguito.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "62c19c54-6dcc-4025-b800-7a74be69808d",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Passi successivi\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Suggerimenti\">\n",
        "  * Per imparare a usare la funzione `generate_preset_passmanager` , iniziare con l'argomento [Impostazioni predefinite e opzioni di configurazione della transpilazione](defaults-and-configuration-options).\n",
        "  * Continua ad apprendere sulla transpilazione con l'argomento [Transpiler con pass manager](transpile-with-pass-managers).\n",
        "  * Prova la guida [Confronta le impostazioni del transpiler](/docs/guides/circuit-transpilation-settings).\n",
        "  * Consulta [la documentazione dell'API Transpile](https://docs.quantum-computing.ibm.com/api/qiskit/transpiler).\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "celltoolbar": "Raw Cell Format",
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}