{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "710d86a8-3243-4133-b7bc-093306598512",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Scrivere un passaggio personalizzato per il transpilatore\"\n",
        "description: \"Impara a scrivere il tuo pass transpiler utilizzando Qiskit, inclusa la rappresentazione del circuito DAG\"\n",
        "---\n",
        "\n",
        "<span id=\"write-a-custom-transpiler-pass\" />\n",
        "\n",
        "# Scrivere un passaggio personalizzato per il transpilatore\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a66bd4b-56b1-4f33-b1bf-b43dbc7c03a7",
      "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": "32806873-3c88-48fc-94ad-9d20e0f378f8",
      "metadata": {},
      "source": [
        "L'SDK di Qiskit consente di creare passaggi di transpilazione personalizzati e di eseguirli nell'oggetto `PassManager` o di aggiungerli a `StagedPassManager`. Qui dimostreremo come scrivere un passaggio di transpiler, concentrandoci sulla costruzione di un passaggio che esegua il [Pauli twirling](https://arxiv.org/abs/quant-ph/0606161) sulle porte quantistiche rumorose di un circuito quantistico. Questo esempio utilizza il DAG, che è l'oggetto manipolato dal tipo di passaggio `TransformationPass` .\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c49a2046-39b0-4e63-aa63-911845ffd315",
      "metadata": {},
      "source": [
        "<Accordion>\n",
        "  <AccordionItem title=\"Contesto: rappresentazione DAG\">\n",
        "    Prima di costruire un passaggio, è importante introdurre la rappresentazione interna dei circuiti quantistici in Qiskit, il [grafo aciclico diretto (DAG)](../api/qiskit/qiskit.dagcircuit.DAGCircuit) (si veda [questo tutorial](https://qiskit.org/ecosystem/rustworkx/tutorial/dags.html) per una panoramica).  Per seguire questi passaggi, installare la [libreria `graphviz` ](https://graphviz.org/download/) per le funzioni di plottaggio DAG.\n",
        "\n",
        "    In Qiskit, nelle fasi di transpilazione, i circuiti sono rappresentati utilizzando un DAG.  In generale, un DAG è composto da *vertici* (noti anche come \"nodi\") e *spigoli* orientati che collegano coppie di vertici in un orientamento particolare.  Questa rappresentazione è memorizzata utilizzando `qiskit.dagcircuit.DAGCircuit` oggetti composti da singoli `DagNode` oggetti.  Il vantaggio di questa rappresentazione rispetto a un semplice elenco di porte (ovvero una *netlist* ) è che il flusso di informazioni tra le operazioni è esplicito, rendendo più facile prendere decisioni di trasformazione.\n",
        "\n",
        "    Questo esempio illustra il DAG creando un semplice circuito che prepara uno stato Bell e applica una rotazione $R_Z$, a seconda del risultato della misurazione.\n",
        "\n",
        "    ```python\n",
        "    from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n",
        "    import numpy as np\n",
        "\n",
        "    qr = QuantumRegister(3, 'qr')\n",
        "    cr = ClassicalRegister(3, 'cr')\n",
        "    qc = QuantumCircuit(qr, cr)\n",
        "\n",
        "    qc.h(qr[0])\n",
        "    qc.cx(qr[0], qr[1])\n",
        "    qc.measure(qr[0], cr[0])\n",
        "    with qc.if_test((cr, 2)):\n",
        "        qc.rz(np.pi/2, qr[1])\n",
        "    qc.draw(output='mpl')\n",
        "\n",
        "    ```\n",
        "\n",
        "    ![Circuito che prepara uno stato di Bell e applica una rotazione R\\_Z in base al risultato della misurazione.](https://quantum.cloud.ibm.com/docs/images/guides/custom-transpiler-pass/DAG_circ.avif \"Circuito\")\n",
        "\n",
        "    Utilizzare la funzione `qiskit.tools.visualization.dag_drawer()` per visualizzare il DAG di questo circuito.  Ci sono tre tipi di nodi del grafo: nodi qubit/clbit (verdi), nodi di operazione (blu) e nodi di uscita (rossi).  Ogni bordo indica il flusso di dati (o la dipendenza) tra due nodi.\n",
        "\n",
        "    ```python\n",
        "    from qiskit.converters import circuit_to_dag\n",
        "    from qiskit.visualization import dag_drawer\n",
        "\n",
        "    dag = circuit_to_dag(qc)\n",
        "    dag_drawer(dag)\n",
        "    ```\n",
        "\n",
        "    ![Il DAG del circuito è costituito da nodi collegati da bordi direzionali. È un modo visivo per rappresentare i qubit o i bit classici, le operazioni e il modo in cui i dati fluiscono.](https://quantum.cloud.ibm.com/docs/images/guides/custom-transpiler-pass/DAG.avif \"DAG\")\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e2e2bc6-c900-4d3b-a948-3f5d154cdea2",
      "metadata": {},
      "source": [
        "<span id=\"transpiler-passes\" />\n",
        "\n",
        "## Passaggi del transpiler\n",
        "\n",
        "I passaggi del transpiler vengono classificati come [`AnalysisPass`](../api/qiskit/qiskit.transpiler.AnalysisPass) o come [`TransformationPass`](../api/qiskit/qiskit.transpiler.TransformationPass). I passaggi, in generale, interagiscono con il [DAG](../api/qiskit/qiskit.dagcircuit.DAGCircuit) e con `property_set`, un oggetto simile a un dizionario utilizzato per memorizzare le proprietà determinate dai passaggi di analisi. I passaggi di analisi funzionano sia con il DAG che con il suo `property_set`.  Non possono modificare il DAG, ma possono modificare il `property_set`.  Ciò è in contrasto con i passaggi di trasformazione, che modificano il DAG e possono leggere (ma non scrivere) `property_set`.  Ad esempio, le fasi di trasformazione traducono un circuito nella sua [ISA](/docs/guides/transpile#instruction-set-architecture) oppure eseguono fasi di instradamento per inserire porte SWAP dove necessario.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f8ead728-b2b7-47b9-b3b1-f3578b594ffe",
      "metadata": {},
      "source": [
        "<span id=\"create-a-paulitwirl-transpiler-pass\" />\n",
        "\n",
        "## Creare un passaggio `PauliTwirl` transpiler\n",
        "\n",
        "L'esempio seguente costruisce un passaggio di transpiler che aggiunge le torsioni di Pauli. Il [Pauli twirling](https://arxiv.org/abs/quant-ph/0606161) è una strategia di soppressione degli errori che randomizza il modo in cui i qubit sperimentano i canali rumorosi, che in questo esempio assumiamo essere porte a due qubit (perché sono molto più soggette a errori rispetto alle porte a singolo qubit). I vortici di Pauli non influenzano il funzionamento delle porte a due qubit. Sono scelti in modo tale che quelli applicati *prima del* gate a due equbit (a sinistra) siano contrastati da quelli applicati *dopo* il gate a due equbit (a destra). In questo senso, le operazioni a due qubit sono identiche, ma il modo in cui vengono eseguite è diverso. Un vantaggio della rotazione di Pauli è che trasforma gli errori coerenti in errori stocastici, che possono essere migliorati con una maggiore media.\n",
        "\n",
        "I passaggi di Transpiler agiscono sul [DAG](../api/qiskit/qiskit.dagcircuit.DAGCircuit), quindi il metodo importante da sovrascrivere è `.run()`, che prende il DAG come input. L'inizializzazione delle coppie di Paulis, come mostrato, preserva il funzionamento di ogni porta a due qubit. Questo viene fatto con il metodo di aiuto `build_twirl_set`, che passa attraverso ogni Pauli a due qubit (come ottenuto da `pauli_basis(2)`) e trova l'altro Pauli che preserva l'operazione.\n",
        "\n",
        "Dal DAG, utilizzare il metodo `op_nodes()` per restituire tutti i suoi nodi. Il DAG può essere utilizzato anche per raccogliere le corse, che sono sequenze di nodi che funzionano ininterrottamente su un qubit. Queste possono essere raccolte come corse a singolo qubit con `collect_1q_runs`, corse a due qubit con `collect_2q_runs`, e corse di nodi in cui i nomi delle istruzioni sono in una namelist con `collect_runs`.  Il sito `DAGCircuit` dispone di molti metodi per cercare e attraversare un grafo.  Un metodo comunemente utilizzato è `topological_op_nodes`, che fornisce i nodi in un ordine di dipendenza. Altri metodi, come `bfs_successors` , sono utilizzati principalmente per determinare come i nodi interagiscono con le operazioni successive su un DAG.\n",
        "\n",
        "Nell'esempio, vogliamo sostituire ogni nodo, che rappresenta un'istruzione, con un sottocircuito costruito come un mini DAG. Al mini DAG è stato aggiunto un registro quantistico a due qubit.  Le operazioni vengono aggiunte al mini DAG utilizzando `apply_operation_back`, che posiziona `Instruction` sull'uscita del mini DAG (mentre `apply_operation_front` lo posizionerebbe sull'ingresso del mini DAG). Il nodo viene quindi sostituito dal mini DAG utilizzando `substitute_node_with_dag`, e il processo continua per ogni istanza di `CXGate` e `ECRGate` nel DAG (corrispondenti alle porte di base a due qubit sui backend di IBM® ).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "80546e59-dcd8-4b61-88b5-00b220409f6d",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.dagcircuit import DAGCircuit\n",
        "from qiskit.circuit import QuantumCircuit, QuantumRegister, Gate\n",
        "from qiskit.circuit.library import CXGate, ECRGate\n",
        "from qiskit.transpiler import PassManager\n",
        "from qiskit.transpiler.basepasses import TransformationPass\n",
        "from qiskit.quantum_info import Operator, pauli_basis\n",
        "\n",
        "import numpy as np\n",
        "\n",
        "from typing import Iterable, Optional"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "6bb6ff72-43dd-4f8c-a67c-b43af2548b2a",
      "metadata": {},
      "outputs": [],
      "source": [
        "class PauliTwirl(TransformationPass):\n",
        "    \"\"\"Add Pauli twirls to two-qubit gates.\"\"\"\n",
        "\n",
        "    def __init__(\n",
        "        self,\n",
        "        gates_to_twirl: Optional[Iterable[Gate]] = None,\n",
        "    ):\n",
        "        \"\"\"\n",
        "        Args:\n",
        "            gates_to_twirl: Names of gates to twirl. The default behavior is to twirl all\n",
        "                two-qubit basis gates, `cx` and `ecr` for IBM backends.\n",
        "        \"\"\"\n",
        "        if gates_to_twirl is None:\n",
        "            gates_to_twirl = [CXGate(), ECRGate()]\n",
        "        self.gates_to_twirl = gates_to_twirl\n",
        "        self.build_twirl_set()\n",
        "        super().__init__()\n",
        "\n",
        "    def build_twirl_set(self):\n",
        "        \"\"\"\n",
        "        Build a set of Paulis to twirl for each gate and store internally as .twirl_set.\n",
        "        \"\"\"\n",
        "        self.twirl_set = {}\n",
        "\n",
        "        # iterate through gates to be twirled\n",
        "        for twirl_gate in self.gates_to_twirl:\n",
        "            twirl_list = []\n",
        "\n",
        "            # iterate through Paulis on left of gate to twirl\n",
        "            for pauli_left in pauli_basis(2):\n",
        "                # iterate through Paulis on right of gate to twirl\n",
        "                for pauli_right in pauli_basis(2):\n",
        "                    # save pairs that produce identical operation as gate to twirl\n",
        "                    if (Operator(pauli_left) @ Operator(twirl_gate)).equiv(\n",
        "                        Operator(twirl_gate) @ pauli_right\n",
        "                    ):\n",
        "                        twirl_list.append((pauli_left, pauli_right))\n",
        "\n",
        "            self.twirl_set[twirl_gate.name] = twirl_list\n",
        "\n",
        "    def run(\n",
        "        self,\n",
        "        dag: DAGCircuit,\n",
        "    ) -> DAGCircuit:\n",
        "        # collect all nodes in DAG and proceed if it is to be twirled\n",
        "        twirling_gate_classes = tuple(\n",
        "            gate.base_class for gate in self.gates_to_twirl\n",
        "        )\n",
        "        for node in dag.op_nodes():\n",
        "            if not isinstance(node.op, twirling_gate_classes):\n",
        "                continue\n",
        "\n",
        "            # random integer to select Pauli twirl pair\n",
        "            pauli_index = np.random.randint(\n",
        "                0, len(self.twirl_set[node.op.name])\n",
        "            )\n",
        "            twirl_pair = self.twirl_set[node.op.name][pauli_index]\n",
        "\n",
        "            # instantiate mini_dag and attach quantum register\n",
        "            mini_dag = DAGCircuit()\n",
        "            register = QuantumRegister(2)\n",
        "            mini_dag.add_qreg(register)\n",
        "\n",
        "            # apply left Pauli, gate to twirl, and right Pauli to empty mini-DAG\n",
        "            mini_dag.apply_operation_back(\n",
        "                twirl_pair[0].to_instruction(), [register[0], register[1]]\n",
        "            )\n",
        "            mini_dag.apply_operation_back(node.op, [register[0], register[1]])\n",
        "            mini_dag.apply_operation_back(\n",
        "                twirl_pair[1].to_instruction(), [register[0], register[1]]\n",
        "            )\n",
        "\n",
        "            # substitute gate to twirl node with twirling mini-DAG\n",
        "            dag.substitute_node_with_dag(node, mini_dag)\n",
        "\n",
        "        return dag"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "da136beb-d1b2-4f68-8274-386e80a49860",
      "metadata": {},
      "source": [
        "<span id=\"use-the-paulitwirl-transpiler-pass\" />\n",
        "\n",
        "## Utilizza il passaggio `PauliTwirl` transpiler\n",
        "\n",
        "Il codice seguente utilizza il pass creato sopra per transpilare un circuito. Consideriamo un circuito semplice con `cx` porte `ecr` e.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "9123905d-b4cb-4ae9-9695-4ad77e70bdab",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-transpiler-pass/extracted-outputs/9123905d-b4cb-4ae9-9695-4ad77e70bdab-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(3)\n",
        "qc.cx(0, 1)\n",
        "qc.ecr(1, 2)\n",
        "qc.ecr(1, 0)\n",
        "qc.cx(2, 1)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f112c2af-c99a-4733-8118-4786e2dfdfd3",
      "metadata": {},
      "source": [
        "Per applicare il pass personalizzato, costruire un pass manager utilizzando il pass `PauliTwirl` ed eseguirlo su 50 circuiti.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "ea884cd2-2446-4b2d-a0f7-82ef574b11ee",
      "metadata": {},
      "outputs": [],
      "source": [
        "pm = PassManager([PauliTwirl()])\n",
        "twirled_qcs = [pm.run(qc) for _ in range(50)]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3d4d921e-1a43-4f9a-bc30-6c64092d8f6b",
      "metadata": {},
      "source": [
        "Ogni porta a due qubit è ora inserita tra due Paulis.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "e2515cf3-f8d9-4281-9673-d5a955d7aab9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-transpiler-pass/extracted-outputs/e2515cf3-f8d9-4281-9673-d5a955d7aab9-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "twirled_qcs[-1].draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "41cccfba-8b65-401c-9d30-66396a3fe3a1",
      "metadata": {},
      "source": [
        "Gli operatori sono gli stessi se si utilizza `Operator` da `qiskit.quantum_info` :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "0f8b4ca1-4205-4b71-941d-0852eebbe917",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "np.True_"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "np.all([Operator(twirled_qc).equiv(qc) for twirled_qc in twirled_qcs])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0d680854-13f8-4ccd-9be1-595edb4f942c",
      "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` invece di scrivere i propri passaggi, iniziare con l'argomento [Impostazioni predefinite e opzioni di configurazione di Transpilation](defaults-and-configuration-options).\n",
        "  * Prova la guida [Confronta le impostazioni del transpiler](/docs/guides/circuit-transpilation-settings).\n",
        "  * Consulta [la documentazione dell'API del transpiler](/docs/api/qiskit/transpiler).\n",
        "</Admonition>\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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}