メインコンテンツへスキップ

西森相転移

使用時間の目安: Heron r2 プロセッサで約3分(注: これは目安です。実際の実行時間は異なる場合があります。)

学習成果

このチュートリアルを通じて、ユーザーは以下の成果を期待できます:

  • 西森相転移とは何か、そしてそれがランダムボンドイジングモデルにおける長距離エンタングルメントの出現としてどのように現れるかを理解する。
  • 回路中間測定と定数深さ回路を使用して、量子ハードウェア上で測定によるエンタングルメント生成(GEM)プロトコルを実装する。
  • 実験データから2点相関と磁化の正規化分散を抽出することで、相転移を特性評価する。

前提条件

このチュートリアルを進める前に、以下のトピックに精通していることを推奨します:

背景

このチュートリアルでは、量子プロセッサ上で西森相転移を実現する方法を示します。この実験は、もともとRealizing the Nishimori transition across the error threshold for constant-depth quantum circuitsで説明されたものです。

西森相転移とは、ランダムボンドイジングモデルにおける短距離秩序相と長距離秩序相の間の転移を指します。量子コンピュータ上では、長距離秩序相はデバイス全体にわたってQubitがエンタングルされた状態として現れます。この高度にエンタングルされた状態は、測定によるエンタングルメント生成(GEM)プロトコルを用いて準備されます。GEMプロトコルは、回路中間測定を利用することで、定数深さの回路のみでデバイス全体のQubitをエンタングルすることができます。このチュートリアルでは、GEM SuiteソフトウェアパッケージのGEMプロトコル実装を使用します。

要件

このチュートリアルを始める前に、以下がインストールされていることを確認してください:

  • Qiskit SDK v1.0 以降(visualizationサポート付き)
  • Qiskit Runtime v0.22 以降(pip install qiskit-ibm-runtime
  • Qiskit Aer v0.14 以降(pip install qiskit-aer
  • GEM Suite(pip install gem-suite

セットアップ

# Added by doQumentation — required packages for this notebook
!pip install -q gem-suite matplotlib qiskit qiskit-aer qiskit-ibm-runtime
import matplotlib.pyplot as plt
import warnings

from collections import defaultdict

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_aer import AerSimulator

from qiskit.transpiler import generate_preset_pass_manager

from gem_suite import PlaquetteLattice
from gem_suite.experiments import GemExperiment

小規模シミュレーターの例

このセクションでは、ノイズのない AerSimulator を使用して完全なワークフローを実行します。プラケット格子は1つのプラケット(12 Qubit)に制限されているため、シミュレーションは小さく高速に保たれますが、GEMプロトコルのすべての部分(回路中間測定、RZZR_{ZZ} 角度スイープ、デコード、正規化分散分析)を実行します。同じワークフローは、後で複数のプラケットと実際のハードウェア上の完全な格子にスケールアップされます。

ステップ 1: 古典的な入力を量子問題にマッピングする

GEMプロトコルは、格子で記述されるQubit接続性を持つ量子プロセッサ上で動作します。現在のIBM Quantum®プロセッサはヘビーヘックス格子を使用しています。プロセッサのQubitは、格子の単位胞のどこに位置するかに基づいてプラケットにグループ分けされます。1つのQubitが複数の単位胞に含まれる場合があるため、プラケットは互いに素ではありません。ヘビーヘックス格子では、1つのプラケットに12個のQubitが含まれます。プラケット自体も格子を形成しており、2つのプラケットがQubitを共有している場合に接続されます。ヘビーヘックス格子では、隣接するプラケットは3個のQubitを共有します。

GEM Suiteソフトウェアパッケージにおいて、GEMプロトコルを実装するための基本クラスは PlaquetteLattice です。これはプラケットの格子を表現するもので(ヘビーヘックス格子とは異なります)、Qubitの結合マップから初期化できます。現在、ヘビーヘックス結合マップのみがサポートされています。

以下のコードセルでは、量子処理ユニット(QPU)の結合マップからプラケット格子を初期化します。プラケット格子は必ずしもハードウェア全体を網羅するわけではありません。たとえば、ibm_torino は合計133個のQubitを持っていますが、デバイスに収まる最大のプラケット格子は125個のQubitのみを使用し、合計18個のプラケットで構成されます。ibm_pittsburgh(156 Qubit)も同様に144個のQubitを21個のプラケットに収めます。同じパターンは、異なるQubit数を持つ他のヘビーヘックスQPUにも当てはまります。

# QiskitRuntimeService.save_account(channel="ibm_quantum", token="<YOUR_API_KEY>", overwrite=True,
# set_as_default=True)
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
aer_backend = AerSimulator.from_backend(backend)
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()))}")

プラケット格子のグラフ表現の図を生成することで、プラケット格子を可視化できます。図中では、プラケットはラベル付きの六角形で表され、2つのプラケットがQubitを共有している場合に辺で結ばれます。

plaquette_lattice.draw_plaquettes()

Output of the previous code cell

plaquettes メソッドを使用して、個々のプラケットに含まれるQubitなどの情報を取得できます。

# Get a list of the plaquettes
plaquettes = list(plaquette_lattice.plaquettes())
# Display information about plaquette 0
plaquettes[0]
PyPlaquette(index=0, qubits=[3, 4, 5, 6, 7, 16, 17, 23, 24, 25, 26, 27], neighbors=[4, 3, 1])

プラケット格子を構成する基盤となるQubitの図も作成できます。

plaquette_lattice.draw_qubits()

Output of the previous code cell

Qubitのラベルと接続を示す辺に加えて、図にはGEMプロトコルに関連する3つの追加情報が含まれています:

  • 各Qubitは塗りつぶし(グレー)または塗りつぶしなしのいずれかです。塗りつぶされたQubitはイジングモデルのサイトを表す「サイト」Qubitであり、塗りつぶされていないQubitはサイトQubit間の相互作用を媒介する「ボンド」Qubitです。
  • 各サイトQubitには (A) または (B) のラベルが付けられており、GEMプロトコルにおいてサイトQubitが果たす2つの役割のいずれかを示しています(役割については後述します)。
  • 各辺は6色のうちの1色で色分けされており、辺を6つのグループに分割しています。この分割は、2QubitゲートをどのようにParalelizeするか、およびノイズのある量子プロセッサ上で異なる量のエラーを引き起こす可能性のある異なるスケジューリングパターンを決定します。各グループ内の辺は互いに素であるため、それらの辺に対して2Qubitゲートの層を同時に適用できます。実際には、6色を2色ずつ3つのグループに分割し、各2色グループの和集合が依然として互いに素になるようにすることが可能です。したがって、すべての辺を活性化するために必要な2Qubitゲートの層は3層のみです。6色をこのように分割する方法は12通りあり、それぞれの分割が異なる3層のGate・スケジュールを生成します。

プラケット格子を作成したので、次のステップは GemExperiment オブジェクトを初期化することです。プラケット格子と実験を実行するBackendの両方を渡します。GemExperiment クラスは、回路の生成、ジョブの送信、データの分析を含むGEMプロトコルの実際の実装を管理します。以下のコードセルでは、プラケット格子を1つのプラケット(12 Qubit)のみに制限して実験クラスを初期化し、シミュレーションを小さく高速に保ちます。完全なプラケット格子は、後で実際のハードウェアにスケールアップする際に使用します。

# Filter the plaquette lattice down to a single plaquette (12 qubits)
# so the AerSimulator run stays fast. The full lattice is used later
# in the large-scale hardware example.
gem_exp = GemExperiment(plaquette_lattice.filter([9]), backend=aer_backend)

# visualize the plaquette lattice after filtering
plaquette_lattice.filter([9]).draw_qubits()

Output of the previous code cell

GEMプロトコルのCircuitは、以下の手順で構築されます:

  1. すべてのQubitにアダマールGateを適用して、全 +|+\rangle 状態を準備します。
  2. 接続されたすべてのQubitペアの間に RZZR_{ZZ} Gateを適用します。これは3層のGateで実現できます。各 RZZR_{ZZ} GateはサイトQubitとボンドQubitに作用します。サイトQubitのラベルが (B) の場合、角度は π2\frac{\pi}{2} に固定されます。サイトQubitのラベルが (A) の場合、角度は可変であり、異なるCircuitを生成します。デフォルトでは、角度の範囲は 00 から π2\frac{\pi}{2} までの両端を含む等間隔の21点に設定されています。
  3. 各ボンドQubitをパウリ XX 基底で測定します。Qubitはパウリ ZZ 基底で測定されるため、測定前にアダマールGateを適用することでこれを実現できます。

このチュートリアルの冒頭で引用した論文では、RZZR_{ZZ} 角度に異なる規約を使用しており、このチュートリアルで使用する規約とは2倍の係数が異なることに注意してください。

ステップ3では、ボンドQubitのみが測定されます。サイトQubitがどのような状態に残されるかを理解するために、ステップ2でサイトQubit (A) に適用される RZZR_{ZZ} 角度が π2\frac{\pi}{2} に等しい場合を考えると有益です。この場合、サイトQubitはGHZ状態に類似した高度にエンタングルされた状態に置かれます、

GHZ=0000+1111.\lvert \text{GHZ} \rangle = \lvert 00 \cdots 00 \rangle + \lvert 11 \cdots 11 \rangle.

測定結果のランダム性により、サイトQubitの実際の状態は、たとえば 00110+11001\lvert 00110 \rangle + \lvert 11001 \rangle のような、長距離秩序を持つ別の状態になる場合があります。しかし、測定結果に基づくデコード操作を適用することで、GHZ状態を回復できます。RZZR_{ZZ} 角度を π2\frac{\pi}{2} から小さくしていくと、臨界角度まで長距離秩序を回復できます。ノイズがない場合、臨界角度は約 0.3π0.3 \pi です。この角度を下回ると、得られる状態は長距離エンタングルメントを示さなくなります。この長距離秩序の有無の間の転移が、西森相転移です。

上記の説明では、サイトQubitは測定されずに残され、デコード操作は量子Gateを適用することで実行できます。GEM Suiteで実装された実験では、実際にはサイトQubitも測定され、デコード操作は古典的な後処理ステップで適用されます。

上記の説明では、デコード操作はサイトQubitに量子Gateを適用して量子状態を回復することで実行できます。しかし、たとえば特性評価の目的で状態を直ちに測定することが目的の場合、サイトQubitはボンドQubitとともに測定され、デコード操作は古典的な後処理ステップで適用できます。

ステップ2の RZZR_{ZZ} 角度(デフォルトでは21個の値をスイープ)に加えて、GEMプロトコル回路は RZZR_{ZZ} Gateの3層を実装するために使用されるスケジューリングパターンにも依存します。前述のとおり、このようなスケジューリングパターンは12通りあります。したがって、実験の回路総数は 21×12=25221 \times 12 = 252 です。

実験の回路は、GemExperiment クラスの circuits メソッドを使用して生成できます。

circuits = gem_exp.circuits()
print(f"Total number of circuits: {len(circuits)}")
Total number of circuits: 252

このチュートリアルでは、単一のスケジューリングパターンのみを考慮すれば十分です。以下のコードセルでは、実験を最初のスケジューリングパターンに制限します。その結果、実験にはスイープされる各 RZZR_{ZZ} 角度に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の回路の図を描画します。図のサイズを縮小するため、回路末尾の測定Gateは除去されています。

# 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)

Output of the previous code cell

ステップ 2: 量子ハードウェア実行のための問題の最適化

量子CircuitをハードウェアでTranspileするには、通常複数のステージが含まれます。一般的に、最も計算コストがかかるステージは、Qubitレイアウトの選択、ハードウェアのQubit接続性に合わせた2QubitゲートのルーティングTranspile、およびゲート数と深さを最小化するための回路最適化です。GEMプロトコルでは、ハードウェアの接続性がすでにプロトコルの設計に組み込まれているため、レイアウトとルーティングのステージは不要です。回路にはすでにQubitレイアウトがあり、2QubitゲートはすでにネイティブCircuit接続にマッピングされています。さらに、RZZR_{ZZ} 角度を変化させる際に回路の構造を保持するため、ごく基本的な回路最適化のみを実行する必要があります。

GemExperiment クラスは、実験の実行時に回路を透過的にTranspileします。レイアウトとルーティングのステージはデフォルトで何もしないようにオーバーライドされており、回路最適化は単一QubitGateのみを最適化するレベルで実行されます。ただし、set_transpile_options メソッドを使用して、オーバーライドしたり追加のオプションを渡したりすることができます。可視化のため、以下のコードセルでは前に表示した回路を手動でTranspileし、Transpile後の回路を描画します。

# 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=aer_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)

Output of the previous code cell

ステップ 3: Qiskitプリミティブを使用した実行

GEMプロトコル回路をハードウェア上で実行するには、GemExperiment オブジェクトの run メソッドを呼び出します。各回路からサンプリングするショット数を指定できます。run メソッドは ExperimentData オブジェクトを返しますので、これを変数に保存してください。run メソッドはジョブの送信のみを行い、完了を待たないため、ノンブロッキング呼び出しであることに注意してください。

exp_data = gem_exp.run(shots=10_000)

