Langkau ke kandungan utama
Projek ini dalam fasa beta. Jumpa pepijat? Buat isu GitHub. Ada soalan atau idea? Tanya dalam Discussions — kami suka dengar maklum balas anda!
Bagaimana kualiti terjemahan pada halaman ini?

Simulasikan sistem kuantum berhingar dengan perambatan Pauli

Dalam panduan ini kita menggunakan pakej pauli-prop untuk mensimulasikan secara klasik dinamik masa bagi model Ising medan melintang (TFIM) sembilan-qubit berhingar pada kekisi segi empat sama 3x3. Kita menggunakan arahan PauliLindbladError untuk mentakrifkan saluran hingar, Λ\Lambda, yang bertindak pada satu set lapisan berbelit, U\mathcal{U}. Kemudian kita merambatkan observable, OO, ke belakang melalui litar berhingar dan menganggarkan nilai jangkaan bagi pelbagai model hingar, serta kes tanpa hingar.

Noisy EV

Apabila observable dirambatkan ke belakang melalui litar, setiap saluran hingar, Λk\Lambda_k, yang dikaitkan dengan lapisan berbelit, Uk\mathcal{U}_k, meredam sebutan Pauli dalam OO yang anti-kalis tukar tertib dengan penjana Pauli-Lindblad-nya. Secara khusus, jika Gk,iG_{k,i} ialah penjana Pauli bagi Λk\Lambda_k dengan kadar, γk,i\gamma_{k,i}, maka sebutan Pauli, PP, dalam OO berubah sebagai: cP↦cPe−2γk,iif {P,Gk,i}=0c_P \mapsto c_P e^{-2\gamma_{k,i}} \quad \text{if } \{P, G_{k,i}\}=0, dengan cPc_P ialah pekali PP. Setelah OO dirambatkan ke permulaan litar, nilai jangkaan terhadap keadaan sifar, ∣0⟩⊗N|0\rangle^{\otimes N}, boleh dikira dengan mudah dengan menjumlahkan pekali setiap sebutan pepenjuru dalam OO (sebutan yang mengandungi ZZ atau II pada semua qubit).

Aliran kerja:

  • Tentukan kekisi TFIM, dan gunakan pewarnaan tepi untuk mengenal pasti set minimum lapisan berbelit
  • Hasilkan model hingar sintetik, Λk\Lambda_k, bagi setiap lapisan berbelit yang unik, UkU_k
    • Cipta model hingar pelbagai skala untuk mengkaji kesan hingar gate terhadap sistem
  • Cipta litar kuantum tanpa hingar dan berhingar untuk pelbagai kedalaman dan skala hingar yang diminati
    • Dalam litar berhingar, arahan PauliLindbladError dimasukkan sebelum setiap lapisan berbelit
  • Gunakan perambatan Pauli untuk mensimulasikan nilai jangkaan tepat sistem pada pelbagai kedalaman
    • Bagi sembilan qubit, ini dilakukan dengan membenarkan OO berkembang hingga 494^9 sebutan, meliputi ruang Pauli penuh
  • Gunakan perambatan Pauli untuk mensimulasikan nilai jangkaan berhingar
  • Perhatikan bagaimana peningkatan hingar gate menjejaskan ketepatan model kuantum

Hasilkan kekisi segi empat sama 3x3 dan cari pewarnaan-4 pada tepi​

Bucu dalam graf mewakili qubit, dan tepi mewakili sambungan antara dua qubit. Pewarnaan tepi sepadan dengan lapisan berbelit yang unik dalam litar kuantum supaya gate pada sambungan yang dikaitkan dengan warna berbeza tidak boleh dikenakan serentak.

Mengenal pasti set minimum lapisan berbelit yang unik selalunya penting untuk melaksanakan protokol pembelajaran hingar yang cekap, kerana hingar bagi setiap lapisan mesti dipelajari secara berasingan. Semakin banyak lapisan yang mesti kita pelajari, semakin banyak shot yang perlu kita ambil daripada QPU. Untuk demo ini, kita menggunakan maklumat lapisan untuk membina litar berhingar dan menyuntik arahan PauliLindbladError daripada qiskit-aer sebelum setiap lapisan berbelit untuk memodelkan hingar gate QPU.

