メインコンテンツへスキップ
このプロジェクトはベータ版です。バグを見つけましたか?GitHub Issueを開く。質問やアイデアがありますか?Discussionsで質問する — フィードバックをお待ちしています!
このページの翻訳品質はいかがですか?

shaded lightcone 可視化の解釈方法

このパッケージは、shaded lightcone を見る 2 つの方法を提供します。

  • draw_shaded_lightcone は、バウンドを回路図に重ねて表示します。回路図と物理的なレイアウトが一致する、1D の量子ビット鎖上の回路に最適です。

  • animate_shaded_lightcone は、バウンドを QPU のカップリングマップに投影し、回路をレイヤーごとに進めます。量子ビットの接続が 1D の線より複雑で、回路図ではどの量子ビットが隣接しているかが伝わらなくなる場合に最適です。

どちらの可視化も、同じ基礎となる数値を示します。このガイドでは、それらの数値が何を意味するかを説明し、読み間違えやすい詳細について解説します。

セットアップ​

クイックスタートガイドと同じ Trotter 化された Ising 回路とオブザーバブルを使用します。

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_slc": "qiskit-addon-slc", "samplomatic": "samplomatic"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Pauli, PauliLindbladMap, QubitSparsePauliList
from qiskit_addon_slc.bounds import (
compute_backward_bounds,
compute_forward_bounds,
merge_bounds,
)
from qiskit_addon_slc.utils import generate_noise_model_paulis
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic.utils import find_unique_box_instructions

def trotter_ising_circuit(num_qubits, num_steps, rx_angle, rzz_angle):
"""Trotterized transverse-field Ising evolution on a 1D chain."""
circuit = QuantumCircuit(num_qubits)
for _ in range(num_steps):
circuit.rx(rx_angle, range(num_qubits))
circuit.barrier()
for start in (0, 1): # even then odd bonds
for i in range(start, num_qubits - 1, 2):
circuit.rzz(rzz_angle, i, i + 1)
circuit.barrier()
return circuit

