Skip to main content
IBM Quantum Platform

Compilatore quantistico approssimativo

qiskit.synthesis.unitary.aqc

Implementazione del compilatore quantistico approssimativo descritto nell'articolo [1].


Interfaccia

L'interfaccia pubblica principale di questo modulo si raggiunge passando unitary_synthesis_method='aqc' a transpile(). In questo modo si cambia il metodo di sintesi per utilizzare AQCSynthesisPlugin. Le singole classi sono:

AQC( [ottimizzatore, seme] )Un'implementazione generica del compilatore quantistico approssimativo.
ApproximateCircuit(num_qubit[, nome] )Una classe base che rappresenta un circuito approssimativo.
ApproximatingObjective()Una classe di base per la definizione di un problema di ottimizzazione.
CNOTUnitCircuit(num_qubit, cnot[, tol, nome] )Una classe che rappresenta un circuito approssimato basato su blocchi di unità CNOT.
CNOTUnitObjective(num_qubit, cnodi)Una classe base per la definizione di un problema basato sull'unità CNOT.
DefaultCNOTUnitObjective(num_qubit, cnodi)Un'implementazione ingenua della funzione obiettivo basata sulle unità CNOT.
FastCNOTUnitObjective(num_qubit, cnodi)Implementazione della funzione obiettivo e del calcolatore del gradiente, simile a DefaultCNOTUnitObjective ma più veloce.

Dettagli matematici

Siamo interessati alla compilazione di un circuito quantistico, che formalizziamo come la ricerca della migliore rappresentazione del circuito in termini di una sequenza ordinata di gate di una matrice unitaria target UU(d)U\in U(d), con alcuni vincoli hardware aggiuntivi. In particolare, esaminiamo le rappresentazioni che potrebbero essere vincolate in termini di connettività hardware e di profondità del gate e scegliamo una base di gate in termini di CNOT e di gate di rotazione. Ricordiamo che la combinazione di CNOT e porte di rotazione è universale in SU(d)SU(d) e quindi non limita la compilazione.

Per definire correttamente cosa intendiamo per "migliore rappresentazione del circuito", definiamo la metrica come la norma di Frobenius tra la matrice unitaria del circuito compilato VV e la matrice unitaria di riferimento UU, ovvero VUF\|V - U\|_{\mathrm{F}}. Questa scelta è motivata da considerazioni di programmazione matematica ed è correlata ad altre formulazioni presenti in letteratura. Analizziamo il problema più nel dettaglio.

Sia nn il numero di qubit e d=2nd=2^n. Data una struttura CNOT ctct e un vettore di angoli di rotazione θ\theta, il circuito parametrico forma una matrice Vct(θ)SU(d)Vct(\theta)\in SU(d). Se ci viene dato un circuito di destinazione che forma una matrice USU(d)U\in SU(d), allora vorremmo calcolare

argmaxθ1dVct(θ),U\mathrm{argmax}_{\theta}\frac{1}{d}|\langle Vct(\theta),U\rangle|

dove il prodotto interno è il prodotto interno di Frobenius. Si noti che V,Ud|\langle V,U\rangle|\leq d per tutti gli unitari UU e VV, quindi l'obiettivo ha campo in [0,1][0,1].

La nostra strategia consiste nel massimizzare

1dVct(θ),U\frac{1}{d}\Re \langle Vct(\theta),U\rangle

utilizzando il suo gradiente. Ne discuteremo ora le caratteristiche specifiche con un esempio.

Mentre l'intervallo di VctVct è un sottoinsieme di SU(d)SU(d) per costruzione, il circuito di destinazione può formare una matrice unitaria generale. Tuttavia, per qualsiasi UU(d)U\in U(d),

exp(2πik/d)det(U)1/dUSU(d) for all k{0,,d1}.\frac{\exp(2\pi i k/d)}{\det(U)^{1/d}}U\in SU(d)\text{ for all }k\in\{0,\ldots,d-1\}.

Pertanto, dovremmo normalizzare il circuito di destinazione in base alla sua fase globale e poi compilare approssimativamente il circuito normalizzato. Possiamo aggiungere la fase globale in seguito.

Nell'algoritmo, UU' indica la matrice target non normalizzata e UU la matrice target normalizzata. Ora che abbiamo UU, diamo la funzione gradiente all'ottimizzatore del metodo di Nesterov e calcoliamo θ\theta.

Per aggiungere nuovamente la fase globale, possiamo formare il circuito di controllo come segue

