انتقل إلى المحتوى الرئيسي

تحديد هندسة الجزيء

في القسم السابق، طبّقنا خوارزمية VQE لتحديد طاقة الحالة الأساسية لجزيء ما. هذا استخدام مشروع للحوسبة الكمية، لكن الأكثر فائدة هو تحديد بنية الجزيء.

الخطوة 1: تحويل المدخلات الكلاسيكية إلى مسألة كمية

بالبقاء مع مثالنا الأساسي على الهيدروجين ثنائي الذرة، المعامل الهندسي الوحيد الذي يمكن تغييره هو طول الرابطة. لتحقيق ذلك، نسير كما في السابق، لكن مع استخدام متغير في بناء الجزيء الأولي (طول الرابطة، x، في الوسيطة). هذا تغيير بسيط نسبياً، لكنه يستلزم تضمين المتغير في الدوال طوال العملية، لأنه يبدأ في بناء هاميلتوني الفرميون وينتشر عبر عملية التعيين وصولاً إلى دالة التكلفة.

أولاً، نحمّل بعض الحزم التي استخدمناها سابقاً ونعرّف دالة Cholesky.

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy pyscf qiskit qiskit-aer qiskit-ibm-runtime scipy
from qiskit.quantum_info import SparsePauliOp
import matplotlib.pyplot as plt
import numpy as np

#!pip install pyscf==2.4.0
from pyscf import ao2mo, gto, mcscf, scf

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

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

الآن لتعريف الهاميلتوني، سنستخدم PySCF تماماً كما في المثال السابق، لكننا سنضمّن متغيراً x ليمثّل المسافة بين الذرتين. سيُعيد هذا طاقة النواة وطاقة الإلكترون الأحادي وطاقات الإلكترونين كما في السابق.

def ham_terms(x: float):
distance = x
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",
)

# mf = scf.RHF(mol)
# mx = mcscf.CASCI(mf, ncas=2, nelecas=(1, 1))
# mx.kernel()

mf = scf.RHF(mol)
mf.kernel()
if not mf.converged:
raise RuntimeError(f"SCF did not converge for distance {x}")

mx = mcscf.CASCI(mf, ncas=2, nelecas=(1, 1))
casci_energy = mx.kernel()
if casci_energy is None:
raise RuntimeError(f"CASCI failed for distance {x}")

# Other variables that might come in handy:
# active_space = range(mol.nelectron // 2 - 1, mol.nelectron // 2 + 1)
# E1 = mf.kernel()
# mo = mx.sort_mo(active_space, base=0)
# E2 = mx.kernel(mo)[:2]

h1e, ecore = mx.get_h1eff()
h2e = ao2mo.restore(1, mx.get_h2eff(), mx.ncas)
return ecore, h1e, h2e

تذكّر أن البناء أعلاه يُنشئ هاميلتونياً فيرميونياً بناءً على الأنواع الذرية والهندسة والمدارات الإلكترونية. في الأسفل، نُعيّن هذا الهاميلتوني الفيرميوني على مؤثرات باولي. ستتضمن دالة build_hamiltonian هذه أيضاً متغيراً هندسياً كوسيطة.

def build_hamiltonian(distx: float) -> SparsePauliOp:
ecore = ham_terms(distx)[0]
h1e = ham_terms(distx)[1]
h2e = ham_terms(distx)[2]

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

سنحمّل الحزم المتبقية اللازمة لتشغيل VQE نفسه، مثل الدائرة التقريبية efficient_su2 ومُحسِّنات SciPy:

# General imports

# Pre-defined ansatz circuit and operator class for Hamiltonian
from qiskit.circuit.library import efficient_su2
from qiskit.quantum_info import SparsePauliOp

# SciPy minimizer routine
from scipy.optimize import minimize

# Plotting functions

# Qiskit Runtime tools
from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()

سنُعرِّف دالة التكلفة من جديد، لكنها كانت دائماً تأخذ هاميلتونياً مبنياً ومُعيَّناً بالكامل كوسيطة، لذا لا يتغيّر شيء في هذه الدالة.

def cost_func(params, ansatz, H, estimator):
pub = (ansatz, [H], [params])
result = estimator.run(pubs=[pub]).result()
energy = result[0].data.evs[0]
return energy

