Comprendre les options « à couche ouverte » et « à couche fermée », ainsi que leur incidence sur la construction des sous-espaces
Dans ce guide, nous allons vous montrer comment choisir les dimensions du sous-espace dans le qiskit_addon_sqd package afin de post-traiter des échantillons quantiques à l'aide de la technique de récupération de configuration auto-cohérente.
Mais surtout, ce guide met également en évidence certaines différences de comportement dans la construction du sous-espace lorsque l'on utilise les open_shell = False modes ou open_shell = True :
-
open_shell = Falsene fonctionne que lorsque le nombre d'électrons en phase de montée en vitesse et en phase de ralentissement est identique. -
open_shell = Truedoit être utilisé lorsque le nombre d'électrons en phase d'accélération et de décélération est différent. On peut également l'utiliser lorsque le nombre d'électrons en phase d'accélération et de décélération est identique. Toutefois, dans ce dernier cas, il existe une différence entre les dimensions des sous-espaces générés paropen_shell = Falseetopen_shell = True, comme l'explique ce guide.
REMARQUE : Certaines des manipulations de configuration électronique (chaîne de bits) effectuées dans ce progiciel ont pour objectif de préserver la symétrie de spin totale . Les solveurs standard d’interaction de configuration sélectionnée (SCI) ne permettent pas d’imposer exactement la conservation de l’ . Par conséquent, ils procèdent approximativement à l'aide d'un multiplicateur de Lagrange.
Le choix des configurations électroniques introduites dans le solveur d'états propres peut également avoir une forte incidence sur la conservation du spin. Par exemple, dans un système (à 2 électrons, 2 orbitales), on peut échantillonner la configuration (présentant une seule excitation de spin vers le haut par rapport à l’état RHF ), qui est une combinaison linéaire des états singulet et triplet à couche ouverte, respectivement . Si la configuration |0110⟩ n’est pas échantillonnée, il n’est possible de construire aucune fonction propre du spin total, ce qui entraîne une contamination ou une redondance de spin (la configuration |1001⟩ est impliquée dans un calcul CI, mais son coefficient est égal à 0 dans le vecteur CI). Étant donné qu’un seul échantillon est généré dans l’ordinateur quantique, voici comment le sqd module gère cette situation :
-
open_shell = False:-
La chaîne de bits « » est divisée en deux parties, représentant respectivement les configurations « spin-up » et « spin-down » : (up) et (down).
-
La liste des configurations uniques à polarisation de spin a été établie : .
-
Nous examinons ensuite toutes les combinaisons possibles d'éléments d' s pour former la base : , qui contient les états singulet et triplet.
-
-
open_shell = True:- Contrairement à ce qui se passe
open_shell = Falsedans ce cas, nous ne combinons pas les deux moitiés de la chaîne de bits pour former la base.
- Contrairement à ce qui se passe
À coque fermée
Cet exemple montre comment les chaînes de bits sont manipulées dans un système (à 2 électrons et 4 orbitales).
# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = FalseDéfinissez manuellement un dictionnaire de résultats de mesure :
counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}Convertissez les nombres d'occurrences dict en une matrice de chaînes de bits et en un tableau de probabilités en vue du post-traitement :
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]
Prélever un sous-échantillon d'un seul lot de taille deux :
n_batches = 1: Nombre de lots de configurations utilisés par les différents appels au solveur d'états propressamples_per_batch = 2: Nombre de configurations uniques à inclure dans chaque lot
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]]
Obtenir la représentation décimale des chaînes de bits « spin-up » et « spin-down » utilisées par le solveur d'états propres.
Le premier élément du tuple correspond à la représentation décimale des configurations de spin vers le haut, tandis que le deuxième élément du tuple correspond à la représentation décimale des configurations de spin vers le bas :
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))
Il convient de noter que, bien que le nombre d'échantillons par lot soit de deux et que les chaînes de bits échantillonnées soient : et , quatre configurations électroniques sont générées par espèce de spin. Dans ce cas, l'ensemble des configurations uniques à polarisation de spin est donné par :
dont la représentation décimale base-10 est
Base du sous-espace :
Le solveur d'états propres prend en compte toutes les paires possibles de chaînes de bits « spin-up » et « spin-down » pour construire la base du sous-espace :
-
Élément 1 :
-
Élément 2 :
-
Élément 3 :
-
Élément 4 :
-
Élément 5 :
-
Élément 6 :
-
Élément 7 :
-
Élément 8 :
-
Élément 9 :
-
Élément 10 :
-
Élément 11 :
-
Élément 12 :
-
Élément 13 :
-
Élément 14 :
-
Élément 15 :
-
Élément 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 dimension du sous-espace est bornée supérieurement par : (samples_per_batch) .
À coque ouverte
Cet exemple montre comment les chaînes de bits sont manipulées dans un système (à 2 électrons et 4 orbitales).
# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = TrueDéfinissez manuellement un dictionnaire de résultats de mesure :
counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}Convertissez les nombres d'occurrences dict en une matrice de chaînes de bits et en un tableau de probabilités en vue du post-traitement :
# 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]
Prélever un sous-échantillon d'un seul lot de taille deux :
n_batches = 1: Nombre de lots de configurations utilisés par les différents appels au solveur d'états propressamples_per_batch = 2: Nombre de configurations uniques à inclure dans chaque lot
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]]
Obtenir la représentation décimale des chaînes de bits « spin-up » et « spin-down » utilisées par le solveur d'états propres.
Le premier élément du tuple correspond à la représentation décimale des configurations de spin vers le haut, tandis que le deuxième élément du tuple correspond à la représentation décimale des configurations de spin vers le bas :
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))
Si l'on spécifie que open_shell = True, on n'inclut pas toutes les demi-chaînes de bits uniques en tant que configurations « spin-up » et « spin-down », ce qui donne une base plus restreinte que lorsque l'on spécifie open_shell = False.
Base du sous-espace :
Le solveur d'états propres prend en compte toutes les paires possibles de chaînes de bits « spin-up » et « spin-down » pour construire la base du sous-espace :
-
Élément 1 :
-
Élément 2 :
-
Élément 3 :
-
Élément 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 dimension du sous-espace est bornée supérieurement par : (samples_per_batch) .