Vct(θ),UVct(θ),UVct(θ).\frac{\langle Vct(\theta),U'\rangle}{|\langle Vct(\theta),U'\rangle|}Vct(\theta).

Si noti che nel documento abbiamo ottimizzato utilizzando il metodo di Nesterov, ma per le sue garanzie di convergenza e non per la sua velocità nella pratica. È molto più veloce utilizzare L-BFGS, che viene utilizzato come ottimizzatore predefinito in questa implementazione.

Un utilizzo di base dell'algoritmo AQC dovrebbe consistere nei seguenti passaggi:

# Define a target circuit as a unitary matrix
unitary = ...

# Define a number of qubits for the algorithm, at least 3 qubits
num_qubits = round(math.log2(unitary.shape[0]))

# Choose a layout of the CNOT structure for the approximate circuit, e.g. ``spin`` for
# a linear layout.
layout = options.get("layout") or "spin"

# Choose a connectivity type, e.g. ``full`` for full connectivity between qubits.
connectivity = options.get("connectivity") or "full"

# Define a targeted depth of the approximate circuit in the number of CNOT units.
depth = int(options.get("depth") or 0)

# Generate a network made of CNOT units
cnots = make_cnot_network(
    num_qubits=num_qubits,
    network_layout=layout,
    connectivity_type=connectivity,
    depth=depth
)

# Create an optimizer to be used by AQC
optimizer = partial(scipy.optimize.minimize, method="L-BFGS-B")

# Create an instance
aqc = AQC(optimizer)

# Create a template circuit that will approximate our target circuit
approximate_circuit = CNOTUnitCircuit(num_qubits=num_qubits, cnots=cnots)

# Create an objective that defines our optimization problem
approximating_objective = DefaultCNOTUnitObjective(num_qubits=num_qubits, cnots=cnots)

# Run optimization process to compile the unitary
aqc.compile_unitary(
    target_matrix=unitary,
    approximate_circuit=approximate_circuit,
    approximating_objective=approximating_objective
)

Ora approximate_circuit è un circuito che approssima l'unitario target a un certo grado e può essere utilizzato al posto della matrice originale.

Utilizza una funzione ausiliaria, make_cnot_network.

make_cnot_network

qiskit.synthesis.unitary.aqc.make_cnot_network(num_qubits, network_layout='spin', connectivity_type='full', depth=0)

GitHub

Genera una rete composta da blocchi di edifici contenenti ciascuno una porta CNOT ed eventualmente alcune porte a singolo qubit. Questa rete modella un operatore quantistico in questione. Si noti che ogni blocco costruttivo ha 2 ingressi e uscite corrispondenti a una coppia di qubit. Ciò che in realtà restituiamo è una catena di indici di coppie di qubit condivisi da ogni blocco di edifici in una fila.

Parametri

  • num_qubits (int) – numero di qubit.
  • network_layout (str) – tipo di geometria della rete, {"sequ", "spin", "cart", "cyclic_spin", "cyclic_line"}.
  • connectivity_type (str) – tipo di connettività inter-qubit, {"full", "line", "star"}.
  • depth (int) – profondità della rete CNOT, cioè il numero di strati, dove ogni strato è costituito da un singolo blocco CNOT; il valore predefinito viene selezionato se L <= 0.

Risultati

Una matrice di dimensioni (2, N) che definisce gli strati in cnot-network, dove N

è uguale a L, oppure è definito da un tipo concreto di rete.

Aumenti

ValueError - se viene passato un tipo di layout di rete CNOT non supportato o un numero di qubit o una combinazione di parametri non supportati.

Tipo di restituzione

ndarray

Si può sfruttare una versione accelerata della funzione obiettivo. Implementa lo stesso algoritmo matematico di quello predefinito DefaultCNOTUnitObjective , ma viene eseguito più velocemente. L'istanziazione della classe di funzioni obiettivo accelerate è simile al caso predefinito:

# Creare un obiettivo che definisca il nostro problema di ottimizzazione approximating_objective = FastCNOTUnitObjective(num_qubits=num_qubits, cnots=cnots)

Il resto del codice dell'esempio precedente non cambia.

Riferimenti

[1] : Liam Madden, Andrea Simonetto, Problemi di compilazione quantistica di miglior approssimazione.

arXiv:2106.05649

Questa pagina è stata utile?
Segnala un bug, un errore di battitura o richiedi contenuti su GitHub.