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

כניסות ויציאות של פרימיטיבים

מודל הרצה חדש, כעת בגרסת בטא

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

Package versions

The code on this page was developed using the following requirements. We recommend using these versions or newer.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

דף זה מספק סקירה כללית של הכניסות והיציאות של פרימיטיבי Qiskit Runtime המריצים עומסי עבודה על משאבי מחשוב של IBM Quantum®. פרימיטיבים אלה מעניקים לך את היכולת להגדיר ביעילות עומסי עבודה מווקטרים באמצעות מבנה נתונים המכונה Primitive Unified Bloc (PUB). PUBs אלה הם יחידת העבודה הבסיסית שה-QPU צריך כדי להריץ עומסי עבודה אלה. הם משמשים כקלטים לשיטת run() עבור פרימיטיבי Sampler ו-Estimator, שמריצים את עומס העבודה המוגדר כמשימה. לאחר השלמת המשימה, התוצאות מוחזרות בפורמט שתלוי הן ב-PUBs שנעשה בהם שימוש והן באפשרויות זמן הריצה שצוינו על ידי פרימיטיבי Sampler או Estimator.

סקירה כללית של PUBs

בעת קריאה לשיטת run() של פרימיטיב, הארגומנט העיקרי הנדרש הוא list של tuple אחת או יותר — אחת לכל Circuit המורץ על ידי הפרימיטיב. כל אחת מ-tuples אלה נחשבת ל-PUB, והאלמנטים הנדרשים של כל tuple ברשימה תלויים בפרימיטיב המשמש. הנתונים המסופקים ל-tuples אלה יכולים גם להיות מסודרים במגוון צורות כדי לספק גמישות בעומס עבודה באמצעות broadcasting — כללים שמתוארים בסעיף הבא.

Estimator PUB

עבור פרימיטיב ה-Estimator, פורמט ה-PUB צריך להכיל לכל היותר ארבעה ערכים:

  • QuantumCircuit יחיד, שעשוי להכיל אובייקט Parameter אחד או יותר
  • רשימה של observable אחד או יותר, המציינים את ערכי הציפייה להערכה, מסודרים במערך (למשל, observable יחיד המיוצג כמערך ממימד 0, רשימת observables כמערך חד-ממדי, וכן הלאה). הנתונים יכולים להיות בכל אחד מפורמטי ObservablesArrayLike כגון Pauli, SparsePauliOp, PauliList, או str.
    הערה

    אם יש לך שני observables מתחלפים ב-PUBs שונים אך עם אותו Circuit, הם לא יוערכו באמצעות אותה מדידה. כל PUB מייצג בסיס שונה למדידה, ולכן נדרשות מדידות נפרדות לכל PUB. כדי להבטיח שה-observables המתחלפים יוערכו באמצעות אותה מדידה, יש לקבץ אותם באותו PUB.

  • אוסף של ערכי פרמטרים לקשירה מול ה-Circuit. ניתן לציין זאת כאובייקט דמוי-מערך יחיד שבו האינדקס האחרון הוא על אובייקטי Parameter של ה-Circuit, או להשמיט (או באופן שקול, להגדיר ל-None) אם ל-Circuit אין אובייקטי Parameter.
  • (אופציונלי) דיוק יעד לערכי ציפייה להערכה

Sampler PUB

עבור פרימיטיב ה-Sampler, פורמט ה-PUB מכיל לכל היותר שלושה ערכים:

  • QuantumCircuit יחיד, שעשוי להכיל אובייקט Parameter אחד או יותר הערה: Circuits אלה צריכים לכלול גם הוראות מדידה לכל ה-Qubits שיש לדגום.
  • אוסף של ערכי פרמטרים לקשירה מול ה-Circuit θk\theta_k (נדרש רק אם נעשה שימוש באובייקטי Parameter שיש לקשור אותם בזמן ריצה)
  • (אופציונלי) מספר shots למדידת ה-Circuit

הקוד הבא מדגים קבוצת קלטים מווקטרת לדוגמה לפרימיטיב Estimator ומריץ אותם על Backend של IBM® כאובייקט RuntimeJobV2 יחיד.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
from qiskit.circuit import (
Parameter,
QuantumCircuit,
ClassicalRegister,
QuantumRegister,
)
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp
from qiskit.primitives.containers import BitArray

from qiskit_ibm_runtime import (
QiskitRuntimeService,
EstimatorV2 as Estimator,
SamplerV2 as Sampler,
)

import numpy as np

# Instantiate runtime service and get
# the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Define a circuit with two parameters.
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.ry(Parameter("a"), 0)
circuit.rz(Parameter("b"), 0)
circuit.cx(0, 1)
circuit.h(0)