# 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_addon_utils": "qiskit-addon-utils", "qiskit_aer": "qiskit-aer", "rustworkx": "rustworkx"}
_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")
from collections import defaultdict

import numpy as np
from qiskit.transpiler import CouplingMap
from qiskit_addon_utils.coloring import auto_color_edges

# Define rectangular square-lattice on 20 qubits
num_rows = 3
num_cols = 3
num_qubits = num_rows * num_cols

coupling_map = CouplingMap.from_grid(
num_rows=num_rows, num_columns=num_cols, bidirectional=False
)

# Create mapping from color to edge list
coloring = auto_color_edges(coupling_map.get_edges())
color_to_edge = defaultdict(list)
for edge, color in coloring.items():
color_to_edge[color].append(edge)
from rustworkx import PyDiGraph
from rustworkx.visualization import graphviz_draw

# Inspect graph coupling and unique entangling layers
print(
f"The circuit will have {num_qubits} qubits and {len(color_to_edge)} unique entangling layers."
)
sq_lattice = PyDiGraph()
sq_lattice.extend_from_weighted_edge_list(
[
(source, target, color)
for ((source, target), color) in coloring.items()
]
)

def color_edge_4color(edge):
color_dict = {0: "red", 1: "green", 2: "blue", 3: "orange"}
return {"color": color_dict[edge]}

graphviz_draw(sq_lattice, edge_attr_fn=color_edge_4color, method="neato")
The circuit will have 9 qubits and 4 unique entangling layers.

Output of the previous code cell

Hasilkan model hingar sintetik​

Sebelum mencipta litar kuantum, kita menghasilkan model hingar (contoh PauliLindbladError) bagi setiap lapisan berbelit. Kita akan membenamkannya sebagai arahan dalam litar kuantum kita kemudian. Bagi setiap lapisan, kita menghasilkan saluran hingar pelbagai skala. Secara khusus, kita menghasilkan model hingar dengan Error Per Layered Gate (EPLG) kira-kira .0004, .0008, .0012, .0016, dan .002.

from qiskit.quantum_info import SparsePauliOp, pauli_basis
from qiskit_aer.noise import PauliLindbladError

# Pauli-Lindblad noise parameters
seed = 1764
target_EPLGs = [0.0004, 0.0008, 0.0012, 0.0016, 0.002]

def generate_random_pauli_lindblad_noise(
edges,
num_qubits: int | None = None,
noise_scale: float = 1e-3,
seed: int | None = None,
) -> PauliLindbladError:
"""Generate random Pauli-Lindblad noise over the full Pauli basis."""
if num_qubits is None:
num_qubits = np.max(edges)

basis_paulis = [p for p in pauli_basis(2) if np.sum(p.x + p.z)]
basis_paulis = SparsePauliOp.from_sparse_list(
[
(pauli.to_label(), edge, 1)
for pauli in basis_paulis
for edge in edges
],
num_qubits=num_qubits,
)
basis_paulis = basis_paulis.simplify()
basis_paulis = basis_paulis.paulis

rng = np.random.default_rng(seed=seed)
rates = rng.random(len(basis_paulis)) * noise_scale

return PauliLindbladError(generators=basis_paulis, rates=rates)

num_generators = (
(num_rows * num_cols)
+ (num_rows - 1) * num_cols
+ num_rows * (num_cols - 1)
)
noise_scales = [
EPLG * (num_rows * num_cols) / num_generators for EPLG in target_EPLGs
]
noise_models_per_EPLG = [
[
generate_random_pauli_lindblad_noise(
color_to_edge[color],
num_qubits=num_qubits,
noise_scale=noise_scale,
seed=seed,
)
for color in range(len(color_to_edge))
]
for noise_scale in noise_scales
]

Cipta litar kuantum​

Untuk demo ini, kita mensimulasikan dinamik masa model Ising medan melintang (TFIM) bagi bilangan langkah Trotter yang meningkat (1-10 langkah). Bagi setiap 10 kedalaman litar, kita mensimulasikan kesan hingar gate, dengan model hingar pelbagai skala (EPLGs = .0004, .0008, .0012, .0016, .002). Hingar dimasukkan ke dalam QuantumCircuit sebagai arahan PauliLindbladError daripada Qiskit Aer. Hamiltonian yang dipertimbangkan ialah:

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

