Перейти до основного вмісту
Цей проєкт у бета-версії. Знайшов(-ла) помилку? Відкрити issue на GitHub. Є запитання чи ідея? Запитати в Discussions — будемо раді твоєму відгуку!
Яка якість перекладу на цій сторінці?

Розуміння опцій відкритої та закритої оболонки та їхнього впливу на побудову підпростору

У цьому посібнику ми покажемо, як вибирати розмірності підпросторів у пакеті qiskit_addon_sqd для постобробки квантових вибірок за допомогою техніки самоузгодженого відновлення конфігурацій.

Що важливіше, цей посібник також підкреслює деякі відмінності в поведінці побудови підпростору в режимах open_shell = False та open_shell = True:

  • open_shell = False працює лише тоді, коли кількість електронів зі спіном угору та зі спіном униз однакова.

  • open_shell = True потрібно використовувати, коли кількість електронів зі спіном угору та зі спіном униз різна. Його також можна використовувати, коли кількість електронів зі спіном угору та зі спіном униз однакова. Проте в цьому останньому випадку є різниця в розмірах підпросторів, згенерованих при open_shell = False і open_shell = True, як обговорюється в цьому посібнику.

ПРИМІТКА: Деякі маніпуляції з електронними конфігураціями (бітовими рядками) у цьому пакеті мають на меті зберегти повну спінову симетрію S2S^2. Стандартні розв'язувачі методу конфігураційної взаємодії з відібраними конфігураціями (SCI) не можуть точно накласти збереження S2S^2. Тому вони роблять це наближено через множник Лагранжа.

Вибір електронних конфігурацій, що входять до розв'язувача власних станів, також може сильно впливати на збереження спіну. Наприклад, у системі (2 електрони, 2 орбіталі) можна отримати вибірку конфігурації ∣1001⟩|1001\rangle (яка має одне збудження зі спіном угору над станом RHF ∣0101⟩|0101\rangle), що є лінійною комбінацією відкритооболонкових синглетного й триплетного станів, відповідно (∣1001⟩±∣0110⟩)/2(|1001\rangle ± |0110\rangle) /\sqrt{2}. Якщо конфігурацію |0110⟩ не отримано у вибірці, не можна побудувати жодну власну функцію повного спіну, що призводить до спінового забруднення або надлишковості (конфігурація |1001⟩ бере участь у CI-обчисленні, але має коефіцієнт 0 у CI-векторі). Враховуючи, що на квантовому комп'ютері згенеровано єдину вибірку ∣1001⟩|1001\rangle, пакет sqd обробляє цю ситуацію так:

  • open_shell = False:

    1. Бітовий рядок 10011001 ділиться навпіл, що представляє конфігурації зі спіном угору та зі спіном униз: 1010 (угору) та 0101 (униз).

    2. Будується список унікальних спін-поляризованих конфігурацій: U=[01,10]\mathcal{U} = [01, 10].

    3. Потім ми розглядаємо всі можливі комбінації елементів U\mathcal{U}, щоб утворити базис: {∣0101⟩,∣0110⟩,∣1001⟩,∣1010⟩}\left \{ |0101\rangle, |0110\rangle , |1001\rangle , |1010\rangle \right \}, який містить синглетний і триплетний стани.

  • open_shell = True:

    1. На відміну від випадку open_shell = False, ми не комбінуємо половини бітового рядка для утворення базису.

Закрита оболонка​

Цей приклад показує, як маніпулюють бітовими рядками в системі (2 електрони, 4 орбіталі).

# 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

Задай вручну словник результатів вимірювань:

counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}

Перетвори лічильники dict на матрицю бітових рядків і масив імовірностей для постобробки:

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]

Зроби підвибірку одного пакета розміру два:

  • n_batches = 1: кількість пакетів конфігурацій, що використовуються різними викликами розв'язувача власних станів

  • samples_per_batch = 2: кількість унікальних конфігурацій, що включаються в кожен пакет

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]]

Отримай десяткове представлення бітових рядків зі спіном угору та зі спіном униз, що використовуються розв'язувачем власних станів.

Перший елемент кортежу відповідає десятковому представленню конфігурацій зі спіном угору, тоді як другий елемент кортежу відповідає десятковому представленню конфігурацій зі спіном униз:

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))

Зауваж, що хоча кількість вибірок на пакет дорівнює двом, а вибрані бітові рядки такі: 0001001000010010 та 0100100001001000, на кожен спіновий вид генерується чотири електронні конфігурації. У цьому випадку множина унікальних спін-поляризованих конфігурацій задається так:

U={0001,0010,0100,1000}\mathcal{U} = \{ 0001, 0010, 0100, 1000 \}

якої десяткове представлення за основою 10 таке:

U10={1,2,4,8}\mathcal{U}_{10} = \{ 1, 2, 4, 8 \}

Базис підпростору:

Розв'язувач власних станів бере всі можливі пари бітових рядків зі спіном угору та зі спіном униз, щоб побудувати базис B\mathcal{B} підпростору:

  • Елемент 1: ∣00010001⟩|00010001\rangle

  • Елемент 2: ∣00010010⟩|00010010\rangle

  • Елемент 3: ∣00010100⟩|00010100\rangle

  • Елемент 4: ∣00011000⟩|00011000\rangle

  • Елемент 5: ∣00100001⟩|00100001\rangle

  • Елемент 6: ∣00100010⟩|00100010\rangle

  • Елемент 7: ∣00100100⟩|00100100\rangle

  • Елемент 8: ∣00101000⟩|00101000\rangle

  • Елемент 9: ∣01000001⟩|01000001\rangle

  • Елемент 10: ∣01000010⟩|01000010\rangle

  • Елемент 11: ∣01000100⟩|01000100\rangle

  • Елемент 12: ∣01001000⟩|01001000\rangle

  • Елемент 13: ∣10000001⟩|10000001\rangle

  • Елемент 14: ∣10000010⟩|10000010\rangle

  • Елемент 15: ∣10000100⟩|10000100\rangle

  • Елемент 16: ∣10001000⟩|10001000\rangle

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>

Розмірність підпростору обмежена зверху величиною: 2⋅2 \cdot (samples_per_batch)2^2.

Відкрита оболонка​

Цей приклад показує, як маніпулюють бітовими рядками в системі (2 електрони, 4 орбіталі).

# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = True

Задай вручну словник результатів вимірювань:

counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}

Перетвори лічильники dict на матрицю бітових рядків і масив імовірностей для постобробки:

# 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]

Зроби підвибірку одного пакета розміру два:

  • n_batches = 1: кількість пакетів конфігурацій, що використовуються різними викликами розв'язувача власних станів

  • samples_per_batch = 2: кількість унікальних конфігурацій, що включаються в кожен пакет

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]]

Отримай десяткове представлення бітових рядків зі спіном угору та зі спіном униз, що використовуються розв'язувачем власних станів.

Перший елемент кортежу відповідає десятковому представленню конфігурацій зі спіном угору, тоді як другий елемент кортежу відповідає десятковому представленню конфігурацій зі спіном униз:

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))

Якщо ми вказуємо open_shell = True, ми не включаємо всі унікальні половинні бітові рядки як конфігурації зі спіном угору та зі спіном униз, отже отримуємо менший базис, ніж при open_shell = False. Базис підпростору:

Розв'язувач власних станів бере всі можливі пари бітових рядків зі спіном угору та зі спіном униз, щоб побудувати базис B\mathcal{B} підпростору:

  • Елемент 1: ∣00010010⟩|00010010\rangle

  • Елемент 2: ∣00011000⟩|00011000\rangle

  • Елемент 3: ∣01000010⟩|01000010\rangle

  • Елемент 4: ∣01001000⟩|01001000\rangle

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>

Розмірність підпростору обмежена зверху величиною: (samples_per_batch)2^2.