# Transpile the circuit
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
transpiled_circuit = pm.run(circuit)
layout = transpiled_circuit.layout

# Now define a sweep over parameter values, the last axis of dimension 2 is
# for the two parameters "a" and "b"
params = np.vstack(
[
np.linspace(-np.pi, np.pi, 100),
np.linspace(-4 * np.pi, 4 * np.pi, 100),
]
).T

# Define three observables. The inner length-1 lists cause this array of
# observables to have shape (3, 1), rather than shape (3,) if they were
# omitted.
observables = [
[SparsePauliOp(["XX", "IY"], [0.5, 0.5])],
[SparsePauliOp("XX")],
[SparsePauliOp("IY")],
]
# Apply the same layout as the transpiled circuit.
observables = [
[observable.apply_layout(layout) for observable in observable_set]
for observable_set in observables
]

# Estimate the expectation value for all 300 combinations of observables
# and parameter values, where the pub result will have shape (3, 100).
#
# This shape is due to our array of parameter bindings having shape
# (100, 2), combined with our array of observables having shape (3, 1).
estimator_pub = (transpiled_circuit, observables, params)

# Instantiate the new estimator object, then run the transpiled circuit
# using the set of parameters and observables.
estimator = Estimator(mode=backend)
job = estimator.run([estimator_pub])
result = job.result()

כללי broadcasting

ה-PUBs מאגדים אלמנטים ממערכים מרובים (observables וערכי פרמטרים) על ידי ביצוע אותם כללי broadcasting כמו NumPy. סעיף זה מסכם בקצרה את הכללים האלה. להסבר מפורט, ראה את תיעוד כללי broadcasting של NumPy.

כללים:

  • מערכי קלט אינם צריכים להיות בעלי אותו מספר ממדים.
    • למערך המתקבל יהיה אותו מספר ממדים כמו למערך הקלט עם הממד הגדול ביותר.
    • הגודל של כל ממד הוא הגודל הגדול ביותר של הממד המתאים.
    • ממדים חסרים מניחים שיש להם גודל אחד.
  • השוואות צורה מתחילות מהממד הימני ביותר וממשיכות שמאלה.
  • שני ממדים תואמים אם הגדלים שלהם שווים או אם אחד מהם הוא 1.

דוגמאות לזוגות מערכים שמבצעים broadcasting:

A1     (1d array):      1
A2 (2d array): 3 x 5
Result (2d array): 3 x 5

A1 (3d array): 11 x 2 x 7
A2 (3d array): 11 x 1 x 7
Result (3d array): 11 x 2 x 7

דוגמאות לזוגות מערכים שאינם מבצעים broadcasting:

A1     (1d array):  5
A2 (1d array): 3

A1 (2d array): 2 x 1
A2 (3d array): 6 x 5 x 4 # This would work if the middle dimension were 2, but it is 5.

EstimatorV2 מחזיר הערכת ערך ציפייה אחת לכל אלמנט של הצורה המבוצעת ב-broadcasting.

להלן מספר דוגמאות לתבניות נפוצות המבוטאות במונחים של broadcasting של מערכים. הייצוג הוויזואלי המלווה שלהן מוצג באיור שלאחר מכן:

קבוצות ערכי פרמטרים מיוצגות על ידי מערכים של n x m, ומערכי observables מיוצגים על ידי מערכי עמודה יחידה אחד או יותר. לכל דוגמה בקוד הקודם, קבוצות ערכי הפרמטרים משולבות עם מערך ה-observables שלהן כדי ליצור הערכות ערך ציפייה מתקבלות.

  • דוגמה 1: (broadcast observable יחיד) כוללת קבוצת ערכי פרמטרים שהיא מערך 5x1 ומערך observables של 1x1. הפריט היחיד במערך ה-observables משולב עם כל פריט בקבוצת ערכי הפרמטרים כדי ליצור מערך יחיד 5x1 שבו כל פריט הוא שילוב של הפריט המקורי בקבוצת ערכי הפרמטרים עם הפריט במערך ה-observables.

  • דוגמה 2: (zip) כוללת קבוצת ערכי פרמטרים של 5x1 ומערך observables של 5x1. הפלט הוא מערך 5x1 שבו כל פריט הוא שילוב של הפריט ה-n בקבוצת ערכי הפרמטרים עם הפריט ה-n במערך ה-observables.

  • דוגמה 3: (outer/product) כוללת קבוצת ערכי פרמטרים של 1x6 ומערך observables של 4x1. השילוב שלהם גורם למערך 4x6 שנוצר על ידי שילוב כל פריט בקבוצת ערכי הפרמטרים עם כל פריט במערך ה-observables, ובכך כל ערך פרמטר הופך לעמודה שלמה בפלט.

  • דוגמה 4: (הכללה סטנדרטית של nd) כוללת מערך קבוצת ערכי פרמטרים של 3x6 ושני מערכי observables של 3x1. אלה משולבים ליצירת שני מערכי פלט של 3x6 בדרך דומה לדוגמה הקודמת.

