Skip to main content
IBM Quantum Platform

ワークロードでポストセレクションを使用する

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

    qiskit[all]~=2.5.1
    qiskit-ibm-runtime~=0.47.0
    qiskit-addon-utils~=0.4.0
    

ワークロードのエラー軽減戦略を最適化する際、非マルコフ的(相関のある)ノイズ過程によって汚染されていることが分かっている測定値をフィルタリングすることが、しばしば有用である。 そのための手法の一つとして、回路の最後に後処理ステップを追加する方法がある。このステップでは、アクティブな量子ビットと隣接する「傍観者」量子ビットを測定し、各量子ビットに緩やかな回転を適用した後、再度測定を行う。 2つの測定結果が予想通り反転した量子ビットであることを確認できない場合、結果にマスクを適用してそのショットを破棄する。

Qiskitアドオンユーティリティパッケージは、一連のトランスパイラパスと、マスクを適用するためのポストセレクション関数を提供します。 このページでは、4量子ビットのGHZ状態を例に、量子ワークロードにポストセレクションを組み込む方法について解説します。


CREATE WORKLOAD

まず、小数点演算ゲートをサポートするバックエンドに対して実行およびトランスパイルを行うための回路を準備します。

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager

circuit = QuantumCircuit(4)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.cx(2, 3)
circuit.measure_all()


service = QiskitRuntimeService()
backend = service.least_busy(use_fractional_gates=True)
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)

transpiled_circuit = pm.run(circuit)
transpiled_circuit.draw("mpl")

Output:

Output of the previous code cell

ポストセレクション・トランスパイラ・パスを追加する

次に、パッケージ qiskit-addon-utils 内の および AddSpectatorMeasures パスを AddPostSelectionMeasures 含むプリセット・パス・マネージャーを作成します。 これにより、回路に一連の微小な角度 RX の回転(実質的に長い X ゲートを形成する)が追加され、さらに2つ目の測定セットが実行されます。

from qiskit.transpiler import PassManager
from qiskit_addon_utils.noise_management.post_selection import PostSelector
from qiskit_addon_utils.noise_management.post_selection.transpiler.passes import (
    AddPostSelectionMeasures,
    AddSpectatorMeasures,
)


post_selection_pm = PassManager(
    [
        AddSpectatorMeasures(backend.coupling_map, add_barrier=True),
        AddPostSelectionMeasures(x_pulse_type="rx"),
    ]
)

template_circuit_ps = post_selection_pm.run(transpiled_circuit)
template_circuit_ps.draw("mpl", fold=-1, idle_wires=False)

Output:

Output of the previous code cell

量子プログラムを実行する

次に、実行する回路を含むオブジェクト QuantumProgram を用意します。

from qiskit_ibm_runtime import QuantumProgram, Executor

shots = 4000

program = QuantumProgram(shots=shots)
program.append_circuit_item(template_circuit_ps)

# Initialize the Executor job and run
executor = Executor(backend)
executor_job = executor.run(program)
print(f"Job ID: {executor_job.job_id()}")

Output:

Job ID: d9mqa4fbupns73e942q0

これで結果の解釈が可能になります。 実行結果は、いくつかのキーを持つ辞書となります。

executor_result = executor_job.result()[0]
executor_result.keys()

Output:

KeysView(QuantumProgramItemResult({'meas': array([[False, False, False, False],
       [ True,  True,  True,  True],
       [False, False, False, False],
       ...,
       [ True,  True,  True,  True],
       [ True,  True,  True,  True],
       [False, False, False, False]], shape=(4000, 4)), 'spec': array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False],
       ...,
       [False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]], shape=(4000, 4)), 'meas_ps': array([[ True,  True,  True,  True],
       [False, False, False, False],
       [ True,  True,  True,  True],
       ...,
       [False, False,  True, False],
       [False, False, False, False],
       [ True,  True,  True,  True]], shape=(4000, 4)), 'spec_ps': array([[ True,  True,  True,  True],
       [ True,  True,  True,  True],
       [ True,  True, False,  True],
       ...,
       [ True,  True,  True,  True],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True]], shape=(4000, 4))}, metadata=ItemMetadata()))

spec_ps``specこれらのキーは、命令 rxmeas および)実行前のアクティブ量子ビットおよびスペクテーター量子ビット、ならびに命令 rxmeas_ps および)実行後のアクティブ量子ビットおよびスペクテーター量子ビットに対応しています。 これらはそれぞれ、ショット数と量子ビット数に基づいた配列の配列です。 この場合、形状は (1000, 4) です。


ポストセレクションマスクを作成する

