למידת מודל הרעש של שער
המדריך הזה מדגים למידה של מודל רעש לשער יוניטרי באמצעות פרוטוקול למידה סטנדרטי, הזמין דרך פונקציות הפרוטוקול ברמה גבוהה prepare_vanilla_program() ו-process_vanilla_result().
-
הגדרת השער
-
הגדרת סימולציה מקומית
-
הכנת התוכנית הקוונטית
-
הרצת התוכנית הקוונטית
-
קריאת התוצאות
המעגלים שלמטה מסומלצים מקומית, ולכן המדריך הזה לא דורש פרטי גישה של IBM Quantum®. כדי להריץ אותו במקום זה על מכשיר אמיתי:
-
שלב 1: מחליפים את
FakeMarrakeshב-Backend אמיתי. -
שלב 2: מעבירים את ה-Backend הזה בתור ה-mode של ה-executor, ומסירים את אפשרויות הסימולטור.
1. הגדרת השער
השער הוא BoxOp שמכיל שכבה עם twirling של שישה שערי CZ זרים.
from qiskit.circuit import QuantumCircuit
from qiskit_ibm_runtime.fake_provider import FakeMarrakesh
from samplomatic import InjectNoise, Tag, Twirl
backend = FakeMarrakesh()
cz_pairs = [(91, 92), (93, 94), (95, 99), (98, 111), (112, 113), (114, 115)]
circuit = QuantumCircuit(backend.num_qubits)
with circuit.box([Twirl(), Tag("cz_gate"), InjectNoise("cz_gate")]):
for pair in cz_pairs:
circuit.cz(*pair)
from qiskit_ibm_runtime import QiskitRuntimeService
backend = QiskitRuntimeService().backend("ibm_marrakesh")
2. הגדרת סימולציה מקומית
אינדקסי הפאולי בכל מפה הם מקומיים לשער, לפי סדר עולה של ה-Qubit הפיזי:
cz_qubits = sorted({qubit for pair in cz_pairs for qubit in pair})
local = {qubit: index for index, qubit in enumerate(cz_qubits)}
local
{91: 0,
92: 1,
93: 2,
94: 3,
95: 4,
98: 5,
99: 6,
111: 7,
112: 8,
113: 9,
114: 10,
115: 11}
מגדירים את הרעש עם איבר ZZ מתואם ואיבר XX חלש יותר על כל זוג CZ, ובנוסף איבר Z של Qubit בודד בכל מקום; למדידה יש איבר היפוך סיביות לכל Qubit.
from qiskit.quantum_info import PauliLindbladMap
num_qubits = len(cz_qubits)
cz_noise = PauliLindbladMap.from_sparse_list(
[("ZZ", [local[a], local[b]], 8e-4) for a, b in cz_pairs]
+ [("XX", [local[a], local[b]], 4e-4) for a, b in cz_pairs]
+ [("Z", [index], 3e-4) for index in range(num_qubits)],
num_qubits=num_qubits,
)
readout_noise = PauliLindbladMap.from_sparse_list(
[("X", [index], 5e-3) for index in range(num_qubits)], num_qubits=num_qubits
)
בונים קופסה שהמדידה תלמד.
measurement = QuantumCircuit(backend.num_qubits, num_qubits)
with measurement.box([Twirl(), Tag("readout"), InjectNoise("readout")]):
for clbit, qubit in enumerate(cz_qubits):
measurement.measure(qubit, clbit)
כל רשומה ב-layer_noise_model מזווגת אחת מהקופסאות האלה עם המפה שמיישמים עליה. משתמשים בשיטת סימולציית ה-stabilizer, וקובעים את seed_simulator כדי שהנתונים המדומים יהיו ניתנים לשחזור.
from qiskit_aer import AerSimulator
from qiskit_ibm_runtime import Executor
executor = Executor(
mode=AerSimulator(method="stabilizer"),
options={
"simulator": {
"layer_noise_model": [
(circuit[0], cz_noise),
(measurement[0], readout_noise),
],
"seed_simulator": 1234,
}
},
)
executor = Executor(mode=backend)
3. הכנת התוכנית הקוואנטית
משתמשים ב-prepare_vanilla_program() כדי לבנות את התוכנית הקוואנטית שמכילה את ניסויי הלמידה.
from qiskit_noise_learning.protocols import prepare_vanilla_program
program = prepare_vanilla_program(
backend,
[circuit[0], measurement[0]],
fragment_depths=[2, 16, 64, 128],
num_randomizations=50,
shots_per_randomization=20,
)
print(f"Number of template circuits: {len(program.items)}")
Number of template circuits: 5
4. הרצת התוכנית הקוואנטית
שולחים את התוכנית הקוואנטית. השלב הזה זהה בין אם ה-executor מכוון לסימולטור ובין אם להתקן אמיתי.
result = executor.run(program).result()
5. קריאת התוצאות
מעבדים את התוצאה באמצעות process_vanilla_result().
from qiskit_noise_learning.protocols import process_vanilla_result
noise_maps, gate_names, fit = process_vanilla_result(result)
משרטטים את דעיכת הנאמנות לכל זוג Qubit: גם את הנתונים וגם את ההתאמה האקספוננציאלית.
fit.plot_qubit_pair_decays(
pairs=cz_pairs,
observable_type="means",
exponential_fit=True,
)