תמונה זו ממחישה מספר ייצוגים חזותיים של broadcasting של מערכים

# Broadcast single observable
parameter_values = np.random.uniform(size=(5,)) # shape (5,)
observables = SparsePauliOp("ZZZ") # shape ()
# >> pub result has shape (5,)

# Zip
parameter_values = np.random.uniform(size=(5,)) # shape (5,)
observables = [
SparsePauliOp(pauli) for pauli in ["III", "XXX", "YYY", "ZZZ", "XYZ"]
] # shape (5,)
# >> pub result has shape (5,)

# Outer/Product
parameter_values = np.random.uniform(size=(1, 6)) # shape (1, 6)
observables = [
[SparsePauliOp(pauli)] for pauli in ["III", "XXX", "YYY", "ZZZ"]
] # shape (4, 1)
# >> pub result has shape (4, 6)

# Standard nd generalization
parameter_values = np.random.uniform(size=(3, 6)) # shape (3, 6)
observables = [
[
[SparsePauliOp(["XII"])],
[SparsePauliOp(["IXI"])],
[SparsePauliOp(["IIX"])],
],
[
[SparsePauliOp(["ZII"])],
[SparsePauliOp(["IZI"])],
[SparsePauliOp(["IIZ"])],
],
] # shape (2, 3, 1)
# >> pub result has shape (2, 3, 6)
SparsePauliOp

כל SparsePauliOp נחשב כאלמנט יחיד בהקשר זה, ללא קשר למספר ה-Paulis הכלולים ב-SparsePauliOp. לכן, לצורך כללי broadcasting אלה, לכל האלמנטים הבאים יש אותה צורה:

a = SparsePauliOp("Z") # shape ()
b = SparsePauliOp("IIIIZXYIZ") # shape ()
c = SparsePauliOp.from_list(["XX", "XY", "IZ"]) # shape ()

הרשימות הבאות של אופרטורים, אף שהן שוות מבחינת המידע הכלול בהן, בעלות צורות שונות:

list1 = SparsePauliOp.from_list(["XX", "XY", "IZ"]) # shape ()
list2 = [SparsePauliOp("XX"), SparsePauliOp("XY"), SparsePauliOp("IZ")] # shape (3, )

סקירה כללית של פלטי פרימיטיבים

לאחר שאחד או יותר PUBs נשלחים ל-QPU לביצוע ומשימה מסתיימת בהצלחה, הנתונים מוחזרים כאובייקט מכיל PrimitiveResult הנגיש על ידי קריאה לשיטת RuntimeJobV2.result(). ה-PrimitiveResult מכיל רשימה ניתנת לאיטרציה של אובייקטי PubResult המכילים את תוצאות הביצוע לכל PUB. בהתאם לפרימיטיב המשמש, נתונים אלה יהיו ערכי ציפייה ופסי השגיאה שלהם במקרה של Estimator, או דגימות של פלט ה-Circuit במקרה של Sampler.

כל אלמנט ברשימה זו מתאים לכל PUB שהוגש לשיטת run() של הפרימיטיב (לדוגמה, משימה שהוגשה עם 20 PUBs תחזיר אובייקט PrimitiveResult המכיל רשימה של 20 PubResultים, אחד המתאים לכל PUB).

לכל אחד מאובייקטי PubResult יש גם מאפיין data וגם מאפיין metadata. מאפיין ה-data הוא DataBin מותאם אישית המכיל את ערכי המדידה בפועל, סטיות תקן, וכן הלאה. ל-DataBin זה יש מאפיינים שונים בהתאם לצורה או למבנה של ה-PUB המשויך וכן לאפשרויות צמצום השגיאות שצוינו על ידי הפרימיטיב ששימש להגשת המשימה (לדוגמה, ZNE או PEC). בינתיים, מאפיין ה-metadata מכיל מידע על אפשרויות זמן הריצה וצמצום השגיאות שנעשה בהן שימוש (מוסבר מאוחר יותר בסעיף מטאדאטה של תוצאות בדף זה).

להלן מתווה חזותי של מבנה הנתונים PrimitiveResult:

└── PrimitiveResult
├── PubResult[0]
│ ├── metadata
│ └── data ## In the form of a DataBin object
│ ├── evs
│ │ └── List of estimated expectation values in the shape
| | specified by the first pub
│ └── stds
│ └── List of calculated standard deviations in the
| same shape as above
├── PubResult[1]
| ├── metadata
| └── data ## In the form of a DataBin object
| ├── evs
| │ └── List of estimated expectation values in the shape
| | specified by the second pub
| └── stds
| └── List of calculated standard deviations in the
| same shape as above
├── ...
├── ...
└── ...

