Aller au contenu principal
Ce projet est en phase bêta. Tu as trouvé un bug ? Ouvrir un ticket GitHub. Une question ou une idée ? Pose ta question dans Discussions — tes retours sont les bienvenus !
Quelle est la qualité de la traduction sur cette page ?

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 :

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

où J>0J>0 décrit le couplage des spins plus proches voisins, i<ji<j, et hh 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, UU, sur 2020 pas de Trotter. La constante de couplage, JJ, sera fixée à J=−π2J=-\frac{\pi}{2}, et hh sera fixé à π6\frac{\pi}{6}. Les interactions ZZZZ seront implémentées avec des portes de Clifford (CXCX, SdgSdg, Y\sqrt{Y}).

Nous implémentons l'évolution temporelle trotterisée sous forme de Circuit quantique et utilisons π6\frac{\pi}{6} pour les rotations non-Clifford autour de l'axe x. Plus ces angles sont éloignés des angles de Clifford (par exemple, θ=nπ2,n∈Z\theta=n\frac{\pi}{2}, n \in \mathbb{Z}), 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, 1N∑i=1N⟨zi⟩\frac{1}{N} \sum_{i=1}^{N} \langle z_i \rangle, où NN 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)

Output of the previous code cell

Simuler l'évolution temporelle du système avec la propagation de Pauli​

Une fois que nous avons notre Circuit, UU, et notre observable, OO, nous pouvons facilement simuler le système en quelques étapes :

  • Séparer UU en sa partie de Clifford, CC, et sa partie non-Clifford, PP, de sorte que U=PCU=PC, avec evolve_through_cliffords

  • Propager OO à travers PP, ce qui donne un nouvel opérateur, O′O^\prime, avec pauli_prop.propagate_through_circuit

  • Faire évoluer O′O^\prime à 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 ⟨0∣O′∣0⟩≈⟨0∣U†OU∣0⟩\langle0|O^\prime|0\rangle \approx \langle0|U^\dagger OU|0\rangle en sommant les coefficients de O′O^\prime associés aux termes de Pauli entièrement diagonaux (termes de Pauli contenant uniquement I ou Z sur tous les qubits). N'oublie pas qu'il s'agit d'une approximation, car nous avons tronqué des termes de O′O^\prime 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 410≈1064^{10}\approx10^6, 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')

Output of the previous code cell