חיתוך Gate להפחתת עומק Circuit
במדריך הזה נפחית את עומק ה-Circuit על ידי חיתוך Gates מרוחקים, תוך הימנעות מ-Swap Gates שהיו מתווספים בדרך כלל במהלך הניתוב.
אלו השלבים שנעבור בתבנית Qiskit pattern הזו:
- שלב 1: מיפוי הבעיה ל-Circuit קוונטי ואופרטורים:
- מיפוי ההמילטוניאן ל-Circuit קוונטי.
- שלב 2: אופטימיזציה לחומרה היעד [משתמש בתוסף החיתוך]:
- חיתוך ה-Circuit והאובייקט הנצפה.
- Transpile של תת-הניסויים לחומרה.
- שלב 3: הרצה על חומרה יעד:
- הרצת תת-הניסויים שהתקבלו בשלב 2 בעזרת הפרימיטיב
Sampler.
- הרצת תת-הניסויים שהתקבלו בשלב 2 בעזרת הפרימיטיב
- שלב 4: עיבוד תוצאות לאחר מכן [משתמש בתוסף החיתוך]:
- שילוב תוצאות שלב 3 לצורך שחזור ערך הציפייה של האובייקט הנצפה.
שלב 1: מיפוי
יצירת Circuit להרצה על ה-Backend
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-addon-cutting qiskit-aer qiskit-ibm-runtime
from qiskit.circuit.library import efficient_su2
circuit = efficient_su2(num_qubits=4, entanglement="circular")
circuit.assign_parameters([0.4] * len(circuit.parameters), inplace=True)
circuit.draw("mpl", scale=0.8)

הגדרת אובייקט נצפה
from qiskit.quantum_info import SparsePauliOp
observable = SparsePauliOp(["ZZII", "IZZI", "-IIZZ", "XIXI", "ZIZZ", "IXIX"])
שלב 2: אופטימיזציה
הגדרת Backend
אפשר לספק Backend מדומה או Backend חומרה אמיתית מ-Qiskit Runtime.
from qiskit_ibm_runtime.fake_provider import FakeManilaV2
backend = FakeManilaV2()
Transpile של ה-Circuit, ויזואליזציה של ה-Swap Gates ורישום העומק
אנחנו בוחרים פריסה שדורשת שני Swap Gates להרצת ה-Gates בין qubit 3 ל-Qubit 0, ועוד שני Swap Gates להחזרת ה-Qubits למיקומם ההתחלתי.
from qiskit.transpiler import generate_preset_pass_manager
pass_manager = generate_preset_pass_manager(
optimization_level=1, backend=backend, initial_layout=[0, 1, 2, 3]
)
transpiled_qc = pass_manager.run(circuit)
print(f"Transpiled circuit depth: {transpiled_qc.depth(lambda x: len(x.qubits) >= 2)}")
Transpiled circuit depth: 30
transpiled_qc.draw("mpl", scale=0.4, idle_wires=False, fold=-1)

החלפת Gates מרוחקים ב-TwoQubitQPDGate על ידי ציון האינדקסים שלהם
cut_gates יחליף את ה-Gates באינדקסים שצוינו ב-TwoQubitQPDGates, ויחזיר גם רשימה של מופעי QPDBasis — אחד לכל פירוק Gate.
from qiskit_addon_cutting import cut_gates
# Find the indices of the distant gates
cut_indices = [
i
for i, instruction in enumerate(circuit.data)
if {circuit.find_bit(q)[0] for q in instruction.qubits} == {0, 3}
]
# Decompose distant CNOTs into TwoQubitQPDGate instances
qpd_circuit, bases = cut_gates(circuit, cut_indices)
qpd_circuit.draw("mpl", scale=0.8)

