Ansaetze e forme variazionali
Alla base di tutti gli algoritmi variazionali c'è l'idea chiave di analizzare le differenze tra gli stati, che sono convenientemente correlati attraverso una qualche mappatura ben educata (ad esempio, continua, differenziabile) da un insieme di parametri o variabili - da cui il nome.
In primo luogo, esploreremo come costruire circuiti parametrizzati a mano. Utilizzeremo questi circuiti per definire un Strati di porte parametrizzate che vengono ripetute un certo numero di volte; i parametri delle porte vengono ottimizzati durante l'algoritmo per minimizzare la funzione di costo. che rappresenta un insieme di stati parametrati da esplorare con il nostro algoritmo variazionale. Quindi, costruiremo il nostro Combinazione di un operatore di riferimento e di una forma variazionale, per descrivere lo spazio di ricerca che stiamo esplorando. applicando questa forma variazionale al nostro stato di riferimento.
Esploreremo anche il modo in cui si può trovare un compromesso tra velocità e accuratezza durante l'esplorazione di questo spazio di ricerca.
Circuiti quantistici parametrizzati
Gli algoritmi variazionali operano esplorando e confrontando una serie di stati quantistici , che dipendono da un insieme finito di parametri . Questi stati possono essere preparati utilizzando un circuito quantistico parametrizzato, in cui le porte sono definite con parametri sintonizzabili. È possibile creare questo circuito parametrizzato senza vincolare angoli specifici:
from qiskit.circuit import QuantumCircuit, Parameter
theta = Parameter("θ")
qc = QuantumCircuit(3)
qc.rx(theta, 0)
qc.cx(0, 1)
qc.x(2)
qc.draw("mpl")Output:
from math import pi
angle_list = [pi / 3, pi / 2]
circuits = [qc.assign_parameters({theta: angle}) for angle in angle_list]
for circuit in circuits:
display(circuit.draw("mpl"))Output:
Forma variazionale e Ansatz
Per ottimizzare iterativamente da uno stato di riferimento a uno stato obiettivo , dobbiamo definire una forma variazionale che rappresenti un insieme di stati parametrizzati che il nostro algoritmo variazionale può esplorare:
Si noti che lo stato parametrizzato dipende sia dallo stato di riferimento , che non dipende da alcun parametro, sia dalla forma variazionale , che dipende sempre da parametri. Ci riferiamo alla combinazione di queste due metà come ad un ansatz: .
Mentre costruiamo il nostro ansatz per rappresentare una collezione di stati parametrizzati da esplorare con il nostro algoritmo variazionale, ci rendiamo conto di un problema importante: la dimensionalità. Un sistema -qubit (cioè uno spazio di Hilbert) ha un numero enorme di stati quantici distinti nello spazio di configurazione. Avremmo bisogno di un numero ingombrante di parametri per esplorarlo completamente. Quantitativamente, la sua dimensionalità è . Come se non bastasse, la complessità del tempo di esecuzione degli algoritmi di ricerca e di altri algoritmi cresce esponenzialmente con questa dimensionalità, un fenomeno spesso indicato in letteratura come maledizione della dimensionalità.
Per ovviare a questo inconveniente, è prassi comune imporre alcuni vincoli ragionevoli sulla forma variazionale, in modo da esplorare solo gli stati più rilevanti. La ricerca di un'ansatz troncata efficiente è un'area di ricerca attiva, ma noi ci occuperemo di due modelli comuni.
Approcci euristici e compromessi
Se non si dispone di informazioni sul problema specifico che possano aiutare a limitare la dimensionalità, si può provare una famiglia arbitraria di circuiti parametrizzati con meno di parametri. Tuttavia, ci sono alcuni compromessi da considerare:
- Velocità : riducendo lo spazio di ricerca, l'algoritmo può funzionare più velocemente.
- Accuratezza : La riduzione dello spazio potrebbe rischiare di escludere la soluzione effettiva del problema, portando a soluzioni non ottimali.
- Rumore : I circuiti più profondi sono influenzati dal rumore, quindi dobbiamo sperimentare la connettività, le porte e la fedeltà delle porte del nostro ansatz.
Esiste un compromesso fondamentale tra qualità (o addirittura risolvibilità) e velocità: maggiore è il numero di parametri, maggiore è la probabilità di trovare un risultato preciso, ma maggiore sarà il tempo necessario per eseguire l'algoritmo.
Circuiti N-locali
Uno degli esempi più utilizzati di ansaetze euristiche è quello dei circuiti N-locali, per alcune ragioni:
- Implementazione efficiente : L'ansatz N-locale è tipicamente composto da semplici porte locali che possono essere implementate in modo efficiente su un computer quantistico, utilizzando un piccolo numero di qubit fisici. In questo modo è più facile costruire e ottimizzare i circuiti quantistici.
- Cattura correlazioni importanti : L'ansatz N-locale può catturare importanti correlazioni tra i qubit di un sistema quantistico, anche con un numero ridotto di porte. Questo perché le porte locali possono agire su qubit vicini e creare entanglement tra di loro, il che può essere importante per simulare sistemi quantistici complessi.
Questi circuiti sono costituiti da strati di rotazione e di entanglement che si ripetono alternativamente una o più volte come segue:
- Ogni strato è formato da porte di dimensione massima , dove deve essere inferiore al numero di qubit.
- Per uno strato di rotazione, le porte sono impilate l'una sull'altra. Possiamo usare le operazioni di rotazione standard, come
RXoCRZ. - Per un livello di entanglement, si possono usare porte come
Toffoligates oCXcon una strategia di entanglement. - Entrambi i tipi di livelli possono essere parametrizzati o meno, ma almeno uno di essi deve contenere dei parametri. Altrimenti, senza almeno un parametro, non ci sarebbero variazioni!
- In alternativa, all'estremità del circuito viene aggiunto un ulteriore strato di rotazione.
Ad esempio, creiamo un circuito a cinque qubit NLocal con blocchi di rotazione formati da RX e CRZ blocchi di rotazione, blocchi di entanglement formati da Toffoli porte che agiscono sui qubit , , e e ripetizioni di ogni strato.
from qiskit.circuit.library import NLocal, CCXGate, CRZGate, RXGate
from qiskit.circuit import Parameter
theta = Parameter("θ")
ansatz = NLocal(
num_qubits=5,
rotation_blocks=[RXGate(theta), CRZGate(theta)],
entanglement_blocks=CCXGate(),
entanglement=[[0, 1, 2], [0, 2, 3], [4, 2, 1], [3, 1, 0]],
reps=2,
insert_barriers=True,
)
ansatz.decompose().draw("mpl")Output:
Nell'esempio precedente, il gate più grande è il gate di Toffoli, che agisce su tre qubit, rendendo il circuito -locale. I circuiti locali più comunemente utilizzati sono i circuiti locali con porte di rotazione a singolo qubit e porte di entanglement a qubit.
Creiamo un circuito -locale utilizzando la classe Qiskit TwoLocal qiskit. La sintassi è la stessa di NLocal, ma ci sono alcune differenze. Ad esempio, la maggior parte dei gate, come RX, RZ, e CNOT, possono essere passati come stringhe senza importare i gate o creare un'istanza di Parameter .
from qiskit.circuit.library import TwoLocal
ansatz = TwoLocal(
num_qubits=5,
rotation_blocks=["rx", "rz"],
entanglement_blocks="cx",
entanglement="linear",
reps=2,
insert_barriers=True,
)
ansatz.decompose().draw("mpl")Output:
In questo caso, abbiamo utilizzato la distribuzione lineare dell'entanglement, in cui ogni qubit è entangled con il successivo. Per conoscere altre strategie, fare riferimento a TwoLocal documentazione.
SU2 efficiente
efficient_su2 è un circuito efficiente dal punto di vista hardware che consiste in strati di operazioni a singolo qubit che abbracciano SU(2) e CX entanglements. Si tratta di un modello euristico che può essere utilizzato per preparare funzioni d'onda di prova per algoritmi quantistici variazionali o come circuito di classificazione per l'apprendimento automatico.
from qiskit.circuit.library import efficient_su2
ansatz = efficient_su2(4, su2_gates=["rx", "y"], entanglement="linear", reps=1)
ansatz.decompose().draw("mpl")Output:
Approcci specifici al problema
Mentre le soluzioni euristiche e quelle efficienti dal punto di vista dell'hardware ci aiutano a risolvere un problema in modo ingenuo, possiamo utilizzare le conoscenze specifiche del problema per limitare lo spazio di ricerca dei circuiti a un tipo specifico. Questo ci aiuterà a guadagnare velocità senza perdere precisione nel processo di ricerca.
Ottimizzazione
In un problema di max-cut, si vuole suddividere i nodi di un grafo in modo da massimizzare il numero di bordi tra nodi di gruppi diversi. La partizione max-cut desiderata per il grafo sottostante è chiara: il nodo 0 a sinistra deve essere separato dal resto dei nodi a destra da un taglio.
import rustworkx as rx
from rustworkx.visualization import mpl_draw
n = 4
G = rx.PyGraph()
G.add_nodes_from(range(n))
# The edge syntax is (start, end, weight)
edges = [(0, 1, 1.0), (0, 2, 1.0), (0, 3, 1.0), (1, 2, 1.0), (2, 3, 1.0)]
G.add_edges_from(edges)
mpl_draw(
G, pos=rx.shell_layout(G), with_labels=True, edge_labels=str, node_color="#1192E8"
)Output:
Per utilizzare l'algoritmo QAOA per un problema di max-cut, è necessario un Hamiltoniano di Pauli che codifichi il costo in modo tale che il valore minimo di aspettativa dell'operatore corrisponda al numero massimo di bordi tra i nodi di due gruppi diversi.
Per questo semplice esempio, l'operatore è una combinazione lineare di termini con operatori Z su nodi collegati da un bordo (ricordiamo che il qubit 0 è il più lontano a destra): . Una volta costruito l'operatore, l'ansatz per l'algoritmo QAOA può essere facilmente costruito utilizzando il circuito QAOAAnsatz dalla libreria di circuiti Qiskit.
# Pre-defined ansatz circuit, operator class and visualization tools
from qiskit.circuit.library import QAOAAnsatz
from qiskit.quantum_info import SparsePauliOp
# Problem to Hamiltonian operator
hamiltonian = SparsePauliOp.from_list(
[("ZZII", 1), ("IZZI", 1), ("ZIIZ", 1), ("IZIZ", 1), ("IIZZ", 1)]
)
# QAOA ansatz circuit
ansatz = QAOAAnsatz(hamiltonian, reps=2)
# Draw
ansatz.decompose(reps=3).draw("mpl")Output:
L'immagine precedente illustra per chiarezza l'ansatz in porte di base. Tuttavia, può essere espresso in più livelli di decomposizione cambiando l'argomento reps o disegnando il circuito senza il metodo di decomposizione. Ad esempio, la seguente rappresentazione mostra direttamente la struttura QAOA con il valore predefinito di reps, che è reps=1.
ansatz.decompose(reps=2).draw("mpl")Output:
Quantum Machine Learning
Nell'apprendimento automatico, un'applicazione comune è la classificazione dei dati in due o più categorie. Ciò implica la codifica di un punto dati in una mappa di caratteristiche che mappa i vettori di caratteristiche classiche nello spazio di Hilbert quantistico. La costruzione di mappe di caratteristiche quantistiche basate su circuiti quantistici parametrizzati, difficili da simulare classicamente, è un passo importante per ottenere un potenziale vantaggio rispetto agli approcci classici di apprendimento automatico ed è un'area attiva di ricerca attuale.
Il sito zz_feature_map può essere utilizzato per creare un circuito parametrizzato. Possiamo passare i nostri punti dati alla mappa delle caratteristiche ( ) e una forma variazionale separata per passare i pesi come parametri ( ).
from qiskit.circuit.library import zz_feature_map, TwoLocal
data = [0.1, 0.2]
zz_feature_map_reference = zz_feature_map(feature_dimension=2, reps=2)
zz_feature_map_reference = zz_feature_map_reference.assign_parameters(data)
variation_form = TwoLocal(2, ["ry", "rz"], "cz", reps=2)
vqc_ansatz = zz_feature_map_reference.compose(variation_form)
vqc_ansatz.decompose().draw("mpl")Output:
Riepilogo
In questa lezione avete imparato a definire lo spazio di ricerca con una forma variazionale:
- Preparare stati con un circuito quantistico parametrizzato, in cui le porte sono definite con parametri sintonizzabili
- Come costruire analisi che compromettano velocità e accuratezza
- Ansaetze euristiche
- Ansaetze specifiche per i problemi
Il nostro carico di lavoro variazionale di alto livello si presenta come segue:
Per ogni parametro variazionale , verrà prodotto uno stato quantico diverso. Per trovare i parametri ottimali, dobbiamo definire una funzione di costo specifica per il problema per aggiornare iterativamente i parametri del nostro ansatz.