# def cost_func_sim(params, ansatz, H, estimator):
# energy = estimator.run(ansatz, H, parameter_values=params).result().values[0]
# return energy

الخطوة 2: تهيئة المسألة للتنفيذ الكمي

بما أن الهاميلتوني سيتغيّر مع كل هندسة جديدة، فإن عملية تحويل المؤثر ستتغيّر في كل خطوة. بالرغم من ذلك، يمكننا تعريف مدير تمرير عام يُطبَّق في كل خطوة، مُخصَّص للعتاد الذي نريد استخدامه.

هنا سنستخدم الخلفية الأقل ازدحاماً المتاحة. سنستخدم تلك الخلفية كنموذج لـ AerSimulator الخاص بنا، مما يتيح لمحاكينا محاكاة سلوك الضوضاء للخلفية الحقيقية على سبيل المثال. هذه النماذج الضوضائية ليست مثالية، لكنها قد تساعدك على توقّع ما ستحصل عليه من العتاد الحقيقي.

# Here, we select the least busy backend available:
backend = service.least_busy(operational=True, simulator=False)
print(backend)
# Or to select a specific real backend use the line below, and substitute 'ibm_strasbourg' for your chosen device.
# backend = service.get_backend('ibm_strasbourg')
# To run on a simulator:
# -----------
from qiskit_aer import AerSimulator

backend_sim = AerSimulator.from_backend(backend)

نستورد مدير التمرير والحزم المرتبطة به لمساعدتنا في تهيئة دائرتنا. هذه الخطوة والخطوة التي تسبقها مستقلتان عن الهاميلتوني، لذا تبقيان دون تغيير عن الدرس السابق.

from qiskit.transpiler import PassManager
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.transpiler.passes import (
ALAPScheduleAnalysis,
PadDynamicalDecoupling,
ConstrainedReschedule,
)
from qiskit.circuit.library import XGate

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
pm.scheduling = PassManager(
[
ALAPScheduleAnalysis(target=target),
ConstrainedReschedule(
acquire_alignment=target.acquire_alignment,
pulse_alignment=target.pulse_alignment,
target=target,
),
PadDynamicalDecoupling(
target=target,
dd_sequence=[XGate(), XGate()],
pulse_alignment=target.pulse_alignment,
),
]
)

الخطوة 3: التنفيذ باستخدام أدوات Qiskit البدائية

في كتلة الكود أدناه، نُعدّ مصفوفة لتخزين مخرجاتنا من كل خطوة في المسافة بين الذرات xx. لقد اخترنا نطاق xx بناءً على معرفتنا بالقيمة التجريبية لطول الرابطة التوازني: 0.74 أنجستروم. سنُشغّل هذا أولاً على محاكٍ، وبالتالي سنستورد المُقدِّر (BackendEstimator) من qiskit.primitives. في كل خطوة هندسية، نبني الهاميلتوني ونسمح بعدد معيّن من خطوات التحسين (هنا 500) باستخدام المُحسِّن "cobyla". في كل خطوة هندسية، نُخزّن كلاً من الطاقة الكلية والطاقة الإلكترونية. نظراً للعدد الكبير من خطوات المُحسِّن، قد يستغرق هذا ساعة أو أكثر. قد ترغب في تعديل المدخلات أدناه لتقليل الوقت المطلوب.

from qiskit.primitives import BackendEstimatorV2

estimator = BackendEstimatorV2(backend=backend_sim)

distances_sim = np.arange(0.3, 1.3, 0.1)
vqe_energies_sim = []
vqe_elec_energies_sim = []

for dist in distances_sim:
xx = dist

# Random initial state and efficient_su2 ansatz
H = build_hamiltonian(xx)
ansatz = efficient_su2(H.num_qubits)
ansatz_isa = pm.run(ansatz)
x0 = 2 * np.pi * np.random.random(ansatz_isa.num_parameters)
H_isa = H.apply_layout(ansatz_isa.layout)
nuclear_repulsion = ham_terms(xx)[0]

res = minimize(
cost_func,
x0,
args=(ansatz_isa, H_isa, estimator),
method="cobyla",
options={"maxiter": 20, "disp": True},
)

# Note this returns the total energy, and we are often interested in the electronic energy
tot_energy = getattr(res, "fun")
electron_energy = getattr(res, "fun") - nuclear_repulsion
print(electron_energy)
vqe_energies_sim.append(tot_energy)
vqe_elec_energies_sim.append(electron_energy)

# Print all results
print(res)

print("All energies have been calculated")
accuracy of Cholesky decomposition  1.1102230246251565e-15
/home/porter284/.pyenv/versions/3.11.12/lib/python3.11/site-packages/scipy/_lib/pyprima/common/preproc.py:68: UserWarning: COBYLA: Invalid MAXFUN; it should be at least num_vars + 2; it is set to 34
warn(f'{solver}: Invalid MAXFUN; it should be at least {min_maxfun_str}; it is set to {maxfun}')
Return from COBYLA because the objective function has been evaluated MAXFUN times.
Number of function values = 34 Least value of F = 1.316011435623847
The corresponding X is:
[2.32948769 5.39918229 3.03787975 4.11789904 4.97130735 2.68662232
1.76573151 2.48982571 5.40431972 3.65780829 1.33792786 5.48472494
6.18738702 1.78741883 0.78195251 2.96658955 1.35827677 5.599321
4.54850148 1.0939048 4.26158726 0.52100721 0.82318 4.76796961
3.75795507 3.8526447 5.51100375 5.91023075 2.61494836 1.79908918
2.65937756 5.53964148]

-0.44791260077615314
message: Return from COBYLA because the objective function has been evaluated MAXFUN times.
success: False
status: 3
fun: 1.316011435623847
x: [ 2.329e+00 5.399e+00 ... 2.659e+00 5.540e+00]
nfev: 34
maxcv: 0.0
accuracy of Cholesky decomposition 5.551115123125783e-16
Return from COBYLA because the objective function has been evaluated MAXFUN times.
Number of function values = 34 Least value of F = 0.7235003672327549
The corresponding X is:
[2.56282915 5.63369524 5.58059887 4.049643 4.2021266 3.06866011
6.01619635 1.52520776 4.35403161 0.33673958 0.32623161 1.2179545
2.84001371 3.98956684 4.89632562 1.38303588 1.96194695 2.13182089
0.29739166 1.77895165 3.29151585 3.54355374 4.49626674 0.95756626
0.87103927 4.53068385 1.31051302 0.37103108 1.02961355 3.13342311
5.65815319 2.24770604]

-0.5994426600672451
message: Return from COBYLA because the objective function has been evaluated MAXFUN times.
success: False
status: 3
fun: 0.7235003672327549
x: [ 2.563e+00 5.634e+00 ... 5.658e+00 2.248e+00]
nfev: 34
maxcv: 0.0
accuracy of Cholesky decomposition 5.551115123125783e-16
Return from COBYLA because the objective function has been evaluated MAXFUN times.
Number of function values = 34 Least value of F = 0.34960914928810116
The corresponding X is:
[5.44143165 6.75955835 1.56836472 3.09522093 4.67873235 1.67071481
0.3056494 0.65998337 1.02197668 5.21162959 0.43690354 3.56522934
4.56033119 1.90736037 0.40863891 2.87007312 3.2516952 5.90360196
1.99057799 5.20726456 0.74710237 6.03179202 3.80685028 0.03844391
5.88580196 3.62233258 3.98723567 2.50591888 5.44020267 2.2792993
5.57102303 4.46548617]

-0.7087452725518989
message: Return from COBYLA because the objective function has been evaluated MAXFUN times.
success: False
status: 3
fun: 0.34960914928810116
x: [ 5.441e+00 6.760e+00 ... 5.571e+00 4.465e+00]
nfev: 34
maxcv: 0.0
accuracy of Cholesky decomposition 2.220446049250313e-16
Return from COBYLA because the objective function has been evaluated MAXFUN times.
Number of function values = 34 Least value of F = 0.10594558882184543
The corresponding X is:
[5.35675483 2.26629567 1.45430546 5.56758296 5.76309509 0.73239338
5.1216998 3.03258872 4.33624828 1.93197674 0.5292902 3.32274987
3.43247633 0.81490741 0.48060245 1.9944799 5.67519646 5.12534057
0.06510627 2.52989834 6.1699519 0.94828957 5.91634548 1.5994961
4.27902164 2.3129213 1.82353095 2.10634209 1.43740426 4.06988733
0.59624074 4.93925418]

