Lumaktaw sa pangunahing nilalaman
Ang proyektong ito ay nasa beta. Nakakita ng bug? Mag-bukas ng GitHub issue. May tanong o ideya? Magtanong sa Discussions — gusto naming marinig ang iyong feedback!
Gaano kaganda ang kalidad ng pagsasalin sa pahinang ito?

I-simulate ang mga noisy na quantum system gamit ang Pauli propagation

Sa gabay na ito, gagamitin natin ang pauli-prop package para i-simulate nang classical ang time dynamics ng isang noisy na nine-qubit na transverse-field Ising model (TFIM) sa 3x3 square lattice. Gumagamit tayo ng mga instruction na PauliLindbladError para tukuyin ang isang noise channel, Λ\Lambda, na kumikilos sa isang set ng mga entangling layer, U\mathcal{U}. Pagkatapos, ipo-propagate natin ang observable, OO, pabalik sa noisy na circuit at tatantiyahin ang mga expectation value para sa iba't ibang noise model, pati na rin sa noiseless na kaso.

Noisy EV

Habang pina-propagate pabalik ang observable sa circuit, ang bawat noise channel, Λk\Lambda_k, na nauugnay sa entangling layer, Uk\mathcal{U}_k, ay nagpapahina sa mga Pauli term sa OO na nag-a-anti-commute sa mga Pauli-Lindblad generator nito. Partikular, kung ang Gk,iG_{k,i} ay isang Pauli generator ng Λk\Lambda_k na may rate, γk,i\gamma_{k,i}, ang isang Pauli term, PP, sa OO ay nagbabago bilang: 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, kung saan ang cPc_P ay ang coefficient ng PP. Kapag na-propagate na ang OO sa simula ng circuit, ang expectation value kaugnay ng zero state, ∣0⟩⊗N|0\rangle^{\otimes N}, ay madaling makalkula sa pamamagitan ng pagsasama-sama ng mga coefficient ng bawat diagonal na term sa OO (mga term na naglalaman ng ZZ o II sa lahat ng qubit).

Workflow:

  • Tukuyin ang TFIM lattice, at gumamit ng edge coloring para tukuyin ang pinakamaliit na set ng mga entangling layer
  • Gumawa ng mga synthetic na noise model, Λk\Lambda_k, para sa bawat natatanging entangling layer, UkU_k
    • Gumawa ng mga noise model na may iba't ibang scale para pag-aralan ang epekto ng gate noise sa sistema
  • Gumawa ng mga noiseless at noisy na quantum circuit para sa iba't ibang depth at noise scale na pinag-aaralan
    • Sa mga noisy na circuit, ipinapasok ang mga instruction na PauliLindbladError bago ang bawat entangling layer
  • Gumamit ng Pauli propagation para i-simulate ang mga eksaktong expectation value ng sistema sa iba't ibang depth
    • Para sa siyam na qubit, ginagawa ito sa pamamagitan ng pagpapalaki sa OO hanggang 494^9 na term, na sumasaklaw sa buong Pauli space
  • Gumamit ng Pauli propagation para i-simulate ang mga noisy na expectation value
  • Obserbahan kung paano sinisira ng pagtaas ng gate noise ang katumpakan ng quantum model

Gumawa ng 3x3 square lattice at maghanap ng 4-coloring sa mga edge​

Ang mga vertex sa graph ay kumakatawan sa mga qubit, at ang mga edge ay kumakatawan sa koneksyon sa pagitan ng dalawang qubit. Ang edge coloring ay tumutugma sa mga natatanging entangling layer sa quantum circuit kung saan ang mga gate sa mga koneksyong may magkakaibang kulay ay hindi maaaring ilapat nang sabay.

Madalas na mahalaga ang pagtukoy ng pinakamaliit na set ng mga natatanging entangling layer para sa pagpapatupad ng mga episyenteng noise-learning protocol, dahil kailangang matutunan nang hiwalay ang noise ng bawat layer. Habang dumarami ang mga layer na kailangan nating matutunan, dumarami rin ang mga shot na kailangan nating kunin mula sa QPU. Para sa demo na ito, ginagamit natin ang impormasyon ng layer para bumuo ng mga noisy na circuit at magpasok ng mga instruction na PauliLindbladError mula sa qiskit-aer bago ang bawat entangling layer para imodelo ang gate noise ng 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