dengan J>0J>0 menerangkan gandingan spin jiran terdekat, i<ji<j, dan hh ialah medan melintang global.

Di sini kita melaksanakan Hamiltonian berevolusi masa merentasi pelbagai skala masa dan hingar. Kita mencipta 60 litar kesemuanya: 10 litar tanpa hingar yang berbeza dalam kedalaman Trotter, dan 50 litar berhingar untuk 10 kedalaman Trotter merentasi lima skala hingar. Diberi graf kesambungan, model ini diparameterkan oleh beberapa pemboleh ubah:

  • num_steps: Bilangan langkah Trotter
  • J: Kekuatan gandingan tapak yang bersambung
  • h: Kekuatan medan magnet luaran
  • dt: Perubahan masa merentasi satu langkah Trotter
  • initial_state_angle: Pengujaan awal, Ry(θ)R_y(\theta), yang dikenakan secara seragam pada semua qubit
from typing import Any

from qiskit import QuantumCircuit

# Ising model parameters
num_steps = 10
J = -1.0
dt = 0.25 / abs(J)
h = 2.0 * abs(J)
initial_state_angle = np.pi / 18.0
rx_angle = 2.0 * h * dt
rzz_angle = 2.0 * J * dt

def generate_ising_circuit(
num_qubits: int,
num_steps: int,
rx_angle: float,
rzz_angle: float,
coloring: dict[Any, list[tuple[int, int]]],
layer_noise_models: list[PauliLindbladError] | None = None,
initial_state_angle: float | None = None,
) -> QuantumCircuit:
"""Generate a quantum circuit implementing a transverse-field Ising model"""
qc = QuantumCircuit(num_qubits)
if initial_state_angle:
qc.ry(initial_state_angle, range(num_qubits))
qc.rx(rx_angle / 2, range(num_qubits))
for i in range(num_steps):
for j, layer in enumerate(coloring):
edges = coloring[layer]
if layer_noise_models:
qc.append(layer_noise_models[j], qargs=range(num_qubits))
for edge in edges:
qc.rzz(rzz_angle, *edge)
if i == num_steps - 1:
qc.rx(rx_angle / 2, range(num_qubits))
else:
qc.rx(rx_angle, range(num_qubits))
return qc

# Create the noiseless and noisy circuits
noiseless_circs = []
noisy_circs = []
for steps in range(1, num_steps + 1):
noiseless_circs.append(
generate_ising_circuit(
num_qubits,
steps,
rx_angle,
rzz_angle,
color_to_edge,
initial_state_angle=initial_state_angle,
)
)
noisy_circs_per_step = []
for noise_models in noise_models_per_EPLG:
noisy_circs_per_step.append(
generate_ising_circuit(
num_qubits,
steps,
rx_angle,
rzz_angle,
color_to_edge,
layer_noise_models=noise_models,
initial_state_angle=initial_state_angle,
)
)
noisy_circs.append(noisy_circs_per_step)
print(
f"{num_steps} noiseless and {num_steps * len(target_EPLGs)} noisy Trotter circuits generated. {num_steps} different depths across {len(target_EPLGs)} different noise models"
)
print("\nBelow: Initial state and one noisy Trotter step.")
noisy_circs[0][0].draw("mpl", fold=-1)
10 noiseless and 50 noisy Trotter circuits generated. 10 different depths across 5 different noise models

Below: Initial state and one noisy Trotter step.

Output of the previous code cell

Tentukan observable dan jalankan simulasi​

Untuk demo ini, kita mensimulasikan nilai jangkaan bagi korelator dua-tapak purata:

⟨O⟩=⟨Ztot2(s)⟩=1N2∑⟨Ψ(θ)∣(U†)sZjZk(U)s∣Ψ(θ)⟩\langle O \rangle = \langle Z_{tot}^2(s) \rangle = \frac{1}{N^2}\sum \langle \Psi(\theta)|(\mathscr{U}^{\dagger})^sZ_jZ_k(\mathscr{U})^s|\Psi(\theta) \rangle