結果を待つには、ExperimentData オブジェクトの block_for_results メソッドを呼び出します。この呼び出しにより、ジョブが完了するまでインタープリタはブロックされます。

# The noiseless AerSimulator produces zero-variance UFloat objects in the
# analysis, which triggers a harmless warning from the `uncertainties`
# library. Suppress it so the output stays clean.
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore", message="Using UFloat objects with std_dev==0"
)
exp_data.block_for_results()
exp_data
ExperimentData(GemExperiment, 90bf2a90-f729-4c4e-a6da-664aecb11039, job_ids=['04a7c405-47fd-46ca-aa4b-aaf7e339cfbe'], metadata=<5 items>, figure_names=['two_point_correlation.svg', 'normalized_variance.svg', 'plaquette_ops.svg', 'bond_ops.svg'])

ステップ 4: 後処理と所望の古典形式での結果の返却

RZZR_{ZZ} 角度が π2\frac{\pi}{2} の場合、ノイズがなければデコードされた状態はGHZ状態になります。GHZ状態の長距離秩序は、測定されたビット列の磁化をプロットすることで可視化できます。磁化 MM は、単一QubitのパウリZ演算子の和として定義されます。

M=j=1NZj,M = \sum_{j=1}^N Z_j,

ここで NN はサイトQubitの数です。ビット列に対するその値は、0の数と1の数の差に等しくなります。GHZ状態を測定すると、全ゼロ状態または全1状態が等確率で得られるため、磁化は半分の確率で +N+N、もう半分の確率で N-N となります。ノイズによるエラーが存在する場合、他の値も現れますが、ノイズが大きすぎなければ、分布は依然として +N+NN-N の近くにピークを持ちます。

デコード前の生のビット列については、ノイズがない場合、磁化の分布は一様ランダムなビット列の分布と等価になります。

以下のコードセルでは、RZZR_{ZZ} 角度が π2\frac{\pi}{2} の場合の生のビット列とデコードされたビット列の磁化をプロットします。

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')

Output of the previous code cell

長距離秩序をより厳密に特性評価するために、平均2点相関 ff を調べることができます。これは以下のように定義されます。

f=1N2(M2M2).f = \frac{1}{N^2} \left(\langle M^2 \rangle - \langle M \rangle ^2\right).

値が大きいほど、エンタングルメントの度合いが高いことを示します。GemExperiment クラスは、実験データの処理の一部として、デコードされたビット列に対してこの値を自動的に計算します。計算結果は、実験データクラスの figure メソッドを介してアクセスできる図として保存されます。この場合、図の名前は two_point_correlation です。

exp_data.figure("two_point_correlation")

Output of the previous code cell

西森相転移の臨界点を決定するには、M2/NM^2 / N の正規化分散 gg を調べます。これは以下のように定義されます。

g=1N3(M4M22),g = \frac{1}{N^3} \left(\langle M^4 \rangle - \langle M^2 \rangle^2\right),

これは二乗磁化の揺らぎの量を定量化します。この値は西森相転移の臨界点で最大になります。ノイズがない場合、臨界点は約 0.3π0.3 \pi で発生します。ノイズが存在する場合、臨界点はより高い値にシフトしますが、臨界点が 0.5π0.5 \pi 以下で発生する限り、相転移は依然として観測されます。

exp_data.figure("normalized_variance")

Output of the previous code cell

大規模ハードウェアの例

シミュレーターでプロトコルを検証したので、セットアップセクションで選択した実際の量子ハードウェアBackend上で実験をスケールアップして実行できます。この例では、2つの大きな問題サイズを使用します:

  • 6プラケット(約49 Qubit): ハードウェアノイズによる臨界点の右方向シフトがすでに現れる中規模の実行。
  • 完全なプラケット格子: デバイスのヘビーヘックス・トポロジーがサポートするすべてのプラケット(たとえば ibm_torino では18プラケット / 125 Qubit、ibm_pittsburgh では21プラケット / 144 Qubit)を使用し、定数深さ回路でデバイス全体のQubitをエンタングルします。

以下の単一コードセルは自己完結型です。BackendのCoupling・MapからプラケットLatticeを構築し、両方の実験を実行します。このセクションはセットアップセルの後に、小規模セクションを先に実行することなく実行できます。

