Zum Hauptinhalt springen

Bestimmung einer Molekülgeometrie

Im vorherigen Abschnitt haben wir VQE implementiert, um die Grundzustandsenergie eines Moleküls zu bestimmen. Das ist eine gültige Anwendung des Quantencomputings, aber noch nützlicher wäre es, die Struktur eines Moleküls zu bestimmen.

Schritt 1: Klassische Eingaben auf ein Quantenproblem abbilden

Da wir weiterhin das einfache Beispiel des zweiatomigen Wasserstoffs verwenden, ist der einzige geometrische Parameter, den wir variieren müssen, die Bindungslänge. Dazu gehen wir wie zuvor vor, verwenden aber eine Variable in unserer anfänglichen Molekülkonstruktion (eine Bindungslänge x als Argument). Das ist eine recht einfache Änderung, erfordert aber, dass die Variable in Funktionen im gesamten Prozess berücksichtigt wird, da sie bei der Konstruktion des fermionischen Hamiltonoperators beginnt und sich durch das Mapping bis hin zur Kostenfunktion fortpflanzt.

Zuerst laden wir einige der Pakete, die wir zuvor verwendet haben, und definieren die Cholesky-Funktion.

# 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

Um unseren Hamiltonoperator zu definieren, verwenden wir PySCF genau wie im vorherigen Beispiel, beziehen jetzt aber eine Variable x als interatomaren Abstand ein. Diese Funktion gibt wie zuvor die Kernenergie sowie die Ein- und Zwei-Elektronen-Energien zurück.

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

Die obige Konstruktion erstellt einen fermionischen Hamiltonoperator auf Basis der Atomspezies, der Geometrie und der elektronischen Orbitale. Im Folgenden bilden wir diesen fermionischen Hamiltonoperator auf Pauli-Operatoren ab. Die Funktion build_hamiltonian enthält ebenfalls eine geometrische Variable als Argument.

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

Wir laden die restlichen Pakete für die Ausführung von VQE selbst, z. B. den efficient_su2-Ansatz und die SciPy-Minimierer:

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

Wir definieren erneut die Kostenfunktion. Da sie immer einen vollständig aufgebauten und gemappten Hamiltonoperator als Argument entgegennimmt, ändert sich an dieser Funktion nichts.

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

Schritt 2: Problem für die Quantenausführung optimieren

Da sich der Hamiltonoperator bei jeder neuen Geometrie ändert, ändert sich auch das Transpiling des Operators bei jedem Schritt. Wir können jedoch einen allgemeinen Pass-Manager definieren, der bei jedem Schritt angewendet wird und spezifisch für die Hardware ist, die wir verwenden möchten.

Hier verwenden wir das am wenigsten ausgelastete verfügbare Backend. Wir verwenden dieses Backend als Modell für unseren AerSimulator, sodass unser Simulator beispielsweise das Rauschverhalten des echten Backends nachahmen kann. Diese Rauschmodelle sind nicht perfekt, können aber helfen einzuschätzen, was von echter Hardware zu erwarten ist.

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

Wir importieren den Pass-Manager und verwandte Pakete, um unseren Circuit zu optimieren. Dieser Schritt sowie der vorherige sind vom Hamiltonoperator unabhängig und daher gegenüber der vorherigen Lektion unverändert.

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

Schritt 3: Mit Qiskit-Primitiven ausführen

Im folgenden Code-Block richten wir ein Array ein, um die Ausgaben jedes Schritts unseres interatomaren Abstands xx zu speichern. Wir haben den Bereich von xx auf Basis unseres Wissens über den experimentellen Gleichgewichts-Bindungsabstand gewählt: 0,74 Ångström. Wir führen dies zunächst auf einem Simulator aus und importieren daher unseren Estimator (BackendEstimator) aus qiskit.primitives. Bei jedem Geometrieschritt bauen wir den Hamiltonoperator auf und erlauben eine bestimmte Anzahl von Optimierungsschritten (hier 500) mit dem Optimierer "cobyla". Bei jedem Geometrieschritt speichern wir sowohl die Gesamtenergie als auch die elektronische Energie. Aufgrund der hohen Anzahl von Optimierungsschritten kann dies eine Stunde oder mehr dauern. Du kannst die Eingaben unten anpassen, um die benötigte Zeit zu reduzieren.

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)

Die Ergebnisse dieser Ausgabe werden weiter unten im Abschnitt zur Nachverarbeitung besprochen. Beachte vorerst einfach, dass die Simulation erfolgreich war. Jetzt bist du bereit, auf echter Hardware zu arbeiten. Wir setzen die Resilience auf 1, was bedeutet, dass TREX-Fehlermitigation verwendet wird. Da wir nun mit echter Hardware arbeiten, verwenden wir Qiskit Runtime und Runtime-Primitive. Beachte, dass sowohl die Schleife für die Geometrie als auch die mehrfachen Variationsversuche innerhalb der Session liegen.

Da mit echter Hardware Kosten und Zeitlimits verbunden sind, haben wir die Anzahl der Geometrieschritte und Optimierungsschritte unten reduziert. Passe diese Schritte unbedingt an deine Genauigkeitsziele und Zeitlimits an.

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

Schritt 4: Nachverarbeitung

Sowohl für den Simulator als auch für echte Hardware können wir die berechneten Grundzustandsenergien für jeden interatomaren Abstand auftragen und sehen, wo die niedrigste Energie erreicht wird. Das sollte dem in der Natur vorkommenden interatomaren Abstand entsprechen – und tatsächlich kommt er dem nahe. Eine glattere Kurve könnte durch andere Ansätze, Optimierer und durch mehrfaches Ausführen der Berechnung bei jedem Geometrieschritt mit anschließender Mittelung über mehrere zufällige Anfangsbedingungen erzielt werden.

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

Ausgabe der vorherigen Code-Zelle

Beachte, dass eine einfache Erhöhung der Anzahl der Optimierungsschritte die Ergebnisse des Simulators wahrscheinlich nicht verbessern wird, da alle Optimierungen tatsächlich in weniger als der maximalen Anzahl von Iterationen auf die erforderliche Toleranz konvergiert sind.

Die Ergebnisse der echten Hardware sind vergleichbar, abgesehen von einem etwas anderen Wertebereich.

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

Ausgabe der vorherigen Code-Zelle

Neben der erwarteten H2-Bindungslänge von 0,74 Ångström sollte die Gesamtenergie -1,17 Hartree betragen. Wir sehen, dass die Ergebnisse der echten Hardware diesen Werten näher kamen als die des Simulators. Das liegt wahrscheinlich daran, dass in beiden Fällen Rauschen vorhanden war (oder simuliert wurde), aber nur bei der echten Hardware Fehlermitigation eingesetzt wurde.

Abschluss

Damit endet unser Kurs über VQE für Quantenchemie. Wenn du daran interessiert bist, etwas über die zugrundeliegende Informationstheorie im Quantencomputing zu verstehen, schau dir John Watrous' Kurs über die Grundlagen der Quanteninformation an. Ein weiteres kurzes Beispiel eines VQE-Workflows findest du in unserem Tutorial zur Grundzustandsenergiebestimmung der Heisenberg-Kette mit VQE. Oder stöbere in den Tutorials und Kursen, um weitere Lernmaterialien über die neueste Technologie im Quantencomputing zu finden.

Vergiss nicht, die Prüfung dieses Kurses abzulegen. Ein Ergebnis von 80 % oder höher bringt dir ein Credly-Abzeichen ein, das dir automatisch per E-Mail zugeschickt wird. Vielen Dank, dass du Teil des IBM Quantum® Network bist!

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