דלג לתוכן הראשי
פרויקט זה בשלב בטא. מצאת באג? פתח issue ב-GitHub. יש שאלה או רעיון? שאל ב-Discussions — נשמח לשמוע ממך!
מה איכות התרגום בדף זה?

סימולציה מדויקת עם primitives של Qiskit SDK

גרסאות חבילות

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

qiskit[all]~=2.5.2

ה-primitives הייחוסיים ב-Qiskit SDK מבצעים סימולציות statevector מקומיות. סימולציות אלו אינן תומכות במידול רעש של המכשיר, אך הן שימושיות ליצירת אב-טיפוס מהיר של אלגוריתמים, לפני שפונים לטכניקות סימולציה מתקדמות יותר (שימוש ב-Qiskit Aer) או להרצה על מכשירים אמיתיים (IBM Quantum primitives).

ה-Estimator Primitive יכול לחשב ערכי תוחלת של Circuit, וה-Sampler Primitive יכול לדגום מהתפלגויות הפלט של Circuit.

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

שימוש ב-Estimator הייחוסי​

המימוש הייחוסי של EstimatorV2 ב-qiskit.primitives שרץ על סימולטורי statevector מקומיים הוא המחלקה StatevectorEstimator. היא יכולה לקבל Circuit, observables ופרמטרים כקלטים ומחזירה את ערכי התוחלת המחושבים באופן מקומי.

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

הערה

אסור שמעגל שמועבר ל-Estimator יכלול מדידות כלשהן.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit"}
_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")
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter

# circuit for which you want to obtain the expected value
circuit = QuantumCircuit(2)
circuit.ry(Parameter("theta"), 0)
circuit.h(0)
circuit.cx(0, 1)
circuit.draw("mpl", style="iqp")

Output of the previous code cell

from qiskit.quantum_info import SparsePauliOp
import numpy as np

# observable(s) whose expected values you want to compute

observable = SparsePauliOp(["II", "XX", "YY", "ZZ"], coeffs=[1, 1, -1, 1])

# value(s) for the circuit parameter(s)
parameter_values = [[0], [np.pi / 6], [np.pi / 2]]
Transpile ל-ISA circuits ו-observables

זרימת העבודה של IBM Quantum primitives דורשת שמעגלים ו-observables יומרו לשימוש רק בהוראות הנתמכות על ידי ה-QPU (המכונים מעגלי instruction set architecture (ISA) ו-observables). ה-primitives הייחוסיים עדיין מקבלים הוראות מופשטות, מכיוון שהם מסתמכים על סימולציות statevector מקומיות, אך Transpile של המעגל עשוי עדיין להיות מועיל מבחינת אופטימיזציית המעגל.

# Generate a pass manager without providing a backend
from qiskit.transpiler import generate_preset_pass_manager

pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)

אתחול Estimator​

צור מופע של qiskit.primitives.StatevectorEstimator.

from qiskit.primitives import StatevectorEstimator

estimator = StatevectorEstimator()

הרצה וקבלת תוצאות​

דוגמה זו משתמשת רק ב-Circuit אחד (מסוג QuantumCircuit) וב-observable אחד.

הרץ את ההערכה על ידי קריאה למתודה StatevectorEstimator.run, שמחזירה מופע של אובייקט PrimitiveJob. ניתן לקבל את התוצאות מהמשימה (כאובייקט qiskit.primitives.PrimitiveResult) עם המתודה qiskit.primitives.PrimitiveJob.result.

job = estimator.run([(circuit, observable, parameter_values)])
result = job.result()
print(f" > Result class: {type(result)}")
> Result class: <class 'qiskit.primitives.containers.primitive_result.PrimitiveResult'>

קבלת ערך התוחלת מהתוצאה​

תוצאות ה-primitives מפיקות מערך של אובייקטי PubResult, כאשר כל פריט במערך הוא אובייקט PubResult שמכיל בנתוניו את מערך ההערכות המתאים לכל שילוב Circuit-observable ב-PUB.

כדי לאחזר את ערכי התוחלת והמטא-נתונים עבור הערכת ה-Circuit הראשונה (ובמקרה זה, היחידה), עלינו לגשת ל-data של ההערכה עבור PUB 0:

print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")
> Expectation value: [4. 3.73205081 2. ]
> Metadata: {'target_precision': 0.0, 'circuit_metadata': {}}

הגדרת אפשרויות הרצה של Estimator​

כברירת מחדל, ה-Estimator הייחוסי מבצע חישוב statevector מדויק המבוסס על המחלקה quantum_info.Statevector. אולם, ניתן לשנות זאת כדי להכניס את ההשפעה של תקורת הדגימה (המכונה גם "shot noise").

ה-Estimator מקבל ארגומנט precision שמבטא את פסי השגיאה שמימוש ה-primitive אמור לשאוף אליהם עבור הערכות ערכי תוחלת. זוהי תקורת הדגימה ומוגדרת אך ורק במתודה .run(). זה מאפשר לכוון את האפשרות עד לרמת ה-PUB.

