西森相転移
使用時間の目安: Heron r2 プロセッサで約3分(注: これは目安です。実際の実行時間は異なる場合があります。)
背景
このチュートリアルでは、IBM® 量子プロセッサ上で西森相転移を実現する方法を示します。この実験は、もともとRealizing the Nishimori transition across the error threshold for constant-depth quantum circuitsで説明されたものです。
西森相転移とは、ランダムボンドイジングモデルにおける短距離秩序相と長距離秩序相の間の転移を指します。量子コンピュータ上では、長距離秩序相はデバイス全体にわたって量子ビットがエンタングルされた状態として現れます。この高度にエンタングルされた状態は、測定によるエンタングルメント生成(GEM: Generation of Entanglement by Measurement)プロトコルを用いて準備されます。GEMプロトコルは、回路中間測定を利用することで、定数深さの回路のみでデバイス全体の量子ビットをエンタングルすることができます。このチュートリアルでは、GEM SuiteソフトウェアパッケージのGEMプロトコル実装を使用します。
前提条件
このチュートリアルを始める前に、以下がインストールされていることを確認してください:
- Qiskit SDK v1.0 以降(visualizationサポート付き)
- Qiskit Runtime v0.22 以降(
pip install qiskit-ibm-runtime) - GEM Suite(
pip install gem-suite)
セットアップ
# Added by doQumentation — installs packages not in the Binder environment
%pip install -q gem-suite
import matplotlib.pyplot as plt
from collections import defaultdict
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.transpiler import generate_preset_pass_manager
from gem_suite import PlaquetteLattice
from gem_suite.experiments import GemExperiment
ステップ 1: 古典的な入力を量子問題にマッピングする
GEMプロトコルは、格子で記述される量子ビット接続性を持つ量子プロセッサ上で動作します。現在のIBM量子プロセッサはヘビーヘックス格子を使用しています。プロセッサの量子ビットは、格子の単位胞のどこに位置するかに基づいてプラケットにグループ分けされます。1つの量子ビットが複数の単位胞に含まれる場合があるため、プラケットは互いに素ではありません。ヘビーヘックス格子では、1つのプラケットに12個の量子ビットが含まれます。プラケット自体も格子を形成しており、2つのプラケットが量子ビットを共有している場合に接続されます。ヘビーヘックス格子では、隣接するプラケットは3個の量子ビットを共有します。
GEM Suiteソフトウェアパッケージにおいて、GEMプロトコルを実装するための基本クラスは PlaquetteLattice です。これはプラケットの格子を表現するもので、ヘビーヘックス格子とは異なるものです。PlaquetteLattice は量子ビットの結合マップから初期化できます。現在、ヘビーヘックス結合マップのみがサポートされています。
以下のコードセルでは、IBM量子プロセッサの結合マップからプラケット格子を初期化します。プラケット格子は必ずしもハードウェア全体を網羅するわけではありません。たとえば、ibm_torino は合計133個の量子ビットを持っていますが、デバイスに収まる最大のプラケット格子は125個の量子ビットのみを使用し、合計18個のプラケットで構成されます。異なる量子ビット数を持つ他のIBM Quantum® デバイスでも同様の傾向が観察されます。
# QiskitRuntimeService.save_account(channel="ibm_quantum", token="<YOUR_API_KEYN>", overwrite=True, set_as_default=True)
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
plaquette_lattice = PlaquetteLattice.from_coupling_map(backend.coupling_map)
print(f"Number of qubits in backend: {backend.num_qubits}")
print(
f"Number of qubits in plaquette lattice: {len(list(plaquette_lattice.qubits()))}"
)
print(f"Number of plaquettes: {len(list(plaquette_lattice.plaquettes()))}")
Number of qubits in backend: 133
Number of qubits in plaquette lattice: 125
Number of plaquettes: 18
プラケット格子のグラフ表現の図を生成することで、プラケット格子を可視化できます。図中では、プラケットはラベル付きの六角形で表され、2つのプラケットが量子ビットを共有している場合に辺で結ばれます。
plaquette_lattice.draw_plaquettes()
plaquettes メソッドを使用して、個々のプラケットに含まれる量子ビットなどの情報を取得できます。
# Get a list of the plaquettes
plaquettes = list(plaquette_lattice.plaquettes())
# Display information about plaquette 0
plaquettes[0]
PyPlaquette(index=0, qubits=[0, 1, 2, 3, 4, 15, 16, 19, 20, 21, 22, 23], neighbors=[3, 1])
プラケット格子を構成する基盤となる量子ビットの図も作成できます。
plaquette_lattice.draw_qubits()

