L'algoritmo Deutsch-Jozsa
L'algoritmo di Deutsch supera tutti gli algoritmi classici per un problema di interrogazione, ma il vantaggio è piuttosto modesto: un'interrogazione contro due. L'algoritmo di Deutsch-Jozsa estende questo vantaggio e, di fatto, può essere utilizzato per risolvere un paio di problemi di interrogazione diversi.
Ecco una descrizione del circuito quantistico dell'algoritmo di Deutsch-Jozsa. A seconda del problema specifico da risolvere, può essere necessaria un'ulteriore fase di post-elaborazione classica, non mostrata nella figura.
Naturalmente, non abbiamo ancora discusso quali problemi risolve questo algoritmo; lo faremo nelle due sezioni successive.
Il problema Deutsch-Jozsa
Inizieremo con il problema di interrogazione che l'algoritmo Deutsch-Jozsa era originariamente destinato a risolvere, noto come problema Deutsch-Jozsa.
La funzione di input per questo problema ha la forma per un numero intero positivo arbitrario Come nel problema di Deutsch, il compito consiste nell'emettere se è costante e se è bilanciato, il che significa ancora una volta che il numero di stringhe di input su cui la funzione assume il valore è uguale al numero di stringhe di input su cui la funzione assume il valore .
Si noti che, quando è più grande di , esistono funzioni della forma che non sono né costanti né bilanciate. Ad esempio, la funzione definita come
non rientra in nessuna delle due categorie. Per il problema di Deutsch-Jozsa, semplicemente non ci preoccupiamo di funzioni come questa: sono considerate ingressi "non importanti". Cioè, per questo problema abbiamo la promessa che sia costante o equilibrato.
Ingresso: una funzione \ Promessa: è costante o bilanciato \ Output: se è costante, se è bilanciata
L'algoritmo di Deutsch-Jozsa, con la sua singola query, risolve questo problema nel senso seguente: se tutti i risultati delle misurazioni sono , allora la funzione è costante; altrimenti, se almeno uno dei risultati delle misurazioni è , allora la funzione è bilanciata. In altre parole, il circuito sopra descritto è seguito da una fase di post-elaborazione classica in cui viene calcolata la somma logica (OR) dei risultati delle misurazioni per ottenere il bit di uscita del problema di Deutsch-Jozsa.
Analisi dell'algoritmo
Per analizzare le prestazioni dell'algoritmo di Deutsch-Jozsa per il problema di Deutsch-Jozsa, è utile iniziare pensando all'azione di un singolo strato di porte di Hadamard. Un'operazione di Hadamard può essere espressa come una matrice nel modo consueto,
ma possiamo anche esprimere questa operazione in termini di azione sugli stati base standard:
Queste due equazioni possono essere combinate in un'unica formula,
che è vero per entrambe le scelte di
Supponiamo ora che invece di un solo qubit abbiamo qubit e che su ognuno di essi venga eseguita un'operazione di Hadamard. L'operazione combinata sui qubit è descritta dal prodotto tensoriale ( volte), che per concisione e chiarezza scriviamo come . Utilizzando la formula precedente, seguita da un'espansione e da una semplificazione, possiamo esprimere l'azione di questa operazione combinata sugli stati base standard dei qubit di in questo modo:
Qui, tra l'altro, stiamo scrivendo stringhe binarie di lunghezza come e seguendo la convenzione di indicizzazione di Qiskit.
Questa formula ci fornisce un utile strumento per analizzare il circuito quantistico di cui sopra. Dopo l'esecuzione del primo strato di porte di Hadamard, lo stato dei qubit di (compreso il qubit più a sinistra/inferiore, che viene trattato separatamente dal resto) è
Quando viene eseguita l'operazione , questo stato viene trasformato in
attraverso lo stesso fenomeno di contraccolpo di fase che abbiamo visto nell'analisi dell'algoritmo di Deutsch.
Quindi viene eseguito il secondo strato di porte di Hadamard, che (in base alla formula precedente) trasforma questo stato in
Questa espressione sembra un po' complicata e non si può concludere molto sulle probabilità di ottenere risultati di misura diversi senza conoscere meglio la funzione
Fortunatamente, tutto ciò che dobbiamo sapere è la probabilità che ognuno dei risultati della misurazione sia - perché questa è la probabilità che l'algoritmo determini che è costante. Questa probabilità ha una formula semplice.
Si noti che questi valori corrispondono alla probabilità di misurare lo stato , piuttosto che direttamente al bit di output classico finale del problema di Deutsch-Jozsa. L'algoritmo restituisce " " quando tutti i risultati delle misurazioni sono " " (a indicare che " " è costante) e restituisce " " in caso contrario (a indicare che " " è bilanciato).
Più in dettaglio, se è costante, allora o per ogni stringa nel qual caso il valore della somma è oppure per ogni stringa nel qual caso il valore della somma è Dividendo per e prendendo il quadrato del valore assoluto si ottiene
Se invece è bilanciato, allora assume il valore su metà delle stringhe e il valore sull'altra metà, quindi i termini e della somma si annullano e rimane il valore
Concludiamo che l'algoritmo funziona correttamente a condizione che la promessa sia mantenuta.
Difficoltà classica
L'algoritmo di Deutsch-Jozsa funziona sempre, ci dà sempre la risposta corretta quando la promessa è soddisfatta e richiede una sola interrogazione. Come si confronta con gli algoritmi di interrogazione classici per il problema di Deutsch-Jozsa?
In primo luogo, qualsiasi algoritmo deterministico classico che risolva correttamente il problema di Deutsch-Jozsa deve effettuare un numero esponenziale di interrogazioni: nel caso peggiore, sono necessarie molte interrogazioni. Il ragionamento è che, se un algoritmo deterministico interroga su o meno stringhe diverse, e ottiene ogni volta lo stesso valore di funzione, allora entrambe le risposte sono ancora possibili. La funzione potrebbe essere costante o bilanciata, ma per sfortuna le query restituiscono tutte lo stesso valore della funzione.
La seconda possibilità potrebbe sembrare improbabile, ma per gli algoritmi deterministici non c'è casualità o incertezza, quindi falliranno sistematicamente su alcune funzioni. A questo proposito, abbiamo quindi un vantaggio significativo degli algoritmi quantistici rispetto a quelli classici.
C'è però una fregatura: gli algoritmi classici probabilistici possono risolvere il problema di Deutsch-Jozsa con una probabilità molto alta, utilizzando solo poche query. In particolare, se scegliamo a caso alcune stringhe diverse di lunghezza e interroghiamo su queste stringhe, è improbabile che otterremo lo stesso valore di funzione per tutte quando è bilanciato.
Per essere precisi, se scegliamo stringhe di input in modo uniformemente casuale, valutiamo e rispondiamo se i valori della funzione sono tutti uguali, e in caso contrario, allora saremo sempre corretti quando è costante, e sbagliati nel caso in cui sia bilanciato con probabilità appena superiore a % Se prendiamo ad esempio , questo algoritmo risponderà correttamente con una probabilità maggiore di %.
Per questo motivo, abbiamo ancora un vantaggio piuttosto modesto degli algoritmi quantistici rispetto a quelli classici, ma si tratta comunque di un vantaggio quantificabile che rappresenta un miglioramento rispetto all'algoritmo di Deutsch.
Deutsch-Jozsa con Qiskit
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
import numpy as npPer implementare l'algoritmo di Deutsch-Jozsa in Qiskit, inizieremo definendo una funzione dj_query che genera un circuito quantistico che implementa un query gate, per una funzione scelta a caso che soddisfa la promessa per il problema di Deutsch-Jozsa.
Con una probabilità del 50%, la funzione è costante, mentre con una variazione del 50% la funzione è bilanciata.
Per ognuna di queste due possibilità, la funzione viene selezionata in modo uniforme tra le funzioni di quel tipo.
L'argomento è il numero di bit di ingresso della funzione.
def dj_query(num_qubits):
# Create a circuit implementing for a query gate for a random function
# satisfying the promise for the Deutsch-Jozsa problem.
qc = QuantumCircuit(num_qubits + 1)
if np.random.randint(0, 2):
# Flip output qubit with 50% chance
qc.x(num_qubits)
if np.random.randint(0, 2):
# return constant circuit with 50% chance
return qc
# Choose half the possible input strings
on_states = np.random.choice(
range(2**num_qubits), # numbers to sample from
2**num_qubits // 2, # number of samples
replace=False, # makes sure states are only sampled once
)
def add_cx(qc, bit_string):
for qubit, bit in enumerate(reversed(bit_string)):
if bit == "1":
qc.x(qubit)
return qc
for state in on_states:
qc.barrier() # Barriers are added to help visualize how the functions are created.
qc = add_cx(qc, f"{state:0b}")
qc.mcx(list(range(num_qubits)), num_qubits)
qc = add_cx(qc, f"{state:0b}")
qc.barrier()
return qcPossiamo mostrare l'implementazione del circuito quantistico della porta di interrogazione utilizzando il metodo draw come di consueto.
display(dj_query(3).draw(output="mpl"))Output:
Definiamo poi una funzione che crea il circuito di Deutsch-Jozsa, prendendo come argomento un'implementazione del circuito quantistico di un query gate.
def compile_circuit(function: QuantumCircuit):
# Compiles a circuit for use in the Deutsch-Jozsa algorithm.
n = function.num_qubits - 1
qc = QuantumCircuit(n + 1, n)
qc.x(n)
qc.h(range(n + 1))
qc.compose(function, inplace=True)
qc.h(range(n))
qc.measure(range(n), range(n))
return qcInfine, viene definita una funzione che esegue una volta il circuito Deutsch-Jozsa.
def dj_algorithm(function: QuantumCircuit):
# Determine if a function is constant or balanced.
qc = compile_circuit(function)
result = AerSimulator().run(qc, shots=1, memory=True).result()
measurements = result.get_memory()
if "1" in measurements[0]:
return "balanced"
return "constant"Possiamo testare la nostra implementazione scegliendo una funzione a caso, visualizzando l'implementazione del circuito quantistico di una porta di interrogazione per questa funzione e poi eseguendo l'algoritmo di Deutsch-Jozsa su quella funzione.
f = dj_query(3)
display(f.draw("mpl"))
display(dj_algorithm(f))Output:
'balanced'
Il problema di Bernstein-Vazirani
Successivamente, discuteremo un problema noto come problema di Bernstein-Vazirani. È anche chiamato problema del campionamento di Fourier, sebbene esistano formulazioni più generali di questo problema che vanno anche sotto questo nome.
Per prima cosa, introduciamo alcune notazioni. Per due stringhe binarie qualsiasi e di lunghezza definiamo
Questa operazione viene chiamata prodotto binario dei punti. Un modo alternativo per definirlo è il seguente.
Si noti che si tratta di un'operazione simmetrica, il che significa che il risultato non cambia se si scambiano e , quindi siamo liberi di farlo ogni volta che è conveniente. A volte è utile pensare al prodotto binario dei punti come alla parità dei bit di nelle posizioni in cui la stringa ha un o, equivalentemente, alla parità dei bit di nelle posizioni in cui la stringa ha un
Con questa notazione in mano possiamo ora definire il problema di Bernstein-Vazirani.
Input: una funzione \ Promessa: esiste una stringa binaria per la quale per tutte le \ Uscita: la stringa
In realtà non abbiamo bisogno di un nuovo algoritmo quantistico per questo problema; l'algoritmo di Deutsch-Jozsa lo risolve. Per chiarezza, chiamiamo il circuito quantistico di cui sopra, che non include la fase classica di post-elaborazione del calcolo dell'OR, circuito Deutsch-Jozsa.
Analisi dell'algoritmo
Per analizzare come funziona il circuito di Deutsch-Jozsa per una funzione che soddisfa la promessa del problema di Bernstein-Vazirani, inizieremo con una rapida osservazione. Utilizzando il prodotto binario dei punti, possiamo descrivere alternativamente l'azione delle porte di Hadamard di sugli stati base standard dei qubit di come segue.
Analogamente a quanto abbiamo visto analizzando l'algoritmo di Deutsch, questo è dovuto al fatto che il valore per qualsiasi intero dipende solo dal fatto che sia pari o dispari.
Passando al circuito di Deutsch-Jozsa, dopo che è stato eseguito il primo strato di porte di Hadamard, lo stato dei qubit di è
Viene quindi eseguito il gate di interrogazione, che (attraverso il fenomeno del contraccolpo di fase) trasforma lo stato in
Utilizzando la nostra formula per l'azione di uno strato di porte di Hadamard, vediamo che il secondo strato di porte di Hadamard trasforma poi questo stato in
Ora possiamo fare alcune semplificazioni, nell'esponente di all'interno della somma. Ci è stato promesso che per qualche stringa in modo da poter esprimere lo stato come
Poiché e sono valori binari, possiamo sostituire l'addizione con l'OR esclusivo - sempre perché l'unica cosa che conta per un intero nell'esponente di è che sia pari o dispari. Sfruttando la simmetria del prodotto binario dei punti, si ottiene questa espressione per lo stato:
(Le parentesi sono state aggiunte per chiarezza, anche se in realtà non sono necessarie perché è convenzionale trattare il prodotto binario dei punti come se avesse una precedenza maggiore rispetto all'OR esclusivo)
A questo punto utilizzeremo la seguente formula.
Possiamo ottenere la formula attraverso una formula simile per i bit,
insieme a un'espansione del prodotto binario dei punti e del bitwise exclusive-OR:
Questo ci permette di esprimere lo stato del circuito immediatamente prima delle misure in questo modo:
Il passo finale consiste nell'utilizzare un'altra formula, che funziona per ogni stringa binaria
Qui usiamo una semplice notazione per le stringhe che useremo più volte nel corso della lezione: è la stringa di lunghezza pari a zero
Un modo semplice per dimostrare che questa formula funziona è considerare i due casi separatamente. Se allora per ogni stringa quindi il valore di ogni termine della somma è e si ottiene sommando e dividendo per D'altra parte, se uno qualsiasi dei bit di è uguale a allora il prodotto binario dei punti è uguale a per esattamente la metà delle scelte possibili per e per l'altra metà - perché il valore del prodotto binario dei punti si capovolge (da a o da a ) se capovolgiamo un qualsiasi bit di in una posizione in cui ha una
Se ora applichiamo questa formula per semplificare lo stato del circuito prima delle misure, otteniamo
perché se e solo se Pertanto, le misure rivelano proprio la stringa che stiamo cercando.
Difficoltà classica
Mentre il circuito Deutsch-Jozsa risolve il problema di Bernstein-Vazirani con una sola interrogazione, qualsiasi algoritmo di interrogazione classico deve effettuare almeno interrogazioni per risolvere questo problema.
Si può ragionare attraverso un cosiddetto argomento di teoria dell'informazione, che in questo caso è molto semplice. Ogni interrogazione classica rivela un singolo bit di informazione sulla soluzione, e ci sono bit di informazione che devono essere scoperti, quindi sono necessarie almeno interrogazioni.
È infatti possibile risolvere il problema di Bernstein-Vazirani in modo classico, interrogando la funzione su ciascuna delle stringhe che hanno un singolo in ogni possibile posizione, e per tutti gli altri bit, che rivela i bit di uno alla volta. Pertanto, il vantaggio degli algoritmi quantistici rispetto a quelli classici per questo problema è query rispetto a query.
Bernstein-Vazirani con Qiskit
Abbiamo già implementato il circuito di Deutsch-Jozsa sopra, e qui lo useremo per risolvere il problema di Bernstein-Vazirani. Per prima cosa definiremo una funzione che implementa una porta di interrogazione per il problema di Bernstein-Vazirani, data una qualsiasi stringa binaria
def bv_query(s):
# Create a quantum circuit implementing a query gate for the
# Bernstein-Vazirani problem.
qc = QuantumCircuit(len(s) + 1)
for index, bit in enumerate(reversed(s)):
if bit == "1":
qc.cx(index, len(s))
return qc
display(bv_query("1011").draw(output="mpl"))Output:
Ora possiamo creare una funzione che esegua il circuito Deutsch-Jozsa sulla funzione, utilizzando la funzione compile_circuit definita in precedenza.
def bv_algorithm(function: QuantumCircuit):
qc = compile_circuit(function)
result = AerSimulator().run(qc, shots=1, memory=True).result()
return result.get_memory()[0]
display(bv_algorithm(bv_query("1011")))Output:
'1011'
Osservazione sulla nomenclatura
Nel contesto del problema di Bernstein-Vazirani, è comune che l'algoritmo di Deutsch-Jozsa sia indicato come "algoritmo di Bernstein-Vazirani" Questo è leggermente fuorviante, perché l'algoritmo è l'algoritmo di Deutsch-Jozsa, come Bernstein e Vazirani hanno detto chiaramente nel loro lavoro.
Dopo aver dimostrato che l'algoritmo di Deutsch-Jozsa risolve il problema di Bernstein-Vazirani (come si è detto), Bernstein e Vazirani hanno definito un problema molto più complicato, noto come problema di campionamento ricorsivo di Fourier. Si tratta di un problema altamente congegnato in cui le soluzioni alle diverse istanze del problema sbloccano effettivamente nuovi livelli del problema disposti in una struttura ad albero. Il problema di Bernstein-Vazirani è essenzialmente solo il caso base di questo problema più complicato.
Il problema del campionamento ricorsivo di Fourier è stato il primo esempio conosciuto di problema di interrogazione in cui gli algoritmi quantistici hanno un vantaggio cosiddetto super-polinomiale rispetto agli algoritmi probabilistici, superando così il vantaggio dei quanti rispetto ai classici offerto dall'algoritmo di Deutsch-Jozsa. Intuitivamente, la versione ricorsiva del problema amplifica il vantaggio di rispetto a degli algoritmi quantistici a qualcosa di molto più grande.
L'aspetto più impegnativo dell'analisi matematica che stabilisce questo vantaggio è dimostrare che gli algoritmi di interrogazione classici non possono risolvere il problema senza effettuare molte interrogazioni. Questo è abbastanza tipico; per molti problemi può essere molto difficile escludere approcci classici creativi che li risolvano in modo efficiente.
Il problema di Simon, e l'algoritmo per esso descritto nella prossima sezione, fornisce un esempio molto più semplice di un vantaggio super-polinomiale (e, di fatto, esponenziale) degli algoritmi quantistici rispetto a quelli classici, e per questo motivo il problema del campionamento ricorsivo di Fourier viene discusso meno spesso. Si tratta comunque di un interessante problema computazionale a sé stante.