התחלה מהירה
title: התחלה מהירה description: מדריך התחלה מהירה לחבילת ה-addons של Qiskit בשם pauli-prop
במדריך הזה נשתמש בחבילה pauli-prop כדי לסמלץ בצורה קלאסית את הדינמיקה בזמן של מודל Ising עם בעיטות על 10 qubit בשרשרת ספינים חד-ממדית.
הכנת הקלטים ל-Pauli propagation
ההמילטוניאן שבו נתמקד הוא:
כאשר מתאר את הצימוד בין ספינים שכנים, , ו- הוא השדה הרוחבי הגלובלי. פירוק Trotter מסדר ראשון של האופרטור המתפתח בזמן ימומש כמעגל קוונטי, , על פני צעדי Trotter. קבוע הצימוד, , יקבע ל-, ו- יקבע ל-. אינטראקציות ה- ימומשו באמצעות שערי Clifford (, , ).
אנחנו מממשים את ההתפתחות בזמן בשיטת Trotter כמעגל קוונטי ומשתמשים ב- לסיבובים שאינם Clifford סביב ציר x. ככל שהזוויות האלה רחוקות יותר מזוויות Clifford (לדוגמה, ), כך יהיה קשה יותר לסמלץ את המערכת בשיטות Pauli propagation.
כאובזרבבל אנחנו בוחרים את המגנטיזציה הממוצעת של אתר בודד, , כאשר הוא מספר הספינים.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"matplotlib": "matplotlib", "numpy": "numpy", "pauli_prop": "pauli-prop", "qiskit": "qiskit", "qiskit_aer": "qiskit-aer"}
_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")
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import CouplingMap
num_qubits = 10
coupling_map = CouplingMap.from_line(num_qubits, bidirectional=False)
# Num Trotter steps
num_steps = 20
theta_rx = np.pi / 6
# Average single-site magnetization
observable = (
SparsePauliOp(
[
"I" * iq + "Z" + "I" * (num_qubits - iq - 1)
for iq in range(num_qubits)
]
)
/ num_qubits
)
# Create the Trotter circuit
num_qubits = 10
num_steps = 20
theta_rx = np.pi / 6
circuit = QuantumCircuit(num_qubits)
edges = CouplingMap.from_line(num_qubits, bidirectional=False).get_edges()
for _ in range(num_steps):
circuit.rx(theta_rx, [i for i in range(num_qubits)])
for edge in edges:
circuit.sdg(edge)
circuit.ry(np.pi / 2, edge[1])
circuit.cx(edge[0], edge[1])
circuit.ry(-np.pi / 2, edge[1])
circuit.draw("mpl", fold=-1)
סימולציה של ההתפתחות בזמן של המערכת באמצעות Pauli propagation
ברגע שיש לנו את המעגל, , ואת האובזרבבל, , אפשר לסמלץ את המערכת בכמה צעדים פשוטים:
-
מפרידים את לחלק ה-Clifford שלו, , ולחלק שאינו Clifford, , כך ש-, באמצעות
evolve_through_cliffords -
מקדמים את דרך , וכך מקבלים אופרטור חדש, , באמצעות
pauli_prop.propagate_through_circuit -
מפתחים את דרך חלק ה-Clifford של המעגל באמצעות התמיכה בהתפתחות Clifford המובנית ב-Qiskit
-
מקרבים את ערך התצפית כ- על ידי סכימת המקדמים ב- המשויכים לאיברי Pauli אלכסוניים לגמרי (איברי Pauli שמכילים
IאוZבלבד בכל ה-qubit). חשוב לזכור שזה קירוב, כי קטענו איברים מ- בזמן שקידמנו אותו דרך החלק של המעגל שאינו Clifford.
import time
from pauli_prop import evolve_through_cliffords, propagate_through_circuit
cliff, non_cliff = evolve_through_cliffords(circuit)
max_terms_list = [10**i for i in range(8)]
approx_evs = []
durations = []
for max_terms in max_terms_list:
st = time.perf_counter()
evolved_obs = propagate_through_circuit(
observable, non_cliff, max_terms=max_terms, atol=1e-12, frame="h"
)[0]
evolved_obs.paulis = evolved_obs.paulis.evolve(cliff, frame="h")
durations.append(time.perf_counter() - st)
approx_evs.append(
float(evolved_obs.coeffs[~evolved_obs.paulis.x.any(axis=1)].sum())
)
ככל שמריצים חישובים גדולים יותר, קירובי ערך התצפית נעשים מדויקים יותר. בדוגמה הזאת אנחנו ממלאים את כל מרחב Pauli סביב , וזה מתבטא בכך שהעקומה מתיישרת בין שתי הנקודות האחרונות.
התרשים שלמטה מראה התכנסות מונוטונית, אבל סימולציות Pauli propagation לא מתכנסות בדרך כלל באופן מונוטוני. זה לא נדיר לראות התנהגות "מחוספסת" בתרשימים מהסוג הזה.
import matplotlib.pyplot as plt
from qiskit_aer import AerSimulator
sim_circ = circuit.copy()
sim_circ.save_statevector()
backend = AerSimulator(method="statevector")
psi = backend.run(sim_circ).result().data()["statevector"]
exact_ev = psi.expectation_value(observable)
ax1 = plt.gca()
ax1.plot(max_terms_list, approx_evs, marker="o", label="Approximate")
ax1.axhline(exact_ev, linestyle="--", color="green", label="Exact")
ax1.set_xscale("log")
ax1.set_xlabel("# terms kept")
ax1.set_ylabel(r"$\frac{1}{N} \sum_{i=1}^{N} \langle z_i \rangle$")
ax2 = ax1.twinx()
ax2.plot(
max_terms_list, durations, marker=".", label="Runtime", color="orange"
)
ax2.set_ylabel("Runtime (s)", color="orange")
ax2.set_yscale("log")
handles1, labels1 = ax1.get_legend_handles_labels()
handles2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(handles1 + handles2, labels1 + labels2, loc="lower right")
plt.title(f"Simulating {num_steps}-step 1D Ising Model")
Text(0.5, 1.0, 'Simulating 20-step 1D Ising Model')

