Zum Hauptinhalt springen
Dieses Projekt befindet sich in der Beta-Phase. Einen Fehler gefunden? GitHub Issue erstellen. Frage oder Idee? In Discussions fragen — wir freuen uns über dein Feedback!
Wie ist die Übersetzungsqualität auf dieser Seite?

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, ⟨Z62⟩\langle Z_{62} \rangle, zu approximieren. Der betrachtete Hamiltonian lautet:

H=−J∑⟨i,j⟩ZiZj+h∑iXiH = -J\sum\limits_{\langle i,j \rangle} Z_iZ_j + h\sum\limits_iX_i

wobei J>0J>0 die Kopplung nächster benachbarter Spins beschreibt, i<ji<j, und hh das globale transversale Feld ist. Eine Trotter-Zerlegung erster Ordnung des zeitentwickelten Operators wird als Quantencircuit UU über 2020 Trotter-Schritte implementiert. Die Kopplungskonstante JJ wird auf J=−π2J=-\frac{\pi}{2} festgelegt, sodass UU immer dann ein Clifford-Circuit ist, wenn hmod  π2=0h\mod\frac{\pi}{2}=0 gilt.

Arbeitsablauf:

  • Quantencircuits erstellen, die das Trotterisierte Ising-Modell implementieren

    • hh zwischen den Clifford-Punkten 0.00.0 und π2\frac{\pi}{2} variieren
  • Einen Gitterplatz in der Mitte des Gitters (Qubit 6262) wählen und für jeden Circuit die Magnetisierung nach 2020 Trotter-Schritten schätzen

  • Beobachten, wie die Magnetisierung von 1.01.0 auf 0.00.0 abfällt, während hh 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 hh, 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 OO fest, die wir messen wollen. In diesem Fall schätzen wir ⟨Z62⟩\langle Z_{62} \rangle.

Um die Magnetisierung zwischen den Clifford-Punkten zu untersuchen, propagieren wir OO näherungsweise an den Anfang des Circuits UU, was eine neue Observable O′≈U†OUO^\prime \approx U^{\dagger}OU 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 O′O^\prime auf 10510^5 und schneiden Terme mit Koeffizienten kleiner als 10−510^{-5} ab. Das Abschneiden von Termen führt zu einem gewissen Fehler. Sobald wir O′O^\prime haben, können wir den Erwartungswert ⟨0∣U†OU∣0⟩=⟨0∣O′∣0⟩\langle0|U^{\dagger}OU|0\rangle = \langle0|O^\prime|0\rangle einfach schätzen, indem wir die Koeffizienten der diagonalen Terme in O′O^\prime 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 (U†OUU^{\dagger}OU). Verwende frame=s für die Schrödinger-Evolution (UOU†UOU^{\dagger}).

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 hh dar. Für h=0h=0 beeinflusst der Circuit den Anfangszustand in der Rechenbasis nicht, und wir wissen, dass ⟨0∣O∣0⟩=1.0\langle0|O|0\rangle = 1.0 gilt. Wenn sich hh weiter von 00 entfernt, nimmt die Magnetisierung monoton ab, bis hh den nächsten Clifford-Winkel π2\frac{\pi}{2} erreicht und die Magnetisierung gegen 00 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>]

Output of the previous code cell