במילים פשוטות, משימה יחידה מחזירה אובייקט PrimitiveResult ומכילה רשימה של אובייקט PubResult אחד או יותר. אובייקטי PubResult אלה שומרים את נתוני המדידה עבור כל PUB שהוגש למשימה.

לכל PubResult יש פורמטים ומאפיינים שונים בהתאם לסוג הפרימיטיב ששימש למשימה. הפרטים מוסברים להלן.

פלט Estimator

כל PubResult עבור פרימיטיב ה-Estimator מכיל לפחות מערך של ערכי ציפייה (PubResult.data.evs) וסטיות תקן משויכות (אחד מ-PubResult.data.stds או PubResult.data.ensemble_standard_error בהתאם ל-resilience_level שנעשה בו שימוש), אך עשוי להכיל נתונים נוספים בהתאם לאפשרויות צמצום השגיאות שצוינו.

קטע הקוד הבא מתאר את פורמט ה-PrimitiveResult (ו-PubResult המשויך) עבור המשימה שנוצרה לעיל.

print(
f"The result of the submitted job had {len(result)} PUB and has a value:\n {result}\n"
)
print(
f"The associated PubResult of this job has the following data bins:\n {result[0].data}\n"
)
print(f"And this DataBin has attributes: {result[0].data.keys()}")
print(
"Recall that this shape is due to our array of parameter binding sets having shape (100, 2) -- where 2 is the\n\
number of parameters in the circuit -- combined with our array of observables having shape (3, 1). \n"
)
print(
f"The expectation values measured from this PUB are: \n{result[0].data.evs}"
)
The result of the submitted job had 1 PUB and has a value:
PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(3, 100), dtype=float64>), stds=np.ndarray(<shape=(3, 100), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(3, 100), dtype=float64>), shape=(3, 100)), metadata={'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': False, 'enable_measure': True, 'num_randomizations': 'auto', 'shots_per_randomization': 'auto', 'interleave_randomizations': True, 'strategy': 'active-accum'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': False, 'pec_mitigation': False}, 'version': 2})

The associated PubResult of this job has the following data bins:
DataBin(evs=np.ndarray(<shape=(3, 100), dtype=float64>), stds=np.ndarray(<shape=(3, 100), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(3, 100), dtype=float64>), shape=(3, 100))

And this DataBin has attributes: dict_keys(['evs', 'stds', 'ensemble_standard_error'])
Recall that this shape is due to our array of parameter binding sets having shape (100, 2) -- where 2 is the
number of parameters in the circuit -- combined with our array of observables having shape (3, 1).

The expectation values measured from this PUB are:
[[ 0.00948597 0.12163221 0.29100944 0.40535344 0.46625814 0.54716103
0.57690846 0.59809047 0.5784682 0.50924868 0.4579837 0.40035644
0.37174056 0.32887613 0.25850853 0.26396412 0.25852429 0.26074166
0.29282485 0.34388535 0.37368314 0.43562138 0.46912323 0.51955146
0.54430185 0.55467261 0.5162183 0.52744696 0.47261781 0.42613541
0.35400013 0.33217125 0.29600426 0.27561903 0.25307754 0.25672088
0.28783701 0.36612701 0.40433263 0.44428286 0.51028376 0.55034507
0.55979913 0.57160124 0.54127534 0.49753533 0.42942659 0.32552331
0.20215918 0.04303087 -0.08115732 -0.18473659 -0.34015892 -0.44489319
-0.49112115 -0.54588034 -0.60601287 -0.55869218 -0.53353861 -0.51628053
-0.44978534 -0.38090252 -0.32481576 -0.28832245 -0.27057547 -0.26542929
-0.27054473 -0.29367389 -0.31531828 -0.38462352 -0.40276794 -0.47168997
-0.48548191 -0.5382924 -0.52716406 -0.53277032 -0.50776933 -0.48512907
-0.44335198 -0.38756463 -0.34438156 -0.29199194 -0.2729216 -0.24602918
-0.23527174 -0.3019153 -0.35159518 -0.38303379 -0.42434541 -0.47743033
-0.54652609 -0.5877912 -0.59175701 -0.57386895 -0.56416812 -0.48022381
-0.3853372 -0.2639702 -0.12030502 0.02081148]
[ 0.00581765 0.0552677 0.15998546 0.20725389 0.25452232 0.34178711
0.39196437 0.47050268 0.50031815 0.527952 0.57231161 0.64066903
0.72429779 0.77011181 0.78174711 0.86610308 0.88646487 0.91337151
0.94245978 0.98100173 0.97372966 1.00936279 1.01881647 1.0544496
1.01954368 1.03699664 0.99845469 1.03845105 1.00936279 1.00354513
0.95409508 0.95264067 0.91264431 0.91846196 0.8355604 0.80283611
0.77956549 0.74102354 0.69520953 0.64575948 0.58976457 0.53231524
0.43996 0.3956004 0.32069812 0.27706572 0.22470684 0.16653032
0.07272066 -0.00218162 -0.05817653 -0.06253977 -0.15853104 -0.25015908
-0.28506499 -0.34251432 -0.44359604 -0.44432324 -0.53158804 -0.60285429
-0.637033 -0.67630215 -0.71266249 -0.76793019 -0.81519862 -0.86464867
-0.90173621 -0.93155168 -0.9337333 -0.98245614 -0.99627307 -1.01518044
-1.01590764 -1.04863194 -1.00499955 -1.02827016 -1.01663485 -1.0108172
-1.02317971 -0.97518407 -0.96500318 -0.94682302 -0.901009 -0.87846559
-0.79556404 -0.84937733 -0.78101991 -0.73811472 -0.65521316 -0.57667485
-0.59921825 -0.49813653 -0.44577766 -0.36505772 -0.33524225 -0.25888556
-0.21161713 -0.12289792 -0.03781474 0.00654486]
[ 0.01315429 0.18799671 0.42203343 0.603453 0.67799397 0.75253494
0.76185256 0.72567827 0.65661825 0.49054535 0.3436558 0.16004385
0.01918334 -0.11235955 -0.26473006 -0.33817484 -0.36941628 -0.39188819
-0.35681008 -0.29323102 -0.22636339 -0.13812003 -0.08057002 -0.01534667
0.06906002 0.07234859 0.03398191 0.01644286 -0.06412716 -0.15127432
-0.24609482 -0.28829816 -0.32063579 -0.3672239 -0.32940532 -0.28939435
-0.20389148 -0.00876953 0.11345574 0.24280625 0.43080296 0.5683749
0.67963826 0.74760208 0.76185256 0.71800493 0.63414634 0.48451631
0.3315977 0.08824335 -0.10413812 -0.30693341 -0.52178679 -0.6396273
-0.69717731 -0.74924637 -0.76842971 -0.67306111 -0.53548918 -0.42970677
-0.26253768 -0.08550288 0.06303097 0.19128528 0.27404768 0.33379008
0.36064675 0.34420389 0.30309674 0.2132091 0.19073719 0.07180049
0.04494382 -0.02795286 -0.04932858 -0.03727049 0.00109619 0.04055906
0.13647575 0.20005481 0.27624007 0.36283913 0.3551658 0.38640723
0.32502055 0.24554673 0.07782954 -0.02795286 -0.19347767 -0.3781858
-0.49383393 -0.67744588 -0.73773637 -0.78268019 -0.793094 -0.70156207
-0.55905728 -0.40504248 -0.20279529 0.0350781 ]]

כיצד Estimator מחשב שגיאה

בנוסף להערכת הממוצע של ה-observables שהועברו ב-PUBs בקלט (שדה ה-evs של ה-DataBin), Estimator גם מנסה לספק הערכה של השגיאה המשויכת לערכי ציפייה אלה. כל שאילתות ה-Estimator ימלאו את שדה ה-stds בכמות כגון שגיאת התקן של הממוצע לכל ערך ציפייה, אך חלק מאפשרויות צמצום השגיאות מייצרות מידע נוסף, כגון ensemble_standard_error.

שקול observable יחיד O\mathcal{O}. בהיעדר ZNE, ניתן לחשוב על כל shot של ביצוע Estimator כמספק הערכה נקודתית של ערך הציפייה O\langle \mathcal{O} \rangle. אם ההערכות הנקודתיות נמצאות בוקטור Os, אז הערך המוחזר ב-ensemble_standard_error שקול לדברים הבאים (בהם σO\sigma_{\mathcal{O}} הוא סטיית התקן של ערך הציפייה ו-NshotsN_{shots} הוא מספר ה-shots):

σONshots,\frac{ \sigma_{\mathcal{O}} }{ \sqrt{N_{shots}} },

שמתייחס לכל ה-shots כחלק ממכלול יחיד. אם ביקשת twirling של Gate (twirling.enable_gates = True), ניתן למיין את ההערכות הנקודתיות של O\langle \mathcal{O} \rangle לקבוצות החולקות twirl משותף. קרא לקבוצות הערכות אלה O_twirls, ויש num_randomizations (מספר ה-twirls) מהן. אז stds הוא שגיאת התקן של ממוצע O_twirls, כמו ב

σONtwirls,\frac{ \sigma_{\mathcal{O}} }{ \sqrt{N_{twirls}} },

כאשר σO\sigma_{\mathcal{O}} הוא סטיית התקן של O_twirls ו-NtwirlsN_{twirls} הוא מספר ה-twirls. כשאינך מפעיל twirling, stds ו-ensemble_standard_error שווים.

אם תפעיל ZNE, אז ה-stds המתוארים לעיל הופכים למשקלים ברגרסיה לא-לינארית למודל extrapolator. מה שסופית מוחזר ב-stds במקרה זה הוא אי-הוודאות של מודל ה-fit המוערך בגורם רעש של אפס. כאשר יש fit גרוע, או אי-ודאות גדולה ב-fit, ה-stds המדווחים יכולים להיות גדולים מאוד. כאשר ZNE מופעל, pub_result.data.evs_noise_factors ו-pub_result.data.stds_noise_factors גם מאוכלסים, כך שתוכל לבצע extrapolation משלך.

פלט Sampler

כאשר משימת Sampler מסתיימת בהצלחה, אובייקט ה-PrimitiveResult המוחזר מכיל רשימה של SamplerPubResultים, אחד לכל PUB. bins הנתונים של אובייקטי SamplerPubResult אלה הם אובייקטים דמויי-dict המכילים BitArray אחד לכל ClassicalRegister ב-Circuit.

מחלקת ה-BitArray היא מכיל לנתוני shot מסודרים. בפירוט רב יותר, היא שומרת את מחרוזות הביטים שנדגמו כ-bytes בתוך מערך דו-ממדי. הציר השמאלי ביותר של מערך זה עובר על shots מסודרים, בעוד שהציר הימני ביותר עובר על bytes.

כדוגמה ראשונה, בואו נסתכל על ה-Circuit הבא בעל עשרה Qubits:

# generate a ten-qubit GHZ circuit
circuit = QuantumCircuit(10)
circuit.h(0)
circuit.cx(range(0, 9), range(1, 10))

# append measurements with the `measure_all` method
circuit.measure_all()

# transpile the circuit
transpiled_circuit = pm.run(circuit)

# run the Sampler job and retrieve the results
sampler = Sampler(mode=backend)
job = sampler.run([transpiled_circuit])
result = job.result()

# the data bin contains one BitArray
data = result[0].data
print(f"Databin: {data}\n")

# to access the BitArray, use the key "meas", which is the default name of
# the classical register when this is added by the `measure_all` method
array = data.meas
print(f"BitArray: {array}\n")
print(f"The shape of register `meas` is {data.meas.array.shape}.\n")
print(f"The bytes in register `alpha`, shot by shot:\n{data.meas.array}\n")
Databin: DataBin(meas=BitArray(<shape=(), num_shots=4096, num_bits=10>))

BitArray: BitArray(<shape=(), num_shots=4096, num_bits=10>)

The shape of register `meas` is (4096, 2).

The bytes in register `alpha`, shot by shot:
[[ 3 254]
[ 0 0]
[ 3 255]
...
[ 0 0]
[ 3 255]
[ 0 0]]

לעתים נוח להמיר מפורמט ה-bytes ב-BitArray למחרוזות ביטים. שיטת get_count מחזירה מילון שממפה מחרוזות ביטים למספר הפעמים שהן התרחשו.

# optionally, convert away from the native BitArray format to a dictionary format
counts = data.meas.get_counts()
print(f"Counts: {counts}")
Counts: {'1111111110': 199, '0000000000': 1337, '1111111111': 1052, '1111111000': 33, '1110000000': 65, '1100100000': 2, '1100000000': 25, '0010001110': 1, '0000000011': 30, '1111111011': 58, '1111111010': 25, '0000000110': 7, '0010000001': 11, '0000000001': 179, '1110111110': 6, '1111110000': 33, '1111101111': 49, '1110111111': 40, '0000111010': 2, '0100000000': 35, '0000000010': 51, '0000100000': 31, '0110000000': 7, '0000001111': 22, '1111111100': 24, '1011111110': 5, '0001111111': 58, '0000111111': 24, '1111101110': 10, '0000010001': 5, '0000001001': 2, '0011111111': 38, '0000001000': 11, '1111100000': 34, '0111111111': 45, '0000000100': 18, '0000000101': 2, '1011111111': 11, '1110000001': 13, '1101111000': 1, '0010000000': 52, '0000010000': 17, '0000011111': 15, '1110100001': 1, '0111111110': 9, '0000000111': 19, '1101111111': 15, '1111110111': 17, '0011111110': 5, '0001101110': 1, '0111111011': 6, '0100001000': 2, '0010001111': 1, '1111011000': 1, '0000111110': 4, '0011110010': 1, '1110111100': 2, '1111000000': 8, '1111111101': 27, '0000011110': 6, '0001000000': 5, '1111010000': 3, '0000011011': 4, '0001111110': 9, '1111011110': 6, '1110001111': 2, '0100000001': 7, '1110111011': 3, '1111101101': 2, '1101111110': 5, '1110000010': 7, '0111111000': 1, '1110111000': 1, '0000100001': 2, '1110100000': 6, '1000000001': 2, '0001011111': 1, '0000010111': 1, '1011111100': 1, '0111110000': 5, '0110111111': 2, '0010000010': 1, '0001111100': 4, '0011111001': 2, '1111110011': 1, '1110000011': 5, '0000001011': 8, '0100000010': 3, '1111011111': 13, '0010111000': 2, '0100111110': 1, '1111101000': 2, '1110110000': 2, '1100000001': 1, '0001110000': 3, '1011101111': 2, '1111000001': 2, '1111110001': 8, '1111110110': 4, '1100000010': 3, '0011000000': 2, '1110011111': 3, '0011101111': 3, '0010010000': 2, '0000100010': 1, '1100001110': 1, '0001111011': 4, '1010000000': 3, '0000001110': 5, '0000001010': 2, '0011111011': 4, '0100100000': 2, '1111110100': 1, '1111100011': 3, '0000110110': 1, '0001111101': 2, '1111100001': 2, '1000000000': 5, '0010000011': 3, '0010011111': 3, '0100001111': 1, '0100000111': 1, '1011101110': 1, '0011110111': 1, '1100000111': 1, '1100111111': 3, '0001111010': 1, '1101111011': 1, '0111111100': 2, '0100000110': 2, '0100000011': 2, '0001101111': 3, '0001000001': 1, '1111110010': 1, '0010100000': 1, '0011100000': 4, '1010001111': 1, '0101111111': 2, '1111101001': 1, '1110111101': 1, '0000011101': 1, '1110001000': 2, '0001111001': 1, '0101000000': 1, '1111111001': 5, '0001110111': 2, '0000111001': 1, '0100001011': 1, '0000010011': 1, '1011110111': 1, '0011110001': 1, '0000001100': 2, '0111010111': 1, '0001101011': 1, '1110010000': 2, '1110000100': 1, '0010111111': 3, '0111011100': 1, '1010001000': 1, '0000101110': 1, '0011111100': 2, '0000111100': 2, '1110011110': 1, '0011111000': 2, '0110100000': 1, '1001101111': 1, '1011000000': 1, '1101000000': 1, '1110001011': 1, '1110110111': 1, '0110111110': 1, '0011011111': 1, '0111100000': 1, '0000110111': 1, '0000010010': 2, '1111101100': 2, '1111011101': 1, '1101100000': 1, '0010111110': 1, '1101101110': 1, '1111001111': 1, '1101111100': 1, '1011111010': 1, '0001100000': 1, '1101110111': 1, '1100001011': 1}

כאשר Circuit מכיל יותר מ-ClassicalRegister אחד, התוצאות מאוחסנות באובייקטי BitArray שונים. הדוגמה הבאה משנה את הקטע הקודם על ידי פיצול ה-ClassicalRegister לשני registers נפרדים:

# generate a ten-qubit GHZ circuit with two classical registers
circuit = QuantumCircuit(
qreg := QuantumRegister(10),
alpha := ClassicalRegister(1, "alpha"),
beta := ClassicalRegister(9, "beta"),
)
circuit.h(0)
circuit.cx(range(0, 9), range(1, 10))

# append measurements with the `measure_all` method
circuit.measure([0], alpha)
circuit.measure(range(1, 10), beta)

# transpile the circuit
transpiled_circuit = pm.run(circuit)

# run the Sampler job and retrieve the results
sampler = Sampler(mode=backend)
job = sampler.run([transpiled_circuit])
result = job.result()

# the data bin contains two BitArrays, one per register, and can be accessed
# as attributes using the registers' names
data = result[0].data
print(f"BitArray for register 'alpha': {data.alpha}")
print(f"BitArray for register 'beta': {data.beta}")
BitArray for register 'alpha': BitArray(<shape=(), num_shots=4096, num_bits=1>)
BitArray for register 'beta': BitArray(<shape=(), num_shots=4096, num_bits=9>)

שימוש ב-BitArray לעיבוד לאחר ביצועי

מכיוון שמערכים בדרך כלל מציעים ביצועים טובים יותר בהשוואה למילונים, מומלץ לבצע כל עיבוד לאחר ישירות על אובייקטי BitArray ולא על מילוני ספירות. מחלקת BitArray מציעה מגוון שיטות לביצוע כמה פעולות עיבוד לאחר נפוצות:

print(f"The shape of register `alpha` is {data.alpha.array.shape}.")
print(f"The bytes in register `alpha`, shot by shot:\n{data.alpha.array}\n")

print(f"The shape of register `beta` is {data.beta.array.shape}.")
print(f"The bytes in register `beta`, shot by shot:\n{data.beta.array}\n")

# post-select the bitstrings of `beta` based on having sampled "1" in `alpha`
mask = data.alpha.array == "0b1"
ps_beta = data.beta[mask[:, 0]]
print(f"The shape of `beta` after post-selection is {ps_beta.array.shape}.")
print(f"The bytes in `beta` after post-selection:\n{ps_beta.array}")

# get a slice of `beta` to retrieve the first three bits
beta_sl_bits = data.beta.slice_bits([0, 1, 2])
print(
f"The shape of `beta` after bit-wise slicing is {beta_sl_bits.array.shape}."
)
print(f"The bytes in `beta` after bit-wise slicing:\n{beta_sl_bits.array}\n")

# get a slice of `beta` to retrieve the bytes of the first five shots
beta_sl_shots = data.beta.slice_shots([0, 1, 2, 3, 4])
print(
f"The shape of `beta` after shot-wise slicing is {beta_sl_shots.array.shape}."
)
print(
f"The bytes in `beta` after shot-wise slicing:\n{beta_sl_shots.array}\n"
)

# calculate the expectation value of diagonal operators on `beta`
ops = [SparsePauliOp("ZZZZZZZZZ"), SparsePauliOp("IIIIIIIIZ")]
exp_vals = data.beta.expectation_values(ops)
for o, e in zip(ops, exp_vals):
print(f"Exp. val. for observable `{o}` is: {e}")

# concatenate the bitstrings in `alpha` and `beta` to "merge" the results of the two
# registers
merged_results = BitArray.concatenate_bits([data.alpha, data.beta])
print(f"\nThe shape of the merged results is {merged_results.array.shape}.")
print(f"The bytes of the merged results:\n{merged_results.array}\n")
The shape of register `alpha` is (4096, 1).
The bytes in register `alpha`, shot by shot:
[[1]
[1]
[1]
...
[0]
[0]
[1]]

The shape of register `beta` is (4096, 2).
The bytes in register `beta`, shot by shot:
[[ 0 135]
[ 0 247]
[ 1 247]
...
[ 0 0]
[ 1 224]
[ 1 255]]

The shape of `beta` after post-selection is (0, 2).
The bytes in `beta` after post-selection:
[]
The shape of `beta` after bit-wise slicing is (4096, 1).
The bytes in `beta` after bit-wise slicing:
[[7]
[7]
[7]
...
[0]
[0]
[7]]

The shape of `beta` after shot-wise slicing is (5, 2).
The bytes in `beta` after shot-wise slicing:
[[ 0 135]
[ 0 247]
[ 1 247]
[ 1 128]
[ 1 255]]

Exp. val. for observable `SparsePauliOp(['ZZZZZZZZZ'],
coeffs=[1.+0.j])` is: 0.068359375
Exp. val. for observable `SparsePauliOp(['IIIIIIIIZ'],
coeffs=[1.+0.j])` is: 0.06396484375

The shape of the merged results is (4096, 2).
The bytes of the merged results:
[[ 1 15]
[ 1 239]
[ 3 239]
...
[ 0 0]
[ 3 192]
[ 3 255]]

מטאדאטה של תוצאות

בנוסף לתוצאות הביצוע, גם אובייקטי PrimitiveResult וגם PubResult מכילים מאפיין מטאדאטה על המשימה שהוגשה. המטאדאטה המכילה מידע על כל ה-PUBs שהוגשו (כגון אפשרויות זמן הריצה השונות הזמינות) ניתן למצוא ב-PrimitiveResult.metatada, בעוד שהמטאדאטה הספציפית לכל PUB נמצאת ב-PubResult.metadata.

הערה

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

# Print out the results metadata
print("The metadata of the PrimitiveResult is:")
for key, val in result.metadata.items():
print(f"'{key}' : {val},")

print("\nThe metadata of the PubResult result is:")
for key, val in result[0].metadata.items():
print(f"'{key}' : {val},")
The metadata of the PrimitiveResult is:
'execution' : {'execution_spans': ExecutionSpans([DoubleSliceSpan(<start='2026-01-15 08:07:33', stop='2026-01-15 08:07:36', size=4096>)])},
'version' : 2,

The metadata of the PubResult result is:
'circuit_metadata' : {},

עבור משימות Sampler, ניתן גם לסקור את מטאדאטה התוצאות כדי להבין מתי נתונים מסוימים הורצו; זה נקרא execution span.