Skip to main content
IBM Quantum Platform

ノイズモデルを構築する

  • このページのコードは、以下の要件に基づいて開発された。 これらのバージョンまたは新しいバージョンの使用をお勧めします。

    qiskit[all]~=2.5.1
    qiskit-ibm-runtime~=0.47.0
    qiskit-aer~=0.17
    

このページではQiskit Aer noise モジュールを使用して、誤差が存在する量子回路をシミュレーションするためのノイズモデルを構築する方法を紹介します。 これは、ノイズの多い量子プロセッサーのエミュレートや、量子アルゴリズムの実行に対するノイズの影響の研究に役立つ。

import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Kraus, SuperOp
from qiskit.visualization import plot_histogram
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator

# Import from Qiskit Aer noise module
from qiskit_aer.noise import (
    NoiseModel,
    QuantumError,
    ReadoutError,
    depolarizing_error,
    pauli_error,
    thermal_relaxation_error,
)

Qiskit Aer noise モジュール

Qiskit Aer noise モジュールには、シミュレーション用にカスタマイズされたノイズモデルを構築するための Python クラスが含まれています。 主要なクラスは3つある:

  1. NoiseModel ノイズシミュレーションに使用されるノイズモデルを格納するクラス。

  2. CPTP ゲートエラーを記述する QuantumError クラス。 これらを適用することができる:

    • ゲートまたはリセット指示後
    • 測定前の注意事項
  3. ReadoutError 古典的な読み出しエラーを記述するクラス。


バックエンドからノイズモデルを初期化する

物理バックエンドの最新のキャリブレーションデータに基づいてパラメータを設定し、ノイズモデルを初期化することができます。

Note

これらの例では の FakeSherbrooke``qiskit_ibm_runtime モックバックエンドを使用していますが、Qiskitと互換性のある実在または模擬のバックエンドであれば、どれでも試すことができます。

from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()
noise_model = NoiseModel.from_backend(backend)

これにより、そのバックエンドを使用したときに遭遇するであろうエラーにほぼ近似したノイズモデルが得られる。 ノイズモデルのパラメータをより詳細にコントロールしたい場合は、このページの残りの部分で説明するように、独自のノイズモデルを作成する必要があります。


量子エラー

オブジェクト QuantumError を直接扱う代わりに、特定の種類のパラメータ化された量子誤差を自動的に生成する多くのヘルパー関数が存在する。 これらは noise モジュールに含まれており、量子コンピューティング研究で使用される多くの一般的なエラータイプに対応する関数を含んでいます。 関数名とそれらが返すエラーの種類は以下の通りです:

標準誤差関数
詳細
kraus_errorクラウス行列のリストとして与えられる一般的なn量子ビットCPTPエラーチャネル [K0,...][K_0, ...]
mixed_unitary_errorn量子ビットの混合ユニタリーエラーは、ユニタリー行列と確率 [(U0,p0),...][(U_0, p_0),...] のリストとして与えられる。
coherent_unitary_errorn-qubit コヒーレントユニタリーエラーは、単一のユニタリー行列 UU として与えられる。
pauli_errorパウリと確率のリストとして与えられるn量子ビットのパウリ誤差チャンネル(混合ユニタリー)。 [(P0,p0),...][(P_0, p_0),...]
depolarizing_error脱分極確率 pp によってパラメータ化されたn量子ビットの脱分極エラーチャネル。
reset_error単一量子ビットリセットエラーは、 1\vert1\rangle 0\vert0\rangle 状態 へのリセット p0,p1p_0, p_1 確率 によってパラメータ化される。
thermal_relaxation_error緩和時間定数 T1T_1T2T_2、ゲート時間 tt、励起状態熱ポピュレーション p1p_1 によってパラメータ化された単一量子ビット熱緩和チャネル。
phase_amplitude_damping_error振幅減衰パラメータ λ\lambda、位相減衰パラメータ γ\gamma、励起状態熱集団 p1p_1 によって与えられる単一量子ビットの一般化された位相と振幅の複合減衰エラーチャネル。
amplitude_damping_error振幅減衰パラメータ λ\lambda と励起状態熱母集団 p1p_1 によって与えられる1量子ビット一般化振幅減衰誤差チャネル。
phase_damping_error位相減衰パラメータによって与えられる単一量子ビット γ\gamma の位相減衰エラーチャネル。

