Hamiltonian untuk Kimia Kuantum
Mari kita mulai dengan gambaran singkat tentang peran Hamiltonian dalam VQE.
Gambaran Umum Hamiltonian dalam VQE​
Dr. Victoria Lipinska memandu kita memahami Hamiltonian dan cara memetakannya untuk digunakan dalam komputasi kuantum.
Referensi​
Artikel-artikel berikut dirujuk dalam video di atas.
- Quantum Algorithms for Fermionic Simulations, Ortiz, et al.
- Simulating Chemistry using Quantum Computers, Kassal et al.
- A Comparison of the Bravyi–Kitaev and Jordan–Wigner Transformations for the Quantum Simulation of Quantum Chemistry, Tranter, et al.
- Quantum Chemistry in the Age of Quantum Computing, Cao, et al.
- Quantum computational chemistry, McArdle, et al.
- The Bravyi-Kitaev transformation for quantum computation of electronic structure, Seeley, et al., McArdle, et al.
Menyiapkan Hamiltonian untuk Kimia Kuantum​
Langkah pertama yang baik dalam menerapkan komputasi kuantum pada masalah kimia adalah mendefinisikan Hamiltonian untuk sistem yang diinginkan. Di sini, kita akan membatasi pembahasan pada Hamiltonian kimia kuantum, karena Hamiltonian tersebut memerlukan pemetaan khusus untuk sistem fermion identik.
Sebagai seseorang yang bekerja di bidang kimia kuantum, kamu mungkin sudah punya software favorit untuk memodelkan molekul, yang dapat menghasilkan Hamiltonian yang mendeskripsikan sistem yang kamu minati. Di sini, kita akan menggunakan kode yang dibangun sepenuhnya dari PySCF, numpy, dan Qiskit. Namun proses persiapan Hamiltonian ini berlaku juga untuk solusi yang sudah dikemas. Satu-satunya perbedaan antara pendekatan ini dan software lain hanyalah perbedaan sintaks minor; beberapa di antaranya dibahas di subbagian "Software pihak ketiga" untuk memudahkan integrasi dengan workflow yang sudah ada.
Untuk menghasilkan Hamiltonian kimia kuantum yang siap digunakan pada QPU IBM Quantum® melibatkan langkah-langkah berikut:
- Definisikan molekulmu (geometri, spin, ruang aktif, dan sebagainya)
- Buat Hamiltonian fermionik (operator kreasi dan anihilasi)
- Petakan dari Hamiltonian fermionik ke operator bosonik (dalam konteks ini, menggunakan operator Pauli)
- Jika menggunakan software pihak ketiga: Tangani ketidakcocokan sintaks antara software pembuat dan Qiskit
Hamiltonian fermionik ditulis dalam bentuk operator fermionik, dan khususnya, memperhitungkan bahwa elektron adalah fermion tak-terbedakan. Artinya mereka mematuhi statistik yang sama sekali berbeda dari qubit yang dapat dibedakan dan bersifat bosonik. Inilah mengapa perlu ada proses pemetaan.
Bagi kamu yang sudah familiar dengan proses-proses ini, bagian ini mungkin bisa dilewati. Tujuan:
Tujuan akhirnya adalah mendapatkan Hamiltonian dalam bentuk:
# Added by doQumentation — required packages for this notebook
!pip install -q numpy openfermion pyscf qiskit
H = [(1, "XX"), (1, "YY"), (1, "ZZ")]
print(H)
[(1, 'XX'), (1, 'YY'), (1, 'ZZ')]
Atau
from qiskit.quantum_info import SparsePauliOp
H = SparsePauliOp(["XX", "YY", "ZZ"], coeffs=[1.0 + 0.0j, 1.0 + 0.0j, 1.0 + 0.0j])
print(H)
SparsePauliOp(['XX', 'YY', 'ZZ'],
coeffs=[1.+0.j, 1.+0.j, 1.+0.j])
Kita mulai dengan mengimpor beberapa paket:
import numpy as np
from pyscf import ao2mo, gto, mcscf, scf
- Definisikan molekulmu
Di sini kita akan menentukan atribut dari molekul yang diinginkan. Dalam contoh ini, kita memilih hidrogen diatomik (karena Hamiltonian yang dihasilkan cukup pendek untuk ditampilkan). Python-based Simulations of Chemistry Framework (PySCF) memiliki koleksi modul struktur elektronik yang luas yang dapat digunakan untuk, antara lain, menghasilkan Hamiltonian molekuler yang cocok untuk komputasi kuantum. Panduan PySCF Quickstart adalah sumber daya yang sangat baik untuk deskripsi lengkap semua variabel dan fungsionalitasnya. Kita hanya akan memberikan gambaran paling singkat, karena banyak dari kalian yang sudah familiar. Untuk memahaminya lebih baik, kunjungi PySCF. Singkatnya:
distance bisa digunakan untuk molekul diatomik, atau cukup tentukan koordinat Kartesian untuk setiap atom. Jarak dalam satuan Angstrom.
gto menghasilkan orbital tipe Gaussian.
basis mengacu pada fungsi yang digunakan untuk memodelkan orbital molekuler. Di sini 'sto-6g' adalah basis minimal yang umum, dinamai dari fitting Slater-Type Orbitals menggunakan 6 orbital Gaussian primitif.
spin nilai integer yang menunjukkan jumlah elektron tidak berpasangan (sama dengan ). Perhatikan bahwa beberapa software menggunakan multiplisitas ().
charge muatan molekul.
symmetry - kelompok simetri titik molekul, bisa ditentukan dengan string atau dideteksi otomatis dengan mengatur "symmetry = True". Di sini "Dooh" adalah kelompok simetri yang tepat untuk molekul diatomik dengan dua spesies atom yang sama.
distance = 0.735
a = distance / 2
mol = gto.Mole()
mol.build(
verbose=0,
atom=[
["H", (0, 0, -a)],
["H", (0, 0, a)],
],
basis="sto-6g",
spin=0,
charge=0,
symmetry="Dooh",
)
<pyscf.gto.mole.Mole at 0x7fc718f07610>
Ingat bahwa kita bisa mendeskripsikan energi total (yang mencakup energi repulsi nuklir serta elektronik), energi orbital elektronik total, atau energi sebagian orbital elektronik (dengan subset pelengkap yang dibekukan). Dalam kasus khusus , perhatikan energi yang berbeda di bawah ini, dan perhatikan bahwa total energi dikurangi energi repulsi nuklir memang menghasilkan energi elektronik:
mf = scf.RHF(mol)
mf.scf()
print(
mf.energy_nuc(),
mf.energy_elec()[0],
mf.energy_tot(),
mf.energy_tot() - mol.energy_nuc(),
)
0.7199689944489797 -1.8455976628764188 -1.125628668427439 -1.8455976628764188
active_space = range(mol.nelectron // 2 - 1, mol.nelectron // 2 + 1)
- Buat Hamiltonian fermionik
scf mengacu pada berbagai metode self-consistent field.
rhf seperti dalam mf = scf.RHF(mol) di mf adalah solver yang menggunakan perhitungan Restricted Hartree Fock. Kernel dari ini (E, di bawah) adalah energi total, termasuk repulsi nuklir dan orbital molekuler.
mcscf adalah paket multi-konfigurasi self-consistent fields.
ao2mo adalah transformasi dari orbital atomik ke orbital molekuler.
Kita juga menggunakan variabel-variabel berikut:
ncas: jumlah orbital dalam complete active space
nelecas: jumlah elektron dalam complete active space
E1 = mf.kernel()
mx = mcscf.CASCI(mf, ncas=2, nelecas=(1, 1))
mo = mx.sort_mo(active_space, base=0)
E2 = mx.kernel(mo)[:2]
Kita menginginkan Hamiltonian, dan ini sering dipisahkan menjadi energi inti elektronik (ecore, tidak terlibat dalam minimisasi), operator elektron tunggal (h1e), dan energi dua elektron (h2e). Ini diekstrak secara eksplisit di bawah ini pada dua baris terakhir.
h1e, ecore = mx.get_h1eff()
h2e = ao2mo.restore(1, mx.get_h2eff(), mx.ncas)
Hamiltonian-Hamiltonian ini saat ini adalah operator fermionik (kreasi dan anihilasi), yang berlaku untuk sistem fermion (tak-terbedakan), dan karenanya tunduk pada antisimetri di bawah pertukaran. Ini menghasilkan statistik yang berbeda dari yang berlaku untuk sistem yang dapat dibedakan atau bosonik. Untuk menjalankan perhitungan pada QPU IBM Quantum, kita memerlukan operator bosonik yang mendeskripsikan energinya. Hasil dari pemetaan semacam itu secara konvensional ditulis dalam bentuk operator Pauli, karena keduanya bersifat Hermitian dan uniter. Ada beberapa pemetaan yang bisa digunakan. Salah satu yang paling sederhana adalah transformasi Jordan Wigner.
- Pemetaan Hamiltonian
Perlu dicatat bahwa ada banyak alat yang tersedia untuk memetakan Hamiltonian kimia ke yang cocok untuk dijalankan pada komputer kuantum. Di sini, kita mengimplementasikan pemetaan Jordan Wigner secara langsung hanya menggunakan PySCF, numpy, dan Qiskit. Kita berkomentar di bawah tentang pertimbangan sintaks untuk solusi lain. Fungsi Cholesky membantu kita mendapatkan dekomposisi low-rank dari suku dua elektron dalam Hamiltonian.
def cholesky(V, eps):
# see https://arxiv.org/pdf/1711.02242.pdf section B2
# see https://arxiv.org/abs/1808.02625
# see https://arxiv.org/abs/2104.08957
no = V.shape[0]
chmax, ng = 20 * no, 0
W = V.reshape(no**2, no**2)
L = np.zeros((no**2, chmax))
Dmax = np.diagonal(W).copy()
nu_max = np.argmax(Dmax)
vmax = Dmax[nu_max]
while vmax > eps:
L[:, ng] = W[:, nu_max]
if ng > 0:
L[:, ng] -= np.dot(L[:, 0:ng], (L.T)[0:ng, nu_max])
L[:, ng] /= np.sqrt(vmax)
Dmax[: no**2] -= L[: no**2, ng] ** 2
ng += 1
nu_max = np.argmax(Dmax)
vmax = Dmax[nu_max]
L = L[:, :ng].reshape((no, no, ng))
print(
"accuracy of Cholesky decomposition ",
np.abs(np.einsum("prg,qsg->prqs", L, L) - V).max(),
)
return L, ng
Fungsi identity dan creators_destructors menggantikan operator kreasi dan anihilasi dalam Hamiltonian fermionik dengan operator Pauli; creators_destructors menggunakan pemetaan Jordan-Wigner.
def identity(n):
return SparsePauliOp.from_list([("I" * n, 1)])
def creators_destructors(n, mapping="jordan_wigner"):
c_list = []
if mapping == "jordan_wigner":
for p in range(n):
if p == 0:
ell, r = "I" * (n - 1), ""
elif p == n - 1:
ell, r = "", "Z" * (n - 1)
else:
ell, r = "I" * (n - p - 1), "Z" * p
cp = SparsePauliOp.from_list([(ell + "X" + r, 0.5), (ell + "Y" + r, -0.5j)])
c_list.append(cp)
else:
raise ValueError("Unsupported mapping.")
d_list = [cp.adjoint() for cp in c_list]
return c_list, d_list
Terakhir, build_hamiltonian menggunakan fungsi cholesky, identity, dan creators_destructors untuk membuat Hamiltonian akhir yang cocok untuk dijalankan pada komputer kuantum.
def build_hamiltonian(ecore: float, h1e: np.ndarray, h2e: np.ndarray) -> SparsePauliOp:
ncas, _ = h1e.shape
C, D = creators_destructors(2 * ncas, mapping="jordan_wigner")
Exc = []
for p in range(ncas):
Excp = [C[p] @ D[p] + C[ncas + p] @ D[ncas + p]]
for r in range(p + 1, ncas):
Excp.append(
C[p] @ D[r]
+ C[ncas + p] @ D[ncas + r]
+ C[r] @ D[p]
+ C[ncas + r] @ D[ncas + p]
)
Exc.append(Excp)
# low-rank decomposition of the Hamiltonian
Lop, ng = cholesky(h2e, 1e-6)
t1e = h1e - 0.5 * np.einsum("pxxr->pr", h2e)
H = ecore * identity(2 * ncas)
# one-body term
for p in range(ncas):
for r in range(p, ncas):
H += t1e[p, r] * Exc[p][r - p]
# two-body term
for g in range(ng):
Lg = 0 * identity(2 * ncas)
for p in range(ncas):
for r in range(p, ncas):
Lg += Lop[p, r, g] * Exc[p][r - p]
H += 0.5 * Lg @ Lg
return H.chop().simplify()
Terakhir, kita menggunakan build_hamiltonian untuk membangun Hamiltonian qubit kita dari operator Pauli menggunakan transformasi Jordan-Wigner. Ini juga memberikan kita akurasi dekomposisi Cholesky yang kita gunakan.
H = build_hamiltonian(ecore, h1e, h2e)
print(H)
accuracy of Cholesky decomposition 2.220446049250313e-16
SparsePauliOp(['IIII', 'IIIZ', 'IZII', 'IIZI', 'ZIII', 'IZIZ', 'IIZZ', 'ZIIZ', 'IZZI', 'ZZII', 'ZIZI', 'YYYY', 'XXYY', 'YYXX', 'XXXX'],
coeffs=[-0.09820182+0.j, -0.1740751 +0.j, -0.1740751 +0.j, 0.2242933 +0.j,
0.2242933 +0.j, 0.16891402+0.j, 0.1210099 +0.j, 0.16631441+0.j,
0.16631441+0.j, 0.1210099 +0.j, 0.17504456+0.j, 0.04530451+0.j,
0.04530451+0.j, 0.04530451+0.j, 0.04530451+0.j])
Notebook contoh molekul ini menunjukkan pengaturan dan Hamiltonian untuk beberapa molekul dengan berbagai kompleksitas; dengan sedikit modifikasi, ini seharusnya memungkinkan kamu memeriksa sebagian besar molekul kecil.
Mari kita catat dua poin penting yang perlu diperhatikan saat membangun operator fermionik untuk molekul. Seiring berubahnya jenis molekul, simetrinya pun akan berubah. Demikian pula, jumlah orbital dengan berbagai simetri, seperti "A1" yang simetris secara silindris, akan berubah. Perubahan-perubahan ini terlihat jelas bahkan dengan ekstensi sederhana ke LiH, seperti yang terlihat di sini:
distance = 1.56
mol = gto.Mole()
mol.build(
verbose=0,
atom=[["Li", (0, 0, 0)], ["H", (0, 0, distance)]],
basis="sto-6g",
spin=0,
charge=0,
symmetry="Coov",
)
mf = scf.RHF(mol)
E1 = mf.kernel()
# %% ----------------------------------------------------------------------------------------------
mx = mcscf.CASCI(mf, ncas=5, nelecas=(1, 1))
cas_space_symmetry = {"A1": 3, "E1x": 1, "E1y": 1}
mo = mcscf.sort_mo_by_irrep(mx, mf.mo_coeff, cas_space_symmetry)
E2 = mx.kernel(mo)[:2]
h1e, ecore = mx.get_h1eff()
h2e = ao2mo.restore(1, mx.get_h2eff(), mx.ncas)
Perlu juga dicatat bahwa intuisi terhadap Hamiltonian akhir yang dihasilkan bisa cepat hilang. Hamiltonian untuk LiH (menggunakan mapper Jordan-Wigner) sudah terdiri dari 276 suku.
len(build_hamiltonian(ecore, h1e, h2e))
accuracy of Cholesky decomposition 1.1102230246251565e-16
276
Saat ragu mengenai simetri, kamu juga bisa menghasilkan beberapa informasi simetri untuk molekul dengan mengatur symmetry = True dan verbose = 4:
distance = 1.56
mol = gto.Mole()
mol.build(
verbose=4,
atom=[["Li", (0, 0, 0)], ["H", (0, 0, distance)]],
basis="sto-6g",
spin=0,
charge=0,
symmetry=True,
)
System: uname_result(system='Linux', node='IBM-R912JTRT', release='5.10.102.1-microsoft-standard-WSL2', version='#1 SMP Wed Mar 2 00:30:59 UTC 2022', machine='x86_64') Threads 16
Python 3.11.12 (main, May 16 2025, 02:33:32) [GCC 11.4.0]
numpy 2.3.1 scipy 1.16.0 h5py 3.14.0
Date: Mon Jun 30 12:56:55 2025
PySCF version 2.9.0
PySCF path /home/porter284/.pyenv/versions/3.11.12/lib/python3.11/site-packages/pyscf
[CONFIG] conf_file None
[INPUT] verbose = 4
[INPUT] num. atoms = 2
[INPUT] num. electrons = 4
[INPUT] charge = 0
[INPUT] spin (= nelec alpha-beta = 2S) = 0
[INPUT] symmetry True subgroup None
[INPUT] Mole.unit = angstrom
[INPUT] Symbol X Y Z unit X Y Z unit Magmom
[INPUT] 1 Li 0.000000000000 0.000000000000 0.000000000000 AA 0.000000000000 0.000000000000 0.000000000000 Bohr 0.0
[INPUT] 2 H 0.000000000000 0.000000000000 1.560000000000 AA 0.000000000000 0.000000000000 2.947972754321 Bohr 0.0
nuclear repulsion = 1.01764848253846
point group symmetry = Coov
symmetry origin: [0. 0. 0.73699319]
symmetry axis x: [1. 0. 0.]
symmetry axis y: [0. 1. 0.]
symmetry axis z: [0. 0. 1.]
num. orbitals of irrep A1 = 4
num. orbitals of irrep E1x = 1
num. orbitals of irrep E1y = 1
number of shells = 4
number of NR pGTOs = 36
number of NR cGTOs = 6
basis = sto-6g
ecp = {}
CPU time: 9.85
<pyscf.gto.mole.Mole at 0x7fc719f94850>
Di antara informasi berguna lainnya, ini mengembalikan point group symmetry = Coov dan juga jumlah orbital dalam setiap representasi tak-tereduksi.
point group symmetry = Coov
num. orbitals of irrep A1 = 4
num. orbitals of irrep E1x = 1
num. orbitals of irrep E1y = 1
number of shells = 4
Ini tidak selalu memberi tahu kamu berapa banyak orbital yang ingin disertakan dalam ruang aktifmu, tapi membantu kamu melihat orbital apa yang ada dan simetrinya.
Menentukan simetri dan orbital seringkali berguna, tapi kamu juga bisa menentukan jumlah orbital yang ingin disertakan. Perhatikan kasus etena berikut. Menggunakan verbose = 4, kita bisa mencetak simetri dari berbagai orbital:
# Replace these variables with correct distances:
a = 1
b = 1
c = 1
# Build
mol = gto.Mole()
mol.build(
verbose=4,
atom=[
["C", (0, 0, a)],
["C", (0, 0, -a)],
["H", (0, c, b)],
["H", (0, -c, b)],
["H", (0, c, -b)],
["H", (0, -c, -b)],
],
basis="sto-6g",
spin=0,
charge=0,
symmetry=True,
)
System: uname_result(system='Linux', node='IBM-R912JTRT', release='5.10.102.1-microsoft-standard-WSL2', version='#1 SMP Wed Mar 2 00:30:59 UTC 2022', machine='x86_64') Threads 16
Python 3.11.12 (main, May 16 2025, 02:33:32) [GCC 11.4.0]
numpy 2.3.1 scipy 1.16.0 h5py 3.14.0
Date: Mon Jun 30 12:57:07 2025
PySCF version 2.9.0
PySCF path /home/porter284/.pyenv/versions/3.11.12/lib/python3.11/site-packages/pyscf
[CONFIG] conf_file None
[INPUT] verbose = 4
[INPUT] num. atoms = 6
[INPUT] num. electrons = 16
[INPUT] charge = 0
[INPUT] spin (= nelec alpha-beta = 2S) = 0
[INPUT] symmetry True subgroup None
[INPUT] Mole.unit = angstrom
[INPUT] Symbol X Y Z unit X Y Z unit Magmom
[INPUT] 1 C 0.000000000000 0.000000000000 1.000000000000 AA 0.000000000000 0.000000000000 1.889726124565 Bohr 0.0
[INPUT] 2 C 0.000000000000 0.000000000000 -1.000000000000 AA 0.000000000000 0.000000000000 -1.889726124565 Bohr 0.0
[INPUT] 3 H 0.000000000000 1.000000000000 1.000000000000 AA 0.000000000000 1.889726124565 1.889726124565 Bohr 0.0
[INPUT] 4 H 0.000000000000 -1.000000000000 1.000000000000 AA 0.000000000000 -1.889726124565 1.889726124565 Bohr 0.0
[INPUT] 5 H 0.000000000000 1.000000000000 -1.000000000000 AA 0.000000000000 1.889726124565 -1.889726124565 Bohr 0.0
[INPUT] 6 H 0.000000000000 -1.000000000000 -1.000000000000 AA 0.000000000000 -1.889726124565 -1.889726124565 Bohr 0.0
nuclear repulsion = 29.3377079104231
point group symmetry = D2h
symmetry origin: [0. 0. 0.]
symmetry axis x: [0. 1. 0.]
symmetry axis y: [1. 0. 0.]
symmetry axis z: [-0. -0. -1.]
num. orbitals of irrep Ag = 4
num. orbitals of irrep B2g = 2
num. orbitals of irrep B3g = 1
num. orbitals of irrep B1u = 4
num. orbitals of irrep B2u = 1
num. orbitals of irrep B3u = 2
number of shells = 10
number of NR pGTOs = 84
number of NR cGTOs = 14
basis = sto-6g
ecp = {}
CPU time: 9.92
<pyscf.gto.mole.Mole at 0x7fc719fa9290>
Kita mendapatkan:
num. orbitals of irrep Ag = 4
num. orbitals of irrep B2g = 2
num. orbitals of irrep B3g = 1
num. orbitals of irrep B1u = 4
num. orbitals of irrep B2u = 1
num. orbitals of irrep B3u = 2
Tapi daripada menentukan semua orbital berdasarkan simetri, kita bisa cukup menulis:
active_space = range(mol.nelectron // 2 - 2, mol.nelectron // 2 + 2)
Dalam pendekatan ini, kita mengambil beberapa orbital di sekitar level pengisian (valensi dan yang tidak terisi). Di sini, 5 orbital telah dipilih untuk disertakan dalam ruang aktif (orbital ke-6 hingga ke-10).
print(
mol.nelectron // 2 - 2,
mol.nelectron // 2 + 2,
)
6 10
- Software Pihak Ketiga
Ada beberapa paket software yang dikembangkan untuk kimia kuantum, beberapa menawarkan beberapa mapper dan alat untuk membatasi ruang aktif. Langkah-langkah yang dijelaskan di atas bersifat umum dan berlaku untuk software pihak ketiga juga. Namun software lain ini mungkin mengembalikan Hamiltonian dalam format yang tidak diterima oleh Qiskit. Sebagai contoh, beberapa software mengembalikan Hamiltonian dalam bentuk:
H = -0.042 [] + -0.045 [X0 X1 Y2 Y3] + ... + 0.178 [Z0] + ... + 0.176 [Z2 Z3] + -0.243 [Z3]
Perhatikan khususnya bahwa Gate diberi nomor, dan operator identitas tidak ditampilkan. Ini berbeda dengan Hamiltonian yang digunakan dalam Qiskit, yang akan menulis suku [Z2 Z3] sebagai ZZII (qubit 0 dan 1 dikenai operator identitas, qubit 2 dan 3 dikenai operator Z, diurutkan dengan qubit 0 paling kanan).
Untuk mengakomodasi workflow yang sudah ada, blok kode di bawah ini mengkonversi dari satu sintaks ke sintaks lainnya. Fungsi convert_openfermion_to_qiskit mengambil sebagai argumennya Hamiltonian yang dihasilkan dalam OpenFermion atau Tangelo (dan sudah dipetakan ke operator Pauli menggunakan mapper yang tersedia), dan jumlah qubit yang dibutuhkan untuk molekul tersebut.
from openfermion import QubitOperator
from qiskit.quantum_info import SparsePauliOp
def convert_openfermion_to_qiskit(
openfermion_operator: QubitOperator, num_qubits: int
) -> SparsePauliOp:
terms = openfermion_operator.terms
labels = []
coefficients = []
for term, constant in terms.items():
# Default set to identity
operator = list("I" * num_qubits)
# Iterate through PauliSum and replace I with Pauli
for index, pauli in term:
operator[index] = pauli
label = "".join(operator)
labels.append(label)
coefficients.append(constant)
return SparsePauliOp(labels, coefficients)
Selanjutnya, notebook Python ini berisi kode contoh lengkap untuk memigrasikan Hamiltonian dari workflow software lain ke Qiskit, termasuk konversi di atas.
Kamu sekarang punya bekal alat untuk mendapatkan Hamiltonian yang kamu butuhkan dalam melakukan perhitungan kimia kuantum pada komputer kuantum IBM®.