Opcje powłoki otwartej i zamkniętej oraz ich wpływ na konstrukcję podprzestrzeni
W tym przewodniku pokażemy, jak wybierać wymiary podprzestrzeni w pakiecie qiskit_addon_sqd, aby przetwarzać końcowo próbki kwantowe za pomocą techniki samouzgodnionego odzyskiwania konfiguracji.
Co ważniejsze, przewodnik ten pokazuje także pewne różnice w zachowaniu konstrukcji podprzestrzeni w trybach open_shell = False i open_shell = True:
-
open_shell = Falsedziała tylko wtedy, gdy liczba elektronów ze spinem w górę i w dół jest taka sama. -
open_shell = Truetrzeba stosować, gdy liczba elektronów ze spinem w górę i w dół jest różna. Można go też używać, gdy te liczby są równe. W tym ostatnim przypadku istnieje jednak różnica w rozmiarach generowanych podprzestrzeni międzyopen_shell = Falseaopen_shell = True, jak omówiono w tym przewodniku.
UWAGA: Niektóre manipulacje konfiguracjami elektronowymi (ciągami bitów) w tym pakiecie mają na celu zachowanie całkowitej symetrii spinowej . Standardowe solwery interakcji konfiguracji wybranych (SCI) nie potrafią dokładnie narzucić zachowania . W konsekwencji robią to w przybliżeniu za pomocą mnożnika Lagrange'a.
Wybór konfiguracji elektronowych trafiających do solwera stanów własnych może również silnie wpływać na zachowanie spinu. Na przykład w układzie (2 elektrony, 2 orbitale) można spróbkować konfigurację (mającą pojedyncze wzbudzenie spinem w górę względem stanu RHF ), która jest kombinacją liniową stanów singletowego i trypletowego o otwartej powłoce, odpowiednio . Jeśli konfiguracja |0110⟩ nie zostanie spróbkowana, nie da się zbudować żadnej z funkcji własnych całkowitego spinu, co prowadzi do zanieczyszczenia spinowego lub redundancji (konfiguracja |1001⟩ uczestniczy w obliczeniach CI, ale ma współczynnik 0 w wektorze CI). Biorąc pod uwagę, że w komputerze kwantowym generowana jest pojedyncza próbka , pakiet sqd obsługuje tę sytuację w następujący sposób:
-
open_shell = False:-
Ciąg bitów jest dzielony na pół, co reprezentuje konfiguracje ze spinem w górę i w dół: (w górę) i (w dół).
-
Tworzona jest lista unikalnych konfiguracji spolaryzowanych spinowo: .
-
Następnie rozważamy wszystkie możliwe kombinacje elementów , aby utworzyć bazę: , która zawiera stany singletowy i trypletowy.
-
-
open_shell = True:- W przeciwieństwie do przypadku
open_shell = Falsenie łączymy połówek ciągu bitów, aby utworzyć bazę.
- W przeciwieństwie do przypadku
Powłoka zamknięta
Ten przykład pokazuje, jak manipuluje się ciągami bitów w układzie (2 elektrony, 4 orbitale).
# 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
Ręcznie zdefiniuj słownik wyników pomiarów:
counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}
Przekształć dict z zliczeniami w macierz ciągów bitów i tablicę prawdopodobieństw do przetwarzania końcowego:
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]
Podpróbkuj pojedynczą partię o rozmiarze dwa:
-
n_batches = 1: liczba partii konfiguracji używanych w różnych wywołaniach solwera stanów własnych -
samples_per_batch = 2: liczba unikalnych konfiguracji w każdej partii
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]]
Uzyskaj reprezentację dziesiętną ciągów bitów ze spinem w górę i w dół używanych przez solwer stanów własnych.
Pierwszy element krotki odpowiada reprezentacji dziesiętnej konfiguracji ze spinem w górę, a drugi element krotki odpowiada reprezentacji dziesiętnej konfiguracji ze spinem w dół:
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))
Zauważ, że chociaż liczba próbek w partii wynosi dwa, a spróbkowane ciągi bitów to i , dla każdego gatunku spinowego generowane są cztery konfiguracje elektronowe. W tym przypadku zbiór unikalnych konfiguracji spolaryzowanych spinowo jest dany przez:
którego reprezentacja dziesiętna (w systemie o podstawie 10) to
Baza podprzestrzeni:
Solwer stanów własnych bierze wszystkie możliwe pary ciągów bitów ze spinem w górę i w dół, aby zbudować bazę podprzestrzeni:
-
Element 1:
-
Element 2:
-
Element 3:
-
Element 4:
-
Element 5:
-
Element 6:
-
Element 7:
-
Element 8:
-
Element 9:
-
Element 10:
-
Element 11:
-
Element 12:
-
Element 13:
-
Element 14:
-
Element 15:
-
Element 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>
Wymiar podprzestrzeni jest ograniczony z góry przez: (samples_per_batch).
Powłoka otwarta
Ten przykład pokazuje, jak manipuluje się ciągami bitów w układzie (2 elektrony, 4 orbitale).
# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = True
Ręcznie zdefiniuj słownik wyników pomiarów:
counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}
Przekształć dict z zliczeniami w macierz ciągów bitów i tablicę prawdopodobieństw do przetwarzania końcowego:
# 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]
Podpróbkuj pojedynczą partię o rozmiarze dwa:
-
n_batches = 1: liczba partii konfiguracji używanych w różnych wywołaniach solwera stanów własnych -
samples_per_batch = 2: liczba unikalnych konfiguracji w każdej partii
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]]
Uzyskaj reprezentację dziesiętną ciągów bitów ze spinem w górę i w dół używanych przez solwer stanów własnych.
Pierwszy element krotki odpowiada reprezentacji dziesiętnej konfiguracji ze spinem w górę, a drugi element krotki odpowiada reprezentacji dziesiętnej konfiguracji ze spinem w dół:
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))
Jeśli określimy open_shell = True, nie uwzględniamy wszystkich unikalnych połówek ciągów bitów jako konfiguracji ze spinem w górę i w dół, co daje mniejszą bazę niż przy open_shell = False.
Baza podprzestrzeni:
Solwer stanów własnych bierze wszystkie możliwe pary ciągów bitów ze spinem w górę i w dół, aby zbudować bazę podprzestrzeni:
-
Element 1:
-
Element 2:
-
Element 3:
-
Element 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>
Wymiar podprzestrzeni jest ograniczony z góry przez: (samples_per_batch).