Saltar al contenido principal
Este proyecto está en fase beta. ¿Encontraste un error? Abre un issue en GitHub. ¿Tienes una pregunta o una idea? Pregunta en Discussions — ¡nos encantaría tu opinión!
¿Cómo es la calidad de la traducción en esta página?

Simula un modelo de Ising con pulsos de 127 qubits

En esta guía usamos el paquete pauli-prop para simular de forma clásica la dinámica temporal de un modelo de Ising con pulsos de 127 qubits en una red heavy-hex y aproximar la magnetización de un solo sitio, ⟨Z62⟩\langle Z_{62} \rangle. El hamiltoniano considerado es:

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

donde J>0J>0 describe el acoplamiento de espines vecinos más cercanos, i<ji<j, y hh es el campo transversal global. Se implementará una descomposición de Trotter de primer orden del operador evolucionado en el tiempo como un circuito cuántico, UU, a lo largo de 2020 pasos de Trotter. La constante de acoplamiento, JJ, se fijará en J=−π2J=-\frac{\pi}{2} de modo que UU sea Clifford siempre que hmod  π2=0h\mod\frac{\pi}{2}=0.

Flujo de trabajo:

  • Crear circuitos cuánticos que implementen el modelo de Ising de Trotter

    • Variar hh entre los puntos Clifford, 0.00.0 y π2\frac{\pi}{2}
  • Elegir un sitio en el centro de la red (qubit 6262) y estimar la magnetización tras 2020 pasos de Trotter para cada circuito

  • Observar cómo la magnetización decae de 1.01.0 a 0.00.0 cuando hh pasa de un punto Clifford a otro

Crea los circuitos​

Primero, usamos FakeSherbrooke de qiskit-ibm-runtime para obtener los índices de las aristas del mapa de acoplamiento de la QPU Eagle de 127 qubits. Una vez que tenemos los índices de las aristas, creamos los circuitos de Trotter para los distintos valores de hh que queremos simular. Los circuitos implementarán una trotterización de primer orden del hamiltoniano usando 20 pasos de Trotter y 5420 puertas.

# 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 dinámica temporal con propagación de Pauli​

A continuación, especificamos el observable, OO, que queremos medir. En este caso, estimamos ⟨Z62⟩\langle Z_{62} \rangle.

Para estudiar la magnetización entre puntos Clifford, propagamos de forma aproximada OO hasta el inicio del circuito, UU, obteniendo un nuevo observable, O′≈U†OUO^\prime \approx U^{\dagger}OU.

Durante la propagación, el número de términos del observable evolucionado crece exponencialmente con el número de puertas, por lo que normalmente es necesario limitar cuánto puede crecer. Aquí limitamos el número de términos de O′O^\prime a 10510^5 y truncamos los términos con coeficientes menores que 10−510^{-5}. Truncar términos introduce cierto error. Una vez que tenemos O′O^\prime, podemos estimar fácilmente el valor esperado, ⟨0∣U†OU∣0⟩=⟨0∣O′∣0⟩\langle0|U^{\dagger}OU|0\rangle = \langle0|O^\prime|0\rangle, sumando los coeficientes de los términos diagonales de O′O^\prime (términos formados únicamente por I o Z en todos los qubits).

Establecemos frame='h' para indicar que queremos evolucionar el observable en el marco de Heisenberg (U†OUU^{\dagger}OU). Usa frame=s para la evolución de 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

Visualiza​

Por último, graficamos la magnetización en función de hh. Cuando h=0h=0, el circuito no afecta al estado inicial en la base computacional, y sabemos que ⟨0∣O∣0⟩=1.0\langle0|O|0\rangle = 1.0. A medida que hh se aleja de 00, la magnetización decae de forma monótona hasta que hh alcanza el siguiente ángulo Clifford, π2\frac{\pi}{2}, y la magnetización 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