メインコンテンツへスキップ

Qiskit Aer primitiveによる完全シミュレーションとノイズありシミュレーション

Package versions

The code on this page was developed using the following requirements. We recommend using these versions or newer.

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

Qiskit primitiveによる完全シミュレーションでは、Qiskitに含まれるリファレンスprimitiveを使用して量子回路の完全シミュレーションを実行する方法を説明しています。現在の量子プロセッサーにはエラー(ノイズ)が存在するため、完全シミュレーションの結果が実際のハードウェア上で回路を実行したときに期待される結果と必ずしも一致するわけではありません。Qiskitのリファレンスprimitiveはノイズのモデリングをサポートしていませんが、Qiskit Aerにはノイズモデリングをサポートするprimitiveの実装が含まれています。Qiskit Aerは高性能な量子回路シミュレーターであり、より高いパフォーマンスと多くの機能を実現するためにリファレンスprimitiveの代わりに使用できます。Qiskit AerはQiskit Ecosystemの一部です。この記事では、完全シミュレーションとノイズありシミュレーションにおけるQiskit Aer primitiveの使用方法を説明します。

注意事項
  • qiskit-aer v0.14以降が必要です。
  • Qiskit Aer primitiveはprimitive インターフェースを実装していますが、Qiskit Runtime primitiveと同じオプションを提供するわけではありません。たとえば、耐性レベル(Resilience level)はQiskit Aer primitiveでは利用できません。
  • Aerがサポートするシミュレーション方式のオプションについては、AerSimulatorのドキュメントを参照してください。

完全シミュレーションとノイズありシミュレーションを試すために、8量子ビットのサンプル回路を作成します。

# 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")

Output of the previous code cell

この回路には、RyR_yゲートとRzR_zゲートの回転角を表すパラメーターが含まれています。この回路をシミュレーションする際には、これらのパラメーターに具体的な値を指定する必要があります。次のセルでは、これらのパラメーターにいくつかの値を指定し、Qiskit AerのEstimator primitiveを使用して、観測量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ゲートに2%の脱分極エラー(depolarizing error)を含むノイズモデルを初期化します。実際には、ここでのCXゲートのような2量子ビットゲートから生じるエラーが、回路を実行する際の主要なエラーの原因です。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ゲートに2%の脱分極エラーを追加するノイズモデルを考えてみましょう。確率ppの脱分極エラーは、密度行列ρ\rhoに対して次の作用を持つ量子チャンネルEEとして定義されます。

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

ここでnnは量子ビット数で、この場合は2です。つまり、確率ppで状態が完全混合状態に置き換えられ、確率1p1 - pで状態が保存されます。脱分極チャンネルをmm回適用した後、状態が保存される確率は(1p)m(1 - p)^mとなります。したがって、シミュレーションの終了時に正しい状態を保持する確率は、回路内のCXゲートの数に対して指数的に減少することが予想されます。

回路内のCXゲートの数を数えて(1p)m(1 - p)^mを計算してみましょう。count_opsを呼び出してゲート名とカウントのマッピングを含む辞書を取得し、CXゲートのエントリーを取り出します。

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

この値(65%)は、最終状態が正しい確率の概算です。シミュレーションの初期状態を考慮していないため、これは保守的な推定値です。

次のコードセルは、Qiskit AerのSampler primitiveを使用してノイズありの回路からサンプリングする方法を示しています。Sampler primitiveで実行する前に、回路に測定を追加する必要があります。

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}

次のステップ

おすすめ