量子エラーを統合する

QuantumError インスタンスは、合成、テンソル積、テンソル展開(逆順テンソル積)を使って、新しい QuantumErrors

  • 組成: E(ρ)=E2(E1(ρ))\cal{E}(\rho)=\cal{E_2}(\cal{E_1}(\rho)) として error = error1.compose(error2)
  • テンソル積: E(ρ)=(E1E2)(ρ)\cal{E}(\rho) =(\cal{E_1}\otimes\cal{E_2})(\rho) として error = error1.tensor(error2)
  • 製品を拡張: E(ρ)=(E2E1)(ρ)\cal{E}(\rho) =(\cal{E_2}\otimes\cal{E_1})(\rho) as error = error1.expand(error2)

5%の1量子ビットのビット反転エラーを構築する:

# Construct a 1-qubit bit-flip and phase-flip errors
p_error = 0.05
bit_flip = pauli_error([("X", p_error), ("I", 1 - p_error)])
phase_flip = pauli_error([("Z", p_error), ("I", 1 - p_error)])
print(bit_flip)
print(phase_flip)

Output:

QuantumError on 1 qubits. Noise circuits:
  P(0) = 0.05, Circuit = 
   ┌───┐
q: ┤ X ├
   └───┘
  P(1) = 0.95, Circuit = 
   ┌───┐
q: ┤ I ├
   └───┘
QuantumError on 1 qubits. Noise circuits:
  P(0) = 0.05, Circuit = 
   ┌───┐
q: ┤ Z ├
   └───┘
  P(1) = 0.95, Circuit = 
   ┌───┐
q: ┤ I ├
   └───┘
# Compose two bit-flip and phase-flip errors
bitphase_flip = bit_flip.compose(phase_flip)
print(bitphase_flip)

Output:

QuantumError on 1 qubits. Noise circuits:
  P(0) = 0.0025000000000000005, Circuit = 
   ┌───┐┌───┐
q: ┤ X ├┤ Z ├
   └───┘└───┘
  P(1) = 0.0475, Circuit = 
   ┌───┐┌───┐
q: ┤ X ├┤ I ├
   └───┘└───┘
  P(2) = 0.0475, Circuit = 
   ┌───┐┌───┐
q: ┤ I ├┤ Z ├
   └───┘└───┘
  P(3) = 0.9025, Circuit = 
   ┌───┐┌───┐
q: ┤ I ├┤ I ├
   └───┘└───┘
# Tensor product two bit-flip and phase-flip errors with
# bit-flip on qubit-0, phase-flip on qubit-1
error2 = phase_flip.tensor(bit_flip)
print(error2)

Output:

QuantumError on 2 qubits. Noise circuits:
  P(0) = 0.0025000000000000005, Circuit = 
     ┌───┐
q_0: ┤ X ├
     ├───┤
q_1: ┤ Z ├
     └───┘
  P(1) = 0.0475, Circuit = 
     ┌───┐
q_0: ┤ I ├
     ├───┤
q_1: ┤ Z ├
     └───┘
  P(2) = 0.0475, Circuit = 
     ┌───┐
q_0: ┤ X ├
     ├───┤
q_1: ┤ I ├
     └───┘
  P(3) = 0.9025, Circuit = 
     ┌───┐
q_0: ┤ I ├
     ├───┤
q_1: ┤ I ├
     └───┘

QuantumChannel 演算子との相互変換

また、Qiskit Aerの QuantumError オブジェクトとQiskitの QuantumChannel オブジェクトを相互に変換することもできます。

# Convert to Kraus operator
bit_flip_kraus = Kraus(bit_flip)
print(bit_flip_kraus)

Output:

Kraus([[[-9.74679434e-01+0.j,  0.00000000e+00+0.j],
        [ 0.00000000e+00+0.j, -9.74679434e-01+0.j]],

       [[ 0.00000000e+00+0.j,  2.23606798e-01+0.j],
        [ 2.23606798e-01+0.j, -4.96506831e-17+0.j]]],
      input_dims=(2,), output_dims=(2,))
