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

أمثلة على Executor

إصدارات الحزم

الكود في هذه الصفحة تم تطويره باستخدام المتطلبات التالية. نوصي باستخدام هذه الإصدارات أو أحدث.

qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
samplomatic~=0.18.0
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime samplomatic

الأمثلة في هذا القسم توضح بعض الطرق الشائعة لاستخدام الأداة البدائية Executor. قبل تشغيل هذه الأمثلة، اتبع التعليمات الواردة في تثبيت Qiskit و البدء السريع مع Executor.

قبل البدء

بعض أمثلة الكود في هذه الصفحة تستخدم samplex، وهو جزء من حزمة Samplomatic. لذلك، قبل تشغيل كتلة الكود تلك، يجب تثبيت Samplomatic، كما هو موضح في كتلة الكود التالية. لمزيد من المعلومات، انظر وثائق Samplomatic.

pip install samplomatic

# For visualization support, include the visualization dependencies.
# pip install samplomatic[vis]

مثال: دائرة ذات معاملات

يوضح هذا المثال كيفية إضافة عناصر دائرة بمعاملات، وكذلك كيفية إضافة عناصر samplex. يتكون من الخطوات التالية:

  1. إعداد الدائرة: توليد الدائرة الهدف ونقلها.
  2. تحضير samplex: تجميع البوابات والقياسات في صناديق موضحة وتوليد زوج قالب الدائرة وsamplex.
  3. التنفيذ: إضافة عنصر دائرة وعنصر samplex إلى QuantumProgram وتنفيذ كليهما في مهمة واحدة.

إعداد الدائرة

تحضير حالة GHZ ثلاثية القبتات، وتدوير القبتات حول محور Pauli-Z، وقياس القبتات في الأساس الحسابي.

from qiskit.circuit import Parameter, QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from qiskit.transpiler import generate_preset_pass_manager
import numpy as np
from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager

# Generate the circuit
circuit = QuantumCircuit(3)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.h(2)
circuit.cz(1, 2)
circuit.h(2)
circuit.rz(Parameter("theta"), 0)
circuit.rz(Parameter("phi"), 1)
circuit.rz(Parameter("lam"), 2)
circuit.measure_all()

حدد Backend وانقل الدائرة لتستخدم فقط التعليمات المدعومة من قِبل QPU (يُشار إليه بدائرة معمارية مجموعة التعليمات (ISA)).

# Initialize the service and choose a backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Transpile the circuit to ISA
preset_pass_manager = generate_preset_pass_manager(
backend=backend, optimization_level=3
)
isa_circuit = preset_pass_manager.run(circuit)

تحضير samplex

استخدم دالة الراحة generate_boxing_pass_manager ومعاملات twirling الخاصة بها لتجميع بوابات ثنائية القبت والقياسات في صناديق وتطبيق تعليقات twirling.

boxing_pm = generate_boxing_pass_manager(
# Add gate twirling
enable_gates=True,
# Add measurement twirling
enable_measures=True,
)

boxed_circuit = boxing_pm.run(isa_circuit)

استخدم طريقة build لتوليد قالب الدائرة وsamplex.

# Build the template circuit and the samplex
template_circuit, samplex = build(boxed_circuit)

تنفيذ الدوائر

يشغّل Executor كائنات QuantumProgram. يمكن لكل QuantumProgram احتواء عدة عناصر. يضيف هذا المثال عنصر دائرة وعنصر samplex للتنفيذ. للتفاصيل الكاملة، انظر مدخلات ومخرجات Executor.

الخطوة الأولى هي تهيئة برنامج فارغ، مع طلب 1024 shots لكل تكوين من كل عنصر.

# Generate a quantum program
program = QuantumProgram(shots=1024)

إلحاق عنصر الدائرة بـ QuantumProgram. يتكون عنصر الدائرة هذا من جزأين - دائرة ISA و10 مجموعات من قيم معاملاتها.

# Append the circuit and the parameter values to the program
program.append_circuit_item(
isa_circuit,
circuit_arguments=np.random.rand(10, 3), # 10 sets of parameter values
)

إلحاق عنصر samplex بـ QuantumProgram مع هذه الوسيطات:

  • قالب الدائرة وsamplex الناتجان عن دالة build
  • عشر مجموعات من قيم المعاملات للدائرة الأصلية
  • عدد العشوائيات المراد إجراؤها
# Append the template circuit and samplex as a samplex item
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
"parameter_values": np.random.rand(
10, 3
), # 10 sets of parameter values
},
shape=(2, 14, 10),
)

تشغيل مهمة Executor

# initialize an Executor with default options
executor = Executor(mode=backend)

# Submit the job
job = executor.run(program)

# Retrieve the result
result = job.result()

استرداد النتيجة لكل مهمة.

# Access the results of the classical register of task #0, the CircuitItem
result_0 = result[0]["meas"]

# Access the results of the classical register of task #1, the SamplexItem
result_1 = result[1]["meas"]

