주 콘텐츠로 건너뛰기

Qiskit Aer 프리미티브를 사용한 정확한 시뮬레이션 및 노이즈 시뮬레이션

패키지 버전

이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다. 이 버전 이상을 사용하길 권장합니다.

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

Qiskit 프리미티브를 사용한 정확한 시뮬레이션에서는 Qiskit에 포함된 참조 프리미티브를 사용하여 양자 Circuit의 정확한 시뮬레이션을 수행하는 방법을 설명합니다. 현재 존재하는 양자 프로세서는 오류 또는 노이즈로 인해 어려움을 겪고 있으므로, 정확한 시뮬레이션의 결과가 실제 하드웨어에서 Circuit을 실행할 때 기대하는 결과와 반드시 일치하지는 않습니다. Qiskit의 참조 프리미티브는 노이즈 모델링을 지원하지 않지만, Qiskit Aer에는 노이즈 모델링을 지원하는 프리미티브 구현이 포함되어 있습니다. Qiskit Aer는 고성능 양자 Circuit 시뮬레이터로, 더 나은 성능과 더 많은 기능을 위해 참조 프리미티브 대신 사용할 수 있습니다. Qiskit Aer는 Qiskit Ecosystem의 일부입니다. 이 문서에서는 정확한 시뮬레이션 및 노이즈 시뮬레이션을 위한 Qiskit Aer 프리미티브의 사용법을 설명합니다.

참고 사항
  • qiskit-aer v0.14 이상이 필요합니다.
  • Qiskit Aer 프리미티브는 프리미티브 인터페이스를 구현하지만, Qiskit Runtime 프리미티브와 동일한 옵션을 제공하지는 않습니다. 예를 들어, 복원력 수준(Resilience level)은 Qiskit Aer 프리미티브에서 사용할 수 없습니다.
  • Aer가 지원하는 시뮬레이션 방법 옵션에 대한 자세한 내용은 AerSimulator 문서를 참조하세요.

정확한 시뮬레이션과 노이즈 시뮬레이션을 탐색하기 위해 8개의 Qubit으로 예제 Circuit을 생성합니다.

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

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

이전 코드 셀의 출력

이 Circuit에는 RyR_yRzR_z Gate의 회전 각도를 나타내는 매개변수가 포함되어 있습니다. 이 Circuit을 시뮬레이션할 때는 이러한 매개변수에 대한 명시적인 값을 지정해야 합니다. 다음 셀에서는 이러한 매개변수에 대한 일부 값을 지정하고, Qiskit Aer의 Estimator 프리미티브를 사용하여 관측량 ZZZZZ \cdots Z의 정확한 기대값을 계산합니다.

from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import EstimatorV2 as Estimator

observable = SparsePauliOp("Z" * n_qubits)
params = [0.1] * circuit.num_parameters

exact_estimator = Estimator()
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(3, AerSimulator())
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.8870140234256602

이제 모든 CX Gate에 2%의 탈분극 오류(depolarizing error)를 포함하는 노이즈 모델을 초기화해 보겠습니다. 실제로는 여기서 CX Gate인 2큐비트 Gate에서 발생하는 오류가 Circuit을 실행할 때 오류의 주요 원인입니다. Qiskit Aer에서 노이즈 모델 구성에 대한 개요는 노이즈 모델 구축을 참조하세요.

다음 셀에서는 이 노이즈 모델을 포함하는 Estimator를 구성하고 이를 사용하여 관측량의 기대값을 계산합니다.

from qiskit_aer.noise import NoiseModel, depolarizing_error

noise_model = NoiseModel()
cx_depolarizing_prob = 0.02
noise_model.add_all_qubit_quantum_error(
depolarizing_error(cx_depolarizing_prob, 2), ["cx"]
)

noisy_estimator = Estimator(
options=dict(backend_options=dict(noise_model=noise_model))
)
job = noisy_estimator.run([pub])
result = job.result()
pub_result = result[0]
noisy_value = float(pub_result.data.evs)
noisy_value
0.7247404214143528

보면 알 수 있듯이, 노이즈가 있을 때의 기대값은 올바른 값과 상당히 차이가 납니다. 실제로는 노이즈의 영향을 상쇄하기 위해 다양한 오류 완화 기술을 사용할 수 있지만, 이러한 기술에 대한 논의는 이 문서의 범위를 벗어납니다.

노이즈가 최종 결과에 어떻게 영향을 미치는지 대략적으로 이해하기 위해, 각 CX Gate에 2%의 탈분극 오류를 추가하는 노이즈 모델을 고려해 보겠습니다. 확률 pp의 탈분극 오류는 밀도 행렬 ρ\rho에 대해 다음과 같은 작용을 하는 양자 채널 EE로 정의됩니다.

E(ρ)=(1p)ρ+pI2nE(\rho) = (1 - p) \rho + p\frac{I}{2^n}

여기서 nn은 Qubit의 수로, 이 경우 2입니다. 즉, 확률 pp로 상태가 완전히 혼합된 상태로 대체되고, 확률 1p1 - p로 상태가 보존됩니다. 탈분극 채널의 mm번 적용 후 상태가 보존될 확률은 (1p)m(1 - p)^m이 됩니다. 따라서 우리 Circuit의 CX Gate 수에 따라 시뮬레이션 끝에 올바른 상태를 유지할 확률이 기하급수적으로 감소할 것으로 예상됩니다.

Circuit에서 CX Gate의 수를 세고 (1p)m(1 - p)^m을 계산해 보겠습니다. count_ops를 호출하여 Gate 이름을 횟수에 매핑하는 딕셔너리를 얻고 CX Gate에 대한 항목을 검색합니다.

cx_count = circuit.count_ops()["cx"]
(1 - cx_depolarizing_prob) ** cx_count
0.6542558123199923

이 값인 65%는 최종 상태가 올바를 확률에 대한 대략적인 추정값입니다. 시뮬레이션의 초기 상태를 고려하지 않기 때문에 보수적인 추정값입니다.

다음 코드 셀은 Qiskit Aer의 Sampler 프리미티브를 사용하여 노이즈가 있는 Circuit에서 샘플링하는 방법을 보여줍니다. Sampler 프리미티브로 실행하기 전에 Circuit에 측정을 추가해야 합니다.

from qiskit_aer.primitives import SamplerV2 as Sampler

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

noisy_sampler = Sampler(
options=dict(backend_options=dict(noise_model=noise_model))
)
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(3, AerSimulator())
isa_circuit = pass_manager.run(measured_circuit)
pub = (isa_circuit, params, 100)
job = noisy_sampler.run([pub])
result = job.result()
pub_result = result[0]
pub_result.data.meas.get_counts()
{'00100000': 1,
'00000000': 65,
'10101000': 1,
'10000000': 5,
'00001000': 1,
'00000110': 2,
'11110010': 1,
'00000011': 3,
'01010000': 3,
'11000000': 3,
'01111000': 1,
'01000000': 2,
'00000010': 1,
'01100000': 1,
'00011000': 1,
'00111100': 1,
'00010100': 1,
'00001111': 1,
'00110000': 1,
'01100101': 1,
'00000100': 1,
'10100000': 1,
'00000001': 1,
'11010000': 1}

다음 단계

권장 사항