Démarrage rapide
title: Démarrage rapide description: Un guide de démarrage rapide pour le package pauli-prop des addons Qiskit
Dans ce guide, tu utilises le package pauli-prop pour simuler classiquement la dynamique temporelle d'un modèle d'Ising avec kicks à 10 qubits sur une chaîne de spins 1D.
Préparer les entrées de la propagation de Pauli
L'hamiltonien considéré est :
où décrit le couplage des spins plus proches voisins, , et est le champ transverse global. Une décomposition de Trotter du premier ordre de l'opérateur évolué dans le temps sera implémentée sous forme de Circuit quantique, , sur pas de Trotter. La constante de couplage, , sera fixée à , et sera fixé à . Les interactions seront implémentées avec des portes de Clifford (, , ).
Nous implémentons l'évolution temporelle trotterisée sous forme de Circuit quantique et utilisons pour les rotations non-Clifford autour de l'axe x. Plus ces angles sont éloignés des angles de Clifford (par exemple, ), plus le système sera difficile à simuler avec les méthodes de propagation de Pauli.
Pour le choix de l'observable, nous considérons l'aimantation moyenne par site, , où est le nombre de spins.
# 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)
Simuler l'évolution temporelle du système avec la propagation de Pauli
Une fois que nous avons notre Circuit, , et notre observable, , nous pouvons facilement simuler le système en quelques étapes :
-
Séparer en sa partie de Clifford, , et sa partie non-Clifford, , de sorte que , avec
evolve_through_cliffords -
Propager à travers , ce qui donne un nouvel opérateur, , avec
pauli_prop.propagate_through_circuit -
Faire évoluer à travers la partie de Clifford du Circuit avec la prise en charge de l'évolution de Clifford intégrée à Qiskit
-
Approximer la valeur moyenne par en sommant les coefficients de associés aux termes de Pauli entièrement diagonaux (termes de Pauli contenant uniquement
IouZsur tous les qubits). N'oublie pas qu'il s'agit d'une approximation, car nous avons tronqué des termes de pendant sa propagation à travers la partie non-Clifford du Circuit.
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())
)
À mesure que nous lançons des calculs plus grands, les approximations de la valeur moyenne deviennent plus précises. Dans cet exemple, nous saturons l'espace de Pauli complet autour de , ce qui se reflète dans l'aplatissement de la courbe entre les deux derniers points.
Bien que le graphique ci-dessous montre une convergence monotone, les simulations de propagation de Pauli ne convergent généralement pas de façon monotone. Il n'est pas rare d'observer un comportement « irrégulier » dans ce type de graphiques.
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')