-0.7760164293781545
message: Return from COBYLA because the objective function has been evaluated MAXFUN times.
success: False
status: 3
fun: 0.10594558882184543
x: [ 5.357e+00 2.266e+00 ... 5.962e-01 4.939e+00]
nfev: 34
maxcv: 0.0
accuracy of Cholesky decomposition 1.1102230246251565e-16
Return from COBYLA because the objective function has been evaluated MAXFUN times.
Number of function values = 34 Least value of F = -0.06473600797229297
The corresponding X is:
[6.07735568 0.18019501 0.20743128 4.15445985 3.59388894 5.10047555
6.09938474 6.54707528 3.36251167 2.05475223 3.67078456 5.96010605
2.58589996 5.2723619 3.26352977 2.47432334 3.50289983 2.06620525
6.0946056 1.22751903 0.97320057 2.19564095 5.73174941 2.05127682
5.73805165 3.84046105 1.84816963 2.1247504 3.11106736 2.44136052
3.39002685 0.81596991]

-0.8207034521437214
message: Return from COBYLA because the objective function has been evaluated MAXFUN times.
success: False
status: 3
fun: -0.06473600797229297
x: [ 6.077e+00 1.802e-01 ... 3.390e+00 8.160e-01]
nfev: 34
maxcv: 0.0
accuracy of Cholesky decomposition 5.551115123125783e-17
Return from COBYLA because the objective function has been evaluated MAXFUN times.
Number of function values = 34 Least value of F = -0.19562982094782935
The corresponding X is:
[-0.02184462 3.67041038 7.25918653 5.89799546 0.63583624 1.84214506
2.84059837 5.31485182 1.6053784 0.04556618 0.32018993 -0.03884066
0.69131496 0.24203727 1.97397262 3.59723495 0.43355775 2.30131056
4.63482292 3.9857415 4.32320753 4.55388437 2.18753433 5.99034987
2.50489913 0.90650534 4.82518088 2.32954849 2.29901832 5.33658863
5.91246716 3.2405013 ]

-0.8571013345978292
message: Return from COBYLA because the objective function has been evaluated MAXFUN times.
success: False
status: 3
fun: -0.19562982094782935
x: [-2.184e-02 3.670e+00 ... 5.912e+00 3.241e+00]
nfev: 34
maxcv: 0.0
accuracy of Cholesky decomposition 1.1102230246251565e-16
Return from COBYLA because the objective function has been evaluated MAXFUN times.
Number of function values = 34 Least value of F = -0.2833766309947055
The corresponding X is:
[ 3.1700088 5.05055456 1.2545611 4.28751811 0.6255103 1.67526577
5.48201473 4.83820497 7.34880059 5.99705431 4.2502643 0.32066274
0.41001404 0.27271241 4.15682546 4.22393693 4.35148115 0.64538137
5.26288622 5.03810489 4.62426621 4.74997689 1.09603919 0.34752466
1.8116275 0.7474807 5.31754143 4.11181763 1.58797998 5.6299796
3.0109383 -0.19062772]

-0.8713513097947054
message: Return from COBYLA because the objective function has been evaluated MAXFUN times.
success: False
status: 3
fun: -0.2833766309947055
x: [ 3.170e+00 5.051e+00 ... 3.011e+00 -1.906e-01]
nfev: 34
maxcv: 0.0
accuracy of Cholesky decomposition 1.1102230246251565e-16
Return from COBYLA because the objective function has been evaluated MAXFUN times.
Number of function values = 34 Least value of F = -0.3527503628484244
The corresponding X is:
[3.90513622 4.61398739 5.92552705 1.99953405 4.82157369 1.35702441
2.77701782 5.73612247 4.22710527 1.83463189 0.45796297 4.62509318
0.98998668 0.11666217 3.0234641 4.54298546 0.14034033 4.15635797
1.41257357 4.48719602 2.39365535 0.19672041 5.0763044 1.86357581
3.657757 4.60298344 2.49769577 1.88086199 3.00108725 1.84475841
5.24047385 4.91142914]

