Skip to main content
IBM Quantum Platform

Iniciação rápida

qiskit-addon-pna Este guia apresenta um exemplo mínimo funcional do pacote. Utilizamos a absorção de ruído propagada (PNA) para construir um observável de mitigação de ruído. Dado um circuito e um modelo de ruído de Pauli-Lindblad, a PNA propaga, de forma clássica, a observável através do canal de ruído inverso. A medição da grandeza observável resultante na QPU com ruído atenua o ruído das portas aprendidas.

Para saber como criar um fluxo de trabalho realista e executá-lo em hardware quântico com o modelo de execução direcionada, incluindo o aprendizado do modelo de ruído com NoiseLearnerV3, confira o tutorial do PNA no site IBM Quantum Platform.


1. Preparar os dados de entrada para o PNA

O PNA recebe como entrada um circuito, um modelo de ruído e uma variável observável. Aqui, construímos um modelo de Ising de campo transversal com Trotterização de 10 qubits em uma cadeia de 1D. Geramos um modelo aleatório de ruído de Pauli-Lindblad de 2 locais para cada porta de entrelaçamento e o incorporamos como uma instrução do Qiskit Aer PauliLindbladError imediatamente antes dessa porta. Escolhemos um observável de Pauli-Z weight-4 para medir.

import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp, pauli_basis
from qiskit_aer.noise import PauliLindbladError


def random_pauli_lindblad_noise(generators, seed, noise_scale=2e-3):
    rates = np.random.default_rng(seed).random(len(generators)) * noise_scale
    return PauliLindbladError(generators, rates)


def ising_circuit(
    num_qubits,
    layers,
    edge_noise=None,
    *,
    num_steps=3,
    rx_angle=np.pi / 8,
    rzz_angle=-np.pi / 2,
):
    """Trotterized transverse-field Ising model; edge_noise=None gives the noiseless circuit."""
    qc = QuantumCircuit(num_qubits)
    for _ in range(num_steps):
        qc.rx(rx_angle, range(num_qubits))
        for layer in layers:
            for edge in layer:
                if edge_noise is not None:
                    qc.append(
                        edge_noise[edge], edge
                    )  # inject synthetic gate noise
                qc.rzz(rzz_angle, *edge)
    return qc


num_qubits = 10

# Two entangling layers per Trotter step: even and odd bonds of a 1D chain
layers = [
    [(i, i + 1) for i in range(0, num_qubits - 1, 2)],
    [(i, i + 1) for i in range(1, num_qubits - 1, 2)],
]
edges = [edge for layer in layers for edge in layer]

# Random 2-local Pauli-Lindblad noise, one instance per entangling gate
two_qubit_paulis = SparsePauliOp(
    [p for p in pauli_basis(2) if np.sum(p.x + p.z)]
).paulis
edge_noise = {
    edge: random_pauli_lindblad_noise(two_qubit_paulis, seed=1234 + j)
    for j, edge in enumerate(edges)
}

noisy_circuit = ising_circuit(num_qubits, layers, edge_noise)

# A single weight-4 observable: <Z3 Z4 Z5 Z6>
observable = SparsePauliOp.from_sparse_list(
    [("ZZZZ", [3, 4, 5, 6], 1.0)], num_qubits=num_qubits
)

noisy_circuit.draw("mpl", fold=-1, scale=0.6)

Output:

Output of the previous code cell

2. Gerar o observável de mitigação de ruído

O generate_noise_mitigating_observable propaga cada gerador de Pauli do canal de ruído inverso até o final do circuito. A observável é então submetida à retropropagação pelo canal de ruído inverso, retornando uma nova observável O~\tilde{O}. Três parâmetros principais afetam o custo computacional:

  • max_err_terms: o número de termos mantidos em cada gerador antirruído à medida que ele é propagado para a frente.
  • max_obs_terms: o número de termos armazenados em O~\tilde{O}.
  • atol: os termos cuja magnitude do coeficiente for inferior a esse limite são descartados.

Para esse pequeno circuito próximo de Clifford, definimos limites altos para os termos e usamos um valor modesto atolde, de modo que O~\tilde{O} permaneça pequeno e possamos medir todos os seus termos.

Observação: Esta função utiliza Python multiprocessing. Ao executá-lo como um script, chame-o dentro de um if __name__ == "__main__": guard.

from qiskit_addon_pna import generate_noise_mitigating_observable

mitigating_observable = generate_noise_mitigating_observable(
    noisy_circuit,
    observable,
    max_err_terms=100_000,
    max_obs_terms=100_000,
    atol=1e-5,
    num_processes=4,
)

print(f"Original observable:         {len(observable)} term")
print(f"Noise-mitigating observable: {len(mitigating_observable)} terms")

Output:

Original observable:         1 term
Noise-mitigating observable: 207 terms

3. Mitigar erros de porta medindo o observável de mitigação de ruído

Aqui vemos que o novo observável atenua efetivamente o ruído do gate que afeta o experimento.

import matplotlib.pyplot as plt
from qiskit_aer.primitives import EstimatorV2

noiseless_circuit = ising_circuit(num_qubits, layers)

# density_matrix method at zero precision -> exact expectation values (no shot noise)
estimator = EstimatorV2(
    options={
        "backend_options": {"method": "density_matrix"},
        "default_precision": 0.0,
    }
)

ideal, noisy, mitigated = (
    result.data.evs
    for result in estimator.run(
        [
            (noiseless_circuit, observable),
            (noisy_circuit, observable),
            (noisy_circuit, mitigating_observable),
        ]
    ).result()
)

print(f"Ideal (noiseless):   {ideal:.4f}")
print(f"Noisy (unmitigated): {noisy:.4f}")
print(f"Mitigated (PNA):     {mitigated:.4f}")

fig, ax = plt.subplots()
ax.bar(
    ["Noisy", "Mitigated"],
    [noisy, mitigated],
    width=0.6,
    color=["#b0b0b0", "#4c4c4c"],
)
ax.axhline(ideal, color="green", linestyle="--", label="Ideal (noiseless)")
ax.set_ylabel(r"$\langle Z_3 Z_4 Z_5 Z_6 \rangle$")
ax.legend()
plt.show()

Output:

Ideal (noiseless):   0.8073
Noisy (unmitigated): 0.6431
Mitigated (PNA):     0.8071
Output of the previous code cell
Esta página foi útil?
Relate um bug, erro de digitação ou solicite conteúdo no GitHub.