TEM関数を用いてキックされたアイジングモデルをシミュレートする
アルゴリズム社のテンソルネットワーク誤差軽減(TEM)手法は、量子・古典ハイブリッドアルゴリズムであり、ノイズ軽減処理を完全に古典的な後処理段階で実行するよう設計されている。 TEMを用いることで、ユーザーは観測量の期待値を計算でき、量子ハードウェア上で発生する避けられないノイズ起因の誤差を、精度とコスト効率を高めつつ軽減できる。これにより、量子研究者や産業実務者双方にとって非常に魅力的な選択肢となっている。
このチュートリアルでは、TEMが量子システムのダイナミクスに対して意味のある結果を得る方法を示します。これはエラー軽減なしでは得られないものであり、PECやZNEなどの他のエラー軽減手法を使用する場合、はるかに多くの量子リソースを必要とします。
使用量見積もり: このノートブックは、Heron r3 デバイス上で約10 QPU分を使用します。 実行時間は選択したデバイスによって大きく異なる場合があります。 セクションごとの使用量見積もりは以下に記載されています。
TEM機能を用いたエラー緩和型多体系物理実験を実行する
このチュートリアルは、以下の参考文献に基づいています: L. E. Fischer et al., Nat. 物理学 (2026). 本論文は、最大91量子ビットの量子ハードウェアを用いた実シミュレーションについて論じている。 このチュートリアルでは、より小さな回路サイズで同様のシミュレーションを再現します。
キックド・アイジングモデルは通常のアイジングモデルに対応する:
これに横蹴りが加えられる:
目標は、横方向キックイジングハミルトニアン下での状態のダイナミクスをシミュレートすることであり、その時間発展は、フロケユニタリ によって実装することができます。発展させる初期状態は、最初の量子ビットが状態 にある一方で、他の量子ビットはペアになってベル状態 に設定されている状態です。
私たちが観察したい量は相関関数である。 本論文では、この量を 量子ビット上の パウリ演算子として書き換える方法を論じている。 物理時間ステップ を数回実行した後、パウリ演算子 の値を計算する。 システムのパラメータによっては、この観測量の値は正確に計算できる値に等しくなるか、近似法によるシミュレーションでしか得られない。 具体的には、 に対して、 に等しくなります。これが、このチュートリアルの結果をベンチマークするために使用する値となります。 さらに、ある時間ステップ において、 はゼロである。 これらの値を得る詳細およびこれらのパラメータ外における近似的な古典的シミュレーション結果との比較については、L. E. Fischer et al. を参照のこと Nat. 物理学 (2026).
TEMは、回路内の2量子ビットゲートを構成する各固有層のノイズ特性をまず評価するとともに、読み出し誤差の特性評価を行うことで機能する。 その後、回路は量子マシン上で実行される。 最後に、 IBM Cloud® の古典リソース上でテンソルネットワーク誤差軽減処理が実行され、軽減後の値が返される。 この例では、回路には特徴付けが必要な2つの固有の層がある。
セットアップ
前提条件として、必要な依存関係がインストールされていることを確認してください。
%pip install numpy matplotlib qiskit qiskit-ibm-catalog qiskit-ibm-runtime pylatexenc qiskit_qasm3_importimport os
from matplotlib import pyplot as plt
import numpy as np
from qiskit.quantum_info import SparsePauliOp
from qiskit.qasm3 import load
from qiskit_ibm_catalog import QiskitFunctionsCatalogTEMによるエラー軽減
ここでは、前述のキックド・アイジングモデルを実装する回路を提供する。 回路は以下のように準備される。 まず、状態準備段階があり、この段階では最初の量子ビットが状態 にあり、他の量子ビットはベル対 を形成している。これに続いて、ユニタリー進化 を実現するレンガ積み構造が続く。物理的な時間ステップの数は、 回路層に対応する。
以下のコードは、このチュートリアルに必要な2つのQASMファイルをダウンロードします。
# Download required QASM files
import urllib
urllib.request.urlretrieve(
"https://ibm.box.com/shared/static/swy5jtq309b0xpzluzlmsmj908yphes8.qasm",
"ki_30q.qasm",
)
urllib.request.urlretrieve(
"https://ibm.box.com/shared/static/et3gkodonw6gsp2trs43lzaozrdtiu7s.qasm",
"ki_12q.qasm",
)12個の量子ビットと6つの時間ステップからなる回路の縮小版を可視化できます:
# Parameters of the kicked Ising model
h = 0.0
num_qubits = 12
t_steps = 6
# Load the circuit for the kicked Ising model
small_circuit = load("ki_12q.qasm")
# Draw the circuit
small_circuit.draw("mpl", scale=0.25, fold=-1)Output:
次に、オブザーバブル を構築します。これはQiskitで使用される順序に一致する順序で、単純なパウリ文字列として構成されます:
def xt_observable(n_qubits, t_steps):
pauli_str = "".join(["I" * t_steps, "X", "I" * (n_qubits - t_steps - 1)])
pauli_str = pauli_str[::-1] # Reverse the string to match qiskit order
return SparsePauliOp(data=pauli_str, coeffs=1.0)私たちの小さな12量子ビットの例では、観測量は次のようになります:
# Build the observable for the kicked Ising model
small_observable = xt_observable(n_qubits=12, t_steps=6)
print(small_observable)Output:
SparsePauliOp(['IIIIIXIIIIII'],
coeffs=[1.+0.j])
Qiskit Functions PUBsを入力収集の手段として使用する。 我々の場合、 PUB として単一の回路と観測量を考えよう:
# Collect the input PUBs, in this case composed of a
# single circuit and observable
pubs = [(small_circuit, [small_observable])]次に、TEM機能にアクセスできるようになります。 まず、 IBM Cloud への必要な認証を設定し、利用可能なデバイスからバックエンドを選択します。 トークン、利用可能なバックエンド、および対応するクラウドリソース名(CRN)は、 IBM Quantum Platform ダッシュボードでアカウントにログインすることで取得できます。
# Set IBM Quantum credentials and backend configuration
personal_token = os.environ.get(
"QISKIT_IBM_TOKEN", "<API-KEY>"
) # Replace with your personal token or set the environment variable
channel = "ibm_quantum_platform"
crn = "your_crn" # Replace with the Cloud Resource Name (CRN)
# Select the QPU backend
backend_name = "ibm_qpu_name" # Replace with your desired backend's nameQiskit Functions Catalog から TEM 関数をロードします:
# Load the TEM function from the Qiskit Functions Catalog
catalog = QiskitFunctionsCatalog(
channel=channel,
token=personal_token,
instance=crn,
)
tem = catalog.load("algorithmiq/tem")TEMによるエラー軽減機能を備えたキックされたアイジング回路で実験を実行できるようになりました。 デフォルト設定を使用すると、TEMは簡単な方法で実行でき、QPUに応じて予想されるQPU実行時間は約 2.5 分です:
tem_job = tem.run(pubs=pubs, backend_name=backend_name)デフォルト設定では、TEM関数は量子コンピュータ上で3つのジョブを実行します:ノイズ学習、読み出し緩和、回路サンプリングです。 これらの各々が使用するショット数は、関数に渡されるオプションで変更できます。 デフォルトでは、これらのパラメータは緩和された期待値において 0.05 の精度を達成するように設定されています。
ジョブのステータスは、 IBM Quantum Platform のダッシュボードまたは以下の方法で確認できます:
print(tem_job.status())Output:
QUEUED
ステータスが の場合 DONE、生の結果と緩和された結果を確認できます。 以下に定義される tem_evs は、要求された観測量の期待値であり、この場合単一の観測量である の期待値であり、 tem_std は対応する標準偏差である。
# Get the results of the TEM job
tem_results = tem_job.result()[
0
] # Get the first and only result from the job
tem_evs = tem_results.data.evs[0]
tem_std = tem_results.data.stds[0]
print(f"TEM Result: {tem_evs:.3f} ± {tem_std:.3f}")Output:
TEM Result: 1.031 ± 0.046
各呼び出しで消費された量子ランタイム量は、 IBM Quantum Platform で確認できます。あるいは、 Python のコードから結果メタデータを検査することで確認できます。
# Get the TEM job runtime
tem_runtime = tem_job.result().metadata["resource_usage"][
"RUNNING: EXECUTING_QPU"
]["QPU_TIME"]
print(f"TEM Runtime: {tem_runtime} seconds")Output:
TEM Runtime: 155.0 seconds
TEMパラメータと高度なオプションのカスタマイズ
TEM機能は、エラー軽減ワークフローをカスタマイズするためのいくつかの高度なオプションを提供します。 これらのオプションにより、実験要件や利用可能な量子リソースに合わせて、精度、ショット数、ノイズ学習戦略、その他のパラメータを制御できます。
一般的な詳細オプションは以下の通りです:
- **
precision**緩和された期待値の目標精度を指定してください。 default_shots: の代わりにprecision、測定ジョブで使用するショット数を指定できます。- **
tem_max_bond_dimension**テンソルネットワークで使用される最大結合次元。 - **
tem_compression_cutoff**テンソルネットワークに使用するカットオフ値。 - ノイズ学習オプション :ノイズの特性設定(繰り返し回数や特定のキャリブレーション回路など)を構成します。
- **
private**回路と実験結果があなた専用のものとなるよう確保し、ジョブ結果の複数回ダウンロードを無効にしてください。
サポートされているオプションの完全なリストとその説明については、TEMドキュメントまたは Qiskit Functions Catalog を参照してください。 これらのパラメータを調整することで、実行時間、リソース使用量、結果の精度のバランスを取ることができます。
TEM関数を実行する際、これらのオプションを辞書として引数 options に渡すことができます:
options = {
"default_shots": 10_000,
"tem_max_bond_dimension": 512,
"tem_compression_cutoff": 1e-16,
# This option helps optimizing the measurement
# stage since the observable is strongly biased
# toward the X operator for all the qubits.
"compute_shadows_bias_from_observable": True,
# set to True to keep experiment results private,
# recommended for confidential circuits
"private": False,
}ノイズ学習器向けのカスタムオプションも渡すことができます。 これらは、以下で使用されている定義に従っています: qiskit-ibm-runtimeNoiseLearnerOptions
nl_options = {
"num_randomizations": 32,
"max_layers_to_learn": 2,
"shots_per_randomization": 128,
"layer_pair_depths": [0, 1, 2, 4, 16, 32],
}
# add noise learning options to the overall options
options |= nl_optionsこれらのカスタムオプションを当回路に合わせて調整し、実験を再実行してください。 予想される実行時間は約4QPU分です。
tem_job_custom = tem.run(
pubs=pubs, backend_name=backend_name, options=options
)ジョブが非公開に設定されていない場合、後で結果を復元できます。 そのためには、ここに表示されているジョブIDを保存し、. を使用してください tem_job_custom = catalog.get_job_by_id("your-job-id")。
job_id = tem_job_custom.job_id
print(f"Job ID: {job_id}")Output:
Job ID: 1ba10094-a541-457a-9287-dbd49306d12d
results_custom = tem_job_custom.result()
tem_evs = results_custom[0].data.evs[0]
tem_std = results_custom[0].data.stds[0]
print(f"TEM Result: {tem_evs:.3f} ± {tem_std:.3f}")Output:
TEM Result: 0.956 ± 0.018
結果とメタデータを検証することで、実験に関する知見を得ることができます:
metadata_custom = results_custom[0].metadata
unmitigated_evs = metadata_custom["evs_non_mitigated"][0]
unmitigated_stds = metadata_custom["stds_non_mitigated"][0]
print(f"Unmitigated Result: {unmitigated_evs:.3f} ± {unmitigated_stds:.3f}")
# Exact result for the kicked Ising model from the reference paper
exact_evs = np.cos(2 * h) ** t_steps
print("Exact Result:", exact_evs)Output:
Unmitigated Result: 0.894 ± 0.015
Exact Result: 1.0
# Plot comparing the different expectation values
plt.bar(
["Unmitigated", "TEM"],
[unmitigated_evs, tem_evs],
yerr=[unmitigated_stds, tem_std],
color=["grey", "c"],
)
plt.hlines(y=exact_evs, xmin=-0.5, xmax=1.5, colors="r", linestyles="dashed")
plt.ylabel("Expectation Value")
plt.ylim(0, 1.1)
plt.show()Output:
最後に、カスタムオプションがQPUおよび古典的な実行時間に与える影響を確認できます:
# Get the metadata of the TEM job
job_metadata = results_custom.metadata
# Get the runtime of the TEM job
qpu_runtime = job_metadata["resource_usage"]["RUNNING: EXECUTING_QPU"][
"QPU_TIME"
]
classical_runtime = (
job_metadata["resource_usage"]["RUNNING: OPTIMIZING_FOR_HARDWARE"][
"CPU_TIME"
]
+ job_metadata["resource_usage"]["RUNNING: POST_PROCESSING"]["CPU_TIME"]
)
print(f"QPU Runtime: {qpu_runtime} seconds")
print(f"Classical Runtime: {classical_runtime} seconds")Output:
QPU Runtime: 342.0 seconds
Classical Runtime: 107.632604 seconds
TEMを大規模回路に拡張する
大規模な回路は、原則としてTEM機能で実行可能である。 ただし、TEMが IBM Cloud ランナー上で実行され、実行時間が非常に長くなる可能性があるため、古典的リソースの限界を認識することが重要です。 非常に大規模な回路については、 qiskit\ [email protected] の TEM サポートチームにお問い合わせください。
ここでは、より大規模なユーティリティ規模の30量子ビット回路を用いた例を実行し、精度ではなく速度を優先してTEMパラメータを最適化します。
# Kicked Ising model parameters
n_qubits = 30
t_steps = 15
h = 0.0
# Load the circuit for the kicked Ising model
circuit = load("ki_30q.qasm")
# Build the observable for the kicked Ising model
observable = xt_observable(n_qubits=n_qubits, t_steps=t_steps)
# Collect the input PUBs, in this case composed of a
# single circuit and observable
pubs = [(circuit, [observable])]パフォーマンス重視のオプションをいくつか定義しましょう:
options = {
"num_randomizations": 32,
"max_layers_to_learn": 2,
"shots_per_randomization": 128,
"layer_pair_depths": [0, 1, 2, 4, 16, 32, 64],
"default_shots": 5_000,
"tem_max_bond_dimension": 128,
"tem_compression_cutoff": 1e-10,
"compute_shadows_bias_from_observable": True,
"private": False,
}最後に、実験を実行し、結果を取得し、それを可視化する。 これは約 3.5 QPU分かかるでしょう。
tem_job_large = tem.run(pubs=pubs, backend_name=backend_name, options=options)job_id = tem_job_large.job_id
print(f"Job ID: {job_id}")Output:
Job ID: 9f3f190f-f4b0-4dcb-bb83-5f71f37d0d77
results_large = tem_job_large.result()
tem_evs = results_large[0].data.evs[0]
tem_std = results_large[0].data.stds[0]
print(f"TEM Result: {tem_evs:.3f} ± {tem_std:.3f}")
# Get the metadata of the TEM job
job_metadata = tem_job_large.result().metadata
# Get the runtime of the TEM job
qpu_runtime = job_metadata["resource_usage"]["RUNNING: EXECUTING_QPU"][
"QPU_TIME"
]
classical_runtime = (
job_metadata["resource_usage"]["RUNNING: OPTIMIZING_FOR_HARDWARE"][
"CPU_TIME"
]
+ job_metadata["resource_usage"]["RUNNING: POST_PROCESSING"]["CPU_TIME"]
)
print(f"QPU Runtime: {qpu_runtime} seconds")
print(f"Classical Runtime: {classical_runtime} seconds")Output:
TEM Result: 0.794 ± 0.026
QPU Runtime: 203.0 seconds
Classical Runtime: 251.71805499999996 seconds
# Plot comparing the different expectation values
metadata_large = results_large[0].metadata
unmitigated_evs = metadata_large["evs_non_mitigated"][0]
unmitigated_stds = metadata_large["stds_non_mitigated"][0]
exact_evs = np.cos(2 * h) ** t_steps
plt.bar(
["Unmitigated", "TEM"],
[unmitigated_evs, tem_evs],
yerr=[unmitigated_stds, tem_std],
color=["grey", "c"],
)
plt.hlines(y=exact_evs, xmin=-0.5, xmax=1.5, colors="r", linestyles="dashed")
plt.ylabel("Expectation Value")
plt.ylim(0, 1.1)
plt.show()Output: