title: "Schnellstart" description: "Eine Kurzanleitung zum Qiskit-Add-ons-Paket „pauli-prop“"
Schnellstart
In dieser Anleitung verwenden wir das Paket pauli-prop , um die zeitliche Dynamik eines 10-Qubit-Kicked-Ising-Modells auf einer Spin-Kette vom Typ „ 1D “ klassisch zu simulieren.
Bereiten Sie die Eingaben für die Pauli-Ausbreitung vor
Der betrachtete Hamilton-Operator lautet:
wobei die Kopplung zwischen Spins nächster Nachbarn beschreibt, und das globale Transversalfeld ist. Eine Trotter-Zerlegung erster Ordnung des zeitabhängigen Operators wird als Quantenschaltung „ “ über Trotter-Schritte implementiert. Die Kopplungskonstante „ “ wird auf „ “ festgelegt, und „ “ wird auf „ “ festgelegt. Die Wechselwirkungen „ “ werden mithilfe von Clifford-Gattern implementiert ( , , ).
Wir implementieren die Trotterisierte Zeitentwicklung als Quantenschaltung und verwenden „ “ für die nicht-Clifford-Rotationen um die x-Achse. Je weiter diese Winkel von den Clifford-Winkeln abweichen (zum Beispiel ), desto schwieriger wird die Simulation des Systems mit Pauli-Ausbreitungsmethoden.
Als Observable wählen wir die durchschnittliche Magnetisierung an einem einzelnen Ort, , wobei die Anzahl der Spins ist.
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)Output:
Simuliere die zeitliche Entwicklung des Systems mit der Pauli-Ausbreitung
Sobald wir unseren Schaltkreis und unsere Observable haben, können wir das System in wenigen Schritten ganz einfach simulieren:
- Teile in seine Clifford-Komponenten und seine Nicht-Clifford-Komponenten auf, sodass gilt, und zwar unter Verwendung von
evolve_through_cliffords - Führen Sie die Ausbreitung von „ “ über „ “ durch, was zu einem neuen Operator „ “ führt, und zwar mithilfe von
pauli_prop.propagate_through_circuit - Entwickeln Sie „ “ im Clifford-Teil des Schaltkreises mithilfe der in Qiskit integrierten Unterstützung für die Clifford-Evolution weiter
- Man approximiert den Erwartungswert als , indem man die Koeffizienten in summiert, die mit vollständig diagonalen Pauli-Termen verbunden sind (Pauli-Terme, die auf
Zallen Qubits entwederIoder enthalten). Denken Sie daran, dass es sich hierbei um eine Näherung handelt, da wir Terme aus abgeschnitten haben, als wir diese durch den Nicht-Clifford-Teil der Schaltung weitergeleitet haben.
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())
)Je umfangreicher die Berechnungen sind, desto genauer werden die Näherungswerte für die Erwartungswerte. In diesem Beispiel erreichen wir bei etwa die Sättigung des gesamten Pauli-Raums, was sich darin zeigt, dass die Kurve zwischen den letzten beiden Punkten abflacht.
Während die untenstehende Grafik eine monotone Konvergenz zeigt, konvergieren Pauli-Ausbreitungssimulationen im Allgemeinen nicht monoton. Es ist nicht ungewöhnlich, dass solche Diagramme ein „unregelmäßiges“ Verhalten aufweisen.
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")Output:
Text(0.5, 1.0, 'Simulating 20-step 1D Ising Model')