ข้ามไปยังเนื้อหาหลัก
โครงการนี้อยู่ในช่วงเบต้า พบข้อผิดพลาด? สร้าง GitHub Issue มีคำถามหรือไอเดีย? ถามใน Discussions — ยินดีรับฟังความคิดเห็น!
คุณภาพการแปลในหน้านี้เป็นอย่างไร?

ทำความเข้าใจตัวเลือกเปลือกเปิดเทียบกับเปลือกปิด และผลต่อการสร้างปริภูมิย่อย

ในคู่มือนี้ เราจะแสดงวิธีเลือกมิติของปริภูมิย่อยในแพ็กเกจ qiskit_addon_sqd เพื่อประมวลผลภายหลังตัวอย่างควอนตัมโดยใช้ เทคนิคการกู้คืนคอนฟิกูเรชันแบบสอดคล้องในตัวเอง

ที่สำคัญกว่านั้น คู่มือนี้ยังชี้ให้เห็นความแตกต่างบางอย่างในพฤติกรรมการสร้างปริภูมิย่อยเมื่อรันในโหมด open_shell = False หรือ open_shell = True:

  • open_shell = False ใช้ได้เฉพาะเมื่อจำนวนอิเล็กตรอนสปินขึ้นและสปินลงเท่ากัน

  • ต้องใช้ open_shell = True เมื่อจำนวนอิเล็กตรอนสปินขึ้นและสปินลงต่างกัน และใช้ได้เช่นกันเมื่อจำนวนอิเล็กตรอนสปินขึ้นและสปินลงเท่ากัน อย่างไรก็ตาม ในกรณีหลังนี้ ขนาดของปริภูมิย่อยที่สร้างขึ้นระหว่าง open_shell = False และ open_shell = True จะต่างกัน ตามที่อธิบายในคู่มือนี้

หมายเหตุ: การจัดการคอนฟิกูเรชันอิเล็กตรอน (บิตสตริง) บางอย่างในแพ็กเกจนี้มีเป้าหมายเพื่อรักษาสมมาตรสปินรวม S2S^2 ตัวแก้ Selected Configuration Interaction (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 \}

ซึ่งการแทนค่าเลขฐานสิบคือ

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