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

تقدير طاقة الحالة الأساسية لسلسلة هايزنبرغ باستخدام VQE

تقدير الاستخدام: دقيقتان على معالج Eagle r3 (ملاحظة: هذا تقدير فحسب. قد يختلف وقت التشغيل الفعلي.)

الخلفية

يوضح هذا البرنامج التعليمي كيفية بناء نمط Qiskit ونشره وتشغيله لمحاكاة سلسلة هايزنبرغ وتقدير طاقة حالتها الأساسية. لمزيد من المعلومات حول أنماط Qiskit وكيفية استخدام Qiskit Serverless لنشرها على السحابة للتنفيذ المُدار، تفضل بزيارة صفحة الوثائق الخاصة بنا على منصة IBM Quantum®.

المتطلبات

قبل البدء في هذا البرنامج التعليمي، تأكد من تثبيت ما يلي:

  • Qiskit SDK الإصدار 1.2 أو أحدث، مع دعم التصور المرئي
  • Qiskit Runtime الإصدار 0.28 أو أحدث (pip install qiskit-ibm-runtime)
  • Qiskit Serverless (pip install qiskit_serverless)
  • IBM Catalog (pip install qiskit-ibm-catalog)

الإعداد

import numpy as np
import matplotlib.pyplot as plt

from scipy.optimize import minimize
from typing import Sequence

from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.primitives.base import BaseEstimatorV2
from qiskit.circuit.library import XGate
from qiskit.circuit.library import efficient_su2
from qiskit.transpiler import PassManager
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.transpiler.passes.scheduling import (
ALAPScheduleAnalysis,
PadDynamicalDecoupling,
)

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Session, Estimator

from qiskit_ibm_catalog import QiskitServerless, QiskitFunction
def visualize_results(results):
plt.plot(results["cost_history"], lw=2)
plt.xlabel("Iteration")
plt.ylabel("Energy")
plt.show()

def build_callback(
ansatz: QuantumCircuit,
hamiltonian: SparsePauliOp,
estimator: BaseEstimatorV2,
callback_dict: dict,
):
def callback(current_vector):
# Keep track of the number of iterations
callback_dict["iters"] += 1
# Set the prev_vector to the latest one
callback_dict["prev_vector"] = current_vector
# Compute the value of the cost function at the current vector
current_cost = (
estimator.run([(ansatz, hamiltonian, [current_vector])])
.result()[0]
.data.evs[0]
)
callback_dict["cost_history"].append(current_cost)
# Print to screen on single line
print(
"Iters. done: {} [Current cost: {}]".format(
callback_dict["iters"], current_cost
),
end="\r",
flush=True,
)

return callback

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

  • المدخل: عدد الأسبابات (spins)
  • المخرج: دالة الاختبار (Ansatz) وهاميلتونيان يُنمذجان سلسلة هايزنبرغ

نبني دالة الاختبار (Ansatz) والهاميلتونيان اللذين ينمذجان سلسلة هايزنبرغ المكونة من 10 أسبابات. أولاً، نستورد بعض الحزم العامة وننشئ بعض الدوال المساعدة.

num_spins = 10
ansatz = efficient_su2(num_qubits=num_spins, reps=3)

# Remember to insert your token in the QiskitRuntimeService constructor
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, min_num_qubits=num_spins, simulator=False
)

coupling = backend.target.build_coupling_map()
reduced_coupling = coupling.reduce(list(range(num_spins)))

edge_list = reduced_coupling.graph.edge_list()
ham_list = []

for edge in edge_list:
ham_list.append(("ZZ", edge, 0.5))
ham_list.append(("YY", edge, 0.5))
ham_list.append(("XX", edge, 0.5))

for qubit in reduced_coupling.physical_qubits:
ham_list.append(("Z", [qubit], np.random.random() * 2 - 1))

hamiltonian = SparsePauliOp.from_sparse_list(ham_list, num_qubits=num_spins)

ansatz.draw("mpl", style="iqp")

Output of the previous code cell

الخطوة 2: تحسين المسألة لتنفيذها على العتاد الكمومي

  • المدخل: دائرة مجردة، ومتغير مرصود (observable)
  • المخرج: الدائرة المستهدفة والمتغير المرصود، محسَّنَين للمعالج الكمومي (QPU) المختار

نستخدم دالة generate_preset_pass_manager من Qiskit لتوليد روتين تحسين آلي لدائرتنا بالنسبة إلى المعالج الكمومي المختار. نختار optimization_level=3 الذي يوفر أعلى مستوى من التحسين بين مديري التمريرات المُعدَّة مسبقاً. كما نُدرج تمريرات الجدولة ALAPScheduleAnalysis وPadDynamicalDecoupling لقمع أخطاء إزالة الترابط الكمومي.