# Convert to Superoperator
phase_flip_sop = SuperOp(phase_flip)
print(phase_flip_sop)

Output:

SuperOp([[1. +0.j, 0. +0.j, 0. +0.j, 0. +0.j],
         [0. +0.j, 0.9+0.j, 0. +0.j, 0. +0.j],
         [0. +0.j, 0. +0.j, 0.9+0.j, 0. +0.j],
         [0. +0.j, 0. +0.j, 0. +0.j, 1. +0.j]],
        input_dims=(2,), output_dims=(2,))
# Convert back to a quantum error
print(QuantumError(bit_flip_kraus))

# Check conversion is equivalent to original error
QuantumError(bit_flip_kraus) == bit_flip

Output:

QuantumError on 1 qubits. Noise circuits:
  P(0) = 1.0, Circuit = 
   ┌───────┐
q: ┤ kraus ├
   └───────┘
True

読み出しエラー

古典的な読み出し誤差は、割り当て確率ベクトルのリストによって P(AB)P(A|B) 指定される:

  • AA記録された古典的なビット値
  • BB は測定から返された真のビット値

例えば、1量子ビットの場合: P(AB)=[P(A0),P(A1)] P(A|B) = [P(A|0), P(A|1)].

# Measurement misassignment probabilities
p0given1 = 0.1
p1given0 = 0.05

ReadoutError([[1 - p1given0, p1given0], [p0given1, 1 - p0given1]])

Output:

ReadoutError([[0.95 0.05]
 [0.1  0.9 ]])

読み出し誤差は、量子誤差と同様に、 composetensorexpand を使って組み合わせることもできる。


ノイズモデルに誤差を追加する

量子エラーをノイズモデルに追加する場合、それが作用する命令の種類と、それを適用する量子ビットを指定しなければならない。 量子エラーには2つのケースがある:

  1. 全量子ビット量子エラー
  2. 特定量子ビットの量子エラー

1. 全量子ビット量子エラー

これは、どの量子ビットに作用するかに関係なく、どの命令に対しても同じエラーを適用する。

noise_model.add_all_qubit_quantum_error(error, instructions) として追加される:

# Create an empty noise model
noise_model = NoiseModel()

# Add depolarizing error to all single qubit u1, u2, u3 gates
error = depolarizing_error(0.05, 1)
noise_model.add_all_qubit_quantum_error(error, ["u1", "u2", "u3"])

# Print noise model info
print(noise_model)

Output:

NoiseModel:
  Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
  Instructions with noise: ['u2', 'u1', 'u3']
  All-qubits errors: ['u1', 'u2', 'u3']

2. 特定の量子ビットの量子エラー

これは、指定された量子ビットのリストに作用する命令のすべての発生に対してエラーを適用する。 例えば、2量子ビットゲートの場合、 [0と1の]量子ビットに適用されるエラーは、 [1と0の]量子ビットに適用されるエラーとは異なる。

noise_model.add_quantum_error(error, instructions, qubits) として追加される:

# Create an empty noise model
noise_model = NoiseModel()

# Add depolarizing error to all single qubit u1, u2, u3 gates on qubit 0 only
error = depolarizing_error(0.05, 1)
noise_model.add_quantum_error(error, ["u1", "u2", "u3"], [0])

# Print noise model info
print(noise_model)

Output:

NoiseModel:
  Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
  Instructions with noise: ['u2', 'u1', 'u3']
  Qubits with noise: [0]
  Specific qubit errors: [('u1', (0,)), ('u2', (0,)), ('u3', (0,))]

非局所量子ビットの量子エラーに関する注記

NoiseModel 非局所的な量子ビットの量子エラーの追加はサポートしていません。 これらは.の外で処理 NoiseModelすべきです。 つまり、 独自の条件で量子エラーを回路に挿入する必要がある場合は、独自のトランスパイラ・パス(TransformationPass)を作成し、シミュレータを実行する直前にそのパスを実行すべきだということです。

ノイズモデルを用いたノイズシミュレーションを実行する

AerSimulator(noise_model=noise_model) コマンドは、与えられたノイズモデルに設定されたシミュレータを返します。 シミュレータのノイズモデルを設定するだけでなく、ノイズモデルのゲートに従って、シミュレータの基底ゲートをオーバーライドします。


