Pular para o conteúdo principal

Simulação eficiente de circuitos estabilizadores com primitivos do Qiskit Aer

Versões dos pacotes

O código desta página foi desenvolvido com os seguintes requisitos. Recomendamos usar essas versões ou mais recentes.

qiskit[all]~=2.3.0
qiskit-aer~=0.17

Esta página mostra como usar os primitivos do Qiskit Aer para simular eficientemente circuitos estabilizadores, incluindo aqueles sujeitos a ruído de Pauli.

Circuitos estabilizadores, também conhecidos como circuitos de Clifford, são uma classe restrita importante de circuitos quânticos que podem ser simulados eficientemente de forma clássica. Existem várias maneiras equivalentes de definir circuitos estabilizadores. Uma definição é que um circuito estabilizador é um circuito quântico composto exclusivamente pelos seguintes gates:

Observe que usando Hadamard e S, podemos construir qualquer gate de rotação de Pauli (RxR_x, RyR_y e RzR_z) que tenha um ângulo contido no conjunto {0,π2,π,3π2}\{0, \frac{\pi}{2}, \pi, \frac{3\pi}{2}\} (a menos de fase global), portanto podemos incluir esses gates na definição também.

Circuitos estabilizadores são importantes para o estudo da correção de erros quânticos. Sua simulabilidade clássica também os torna úteis para verificar a saída de computadores quânticos. Por exemplo, suponha que você queira executar um circuito quântico com 100 qubits em um computador quântico. Como você sabe que o computador quântico está se comportando corretamente? Um circuito quântico com 100 qubits está além do alcance da simulação clássica por força bruta. Ao modificar seu circuito para que ele se torne um circuito estabilizador, você pode executar circuitos no computador quântico que tenham uma estrutura semelhante ao seu circuito desejado, mas que você pode simular em um computador clássico. Ao verificar a saída do computador quântico nos circuitos estabilizadores, você pode ganhar confiança de que ele também está se comportando corretamente nos circuitos não estabilizadores. Veja Evidence for the utility of quantum computing before fault tolerance para um exemplo dessa ideia na prática.

Simulação exata e com ruído com primitivos do Qiskit Aer mostra como usar o Qiskit Aer para realizar simulações exatas e com ruído de circuitos quânticos genéricos. Considere o circuito de exemplo usado naquele artigo, um Circuit de 8 qubits construído com efficient_su2:

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer
from qiskit.circuit.library import efficient_su2

n_qubits = 8
circuit = efficient_su2(n_qubits)
circuit.draw("mpl")

Saída da célula de código anterior

Usando o Qiskit Aer, conseguimos simular esse Circuit facilmente. No entanto, suponha que definamos o número de qubits como 500:

n_qubits = 500
circuit = efficient_su2(n_qubits)
# don't try to draw the circuit because it's too large

Como o custo de simular circuitos quânticos cresce exponencialmente com o número de qubits, um Circuit tão grande geralmente excederia as capacidades até mesmo de um simulador de alto desempenho como o Qiskit Aer. A simulação clássica de circuitos quânticos genéricos torna-se inviável quando o número de qubits ultrapassa aproximadamente 50 a 100 qubits. No entanto, observe que o circuito efficient_su2 é parametrizado por ângulos nos gates RyR_y e RzR_z. Se todos esses ângulos estiverem contidos no conjunto {0,π2,π,3π2}\{0, \frac{\pi}{2}, \pi, \frac{3\pi}{2}\}, então o Circuit é um circuito estabilizador e pode ser simulado eficientemente!

Na célula a seguir, executamos o Circuit com o primitivo Sampler apoiado pelo simulador de circuitos estabilizadores, usando parâmetros escolhidos aleatoriamente de forma que o Circuit seja garantidamente um circuito estabilizador.

import numpy as np
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import SamplerV2 as Sampler

measured_circuit = circuit.copy()
measured_circuit.measure_all()

rng = np.random.default_rng(1234)
params = rng.choice(
[0, np.pi / 2, np.pi, 3 * np.pi / 2],
size=circuit.num_parameters,
)

# Initialize a Sampler backed by the stabilizer circuit simulator
exact_sampler = Sampler(
options=dict(backend_options=dict(method="stabilizer"))
)
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(
1, AerSimulator(method="stabilizer")
)
isa_circuit = pass_manager.run(measured_circuit)
pub = (isa_circuit, params)
job = exact_sampler.run([pub])
result = job.result()
pub_result = result[0]
counts = pub_result.data.meas.get_counts()

O simulador de circuitos estabilizadores também suporta simulação com ruído, mas apenas para uma classe restrita de modelos de ruído. Especificamente, qualquer ruído quântico deve ser caracterizado por um canal de erro de Pauli. O erro de despolarização se enquadra nessa categoria, portanto também pode ser simulado. Canais de ruído clássico, como o erro de leitura, também podem ser simulados.

A célula de código a seguir executa a mesma simulação de antes, mas desta vez especificando um modelo de ruído que adiciona erro de despolarização de 2% a cada gate CX, além de erro de leitura que inverte cada bit medido com probabilidade de 5%.

from qiskit_aer.noise import NoiseModel, depolarizing_error, ReadoutError

noise_model = NoiseModel()
cx_depolarizing_prob = 0.02
bit_flip_prob = 0.05
noise_model.add_all_qubit_quantum_error(
depolarizing_error(cx_depolarizing_prob, 2), ["cx"]
)
noise_model.add_all_qubit_readout_error(
ReadoutError(
[
[1 - bit_flip_prob, bit_flip_prob],
[bit_flip_prob, 1 - bit_flip_prob],
]
)
)

noisy_sampler = Sampler(
options=dict(
backend_options=dict(method="stabilizer", noise_model=noise_model)
)
)
job = noisy_sampler.run([pub])
result = job.result()
pub_result = result[0]
counts = pub_result.data.meas.get_counts()

Agora, vamos usar o primitivo Estimator apoiado pelo simulador estabilizador para calcular o valor esperado do observável ZZZZZ \cdots Z. Devido à estrutura especial dos circuitos estabilizadores, o resultado é muito provavelmente 0.

from qiskit.quantum_info import SparsePauliOp
from qiskit_aer.primitives import EstimatorV2 as Estimator

observable = SparsePauliOp("Z" * n_qubits)

exact_estimator = Estimator(
options=dict(backend_options=dict(method="stabilizer")),
)
isa_circuit = pass_manager.run(circuit)
pub = (isa_circuit, observable, params)
job = exact_estimator.run([pub])
result = job.result()
pub_result = result[0]
exact_value = float(pub_result.data.evs)
exact_value
0.0

Próximos passos

Recomendações