Open-Shell- versus Closed-Shell-Optionen und die Auswirkung auf die Unterraumkonstruktion verstehen
In dieser Anleitung zeigen wir, wie du im Paket qiskit_addon_sqd Unterraumdimensionen wählst, um Quanten-Samples mit der Technik der selbstkonsistenten Konfigurationswiederherstellung nachzubearbeiten.
Wichtiger noch: Diese Anleitung hebt auch einige Unterschiede im Verhalten der Unterraumkonstruktion hervor, wenn sie im Modus open_shell = False oder open_shell = True ausgeführt wird:
-
open_shell = Falsefunktioniert nur, wenn die Anzahl der Spin-up- und Spin-down-Elektronen gleich ist. -
open_shell = Truemuss verwendet werden, wenn die Anzahl der Spin-up- und Spin-down-Elektronen verschieden ist. Er kann auch verwendet werden, wenn die Anzahl der Spin-up- und Spin-down-Elektronen gleich ist. In diesem letzten Fall unterscheiden sich jedoch die Größen der erzeugten Unterräume zwischenopen_shell = Falseundopen_shell = True, wie in dieser Anleitung besprochen.
HINWEIS: Einige der Manipulationen elektronischer Konfigurationen (Bitstrings) in diesem Paket haben zum Ziel, die Gesamtspinsymmetrie zu erhalten. Standard-Solver für Selected Configuration Interaction (SCI) können die -Erhaltung nicht exakt erzwingen. Folglich tun sie dies näherungsweise über einen Lagrange-Multiplikator.
Die Wahl der elektronischen Konfigurationen, die in den Eigenzustands-Solver eingehen, kann sich ebenfalls stark auf die Spinerhaltung auswirken. In einem (2-Elektronen, 2-Orbitale)-System kann man zum Beispiel die Konfiguration samplen (mit einer einzelnen Spin-up-Anregung über dem RHF-Zustand ), die eine Linearkombination des Open-Shell-Singulett- und des Triplett-Zustands ist, nämlich . Wird die Konfiguration |0110⟩ nicht gesampelt, lässt sich keine der beiden Eigenfunktionen des Gesamtspins konstruieren, was zu Spinkontamination oder Redundanz führt (die Konfiguration |1001⟩ geht in eine CI-Rechnung ein, hat aber im CI-Vektor den Koeffizienten 0). Wird auf dem Quantencomputer ein einzelnes Sample erzeugt, geht das Paket sqd in dieser Situation wie folgt vor:
-
open_shell = False:-
Der Bitstring wird in zwei Hälften geteilt, die Spin-up- und Spin-down-Konfigurationen darstellen: (up) und (down).
-
Die Liste der eindeutigen spinpolarisierten Konfigurationen wird aufgebaut: .
-
Dann betrachten wir alle möglichen Kombinationen der Elemente von , um die Basis zu bilden: , die den Singulett- und den Triplett-Zustand enthält.
-
-
open_shell = True:- Im Gegensatz zum Fall
open_shell = Falsekombinieren wir die Hälften des Bitstrings nicht, um die Basis zu bilden.
- Im Gegensatz zum Fall
Closed-Shell
Dieses Beispiel zeigt, wie die Bitstrings in einem (2-Elektronen, 4-Orbitale)-System manipuliert werden.
# 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
Ein Dictionary von Messergebnissen von Hand angeben:
counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}
Die Counts-dict in eine Bitstring-Matrix und ein Wahrscheinlichkeits-Array für die Nachbearbeitung umwandeln:
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]
Einen einzelnen Batch der Größe zwei subsamplen:
-
n_batches = 1: Anzahl der Batches von Konfigurationen, die von den verschiedenen Aufrufen des Eigenzustands-Solvers verwendet werden -
samples_per_batch = 2: Anzahl der eindeutigen Konfigurationen, die in jeden Batch aufgenommen werden
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]]
Die Dezimaldarstellung der vom Eigenzustands-Solver verwendeten Spin-up- und Spin-down-Bitstrings ermitteln.
Das erste Element des Tupels entspricht der Dezimaldarstellung der Spin-up-Konfigurationen, das zweite Element des Tupels der Dezimaldarstellung der Spin-down-Konfigurationen:
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))
Beachte: Obwohl die Anzahl der Samples pro Batch zwei beträgt und die gesampelten Bitstrings und lauten, werden pro Spinsorte vier elektronische Konfigurationen erzeugt. In diesem Fall ist die Menge der eindeutigen spinpolarisierten Konfigurationen gegeben durch:
deren Dezimaldarstellung zur Basis 10 lautet
Basis des Unterraums:
Der Eigenzustands-Solver nimmt alle möglichen Paare aus Spin-up- und Spin-down-Bitstrings, um die Basis des Unterraums zu konstruieren:
-
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>
Die Unterraumdimension ist nach oben beschränkt durch: (samples_per_batch).
Open-Shell
Dieses Beispiel zeigt, wie die Bitstrings in einem (2-Elektronen, 4-Orbitale)-System manipuliert werden.
# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = True
Ein Dictionary von Messergebnissen von Hand angeben:
counts_dict = {
"00010010": 1 / 2.0 - 0.01,
"01001000": 1 / 2.0 - 0.01,
"00010001": 0.02,
}
Die Counts-dict in eine Bitstring-Matrix und ein Wahrscheinlichkeits-Array für die Nachbearbeitung umwandeln:
# 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]
Einen einzelnen Batch der Größe zwei subsamplen:
-
n_batches = 1: Anzahl der Batches von Konfigurationen, die von den verschiedenen Aufrufen des Eigenzustands-Solvers verwendet werden -
samples_per_batch = 2: Anzahl der eindeutigen Konfigurationen, die in jeden Batch aufgenommen werden
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]]
Die Dezimaldarstellung der vom Eigenzustands-Solver verwendeten Spin-up- und Spin-down-Bitstrings ermitteln.
Das erste Element des Tupels entspricht der Dezimaldarstellung der Spin-up-Konfigurationen, das zweite Element des Tupels der Dezimaldarstellung der Spin-down-Konfigurationen:
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))
Wenn wir open_shell = True angeben, nehmen wir nicht alle eindeutigen Halb-Bitstrings als Spin-up- und Spin-down-Konfigurationen auf und erhalten so eine kleinere Basis als bei open_shell = False.
Basis des Unterraums:
Der Eigenzustands-Solver nimmt alle möglichen Paare aus Spin-up- und Spin-down-Bitstrings, um die Basis des Unterraums zu konstruieren:
-
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>
Die Unterraumdimension ist nach oben beschränkt durch: (samples_per_batch).