דלג לתוכן הראשי

אומדן אנרגיית מצב היסוד של שרשרת היזנברג עם VQE

אומדן שימוש: שתי דקות על מעבד Eagle r3 (הערה: זהו אומדן בלבד. זמן הריצה עשוי להשתנות.)

רקע

מדריך זה מראה כיצד לבנות, לפרוס ולהריץ תבנית Qiskit לסימולציה של שרשרת היזנברג ואומדן אנרגיית מצב היסוד שלה. למידע נוסף על תבניות Qiskit וכיצד ניתן להשתמש ב-Qiskit Serverless כדי לפרוס אותן לענן להרצה מנוהלת, בקרו בדף התיעוד שלנו על IBM Quantum® Platform.

דרישות

לפני תחילת מדריך זה, ודאו שיש לכם את הדברים הבאים מותקנים:

  • Qiskit SDK v1.2 או מאוחר יותר, עם תמיכה בהדמייה
  • Qiskit Runtime v0.28 או מאוחר יותר (pip install qiskit-ibm-runtime)
  • Qiskit Serverless (pip install qiskit_serverless)
  • IBM Catalog (pip install qiskit-ibm-catalog)

הגדרה

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-ibm-catalog qiskit-ibm-runtime scipy
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: מיפוי קלטים קלאסיים לבעיה קוונטית

  • קלט: מספר הספינים
  • פלט: 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")

פלט של תא הקוד הקודם

שלב 2: אופטימיזציה של הבעיה להרצה על חומרה קוונטית

  • קלט: מעגל מופשט, observable
  • פלט: מעגל יעד ו-observable, מותאמים עבור ה-QPU שנבחר

השתמשו בפונקציה generate_preset_pass_manager מ-Qiskit כדי ליצור אוטומטית שגרת אופטימיזציה עבור המעגל שלנו ביחס ל-QPU שנבחר. אנו בוחרים 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)

פלט של תא הקוד הקודם

שלב 3: הרצה באמצעות primitives של Qiskit

  • קלט: מעגל יעד ו-observable
  • פלט: תוצאות האופטימיזציה

מזעור אנרגיית מצב היסוד המוערכת של המערכת על ידי אופטימיזציה של פרמטרי המעגל. השתמשו ב-primitive Estimator מ-Qiskit Runtime כדי להעריך את פונקציית העלות במהלך האופטימיזציה.

להדגמה זו, נריץ על QPU באמצעות primitives של qiskit-ibm-runtime. כדי להריץ עם primitives מבוססי statevector של qiskit, החליפו את בלוק הקוד המשתמש ב-primitives של 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())

סקר מדריך

אנא השלימו סקר קצר זה כדי לספק משוב על מדריך זה. התובנות שלכם יעזרו לנו לשפר את הצעות התוכן ואת חוויית המשתמש שלנו.

קישור לסקר