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?

Simula un modello di Ising kicked a 127 qubit

In questa guida usiamo il pacchetto pauli-prop per simulare classicamente la dinamica temporale di un modello di Ising kicked a 127 qubit su un reticolo heavy-hex e approssimare la magnetizzazione del singolo sito, ⟨Z62⟩\langle Z_{62} \rangle. 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} in modo che UU sia di Clifford ogni volta che hmod  π2=0h\mod\frac{\pi}{2}=0.

Flusso di lavoro:

  • Crea circuiti quantistici che implementano il modello di Ising trotterizzato

    • Fai variare hh tra i punti di Clifford, 0.00.0 e π2\frac{\pi}{2}
  • Scegli un sito al centro del reticolo (qubit 6262) e stima la magnetizzazione dopo 2020 passi di Trotter per ciascun circuito

  • Osserva la magnetizzazione scendere da 1.01.0 a 0.00.0 mentre hh passa da un punto di Clifford all'altro

Crea i circuiti​

Per prima cosa usiamo FakeSherbrooke da qiskit-ibm-runtime per ottenere gli indici degli archi della mappa di accoppiamento della QPU Eagle a 127 qubit. Una volta ottenuti gli indici degli archi, creiamo i circuiti di Trotter per i diversi valori di hh che vogliamo simulare. I circuiti implementeranno una trotterizzazione del primo ordine dell'Hamiltoniana usando 20 passi di Trotter e 5420 gate.

# 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_ibm_runtime": "qiskit-ibm-runtime"}
_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_ibm_runtime.fake_provider import FakeSherbrooke

# Get the edges in the device coupling map
backend = FakeSherbrooke()
edges = backend.coupling_map.get_edges()

# Num Trotter steps
num_steps = 20

# Create Trotter circuits with varying global fields
hs = [i * np.pi / 32 for i in range(17)]
circuits = []
for h in hs:
circuit = QuantumCircuit(backend.num_qubits)
for _ in range(num_steps):
circuit.rx(h, [i for i in range(backend.num_qubits)])
for edge in edges:
circuit.rzz(-np.pi / 2, edge[0], edge[1])
circuits.append(circuit)

Simula la dinamica temporale con la propagazione di Pauli​

Successivamente specifichiamo l'osservabile, OO, che vogliamo misurare. In questo caso stimiamo ⟨Z62⟩\langle Z_{62} \rangle.

Per studiare la magnetizzazione tra i punti di Clifford, propaghiamo approssimativamente OO all'inizio del circuito, UU, ottenendo una nuova osservabile, O′≈U†OUO^\prime \approx U^{\dagger}OU.

Durante la propagazione, il numero di termini dell'osservabile evoluta cresce esponenzialmente nel numero di gate, quindi di solito è necessario limitare quanto può crescere. Qui limitiamo il numero di termini in O′O^\prime a 10510^5 e tronchiamo i termini con coefficienti più piccoli di 10−510^{-5}. Il troncamento dei termini introduce un certo errore. Una volta ottenuto O′O^\prime, possiamo stimare facilmente il valore di aspettazione, ⟨0∣U†OU∣0⟩=⟨0∣O′∣0⟩\langle0|U^{\dagger}OU|0\rangle = \langle0|O^\prime|0\rangle, sommando i coefficienti dei termini diagonali in O′O^\prime (termini costituiti solo da I o Z su tutti i qubit).

Impostiamo frame='h' per specificare che vogliamo far evolvere l'osservabile nel quadro di Heisenberg (U†OUU^{\dagger}OU). Usa frame=s per l'evoluzione di Schrödinger (UOU†UOU^{\dagger}).

import time

from pauli_prop import propagate_through_circuit
from qiskit.quantum_info import Pauli, SparsePauliOp

# Z_62 observable
id_pauli = Pauli("I" * backend.num_qubits)
observable = SparsePauliOp(id_pauli.dot(Pauli("Z"), [62]))

# Estimate the single-site magnetization for varying magnetic fields
times = []
approx_evs = []
for circuit in circuits:
st = time.perf_counter()
propagated_obs = propagate_through_circuit(
observable, circuit, 100_000, 1e-5, frame="h"
)[0]
times.append(time.perf_counter() - st)
approx_evs.append(
float(
propagated_obs.coeffs[~propagated_obs.paulis.x.any(axis=1)].sum()
)
)
print(f"Finished {len(circuits)} simulations in {sum(times):.0f}s")
Finished 17 simulations in 494s

Visualizza​

Infine, tracciamo il grafico della magnetizzazione in funzione di hh. Quando h=0h=0, il circuito non influisce sullo stato iniziale nella base computazionale, e sappiamo che ⟨0∣O∣0⟩=1.0\langle0|O|0\rangle = 1.0. Man mano che hh si allontana da 00, la magnetizzazione decade in modo monotono finché hh raggiunge il successivo angolo di Clifford, π2\frac{\pi}{2}, e la magnetizzazione converge a 00.

import matplotlib.pyplot as plt

plt.xlabel(r"$R_x$ angle $\theta_h$")
plt.ylabel(r"$\langle Z_{62} \rangle$")
plt.plot(hs, approx_evs, marker="o")
[<matplotlib.lines.Line2D at 0x123f68b00>]

Output of the previous code cell