# Estimate expectation values for two PUBs, both with 0.05 precision.
precise_job = estimator.run(
[(circuit, observable, parameter_values)], precision=0.05
)

לדוגמה מלאה, ראה את הדף דוגמאות Estimator.

שימוש ב-Sampler הייחוסי​

המימוש הייחוסי של SamplerV2 ב-qiskit.primitives הוא המחלקה StatevectorSampler. היא מקבלת מעגלים ופרמטרים כקלטים ומחזירה את תוצאות הדגימה מהתפלגויות ההסתברות של הפלט, כהתפלגות קוואזי-הסתברותית של מצבי הפלט.

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

from qiskit import QuantumCircuit

circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
circuit.draw("mpl", style="iqp")

Output of the previous code cell

הערה

כל Circuit קוונטי שמועבר ל-Sampler חייב לכלול מדידות.

Transpile ל-ISA circuits ו-observables

זרימת העבודה של IBM Quantum primitives דורשת שמעגלים יומרו לשימוש רק בהוראות הנתמכות על ידי ה-QPU (המכונים מעגלי ISA). ה-primitives הייחוסיים עדיין מקבלים הוראות מופשטות, מכיוון שהם מסתמכים על סימולציות statevector מקומיות, אך Transpile של המעגל עשוי עדיין להיות מועיל מבחינת אופטימיזציית המעגל.

# Generate a pass manager without providing a backend
from qiskit.transpiler import generate_preset_pass_manager

pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(qc)

אתחול SamplerV2​

צור מופע של qiskit.primitives.StatevectorSampler:

from qiskit.primitives import StatevectorSampler

sampler = StatevectorSampler()

הרצה וקבלת תוצאות​

# execute 1 circuit with Sampler
job = sampler.run([circuit])
pub_result = job.result()[0]
print(f" > Result class: {type(pub_result)}")
> Result class: <class 'qiskit.primitives.containers.sampler_pub_result.SamplerPubResult'>

Primitives מקבלים מספר PUBs כקלטים, וכל PUB מקבל תוצאה משלו. לפיכך, ניתן להריץ Circuit שונים עם שילובי פרמטר/observable שונים, ולאחזר את תוצאות ה-PUB:

from qiskit.transpiler import generate_preset_pass_manager

# create two circuits
circuit1 = circuit.copy()
circuit2 = circuit.copy()

# transpile circuits
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit1 = pm.run(circuit1)
isa_circuit2 = pm.run(circuit2)
# execute 2 circuits using Sampler
job = sampler.run([(isa_circuit1), (isa_circuit2)])
pub_result_1 = job.result()[0]
pub_result_2 = job.result()[1]
print(f" > Result class: {type(pub_result)}")
> Result class: <class 'qiskit.primitives.containers.sampler_pub_result.SamplerPubResult'>

קבלת התפלגות ההסתברות או תוצאת המדידה​

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

הערה

שם הרגיסטר הקלאסי מוגדר כברירת מחדל ל-"meas". שם זה ישמש מאוחר יותר לגישה ל-bitstrings של המדידה.

# Define quantum circuit with 2 qubits
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
circuit.draw()
┌───┐ ░ ┌─┐
q_0: ┤ H ├──■───░─┤M├───
└───┘┌─┴─┐ ░ └╥┘┌─┐
q_1: ─────┤ X ├─░──╫─┤M├
└───┘ ░ ║ └╥┘
meas: 2/══════════════╩══╩═
0 1
# Transpile circuit
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(circuit)
# Run using Sampler
result = sampler.run([circuit]).result()
# Access result data for PUB 0
data_pub = result[0].data
# Access bitstring for the classical register "meas"
bitstrings = data_pub.meas.get_bitstrings()
print(f"The number of bitstrings is: {len(bitstrings)}")
# Get counts for the classical register "meas"
counts = data_pub.meas.get_counts()
print(f"The counts are: {counts}")
The number of bitstrings is: 1024
The counts are: {'00': 513, '11': 511}

שינוי אפשרויות הרצה​

כברירת מחדל, ה-Sampler הייחוסי מבצע חישוב statevector מדויק המבוסס על המחלקה quantum_info.Statevector. אולם, ניתן לשנות זאת כדי להכניס את ההשפעה של תקורת הדגימה (המכונה גם "shot noise"). כדי לעזור לנהל תקורה זו, ממשק ה-Sampler מקבל ארגומנט shots שניתן להגדיר ברמת ה-PUB.

דוגמה זו מניחה שהגדרת שני Circuit.

# Sample two circuits at 128 shots each.
sampler.run([isa_circuit1, isa_circuit2], shots=128)
# Sample two circuits at different amounts of shots. The "None"s are necessary
# as placeholders
# for the lack of parameter values in this example.
sampler.run([(isa_circuit1, None, 123), (isa_circuit2, None, 456)])
<qiskit.primitives.primitive_job.PrimitiveJob at 0x1297391d0>

לדוגמה מלאה, ראה את הדף דוגמאות Sampler.

הצעדים הבאים​

המלצות