{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "18a3d7ba-200a-42e0-ab18-9eb03999c1f6",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"QAOA su scala industriale\"\n",
        "description: \"Risolvi un esempio su larga scala del problema del taglio massimo, un famoso problema della teoria dei grafi.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore Longleftrightarrow ZIZII */}\n",
        "\n",
        "<span id=\"utility-scale-qaoa\" />\n",
        "\n",
        "# QAOA su scala industriale\n",
        "\n",
        "Guardate il video su QAOA su scala utility di Olivia Lanes, oppure aprite il video in una finestra separata su [YouTube.](https://youtube.com/watch?v=P3s7TIMIvZ0)\n",
        "\n",
        "<IBMVideo id=\"134063421\" title=\"In questo video, Olivia Lanes illustra come eseguire un calcolo su scala industriale su un computer quantistico. Il calcolo riguarda il problema del taglio massimo e utilizza l'approccio QAOA.\" />\n",
        "\n",
        "<span id=\"lesson-overview\" />\n",
        "\n",
        "## Panoramica della lezione:\n",
        "\n",
        "Finora, in questo corso, ci auguriamo di avervi dato una solida base del quadro e degli strumenti necessari per risolvere i problemi su scala industriale con un computer quantistico. Ora, finalmente, vedremo questi strumenti in azione.\n",
        "\n",
        "In questa lezione ci metteremo alla prova con un esempio su larga scala del problema del taglio massimo, un famoso problema della teoria dei grafi che riguarda il modo migliore per dividere un grafo in due parti. Inizieremo con un semplice grafico a cinque nodi per capire come un computer quantistico possa aiutarci a risolvere il problema, per poi applicare questo approccio a una versione su larga scala dello stesso problema.\n",
        "\n",
        "Questa lezione fornirà una panoramica generale dell'approccio che adottiamo per risolvere questo problema. Non si tratterà di una guida dettagliata al codice. Insieme a questa lezione, però, c'è un [tutorial](/docs/tutorials/quantum-approximate-optimization-algorithm) con codice reale che puoi eseguire per risolvere il problema del taglio massimo su un computer quantistico.\n",
        "\n",
        "<span id=\"the-problem\" />\n",
        "\n",
        "## Il problema\n",
        "\n",
        "Come promemoria, non tutti i problemi di calcolo sono adatti all'informatica quantistica. i \"problemi facili\" non trarranno alcun vantaggio da questa tecnologia perché i computer classici sono già perfettamente in grado di risolverli.\n",
        "\n",
        "I tre casi d'uso che siamo più ottimisti di esplorare sono:\n",
        "\n",
        "1. simulare la natura\n",
        "2. elaborazione di dati con struttura complessa\n",
        "3. di rete\n",
        "\n",
        "Oggi ci concentreremo sul terzo caso d'uso, l'ottimizzazione. In un problema di ottimizzazione, in genere si cerca il valore più grande o più piccolo possibile per una determinata funzione. La difficoltà di trovare questi estremi con i metodi classici può aumentare esponenzialmente al crescere delle dimensioni del problema.\n",
        "\n",
        "Il problema di ottimizzazione che ci interessa oggi è chiamato \"max-cut\", che risolveremo utilizzando un algoritmo denominato \"Quantum Approximate Optimization Algorithm\" (QAOA).\n",
        "\n",
        "<span id=\"what-is-max-cut\" />\n",
        "\n",
        "### Che cos'è Max-Cut?\n",
        "\n",
        "Iniziamo con un grafico, costituito da un insieme di vertici (o nodi), alcuni dei quali sono collegati da spigoli. Nel problema, ci viene chiesto di dividere i nodi del grafo in due sottoinsiemi \"tagliando\" i bordi che li collegano. Vogliamo trovare la partizione che massimizzi il numero di spigoli tagliati in questo modo – da qui il nome «max-cut»\n",
        "\n",
        "![Illustrazione di un problema di max-cut](https://quantum.cloud.ibm.com/learning/images/courses/quantum-computing-in-practice/utility-scale-qaoa/maxcut-illustration.avif)\n",
        "\n",
        "Ad esempio, la figura sopra mostra un grafo a cinque nodi con, sulla destra, una soluzione del taglio massimo. Taglia cinque spigoli, il massimo che si possa ottenere con questo grafo.\n",
        "\n",
        "Dato che un grafo a cinque nodi è così piccolo, non è troppo difficile calcolare il taglio massimo a mente o provando alcuni tagli su un foglio di carta. Ma, come potete immaginare, il problema diventa sempre più complesso all'aumentare del numero di vertici — in parte perché il numero di possibili tagli da considerare cresce in modo esponenziale con l'aumentare del numero di nodi. E a un certo punto, questo diventa difficile persino per i supercomputer, utilizzando qualsiasi algoritmo classico conosciuto.\n",
        "\n",
        "Vorremmo trovare un modo per risolvere il problema del taglio massimo su questi grafi più grandi e complessi, poiché tale problema trova numerose applicazioni pratiche, tra cui l'individuazione delle frodi nel settore finanziario, il clustering dei grafi, la progettazione di reti e l'analisi dei social media. Il metodo Max-cut viene spesso utilizzato come sottoproblema nell'ambito di un approccio specifico a un problema più ampio. Quindi, è molto più comune di quanto potremmo ingenuamente pensare.\n",
        "\n",
        "<span id=\"the-solution\" />\n",
        "\n",
        "## La soluzione\n",
        "\n",
        "Ora vedremo in dettaglio l'approccio che utilizziamo per risolvere il problema del taglio massimo su un computer quantistico. Lo faremo utilizzando un semplice grafico a cinque nodi. Puoi seguire il tutorial utilizzando il notebook Python. Dopo questo semplice esempio, il tutorial ti guiderà attraverso un caso pratico su larga scala.\n",
        "\n",
        "Il primo passo consiste nel creare il nostro grafo, definendo il numero di nodi e gli spigoli che collegano due nodi. È possibile farlo importando un pacchetto chiamato `rustworkx`, come mostrato nel tutorial. Il risultato sarà un grafico di questo tipo:\n",
        "\n",
        "![Risultato del grafico max-cut di Rustworkx](https://quantum.cloud.ibm.com/learning/images/courses/quantum-computing-in-practice/utility-scale-qaoa/rustworxMaxCut.avif)\n",
        "\n",
        "Utilizzeremo il framework Qiskit Patterns per trovare le soluzioni max-cut per questo grafo sul nostro computer quantistico.\n",
        "\n",
        "<span id=\"map\" />\n",
        "\n",
        "### Associazione\n",
        "\n",
        "Dobbiamo mappare il problema sul nostro computer quantistico. Per fare ciò, notiamo innanzitutto che la massimizzazione del numero di tagli in un grafo può essere scritta matematicamente come:\n",
        "\n",
        "$$\n",
        "\\max\\limits_{x\\in\\{0,1\\}^n} \\sum\\limits_{(i,j)} {x_i + x_j - 2x_ix_j}\n",
        "$$\n",
        "\n",
        "Dove $i$ e $j$ sono nodi del grafo e $x_i$ e $x_j$ sono 0 o 1, a seconda del lato della partizione in cui si trova ciascun nodo (un gruppo è etichettato come \"0\" e uno come \"1\"). Quando $x_i$ e $x_j$ si trovano dalla stessa parte della partizione, l'espressione della somma è uguale a zero. Quando si trovano su lati opposti, quindi c'è un taglio tra di loro, l'espressione è uguale a uno. Quindi, massimizzando il numero di tagli si massimizza la somma.\n",
        "\n",
        "Possiamo anche invertire la situazione e cercare il minimo moltiplicando ogni valore per uno negativo.\n",
        "\n",
        "$$\n",
        "\\min\\limits_{x\\in\\{0,1\\}^n} \\sum\\limits_{(i,j)} {2x_ix_j - x_i - x_j}\n",
        "$$\n",
        "\n",
        "Ora siamo pronti per la mappatura. Può essere scoraggiante pensare a come passare da un grafico come quello che abbiamo appena disegnato a un circuito quantistico. Ma faremo un passo alla volta.\n",
        "\n",
        "Ricordate, cercheremo di risolvere il problema del taglio massimo utilizzando il metodo QAOA. Nella metodologia QAOA, il nostro obiettivo finale è quello di ottenere un operatore (o, in altre parole, un hamiltoniano) che serva a rappresentare la funzione di costo del nostro algoritmo ibrido, nonché un circuito parametrizzato (l'ansatz) che utilizziamo per rappresentare le possibili soluzioni al problema.\n",
        "\n",
        "<span id=\"qubo\" />\n",
        "\n",
        "#### QUBO\n",
        "\n",
        "Possiamo scegliere tra queste soluzioni candidate e valutarle con la funzione di costo. Per farlo, ci avvaliamo di una serie di riformulazioni matematiche, tra cui la notazione Quadratic Unconstrained Binary Optimization (in breve QUBO), un modo utile per codificare i problemi di ottimizzazione combinatoria. In QUBO, vogliamo trovare:\n",
        "\n",
        "$$\n",
        "\\min\\limits_{x\\in\\{0,1\\}^n} x^TQx\n",
        "$$\n",
        "\n",
        "dove $Q$ è una matrice $n\\times n$ di numeri reali, $n$ corrisponde al numero di nodi del nostro grafo, in questo caso cinque.\n",
        "\n",
        "Per applicare il QAOA, dobbiamo formulare il nostro problema come un'hamiltoniana, ovvero una funzione o matrice che rappresenta l'energia totale di un sistema. In particolare, vogliamo creare una funzione di costo hamiltoniana che abbia la proprietà che lo stato fondamentale corrisponde al valore minimo della funzione. Quindi, per risolvere il nostro problema di ottimizzazione, cercheremo di preparare lo stato fondamentale di $H$ su un computer quantistico. Quindi, il campionamento da questo stato produrrà la soluzione di $\\min 𝑓(𝑥)$ con un'alta probabilità.\n",
        "\n",
        "<span id=\"mapping-to-a-cost-function-hamiltonian\" />\n",
        "\n",
        "#### Mappatura su una funzione di costo hamiltoniana\n",
        "\n",
        "Siamo fortunati, perché il problema di QUBO è strettamente legato, e di fatto computazionalmente equivalente, a uno degli hamiltoniani più famosi e diffusi in fisica: l'hamiltoniano di Ising.\n",
        "\n",
        "Per esprimere il problema QUBO come Hamiltoniano di Ising, basta semplicemente effettuare un semplice cambio di variabili da $x \\in \\{0, 1\\}^n$ a $z \\in \\{-1, 1\\}^n$ :\n",
        "\n",
        "$$\n",
        "x_i = \\frac{1-z_i}{2}.\n",
        "$$\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Dettagli\">\n",
        "    Innanzitutto, si noti che possiamo riscrivere la nostra espressione QUBO come somma di termini matriciali:\n",
        "\n",
        "    $$\n",
        "    x^TQx = \\sum_{ij}Q_{ij}x_ix_j\n",
        "    $$\n",
        "\n",
        "    Applicando il cambio di variabili si ottiene\n",
        "\n",
        "    $$\n",
        "    \\sum_{ij}Q_{ij}(\\frac{1-z_i}{2})(\\frac{1-z_j}{2}) = \\sum_{ij}\\frac{Q_{ij}}{4}(1 - z_i - z_j + z_iz_j)\n",
        "    $$\n",
        "\n",
        "    che può essere riscritta come segue.\n",
        "\n",
        "    $$\n",
        "    \\sum_{ij}\\frac{Q_{ij}}{4}z_iz_j - \\frac{Q_{ij}}{4}z_i - \\frac{Q_{ij}}{4}z_j + \\frac{Q_{ij}}{4}\n",
        "    $$\n",
        "\n",
        "    Possiamo tralasciare il termine costante poiché non influirà sulla scelta dell’ $z$ e che minimizza il problema QUBO. Inoltre, possiamo moltiplicare questa espressione per quattro per ottenere nuovamente il valore originale di $Q$, poiché ciò non influisce sulla scelta ottimale di $z$.\n",
        "\n",
        "    $$\n",
        "    \\sum_{ij}Q_{ij}z_iz_j - Q_{ij}z_i - Q_{ij}z_j = z^TQz + (-\\sum_{ij} Q_{ij}z_i + Q_{ij}z_j)\n",
        "    $$\n",
        "\n",
        "    Raggruppando i termini lineari simili, possiamo definire il nostro vettore di coefficienti lineari $b$ utilizzando l'equazione\n",
        "\n",
        "    $$\n",
        "    b_i = -\\sum_{j} Q_{ij} + Q_{ji}\n",
        "    $$\n",
        "\n",
        "    il che completa la trasformazione delle variabili in $z \\in \\{-1, 1\\}^n$ dopo aver sostituito nell'equazione precedente.\n",
        "\n",
        "    $$\n",
        "    z^TQz + b^Tz\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "In definitiva, la minimizzazione dell’espressione QUBO equivale alla minimizzazione di questa espressione, dove $b$ è un coefficiente scalare reale:\n",
        "\n",
        "$$\n",
        "\\min_{x\\in\\{0,1\\}^n} x^TQx\\Longleftrightarrow \\min_{z\\in\\{-1,1\\}^n}z^TQz + b^Tz\n",
        "$$\n",
        "\n",
        "Riscrivendo ancora una volta in modo leggermente diverso, otteniamo la nostra funzione di costo hamiltoniana, dove il minimo dell’espressione rappresenta lo stato fondamentale e `Z` è l’operatore Z di Pauli:\n",
        "\n",
        "$$\n",
        "H_C=\\sum_{ij}Q_{ij}Z_iZ_j + \\sum_i b_i Z_i\n",
        "$$\n",
        "\n",
        "Ora che abbiamo la nostra hamiltoniana, dobbiamo riscriverla in termini di operatori Pauli ZZ bipolari, che possiamo facilmente convertire in porte a due qubit nel nostro circuito quantistico. Alla fine avremo sei oggetti - o stringhe di Pauli - ognuno dei quali corrisponde a ciascuno dei sei spigoli del grafo. Ognuno dei cinque elementi di una stringa rappresenta un'operazione su un nodo: l'identità se il nodo non è collegato a quel particolare bordo e l'operatore Pauli Z se lo è. In Qiskit, le stringhe di bit che rappresentano i qubit sono indicizzate all'indietro. Ad esempio, un bordo tra i nodi 0 e 1 è codificato come `IIIZZ`, mentre un bordo tra 2 e 4 è codificato come `ZIZII`.\n",
        "\n",
        "<span id=\"construct-the-quantum-circuit\" />\n",
        "\n",
        "#### Costruisci il circuito quantistico\n",
        "\n",
        "Con la nostra hamiltoniana scritta in termini di operatori di Pauli, siamo pronti a costruire il nostro circuito quantistico, che ci permette di campionare buone soluzioni utilizzando un computer quantistico:\n",
        "\n",
        "![Schema di circuito con strati QAOA](https://quantum.cloud.ibm.com/learning/images/courses/quantum-computing-in-practice/utility-scale-qaoa/circuit-diagram.svg)\n",
        "\n",
        "L'algoritmo QAOA si ispira al teorema adiabatico, secondo il quale se si parte dallo stato fondamentale di un'hamiltoniana dipendente dal tempo, se l'hamiltoniana si evolve abbastanza lentamente e con un tempo sufficiente, lo stato finale sarà lo stato fondamentale dell'hamiltoniana finale. Il QAOA può essere considerato come la versione discreta e trotterizzata di questo Algoritmo Adiabatico Quantistico, dove ogni passo di trotter rappresenta un livello dell'algoritmo QAOA. Quindi, invece di evolvere da uno stato all'altro, in ogni strato passeremo dall'Hamiltoniana della funzione di costo a una cosiddetta Hamiltoniana \"mixer\", che tratteremo più avanti in questa lezione.\n",
        "\n",
        "Il vantaggio di QAOA è che è più veloce dell'algoritmo adiabatico quantistico, ma restituisce soluzioni approssimate anziché ottimali. Nel limite in cui il numero di strati arriva all'infinito, QAOA converge al caso QAA, ma naturalmente questo è molto costoso dal punto di vista computazionale.\n",
        "\n",
        "Per creare il nostro circuito quantistico, applicheremo operatori alternati, parametrizzati da $\\gamma$ e $\\beta$, che rappresenteranno la discretizzazione dell'evoluzione temporale.\n",
        "\n",
        "Quindi, le tre parti principali del circuito QAOA sono:\n",
        "\n",
        "1. lo stato di prova iniziale, in grigio, che è lo stato ground del mixer, creato applicando un gate di Hadamard a ogni qubit\n",
        "2. l'evoluzione della funzione di costo, di cui abbiamo parlato in precedenza, in viola scuro\n",
        "3. l'evoluzione sotto l'hamiltoniana del mixer, che non abbiamo ancora trattato, in viola chiaro.\n",
        "\n",
        "La nostra hamiltoniana di partenza è chiamata Mixer perché il suo stato fondamentale è la sovrapposizione di tutte le possibili stringhe di bit di interesse: quindi impone una miscela di tutte le possibili soluzioni all'inizio.\n",
        "\n",
        "L'hamiltoniana del mixer è la semplice somma delle operazioni Pauli-X su ogni nodo del grafo. Qiskit consente di utilizzare un operatore di miscelazione diverso e personalizzato, ma in questo caso utilizzeremo quello standard. Quindi, ancora una volta, si può notare che con Qiskit si elimina gran parte del lavoro, rendendo banale la creazione dell'hamiltoniana del mixer e dello stato iniziale. L'unico lavoro da fare era trovare la funzione di costo.\n",
        "\n",
        "Ogni iterazione di questi operatori è chiamata strato. Questi strati possono essere visti come una discretizzazione dell'evoluzione temporale del sistema, come descritto in precedenza. L'alternanza deriva dalla decomposizione di Trotter e approssima le funzioni esponenziali di matrici non comunicanti. In generale, più strati o fasi includiamo, più ci avvicineremo all'evoluzione temporale continua, come in QAA, quindi in teoria più il risultato sarà accurato. Ma per questo esempio, inizieremo a campionare con un solo livello. Ricordiamo che sia la funzione di costo hamiltoniana che il miscelatore sono parametrizzati; dobbiamo comunque trovare i valori ottimali per $\\gamma$ e $\\beta.$\n",
        "\n",
        "<span id=\"optimize\" />\n",
        "\n",
        "### Ottimizza\n",
        "\n",
        "Sebbene il circuito appena creato sembri piuttosto semplice e sia utile per costruire una comprensione intuitiva, ricordate che il chip quantistico non capisce cosa sia il gate QAOA. Dobbiamo trasformare tutto questo in una serie di porte \"native\" a uno o due qubit che possano essere eseguite direttamente sull'hardware. Le porte native sono quelle che possono essere eseguite direttamente sui qubit. Si dice che tali circuiti siano scritti nell'Instruction Set Architecture (ISA) del backend.\n",
        "\n",
        "La libreria Qiskit offre una serie di passaggi di trasposizione che soddisfano un'ampia gamma di trasformazioni circuitali. Vogliamo assicurarci che il circuito sia ottimizzato per il nostro scopo.\n",
        "\n",
        "Ricordiamo dalla lezione precedente che il processo di trasposizione prevede diverse fasi:\n",
        "\n",
        "* Mappatura iniziale dei qubit del circuito (cioè delle variabili decisionali) ai qubit fisici del dispositivo.\n",
        "* Srotolamento delle istruzioni del circuito quantistico alle istruzioni native dell'hardware che il backend comprende.\n",
        "* Instradamento dei qubit del circuito che interagiscono verso qubit fisici adiacenti.\n",
        "\n",
        "E come sempre, ulteriori dettagli sono disponibili nella [documentazione](/docs/guides/transpile).\n",
        "\n",
        "Prima di eseguire il transpiling, però, dobbiamo scegliere il backend su cui eseguire il nostro circuito, poiché il transpiler ottimizza in modo diverso per i diversi processori. Questa è un'altra ragione per cui è importante utilizzare un transpiler automatico: non si vuole affrontare il lungo processo di ottimizzazione del circuito a mano, per poi rendersi conto che si vuole eseguire il circuito su un processore diverso con proprietà diverse.\n",
        "\n",
        "Passare il backend scelto attraverso la funzione di transpiler e specificare il livello di ottimizzazione. Nel tutorial, selezionerete il livello 3, che è il livello più alto e approfondito.\n",
        "\n",
        "E con questo abbiamo un circuito transpilato pronto per essere eseguito sull'hardware!\n",
        "\n",
        "<span id=\"execute\" />\n",
        "\n",
        "### Esegui\n",
        "\n",
        "Finora abbiamo trapiantato il circuito lasciando i parametri gamma e beta da soli, ma in realtà non possiamo far funzionare il circuito senza specificare questi parametri. Nel flusso di lavoro di QAOA, i parametri ottimali di QAOA vengono trovati in un ciclo di ottimizzazione iterativa, in cui si esegue una serie di valutazioni del circuito e poi si utilizza un ottimizzatore classico per trovare i parametri 𝛽 e 𝛾 ottimali. Tuttavia, dobbiamo iniziare da qualche parte, quindi facciamo un'ipotesi iniziale di $\\gamma=\\pi/2$ e di $\\beta=\\pi.$\n",
        "\n",
        "Modalità di esecuzione\n",
        "\n",
        "Ora siamo quasi pronti a percorrere il circuito - lo prometto! Ma prima è importante notare che è possibile inviare il lavoro in una serie di modi diversi, chiamati modalità di esecuzione.\n",
        "\n",
        "* Modalità di esecuzione: viene inviata una singola richiesta alla primitiva Estimator o Sampler senza un gestore di contesto. I circuiti e gli input vengono raggruppati in blocchi primitivi unificati (PUB) e inviati al computer quantistico come attività di esecuzione.\n",
        "\n",
        "* Modalità batch: Un gestore di più lavori per eseguire in modo efficiente un esperimento composto da un gruppo di lavori indipendenti. Utilizzare la modalità batch per inviare più lavori primitivi contemporaneamente\n",
        "\n",
        "* Modalità sessione: Una finestra dedicata per l'esecuzione di un carico di lavoro multiplo. Ciò consente agli utenti di sperimentare algoritmi variazionali in modo più prevedibile e persino di eseguire più esperimenti contemporaneamente, sfruttando il parallelismo nello stack. Utilizzate le sessioni per carichi di lavoro iterativi o esperimenti che richiedono un accesso dedicato. Per esempi, vedere Esecuzione di lavori in una sessione.\n",
        "\n",
        "Per un esperimento di QAOA, una sessione sarebbe una buona scelta per procedere se si ha accesso ad essa, dal momento che abbiamo bisogno di campionare il nostro circuito molte volte con diversi valori di parametro per trovare l'optimum.\n",
        "\n",
        "Torniamo al problema dell'ottimizzazione. Dobbiamo trovare valori migliori di gamma e beta rispetto alle nostre prime ipotesi. Per farlo, inseriamo la nostra funzione di costo e queste ipotesi iniziali in un ottimizzatore scipy `COBYLA`.\n",
        "\n",
        "![Grafico di ottimizzazione COBYLA](https://quantum.cloud.ibm.com/learning/images/courses/quantum-computing-in-practice/utility-scale-qaoa/COBYLA.avif)\n",
        "\n",
        "Qui si può vedere il valore della funzione di costo nel corso delle iterazioni. All'inizio è un po' strano, sale e scende, ma poi si stabilizza su un valore basso. Utilizzeremo i valori trovati da scipy che corrispondono alla valutazione più bassa della funzione di costo.\n",
        "\n",
        "Ora che siamo riusciti a ridurre la nostra funzione di costo individuando valori migliori per i nostri parametri, faremo funzionare il nostro circuito utilizzando i nuovi valori che abbiamo trovato per gamma e beta. Ho elencato qui i valori specifici che sto utilizzando, ma ricordate che, quando proverete a farlo voi stessi o anche solo quando rieseguirete lo stesso notebook del tutorial, questi valori potrebbero variare leggermente. Ora faremo funzionare il nostro circuito ottimizzato con questi valori e troveremo la soluzione candidata al nostro problema del taglio massimo.\n",
        "\n",
        "Nella fase di post-elaborazione, analizzeremo i dati e visualizzeremo i risultati per vedere se il nostro algoritmo quantistico ha trovato le soluzioni corrette.\n",
        "\n",
        "<span id=\"post-process\" />\n",
        "\n",
        "### Post-elaborazione\n",
        "\n",
        "Ora tracciamo un istogramma dei dati per osservare la soluzione finale:\n",
        "\n",
        "![Istogramma della soluzione Max-cut](https://quantum.cloud.ibm.com/learning/images/courses/quantum-computing-in-practice/utility-scale-qaoa/MaxcutHistogram.avif)\n",
        "\n",
        "Le stringhe di bit rappresentano il modo in cui ciascuno dei nodi è stato suddiviso in due gruppi (etichettati come \"0\" e \"1\") dal taglio. Dovrebbero esserci quattro soluzioni che danno tutte il valore massimo dei bordi tagliati. Questi quattro sono indicati in viola. Si nota subito che 4 soluzioni sono molto più probabili di tutte le altre. La soluzione di stringa di bit più alta, e quindi più probabile, è 0,1,0,1,1. (Ricordate: l'ordine dei qubit è invertito nelle stringhe di bit della trama)\n",
        "\n",
        "Da questo grafico, possiamo prendere la stringa di bit più probabile e rappresentarla come un grafico partizionato, con il taglio che passa attraverso cinque bordi:\n",
        "\n",
        "![Soluzione Max-cut](https://quantum.cloud.ibm.com/learning/images/courses/quantum-computing-in-practice/utility-scale-qaoa/MaxCutsolution.avif)\n",
        "\n",
        "Quindi, si tratta effettivamente di una soluzione \"max-cut\". Ma non è l'unico! Data la simmetria di questo grafico, esistono diverse soluzioni corrette. Invece di includere i nodi 0 e 3 nel taglio, potremmo includere i nodi 2 e 4. Come puoi vedere, mi è bastato ruotare il mio disegno per includere questi nuovi punti. Il numero di spigoli tagliati rimane cinque. Risulta che ci siano al massimo quattro soluzioni di taglio, poiché ciascuna delle due soluzioni che abbiamo osservato ha anche una controparte \"opposto\", in cui i nodi viola diventano grigi e quelli grigi diventano viola: il taglio rimane quindi lo stesso, ma ogni nodo passa di fatto al lato opposto della partizione.\n",
        "\n",
        "Diamo un'altra occhiata all'istogramma e alle quattro soluzioni più probabili. Idealmente, dovrebbero essere tutte e quattro le soluzioni di massimo taglio vere. Il problema è che l'algoritmo, in realtà, non ha individuato la quarta e ultima soluzione tra le prime quattro risposte più probabili. Era la quinta opzione più probabile. La quarta soluzione individuata dall'algoritmo è errata: se la disegnassi, vedresti che la soluzione presenta solo quattro tagli.\n",
        "\n",
        "Ma ricordate: si tratta di un algoritmo approssimativo. Non è infallibile e non è corretto il 100% delle volte. È necessario impiegare un po' della propria conoscenza e comprensione per verificare la correttezza delle soluzioni.\n",
        "\n",
        "Questo errore può derivare da diversi punti:\n",
        "\n",
        "1. Potrebbe essere la natura approssimativa dell'algoritmo stesso e il numero ridotto di livelli che ho impiegato.\n",
        "2. Potrebbe trattarsi di un errore di campionamento finito, che potrebbe essere ridotto se aumentassi il numero di scatti nel mio esperimento.\n",
        "3. Potrebbe anche trattarsi di un errore di lettura, dato che la quarta soluzione reale è sbagliata di un solo bit.\n",
        "\n",
        "Questo tipo di analisi degli errori è ciò che serve per diventare un professionista dell'informatica quantistica. È necessario comprendere le prestazioni dell'hardware e come questo possa contribuire a certi tipi di errori e come correggerli.\n",
        "\n",
        "Tuttavia, non dimentichiamo che c'erano 32 possibili sequenze di bit e che le quattro soluzioni reali erano comprese tra le prime cinque migliori candidate. E per arrivare a questa conclusione ci sono bastati solo due livelli. In generale, se volessimo aumentare le nostre possibilità di trovare ogni volta il max-cut ottimale, potremmo aumentare la profondità dello strato. Ci sono alcune sfumature da considerare, ma ne parleremo in una lezione successiva.\n",
        "\n",
        "<span id=\"at-utility-scale\" />\n",
        "\n",
        "## Su scala industriale\n",
        "\n",
        "Ora che avete avuto un assaggio di come si risolve un piccolo problema di max-cut su un computer quantistico, vi sfido a farlo su larga scala. Segui il [tutorial](/docs/tutorials/quantum-approximate-optimization-algorithm) al link per scoprire quanti tagli è possibile ottenere in un grafo a 125 nodi.\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": 5
}