יצירת תת-הניסויים להרצה על ה-Backend
generate_cutting_experiments מקבל Circuit המכיל מופעי TwoQubitQPDGate ואובייקטים נצפים כ-PauliList.
כדי לדמות את ערך הציפייה של ה-Circuit המלא, נוצרים תת-ניסויים רבים מהתפלגות הקוואזי-הסתברות המשותפת של ה-Gates המפורקים, ולאחר מכן הם מורצים על Backend אחד או יותר. מספר הדגימות מהתפלגות נשלט על ידי num_samples, ומקדם משולב אחד ניתן לכל דגימה ייחודית. למידע נוסף על אופן חישוב המקדמים, ראה את החומר ההסברתי.
הערה: ארגומנט ה-observables של generate_cutting_experiments הוא מסוג PauliList. מקדמי ופאזות של איברי האובייקט הנצפה מתעלמים בעת פירוק הבעיה וביצוע תת-הניסויים. ניתן להחיל אותם מחדש בשלב שחזור ערך הציפייה.
import numpy as np
from qiskit_addon_cutting import generate_cutting_experiments
# Generate the subexperiments and sampling coefficients
subexperiments, coefficients = generate_cutting_experiments(
circuits=qpd_circuit, observables=observable.paulis, num_samples=np.inf
)
חישוב עלות הדגימה עבור החיתוכים שנבחרו
כאן אנחנו חותכים שלושה CNOT Gates, וכתוצאה מכך עלות הדגימה היא .
למידע נוסף על עלות הדגימה שנגרמת מחיתוך Circuit, ראה את החומר ההסברתי.
print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
Sampling overhead: 729.0
הדגמה שתת-ניסויי QPD יהיו רדודים יותר לאחר חיתוך Gates מרוחקים
הנה דוגמה לתת-ניסוי שנבחר באקראי שנוצר מה-Circuit של QPD. עומקו הופחת ביותר מחצי. יש לייצר ולהעריך תת-ניסויים הסתברותיים רבים כדי לשחזר ערך ציפייה של ה-Circuit העמוק יותר.
# Transpile the decomposed circuit to the same layout
transpiled_qpd_circuit = pass_manager.run(subexperiments[100])
print(
f"Original circuit depth after transpile: {transpiled_qc.depth(lambda x: len(x.qubits) >= 2)}"
)
print(
f"QPD subexperiment depth after transpile: {transpiled_qpd_circuit.depth(lambda x: len(x.qubits) >= 2)}"
)
transpiled_qpd_circuit.draw("mpl", scale=0.8, idle_wires=False, fold=-1)
Original circuit depth after transpile: 30
QPD subexperiment depth after transpile: 7

הכנת תת-הניסויים ל-Backend
# Transpile the subeperiments to the backend's instruction set architecture (ISA)
isa_subexperiments = pass_manager.run(subexperiments)
שלב 3: הרצה
הרצת תת-הניסויים באמצעות הפרימיטיב Sampler של Qiskit Runtime
from qiskit_ibm_runtime import SamplerV2
# Set up the Qiskit Runtime Sampler primitive. For a fake backend, this will use a local simulator.
sampler = SamplerV2(backend)
# Submit the subexperiments
job = sampler.run(isa_subexperiments)
# Retrieve the results
results = job.result()
שלב 4: עיבוד לאחר מכן
שחזור ערך הציפייה
שחזור ערכי ציפייה לכל איבר של האובייקט הנצפה ושילובם לשחזור ערך הציפייה של האובייקט הנצפה המקורי.
from qiskit_addon_cutting import reconstruct_expectation_values
reconstructed_expval_terms = reconstruct_expectation_values(
results,
coefficients,
observable.paulis,
)
# Reconstruct final expectation value
reconstructed_expval = np.dot(reconstructed_expval_terms, observable.coeffs)
השוואת ערך הציפייה המשוחזר לערך הציפייה המדויק מה-Circuit והאובייקט הנצפה המקוריים
from qiskit_aer.primitives import EstimatorV2
estimator = EstimatorV2()
exact_expval = estimator.run([(circuit, observable)]).result()[0].data.evs
print(f"Reconstructed expectation value: {np.real(np.round(reconstructed_expval, 8))}")
print(f"Exact expectation value: {np.round(exact_expval, 8)}")
print(f"Error in estimation: {np.real(np.round(reconstructed_expval-exact_expval, 8))}")
print(
f"Relative error in estimation: {np.real(np.round((reconstructed_expval-exact_expval) / exact_expval, 8))}"
)
Reconstructed expectation value: 0.44018555
Exact expectation value: 0.50497603
Error in estimation: -0.06479049
Relative error in estimation: -0.12830408