メインコンテンツまでスキップ

Readout error mitigation

実機のデバイスは不完全であるため、状態の準備や測定でエラーが発生します。読み出しエラーの軽減は、このようなノイズ演算の逆変換を適用することにより、これらのエラーの影響を軽減します。ノイズ演算の逆行列(ここではフィルター行列と呼ぶ)は、読み出しエラー緩和において重要な役割を果たします。ノイジーカウントCnoisyC_{\text{noisy}}は、ノイズのない世界で得ることのできる理想的なカウントCidealC_{\text{ideal}}とエラー行列EEの積として考えることができます。

Cnoisy=ECidealC_{\text{noisy}} = EC_{\text{ideal}}

EE(i,j)(i, j)要素は、真の状態がj|j\rangleであった場合に測定結果としてi|i\rangleを得る確率を表しており、P(ij)P(i|j)と表現されます。つまり、列方向に合計すると1になります。例えば、2量子ビットのデバイスのEE

E=(P(0000)P(0001)P(0010)P(0011)P(0100)P(0101)P(0110)P(0111)P(1000)P(1001)P(1010)P(1011)P(1100)P(1101)P(1110)P(1111))E = \left( \begin{matrix} P(00|00) & P(00|01) & P(00|10) & P(00|11) \\ P(01|00) & P(01|01) & P(01|10) & P(01|11) \\ P(10|00) & P(10|01) & P(10|10) & P(10|11) \\ P(11|00) & P(11|01) & P(11|10) & P(11|11) \end{matrix} \right)

EEは、各基底において状態の準備と測定を繰り返し、実際の測定結果のヒストグラムから確率分布を求めることによって推定されます。

フィルター行列はエラー行列の逆行列として定義されます。フィルター行列を用いれば、エラーのないカウントを推定することができます。

Cideal=E1Cnoisy.C_{\text{ideal}} = E^{-1}C_{\text{noisy}}.

このチュートリアルでは、フィルター行列を構築し、ノイズのないサンプリング数を予測する方法を示します。

前提条件

このチュートリアルで使用されるQURI Partsモジュール:quri-parts-algo,quri-parts-circuit, quri-parts-core

以下のようにインストールできます:

# !pip install "quri-parts[qulacs]"

準備と概要

ここでは、このチュートリアルで使用する回路とノイズモデルを準備します。このチュートリアルで使用する回路は、恒等パートと非自明パートで構成されています。非自明パートは状態000|000\rangle12(000+111)\frac{1}{\sqrt{2}}\left(|000\rangle + |111\rangle\right)に変換する部分を担っている一方、ノイズの影響を増幅するために、恒等回路を複数のゲートに分解します。

from quri_parts.circuit import QuantumCircuit
from quri_parts.circuit.utils.circuit_drawer import draw_circuit

qubit_count = 3

identity_circuit = QuantumCircuit(3)
identity_circuit.add_RX_gate(0, 1.3)
identity_circuit.add_RY_gate(1, 0.2)
identity_circuit.add_RZ_gate(0, -2.3)
identity_circuit.add_SqrtXdag_gate(1)
identity_circuit.add_T_gate(0)
identity_circuit.add_RX_gate(1, 0.4)
identity_circuit.add_RY_gate(0, 2.7)
identity_circuit.add_Tdag_gate(1)
identity_circuit.add_RY_gate(0, -2.7)
identity_circuit.add_T_gate(1)
identity_circuit.add_Tdag_gate(0)
identity_circuit.add_RX_gate(1, -0.4)
identity_circuit.add_RZ_gate(0, 2.3)
identity_circuit.add_SqrtX_gate(1)
identity_circuit.add_RX_gate(0, -1.3)
identity_circuit.add_RY_gate(1, -0.2)

circuit = QuantumCircuit(3)
circuit += identity_circuit
circuit.add_H_gate(0)
circuit.add_CNOT_gate(0, 1)
circuit.add_CNOT_gate(0, 2)


