Guida rapida
title: Guida rapida description: Una guida rapida al pacchetto pauli-prop dei Qiskit addons
In questa guida usiamo il pacchetto pauli-prop per simulare classicamente la dinamica temporale di un modello di Ising kicked a 10 qubit su una catena di spin 1D.
Prepara gli input per la propagazione di Pauli
L'Hamiltoniana considerata è:
dove descrive l'accoppiamento tra spin primi vicini, , e è il campo trasverso globale. Una decomposizione di Trotter del primo ordine dell'operatore evoluto nel tempo verrà implementata come circuito quantistico, , su passi di Trotter. La costante di accoppiamento, , sarà fissata a , e sarà fissato a . Le interazioni verranno implementate usando gate di Clifford (, , ).
Implementiamo l'evoluzione temporale trotterizzata come circuito quantistico e usiamo per le rotazioni non Clifford attorno all'asse x. Più questi angoli sono lontani dagli angoli di Clifford (per esempio ), più sarà difficile simulare il sistema con i metodi di propagazione di Pauli.
Come osservabile consideriamo la magnetizzazione media del singolo sito, , dove è il numero di spin.
# 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)
Simula l'evoluzione temporale del sistema con la propagazione di Pauli
Una volta ottenuti il circuito, , e l'osservabile, , possiamo simulare facilmente il sistema in pochi passaggi:
-
Separa nella sua parte di Clifford, , e nella sua parte non Clifford, , in modo che , usando
evolve_through_cliffords -
Propaga attraverso , ottenendo un nuovo operatore, , usando
pauli_prop.propagate_through_circuit -
Fai evolvere attraverso la parte di Clifford del circuito usando il supporto per l'evoluzione di Clifford integrato in Qiskit
-
Approssima il valore di aspettazione come sommando i coefficienti in associati ai termini di Pauli completamente diagonali (termini di Pauli contenenti solo
IoZsu tutti i qubit). Ricorda che si tratta di un'approssimazione perché abbiamo troncato dei termini da durante la propagazione attraverso la parte non Clifford del circuito.
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())
)
Man mano che eseguiamo calcoli più grandi, le approssimazioni del valore di aspettazione diventano più accurate. In questo esempio saturiamo l'intero spazio di Pauli attorno a , come si vede dalla curva che si appiattisce tra gli ultimi due punti.
Sebbene il grafico seguente mostri una convergenza monotona, le simulazioni con propagazione di Pauli in generale non convergono in modo monotono. Non è insolito vedere un comportamento "irregolare" in questo tipo di grafici.
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')