target = backend.target
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
pm.scheduling = PassManager(
[
ALAPScheduleAnalysis(durations=target.durations()),
PadDynamicalDecoupling(
durations=target.durations(),
dd_sequence=[XGate(), XGate()],
pulse_alignment=target.pulse_alignment,
),
]
)
ansatz_ibm = pm.run(ansatz)
observable_ibm = hamiltonian.apply_layout(ansatz_ibm.layout)
ansatz_ibm.draw("mpl", scale=0.6, style="iqp", fold=-1, idle_wires=False)

Output of the previous code cell

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

  • المدخل: الدائرة المستهدفة والمتغير المرصود
  • المخرج: نتائج عملية التحسين

نُصغِّر طاقة الحالة الأساسية المُقدَّرة للنظام عبر تحسين معاملات الدائرة. نستخدم الأداة الأولية Estimator من Qiskit Runtime لتقييم دالة التكلفة خلال عملية التحسين.

في هذا العرض التوضيحي، سنُشغِّل النمط على معالج كمومي (QPU) باستخدام أدوات qiskit-ibm-runtime الأولية. للتشغيل باستخدام الأدوات الأولية المبنية على متجه الحالة في qiskit، استبدل كتلة الكود المستخدمة لـ Qiskit IBM Runtime بالكتلة المُعلَّقة.

# SciPy minimizer routine
def cost_func(
params: Sequence,
ansatz: QuantumCircuit,
hamiltonian: SparsePauliOp,
estimator: BaseEstimatorV2,
) -> float:
"""Ground state energy evaluation."""
return (
estimator.run([(ansatz, hamiltonian, [params])])
.result()[0]
.data.evs[0]
)

num_params = ansatz_ibm.num_parameters
params = 2 * np.pi * np.random.random(num_params)

callback_dict = {
"prev_vector": None,
"iters": 0,
"cost_history": [],
}

# Evaluate the problem on a QPU by using Qiskit IBM Runtime
with Session(backend=backend) as session:
estimator = Estimator()
callback = build_callback(
ansatz_ibm, observable_ibm, estimator, callback_dict
)
res = minimize(
cost_func,
x0=params,
args=(ansatz_ibm, observable_ibm, estimator),
callback=callback,
method="cobyla",
options={"maxiter": 100},
)

visualize_results(callback_dict)

الخطوة 4: المعالجة اللاحقة وإعادة النتيجة بالتنسيق الكلاسيكي المطلوب

  • المدخل: تقديرات طاقة الحالة الأساسية خلال عملية التحسين
  • المخرج: طاقة الحالة الأساسية المُقدَّرة
print(f'Estimated ground state energy: {res["fun"]}')

نشر نمط Qiskit على السحابة

لتحقيق ذلك، انقل الكود المصدري أعلاه إلى ملف باسم ./source/heisenberg.py، ولُفَّ الكود في سكريبت يستقبل المدخلات ويُعيد الحل النهائي، ثم ارفعه إلى عنقود بعيد باستخدام الفئة QiskitFunction من qiskit-ibm-catalog. للاطلاع على إرشادات تحديد التبعيات الخارجية وتمرير معاملات الإدخال وغير ذلك، راجع أدلة Qiskit Serverless.

مدخل النمط هو عدد الأسبابات في السلسلة. والمخرج هو تقدير لطاقة الحالة الأساسية للنظام.

# Authenticate to the remote cluster and submit the pattern for remote execution
serverless = QiskitServerless()
heisenberg_function = QiskitFunction(
title="ibm_heisenberg",
entrypoint="heisenberg.py",
working_dir="./source/",
)
serverless.upload(heisenberg_function)

تشغيل نمط Qiskit كخدمة مُدارة

بعد رفع النمط إلى السحابة، يمكننا تشغيله بسهولة باستخدام عميل QiskitServerless.

# Run the pattern on the remote cluster

ibm_heisenberg = serverless.load("ibm_heisenberg")
job = serverless.run(ibm_heisenberg)
solution = job.result()

print(solution)
print(job.logs())

استطلاع البرنامج التعليمي

يُرجى المشاركة في هذا الاستطلاع القصير لتقديم ملاحظاتك حول هذا البرنامج التعليمي. ستُساعدنا آراؤك على تحسين محتوانا وتجربة المستخدم.

رابط الاستطلاع