Gumawa ng mga synthetic na noise model​

Bago gumawa ng mga quantum circuit, gagawa tayo ng noise model (instance ng PauliLindbladError) para sa bawat entangling layer. Isasama natin ang mga ito bilang mga instruction sa ating mga quantum circuit mamaya. Para sa bawat layer, gagawa tayo ng mga noise channel na may iba't ibang scale. Partikular, gagawa tayo ng mga noise model na may Error Per Layered Gate (EPLG) na humigit-kumulang .0004, .0008, .0012, .0016, at .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
]

Gawin ang mga quantum circuit​

Para sa demo na ito, sini-simulate natin ang time dynamics ng isang transverse-field Ising model (TFIM) para sa dumaraming bilang ng mga Trotter step (1-10 step). Para sa bawat isa sa 10 circuit depth, sini-simulate natin ang epekto ng gate noise, gamit ang mga noise model na may iba't ibang scale (EPLGs = .0004, .0008, .0012, .0016, .002). Ipinapasok ang noise sa QuantumCircuit bilang instruction na PauliLindbladError mula sa Qiskit Aer. Ang Hamiltonian na isinasaalang-alang ay:

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

kung saan ang J>0J>0 ay naglalarawan ng coupling ng mga magkatabing spin, i<ji<j, at ang hh ay ang global na transverse field.

Dito, ipinapatupad natin ang time-evolved na Hamiltonian sa iba't ibang time at noise scale. Gumagawa tayo ng 60 kabuuang circuit: 10 noiseless na circuit na magkakaiba ang Trotter depth, at 50 noisy na circuit para sa 10 Trotter depth sa limang noise scale. Dahil sa isang connectivity graph, ang model ay pina-parametrize ng ilang variable:

  • num_steps: Ang bilang ng mga Trotter step
  • J: Lakas ng coupling ng mga konektadong site
  • h: Lakas ng external na magnetic field
  • dt: Pagbabago ng oras sa bawat Trotter step
  • initial_state_angle: Isang initial na excitation, Ry(θ)R_y(\theta), na ilalapat nang pantay sa lahat ng 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

Tukuyin ang observable at patakbuhin ang mga simulation​

Para sa demo na ito, sini-simulate natin ang mga expectation value ng average na two-site correlator:

⟨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

kung saan ang Ψ(θ)\Psi(\theta) ay tumutugma sa uniform na Ry(θ)R_y(\theta) rotation sa lahat ng qubit, ang Us\mathscr{U}^s ay naglalarawan ng ss Trotter layer, at ang (j,k)(j,k) ay nag-i-index sa lahat ng konektadong pares ng vertex sa lattice.

Panghuli, gagamitin natin ang pauli_prop para i-simulate ang mga expectation value ng observable para sa bawat circuit. Para sa nine-qubit na demo na ito, ginagawa natin ang lahat ng simulation nang eksakto. Walang gagawing Pauli propagation truncation; kaya, ang mga pagkakaiba sa mga expectation value sa iba't ibang noise model ay buong maiuugnay sa gate error. Ang proseso ng simulation ay hinahawakan sa apat na hakbang:

  • I-evolve ang mga Clifford gate sa circuit papunta sa harap ng circuit gamit ang pauli_prop.evolve_through_cliffords
  • I-propagate ang observable sa non-Clifford na bahagi ng circuit gamit ang pauli_prop.propagate_through_circuit
    • Gumagawa tayo ng mga eksaktong simulation sa pamamagitan ng pagpapalaki sa observable hanggang sa laki ng buong Pauli space, 494^9
  • I-propagate ang evolved na observable sa Clifford na bahagi ng circuit gamit ang SparsePauliOp.evolve ng Qiskit
  • Tantiyahin ang expectation value kaugnay ng zero state, ∣0⟩⊗N|0\rangle^{\otimes N}, sa pamamagitan ng pagsasama-sama ng mga coefficient ng bawat diagonal na term sa OO (mga term na naglalaman ng ZZ o II sa lahat ng 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.

Obserbahan ang epekto ng gate error sa model​

Tandaan na, dahil nine-qubit na eksperimento ito, eksakto ang Pauli propagation routine, at ang lahat ng error sa mga noise plot ay maiuugnay sa gate error.

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