print("The circuit:")
draw_circuit(circuit, line_length=200)
#output
The circuit:
___ ___ ___ ___ ___ ___ ___ ___ ___
|RX | |RZ | | T | |RY | |RY | |Tdg| |RZ | |RX | | H |
--|0 |---|2 |---|4 |---|6 |---|8 |---|10 |---|12 |---|14 |---|16 |-----●-------●---
|___| |___| |___| |___| |___| |___| |___| |___| |___| | |
___ ___ ___ ___ ___ ___ ___ ___ _|_ |
|RY | |sXd| |RX | |Tdg| | T | |RX | |sqX| |RY | |CX | |
--|1 |---|3 |---|5 |---|7 |---|9 |---|11 |---|13 |---|15 |-----------|17 |-----|---
|___| |___| |___| |___| |___| |___| |___| |___| |___| |
_|_
|CX |
----------------------------------------------------------------------------------|18 |-
|___|

次に、いくつかのNoiseInstructionsでノイズモデルを作成します。ここでは、MeasurementNoiseだけを考えます。

from quri_parts.circuit.noise import BitFlipNoise, MeasurementNoise, NoiseModel

noise_model = NoiseModel([
MeasurementNoise([BitFlipNoise(0.01)])
])

このノイズモデルでは、測定中にビット反転エラーが発生します。

読み出し誤差の軽減と性能

ここでは、読み出し誤差緩和を行うestimatorの構築方法を示します。この簡単な例では、読み出し誤差の緩和を実行するsampling estimatorの性能を、ノイズのないestimatorやノイズのあるestimatorと比較します。まずは演算子を用意します。

from quri_parts.core.operator import Operator, pauli_label, PAULI_IDENTITY
op = Operator({
pauli_label("Z0"): 0.25,
pauli_label("Z1 Z2"): 2.0,
pauli_label("X1 X2"): 0.5,
pauli_label("Z1 Y2"): 1.0,
pauli_label("X1 Y2"): 2.0,
PAULI_IDENTITY: 3.0,
})

次に、読み出し誤差を軽減するサンプリング推定器の構築方法を示します。sampling estimatorのチュートリアルで示したように、サンプリング推定器を作成するには同時サンプラーが必要です。読み出しエラー軽減sampling estimatorの場合、フィルター行列を構築し、軽減スキームを内部で実行するサンプラーを構築します。このサンプラーはquri_parts.algoで提供されているcreate_readout_mitigation_concurrent_sampler関数で作成します。

from quri_parts.qulacs.estimator import create_qulacs_vector_estimator, create_qulacs_density_matrix_estimator
from quri_parts.qulacs.sampler import create_qulacs_density_matrix_concurrent_sampler
from quri_parts.core.estimator.sampling import create_sampling_estimator
from quri_parts.core.estimator import QuantumEstimator
from quri_parts.core.sampling.shots_allocator import create_equipartition_shots_allocator
from quri_parts.core.measurement import bitwise_commuting_pauli_measurement
from quri_parts.core.state import CircuitQuantumState, quantum_state
from quri_parts.algo.mitigation.readout_mitigation import create_readout_mitigation_concurrent_sampler

def get_readout_mit_estimator(qubit_count: int, shots: int=int(1e6)) -> QuantumEstimator[CircuitQuantumState]:
noisy_concurrent_sampler = create_qulacs_density_matrix_concurrent_sampler(noise_model)
allocator = create_equipartition_shots_allocator()

readout_mit_concurrent_sampler = create_readout_mitigation_concurrent_sampler(
qubit_count,
noisy_concurrent_sampler, # takes in a noisy concurrent sampler
shots
)
return create_sampling_estimator(
shots,
readout_mit_concurrent_sampler,
bitwise_commuting_pauli_measurement,
allocator
)

# Returns the estimator
readout_mit_estimator = get_readout_mit_estimator(qubit_count=3)

ここで、読み出し誤差の緩和を行うsampling estimatorができたので、その推定結果をノイズのないestimator、ノイズのあるestimatorと比較します。

exact_estimator = create_qulacs_vector_estimator()
noisy_estimator = create_qulacs_density_matrix_estimator(noise_model)

state = quantum_state(3, circuit=circuit)

print("Noiseless estimate:", exact_estimator(op, state).value)
print("Noisy estimate:", noisy_estimator(op, state).value)
print("Readout mitigation estimate:", readout_mit_estimator(op, state).value)
#output
Noiseless estimate: (4.999999999999998+0j)
Noisy estimate: (4.920800000000014+0j)
Readout mitigation estimate: 4.998136830346459

ノイズは確かに緩和され、ノイズのある場合の推定値と比較してより良い期待値の推定値が得られていることがわかります。

読み出しエラー軽減サンプラーをステップバイステップで構築