dengan Ψ(θ)\Psi(\theta) sepadan dengan putaran Ry(θ)R_y(\theta) seragam pada semua qubit, Us\mathscr{U}^s menerangkan ss lapisan Trotter, dan (j,k)(j,k) mengindeks semua pasangan bucu yang bersambung pada kekisi.

Akhir sekali, kita menggunakan pauli_prop untuk mensimulasikan nilai jangkaan observable bagi setiap litar. Untuk demo sembilan-qubit ini, kita melakukan semua simulasi secara tepat. Tiada pemangkasan perambatan Pauli akan dilakukan; oleh itu, perbezaan nilai jangkaan merentasi model hingar yang berbeza boleh dikaitkan sepenuhnya dengan ralat gate. Proses simulasi dikendalikan dalam empat langkah:

  • Evolusikan gate Clifford dalam litar ke hadapan litar menggunakan pauli_prop.evolve_through_cliffords
  • Rambatkan observable melalui bahagian bukan Clifford litar menggunakan pauli_prop.propagate_through_circuit
    • Kita melakukan simulasi tepat dengan membenarkan observable berkembang hingga saiz ruang Pauli penuh, 494^9
  • Rambatkan observable yang telah berevolusi melalui bahagian Clifford litar menggunakan SparsePauliOp.evolve Qiskit
  • Anggarkan nilai jangkaan terhadap keadaan sifar, ∣0⟩⊗N|0\rangle^{\otimes N}, dengan menjumlahkan pekali setiap sebutan pepenjuru dalam OO (sebutan yang mengandungi ZZ atau II pada semua qubit)
import time

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

# Average ZZ-correlator observable
id_pauli = Pauli("I" * num_qubits)
observable = 2 * SparsePauliOp(
[
id_pauli.dot(Pauli("ZZ"), [i, j])
for i in range(num_qubits)
for j in range(i + 1, num_qubits)
]
)
observable /= num_qubits**2

# Pauli propagation parameters
max_terms = 4**num_qubits # Exact propagation
atol = 1e-12

# Run simulations
exact_evs = []
noisy_evs = [[] for _ in range(len(target_EPLGs))]
st = time.perf_counter()
for i, noiseless_circ in enumerate(noiseless_circs):
cliff, non_cliff = evolve_through_cliffords(noiseless_circ)
evolved_obs = propagate_through_circuit(
observable, non_cliff, max_terms=max_terms, atol=atol, frame="h"
)[0]
evolved_obs.paulis = evolved_obs.paulis.evolve(cliff, frame="h")
exact_evs.append(
float(evolved_obs.coeffs[~evolved_obs.paulis.x.any(axis=1)].sum())
)
for j in range(len(target_EPLGs)):
noisy_circ = noisy_circs[i][j]
cliff, non_cliff = evolve_through_cliffords(noisy_circ)
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")
noisy_evs[j].append(
float(evolved_obs.coeffs[~evolved_obs.paulis.x.any(axis=1)].sum())
)
print(
f"Ran {len(noiseless_circs)} noiseless and {len(target_EPLGs) * num_steps} noisy simulations in {int(time.perf_counter() - st)}s."
)
Ran 10 noiseless and 50 noisy simulations in 103s.

Perhatikan kesan ralat gate terhadap model​

Ingat bahawa, memandangkan ini ialah eksperimen sembilan-qubit, rutin perambatan Pauli adalah tepat, dan semua ralat dalam plot hingar boleh dikaitkan dengan ralat gate.

import matplotlib.pyplot as plt

xs = range(1, num_steps + 1)
plt.plot(xs, exact_evs, label="Noiseless", color="black", marker="o")
colors = [".3", ".4", ".5", ".6", ".7"]
for i, evs in enumerate(noisy_evs):
plt.plot(
xs,
evs,
label=f"{target_EPLGs[i]} EPLG",
linestyle="--",
color=colors[i],
marker="o",
)
plt.xlabel("# Trotter steps")
plt.ylabel(r"$\langle Z_{tot}^2 \rangle$")
plt.legend()
plt.show()

Output of the previous code cell