Ein gekicktes Ising-Modell mit 127 Qubits simulieren
In diesem Leitfaden verwenden wir das Paket pauli-prop, um die Zeitdynamik eines gekickten Ising-Modells mit 127 Qubits auf einem Heavy-Hex-Gitter klassisch zu simulieren und die Magnetisierung eines einzelnen Gitterplatzes, , zu approximieren. Der betrachtete Hamiltonian lautet:
wobei die Kopplung nächster benachbarter Spins beschreibt, , und das globale transversale Feld ist. Eine Trotter-Zerlegung erster Ordnung des zeitentwickelten Operators wird als Quantencircuit über Trotter-Schritte implementiert. Die Kopplungskonstante wird auf festgelegt, sodass immer dann ein Clifford-Circuit ist, wenn gilt.
Arbeitsablauf:
-
Quantencircuits erstellen, die das Trotterisierte Ising-Modell implementieren
- zwischen den Clifford-Punkten und variieren
-
Einen Gitterplatz in der Mitte des Gitters (Qubit ) wählen und für jeden Circuit die Magnetisierung nach Trotter-Schritten schätzen
-
Beobachten, wie die Magnetisierung von auf abfällt, während von einem Clifford-Punkt zum anderen wandert
Circuits erstellen
Zuerst verwenden wir FakeSherbrooke aus qiskit-ibm-runtime, um die Kantenindizes der Kopplungskarte des 127-Qubit-Eagle-QPU zu erhalten. Sobald wir die Kantenindizes haben, erstellen wir die Trotter-Circuits für die verschiedenen Werte von , die wir simulieren wollen. Die Circuits implementieren eine Trotterisierung erster Ordnung des Hamiltonians mit 20 Trotter-Schritten und 5420 Gates.
# 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_ibm_runtime": "qiskit-ibm-runtime"}
_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_ibm_runtime.fake_provider import FakeSherbrooke
# Get the edges in the device coupling map
backend = FakeSherbrooke()
edges = backend.coupling_map.get_edges()
# Num Trotter steps
num_steps = 20
# Create Trotter circuits with varying global fields
hs = [i * np.pi / 32 for i in range(17)]
circuits = []
for h in hs:
circuit = QuantumCircuit(backend.num_qubits)
for _ in range(num_steps):
circuit.rx(h, [i for i in range(backend.num_qubits)])
for edge in edges:
circuit.rzz(-np.pi / 2, edge[0], edge[1])
circuits.append(circuit)
Die Zeitdynamik mit Pauli-Propagation simulieren
Als Nächstes legen wir die Observable fest, die wir messen wollen. In diesem Fall schätzen wir .
Um die Magnetisierung zwischen den Clifford-Punkten zu untersuchen, propagieren wir näherungsweise an den Anfang des Circuits , was eine neue Observable ergibt.
Während der Propagation wächst die Anzahl der Terme in der entwickelten Observable exponentiell mit der Anzahl der Gates, daher ist es meist nötig, ihr Wachstum zu begrenzen. Hier begrenzen wir die Anzahl der Terme in auf und schneiden Terme mit Koeffizienten kleiner als ab. Das Abschneiden von Termen führt zu einem gewissen Fehler.
Sobald wir haben, können wir den Erwartungswert einfach schätzen, indem wir die Koeffizienten der diagonalen Terme in summieren (Terme, die auf allen Qubits nur aus I oder Z bestehen).
Wir setzen frame='h', um anzugeben, dass wir die Observable im Heisenberg-Bild entwickeln wollen (). Verwende frame=s für die Schrödinger-Evolution ().
import time
from pauli_prop import propagate_through_circuit
from qiskit.quantum_info import Pauli, SparsePauliOp
# Z_62 observable
id_pauli = Pauli("I" * backend.num_qubits)
observable = SparsePauliOp(id_pauli.dot(Pauli("Z"), [62]))
# Estimate the single-site magnetization for varying magnetic fields
times = []
approx_evs = []
for circuit in circuits:
st = time.perf_counter()
propagated_obs = propagate_through_circuit(
observable, circuit, 100_000, 1e-5, frame="h"
)[0]
times.append(time.perf_counter() - st)
approx_evs.append(
float(
propagated_obs.coeffs[~propagated_obs.paulis.x.any(axis=1)].sum()
)
)
print(f"Finished {len(circuits)} simulations in {sum(times):.0f}s")
Finished 17 simulations in 494s
Visualisieren
Schließlich stellen wir die Magnetisierung als Funktion von dar. Für beeinflusst der Circuit den Anfangszustand in der Rechenbasis nicht, und wir wissen, dass gilt. Wenn sich weiter von entfernt, nimmt die Magnetisierung monoton ab, bis den nächsten Clifford-Winkel erreicht und die Magnetisierung gegen konvergiert.
import matplotlib.pyplot as plt
plt.xlabel(r"$R_x$ angle $\theta_h$")
plt.ylabel(r"$\langle Z_{62} \rangle$")
plt.plot(hs, approx_evs, marker="o")
[<matplotlib.lines.Line2D at 0x123f68b00>]