ノイズモデルの例

次に、ノイズモデルの例をいくつか示します。 デモンストレーションでは、n量子ビットGHZ状態を生成する単純なテスト回路を使用します:

# System Specification
n_qubits = 4
circ = QuantumCircuit(n_qubits)

# Test Circuit
circ.h(0)
for qubit in range(n_qubits - 1):
    circ.cx(qubit, qubit + 1)
circ.measure_all()
print(circ)

Output:

        ┌───┐                ░ ┌─┐         
   q_0: ┤ H ├──■─────────────░─┤M├─────────
        └───┘┌─┴─┐           ░ └╥┘┌─┐      
   q_1: ─────┤ X ├──■────────░──╫─┤M├──────
             └───┘┌─┴─┐      ░  ║ └╥┘┌─┐   
   q_2: ──────────┤ X ├──■───░──╫──╫─┤M├───
                  └───┘┌─┴─┐ ░  ║  ║ └╥┘┌─┐
   q_3: ───────────────┤ X ├─░──╫──╫──╫─┤M├
                       └───┘ ░  ║  ║  ║ └╥┘
meas: 4/════════════════════════╩══╩══╩══╩═
                                0  1  2  3 

理想的なシミュレーション

# Ideal simulator and execution
sim_ideal = AerSimulator()
result_ideal = sim_ideal.run(circ).result()
plot_histogram(result_ideal.get_counts(0))

Output:

Output of the previous code cell

ノイズ例1:基本的なビット反転エラーノイズモデル

量子情報理論の研究でよく使われる簡単なおもちゃのノイズモデルの例を考えてみよう:

  • 単一量子ビットゲートを適用する場合、 p_gate1 の確率で量子ビットの状態を反転させる。
  • 2量子ビットのゲートを適用する場合、それぞれの量子ビットに1量子ビットのエラーを適用する。
  • 量子ビットをリセットする場合、確率 p_reset で 0 ではなく 1 にリセットする。
  • 量子ビットを測定するとき、確率 p_meas で量子ビットの状態を反転させる。
# Example error probabilities
p_reset = 0.03
p_meas = 0.1
p_gate1 = 0.05

# QuantumError objects
error_reset = pauli_error([("X", p_reset), ("I", 1 - p_reset)])
error_meas = pauli_error([("X", p_meas), ("I", 1 - p_meas)])
error_gate1 = pauli_error([("X", p_gate1), ("I", 1 - p_gate1)])
error_gate2 = error_gate1.tensor(error_gate1)

# Add errors to noise model
noise_bit_flip = NoiseModel()
noise_bit_flip.add_all_qubit_quantum_error(error_reset, "reset")
noise_bit_flip.add_all_qubit_quantum_error(error_meas, "measure")
noise_bit_flip.add_all_qubit_quantum_error(error_gate1, ["u1", "u2", "u3"])
noise_bit_flip.add_all_qubit_quantum_error(error_gate2, ["cx"])

print(noise_bit_flip)

Output:

NoiseModel:
  Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
  Instructions with noise: ['u3', 'u1', 'u2', 'reset', 'cx', 'measure']
  All-qubits errors: ['reset', 'measure', 'u1', 'u2', 'u3', 'cx']

ノイズの多いシミュレーションを実行する

# Create noisy simulator backend
sim_noise = AerSimulator(noise_model=noise_bit_flip)

# Transpile circuit for noisy basis gates
passmanager = generate_preset_pass_manager(
    optimization_level=3, backend=sim_noise
)
circ_tnoise = passmanager.run(circ)

# Run and get counts
result_bit_flip = sim_noise.run(circ_tnoise).result()
counts_bit_flip = result_bit_flip.get_counts(0)

# Plot noisy output
plot_histogram(counts_bit_flip)

Output:

Output of the previous code cell

例2: T1/T2 熱緩和

ここで、量子ビット環境との熱緩和に基づく、より現実的な誤差モデルを考えてみよう:

  • それぞれの量子ビットは、熱緩和時定数 T1T_1 とデフェーズ時定数 T2T_2 によってパラメータ化される。
  • なお、 T22T1T_2 \le 2 T_1
  • 命令のエラー率は、ゲート時間と量子ビット T1T_1T2T_2 の値によって決まる。