qiskit-addon-utilsこれらの測定値をもとに、の PostSelector クラスを使用してマスクを作成できます。 このマスクはブール配列であり、各ショットは2つのポストセレクション戦略のいずれかに基づいて、または False``True としてマークされます。 edge``node最初の戦略は、量子ビットの情報を利用して測定ショットを破棄すべきかどうかを判断するものであり、2つ目の戦略は、最近接の接続情報を利用してこの判断を行うものである。

post_selector = PostSelector.from_circuit(
    circuit=template_circuit_ps, coupling_map=backend.coupling_map
)

mask_node = post_selector.compute_mask(executor_result, strategy="node")
mask_edge = post_selector.compute_mask(executor_result, strategy="edge")

ノード戦略とエッジ戦略のどちらも、しばしば異なるショットを破棄することがある。 どれでもお選びいただけます。 このノートブックではビット単位のAND演算を採用しています。これは、ノード戦略とエッジ戦略の両方で通過判定されたショットのみを保持するという、保守的な戦略です。

mask = mask_node & mask_edge
print(f"The combined mask: {mask}")
count_retained = 0

for m in mask:
    count_retained += m

print(
    f"Percentage of the shots retained is after post selection "
    f"{100 * count_retained / shots}"
)

Output:

The combined mask: [ True  True False ... False  True  True]
Percentage of the shots retained is after post selection 70.35

事後選択を行う場合と行わない場合で、確率分布を比較してください。 以下のコードスニペットは、ポストセレクションの前後における確率分布を計算するとともに、観測された分布と理想的な分布との間の距離を算出します。

counts = {}
counts_ps = {}


for idx, measurement in enumerate(executor_result["meas"]):
    bitstring = ""
    for bit in measurement:
        bitstring += str(int(bit))

    if bitstring in counts:
        counts[bitstring] += 1
    else:
        counts[bitstring] = 1

    # Compute count data for postselected shots based on the mask
    if mask[idx]:
        bitstring = ""
        for bit in measurement:
            bitstring += str(int(bit))

        if bitstring in counts_ps:
            counts_ps[bitstring] += 1
        else:
            counts_ps[bitstring] = 1

for key, val in counts.items():
    counts[key] = val / shots


for key, val in counts_ps.items():
    counts_ps[key] = float(val / count_retained)

事後選択が結果にどのような影響を与えたかを確認するために、理想的な確率分布と測定された確率分布との間の距離を計算してください。

import itertools
from qiskit.visualization import plot_histogram

bitstrings = ["".join(i) for i in itertools.product("01", repeat=4)]
counts_ideal = {}
for bitstring in bitstrings:
    counts_ideal[bitstring] = 0.0
counts_ideal["1111"] = 0.5
counts_ideal["0000"] = 0.5


prob_distance = 0.0
prob_distance_ps = 0.0

for bitstring in counts_ideal.keys():
    dist = 0.0
    dist_ps = 0.0
    if bitstring in counts:
        dist = abs(counts[bitstring] - counts_ideal[bitstring])
    if bitstring in counts_ps:
        dist_ps = abs(counts_ps[bitstring] - counts_ideal[bitstring])
    prob_distance += dist
    prob_distance_ps += dist_ps


print(
    f"Distance from ideal distribution before postselection: "
    f"{1-prob_distance*0.5}"
)
print(
    f"Distance from ideal distribution before after-selection: "
    f"{1-prob_distance_ps*0.5}"
)


plot_histogram([counts, counts_ps], legend=["Normal", "Post selected"])

Output:

Distance from ideal distribution before postselection: 0.95225
Distance from ideal distribution before after-selection: 0.939587775408671
Output of the previous code cell

事後選択は、非マルコフ的ノイズの影響を受けた結果測定値を排除することで結果の質を大幅に向上させることができるが、それだけでは誤差低減の完全な解決策とはならない。 事後選択は、無効な測定結果を排除することで特定のエラーの影響を軽減するが、その代償としてサンプリングのオーバーヘッドが増大し、また、近未来の量子ハードウェアに存在するすべてのエラーメカニズムに対処できるわけではない。 その結果、より複雑あるいは深層の回路においては、ポストセレクションのみに依存するだけでは不十分であると考えられる。 むしろ、ポストセレクションは、測定誤差の低減、ノイズを考慮した回路コンパイル、確率的誤差相殺といった手法を補完する形で、より広範な誤差低減戦略の一環として活用される場合に最も効果的であり、精度とリソースコストのバランスを取りながら量子ワークロードの信頼性を向上させることができる。


次のステップ

推奨事項
  • ノイズ学習を量子ワークロードに組み込む方法を理解する。
  • 利用可能なその他のエラー軽減および抑制手法について確認してください。
  • オーバーヘッドの少ないエラー検出手法として、 時空間符号を活用する方法について学びましょう
このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。