Comprendi le opzioni a guscio aperto rispetto a guscio chiuso e l'effetto sulla costruzione del sottospazio
In questa guida mostreremo come scegliere le dimensioni dei sottospazi nel pacchetto qiskit_addon_sqd per post-elaborare campioni quantistici usando la tecnica di recupero della configurazione autoconsistente.
Ancora più importante, questa guida evidenzia anche alcune differenze nel comportamento della costruzione del sottospazio quando si esegue in modalità open_shell = False o open_shell = True:
-
open_shell = Falsefunziona solo quando il numero di elettroni di spin up e di spin down è lo stesso. -
open_shell = Truedeve essere usato quando il numero di elettroni di spin up e di spin down è diverso. Può essere usato anche quando il numero di elettroni di spin up e di spin down è lo stesso. Tuttavia, in quest'ultimo caso, c'è una differenza nelle dimensioni dei sottospazi generati traopen_shell = Falseeopen_shell = True, come discusso in questa guida.
NOTA: Alcune delle manipolazioni delle configurazioni elettroniche (stringhe di bit) in questo pacchetto hanno come obiettivo la conservazione della simmetria di spin totale . I solver standard di Selected Configuration Interaction (SCI) non possono imporre esattamente la conservazione di . Di conseguenza, lo fanno in modo approssimato tramite un moltiplicatore di Lagrange.
La scelta delle configurazioni elettroniche che entrano nel solver degli autostati può avere anche un forte effetto sulla conservazione dello spin. Per esempio, in un sistema (2 elettroni, 2 orbitali), si può campionare la configurazione (che ha una singola eccitazione di spin up rispetto allo stato RHF ), che è una combinazione lineare degli stati di singoletto e tripletto a guscio aperto, rispettivamente . Se la configurazione |0110⟩ non viene campionata, non si può costruire nessuna delle due autofunzioni di spin totale, il che porta a contaminazione di spin o ridondanza (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 , il pacchetto sqd gestisce questa situazione così:
-
open_shell = False:-
La stringa di bit viene divisa a metà, rappresentando le configurazioni di spin up e di spin down: (up) e (down).
-
Viene costruita la lista delle configurazioni uniche polarizzate in spin: .
-
Consideriamo quindi tutte le possibili combinazioni degli elementi di per formare la base: , che contiene gli stati di singoletto e tripletto.
-
-
open_shell = True:- Contrariamente al caso
open_shell = False, non combiniamo le metà della stringa di bit per formare la base.
- Contrariamente al caso
Guscio chiuso
Questo esempio mostra come vengono manipolate le stringhe di bit in un sistema (2 elettroni, 4 orbitali).
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"qiskit_addon_sqd": "qiskit-addon-sqd"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = False
Specifica a mano un dizionario di risultati di misura:
counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}
Trasforma il dict dei conteggi in una matrice di stringhe di bit e 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)
[[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]
Sottocampiona un singolo batch di dimensione due:
-
n_batches = 1: numero di batch di configurazioni usati dalle diverse chiamate al solver degli autostati -
samples_per_batch = 2: numero di configurazioni uniche da includere in ogni batch
from qiskit_addon_sqd.subsampling import (
postselect_by_hamming_right_and_left,
subsample,
)
n_batches = 1
samples_per_batch = 2
# seed for random number generator
rand_seed = 48
# Post-select the configurations with the correct Hamming weight on each half
bitstring_matrix_postsel, probs_arr_postsel = (
postselect_by_hamming_right_and_left(
bitstring_matrix_full,
probs_arr_full,
hamming_right=num_elec_a,
hamming_left=num_elec_b,
)
)
# Generate the batches
batches = subsample(
bitstring_matrix_postsel,
probs_arr_postsel,
samples_per_batch,
n_batches,
rand_seed=rand_seed,
)
print(batches[0])
[[False False False True False False True False]
[False True False False True False False False]]
Ottieni la rappresentazione decimale delle stringhe di bit di spin up e di spin down usate dal solver degli autostati.
Il primo elemento della tupla corrisponde alla rappresentazione decimale delle configurazioni di spin up, mentre il secondo elemento della tupla corrisponde alla rappresentazione decimale delle configurazioni di spin down:
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)
(array([1, 2, 4, 8], dtype=int64), array([1, 2, 4, 8], dtype=int64))
Nota che, sebbene il numero di campioni per batch sia due e le stringhe di bit campionate siano e , vengono generate quattro configurazioni elettroniche per specie di spin. In questo caso, l'insieme delle configurazioni uniche polarizzate in spin è dato da:
cui rappresentazione decimale in base 10 è
Base del sottospazio:
Il solver degli autostati prende tutte le possibili coppie di stringhe di bit di spin up e di 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)
+ ">"
)
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).
Guscio aperto
Questo esempio mostra come vengono manipolate le stringhe di bit in un sistema (2 elettroni, 4 orbitali).
# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = True
Specifica a mano un dizionario di risultati di misura:
counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}
Trasforma il dict dei conteggi in una matrice di stringhe di bit e 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)
[[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]
Sottocampiona un singolo batch di dimensione due:
-
n_batches = 1: numero di batch di configurazioni usati dalle diverse chiamate al solver degli autostati -
samples_per_batch = 2: numero di configurazioni uniche da includere in ogni batch
n_batches = 1
samples_per_batch = 2
# seed for random number generator
rand_seed = 48
# Post-select the configurations with the correct Hamming weight on each half
bitstring_matrix_postsel, probs_arr_postsel = (
postselect_by_hamming_right_and_left(
bitstring_matrix_full,
probs_arr_full,
hamming_right=num_elec_a,
hamming_left=num_elec_b,
)
)
# Generate the batches
batches = subsample(
bitstring_matrix_postsel,
probs_arr_postsel,
samples_per_batch,
n_batches,
rand_seed=rand_seed,
)
print(batches[0])
[[False False False True False False True False]
[False True False False True False False False]]
Ottieni la rappresentazione decimale delle stringhe di bit di spin up e di spin down usate dal solver degli autostati.
Il primo elemento della tupla corrisponde alla rappresentazione decimale delle configurazioni di spin up, mentre il secondo elemento della tupla corrisponde alla rappresentazione decimale delle configurazioni di spin down:
ci_strs = bitstring_matrix_to_ci_strs(batches[0], open_shell=open_shell)
print(ci_strs)
(array([2, 8], dtype=int64), array([1, 4], dtype=int64))
Se specifichiamo open_shell = True, non includiamo tutte le mezze stringhe di bit uniche come configurazioni di spin up e di spin down, ottenendo così una base più piccola rispetto a quando si specifica open_shell = False.
Base del sottospazio:
Il solver degli autostati prende tutte le possibili coppie di stringhe di bit di spin up e di 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)
+ ">"
)
Basis elements of the subspace:
|00100001>
|00100100>
|10000001>
|10000100>
La dimensione del sottospazio è limitata superiormente da: (samples_per_batch).