Rychlý start
Tento návod ukazuje minimální funkční příklad balíčku qiskit-addon-sqd. Pomocí sample-based quantum diagonalization (SQD) zpřesňujeme zašuměné vzorky získané z kvantového obvodu, který aproximuje základní stav chemického Hamiltoniánu. Energie základního stavu se aproximují diagonalizací Hamiltoniánu v podprostorech tvořených zpřesněnými vzorky.
Podrobnější kompletní workflowy spouštěné na kvantovém hardwaru najdeš v tutoriálech:
-
Sample-based quantum diagonalization: workflow pro chemický Hamiltonián
-
Sample-based Krylov quantum diagonalization: workflow pro fermionový mřížkový model
1. Příprava vstupů pro SQD
Nejprve definujeme chemický Hamiltonián a kvantový obvod, který aproximuje jeho základní stav. Systémem studovaným v tomto příkladu je N₂ v rovnovážné geometrii v bázi STO-3G se dvěma zamrazenými jádrovými orbitaly. Tento systém má 8 prostorových orbitalů a 10 elektronů, což znamená, že kvantový obvod je definován na 16 qubitech, kde qubity 0-7 představují orbitaly se spinem nahoru a qubity 8-15 orbitaly se spinem dolů. Protože jde o systém s uzavřenými slupkami s 10 elektrony, víme, že každý fyzikálně platný vzorek by měl mít Hammingovu váhu 10, přičemž Hammingova váha levé i pravé poloviny bitového řetězce je 5.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"numpy": "numpy", "pyscf": "pyscf", "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")
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}"
)
Spatial orbitals: 8
Qubits: 16
Electrons (alpha, beta): (5, 5)
2. Generování zašuměných vzorků
V reálném workflowu bys navrhl ansatz obvod, optimalizoval ho pro hardware a vzorkoval ho na QPU. Zde to přeskočíme a místo toho vygenerujeme 10,000 rovnoměrně náhodných bitových řetězců. Ačkoli naše vzorky neobsahují žádnou informaci o skutečném základním stavu, uvidíme, že protokol SQD může skutečný základní stav přesto obnovit tím, že tyto vzorky iterativně zpřesňuje, diagonalizuje a energie z každé iterace využívá k řízení dalšího kola zpřesňování bitových řetězců. Přesný základní stav můžeme tímto způsobem nakonec obnovit, protože podprostor obsahující základní stav je dostatečně malý, aby šel spočítat přesně. Protože víme, že každá polovina každého bitového řetězce (8 bitů) by měla mít Hammingovu váhu 5, víme konkrétně, že celý Hilbertův podprostor systému má velikost .
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."
)
Generated 10000 uniformly-random, 16-qubit samples.
3. Následné zpracování pomocí SQD
Cílem algoritmu SQD je zpřesnit zašuměné vzorky získané z QPU a nakonec diagonalizovat Hamiltonián v podprostoru generovaném těmito zpřesněnými vzorky. To se provádí iterativně takto:
-
Zpřesni vzorky postselekcí pouze těch, které mají správný počet částic pro podsystémy se spinem nahoru i dolů
-
Diagonalizuj v malých podprostorech generovaných zpřesněnými vzorky a shromažďuj informace o podprostorech, které poskytují nejlepší (nejnižší) energie.
-
Pro každou iteraci:
-
Zpřesni zašuměné vzorky pravděpodobnostním překlápěním bitů ve vzorcích s nesprávným počtem částic. Pravděpodobnosti se počítají z informací o podprostoru z poslední diagonalizace.
-
Diagonalizuj v malých podprostorech generovaných zpřesněnými vzorky
-
Shromáždi informace o podprostorech poskytujících nejlepší (nejnižší) energie
-
Z výstupu vidíme, že algoritmus konverguje k přesné energii základního stavu po 6 iteracích a že diagonalizace je provedena v celém Hilbertově podprostoru dimenze . Diagonalizace v celém podprostoru samozřejmě obvykle není proveditelná, a proto z technik diagonalizace v podprostoru, jako je SQD, nejpravděpodobněji profitují systémy se základními stavy s řídkým nosičem.
Další informace o funkci diagonalize_fermionic_hamiltonian najdeš v dokumentaci 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),
)
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