-0.8819275737684243
message: Return from COBYLA because the objective function has been evaluated MAXFUN times.
success: False
status: 3
fun: -0.3527503628484244
x: [ 3.905e+00 4.614e+00 ... 5.240e+00 4.911e+00]
nfev: 34
maxcv: 0.0
accuracy of Cholesky decomposition 2.7755575615628914e-17
Return from COBYLA because the objective function has been evaluated MAXFUN times.
Number of function values = 34 Least value of F = -0.4022181851996095
The corresponding X is:
[6.09453981 3.5109422 3.37216019 4.94732621 1.25662002 5.89645164
5.06403334 2.68073141 4.40385083 1.13638366 1.73347762 6.82932871
1.15265014 2.07145964 4.36520459 1.14960341 1.62288871 4.32315915
5.45622821 0.93554005 3.17418483 0.47230243 1.31535502 5.77698726
2.04927925 2.50663538 5.9706002 5.4984681 2.9421232 1.56636313
1.09394523 4.62582 ]

-0.8832883769450639
message: Return from COBYLA because the objective function has been evaluated MAXFUN times.
success: False
status: 3
fun: -0.4022181851996095
x: [ 6.095e+00 3.511e+00 ... 1.094e+00 4.626e+00]
nfev: 34
maxcv: 0.0
accuracy of Cholesky decomposition 1.1102230246251565e-16
Return from COBYLA because the objective function has been evaluated MAXFUN times.
Number of function values = 34 Least value of F = -0.44423031870708934
The corresponding X is:
[4.05765050e+00 3.99144950e+00 3.13287593e+00 3.28855137e+00
4.32613515e+00 4.91104512e+00 1.86521867e+00 2.18822879e+00
6.01336171e+00 1.82501276e+00 2.64830637e+00 5.53045823e+00
2.36110093e+00 3.98821703e+00 4.69013438e-01 4.38996815e+00
7.78103801e-04 1.72994378e+00 2.24970934e+00 1.11978200e+00
2.24846445e+00 4.90745512e+00 5.38474921e+00 5.03587994e+00
3.54297277e+00 4.78147533e+00 1.25990218e+00 1.99168068e+00
5.89203503e+00 1.77673987e+00 5.37848357e+00 5.60245198e-01]

-0.8852113278070892
message: Return from COBYLA because the objective function has been evaluated MAXFUN times.
success: False
status: 3
fun: -0.44423031870708934
x: [ 4.058e+00 3.991e+00 ... 5.378e+00 5.602e-01]
nfev: 34
maxcv: 0.0
All energies have been calculated
xx
np.float64(1.2000000000000004)

تُناقَش نتائج هذا المخرج أدناه في قسم المعالجة اللاحقة؛ في الوقت الحالي، لاحظ فقط أن المحاكاة كانت ناجحة. أنت الآن مستعدّ للتشغيل على عتاد حقيقي. سنضبط المرونة (resilience) على 1، مما يعني أن تخفيف الأخطاء TREX سيُستخدم. بما أننا نعمل الآن مع عتاد حقيقي، سنستخدم Qiskit Runtime وأدوات Runtime البدائية. لاحظ أن كلاً من حلقة التكرار المتعلقة بالهندسة والتجارب التباينية المتعددة موجودة داخل الجلسة (session).

نظراً لوجود تكاليف وحدود زمنية مرتبطة بتشغيل العتاد الحقيقي، قلّلنا عدد خطوات الهندسة وخطوات المُحسِّن أدناه. تأكّد من تعديل هذه الخطوات وفقاً لأهداف الدقة والحدود الزمنية الخاصة بك.

# To continue running on real hardware use
from qiskit_ibm_runtime import Session
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit_ibm_runtime import EstimatorOptions

estimator_options = EstimatorOptions(resilience_level=1, default_shots=2000)

distances = np.arange(0.5, 0.9, 0.1)
vqe_energies = []
vqe_elec_energies = []

with Session(backend=backend) as session:
estimator = Estimator(mode=session, options=estimator_options)

