Zum Hauptinhalt springen
Dieses Projekt befindet sich in der Beta-Phase. Einen Fehler gefunden? GitHub Issue erstellen. Frage oder Idee? In Discussions fragen — wir freuen uns über dein Feedback!
Wie ist die Übersetzungsqualität auf dieser Seite?

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 = False funktioniert nur, wenn die Anzahl der Spin-up- und Spin-down-Elektronen gleich ist.

  • open_shell = True muss 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 zwischen open_shell = False und open_shell = True, wie in dieser Anleitung besprochen.

HINWEIS: Einige der Manipulationen elektronischer Konfigurationen (Bitstrings) in diesem Paket haben zum Ziel, die Gesamtspinsymmetrie S2S^2 zu erhalten. Standard-Solver für Selected Configuration Interaction (SCI) können die S2S^2-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 ∣1001⟩|1001\rangle samplen (mit einer einzelnen Spin-up-Anregung über dem RHF-Zustand ∣0101⟩|0101\rangle), die eine Linearkombination des Open-Shell-Singulett- und des Triplett-Zustands ist, nämlich (∣1001⟩±∣0110⟩)/2(|1001\rangle ± |0110\rangle) /\sqrt{2}. 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 ∣1001⟩|1001\rangle erzeugt, geht das Paket sqd in dieser Situation wie folgt vor:

  • open_shell = False:

    1. Der Bitstring 10011001 wird in zwei Hälften geteilt, die Spin-up- und Spin-down-Konfigurationen darstellen: 1010 (up) und 0101 (down).

    2. Die Liste der eindeutigen spinpolarisierten Konfigurationen wird aufgebaut: U=[01,10]\mathcal{U} = [01, 10].

    3. Dann betrachten wir alle möglichen Kombinationen der Elemente von U\mathcal{U}, um die Basis zu bilden: {∣0101⟩,∣0110⟩,∣1001⟩,∣1010⟩}\left \{ |0101\rangle, |0110\rangle , |1001\rangle , |1010\rangle \right \}, die den Singulett- und den Triplett-Zustand enthält.

  • open_shell = True:

    1. Im Gegensatz zum Fall open_shell = False kombinieren wir die Hälften des Bitstrings nicht, um die Basis zu bilden.

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 0001001000010010 und 0100100001001000 lauten, werden pro Spinsorte vier elektronische Konfigurationen erzeugt. In diesem Fall ist die Menge der eindeutigen spinpolarisierten Konfigurationen gegeben durch:

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

deren Dezimaldarstellung zur Basis 10 lautet

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

Basis des Unterraums:

Der Eigenzustands-Solver nimmt alle möglichen Paare aus Spin-up- und Spin-down-Bitstrings, um die Basis B\mathcal{B} des Unterraums zu konstruieren:

  • Element 1: ∣00010001⟩|00010001\rangle

  • Element 2: ∣00010010⟩|00010010\rangle

  • Element 3: ∣00010100⟩|00010100\rangle

  • Element 4: ∣00011000⟩|00011000\rangle

  • Element 5: ∣00100001⟩|00100001\rangle

  • Element 6: ∣00100010⟩|00100010\rangle

  • Element 7: ∣00100100⟩|00100100\rangle

  • Element 8: ∣00101000⟩|00101000\rangle

  • Element 9: ∣01000001⟩|01000001\rangle

  • Element 10: ∣01000010⟩|01000010\rangle

  • Element 11: ∣01000100⟩|01000100\rangle

  • Element 12: ∣01001000⟩|01001000\rangle

  • Element 13: ∣10000001⟩|10000001\rangle

  • Element 14: ∣10000010⟩|10000010\rangle

  • Element 15: ∣10000100⟩|10000100\rangle

  • Element 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>

Die Unterraumdimension ist nach oben beschränkt durch: 2⋅2 \cdot (samples_per_batch)2^2.

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 B\mathcal{B} des Unterraums zu konstruieren:

  • Element 1: ∣00010010⟩|00010010\rangle

  • Element 2: ∣00011000⟩|00011000\rangle

  • Element 3: ∣01000010⟩|01000010\rangle

  • Element 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>

Die Unterraumdimension ist nach oben beschränkt durch: (samples_per_batch)2^2.