# -------------------------Step 1-------------------------
# Initialize the runtime service, pick a real quantum hardware backend,
# and build the plaquette lattice from its coupling map. This is repeated
# from the small-scale example so this cell can run standalone after the
# Setup section. The full plaquette lattice is the "large-scale" target;
# a six-plaquette subset (range(3, 9)) is also used to show an intermediate
# scaling step.
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
plaquette_lattice = PlaquetteLattice.from_coupling_map(backend.coupling_map)

# Build a GemExperiment for the full plaquette lattice and one for the
# six-plaquette subset, each restricted to a single scheduling pattern so
# the experiment has one circuit per RZZ angle (21 circuits total).
gem_exp_full = GemExperiment(plaquette_lattice, backend=backend)
gem_exp_full.set_experiment_options(schedule_idx=0)
gem_exp_6 = GemExperiment(
plaquette_lattice.filter(range(3, 9)), backend=backend
)
gem_exp_6.set_experiment_options(schedule_idx=0)

circuits = gem_exp_full.circuits()
print(f"Total number of circuits (full lattice): {len(circuits)}")

# -------------------------Step 2-------------------------
# GemExperiment transpiles internally for the target backend: the layout
# and routing stages are overridden because the plaquette lattice already
# matches the hardware connectivity, and optimization is restricted so the
# RZZ angle structure is preserved. The code below manually transpiles one
# circuit from the six-plaquette experiment with the same settings this
# experiment will use, and draws it for inspection. (The full-lattice
# transpiled circuit has too many qubits to visualize cleanly, so the
# six-plaquette circuit is used here as a representative example.)
gem_exp_6.set_transpile_options(optimization_level=1)
circuits_6 = gem_exp_6.circuits()
pass_manager = generate_preset_pass_manager(
backend=backend,
initial_layout=list(gem_exp_6.physical_qubits),
**dict(gem_exp_6.transpile_options),
)
transpiled = pass_manager.run(circuits_6[5])
display(transpiled.draw("mpl", idle_wires=False, fold=-1, scale=0.5))

# -------------------------Step 3-------------------------
# Run both problem sizes on real hardware:
# 1. Six plaquettes (~49 qubits) — an intermediate scale-up.
# 2. The full plaquette lattice — every plaquette the device supports.
exp_data_6 = gem_exp_6.run(shots=10_000, job_tags=["TUT_NPT"])
exp_data_full = gem_exp_full.run(shots=10_000, job_tags=["TUT_NPT"])
exp_data_6.block_for_results()
exp_data_full.block_for_results()

# -------------------------Step 4-------------------------
# Plot the normalized variance at each scale. The peak marks the critical
# point of the Nishimori transition; as the system grows, hardware noise
# shifts the peak rightward.
display(exp_data_6.figure("normalized_variance"))
exp_data_full.figure("normalized_variance")
Total number of circuits (full lattice): 21

Output of the previous code cell

Output of the previous code cell

Output of the previous code cell

使用したBackendのノイズレベルによっては、より大きなサイズでの正規化分散曲線が、スイープされた角度範囲内で明確なピークを示さない場合があることに注意してください。上記の実行では、ピークはスイープの右端である 0.5π0.5 \pi まで押し上げられています(分析は6プラケットおよび完全格子の両方の実行に対して critical_angle = 0.5000 を報告します)。これは、ハードウェアノイズによって臨界点がプロトコルの物理的に意味のある角度範囲の境界またはそのわずか先まで押し上げられており、このスイープで解決できる限界にあることを意味します。

まとめ

このチュートリアルでは、GEMプロトコルを使用して量子プロセッサ上で西森相転移を実現しました。後処理で調べた指標、特に2点相関と正規化分散は、デバイスが長距離エンタングル状態を生成する能力のベンチマークとして機能します。これらのベンチマークは、GEMプロトコルの有用性を興味深い物理の探究を超えて拡張するものです。プロトコルの一部として、定数深さの回路のみを使用してデバイス全体のQubitをエンタングルしました。この偉業は、プロトコルが回路中間測定を使用することで初めて可能になります。この実験ではエンタングル状態は直ちに測定されましたが、この状態をさらなる量子処理に使用することを探究してみてください。

次のステップ

推奨事項

この研究に興味を持たれた方には、以下の資料をお勧めします:

参考文献

[1] E. H. Chen, G.-Y. Zhu, R. Verresen, A. Seif, E. Bäumer, D. Layden, N. Tantivasadakarn, G. Zhu, S. Sheldon, A. Vishwanath, S. Trebst, A. Kandala. Realizing the Nishimori transition across the error threshold for constant-depth quantum circuits. arXiv:2309.02863 (2023).

[2] GEM Suite software package.