for dist in distances:
xx = dist

# Random initial state and efficient_su2 ansatz

H = build_hamiltonian(xx)
ansatz = efficient_su2(H.num_qubits)
ansatz_isa = pm.run(ansatz)
H_isa = H.apply_layout(ansatz_isa.layout)
nuclear_repulsion = ham_terms(xx)[0]
x0 = 2 * np.pi * np.random.random(ansatz_isa.num_parameters)

res = minimize(
cost_func,
x0,
args=(ansatz_isa, H_isa, estimator),
method="cobyla",
options={"maxiter": 50, "disp": True},
)

# Note this returns the total energy, and we are often interested in the electronic energy
tot_energy = getattr(res, "fun")
electron_energy = getattr(res, "fun") - nuclear_repulsion
print(electron_energy)
vqe_energies.append(tot_energy)
vqe_elec_energies.append(electron_energy)

# Print all results
print(res)

print("All energies have been calculated")

الخطوة 4: المعالجة اللاحقة

بالنسبة لكل من المحاكي والعتاد الحقيقي، يمكننا رسم طاقات الحالة الأساسية المحسوبة لكل مسافة بين الذرات ومعرفة أين تتحقق أدنى طاقة. يجب أن تكون هذه هي المسافة بين الذرات الموجودة في الطبيعة، وهي فعلاً قريبة منها. يمكن الحصول على منحنى أكثر سلاسة بتجربة دوائر تقريبية (ansaetze) ومُحسِّنات أخرى، وتشغيل الحسابات عدة مرات عند كل خطوة هندسية وحساب المتوسط على عدة شروط ابتدائية عشوائية.

# Here we can plot the results from this simulation.
plt.plot(distances_sim, vqe_energies_sim, label="VQE Energy")
plt.xlabel("Atomic distance (Angstrom)")
plt.ylabel("Energy")
plt.legend()
plt.show()

Output of the previous code cell

لاحظ أن مجرد زيادة عدد خطوات التحسين ليس من المرجح أن يُحسّن النتائج من المحاكي، لأن جميع عمليات التحسين تقاربت فعلياً إلى التفاوت المطلوب في عدد تكرارات أقل من الحدّ الأقصى.

النتائج من العتاد الحقيقي قابلة للمقارنة، باستثناء نطاق مختلف قليلاً من القيم المُعاينة.

plt.plot(distances, vqe_energies, label="VQE Energy")
plt.xlabel("Atomic distance (Angstrom)")
plt.ylabel("Energy")
plt.legend()
plt.show()

Output of the previous code cell

بالإضافة إلى توقّع طول رابطة H2 البالغ 0.74 أنجستروم، يجب أن تكون الطاقة الكلية ‎-1.17 هارتري. نلاحظ أن نتائج العتاد الحقيقي اقتربت أكثر من هذه القيم مقارنة بالمحاكي. من المرجح أن يكون ذلك لأن الضوضاء كانت موجودة (أو مُحاكاة) في كلتا الحالتين، لكن تخفيف الأخطاء لم يُستخدم إلا في حالة العتاد الحقيقي.

الخاتمة

بهذا نختتم دورتنا حول VQE للكيمياء الكمية. إذا كنت مهتماً بفهم بعض نظرية المعلومات الأساسية المستخدمة في الحوسبة الكمية، اطّلع على دورة John Watrous حول أساسيات المعلومات الكمية. للحصول على مثال موجز إضافي لسير عمل VQE، راجع تعليم تقدير طاقة الحالة الأساسية لسلسلة Heisenberg باستخدام VQE. أو تصفّح الدروس التعليمية والدورات للعثور على مزيد من المواد التعليمية حول أحدث تقنيات الحوسبة الكمية.

لا تنسَ أن تخوض امتحان هذه الدورة. الحصول على درجة 80% أو أعلى سيمنحك شارة Credly، والتي ستُرسل إليك تلقائياً عبر البريد الإلكتروني. شكراً لكونك جزءاً من شبكة IBM Quantum®!

import qiskit
import qiskit_ibm_runtime

print(qiskit.version.get_version_info())
print(qiskit_ibm_runtime.version.get_version_info())
1.3.2
0.35.0