量子ビットのラベルと接続を示す辺に加えて、図にはGEMプロトコルに関連する3つの追加情報が含まれています:
- 各量子ビットは塗りつぶし(グレー)または塗りつぶしなしのいずれかです。塗りつぶされた量子ビットはイジングモデルのサイトを表す「サイト」量子ビットであり、塗りつぶされていない量子ビットはサイト量子ビット間の相互作用を媒介する「ボンド」量子ビットです。
- 各サイト量子ビットには (A) または (B) のラベルが付けられており、GEMプロトコルにおいてサイト量子ビットが果たす2つの役割のいずれかを示しています(役割については後述します)。
- 各辺は6色のうちの1色で色分けされており、辺を6つのグループに分割しています。この分割は、2量子ビットゲートの並列化方法と、ノイズの多い量子プロセッサ上で異なる量のエラーを引き起こす可能性のある異なるスケジューリングパターンを決定します。各グループ内の辺は互いに素であるため、それらの辺に対して2量子ビットゲートの層を同時に適用できます。実際には、6色を2色ずつ3つのグループに分割し、各2色グループの和集合が依然として互いに素になるようにすることが可能です。したがって、すべての辺を活性化するために必要な2量子ビットゲートの層は3層のみです。6色をこのように分割する方法は12通りあり、それぞれの分割が異なる3層のゲートスケジュールを生成します。
プラケット格子を作成したので、次のステップは GemExperiment オブジェクトを初期化することです。プラケット格子と実験を実行するバックエンドの両方を渡します。GemExperiment クラスは、回路の生成、ジョブの送信、データの分析を含むGEMプロトコルの実際の実装を管理します。以下のコードセルでは、プラケット格子を2つのプラケット(21量子ビット)のみに制限して実験クラスを初期化し、ハードウェアのノイズが信号を圧倒しないように実験のサイズを縮小しています。
gem_exp = GemExperiment(plaquette_lattice.filter([9, 12]), backend=backend)
# visualize the plaquette lattice after filtering
plaquette_lattice.filter([9, 12]).draw_qubits()