مثال: تنفيذ PEC

يوضح هذا المثال كيفية استخدام عنصر samplex لتنفيذ إلغاء الأخطاء الاحتمالي (PEC) لتخفيف الأخطاء.

ضع في اعتبارك نسخة معكوسة من دائرة مكونة من عشرة قبتات وطبقتين فريدتين من بوابات CX. هذه هي المهام الرئيسية:

تتكون الأنبوبة من الخطوات التالية:

  1. الإعداد: توليد الدائرة الهدف وتجميع عملياتها في صناديق.
  2. التعلم: تعلم الضوضاء للتعليمات التي نريد تخفيفها باستخدام PEC.
  3. التنفيذ: تشغيل الدائرة على Backend.
  4. التحليل: المعالجة اللاحقة وتحليل النتائج.

للمقارنة، سنشغل هذه الدائرة المعكوسة مرتين. مرة مع تطبيق Pauli-twirling فقط، ومرة مع تطبيق تخفيف PEC.

ملاحظة

الاستخدام لهذا المثال هو حوالي 10 دقائق على معالج Heron r2.

إعداد الدائرة

اختر Backend وحضّر دائرة مكونة من 10 قبتات.

from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.transpiler import generate_preset_pass_manager
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic import build

# Initialize the service and choose a backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Prepare a circuit

num_qubits = 10
num_layers = 10

qubits = list(range(num_qubits))
circuit = QuantumCircuit(num_qubits)

for layer_idx in range(num_layers):
circuit.rx(Parameter(f"theta_{layer_idx}"), qubits)
for i in range(num_qubits // 2):
circuit.cz(qubits[2 * i], qubits[2 * i + 1])

circuit.rx(Parameter(f"phi_{layer_idx}"), qubits)
for i in range(num_qubits // 2 - 1):
circuit.cz(qubits[2 * i] + 1, qubits[2 * i + 1] + 1)

circuit.draw("mpl", scale=0.35, fold=100)

Output of the previous code cell

ادمج الدائرة مع معكوسها لإنشاء دائرة معكوسة.

mirror_circuit = circuit.compose(circuit.inverse())
mirror_circuit.measure_all()

mirror_circuit.draw("mpl", scale=0.35, fold=100)

Output of the previous code cell

ضبط بعض قيم المعاملات:

import numpy as np

parameter_values = np.random.rand(mirror_circuit.num_parameters)

استخدم مدير التمرير لنقل الدائرة لتصبح دائرة ISA.

preset_pass_manager = generate_preset_pass_manager(
backend=backend,
optimization_level=3,
)

isa_circuit = preset_pass_manager.run(mirror_circuit)

بعد ذلك، جمّع البوابات والقياسات في صناديق موضحة. يمكنك القيام بذلك يدوياً أو استخدام دالة generate_boxing_pass_manager من Samplomatic للراحة. ستحتوي الدائرة الأولى على twirling فقط وبالتالي تحتاج فقط إلى تعليق Twirl. ستُشغَّل الدائرة الثانية مع تخفيف PEC كامل وتحتاج إلى كل من تعليقي Twirl وInjectNoise.

# Pass manager used to create twirled-annotated boxes.
boxing_pm = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
)

mirror_circuit_twirl = boxing_pm.run(isa_circuit)

# Pass manager used to create a new boxed circuit with
# both Twirl and InjectNoise annotations.
boxing_pm = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
inject_noise_targets="gates", # no measurement mitigation
inject_noise_strategy="uniform_modification",
)

mirror_circuit_pec = boxing_pm.run(isa_circuit)

تعلم الضوضاء

لتقليل عدد تجارب تعلم الضوضاء، حدد التعليمات الفريدة في الدائرة الثانية (تلك التي تحتوي على صناديق موضحة بـ InjectNoise). في تحديد التفرد، يكون تعليمَا صندوق متساويَين إذا كان كلا الأمرين التاليين صحيحَين:

  • محتواهما متساوٍ، حتى البوابات أحادية القبت.
  • تعليق Twirl الخاص بهما متساوٍ (يُهمَل كل تعليق آخر).

يؤدي هذا إلى ثلاث تعليمات فريدة، وهي صناديق البوابات الفردية والزوجية، وصندوق القياس النهائي.

from samplomatic.utils import find_unique_box_instructions

unique_box_instructions = find_unique_box_instructions(
mirror_circuit_pec.data
)
assert len(unique_box_instructions) == 3

قم بتهيئة NoiseLearnerV3، واختر معاملات التعلم عن طريق ضبط خياراته، وشغّل مهمة تعلم الضوضاء.

from qiskit_ibm_runtime.noise_learner_v3 import NoiseLearnerV3

learner = NoiseLearnerV3(backend)

learner.options.shots_per_randomization = 128
learner.options.num_randomizations = 32
learner.options.layer_pair_depths = [0, 1, 2, 4, 16, 32]

learner_job = learner.run(unique_box_instructions)

learner_job.job_id()
learner_result = learner_job.result()

تحويل result إلى الكائن المطلوب من قِبل samplex باستخدام طريقة result.to_dict.

noise_maps = learner_result.to_dict(
instructions=unique_box_instructions, require_refs=False
)

تنفيذ الدوائر

يشغّل Executor كائنات QuantumProgram. يمكن لكل QuantumProgram احتواء عدة عناصر، يتم إلحاقها بالبرنامج. كل عنصر هو مهمة يقوم البرنامج بتنفيذها.

قم بتهيئة برنامج فارغ، مع طلب 1000 shots لكل تكوين من كل عنصر.

from qiskit_ibm_runtime.quantum_program import QuantumProgram

# Initialize an empty QuantumProgram
program = QuantumProgram(shots=1000)

بعد ذلك، أنشئ قالب الدائرة وsamplex لـ mirror_circuit_twirl وألحقهما بالبرنامج. اطلب أيضاً 900 عشوائية من samplex. هذا يعني أن samplex سيولّد 900 مجموعة من المعاملات، وستُنفَّذ كل مجموعة 1000 مرة (عدد الـ shots) في QPU.

هذه هي المهمة الأولى للبرنامج (النتيجة 0).

template_twirl, samplex_twirl = build(mirror_circuit_twirl)

program.append_samplex_item(
template_twirl,
samplex=samplex_twirl,
samplex_arguments={"parameter_values": parameter_values},
shape=(900,),
)

بالمثل، ألحق قالب الدائرة وsamplex المبنيين لـ mirror_circuit_pec، مع طلب 900 عشوائية. هذه هي المهمة الثانية للبرنامج (النتيجة 1).

template_pec, samplex_pec = build(mirror_circuit_pec)

program.append_samplex_item(
template_pec,
samplex=samplex_pec,
samplex_arguments={
"parameter_values": parameter_values,
"pauli_lindblad_maps": noise_maps,
"noise_scales": {
ref: -1.0 for ref in noise_maps
}, # Set the scales to -1 for PEC
},
shape=(900,),
)

قم باستيراد Executor وإرسال مهمة.

from qiskit_ibm_runtime.executor import Executor

executor = Executor(backend)
executor_job = executor.run(program)

executor_job.job_id()

executor_results = executor_job.result()
executor_results

twirl_result = executor_results[0]

print(f"Twirl result keys:\n {list(twirl_result.keys())}\n")
print(f"Shape of results: {twirl_result['meas'].shape}")

pec_result = executor_results[1]

print(f"PEC result keys:\n {list(pec_result.keys())}\n")
print(f"Shape of results: {pec_result['meas'].shape}")
Twirl result keys:
['meas', 'measurement_flips.meas']

Shape of results: (900, 1000, 10)
PEC result keys:
['meas', 'measurement_flips.meas', 'pauli_signs']

Shape of results: (900, 1000, 10)

تحليل النتائج

أخيراً، قم بمعالجة النتائج لاحقاً لتقدير قيم التوقع لمؤثرات Pauli-Z أحادية القبت التي تعمل على كل من القبتات العشر النشطة (القيمة المتوقعة: 1.0).

# Undo measurement twirling
twirl_result_unflipped = (
twirl_result["meas"] ^ twirl_result["measurement_flips.meas"]
)

# Calculate the expectation values of single-qubit Z operators
exp_vals = 1 - 2 * twirl_result_unflipped.mean(axis=1).mean(axis=0)

for qubit, val in enumerate(exp_vals):
print(f"Qubit {qubit} -> {np.round(val, 2)}")
Qubit 0 -> 0.77
Qubit 1 -> 0.76
Qubit 2 -> 0.66
Qubit 3 -> 0.71
Qubit 4 -> 0.69
Qubit 5 -> 0.67
Qubit 6 -> 0.62
Qubit 7 -> 0.59
Qubit 8 -> 0.62
Qubit 9 -> 0.68
# Undo measurement twirling
pec_result_unflipped = (
pec_result["meas"] ^ pec_result["measurement_flips.meas"]
)

# Calculate the signs for PEC mitigation
signs = np.prod((-1) ** pec_result["pauli_signs"], axis=-1)
signs = signs.reshape((signs.shape[0], 1))

# Calculate the expectation values of single-qubit Z operators as required by
# PEC mitigation
exp_vals = 1 - (2 * pec_result_unflipped.mean(axis=1) * signs).mean(axis=0)

for qubit, val in enumerate(exp_vals):
print(f"Qubit {qubit} -> {np.round(val, 2)}")
Qubit 0 -> 0.98
Qubit 1 -> 0.99
Qubit 2 -> 0.96
Qubit 3 -> 0.98
Qubit 4 -> 0.98
Qubit 5 -> 0.98
Qubit 6 -> 0.98
Qubit 7 -> 0.95
Qubit 8 -> 0.95
Qubit 9 -> 0.94

الخطوات التالية

توصيات