ここで、読み出しエラー軽減(コンカレント)サンプラーを構築するために必要なすべてのステップを説明します。ここでは以下のことを含みます:

  • ノイズありサンプラーからフィルター行列を作成
  • ノイズありサンプラーによって生成されたサンプリングカウントにフィルターマトリックスを適用

Qulacsでのサンプリングシミュレーション

まず、ノイズありSamplerを作成し、誤差を軽減せずにサンプリングを実行します。

from quri_parts.qulacs.sampler import create_qulacs_density_matrix_sampler

sampler = create_qulacs_density_matrix_sampler(noise_model)
counts = sampler(circuit, shots=10000)
counts
#output
{0: 4912, 1: 44, 2: 49, 3: 48, 4: 51, 5: 52, 6: 45, 7: 4799}

フィルター行列の作成

フィルター行列を作成するためにcreate_filter_matrixを使用します。

from quri_parts.algo.mitigation.readout_mitigation import create_filter_matrix
from quri_parts.qulacs.sampler import create_qulacs_density_matrix_concurrent_sampler

concurernt_sampler = create_qulacs_density_matrix_concurrent_sampler(noise_model)

filter_matrix = create_filter_matrix(qubit_count, concurernt_sampler, shots=1000000)
filter_matrix.round(5)
#output
array([[ 1.03065e+00, -1.01600e-02, -1.05200e-02, 1.00000e-04,
-1.03600e-02, 9.00000e-05, 9.00000e-05, 0.00000e+00],
[-1.05200e-02, 1.03066e+00, 1.20000e-04, -1.05200e-02,
1.10000e-04, -1.03900e-02, -0.00000e+00, 1.10000e-04],
[-1.02800e-02, 1.00000e-04, 1.03128e+00, -1.03600e-02,
1.10000e-04, -0.00000e+00, -1.04700e-02, 1.00000e-04],
[ 1.00000e-04, -1.05300e-02, -1.04100e-02, 1.03087e+00,
-0.00000e+00, 1.00000e-04, 1.10000e-04, -1.01200e-02],
[-1.01300e-02, 1.10000e-04, 1.00000e-04, -0.00000e+00,
1.03076e+00, -1.06300e-02, -1.04400e-02, 1.10000e-04],
[ 9.00000e-05, -1.02800e-02, -0.00000e+00, 1.10000e-04,
-1.04400e-02, 1.03110e+00, 1.20000e-04, -1.02800e-02],
[ 9.00000e-05, -0.00000e+00, -1.06800e-02, 1.20000e-04,
-1.03100e-02, 1.10000e-04, 1.03115e+00, -1.03900e-02],
[-0.00000e+00, 1.00000e-04, 1.20000e-04, -1.03300e-02,
1.20000e-04, -1.03800e-02, -1.05600e-02, 1.03047e+00]])

読み出しエラーの緩和を実行

readout_mitigationを呼び出すことで、エラーが軽減されたカウントを得ることができます。

from quri_parts.algo.mitigation.readout_mitigation import readout_mitigation

mitigated_counts = readout_mitigation([counts], filter_matrix)
next(mitigated_counts)
#output
{0: 5062.934660510149,
4: 0.7909420515811665,
5: 3.290159602996353,
7: 4946.536432906023}

読み出しエラー緩和サンプラーの作成

また、ノイズあり回路からサンプリングし、裏側で読み出しエラーの緩和を行うConcurrentSamplerを作成することもできます。

from quri_parts.algo.mitigation.readout_mitigation import (
create_readout_mitigation_concurrent_sampler,
create_readout_mitigation_sampler,
)
from quri_parts.qulacs.sampler import create_qulacs_density_matrix_sampler

# Create a ConcurrentSampler
rem_concurrent_sampler = create_readout_mitigation_concurrent_sampler(
qubit_count, concurernt_sampler, shots=1000000
)

# You can also create a Sampler
# rem_sampler = create_readout_mitigation_sampler(
# qubit_count, concurernt_sampler, shots=1000000
# )
# mitigated_counts = rem_sampler(circuit, 10000)
# print(mitigated_counts)

mitigated_counts_concurrent = rem_concurrent_sampler([(circuit, 10000)])
next(mitigated_counts_concurrent)

#output
{0: 4993.502510704794,
1: 1.0062540276240308,
2: 5.686739903778277,
3: 2.304943262678012,
4: 6.040353491108938,
6: 0.7900380906298454,
7: 4991.698210158229}