# T1 and T2 values for qubits 0-3
T1s = np.random.normal(
    50e3, 10e3, 4
)  # Sampled from normal distribution mean 50 microsec
T2s = np.random.normal(
    70e3, 10e3, 4
)  # Sampled from normal distribution mean 50 microsec

# Truncate random T2s <= T1s
T2s = np.array([min(T2s[j], 2 * T1s[j]) for j in range(4)])

# Instruction times (in nanoseconds)
time_u1 = 0  # virtual gate
time_u2 = 50  # (single X90 pulse)
time_u3 = 100  # (two X90 pulses)
time_cx = 300
time_reset = 1000  # 1 microsecond
time_measure = 1000  # 1 microsecond

# QuantumError objects
errors_reset = [
    thermal_relaxation_error(t1, t2, time_reset) for t1, t2 in zip(T1s, T2s)
]
errors_measure = [
    thermal_relaxation_error(t1, t2, time_measure) for t1, t2 in zip(T1s, T2s)
]
errors_u1 = [
    thermal_relaxation_error(t1, t2, time_u1) for t1, t2 in zip(T1s, T2s)
]
errors_u2 = [
    thermal_relaxation_error(t1, t2, time_u2) for t1, t2 in zip(T1s, T2s)
]
errors_u3 = [
    thermal_relaxation_error(t1, t2, time_u3) for t1, t2 in zip(T1s, T2s)
]
errors_cx = [
    [
        thermal_relaxation_error(t1a, t2a, time_cx).expand(
            thermal_relaxation_error(t1b, t2b, time_cx)
        )
        for t1a, t2a in zip(T1s, T2s)
    ]
    for t1b, t2b in zip(T1s, T2s)
]

# Add errors to noise model
noise_thermal = NoiseModel()
for j in range(4):
    noise_thermal.add_quantum_error(errors_reset[j], "reset", [j])
    noise_thermal.add_quantum_error(errors_measure[j], "measure", [j])
    noise_thermal.add_quantum_error(errors_u1[j], "u1", [j])
    noise_thermal.add_quantum_error(errors_u2[j], "u2", [j])
    noise_thermal.add_quantum_error(errors_u3[j], "u3", [j])
    for k in range(4):
        noise_thermal.add_quantum_error(errors_cx[j][k], "cx", [j, k])

print(noise_thermal)

Output:

NoiseModel:
  Basis gates: ['cx', 'id', 'rz', 'sx', 'u2', 'u3']
  Instructions with noise: ['u3', 'u2', 'reset', 'cx', 'measure']
  Qubits with noise: [0, 1, 2, 3]
  Specific qubit errors: [('reset', (0,)), ('reset', (1,)), ('reset', (2,)), ('reset', (3,)), ('measure', (0,)), ('measure', (1,)), ('measure', (2,)), ('measure', (3,)), ('u2', (0,)), ('u2', (1,)), ('u2', (2,)), ('u2', (3,)), ('u3', (0,)), ('u3', (1,)), ('u3', (2,)), ('u3', (3,)), ('cx', (0, 0)), ('cx', (0, 1)), ('cx', (0, 2)), ('cx', (0, 3)), ('cx', (1, 0)), ('cx', (1, 1)), ('cx', (1, 2)), ('cx', (1, 3)), ('cx', (2, 0)), ('cx', (2, 1)), ('cx', (2, 2)), ('cx', (2, 3)), ('cx', (3, 0)), ('cx', (3, 1)), ('cx', (3, 2)), ('cx', (3, 3))]

ノイズの多いシミュレーションを実行する

# Run the noisy simulation
sim_thermal = AerSimulator(noise_model=noise_thermal)

# Transpile circuit for noisy basis gates
passmanager = generate_preset_pass_manager(
    optimization_level=3, backend=sim_thermal
)
circ_tthermal = passmanager.run(circ)

# Run and get counts
result_thermal = sim_thermal.run(circ_tthermal).result()
counts_thermal = result_thermal.get_counts(0)

# Plot noisy output
plot_histogram(counts_thermal)

Output:

Output of the previous code cell

次のステップ

推奨事項
このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。