הרץ את המעגל הראשון שלך על חומרה
Package versions
הקוד בעמוד הזה פותח באמצעות הדרישות הבאות. אנחנו ממליצים להשתמש בגרסאות האלה או חדשות יותר.
qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0
דוגמה זו מכילה שני חלקים. תחילה תיצור תוכנית קוונטית "Hello world" פשוטה ותריץ אותה על יחידת עיבוד קוונטי (QPU). מכיוון שמחקר קוונטי אמיתי דורש תוכניות חזקות ועמידות הרבה יותר, בחלק השני (הרחבה למספרים גדולים של קיוביטים), תרחיב את התוכנית הפשוטה לרמת תועלת (utility level).
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"matplotlib": "matplotlib", "qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
התקנה ואימות
-
אם עדיין לא התקנת את Qiskit, מצא הוראות במדריך Quickstart.
-
התקן את לקוח IBM Quantum Compute כדי להריץ משימות על חומרה קוונטית:
pip install qiskit-ibm-runtime -
הגדר סביבה להרצת מחברות Jupyter באופן מקומי:
pip install jupyter
-
-
הגדר את האימות שלך לגישה לחומרה קוונטית דרך ה-Open Plan החינמי.
(אם קיבלת הזמנה בדואר אלקטרוני להצטרף לחשבון, בצע את השלבים למשתמשים מוזמנים במקום.)
-
היכנס ל-IBM Quantum Platform כדי להתחבר או ליצור חשבון.
חשובאם אתה מתחבר דרך שרת פרוקסי, עליך להשתמש ב-
qiskit-ibm-runtimeגרסה 0.44.0 ומעלה. -
צור את מפתח ה-API שלך (הידוע גם כ-API token) בלוח הבקרה, ואז העתק אותו למיקום מאובטח.
-
עבור לדף Instances ומצא את ה-instance שברצונך להשתמש בו. רחף מעל ה-CRN שלו ולחץ להעתקה.
-
שמור את פרטי הגישה שלך באופן מקומי עם הקוד הזה:
from qiskit_ibm_runtime import QiskitRuntimeServiceQiskitRuntimeService.save_account(# For `token`, use the 44-character API_KEY you created# and saved from the IBM Quantum Platform Home dashboardtoken="<your-api-key>",instance="<CRN>", # Optional)
-
-
עכשיו תוכל להשתמש בקוד Python הזה בכל פעם שתרצה לאמת מול IBM Quantum Compute Service:
from qiskit_ibm_runtime import QiskitRuntimeService# Run every time you need the serviceservice = QiskitRuntimeService()
אם אתה משתמש במחשב ציבורי או בסביבה לא מאובטחת אחרת, בצע את הוראות האימות הידני במקום כדי לשמור על אבטחת פרטי הגישה שלך.
יצירה והרצה של תוכנית קוונטית פשוטה
ארבעת השלבים לכתיבת תוכנית קוונטית באמצעות תבניות Qiskit הם:
-
מיפוי הבעיה לייצוג קוונטי טבעי (native).
-
אופטימיזציה של המעגלים והאופרטורים.
-
הרצה באמצעות פונקציית primitive קוונטית.
-
ניתוח התוצאות.
שלב 1. מיפוי הבעיה לפורמט קוונטי-מקורי
בתוכנית קוונטית, מעגלים קוונטיים הם הפורמט המקורי לייצוג הוראות קוונטיות, ואופרטורים מייצגים את ה-observables שיש למדוד. בעת יצירת מעגל, בדרך כלל תיצור אובייקט QuantumCircuit חדש, ואז תוסיף הוראות ברצף.
תא הקוד הבא יוצר מעגל שמייצר מצב Bell, שהוא מצב שבו שני Qubit שזורים לחלוטין זה בזה.
ה-Qiskit SDK משתמש במספור ביטים LSb 0, שבו לספרה ה- יש ערך או . לפרטים נוספים, ראו את הנושא סדר ביטים ב-Qiskit SDK.
# This cell is hidden from users. It hides several unnecessary warnings.
import warnings
import logging
warnings.filterwarnings("ignore", message=".*Instance was not set*")
warnings.filterwarnings("ignore", message=".*loading instance*")
warnings.filterwarnings("ignore", message=".*using instance*")
# This cell is hidden from users. It hides several unnecessary warnings.
class IgnoreSpecificMessages(logging.Filter):
def filter(self, record):
for text in [
"Instance was not set",
"Loading default saved account",
"Loading instance",
"Instance was not set",
"using instance",
]:
if text in record.getMessage():
return False
return True
logger = logging.getLogger("qiskit_ibm_runtime")
logger.addFilter(IgnoreSpecificMessages())
for handler in logger.handlers:
handler.addFilter(IgnoreSpecificMessages())
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService
from matplotlib import pyplot as plt
# Legacy server-side primitive before qiskit-ibm-runtime 0.50.0
# from qiskit_ibm_runtime import EstimatorOptions
# from qiskit_ibm_runtime import Estimator
# Client-side primitive introduced in qiskit-ibm-runtime 0.50.0
from qiskit_ibm_runtime.options_models import EstimatorOptions
from qiskit_ibm_runtime.executor_estimator import Estimator
# Uncomment the next line if you want to use a simulator:
# from qiskit_ibm_runtime.fake_provider import FakeBelemV2
# Create a new circuit with two qubits
qc = QuantumCircuit(2)
# Add a Hadamard gate to qubit 0
qc.h(0)
# Perform a controlled-X gate on qubit 1, controlled by qubit 0
qc.cx(0, 1)
# Return a drawing of the circuit using MatPlotLib ("mpl").
# These guides are written by using Jupyter notebooks, which
# display the output of the last line of each cell.
# If you're running this in a script, use `print(qc.draw())` to
# print a text drawing.
qc.draw("mpl")
ראה QuantumCircuit בתיעוד לכל הפעולות הזמינות.
בעת יצירת מעגלים קוונטיים, עליך גם לשקול איזה סוג נתונים ברצונך לקבל לאחר הביצוע. Qiskit מספקת שתי דרכים להחזרת נתונים: ניתן לקבל פלט דגימה עבור קבוצת Qubit שתבחר למדוד, או לקבל את ערך הציפייה של observable. הכן את העומס שלך למדידת המעגל באחת משתי הדרכים הללו עם primitives (מוסבר בפירוט בשלב 3).
דוגמה זו מודדת ערכי ציפייה באמצעות מודול המשנה qiskit.quantum_info, המצוין באמצעות אופרטורים (אובייקטים מתמטיים המשמשים לייצוג פעולה או תהליך שמשנים מצב קוונטי). תא הקוד הבא יוצר שישה אופרטורי Pauli דו-קיוביטיים: IZ, IX, ZI, XI, ZZ, ו-XX.
# Set up six different observables.
observables_labels = ["IZ", "IX", "ZI", "XI", "ZZ", "XX"]
observables = [SparsePauliOp(label) for label in observables_labels]
כאן, משהו כמו האופרטור ZZ הוא קיצור לכפל טנזורי , שמשמעותו מדידת Z על Qubit 1 ו-Z על Qubit 0 יחד, וקבלת מידע על הקורלציה בין Qubit 1 ל-Qubit 0. ערכי ציפייה כאלה נכתבים בדרך כלל גם כ-.
אם המצב שזור, אז מדידת צריכה להיות שונה ממדידת . עבור המצב השזור הספציפי שנוצר על ידי המעגל שלנו המתואר לעיל, מדידת צריכה להיות 1 ומדידת צריכה להיות אפס.
שלב 2. אופטימיזציה של המעגלים והאופרטורים
בעת ביצוע מעגלים על מכשיר, חשוב לייעל את קבוצת ההוראות שהמעגל מכיל ולמזער את העומק הכולל (בקירוב מספר ההוראות) של המעגל. הדבר מבטיח שתקבל את התוצאות הטובות ביותר האפשריות על ידי הפחתת השפעות שגיאות ורעש. בנוסף, הוראות המעגל חייבות להתאים ל-Instruction Set Architecture (ISA) של Backend המכשיר ולקחת בחשבון את שערי הבסיס וקישוריות ה-Qubit של המכשיר.
הקוד הבא מאתחל מכשיר אמיתי להגשת משימה אליו ומשנה את המעגל וה-observables כך שיתאימו ל-ISA של ה-Backend. הוא דורש שכבר שמרת את פרטי הגישה שלך
service = QiskitRuntimeService()
backend = service.least_busy(simulator=False, operational=True)
# Convert to an ISA circuit and layout-mapped observables.
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
isa_circuit.draw("mpl", idle_wires=False)
שלב 3. הרצה באמצעות ה-primitives הקוונטיים
מחשבים קוונטיים יכולים לייצר תוצאות אקראיות, לכן בדרך כלל אוספים דגימה של הפלטים על ידי הרצת המעגל פעמים רבות. ניתן להעריך את ערך ה-observable באמצעות מחלקת Estimator. Estimator הוא אחד משני primitives; השני הוא Sampler, שניתן להשתמש בו לקבלת נתונים ממחשב קוונטי. לאובייקטים אלה יש מתודת run() שמריצה את המעגלים, ה-observables והפרמטרים שנבחרו (אם רלוונטי), באמצעות primitive unified bloc (PUB).
# Construct the Estimator instance.
estimator = Estimator(mode=backend)
estimator.options.resilience_level = 1
estimator.options.default_shots = 5000
mapped_observables = [
observable.apply_layout(isa_circuit.layout) for observable in observables
]
# One pub, with one circuit to run against five different observables.
job = estimator.run([(isa_circuit, mapped_observables)])
# Use the job ID to retrieve your job data later
print(f">>> Job ID: {job.job_id()}")
>>> Job ID: dab7lm9l216s739p6q10
לאחר הגשת משימה, תוכל להמתין עד שהמשימה תושלם בתוך מופע ה-Python הנוכחי שלך, או להשתמש ב-job_id כדי לאחזר את הנתונים בשלב מאוחר יותר. (ראה את הסעיף על אחזור משימות לפרטים.)
לאחר השלמת המשימה, בחן את הפלט שלה דרך המאפיין result() של המשימה.
# This is the result of the entire submission. You submitted one Pub,
# so this contains one inner result (and some metadata of its own).
job_result = job.result()
# This is the result from our single pub, which had six observables,
# so contains information on all six.
pub_result = job.result()[0]
# Check there are six observables.
# If not, edit the comments in the previous cell and update this test.
assert len(pub_result.data.evs) == 6
כאשר אתה מריץ את התוכנית הקוונטית שלך על מכשיר אמיתי, העומס שלך חייב להמתין בתור לפני שירוץ. כדי לחסוך זמן, תוכל להשתמש בקוד הבא כדי להריץ עומס קטן זה על fake_provider עם מצב הבדיקה המקומי של qiskit-ibm-runtime. שים לב שזה אפשרי רק עבור מעגל קטן. כאשר תרחיב בסעיף הבא, יהיה עליך להשתמש במכשיר אמיתי.
# Use the following code instead if you want to run on a simulator:
from qiskit_ibm_runtime.fake_provider import FakeBelemV2
backend = FakeBelemV2()
estimator = Estimator(backend)
# Convert to an ISA circuit and layout-mapped observables.
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
mapped_observables = [
observable.apply_layout(isa_circuit.layout) for observable in observables
]
job = estimator.run([(isa_circuit, mapped_observables)])
result = job.result()
# This is the result of the entire submission. You submitted one Pub,
# so this contains one inner result (and some metadata of its own).
job_result = job.result()
# This is the result from our single pub, which had five observables,
# so contains information on all five.
pub_result = job.result()[0]
שלב 4. ניתוח התוצאות
שלב הניתוח הוא בדרך כלל המקום שבו מבצעים עיבוד לאחר ההרצה לתוצאות, למשל באמצעות הפחתת שגיאות מדידה או אקסטרפולציה לרעש אפס (ZNE). ייתכן שתזין תוצאות אלה לתוך תהליך עבודה אחר לניתוח נוסף או תכין גרף של הערכים והנתונים המרכזיים. באופן כללי, שלב זה ספציפי לבעיה שלך. לדוגמה זו, צייר גרף של כל ערכי הציפייה שנמדדו עבור המעגל שלנו.
ערכי הציפייה והסטיות התקניות עבור ה-observables שציינת ל-Estimator נגישים דרך המאפיינים PubResult.data.evs ו-PubResult.data.stds של תוצאת המשימה. כדי לקבל את התוצאות מ-Sampler, השתמש בפונקציה PubResult.data.meas.get_counts(), שתחזיר dict של מדידות בצורת מחרוזות ביטים כמפתחות וספירות כערכים המתאימים. למידע נוסף, ראה מדריך Sampler quickstart.
# Plot the result
values = pub_result.data.evs
errors = pub_result.data.stds
# plotting graph
plt.plot(observables_labels, values, "-o")
plt.xlabel("Observables")
plt.ylabel("Values")
plt.show()
שים לב שעבור Qubit 0 ו-1, ערכי הציפייה העצמאיים של X ו-Z הם 0, בעוד שהקורלציות (XX ו-ZZ) הן 1. זהו סימן היכר של שזירה קוונטית.
# Make sure the results follow the claim from the previous markdown cell.
# This can happen when the device occasionally behaves strangely. If this cell
# fails, you may just need to run the notebook again.
_results = {obs: val for obs, val in zip(observables_labels, values)}
for _label in ["IZ", "IX", "ZI", "XI"]:
assert abs(_results[_label]) < 0.2
for _label in ["XX", "ZZ"]:
assert _results[_label] > 0.8
הרחבה למספרים גדולים של קיוביטים
בחישוב קוונטי, עבודה בקנה מידה של תועלת (utility-scale) היא קריטית לקידום בתחום. עבודה כזו דורשת ביצוע חישובים בקנה מידה גדול הרבה יותר; עבודה עם מעגלים שעשויים להשתמש ביותר מ-100 Qubit וביותר מ-1000 שערים. דוגמה זו מדגימה כיצד תוכל לבצע עבודה בקנה מידה של תועלת (utility-scale) על QPU של IBM® על ידי יצירה וניתוח של מצב GHZ של 100 Qubit. היא משתמשת בתהליך העבודה של תבניות Qiskit ומסתיימת במדידת ערך הציפייה עבור כל Qubit.
שלב 1. מיפוי הבעיה
כתוב פונקציה שמחזירה QuantumCircuit המכין מצב GHZ של Qubit (בעצם מצב Bell מורחב), ואז השתמש בפונקציה זו להכנת מצב GHZ של 100 Qubit ואסוף את ה-observables שיש למדוד.
def get_qc_for_n_qubit_GHZ_state(n: int) -> QuantumCircuit:
"""This function will create a qiskit.QuantumCircuit (qc)
for an n-qubit GHZ state.
Args:
n (int): Number of qubits in the n-qubit GHZ state
Returns:
QuantumCircuit: Quantum circuit that generate the n-qubit GHZ state,
assuming all qubits start in the 0 state
"""
if isinstance(n, int) and n >= 2:
qc = QuantumCircuit(n)
qc.h(0)
for i in range(n - 1):
qc.cx(i, i + 1)
else:
raise Exception("n is not a valid input")
return qc
# Create a new circuit with 100 qubits in the GHZ state
n = 100
qc = get_qc_for_n_qubit_GHZ_state(n)
לאחר מכן, מפו לאופרטורים המעניינים. דוגמה זו משתמשת באופרטורי ZZ בין Qubit כדי לבחון את ההתנהגות ככל שהם מתרחקים זה מזה. ערכי ציפייה שגויים יותר ויותר (פגומים) בין Qubit מרוחקים יחשפו את רמת הרעש הקיימת.
# ZZII...II, ZIZI...II, ... , ZIII...IZ
operator_strings = [
"Z" + "I" * i + "Z" + "I" * (n - 2 - i) for i in range(n - 1)
]
operators = [SparsePauliOp(operator) for operator in operator_strings]
שלב 2. אופטימיזציה של הבעיה לביצוע על חומרה קוונטית
הקוד הבא משנה את המעגל וה-observables כך שיתאימו ל-ISA של ה-Backend. הוא דורש שכבר שמרת את פרטי הגישה שלך
service = QiskitRuntimeService()
backend = service.least_busy(
simulator=False, operational=True, min_num_qubits=100
)
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(qc)
isa_operators_list = [op.apply_layout(isa_circuit.layout) for op in operators]
שלב 3. הרצה על חומרה
הגש את המשימה והפעל דיכוי שגיאות באמצעות טכניקה להפחתת שגיאות הנקראת dynamical decoupling. רמת החוסן קובעת עד כמה התוצאות יהיו עמידות בפני שגיאות. רמות גבוהות יותר מייצרות תוצאות מדויקות יותר, על חשבון זמני עיבוד ארוכים יותר. להסבר נוסף על האפשרויות שנקבעו בקוד הבא, ראה טכניקות להפחתת שגיאות ולדיכוי שגיאות.
options = EstimatorOptions()
options.resilience_level = 1
options.dynamical_decoupling.enable = True
options.dynamical_decoupling.sequence_type = "XY4"
# Create an Estimator object
estimator = Estimator(backend, options=options)
# Submit the circuit to Estimator
job = estimator.run([(isa_circuit, isa_operators_list)])
job_id = job.job_id()
print(job_id)
dab84omrrl7c7386h52g
שלב 4. עיבוד תוצאות לאחר הרצה
לאחר השלמת המשימה, צייר גרף של התוצאות ושים לב ש- יורד עם גדילת , למרות שבסימולציה אידיאלית כל צריך להיות 1.
# data
data = list(range(1, len(operators) + 1)) # Distance between the Z operators
result = job.result()[0]
values = result.data.evs # Expectation value at each Z operator.
values = [
v / values[0] for v in values
] # Normalize the expectation values to evaluate how they decay with distance.
# plotting graph
plt.plot(data, values, marker="o", label="100-qubit GHZ state")
plt.xlabel("Distance between qubits $i$")
plt.ylabel(r"$\langle Z_i Z_0 \rangle / \langle Z_1 Z_0 \rangle $")
plt.legend()
plt.show()
הגרף הקודם מראה שככל שהמרחק בין ה-Qubit גדל, האות מתדעך בשל נוכחות הרעש.
הצעדים הבאים
- נסה אחד מהמדריכים הבאים:
- אומדן אנרגיית מצב הבסיס של שרשרת Heisenberg עם VQE
- פתור בעיות אופטימיזציה באמצעות QAOA
- אמן מודלים של גרעין קוונטי למשימות למידת מכונה
- מצא הוראות התקנה מפורטות במדריך התקנת Qiskit.
- אם אתה מעדיף לא להתקין את Qiskit באופן מקומי, קרא על אפשרויות לשימוש ב-Qiskit בסביבת פיתוח מקוונת.
- כדי לשמור מספר פרטי גישה לחשבון או לציין אפשרויות חשבון אחרות, ראה הוראות מפורטות במדריך שמירת פרטי הכניסה שלך.