Vai al contenuto principale
Questo progetto è in fase beta. Hai trovato un bug? Apri una issue su GitHub. Hai una domanda o un'idea? Chiedi su GitHub Discussions — apprezziamo il tuo feedback!
Com'è la qualità della traduzione su questa pagina?

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 è:

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

dove J>0J>0 descrive l'accoppiamento tra spin primi vicini, i<ji<j, e hh è il campo trasverso globale. Una decomposizione di Trotter del primo ordine dell'operatore evoluto nel tempo verrà implementata come circuito quantistico, UU, su 2020 passi di Trotter. La costante di accoppiamento, JJ, sarà fissata a J=−π2J=-\frac{\pi}{2}, e hh sarà fissato a π6\frac{\pi}{6}. Le interazioni ZZZZ verranno implementate usando gate di Clifford (CXCX, SdgSdg, Y\sqrt{Y}).

Implementiamo l'evoluzione temporale trotterizzata come circuito quantistico e usiamo π6\frac{\pi}{6} per le rotazioni non Clifford attorno all'asse x. Più questi angoli sono lontani dagli angoli di Clifford (per esempio θ=nπ2,n∈Z\theta=n\frac{\pi}{2}, n \in \mathbb{Z}), più sarà difficile simulare il sistema con i metodi di propagazione di Pauli.

Come osservabile consideriamo la magnetizzazione media del singolo sito, 1N∑i=1N⟨zi⟩\frac{1}{N} \sum_{i=1}^{N} \langle z_i \rangle, dove NN è 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)

Output of the previous code cell

Simula l'evoluzione temporale del sistema con la propagazione di Pauli​

Una volta ottenuti il circuito, UU, e l'osservabile, OO, possiamo simulare facilmente il sistema in pochi passaggi:

  • Separa UU nella sua parte di Clifford, CC, e nella sua parte non Clifford, PP, in modo che U=PCU=PC, usando evolve_through_cliffords

  • Propaga OO attraverso PP, ottenendo un nuovo operatore, O′O^\prime, usando pauli_prop.propagate_through_circuit

  • Fai evolvere O′O^\prime attraverso la parte di Clifford del circuito usando il supporto per l'evoluzione di Clifford integrato in Qiskit

  • Approssima il valore di aspettazione come ⟨0∣O′∣0⟩≈⟨0∣U†OU∣0⟩\langle0|O^\prime|0\rangle \approx \langle0|U^\dagger OU|0\rangle sommando i coefficienti in O′O^\prime associati ai termini di Pauli completamente diagonali (termini di Pauli contenenti solo I o Z su tutti i qubit). Ricorda che si tratta di un'approssimazione perché abbiamo troncato dei termini da O′O^\prime 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 410≈1064^{10}\approx10^6, 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')

Output of the previous code cell