メインコンテンツへスキップ
このプロジェクトはベータ版です。バグを見つけましたか?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 を保存することを目的としています。標準的な選択配置間相互作用 (SCI) ソルバーは、S2S^2 の保存を厳密には課すことができません。そのため、ラグランジュ乗数を用いて近似的に課します。

固有状態ソルバーに入力する電子配置の選び方も、スピンの保存に大きな影響を与えることがあります。たとえば (2電子、2軌道) の系では、配置 ∣1001⟩|1001\rangle (RHF 状態 ∣0101⟩|0101\rangle に対して単一のスピンアップ励起を持つ) をサンプルすることがあります。これは開殻の一重項状態と三重項状態、すなわち (∣1001⟩±∣0110⟩)/2(|1001\rangle ± |0110\rangle) /\sqrt{2} の線形結合です。配置 |0110⟩ がサンプルされない場合、全スピンの固有関数をどちらも構築できず、スピン汚染または冗長性が生じます (配置 |1001⟩ は CI 計算に含まれますが、CI ベクトルでの係数は 0 になります)。量子コンピューターで単一のサンプル ∣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]

サイズ2のバッチを1つサブサンプリングします。

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

固有状態ソルバーが使用する、スピンアップとスピンダウンのビット列の10進表現を取得します。

タプルの最初の要素はスピンアップ配置の10進表現に対応し、2番目の要素はスピンダウン配置の10進表現に対応します。

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

バッチあたりのサンプル数は2つで、サンプルされたビット列は 0001001000010010 と 0100100001001000 ですが、スピン種ごとに4つの電子配置が生成されることに注意してください。この場合、スピン偏極した一意な配置の集合は次のようになります。

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]

サイズ2のバッチを1つサブサンプリングします。

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

固有状態ソルバーが使用する、スピンアップとスピンダウンのビット列の10進表現を取得します。

タプルの最初の要素はスピンアップ配置の10進表現に対応し、2番目の要素はスピンダウン配置の10進表現に対応します。

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。