{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "3e8391e9-be00-46b0-81a9-5474ae778663",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Teletrasporto quantistico\"\n",
        "description: \"Scopri come il teletrasporto quantistico trasferisce uno stato quantistico da un luogo all'altro utilizzando i principi dell'entanglement quantistico.\"\n",
        "---\n",
        "\n",
        "<span id=\"quantum-teleportation\" />\n",
        "\n",
        "# Teletrasporto quantistico\n",
        "\n",
        "Per questo modulo Qiskit in Classrooms, gli studenti devono avere un ambiente Python funzionante con i seguenti pacchetti installati:\n",
        "\n",
        "* `qiskit` v2.1.0 o più recente\n",
        "* `qiskit-ibm-runtime` v0.40.1 o più recente\n",
        "* `qiskit-aer` v0.17.0 o più recente\n",
        "* `qiskit.visualization`\n",
        "* `numpy`\n",
        "* `pylatexenc`\n",
        "\n",
        "Per configurare e installare i pacchetti di cui sopra, consultare la guida [Installare Qiskit](/docs/guides/install-qiskit).\n",
        "Per poter eseguire lavori su veri computer quantistici, gli studenti dovranno creare un account con IBM Quantum® seguendo i passaggi della guida [Set up your IBM Cloud account](/docs/guides/cloud-setup).\n",
        "\n",
        "Questo modulo è stato testato e ha utilizzato 14 secondi di tempo della QPU. Si tratta solo di una stima. L'utilizzo effettivo può variare.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0df1108e-f1ac-4e75-96c2-3d8b5992504e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Uncomment and modify this line as needed to install dependencies\n",
        "#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "404ed202-a761-4e82-a480-ce59d4b04adf",
      "metadata": {},
      "source": [
        "Guardate la presentazione del modulo da parte della dottoressa Katie McCormick qui sotto, oppure fate clic [qui](https://youtu.be/jxqnzltpDdE?si=UVL58hFOOWe2Q9qI) per guardarla su YouTube.\n",
        "\n",
        "***\n",
        "\n",
        "<IBMVideo id=\"134413680\" title=\"Katie McCormick demistifica il teletrasporto quantistico e ci guida attraverso alcuni esempi utilizzando Qiskit.\" />\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a200b899-0c56-4f69-a7ba-0ca4d83e47cd",
      "metadata": {},
      "source": [
        "<span id=\"introduction-and-background\" />\n",
        "\n",
        "## Introduzione e contesto\n",
        "\n",
        "Il teletrasporto quantistico è una tecnica della fisica quantistica che permette di trasferire informazioni quantistiche da un luogo all'altro senza spostare fisicamente le particelle. A differenza del concetto fantascientifico di teletrasporto, questo processo non comporta il trasporto di materia. Si basa invece sul principio dell'entanglement quantistico, secondo il quale due particelle diventano collegate indipendentemente dalla distanza. Attraverso una serie di misurazioni precise e comunicazioni classiche, lo stato quantistico di una particella può essere ricreato in un'altra particella in una posizione distante, \"teletrasportando\" di fatto l'informazione quantistica. In questo modulo vedremo come funziona matematicamente e poi implementeremo il teletrasporto quantistico su un vero computer quantistico. L'introduzione sarà breve; per maggiori informazioni sull'informazione quantistica e per maggiori spiegazioni sul teletrasporto, consigliamo il corso di John Watrous sui [Fondamenti dell'informazione quantistica](/learning/courses/basics-of-quantum-information), in particolare la sezione sul [Teletrasporto](/learning/courses/basics-of-quantum-information/entanglement-in-action/quantum-teleportation)\n",
        "\n",
        "I bit classici possono trovarsi negli stati 0 o 1. I bit quantistici (qubit) possono trovarsi in stati quantistici denominati $|0\\rangle$ e $|1\\rangle$ e anche in combinazioni lineari di questi stati, chiamate \"superposizioni\", come $|\\psi\\rangle = \\alpha_0|0\\rangle +\\alpha_1|1\\rangle$, con $\\alpha_0,\\alpha_1 \\in \\mathbb{C},$ e $|\\alpha_0|^2+|\\alpha_1|^2 = 1.$ Sebbene gli stati possano esistere in questa superposizione, una misurazione dello stato lo farà \"collassare\" negli stati $|0\\rangle$ o $|1\\rangle$. I parametri $a$ e $b$ sono correlati alla probabilità di ciascun risultato di misura secondo la formula\n",
        "\n",
        "$$\n",
        "P_0 = |\\alpha_0|^2\n",
        "$$\n",
        "\n",
        "$$\n",
        "P_1 = |\\alpha_1|^2\n",
        "$$\n",
        "\n",
        "Da qui il vincolo che $|\\alpha_0|^2+|\\alpha_1|^2 = 1.$\n",
        "\n",
        "Un'altra caratteristica fondamentale è che i bit quantistici possono essere \"aggrovigliati\", il che significa che la misurazione di un qubit può influenzare il risultato della misurazione di un altro qubit aggrovigliato. Capire come l'entanglement sia diverso dalle semplici correlazioni classiche è un po' complicato. Spieghiamo innanzitutto la nostra notazione. Chiamiamo due qubit appartenenti all'amico 0 (Alice) e all'amico 1 (Bob), e ciascuno nello stato $|0\\rangle$\n",
        "\n",
        "$$\n",
        "|0\\rangle_B|0\\rangle_A\n",
        "$$\n",
        "\n",
        "oppure\n",
        "\n",
        "$$\n",
        "|0\\rangle_1|0\\rangle_0\n",
        "$$\n",
        "\n",
        "a volte abbreviato semplicemente in\n",
        "\n",
        "$$\n",
        "|00\\rangle\n",
        "$$\n",
        "\n",
        "Si noti che il qubit con il numero più basso (o la lettera) è il più lontano a destra. Si tratta di una convenzione chiamata notazione \"little-endian\", utilizzata in tutto Qiskit.\n",
        "Se lo stato a due qubit degli amici è $|00\\rangle,$ ed essi misurano lo stato dei rispettivi qubit, troveranno ciascuno uno 0. Allo stesso modo, se i qubit si trovassero nello stato $|11\\rangle,$, ciascuna delle loro misurazioni darebbe un 1. Questo non è diverso dal caso classico. Tuttavia, nell'informatica quantistica, possiamo combinare questo aspetto con la superposizione per ottenere stati come\n",
        "\n",
        "$$\n",
        "\\frac{1}{\\sqrt{2}}(|00\\rangle+|11\\rangle)\n",
        "$$\n",
        "\n",
        "In uno stato come questo, se Alice e Bob hanno qubit nello stato 0 o 1 non è ancora noto, nemmeno determinato dalla natura, eppure sappiamo che misureranno lo stesso stato per il loro qubit. Per esempio, se Bob misura che il suo qubit si trova nello stato $|0\\rangle,$, questo può avvenire solo se la misura ha fatto collassare lo stato a due qubit in uno dei due stati possibili, in particolare in $|00\\rangle.$. Ciò lascia il qubit di Alice nello stato $|0\\rangle$.\n",
        "\n",
        "L'entangled dei qubit in questo modo non richiede che i qubit rimangano fisicamente vicini l'uno all'altro. In altre parole, potremmo agganciare i qubit, poi separarli da una grande distanza e usare il loro entanglement per inviare informazioni. Uno stato entangled come quello sopra descritto è un'unità di base dell'entanglement ed è talvolta indicato come un \"e-bit\", un singolo bit di entanglement. Questi e-bit possono essere considerati come risorse nella comunicazione quantistica, poiché ogni e-bit condiviso tra partner distanti può essere utilizzato, come illustriamo qui, per spostare informazioni da una posizione all'altra.\n",
        "\n",
        "Il primo pensiero di molte persone che ne vengono a conoscenza per la prima volta riguarda la violazione della relatività: possiamo usarla per inviare informazioni più veloci della luce? Continuate pure a mettere in discussione e a sondare le regole scientifiche, ma purtroppo questo non ci permetterà di inviare informazioni più veloci della luce, per ragioni che diventeranno chiare nel corso di questo modulo. Spoiler: incredibilmente NON è dovuto alla velocità di propagazione del collasso, che sembra avvenire più velocemente della luce [\\[1\\]](https://www.nature.com/articles/nature15759).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4ce474e6-cea7-4327-9742-9e1a7dd468b0",
      "metadata": {},
      "source": [
        "Iniziamo con due collaboratori, Alice e Bob, che inizialmente si trovano nello stesso luogo e possono lavorare insieme sugli stessi qubit. Questi collaboratori agganciano i loro qubit. Poi si allontaneranno in due luoghi geografici diversi, portando con sé i rispettivi qubit. Alice otterrà quindi informazioni quantistiche su un nuovo qubit Q. Non facciamo ipotesi sulle informazioni relative a Q. Lo stato di Q potrebbe essere un segreto sconosciuto ad Alice; potrebbe essere sconosciuto a tutte le persone. Ma ad Alice viene affidato il compito di trasferire le informazioni su Q a Bob. Lo farà utilizzando il teletrasporto quantistico.\n",
        "\n",
        "Per farlo, dovremo conoscere alcune operazioni quantistiche o \"porte\".\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "03fe38b1-66fe-4c50-8403-d8c64197b5c6",
      "metadata": {},
      "source": [
        "<span id=\"quantum-operators-gates\" />\n",
        "\n",
        "## Operatori quantistici (porte)\n",
        "\n",
        "Se avete già familiarità con le porte quantiche, potete saltare questa sezione. Se volete capire meglio queste porte, date un'occhiata a [Fondamenti dell'informazione quantistica](/learning/courses/basics-of-quantum-information), in particolare alle prime due lezioni, su IBM Quantum Learning.\n",
        "\n",
        "Per questo protocollo di teletrasporto utilizzeremo principalmente due tipi di porte quantistiche: la porta di Hadamard e la porta CNOT. Alcuni altri avranno un ruolo minore: il gate $X$, il gate $Z$ e il gate SWAP.\n",
        "\n",
        "Questo modulo può essere completato con una preparazione molto limitata in algebra lineare, ma a volte può essere utile visualizzare le porte della meccanica quantistica utilizzando matrici e vettori. Presentiamo quindi anche le forme matriciali/vettoriali delle porte/stati quantistici.\n",
        "\n",
        "Gli stati che abbiamo già presentato sono stati scelti (in parte per convenzione e in parte per vincoli) per avere forme vettoriali:\n",
        "\n",
        "$$\n",
        "|0\\rangle = \\begin{pmatrix}1 \\\\ 0\\end{pmatrix}\n",
        "$$\n",
        "\n",
        "$$\n",
        "|1\\rangle = \\begin{pmatrix}0 \\\\ 1\\end{pmatrix}\n",
        "$$\n",
        "\n",
        "In questo modo, uno stato arbitrario $|\\psi\\rangle = a|0\\rangle+b|1\\rangle$ può essere scritto come\n",
        "\n",
        "$$\n",
        "|\\psi\\rangle =\\begin{pmatrix}a \\\\ b\\end{pmatrix}\n",
        "$$\n",
        "\n",
        "È possibile scegliere come estendere la notazione agli stati a qubit multipli, ma la scelta che segue è abbastanza standard:\n",
        "\n",
        "$$\n",
        "|00\\rangle = \\begin{pmatrix}1 \\\\ 0 \\\\ 0 \\\\ 0\\end{pmatrix},|01\\rangle = \\begin{pmatrix}0 \\\\ 1 \\\\ 0 \\\\ 0\\end{pmatrix},\n",
        "|10\\rangle = \\begin{pmatrix}0 \\\\ 0 \\\\ 1 \\\\0\\end{pmatrix},|11\\rangle = \\begin{pmatrix}0 \\\\ 0 \\\\ 0 \\\\ 1\\end{pmatrix}.\n",
        "$$\n",
        "\n",
        "Tenendo presente questa scelta di notazione vettoriale, possiamo introdurre le porte quantistiche necessarie, i loro effetti sugli stati quantistici e le loro forme matriciali.\n",
        "\n",
        "**H Porta di Hadamard:** Crea uno stato di sovrapposizione. Cancello a singolo qubit.\n",
        "\n",
        "$$\n",
        "H|0\\rangle = \\frac{1}{\\sqrt{2}}\\left(|0\\rangle+|1\\rangle\\right),\n",
        "$$\n",
        "\n",
        "$$\n",
        "H|1\\rangle = \\frac{1}{\\sqrt{2}}\\left(|0\\rangle-|1\\rangle\\right)\n",
        "$$\n",
        "\n",
        "$$\n",
        "H=\\frac{1}{\\sqrt{2}}\\begin{pmatrix} 1 & 1 \\\\ 1 & -1 \\end{pmatrix}\n",
        "$$\n",
        "\n",
        "Un circuito con una porta di Hadamard è realizzato come segue:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "a66b8ef2-6660-45b8-97bd-dbc98db49857",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/quantum-teleportation/extracted-outputs/a66b8ef2-6660-45b8-97bd-dbc98db49857-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "\n",
        "qc = QuantumCircuit(1)\n",
        "qc.h(0)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "19b06d0f-0811-48aa-bf5d-a575f7b63876",
      "metadata": {},
      "source": [
        "**Gate CNOT Controlled-NOT:** questo gate utilizza due qubit: uno di controllo e uno di destinazione. Controlla lo stato di un qubit di controllo che non viene modificato. Ma se il qubit di controllo si trova nello stato $|1\\rangle$, il gate cambia lo stato del qubit di destinazione; se lo stato del qubit di controllo è $|0\\rangle$ non viene effettuato alcun cambiamento. Nella notazione che segue, si assume che il qubit $A$ (il qubit più a destra) sia il controllo e il qubit $B$ (il qubit più a sinistra) sia il bersaglio. Di seguito, la notazione utilizzata è $CNOT(q_{control},q_{target})|BA\\rangle.$\n",
        "\n",
        "$$\n",
        "CNOT(A,B)|00\\rangle = |00\\rangle, \\\\ CNOT(A,B)|01\\rangle = |11\\rangle, \\\\ CNOT(A,B)|10\\rangle = |10\\rangle, \\\\ CNOT(A,B)|11\\rangle = |01\\rangle\n",
        "$$\n",
        "\n",
        "A volte si può vedere scritto CNOT con l'ordine del controllo e del target semplicemente sottinteso. Ma non c'è questa ambiguità nel codice o negli schemi dei circuiti.\n",
        "\n",
        "$$\n",
        "CNOT=\\begin{pmatrix} 1 & 0 & 0 & 0 \\\\ 0 & 0 & 0 & 1 \\\\ 0 & 0 & 1 & 0 \\\\ 0 & 1 & 0 & 0\\end{pmatrix}\n",
        "$$\n",
        "\n",
        "Un gate CNOT ha un aspetto un po' diverso in un circuito, poiché richiede due qubit. Ecco come viene implementato:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "df5acfc1-feb8-4008-8e51-d9709352edde",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/quantum-teleportation/extracted-outputs/df5acfc1-feb8-4008-8e51-d9709352edde-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(2)\n",
        "qc.cx(0, 1)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "131d90c7-6ef3-4c32-a01b-52da9f8e0e83",
      "metadata": {},
      "source": [
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifica la tua comprensione\n",
        "\n",
        "La maggior parte dei gate ha la stessa forma a matrice in Qiskit come in tutti gli altri contesti. Ma la porta CNOT agisce su due qubit, e così improvvisamente le convenzioni di ordinamento dei qubit diventano un problema. I testi che trattano i qubit $|q_0,q_1,...\\rangle$ presentano una forma matriciale diversa per i loro porte CNOT. Verificare, mediante una moltiplicazione esplicita delle matrici, che la matrice CNOT sopra riportata abbia l'azione corretta sullo stato $|01\\rangle.$\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Risposta\">\n",
        "    $CNOT|01\\rangle =\\begin{pmatrix} 1 & 0 & 0 & 0 \\\\ 0 & 0 & 0 & 1 \\\\ 0 & 0 & 1 & 0 \\\\ 0 & 1 & 0 & 0\\end{pmatrix}\\begin{pmatrix}0 \\\\ 1 \\\\ 0 \\\\0\\end{pmatrix} = \\begin{pmatrix}0 \\\\ 0 \\\\ 0 \\\\1\\end{pmatrix} = |11\\rangle$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2c1a61f3-770a-443e-8e01-26fc1106f92b",
      "metadata": {},
      "source": [
        "**$X$ Gate** : equivalente a un'operazione NOT. Cancello a singolo qubit.\n",
        "\n",
        "$$\n",
        "X|0\\rangle = |1\\rangle,\\\\X|1\\rangle=|0\\rangle\n",
        "$$\n",
        "\n",
        "$$\n",
        "X=\\begin{pmatrix} 0 & 1 \\\\ 1 & 0 \\end{pmatrix}\n",
        "$$\n",
        "\n",
        "In Qiskit, la creazione di un circuito con una porta $X$ si presenta come segue:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "5a23a576-385b-4a7c-899d-67ef4bb0bfed",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/quantum-teleportation/extracted-outputs/5a23a576-385b-4a7c-899d-67ef4bb0bfed-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(1)\n",
        "qc.x(0)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "81eaa9dc-740a-4a99-8950-fc7724c6440b",
      "metadata": {},
      "source": [
        "**$Z$ Cancello** : Aggiunge una \"fase\" a uno stato (un prefattore, che nel caso degli autostati Z $|0\\rangle$ e $|1\\rangle$ è rispettivamente un 1 o -1 ). Cancello a singolo qubit.\n",
        "\n",
        "$$\n",
        "Z|0\\rangle = |0\\rangle,\\\\Z|1\\rangle=-|1\\rangle\n",
        "$$\n",
        "\n",
        "$$\n",
        "Z=\\begin{pmatrix} 1 & 0 \\\\ 0 & -1 \\end{pmatrix}\n",
        "$$\n",
        "\n",
        "In Qiskit, la creazione di un circuito con una porta $Z$ si presenta come segue:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "653b2420-eaa8-41ef-8262-3a9efa638cd3",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/quantum-teleportation/extracted-outputs/653b2420-eaa8-41ef-8262-3a9efa638cd3-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(1)\n",
        "qc.z(0)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "476c82d2-4c58-4c25-8f0d-646cd4afb757",
      "metadata": {},
      "source": [
        "<span id=\"theory\" />\n",
        "\n",
        "## Teoria\n",
        "\n",
        "Illustriamo il protocollo per il teletrasporto quantistico usando la matematica. Poi, nella prossima sezione, realizzeremo questa configurazione utilizzando un computer quantistico.\n",
        "\n",
        "**Alice e Bob agganciano i loro qubit:** Inizialmente, il qubit di Alice e il qubit di Bob sono ciascuno, separatamente, nello stato $|0\\rangle$ (un'ipotesi corretta e anche l'inizializzazione corretta per i computer quantistici di IBM® ). Possiamo scriverlo come $|0\\rangle_B|0\\rangle_A$ o semplicemente come $|00\\rangle$. Calcoliamo cosa succede quando Alice e Bob agiscono con il gate di Hadamard sul qubit di Alice e poi con un gate CNOT con il qubit di Alice come controllo e quello di Bob come bersaglio:\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "CNOT(A,B)H_A |0\\rangle_B|0\\rangle_A &= CNOT(A,B)|0\\rangle_B\\frac{1}{\\sqrt{2}}\\left(|0\\rangle_A+|1\\rangle_A\\right)\\\\\n",
        "&=\\frac{1}{\\sqrt{2}}\\left(CNOT(A,B)|0\\rangle_B|0\\rangle_A+CNOT(A,B)|0\\rangle_B|1\\rangle_A\\right)\\\\\n",
        "&=\\frac{1}{\\sqrt{2}}\\left(|0\\rangle_B|0\\rangle_A+|1\\rangle_B|1\\rangle_A\\right)\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "Si noti che ora i qubit di Alice e Bob sono entangled. Sebbene non sia ancora determinato dalla natura se entrambi i loro qubit si trovino nello stato $|0\\rangle$ o nello stato $|1\\rangle$, è noto che i loro qubit si trovano nello stesso stato.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b51aed85-2976-4c46-a1d8-07dba8af78fe",
      "metadata": {},
      "source": [
        "**Alice e Bob si separano:** I due amici spostano i loro qubit in nuove posizioni, possibilmente molto distanti tra loro. Ciò comporta molte avvertenze: non è banale spostare l'informazione quantistica senza disturbarla. Ma può essere spostata, e infatti la sposterete in questo modulo. Ma teniamo presente che ci aspettiamo di incontrare alcuni errori quando spostiamo molto le informazioni quantistiche.\n",
        "\n",
        "**Q viene introdotto:** Lo stato segreto viene preparato sul qubit Q:\n",
        "\n",
        "$$\n",
        "|\\psi\\rangle_Q = \\alpha_0 |0\\rangle_Q + \\alpha_1 |1\\rangle_Q\n",
        "$$\n",
        "\n",
        "A questo punto Q è semplicemente adiacente al qubit di Alice (A). Non c'è stato entanglement, quindi lo stato quantistico dei tre qubit insieme può essere scritto come:\n",
        "\n",
        "$$\n",
        "|\\psi\\rangle_{AB}|\\psi\\rangle_Q = \\frac{1}{\\sqrt{2}}\\left(|0\\rangle_B|0\\rangle_A+|1\\rangle_B|1\\rangle_A\\right)\\left(\\alpha_0 |0\\rangle_Q + \\alpha_1 |1\\rangle_Q\\right).\n",
        "$$\n",
        "\n",
        "L'obiettivo è spostare le informazioni su Q dalla posizione di Alice a quella di Bob. A questo punto, non abbiamo alcuna pretesa o requisito di segretezza o velocità di trasferimento delle informazioni. Stiamo semplicemente esplorando il modo in cui le informazioni possono passare da Alice a Bob.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cd8f8dab-601f-42b6-8b1e-027568f8726c",
      "metadata": {},
      "source": [
        "Poiché le informazioni iniziano da Q, assumeremo che a Q sia assegnato il numero più basso tra i qubit, in modo che la notazione little endian faccia sì che Q sia il qubit più a destra nella matematica che segue.\n",
        "\n",
        "**Alice aggancia i qubit A e Q:** ora Alice opera con una porta CNOT con il proprio qubit come controllo e Q come bersaglio, quindi applica una porta Hadamard a Q.  Calcoliamo lo stato a tre qubit dopo questa operazione:\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "H_Q CNOT(A,Q)|\\psi\\rangle_{AB}|\\psi\\rangle_Q &= H_Q CNOT(A,Q)\\frac{1}{\\sqrt{2}}\\left(|0\\rangle_B|0\\rangle_A+|1\\rangle_B|1\\rangle_A\\right)\\left(\\alpha_0 |0\\rangle_Q + \\alpha_1 |1\\rangle_Q\\right)\\\\\n",
        "&= H_Q CNOT(A,Q)\\frac{1}{\\sqrt{2}}\\left(\\left(\\alpha_0 |0\\rangle_B|0\\rangle_A|0\\rangle_Q + \\alpha_1 |0\\rangle_B|0\\rangle_A|1\\rangle_Q\\right)+\\left(\\alpha_0 |1\\rangle_B|1\\rangle_A|0\\rangle_Q + \\alpha_1 |1\\rangle_B|1\\rangle_A|1\\rangle_Q\\right)\\right)\\\\\n",
        "&= H_Q \\frac{1}{\\sqrt{2}}\\left(\\alpha_0 |0\\rangle_B|0\\rangle_A|0\\rangle_Q + \\alpha_1 |0\\rangle_B|1\\rangle_A|1\\rangle_Q+\\alpha_0 |1\\rangle_B|1\\rangle_A|0\\rangle_Q + \\alpha_1 |1\\rangle_B|0\\rangle_A|1\\rangle_Q\\right)\\\\\n",
        "&= \\frac{1}{2}\\left(\\alpha_0 |0\\rangle_B|0\\rangle_A|0\\rangle_Q + \\alpha_0 |0\\rangle_B|0\\rangle_A|1\\rangle_Q + \\alpha_1 |0\\rangle_B|1\\rangle_A|0\\rangle_Q-\\alpha_1 |0\\rangle_B|1\\rangle_A|1\\rangle_Q\\right)\\\\\n",
        "&+\\frac{1}{2}\\left(\\alpha_0 |1\\rangle_B|1\\rangle_A|0\\rangle_Q + \\alpha_0 |1\\rangle_B|1\\rangle_A|1\\rangle_Q + \\alpha_1 |1\\rangle_B|0\\rangle_A|0\\rangle_Q - \\alpha_1 |1\\rangle_B|0\\rangle_A|1\\rangle_Q\\right)\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "78aaf4c7-2775-483e-91cd-11d400793776",
      "metadata": {},
      "source": [
        "Poiché A e Q si trovano nella stessa posizione, raggruppiamo i termini di cui sopra in base ai risultati delle misurazioni sui qubit A e Q:\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "|\\psi\\rangle = \\frac{1}{2}\\left((\\alpha_0 |0\\rangle_B+\\alpha_1 |1\\rangle_B)|0\\rangle_A|0\\rangle_Q +  (\\alpha_0 |0\\rangle_B-\\alpha_1 |1\\rangle_B)|0\\rangle_A|1\\rangle_Q + (\\alpha_1 |0\\rangle_B+\\alpha_0 |1\\rangle_B)|1\\rangle_A|0\\rangle_Q+ (-\\alpha_1 |0\\rangle_B+\\alpha_0 |1\\rangle_B)|1\\rangle_A|1\\rangle_Q \\right)\\\\\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifica la tua comprensione\n",
        "\n",
        "Data l'espressione sopra riportata relativa agli stati di tutti e tre i qubit, qual è la probabilità che una misurazione dei qubit A e Q dia come risultato un $|0\\rangle_A|0\\rangle_Q?$\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Risposta\">\n",
        "    25%. Per capire questo, ricordiamo che lo stato di Bob deve essere normalizzato, quindi $ |_A \\langle0|_Q\\langle0| \\frac{1}{2} |0\\rangle_A|0\\rangle_Q (\\alpha_0 |0\\rangle_B+\\alpha_1 |1\\rangle_B)|^2 = \\frac{1}{4}|(\\alpha_0 |0\\rangle_B+\\alpha_1 |1\\rangle_B)|^2 = \\frac{1}{4}$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8df3034b-9807-487b-a046-e689061cb026",
      "metadata": {},
      "source": [
        "Ora, Alice può misurare i qubit A e Q. Non può controllare l'esito della misurazione, poiché le misure quantistiche sono probabilistiche. Quindi, quando misura, ci sono 4 risultati possibili e tutti e 4 sono ugualmente probabili: $|0\\rangle_A|0\\rangle_Q,$ $|0\\rangle_A|1\\rangle_Q,$ $|1\\rangle_A|0\\rangle_Q,$ e $|1\\rangle_A|1\\rangle_Q.$ Si noti che ogni risultato ha implicazioni diverse per il qubit di Bob. Ad esempio, se Alice trova i suoi qubit in $|0\\rangle_A|0\\rangle_Q,$, l'intero stato quantistico a 3 qubit è collassato in $(\\alpha_0|0\\rangle_B+\\alpha_1|1\\rangle_B)|0\\rangle_A|0\\rangle_Q.$. Altri risultati di misurazione per Alice producono stati diversi per Bob. Questi sono raccolti nella tabella seguente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "99e01c8f-e6e1-4679-8e48-1e33a1b78e63",
      "metadata": {},
      "source": [
        "| Risultato di Alice                   | Stato di Bob                                         | Istruzioni a Bob | Risultato                                           |\n",
        "| ------------------------------------ | ---------------------------------------------------- | ---------------- | --------------------------------------------------- |\n",
        "| $ \\vert 0\\rangle_A \\vert 0\\rangle_Q$ | $\\alpha_0\\vert 0\\rangle_B+\\alpha_1\\vert 1\\rangle_B$  | Nessuna          | $\\alpha_0\\vert 0\\rangle_B+\\alpha_1\\vert 1\\rangle_B$ |\n",
        "| $ \\vert 0\\rangle_A \\vert 1\\rangle_Q$ | $\\alpha_0\\vert 0\\rangle_B-\\alpha_1\\vert 1\\rangle_B$  | $Z$              | $\\alpha_0\\vert 0\\rangle_B+\\alpha_1\\vert 1\\rangle_B$ |\n",
        "| $ \\vert 1\\rangle_A \\vert 0\\rangle_Q$ | $\\alpha_1\\vert 0\\rangle_B+\\alpha_0\\vert 1\\rangle_B$  | $X$              | $\\alpha_0\\vert 0\\rangle_B+\\alpha_1\\vert 1\\rangle_B$ |\n",
        "| $ \\vert 1\\rangle_A \\vert 1\\rangle_Q$ | $-\\alpha_1\\vert 0\\rangle_B+\\alpha_0\\vert 1\\rangle_B$ | $X$ allora $Z$   | $\\alpha_0\\vert 0\\rangle_B+\\alpha_1\\vert 1\\rangle_B$ |\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ff32d084-31ea-4408-b3cb-b5bebb845a3b",
      "metadata": {},
      "source": [
        "Per tutti i possibili risultati delle misurazioni sui qubit di Alice, il qubit di Bob rimane in uno stato che assomiglia vagamente allo stato segreto originariamente presente su Q. Nel caso in cui Alice misuri $|0\\rangle_C|0\\rangle_A$ (la prima riga della tabella), il qubit di Bob viene lasciato esattamente nello stato segreto! Negli altri casi, c'è qualcosa di strano nello Stato. I coefficienti ( $\\alpha$ 's) sono scambiati, oppure c'è un segno \"-\" dove dovrebbe esserci un segno \"+\", o entrambi. Per modificare il qubit di Bob e renderlo esattamente uguale allo stato segreto, Alice deve chiamare Bob (utilizzando un mezzo di comunicazione classico) e dire a Bob di eseguire operazioni aggiuntive sul suo qubit, come indicato nella tabella. Ad esempio, nella terza riga i coefficienti sono scambiati. Se Alice chiama Bob e gli dice di applicare un gate $X$ al suo qubit, questo cambia un $|0\\rangle$ in un $|1\\rangle$ e viceversa, e viene fuori lo stato segreto.\n",
        "\n",
        "Ora dovrebbe essere chiaro perché non possiamo usare questa configurazione per inviare informazioni più veloci della luce. Potremmo essere fortunati e misurare $|0\\rangle_A|0\\rangle_Q,$, il che significa che Bob ha esattamente lo stato segreto, all'istante. Ma Bob non lo sa finché non lo chiamiamo e gli diciamo: \"Abbiamo misurato $|0\\rangle_A|0\\rangle_Q$, quindi non devi fare nulla\"\n",
        "\n",
        "Nell'esperimento di pensiero, i qubit vengono spesso separati fisicamente e portati in una nuova posizione. IBM® i computer quantistici utilizzano qubit a stato solido su un chip che non possono essere separati. Quindi, invece di spostare Alice e Bob in luoghi diversi, separeremo le informazioni sul chip stesso utilizzando i cosiddetti \"swap gate\" per spostare le informazioni da un qubit all'altro.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "efa0afed-97e7-42fd-a06d-7c095e703537",
      "metadata": {},
      "source": [
        "<span id=\"experiment-1-basic-teleportation\" />\n",
        "\n",
        "## Esperimento 1: Teletrasporto di base\n",
        "\n",
        "IBM Quantum raccomanda di affrontare i problemi di calcolo quantistico utilizzando un quadro che chiamiamo \"modelli Qiskit\". Si compone delle seguenti fasi.\n",
        "\n",
        "* Fase 1: mappare il problema in un circuito quantistico\n",
        "* Fase 2: Ottimizzazione del circuito per l'esecuzione su hardware quantistico reale\n",
        "* Fase 3: Eseguire il proprio processo sui computer quantistici dell' IBM utilizzando le primitive dell' IBM Quantum\n",
        "* Fase 4: Postelaborazione dei risultati\n",
        "\n",
        "<span id=\"step-1-map-your-problem-to-a-quantum-circuit\" />\n",
        "\n",
        "### Passaggio 1: mappa il tuo problema su un circuito quantistico\n",
        "\n",
        "Tutti i calcoli che abbiamo fatto in precedenza erano per delineare il passo 1. Lo implementeremo ora, costruendo il nostro circuito quantistico con Qiskit! Iniziamo a creare un circuito quantistico con tre qubit e ad agganciare i due qubit di Alice e Bob. Questi saranno i qubit 1 e 2, mentre il qubit 0 sarà riservato allo stato segreto.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "6e3e0d07-b52f-4e17-9233-0a00065f2d77",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/quantum-teleportation/extracted-outputs/6e3e0d07-b52f-4e17-9233-0a00065f2d77-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Step 1: Map your problem to a quantum circuit\n",
        "\n",
        "# Import some general packages\n",
        "from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister\n",
        "import numpy as np\n",
        "\n",
        "# Define registers\n",
        "secret = QuantumRegister(1, \"Q\")\n",
        "Alice = QuantumRegister(1, \"A\")\n",
        "Bob = QuantumRegister(1, \"B\")\n",
        "\n",
        "cr = ClassicalRegister(3, \"c\")\n",
        "\n",
        "qc = QuantumCircuit(secret, Alice, Bob, cr)\n",
        "\n",
        "# We entangle Alice's and Bob's qubits as in our work above.\n",
        "# We apply a Hadamard gate and then a CNOT gate.\n",
        "# Note that the second argument in the CNOT gate is the target.\n",
        "qc.h(Alice)\n",
        "qc.cx(Alice, Bob)\n",
        "\n",
        "# Inserting a barrier changes nothing about the logic. It just allows us to\n",
        "# force gates to be positioned in \"layers\".\n",
        "qc.barrier()\n",
        "\n",
        "# Now we will use random variables to create the secret state.\n",
        "# Don't worry about the \"u\" gate and the details.\n",
        "np.random.seed(42)  # fixing seed for repeatability\n",
        "theta = np.random.uniform(0.0, 1.0) * np.pi  # from 0 to pi\n",
        "varphi = np.random.uniform(0.0, 2.0) * np.pi  # from 0 to 2*pi\n",
        "\n",
        "# Assign the secret state to the qubit on the other side of Alice's (qubit 0), labeled Q\n",
        "qc.u(theta, varphi, 0.0, secret)\n",
        "qc.barrier()\n",
        "\n",
        "# Now entangle Q and Alice's qubits as in the discussion above.\n",
        "qc.cx(secret, Alice)\n",
        "qc.h(secret)\n",
        "qc.barrier()\n",
        "\n",
        "# Now Alice measures her qubits, and stores the outcomes in the \"classical registers\" cr[]\n",
        "qc.measure(Alice, cr[1])\n",
        "qc.measure(secret, cr[0])\n",
        "\n",
        "# Now we insert some conditional logic. If Alice measures Q in a \"1\" we need a Z gate, and if Alice\n",
        "# measures A in a \"1\" we need an X gate (see the table).\n",
        "with qc.if_test((cr[1], 1)):\n",
        "    qc.x(Bob)\n",
        "with qc.if_test((cr[0], 1)):\n",
        "    qc.z(Bob)\n",
        "\n",
        "qc.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2802dfbf-e3cb-4bd8-80cd-83ec972c7bd9",
      "metadata": {},
      "source": [
        "Questo è tutto ciò che dobbiamo fare per far teletrasportare lo stato di Alice a Bob. Tuttavia, ricordiamo che quando misuriamo uno stato quantistico $\\alpha_0 |0\\rangle+\\alpha_1|1\\rangle$ troviamo o $|0\\rangle$ o $|1\\rangle.$ Quindi, alla fine di tutto questo, Bob ha sicuramente lo stato segreto di Alice, ma non possiamo verificarlo facilmente con una misurazione. Affinché una misurazione ci dica che abbiamo fatto questo correttamente, dobbiamo fare un trucco. Avevamo un operatore contrassegnato con \"U\" per \"unitario\", che abbiamo usato per preparare lo stato segreto di Alice. Possiamo applicare l'inverso di U alla fine del nostro circuito. Se U ha mappato lo stato $|0\\rangle$ di Alice in $\\alpha_0 |0\\rangle+\\alpha_1|1\\rangle$, allora l'inverso di U mapperà lo stato $\\alpha_0 |0\\rangle+\\alpha_1|1\\rangle$ di Bob in $|0\\rangle.$ Quest'ultima parte non verrebbe necessariamente eseguita se l'obiettivo fosse solo quello di spostare informazioni quantistiche. Questo viene fatto solo per controllare noi stessi.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "dac9d281-6c57-4e70-9a61-74efa5d4bdc2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/quantum-teleportation/extracted-outputs/dac9d281-6c57-4e70-9a61-74efa5d4bdc2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Add the inverse of U and measure Bob's qubit.\n",
        "qc.barrier()\n",
        "\n",
        "qc.u(theta, varphi, 0.0, Bob).inverse()  # inverse of u(theta,varphi,0.0)\n",
        "qc.measure(Bob, cr[2])  # add measurement gate\n",
        "\n",
        "qc.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bd6643de-e67f-44f6-b83d-d7ea9f314eb8",
      "metadata": {},
      "source": [
        "Quindi, se abbiamo fatto questo correttamente, la nostra misura sul qubit di Bob dovrebbe produrre uno stato $|0\\rangle$. Naturalmente, queste misure sono probabilistiche. Quindi, se c'è anche solo una piccola possibilità di misurare il qubit di Bob nello stato $|1\\rangle$, allora una singola misurazione potrebbe risultare in $|1\\rangle.$ Vorremmo davvero effettuare molte misurazioni per essere certi che la probabilità di $|0\\rangle$ sia piuttosto alta.\n",
        "\n",
        "<span id=\"step-2-optimize-problem-for-quantum-execution\" />\n",
        "\n",
        "### Fase 2: Ottimizzazione del problema per l'esecuzione quantistica\n",
        "\n",
        "Questa fase prende le operazioni che vogliamo eseguire e le esprime in termini di funzionalità di uno specifico computer quantistico. Inoltre, il nostro problema è stato tracciato sul layout del computer quantistico.\n",
        "\n",
        "Inizieremo caricando diversi pacchetti che sono necessari per comunicare con i computer quantistici di IBM. Dobbiamo anche selezionare un backend su cui eseguire l'operazione. Possiamo scegliere il backend meno trafficato, oppure selezionare un backend specifico di cui conosciamo le proprietà.\n",
        "\n",
        "Di seguito è riportato un codice per salvare le credenziali al primo utilizzo. Assicurarsi di eliminare queste informazioni dal blocco note dopo averlo salvato nel proprio ambiente, in modo che le credenziali non vengano accidentalmente condivise quando si condivide il blocco note. Per ulteriori informazioni, vedere [Configurazione dell'account IBM Cloud](/docs/guides/initialize-account) e [Inizializzazione del servizio in un ambiente non attendibile](/docs/guides/cloud-setup-untrusted).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8f24b6b9-db1b-4077-8660-e355e377807e",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "ibm_sherbrooke\n"
          ]
        }
      ],
      "source": [
        "# Load IBM Quantum Compute Service\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "\n",
        "# Load IBM Quantum Compute Service\n",
        "\n",
        "# Syntax for first saving your token.  Delete these lines after saving your credentials.\n",
        "# QiskitRuntimeService.save_account(channel='ibm_quantum_platform',\n",
        "# instance = '<YOUR_IBM_INSTANCE_CRN>', token='<YOUR-API_KEY>', overwrite=True, set_as_default=True)\n",
        "# service = QiskitRuntimeService(channel='ibm_quantum_platform')\n",
        "\n",
        "# Load saved credentials\n",
        "service = QiskitRuntimeService()\n",
        "\n",
        "# Use the least busy backend, or uncomment the loading of a specific backend like \"ibm_brisbane\".\n",
        "backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)\n",
        "# backend = service.backend(\"ibm_brisbane\")\n",
        "print(backend.name)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "35bb9c51-a573-4363-89ed-2159aaa1976f",
      "metadata": {},
      "source": [
        "Abilitiamo esplicitamente la logica sulle misure.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "e238e397-33f2-4fa1-99b1-94c78dd966f1",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.circuit import IfElseOp\n",
        "\n",
        "backend.target.add_instruction(IfElseOp, name=\"if_else\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6074a3b9-54c3-4c52-90ee-f308bd96de76",
      "metadata": {},
      "source": [
        "Ora dobbiamo \"transpilare\" il circuito quantistico. Si tratta di un argomento affascinante che coinvolge molte fasi secondarie. Solo per fare un esempio di un sottofase: non tutti i computer quantistici possono implementare direttamente tutte le porte logiche di Qiskit. Dobbiamo scrivere le porte del nostro circuito in termini di porte che il computer quantistico può implementare. Possiamo eseguire questo processo, e altri, utilizzando un gestore di pass preimpostati. L'impostazione di `optimization = 3` (il livello più alto di ottimizzazione) garantisce che la mappatura dal nostro circuito quantistico astratto alle istruzioni fornite al computer quantistico sia la più efficiente possibile, grazie alla nostra pre-elaborazione.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "c533d4a7-c53c-4048-bf99-46e06ad9cb95",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Step 2: Transpile\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "qc_isa = pm.run(qc)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "85f3e53c-f910-4427-a977-f6e24798542c",
      "metadata": {},
      "source": [
        "Un \"Sampler\" è una primitiva progettata per campionare i possibili stati risultanti da un circuito quantistico e raccogliere dati statistici su quali stati potrebbero essere misurati e con quale probabilità. Qui importiamo il codice di esempio \" IBM Quantum \":\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "d3292506-1486-48cd-bf1e-696135572eab",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Load the Runtime primitive and session\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
        "\n",
        "sampler = Sampler(mode=backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5ea27bf8-2dbf-4d68-8375-e40e89b71341",
      "metadata": {},
      "source": [
        "Non tutti i calcoli di un computer quantistico possono essere ragionevolmente simulati su computer classici. Questo semplice teletrasporto può sicuramente esserlo, ma non è affatto sorprendente che possiamo classicamente salvare le informazioni in un luogo o in un altro. Si consiglia vivamente di eseguire questi calcoli utilizzando un vero computer quantistico IBM. Ma nel caso in cui abbiate esaurito il vostro utilizzo mensile gratuito, o se dovete completare qualcosa in classe e non potete aspettare in coda, questo modulo può essere completato utilizzando un simulatore. A tale scopo, è sufficiente eseguire la cella sottostante e decommentare le righe associate nei passaggi \"Esegui\".\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2332b984-cff6-4022-b7fa-f100d35a2719",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Load the backend sampler\n",
        "from qiskit.primitives import BackendSamplerV2\n",
        "\n",
        "# Load the Aer simulator and generate a noise model based on the currently-selected backend.\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_aer.noise import NoiseModel\n",
        "\n",
        "\n",
        "noise_model = NoiseModel.from_backend(backend)\n",
        "\n",
        "# Define a simulator using Aer, and use it in Sampler.\n",
        "backend_sim = AerSimulator(noise_model=noise_model)\n",
        "sampler_sim = BackendSamplerV2(backend=backend_sim)\n",
        "\n",
        "# Alternatively, load a fake backend with generic properties and define a simulator.\n",
        "# backend_gen = GenericBackendV2(num_qubits=18)\n",
        "# sampler_gen = BackendSamplerV2(backend=backend_gen)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bff5bb04-fc2d-45f4-ab26-98fe9a5a0b5c",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute\" />\n",
        "\n",
        "### Fase 3: Esecuzione\n",
        "\n",
        "Utilizzare il campionatore per eseguire il lavoro, con il circuito come argomento.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "cbf63f9a-5b93-4bbd-b527-f3892e2188bd",
      "metadata": {},
      "outputs": [],
      "source": [
        "job = sampler.run([qc_isa])\n",
        "# job = sampler_sim.run([qc_isa])\n",
        "res = job.result()\n",
        "counts = res[0].data.c.get_counts()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a6a68d85-486a-401a-8336-805713eafd57",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-processing-and-analysis\" />\n",
        "\n",
        "### Fase 4: Post-elaborazione e analisi\n",
        "\n",
        "Tracciamo i risultati e interpretiamoli.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "47488ddf-9357-41e4-a0fb-45616bee307c",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/quantum-teleportation/extracted-outputs/47488ddf-9357-41e4-a0fb-45616bee307c-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# This required 5 s to run on a Heron r2 processor on 10-28-24\n",
        "from qiskit.visualization import plot_histogram\n",
        "\n",
        "plot_histogram(counts)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "12dcb4f6-d105-41f0-8800-87f291ce1aeb",
      "metadata": {},
      "source": [
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifica la tua comprensione\n",
        "\n",
        "Quali degli stati sopra indicati indicano che il teletrasporto è andato a buon fine, e come si fa a capirlo?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Risposta\">\n",
        "    Gli stati $|000\\rangle,$ $|001\\rangle,$ $|010\\rangle,$ $|011\\rangle$ sono tutti coerenti con il successo del teletrasporto. Questo perché abbiamo aggiunto un cancello per annullare la preparazione iniziale dello stato segreto. Se lo stato segreto è stato teletrasportato con successo al qubit di Bob, quel gate aggiuntivo dovrebbe riportare il qubit di Bob allo stato $|0\\rangle$. Quindi qualsiasi stato superiore con il qubit di Bob (qubit 0, misurato anche sulla componente 0 del registro classico, e quindi il più alto/più a destra) nello stato $|0\\rangle$ indica un successo.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Questo grafico mostra tutti i risultati delle misure dei tre qubit, su 5.000 prove o \"scatti\". Abbiamo sottolineato in precedenza che Alice misurerebbe tutti i possibili stati dei qubit A e Q con la stessa probabilità. Abbiamo assegnato i qubit 0-2 del circuito a Q, A e B, in quest'ordine. In notazione little-endian, il qubit di Bob è il più a sinistra/il più basso. Quindi le quattro barre a sinistra corrispondono al fatto che il qubit di Bob è $|0\\rangle$ e gli altri due qubit sono in tutte le combinazioni possibili con una probabilità approssimativamente uguale. Si noti che quasi tutte le misurazioni (di solito ´95%) danno il qubit di Bob nello stato $|0\\rangle$, il che significa che la nostra configurazione ha avuto successo! Ci sono una manciata di scatti (\\~5%) che hanno prodotto il qubit di Bob nello stato $|1\\rangle$. Questo non dovrebbe essere logicamente possibile. Tuttavia, tutti i moderni computer quantistici soffrono di rumore ed errori in misura molto maggiore rispetto ai computer classici. E la correzione quantistica degli errori è ancora un campo emergente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cd75b04b-2d2d-4d87-b6cc-b0fed440d912",
      "metadata": {},
      "source": [
        "<span id=\"experiment-2-teleporting-across-a-processor\" />\n",
        "\n",
        "## Esperimento 2: Teletrasporto attraverso un processore\n",
        "\n",
        "Probabilmente, la parte più interessante del teletrasporto quantistico è che uno stato quantistico può essere teletrasportato su lunghe distanze in modo istantaneo (sebbene la comunicazione classica di porte extra non sia istantanea). Come già detto, non possiamo staccare i qubit dal processore e spostarli. Ma possiamo spostare l'informazione da un qubit all'altro, finché i qubit coinvolti nel teletrasporto non si trovano ai lati opposti del processore. Ripetiamo i passaggi precedenti, ma ora realizzeremo un circuito più grande con un numero di qubit sufficiente a coprire il processore.\n",
        "\n",
        "<span id=\"step-1-map-your-problem-to-a-quantum-circuit\" />\n",
        "\n",
        "### Passaggio 1: mappa il tuo problema su un circuito quantistico\n",
        "\n",
        "Questa volta, i qubit corrispondenti ad Alice e Bob cambieranno. Quindi non chiameremo un singolo qubit \"A\" e un altro \"B\". Piuttosto, numereremo i qubit e useremo variabili per rappresentare la posizione attuale delle informazioni sui qubit appartenenti ad Alice e Bob. Tutte le altre fasi, ad eccezione delle porte di scambio, sono descritte in precedenza.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "7d7742fa-e9a2-4ca0-9d9b-f29d73e07cd9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/quantum-teleportation/extracted-outputs/7d7742fa-e9a2-4ca0-9d9b-f29d73e07cd9-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Step 1: Map\n",
        "\n",
        "# Define registers\n",
        "qr = QuantumRegister(13, \"q\")\n",
        "\n",
        "qc = QuantumCircuit(qr, cr)\n",
        "\n",
        "# Define registers\n",
        "secret = QuantumRegister(1, \"Q\")\n",
        "ebitsa = QuantumRegister(6, \"A\")\n",
        "ebitsb = QuantumRegister(6, \"B\")\n",
        "# q = ClassicalRegister(1, \"q meas\")\n",
        "# a = ClassicalRegister(1, \"a\")\n",
        "# b = ClassicalRegister(1, \"b\")\n",
        "cr = ClassicalRegister(3, \"c\")\n",
        "qc = QuantumCircuit(secret, ebitsa, ebitsb, cr)\n",
        "\n",
        "# We'll start Alice in the middle of the circuit, then move information outward in both directions.\n",
        "Alice = 5\n",
        "Bob = 0\n",
        "qc.h(ebitsa[Alice])\n",
        "qc.cx(ebitsa[Alice], ebitsb[Bob])\n",
        "\n",
        "# Starting with Bob and Alice in the center, we swap their information onto adjacent qubits,\n",
        "# until the information is on distant qubits.\n",
        "\n",
        "for n in range(Alice):\n",
        "    qc.swap(ebitsb[Bob], ebitsb[Bob + 1])\n",
        "    qc.swap(ebitsa[Alice], ebitsa[Alice - 1])\n",
        "    Alice = Alice - 1\n",
        "    Bob = Bob + 1\n",
        "\n",
        "qc.barrier()\n",
        "\n",
        "# Create a random state for Alice (qubit zero)\n",
        "np.random.seed(42)  # fixing seed for repeatability\n",
        "# theta = np.random.uniform(0.0, 1.0) * np.pi    #from 0 to pi\n",
        "theta = 0.3\n",
        "varphi = np.random.uniform(0.0, 2.0) * np.pi  # from 0 to 2*pi\n",
        "\n",
        "\n",
        "qc.u(theta, varphi, 0.0, secret)\n",
        "\n",
        "# Entangle Alice's two qubits\n",
        "qc.cx(secret, ebitsa[Alice])\n",
        "qc.h(secret)\n",
        "\n",
        "qc.barrier()\n",
        "\n",
        "# Make measurements of Alice's qubits and store the results in the classical register.\n",
        "qc.measure(ebitsa[Alice], cr[1])\n",
        "qc.measure(secret, cr[0])\n",
        "\n",
        "# Send instructions to Bob's qubits based on the outcome of Alice's measurements.\n",
        "with qc.if_test((cr[1], 1)):\n",
        "    qc.x(ebitsb[Bob])\n",
        "with qc.if_test((cr[0], 1)):\n",
        "    qc.z(ebitsb[Bob])\n",
        "\n",
        "qc.barrier()\n",
        "\n",
        "# Invert the preparation we did for Carl's qubit so we can check whether we did this correctly.\n",
        "qc.u(theta, varphi, 0.0, ebitsb[Bob]).inverse()  # inverse of u(theta,varphi,0.0)\n",
        "qc.measure(ebitsb[Bob], cr[2])  # add measurement gate\n",
        "\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5174ffeb-28d4-49d4-9693-5271e026b026",
      "metadata": {},
      "source": [
        "Nello schema del circuito si può notare che i passaggi logici sono gli stessi. L'unica differenza è che abbiamo usato le porte di scambio per portare lo stato del qubit di Alice dal qubit 6 ( $A_5$ ) fino al qubit 1 ( $A_0$ ), proprio accanto a Q. E abbiamo usato le porte di scambio per portare lo stato iniziale di Bob dal qubit 7 ( $B_0$ ) al qubit 12 ( $B_5$ ). Si noti che lo stato del qubit 12 non è nemmeno correlato allo stato segreto di Q finché non vengono effettuate misure sui qubit 0 e 1 distanti, e lo stato del qubit 12 non è uguale allo stato segreto finché non vengono applicate le porte condizionali $X$ e $Z$.\n",
        "\n",
        "<span id=\"step-2-optimize-your-circuit\" />\n",
        "\n",
        "### Passaggio 2: Ottimizza il tuo circuito\n",
        "\n",
        "Normalmente, quando si usa il gestore dei passaggi per transpilare e ottimizzare i circuiti, ha senso impostare `optimization_level = 3`, perché si vuole che i circuiti siano il più efficienti possibile. In questo caso, non c'è alcuna ragione computazionale per trasferire gli stati dai qubit 6 e 7 ai qubit 1 e 12. Era solo una cosa che abbiamo fatto per dimostrare il teletrasporto a distanza. Se chiediamo al pass manager di ottimizzare il nostro circuito, si renderà conto che non c'è alcuna ragione logica per questi swap gate, e li rimuoverà ed eseguirà le operazioni di gate sui qubit adiacenti. Quindi, per questo caso speciale, utilizziamo `optimization_level = 0`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "d7865560-a8a6-4abb-af8d-6a86ecc76bff",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "105\n"
          ]
        }
      ],
      "source": [
        "# Step 2: Transpile\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "target = backend.target\n",
        "pmzero = generate_preset_pass_manager(target=target, optimization_level=0)\n",
        "\n",
        "qc_isa_zero = pmzero.run(qc)\n",
        "\n",
        "print(qc_isa_zero.depth())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "38c1dc99-e5e0-4969-b7a0-cdc1e4e6bedd",
      "metadata": {},
      "source": [
        "Possiamo visualizzare la posizione di questi qubit sul processore quantistico utilizzando la funzione `plot_circuit_layout` .\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6a74e5a5-d32f-41a5-adf8-29174a0d5e8a",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute\" />\n",
        "\n",
        "### Fase 3: Esecuzione\n",
        "\n",
        "Come in precedenza, si consiglia di eseguire l'operazione su computer quantistici reali IBM. Se l'utilizzo mensile gratuito è stato raggiunto, è possibile decommentare le celle del simulatore per eseguirle su un simulatore.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "5536d98a-480b-4193-8c63-2ef77d1aeda0",
      "metadata": {},
      "outputs": [],
      "source": [
        "# This required 5 s to run on a Heron r2 processor on 10-28-24\n",
        "job = sampler.run([qc_isa_zero])\n",
        "# job = sampler_sim.run([qc_isa_zero])\n",
        "counts = job.result()[0].data.c.get_counts()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "13b6375b-73c7-436d-bf1c-98de45ef4056",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/quantum-teleportation/extracted-outputs/13b6375b-73c7-436d-bf1c-98de45ef4056-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 16,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.visualization import plot_histogram\n",
        "\n",
        "plot_histogram(counts)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "49ed3ba0-3482-4ad5-84c3-f8fba80d8668",
      "metadata": {},
      "source": [
        "<span id=\"step-4-classical-post-processing\" />\n",
        "\n",
        "### Fase 4: Post-elaborazione classica\n",
        "\n",
        "Anche in questo caso vediamo che le probabilità dei possibili risultati per i qubit di Alice sono abbastanza uniformi. C'è una forte preferenza per trovare il qubit di Bob in $|0\\rangle$ dopo aver invertito il codice segreto, il che significa che c'è una forte probabilità di aver teletrasportato correttamente lo stato segreto attraverso il processore da Q a Bob (qubit da 0 a 12). Tuttavia, notiamo che ora c'è una probabilità maggiore di *non* misurare $|0\\rangle$ per Bob. Questa è una lezione importante per l'informatica quantistica: più porte si hanno, soprattutto porte multi-qubit come le porte swap, più rumore ed errori si incontrano.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ede2724d-536b-472a-b4bd-b1276b5b851d",
      "metadata": {},
      "source": [
        "<span id=\"questions\" />\n",
        "\n",
        "## Domande\n",
        "\n",
        "Gli insegnanti possono richiedere le versioni di questi quaderni con le chiavi di risposta e le indicazioni per l'inserimento nei curricula comuni compilando questo [rapido sondaggio](https://ibm.biz/classrooms_instructor_key_request) sull'utilizzo dei quaderni.\n",
        "\n",
        "<span id=\"critical-concepts\" />\n",
        "\n",
        "### Concetti fondamentali\n",
        "\n",
        "* I qubit possono essere entangled, ovvero la misurazione di un qubit influenza o addirittura determina lo stato di un altro qubit.\n",
        "* L'entanglement è diverso dalle correlazioni classiche; ad esempio, i qubit A e B potrebbero trovarsi in una sovrapposizione di stati come $\\alpha_0|00\\rangle+\\alpha_1|11\\rangle.$. Lo stato di A o B potrebbe essere indeterminato dalla natura, eppure si potrebbe garantire che A e B si trovino nello stesso stato.\n",
        "* Attraverso una combinazione di entanglement e misure, possiamo trasferire uno stato (che può memorizzare informazioni) da un qubit all'altro. Questo trasferimento può avvenire anche su lunghe distanze e si chiama teletrasporto quantistico.\n",
        "* Il teletrasporto quantistico si basa su misure quantistiche, che sono probabilistiche. Pertanto, la comunicazione classica può essere necessaria per modificare gli stati teletrasportati. Questo impedisce al teletrasporto quantistico di spostare le informazioni più velocemente della luce. Il teletrasporto quantistico non viola la relatività o la causalità.\n",
        "* I moderni computer quantistici sono più sensibili al rumore e agli errori rispetto ai computer classici. Aspettatevi un errore di qualche punto percentuale.\n",
        "* Più porte si aggiungono in sequenza (soprattutto quelle a 2 qubit), più errori e rumore si possono prevedere.\n",
        "\n",
        "<span id=\"true/false-questions\" />\n",
        "\n",
        "### Domande vero/falso\n",
        "\n",
        "1. T/F Il teletrasporto quantistico può essere utilizzato per inviare informazioni più velocemente della luce.\n",
        "2. T/F Le prove moderne suggeriscono che il collasso di uno stato quantistico si propaga più velocemente della luce.\n",
        "3. T/F In Qiskit, i qubit sono ordinati in stati con il qubit di numero più basso a destra, come in $|q_3,q_2,q_1, q_0\\rangle$\n",
        "\n",
        "<span id=\"mc-questions\" />\n",
        "\n",
        "### Domande del presentatore\n",
        "\n",
        "1. I Qubit A e B sono entangled, quindi separati da una grande distanza $d$. Il Qubit A viene misurato. Quale affermazione è corretta riguardo alla velocità con cui viene influenzato lo stato del qubit B?\n",
        "\n",
        "* a. Il Qubit B viene influenzato istantaneamente, entro la tolleranza sperimentale, negli esperimenti condotti finora.\n",
        "* b. Il Qubit B viene colpito dopo un tempo $d/c$, il che significa che lo stato quantistico \"collassa\" approssimativamente alla velocità della luce, entro la tolleranza sperimentale.\n",
        "* c. Il Qubit B è interessato solo dopo che si è verificata la comunicazione classica, il che significa che avviene in un tempo superiore a $d/c$.\n",
        "* d. Nessuna delle precedenti\n",
        "\n",
        "2. Ricordiamo che la probabilità di misurazione è legata alle ampiezze degli stati quantistici. Ad esempio, se un qubit si trova inizialmente nello stato $\\alpha_0|0\\rangle+\\alpha_1 |1\\rangle,$, la probabilità di misurare lo stato $|0\\rangle$ è $|\\alpha_0|^2.$ Non tutti gli insiemi di misurazioni corrisponderanno esattamente a queste probabilità, a causa di un campionamento finito (proprio come il lancio di una moneta potrebbe dare testa per due volte di seguito). L'istogramma di misura sottostante potrebbe corrispondere a quale dei seguenti stati quantistici? Selezionare l'opzione migliore.\n",
        "\n",
        "![entangled\\_teleportation\\_fig](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/quantum-teleportation/entangled_teleportation_fig.avif)\n",
        "\n",
        "* a. $|0\\rangle$\n",
        "* b. $\\frac{1}{\\sqrt{2}}\\left(|0\\rangle-|1\\rangle\\right)$\n",
        "* c. $\\frac{1}{\\sqrt{2}}\\left(|0\\rangle+|1\\rangle\\right)$\n",
        "* d. $\\frac{4}{5}|0\\rangle+\\frac{3}{5}|1\\rangle$\n",
        "* e. $\\frac{3}{5}|0\\rangle+\\frac{4}{5}|1\\rangle$\n",
        "\n",
        "3. Quale dei seguenti stati mostra i qubit A e B entangled? Selezionare tutte le opzioni appropriate.\n",
        "\n",
        "* a. $\\frac{1}{\\sqrt{2}}\\left(|0\\rangle_B|0\\rangle_A+|1\\rangle_B|1\\rangle_A\\right)$\n",
        "* b. $\\frac{4}{5}|0\\rangle_B|0\\rangle_A+\\frac{3}{5}|1\\rangle_B|1\\rangle_A$\n",
        "* c. $\\frac{1}{\\sqrt{2}}\\left(|0\\rangle_B|1\\rangle_A-|1\\rangle_B|0\\rangle_A\\right)$\n",
        "* d. $\\frac{1}{\\sqrt{2}}\\left(|0\\rangle_B|0\\rangle_A+|1\\rangle_B|0\\rangle_A\\right)$\n",
        "* e. $|0\\rangle_B|0\\rangle_A$\n",
        "\n",
        "4. In questo modulo abbiamo preparato uno stato entangled: $\\frac{1}{\\sqrt{2}}\\left(|0\\rangle_B|0\\rangle_A+|1\\rangle_B|1\\rangle_A\\right).$ Ma ci sono molti altri stati entangled che si possono usare per un protocollo simile. Quale dei seguenti stati potrebbe produrre un istogramma di misura a 2 qubit come il seguente? Selezionare la risposta migliore.\n",
        "\n",
        "![entangled\\_teleportation\\_fig\\_0110](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/quantum-teleportation/entangled_teleportation_fig_0110.avif)\n",
        "\n",
        "* a. $\\frac{1}{\\sqrt{2}}\\left(|0\\rangle_B|0\\rangle_A+|1\\rangle_B|1\\rangle_A\\right)$\n",
        "* b. $\\frac{4}{5}|0\\rangle_B|0\\rangle_A+\\frac{3}{5}|1\\rangle_B|1\\rangle_A$\n",
        "* c. $\\frac{1}{\\sqrt{2}}\\left(|0\\rangle_B|1\\rangle_A-|1\\rangle_B|0\\rangle_A\\right)$\n",
        "* d. $\\frac{4}{5}|0\\rangle_B|1\\rangle_A+\\frac{3}{5}|1\\rangle_B|0\\rangle_A$\n",
        "* e. $|0\\rangle_B|0\\rangle_A$\n",
        "\n",
        "<span id=\"discussion-questions\" />\n",
        "\n",
        "### Domande di discussione\n",
        "\n",
        "1. Descrivete al vostro compagno/gruppo il protocollo di teletrasporto quantistico, dall'inizio alla fine. Chiedete se hanno qualcosa da aggiungere o se hanno domande da fare.\n",
        "\n",
        "2. C'è qualcosa di unico nello stato entangled iniziale tra Alice e Bob: $\\frac{1}{\\sqrt{2}}\\left(|0\\rangle_B|0\\rangle_A+|1\\rangle_B|1\\rangle_A\\right)?$ Se sì, che cosa c'è di unico? In caso contrario, quali altri stati entangled avremmo potuto utilizzare?\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "in_page_toc_max_heading_level": 2,
    "in_page_toc_min_heading_level": 2,
    "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
}