Comprendere le differenze tra le opzioni a guscio aperto e a guscio chiuso e il loro effetto sulla costruzione dei sottospazi
In questa guida illustreremo come scegliere le dimensioni del sottospazio nel qiskit_addon_sqd pacchetto per la post-elaborazione di campioni quantistici utilizzando la tecnica di recupero della configurazione auto-consistente.
Ma soprattutto, questa guida mette in evidenza alcune differenze nel comportamento della costruzione del sottospazio quando viene eseguita in open_shell = False modalità o open_shell = True :
-
open_shell = Falsefunziona solo quando il numero di elettroni in fase di accelerazione e di decelerazione è lo stesso. -
open_shell = Truedeve essere utilizzato quando il numero di elettroni in fase di accelerazione e di decelerazione è diverso. Può essere utilizzato anche quando il numero di elettroni in fase di accelerazione e di decelerazione è lo stesso. Tuttavia, in quest’ultimo caso, vi è una differenza nelle dimensioni dei sottospazi generati traopen_shell = Falseeopen_shell = True, come illustrato in questa guida.
NOTA: Alcune delle manipolazioni della configurazione elettronica (stringa di bit) presenti in questo pacchetto hanno lo scopo di preservare la simmetria di spin totale . I risolutori standard dell'interazione di configurazione selezionata (SCI) non sono in grado di garantire con esattezza la conservazione dell' . Di conseguenza, lo fanno approssimativamente tramite un moltiplicatore di Lagrange.
Anche la scelta delle configurazioni elettroniche inserite nel risolutore degli stati propri può avere un forte effetto sulla conservazione dello spin. Ad esempio, in un sistema (a 2 elettroni, 2 orbitali), è possibile campionare la configurazione (che presenta una singola eccitazione di spin-up rispetto allo stato RHF ), la quale è una combinazione lineare degli stati singoletto e tripletto a guscio aperto, rispettivamente . Se la configurazione |0110⟩ non viene campionata, non è possibile costruire nessuna delle funzioni proprie dello spin totale, il che porta a contaminazione o ridondanza di spin (la configurazione |1001⟩ è coinvolta in un calcolo CI, ma ha coefficiente 0 nel vettore CI). Dato che nel computer quantistico viene generato un singolo campione , ecco come il sqd pacchetto gestisce questa situazione:
-
open_shell = False:-
La stringa di bit viene divisa a metà, rappresentando le configurazioni "spin-up" e "spin-down": (up) e (down).
-
È stato stilato l'elenco delle configurazioni uniche con polarizzazione di spin: .
-
Consideriamo quindi tutte le possibili combinazioni di elementi dell’ e per formare la base: , che contiene gli stati singoletto e tripletto.
-
-
open_shell = True:- A differenza di quanto
open_shell = Falseavviene in quel caso, non uniamo le due metà della stringa di bit per formare la base.
- A differenza di quanto
A guscio chiuso
Questo esempio illustra come vengono manipolate le stringhe di bit in un sistema (a 2 elettroni e 4 orbitali).
# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = FalseSpecificare manualmente un dizionario dei risultati delle misurazioni:
counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}Trasforma i conteggi dict in una matrice di stringhe di bit e in un array di probabilità per la post-elaborazione:
from qiskit_addon_sqd.counts import counts_to_arrays
# Convert counts into bitstring and probability arrays
bitstring_matrix_full, probs_arr_full = counts_to_arrays(counts_dict)
print(bitstring_matrix_full)
print(probs_arr_full)Output:
[[False False False True False False True False]
[False True False False True False False False]
[False False False True False False False True]]
[0.49 0.49 0.02]
Creare un sottocampione di un singolo lotto di dimensione pari a due:
n_batches = 1: Numero di lotti di configurazioni utilizzati dalle diverse chiamate al risolutore di stati proprisamples_per_batch = 2: Numero di configurazioni uniche da includere in ogni lotto
from qiskit_addon_sqd.subsampling import postselect_and_subsample
n_batches = 1
samples_per_batch = 2
# seed for random number generator
rand_seed = 48
# Generate the batches
batches = postselect_and_subsample(
bitstring_matrix_full,
probs_arr_full,
hamming_right=num_elec_a,
hamming_left=num_elec_b,
samples_per_batch=samples_per_batch,
num_batches=n_batches,
rand_seed=rand_seed,
)
print(batches[0])Output:
[[False False False True False False True False]
[False True False False True False False False]]
Ottenere la rappresentazione decimale delle stringhe di bit "spin-up" e "spin-down" utilizzate dal risolutore degli stati propri.
Il primo elemento della tupla corrisponde alla rappresentazione decimale delle configurazioni con spin verso l'alto, mentre il secondo elemento della tupla corrisponde alla rappresentazione decimale delle configurazioni con spin verso il basso:
from qiskit_addon_sqd.fermion import bitstring_matrix_to_ci_strs
ci_strs = bitstring_matrix_to_ci_strs(batches[0], open_shell=open_shell)
print(ci_strs)Output:
(array([1, 2, 4, 8], dtype=int64), array([1, 2, 4, 8], dtype=int64))
Si noti che, sebbene il numero di campioni per lotto sia pari a due e le stringhe di bit campionate siano: e , vengono generate quattro configurazioni elettroniche per ogni specie di spin. In questo caso, l'insieme delle configurazioni uniche con polarizzazione di spin è dato da:
la cui rappresentazione decimale base-10 è
Basi del sottospazio:
Il risolutore di stati propri considera tutte le possibili coppie di stringhe di bit con spin-up e spin-down per costruire la base del sottospazio:
-
Elemento 1:
-
Elemento 2:
-
Elemento 3:
-
Elemento 4:
-
Elemento 5:
-
Elemento 6:
-
Elemento 7:
-
Elemento 8:
-
Elemento 9:
-
Elemento 10:
-
Elemento 11:
-
Elemento 12:
-
Elemento 13:
-
Elemento 14:
-
Elemento 15:
-
Elemento 16:
ci_strs_up, ci_strs_dn = ci_strs
print("Basis elements of the subspace:")
for ci_str_up in ci_strs_up:
for ci_str_dn in ci_strs_dn:
format_name = "{0:0" + str(num_orbitals) + "b}"
print(
"|"
+ format_name.format(ci_str_up)
+ format_name.format(ci_str_dn)
+ ">"
)Output:
Basis elements of the subspace:
|00010001>
|00010010>
|00010100>
|00011000>
|00100001>
|00100010>
|00100100>
|00101000>
|01000001>
|01000010>
|01000100>
|01001000>
|10000001>
|10000010>
|10000100>
|10001000>
La dimensione del sottospazio è limitata superiormente da : (samples_per_batch) .
A guscio aperto
Questo esempio illustra come vengono manipolate le stringhe di bit in un sistema (a 2 elettroni e 4 orbitali).
# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = TrueSpecificare manualmente un dizionario dei risultati delle misurazioni:
counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}Trasforma i conteggi dict in una matrice di stringhe di bit e in un array di probabilità per la post-elaborazione:
# Convert counts into bitstring and probability arrays
bitstring_matrix_full, probs_arr_full = counts_to_arrays(counts_dict)
print(bitstring_matrix_full)
print(probs_arr_full)Output:
[[False False False True False False True False]
[False True False False True False False False]
[False False False True False False False True]]
[0.49 0.49 0.02]
Creare un sottocampione di un singolo lotto di dimensione pari a due:
n_batches = 1: Numero di lotti di configurazioni utilizzati dalle diverse chiamate al risolutore di stati proprisamples_per_batch = 2: Numero di configurazioni uniche da includere in ogni lotto
n_batches = 1
samples_per_batch = 2
# seed for random number generator
rand_seed = 48
# Generate the batches
batches = postselect_and_subsample(
bitstring_matrix_full,
probs_arr_full,
hamming_right=num_elec_a,
hamming_left=num_elec_b,
samples_per_batch=samples_per_batch,
num_batches=n_batches,
rand_seed=rand_seed,
)
print(batches[0])Output:
[[False False False True False False True False]
[False True False False True False False False]]
Ottenere la rappresentazione decimale delle stringhe di bit "spin-up" e "spin-down" utilizzate dal risolutore degli stati propri.
Il primo elemento della tupla corrisponde alla rappresentazione decimale delle configurazioni con spin verso l'alto, mentre il secondo elemento della tupla corrisponde alla rappresentazione decimale delle configurazioni con spin verso il basso:
ci_strs = bitstring_matrix_to_ci_strs(batches[0], open_shell=open_shell)
print(ci_strs)Output:
(array([2, 8], dtype=int64), array([1, 4], dtype=int64))
Se specifichiamo che open_shell = True, non includiamo tutte le semistringhe univoche come configurazioni “spin-up” e “spin-down”, ottenendo così una base più ridotta rispetto a quando si specifica open_shell = False.
Basi del sottospazio:
Il risolutore di stati propri considera tutte le possibili coppie di stringhe di bit con spin-up e spin-down per costruire la base del sottospazio:
-
Elemento 1:
-
Elemento 2:
-
Elemento 3:
-
Elemento 4:
ci_strs_up, ci_strs_dn = ci_strs
print("Basis elements of the subspace:")
for ci_str_up in ci_strs_up:
for ci_str_dn in ci_strs_dn:
format_name = "{0:0" + str(num_orbitals) + "b}"
print(
"|"
+ format_name.format(ci_str_up)
+ format_name.format(ci_str_dn)
+ ">"
)Output:
Basis elements of the subspace:
|00100001>
|00100100>
|10000001>
|10000100>
La dimensione del sottospazio è limitata superiormente da : (samples_per_batch) .