num_qubits = 10
circuit = trotter_ising_circuit(
num_qubits, num_steps=4, rx_angle=np.pi / 16, rzz_angle=-np.pi / 3
)
observable = Pauli("I" * num_qubits).compose("Z", [num_qubits // 2])

boxing_pass = generate_boxing_pass_manager(
inject_noise_targets="all",
inject_noise_strategy="individual_modification",
inject_noise_site="after",
twirling_strategy="active",
remove_barriers="never",
)
boxed_circuit = boxing_pass.run(circuit)
noise_model_paulis = generate_noise_model_paulis(
find_unique_box_instructions(boxed_circuit)
)

forward_bounds = compute_forward_bounds(
boxed_circuit, noise_model_paulis, observable
)
backward_bounds = compute_backward_bounds(boxed_circuit, noise_model_paulis)

rng = np.random.default_rng(42)
noise_rates = {
layer: PauliLindbladMap.from_components(
rng.random(len(terms)) * 5e-3,
QubitSparsePauliList.from_sparse_list(
terms.to_sparse_list(), terms.num_qubits
),
)
for layer, terms in noise_model_paulis.items()
}
merged_bounds = merge_bounds(
boxed_circuit, forward_bounds, backward_bounds, noise_rates
)
print(f"observable: Z on qubit {num_qubits // 2}")
Optimal spacetime partitioning not implemented! Just partitioning list of noisy boxes.
observable: Z on qubit 5

draw_shaded_lightcone​

ノイズを持つ各ボックスは、そこで発生するエラーに対するバウンドに応じて色付けされます。明るいものは大きなバウンドを意味し、背景に溶け込むボックスは、そのエラーがオブザーバブルにほとんど影響しないことを意味します。これらの薄くなったボックスは、緩和されるノイズモデルから除外する候補です。

from qiskit_addon_slc.visualization import draw_shaded_lightcone

draw_shaded_lightcone(
boxed_circuit, merged_bounds, noise_model_paulis, fold=-1, scale=0.5
)

Output of the previous code cell

重要な注意点​

1. 各数値は、同じサポートを共有するエラー項の合計です。 フィルターがない場合、同じ量子ビット、または同じ量子ビットのペアに作用するすべてのエラー項のバウンドが 1 つの値に加算されます。つまり、量子ビット上の 3 種類すべての Pauli、およびペア上の 9 種類すべてです。これには 2 つの帰結があります。値が 2.0 を超えることがあります。単一の項のバウンドは超えられないにもかかわらずです(4.5 と表示されたボックスは、複数の項が加算されたものであり、バウンドの違反ではありません)。また、図からは、大きな値が 1 種類の Pauli によるものか、同程度の複数の種類によるものかを判別できません。次のセクションで、それらを分離する方法を示します。

2. カラースケールは 2.0 から始まり、データに合わせて拡大します。 スケールは 0 から、重ねて表示された回路のメタデータの "max_bound" エントリまでで、これは 2.0 と表示された最大値のうち大きい方です。フィルターなしの合計はしばしば 2.0 を超えるため、スケールはそれに合わせて広がり、同じ色が図によって異なる値を表すことがあります。すべての値が小さい場合、スケールは 2.0 のままで、すべてが一様に暗く見えます(これは絶対的な大きさを反映したスケールであり、描画の不具合ではありません)。

Pauli の種類を分離する​

pauli_filter を使用すると、一度に 1 種類ずつ表示できます。整数は Pauli ウェイトを選択し、文字列は、各ノイズ項をそれ自身の非恒等サポートに縮約したものと照合して特定の Pauli を選択します。したがって "X" は、どの量子ビットに作用するかにかかわらず、すべての単一量子ビット XX エラーを選択し、"XX" はウェイト 2 のものを選択します("XII" のような全幅のラベルは何にも一致しません)。

from qiskit_addon_slc.visualization import accumulate_filtered_bounds

box_id = next(iter(merged_bounds))
print(f"single-qubit supports of box {box_id!r}:\n")
print(f"{'filter':>8} bounds per qubit")
for pauli_filter in (None, 1, "X", "Y", "Z"):
filtered = accumulate_filtered_bounds(
boxed_circuit, merged_bounds, noise_model_paulis, pauli_filter
)
per_qubit = {
support[0]: round(float(bound), 3)
for support, bound in sorted(filtered[box_id].items())
if len(support) == 1
}
print(f"{pauli_filter!s:>8} {per_qubit}")
single-qubit supports of box 'm0':

filter bounds per qubit
None {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.312, 4: 1.355, 5: 5.111, 6: 1.506, 7: 0.124, 8: 0.019, 9: 0.0}
1 {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.312, 4: 1.355, 5: 5.111, 6: 1.506, 7: 0.124, 8: 0.019, 9: 0.0}
X {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.153, 4: 0.577, 5: 2.0, 6: 0.702, 7: 0.056, 8: 0.01, 9: 0.0}
Y {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.148, 4: 0.607, 5: 2.0, 6: 0.631, 7: 0.057, 8: 0.01, 9: 0.0}
Z {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.011, 4: 0.172, 5: 1.111, 6: 0.172, 7: 0.011, 8: 0.0, 9: 0.0}

フィルターなしの行は、その下の 3 種類の Pauli の合計です。フィルタリングは、フィルターなしの大きな値が 1 つの支配的なエラーの種類によるものか、同程度の複数の種類によるものかを見分ける唯一の方法です。緩和は、サイトごとではなく項ごとに作用するため、これは重要です。

同じフィルターを draw_shaded_lightcone に渡すと、図のタイトルに記録されるため、フィルター付きの図をフィルターなしの図と取り違えることはありません。

draw_shaded_lightcone(
boxed_circuit,
merged_bounds,
noise_model_paulis,
pauli_filter="X",
fold=-1,
scale=0.5,
)

Output of the previous code cell

この図は、上のフィルターなしの図とはかなり異なって見えますが、それは表示される値が少ないからだけではありません。これらの図の各プレースホルダーは 1 つのサポート、つまり単一の量子ビット、または量子ビットのペアを表します。フィルターがない場合、ボックスはすべての量子ビットとすべての隣接する量子ビットのペアにプレースホルダーを表示するため、複数の列にまたがります。"X" を指定すると、単一量子ビットのサポートだけが残り、各ボックスは 1 列に縮小します。

ただし、どちらの図もPECが実際に適用するものを示しているわけではありません。プレースホルダーは上界を表示するための手段であり、ノイズ打ち消しゲートではありません。実験中は、エラー項が緩和されるすべてのボックスが2量子ビットゲートの単一レイヤーとして扱われ、そのエラー項のためにサンプリングされたノイズ打ち消し用パウリは、1つのパウリに合成されて、そのレイヤー全体に適用されます。

animate_shaded_lightcone​

接続性が1次元の線ではないデバイスでは、回路図を見ても、どの量子ビットが隣り合っているかがわからなくなるため、ライトコーンの空間的な広がりを読み取れなくなります。そこでanimate_shaded_lightconeは、QPUのカップリングマップを描画し、その上で上界をアニメーション表示します。1フレームにつき、ノイズのあるボックスを1つ表示します。

CouplingMapが必要です。デバイスのグラフを埋め込むことでグリッド上に配置するため、ヘビーヘックス接続と正方格子接続の両方に対応できます。

注意: このレンダリング済みドキュメントでは、アニメーションは静止画です。スライダーと再生ボタンは、Jupyterなどでノートブックをインタラクティブに実行した場合にのみ動作します。

from qiskit import transpile
from qiskit.transpiler import CouplingMap
from qiskit_addon_slc.visualization import animate_shaded_lightcone

# A small square-lattice device stands in for a real backend here.
coupling_map = CouplingMap.from_grid(3, 4)

# Lay the chain onto a connected path of physical qubits, snaking through the grid, so the
# transpiler inserts no SWAPs: a SWAP-laden circuit is far more expensive to bound and harder to
# read.
initial_layout = [0, 1, 2, 3, 7, 6, 5, 4, 8, 9]
device_circuit = transpile(
circuit,
coupling_map=coupling_map,
initial_layout=initial_layout,
optimization_level=0,
)
boxed_device_circuit = boxing_pass.run(device_circuit)
device_noise_paulis = generate_noise_model_paulis(
find_unique_box_instructions(boxed_device_circuit),
coupling_map=coupling_map,
circuit=boxed_device_circuit,
)
# The same observable, on the physical qubit the middle of the chain was laid onto.
device_observable = Pauli("I" * device_circuit.num_qubits).compose(
"Z", [initial_layout[num_qubits // 2]]
)
device_bounds = compute_forward_bounds(
boxed_device_circuit, device_noise_paulis, device_observable
)

animate_shaded_lightcone(boxed_device_circuit, device_bounds, coupling_map)

Output of the previous code cell

アニメーションの読み方​

各量子ビットは円グラフで、パウリの種類ごとに1つのスライスがあります。 量子ビットのマーカーは、XX、YY、ZZエラーに対応する3つのスライスに分割され、それぞれが固有の上界に応じて色付けされます。これは前のセクションのフィルタリングを図に組み込んだものです(種類を区別するためにpauli_filterは不要です)。

エッジは2量子ビットエラーの上界を表します。 結合された2つの量子ビット間の線は、そのペアに作用する重み2のエラーの上界に応じて色付けされます。

薄いグレーは小さな上界ではなく、データなしを意味します。 ボックスのノイズモデルにそのスライスやエッジに対応するエラー項がない場合(たとえば、ボックスが作用しない量子ビットの場合)、スライスまたはエッジは薄いグレーで描画されます。ゼロの上界と混同されないよう、濃い色ではなくグレーで描画されます。max_num_boxesの上限を超えたボックスは異なります。これらは自明な上界である2.0を持つため、スケールの明るい側の端で描画されます。

スライダーはボックス単位で進み、時間を均等に進めるわけではありません。 ノイズのあるボックスごとに1フレームがあり、回路の順序で進みます(reverse=Trueを指定すると逆順になり、オブザーバブルからライトコーンを逆向きにたどります)。逆順で見るほうが直感的なことが多く、測定された量子ビットから外側へコーンが広がっていきます。各フレームにはそのボックスの識別子が表示されます。これは、上界の辞書がそのボックスを格納するときのキーと同じものなので、スライダーを使って特定のボックスに移動し、その数値を調べることもできます。

注意: 量子ビットのレイアウトは、カップリングマップのグラフを正方格子に埋め込むことで復元されます。埋め込めないカップリングマップ(非連結である場合や、格子にしては接続が密すぎる場合)では、誤解を招く図を描画するのではなくValueErrorが発生します。

どちらを使うか​

draw_shaded_lightconeanimate_shaded_lightcone
幾何回路図QPUのカップリングマップ
最適な用途1次元チェーン任意の接続性
パウリの種類フィルタしない限り合算常に円グラフのスライスとして分割
時間すべてのレイヤーを一度に表示1フレームにつき1レイヤー
出力matplotlibの図plotlyの図

1次元チェーンでは、静止画のほうが一目で把握しやすく、論文にも再現しやすいです。1次元を超える場合は、2つのうち空間構造を正確に示せるのはアニメーションだけです。