GEMプロトコル回路は、以下の手順で構築されます:
- すべての量子ビットにアダマールゲートを適用して、全 状態を準備します。
- 接続されたすべての量子ビットペアの間に ゲートを適用します。 これは3層のゲートで実現できます。各 ゲートはサイト量子ビットとボンド量子ビットに作用します。サイト量子ビットのラベルが (B) の場合、角度は に固定されます。サイト量子ビットのラベルが (A) の場合、角度は可変であり、異なる回路を生成します。デフォルトでは、角度の範囲は から までの両端を含む等間隔の21点に設定されています。
- 各ボンド量子ビットをパウリ 基底で測定します。量子ビットはパウリ 基底で測定されるため、測定前にアダマールゲートを適用することでこれを実現できます。
このチュートリアルの冒頭で引用した論文では、 角度に異なる規約を使用しており、このチュートリアルで使用する規約とは2倍の係数が異なることに注意してください。
ステップ3では、ボンド量子ビットのみが測定されます。サイト量子ビットがどのような状態に残されるかを理解するために、ステップ2でサイト量子ビット (A) に適用される 角度が に等しい場合を考えると有益です。この場合、サイト量子ビットはGHZ状態に類似した高度にエンタングルされた状態に置かれます。
測定結果のランダム性により、サイト量子ビットの実際の状態は、たとえば のような、長距離秩序を持つ別の状態になる場合があります。しかし、測定結果に基づくデコード操作を適用することで、GHZ状態を回復できます。 角度を から小さくしていくと、臨界角度まで長距離秩序を回復できます。ノイズがない場合、臨界角度は約 です。この角度を下回ると、得られる状態は長距離エンタングルメントを示さなくなります。この長距離秩序の 有無の間の転移が、西森相転移です。
上記の説明では、サイト量子ビットは測定されずに残され、デコード操作は量子ゲートを適用することで実行できます。このチュートリアルが従うGEM Suiteで実装された実験では、実際にはサイト量子ビットも測定され、デコード操作は古典的な後処理ステップで適用されます。
上記の説明では、デコード操作はサイト量子ビットに量子ゲートを適用して量子状態を回復することで実行できます。しかし、たとえば特性評価の目的で状態を直ちに測定することが目的の場合、サイト量子ビットはボンド量子ビットとともに測定され、デコード操作は古典的な後処理ステップで適用できます。これがGEM Suiteでの実験の実装方法であり、このチュートリアルはこれに従います。
ステップ2の 角度(デフォルトでは21個の値をスイープ)に加えて、GEMプロトコル回路は ゲートの3層を実装するために使用されるスケジューリングパターンにも依存します。前述のとおり、このようなスケジューリングパターンは12通りあります。したがって、実験の回路総数は です。
実験の回路は、GemExperiment クラスの circuits メソッドを使用して生成できます。
circuits = gem_exp.circuits()
print(f"Total number of circuits: {len(circuits)}")
Total number of circuits: 252
このチュートリアルでは、単一のスケジューリングパターンのみを考慮すれば十分です。以下のコードセルでは、実験を最初のスケジューリングパターンに制限します。その結果、実験にはスイープされる各 角度に1つずつ、合計21個の回路のみが含まれます。
# Restrict experiment to the first scheduling pattern
gem_exp.set_experiment_options(schedule_idx=0)
# There are less circuits now
circuits = gem_exp.circuits()
print(f"Total number of circuits: {len(circuits)}")
# Print the RZZ angles swept over
print(f"RZZ angles:\n{gem_exp.parameters()}")
Total number of circuits: 21
RZZ angles:
[0. 0.07853982 0.15707963 0.23561945 0.31415927 0.39269908
0.4712389 0.54977871 0.62831853 0.70685835 0.78539816 0.86393798
0.9424778 1.02101761 1.09955743 1.17809725 1.25663706 1.33517688
1.41371669 1.49225651 1.57079633]
以下のコードセルでは、インデックス5の回路の図を描画します。図のサイズを縮小するため、回路末尾の測定ゲートは除去されています。
# Get the circuit at index 5
circuit = circuits[5]
# Remove the final measurements to ease visualization
circuit.remove_final_measurements()
# Draw the circuit
circuit.draw("mpl", fold=-1, scale=0.5)
ステップ 2: 量子ハードウェア実行のための問題の最適化
量子回路をハードウェア上で実行するためのトランスパイルには、通常複数のステージが含まれます。一般的に、最も計算コストがかかるステージは、量子ビットレイアウトの選択、ハードウェアの量子ビット接続性に合わせた2量子ビットゲートのルーティング、およびゲート数と深さを最小化するための回路最適化です。GEMプロトコルでは、ハードウェアの接続性がすでにプロトコルの設計に組み込まれているため、レイアウトとルーティングのステージは不要です。回路にはすでに量子ビットレイアウトがあり、2量子ビットゲートはすでにネイティブ接続にマッピングされています。さらに、 角度を変化させる際に回路の構造を保持するため、ごく基本的な回路最適化のみを実行する必要があります。
GemExperiment クラスは、実験の実行時に回路を透過的にトランスパイルします。レイアウトとルーティングのステージはデフォルトで何もしないようにオーバーライドされており、回路最適化は単一量子ビットゲートのみを最適化するレベルで実行されます。ただし、set_transpile_options メソッドを使用して、オーバーライドしたり追加のオプションを渡したりすることができます。可視化のため、以下のコードセルでは前に表示した回路を手動でトランスパイルし、トランスパイル後の回路を描画します。
# Demonstrate setting transpile options
gem_exp.set_transpile_options(
optimization_level=1 # This is the default optimization level
)
pass_manager = generate_preset_pass_manager(
backend=backend,
initial_layout=list(gem_exp.physical_qubits),
**dict(gem_exp.transpile_options),
)
transpiled = pass_manager.run(circuit)
transpiled.draw("mpl", idle_wires=False, fold=-1, scale=0.5)

