Skip to main content
IBM Quantum Platform

クイック・スタート

このガイドでは、この qiskit-addon-sqd パッケージの最小限の動作例を紹介します。 我々は、化学ハミルトニアンの基底状態を近似する量子回路から取得したノイズの混じったサンプルに対し、サンプルベース量子対角化(SQD)を用いて精緻化を行う。 基底状態のエネルギーは、精製された試料によって形成される部分空間においてハミルトニアンを対角化することで近似される。

量子ハードウェア上で実行されるエンドツーエンドのワークフローについて、さらに詳しく知りたい場合は、以下のチュートリアルをご覧ください:


1. SQD用の入力データを準備する

まず、化学ハミルトニアンと、その基底状態を近似する量子回路を定義する。 この例で検討した系は、 STO-3G 基底において、2つのコア軌道を固定した平衡幾何構造のN₂である。 この系には 8 個の空間軌道と 10 個の電子があり、これは量子回路が 個の量子ビット上で 16 定義されていることを意味する。ここで、量子ビット 0-7 はスピンアップの軌道を、量子ビット 8-15 はスピンダウンの軌道を表す。 5``10これは電子を持つ 10 閉殻系であるため、物理的に妥当な各試料はハミング重みが であることがわかっている。ここで、ビット列の左右両半分のハミング重みは である。

from pyscf import ao2mo, gto, mcscf, scf

# Construct the Hamiltonian, pull out integrals and other information about the system
mol = gto.M(
    atom="N 0 0 0; N 0 0 1.09768", basis="sto-3g", spin=0, charge=0, verbose=0
)
mf = scf.RHF(mol).run()
cas = mcscf.CASCI(mf, ncas=8, nelecas=10)
hcore, nuclear_repulsion_energy = cas.get_h1eff()
eri = cas.get_h2eff()
num_orbitals = cas.ncas
eri = ao2mo.restore(1, eri, num_orbitals)
n_alpha, n_beta = cas.nelecas
nelec = (n_alpha, n_beta)

print(
    f"Spatial orbitals: {num_orbitals}\nQubits: {num_orbitals * 2}\nElectrons (alpha, beta): {nelec}"
)

Output:

Spatial orbitals: 8
Qubits: 16
Electrons (alpha, beta): (5, 5)

2. ノイズを含むサンプルを生成する

実際のワークフローでは、アンザッツ回路を設計し、ハードウェア向けに最適化した上で、QPU上でサンプリングを行います。 ここではその手順を省略し、代わりに一様分布に従うランダムなビット列を生成 10,000 します。 これらのサンプルには実際の基底状態に関する情報は含まれていませんが、SQDプロトコルでは、これらのサンプルを反復的に精緻化し、対角化を行い、各反復におけるエネルギーを次のビット列の精緻化に反映させることで、真の基底状態を復元できることがわかります。 基底状態を含む部分空間は十分に小さいため、正確に計算することが可能であり、この方法によって最終的には正確な基底状態を復元することができる。 5具体的には、各ビット列(8 bits)のそれぞれの半分がハミング重みを持つことがわかっているため、このシステムのヒルベルト部分空間全体のサイズは (85)2=3136\binom{8}{5}^2=3136 であることがわかる。

import numpy as np
from qiskit_addon_sqd.counts import generate_bit_array_uniform

# Generate some uniformly-random bitstrings to simulate QPU samples
rng = np.random.default_rng(24)
bit_array = generate_bit_array_uniform(
    10_000, num_orbitals * 2, rand_seed=rng
)
print(
    f"Generated {bit_array.num_shots} uniformly-random, {bit_array.num_bits}-qubit samples."
)

Output:

Generated 10000 uniformly-random, 16-qubit samples.

3. SQDによる後処理

SQDアルゴリズムの目的は、QPUから取得したノイズの多いサンプルを精緻化し、最終的にそれらの精緻化されたサンプルによって張られる部分空間においてハミルトニアンを対角化することです。 これは、次のように反復的に行われます:

  • スピンアップおよびスピンダウンの両サブシステムにおいて、粒子数が正しいサンプルのみを後選択して、サンプルを絞り込む
  • 精緻化されたサンプルによって張られる小さな部分空間について対角化を行い、エネルギーが最小となる部分空間に関する情報を収集する。
  • 各反復ごとに:
    • 粒子数が不正確なサンプルのビットを確率的に反転させることで、ノイズの多いサンプルを精緻化する。 確率は、直近の対角化から得られた部分空間情報を用いて計算される。
    • 精製されたサンプルによって張られる小さな部分空間において対角化を行う
    • 最良(最小)のエネルギーをもたらす部分空間に関する情報を収集する

出力結果から、アルゴリズムが 回の反復後に 6 正確な基底状態エネルギーに収束すること、また、次元 (85)2=3136\binom{8}{5}^2=3136 のヒルベルト部分空間全体に対して対角化が行われていることがわかります。もちろん、部分空間全体に対して対角化を行うことは通常現実的ではないため、基底状態のサポートが疎な系ほど、SQDなどの部分空間対角化手法の恩恵を受けやすいと言えます。

diagonalize_fermionic_hamiltonian 関数の詳細については、 APIドキュメントをご覧ください。

from functools import partial

from pyscf import fci
from qiskit_addon_sqd.fermion import (
    SCIResult,
    diagonalize_fermionic_hamiltonian,
    solve_sci_batch,
)

exact_energy, _ = fci.direct_spin1.kernel(
    hcore, eri, int(num_orbitals), nelec
)
exact_energy += nuclear_repulsion_energy
print(f"Exact (FCI) reference energy: {exact_energy:.6f} Ha\n")

sci_solver = partial(solve_sci_batch, spin_sq=0.0, max_cycle=200)

result_history = []


def callback(results: list[SCIResult]):
    result_history.append(results)
    iteration = len(result_history)
    print(f"Iteration {iteration}")
    for i, result in enumerate(results):
        error = result.energy + nuclear_repulsion_energy - exact_energy
        print(f"  Subsample {i}")
        print(f"    Energy: {result.energy + nuclear_repulsion_energy:.6f}")
        print(
            f"    Subspace dimension: {np.prod(result.sci_state.amplitudes.shape)}"
        )
        print(f"    Error vs exact: {error:.6f} Ha")


samples_per_batch = 20
result = diagonalize_fermionic_hamiltonian(
    hcore,
    eri,
    bit_array,
    samples_per_batch=samples_per_batch,
    norb=num_orbitals,
    nelec=nelec,
    occupancies_tol=1e-7,
    max_iterations=30,
    sci_solver=sci_solver,
    symmetrize_spin=True,
    callback=callback,
    seed=np.random.default_rng(32),
)

Output:

Exact (FCI) reference energy: -107.652521 Ha

Iteration 1
  Subsample 0
    Energy: -106.908481
    Subspace dimension: 784
    Error vs exact: 0.744040 Ha
Iteration 2
  Subsample 0
    Energy: -106.934921
    Subspace dimension: 1764
    Error vs exact: 0.717600 Ha
Iteration 3
  Subsample 0
    Energy: -106.953430
    Subspace dimension: 2209
    Error vs exact: 0.699091 Ha
Iteration 4
  Subsample 0
    Energy: -107.651946
    Subspace dimension: 2916
    Error vs exact: 0.000575 Ha
Iteration 5
  Subsample 0
    Energy: -107.652003
    Subspace dimension: 3025
    Error vs exact: 0.000518 Ha
Iteration 6
  Subsample 0
    Energy: -107.652521
    Subspace dimension: 3136
    Error vs exact: 0.000000 Ha
Iteration 7
  Subsample 0
    Energy: -107.652521
    Subspace dimension: 3136
    Error vs exact: 0.000000 Ha
このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。