ステップ 3: Qiskitプリミティブを使用した実行
GEMプロトコル回路をハードウェア上で実行するには、GemExperiment オブジェクトの run メソッドを呼び出します。各回路からサンプリングするショット数を指定できます。run メソッドは ExperimentData オブジェクトを返しますので、これを変数に保存してください。run メソッドはジョブの送信のみを行い、完了を待たないため、ノンブロッキング呼び出しであることに注意してください。
exp_data = gem_exp.run(shots=10_000)
結果を待つには、ExperimentData オブジェクトの block_for_results メソッドを呼び出します。この呼び出しにより、ジョブが完了するまでインタープリタはブロックされます。
exp_data.block_for_results()
ExperimentData(GemExperiment, d0d5880a-34c1-4aab-a7b6-c4f58516bc03, job_ids=['cwg12ptmptp00082khhg'], metadata=<5 items>, figure_names=['two_point_correlation.svg', 'normalized_variance.svg', 'plaquette_ops.svg', 'bond_ops.svg'])
ステップ 4: 後処 理と所望の古典形式での結果の返却
角度が の場合、ノイズがなければデコードされた状態はGHZ状態になります。GHZ状態の長距離秩序は、測定されたビット列の磁化をプロットすることで可視化できます。磁化 は、単一量子ビットのパウリ 演算子の和として定義されます。
ここで はサイト量子ビットの数です。ビット列に対するその値は、0の数と1の数の差に等しくなります。GHZ状態を測定すると、全ゼロ状態または全1状態が等確率で得られるため、磁化は半分の確率で 、もう半分の確率で となります。ノイズによるエラーが存在する場合、他の値も現れますが、ノイズが大きすぎなければ、分布は依然として と の近くにピークを持ちます。
デコード前の生のビット列については、ノイズがない場合、磁化の分布は一様ランダムなビット列の分布と等価になります。
以下のコードセルでは、 角度が の場合の生のビット列とデコードされたビット列の磁化をプロットします。
def magnetization_distribution(
counts_dict: dict[str, int],
) -> dict[str, float]:
"""Compute magnetization distribution from counts dictionary."""
# Construct dictionary from magnetization to count
mag_dist = defaultdict(float)
for bitstring, count in counts_dict.items():
mag = bitstring.count("0") - bitstring.count("1")
mag_dist[mag] += count
# Normalize
shots = sum(counts_dict.values())
for mag in mag_dist:
mag_dist[mag] /= shots
return mag_dist
# Get counts dictionaries with and without decoding
data = exp_data.data()
# Get the last data point, which is at the angle for the GHZ state
raw_counts = data[-1]["counts"]
# Without decoding
site_indices = [
i for i, q in enumerate(gem_exp.plaquettes.qubits()) if q.role == "Site"
]
site_raw_counts = defaultdict(int)
for key, val in raw_counts.items():
site_str = "".join(key[-1 - i] for i in site_indices)
site_raw_counts[site_str] += val
# With decoding
_, site_decoded_counts = gem_exp.plaquettes.decode_outcomes(
raw_counts, return_counts=True
)
# Compute magnetization distribution
raw_magnetization = magnetization_distribution(site_raw_counts)
decoded_magnetization = magnetization_distribution(site_decoded_counts)
# Plot
plt.bar(*zip(*raw_magnetization.items()), label="raw")
plt.bar(*zip(*decoded_magnetization.items()), label="decoded", width=0.3)
plt.legend()
plt.xlabel("Magnetization")
plt.ylabel("Frequency")
plt.title("Magnetization distribution with and without decoding")
Text(0.5, 1.0, 'Magnetization distribution with and without decoding')
長距離秩序をより厳密に特性評価するために、平均2点相関 を調べることができます。これは以下のように定義されます。
値が大きいほど、エンタングルメントの度合いが高いことを示します。GemExperiment クラスは、実験データの処理の一部として、デコードされたビット列に対してこの値を自動的に計算します。計算結果は、実験データクラスの figure メソッドを介してアクセスできる図として保存されます。この場合、図の名前は two_point_correlation です。
exp_data.figure("two_point_correlation")
西森相転移の臨界点を決定するには、 の正規化分散を調べます。これは以下のように定義されます。
これは二乗磁化の揺らぎの量を定量化します。この値は西森相転移の臨界点で最大になります。ノイズがない場合、臨界点は約 で発生します。ノイズが存在する場合、臨界点はより高い値にシフトしますが、臨界点が 以下で発生する限り、相転移は依然として観測されます。
exp_data.figure("normalized_variance")
実験のスケールアップ
以下のコードセルでは、6プラケット(49量子ビット)および全18プラケット(125量子ビット)で実験を実行し、正規化分散をプロットします。実験をより大きなサイズにスケールアップすると、ノイズの増加により臨界点が右方向にシフトします。
gem_exp = GemExperiment(
plaquette_lattice.filter(range(3, 9)), backend=backend
)
gem_exp.set_experiment_options(schedule_idx=0)
exp_data = gem_exp.run(shots=10_000)
exp_data.block_for_results()
exp_data.figure("normalized_variance")
gem_exp = GemExperiment(plaquette_lattice, backend=backend)
gem_exp.set_experiment_options(schedule_idx=0)
exp_data = gem_exp.run(shots=10_000)
exp_data.block_for_results()
exp_data.figure("normalized_variance")
まとめ
このチュートリアルでは、GEMプロトコルを使用して量子プロセッサ上で西森相転移を実現しました。後処理で調べた指標、特に2点相関と正規化分散は、デバイスが長距離エンタングル状態を生成する能力のベンチマークとして機能します。これらのベンチマークは、GEMプロトコルの有用性を興味深い物理の探究を超えて拡張するものです。プロトコルの一部として、定数深さの回路のみを使用してデバイス全体の量子ビットをエンタングルしました。この偉業は、プロトコルが回路中間測定を使用することで初めて可能になります。この実験ではエンタングル状態は直ちに測定されましたが、その状態をさらなる量子処理に引き続き使用することは、探究すべき興味深い方向性です。
チュートリアルアンケート
このチュートリアルに関するフィードバックをお寄せいただくため、簡単なアンケートにご協力ください。皆様のご意見は、コンテンツの提供内容とユーザーエクスペリエンスの向上に役立てさせていただきます。