Skip to main content
IBM Quantum Platform

ユーティリティ規模の実験 I

Note

小野寺民也(2024年7月5日)

講演の原文の PDFをダウンロードする。 これらは静的画像なので、いくつかのコード・スニペットは非推奨になるかもしれないことに注意してください。

この実験の実行にかかるQPUのおおよその時間は45秒である。


1. ユーティリティペーパーの概要

このレッスンでは、2023年6月15日発行の『Nature』誌第618号に掲載された、我々が非公式に 「ユーティリティ・ペーパー 」と呼んでいるユーティリティ・スケールの回路を動かす。 この論文では、 2D 横磁場イジング模型の時間発展を扱っている。 特に、ハミルトニアンの時間力学を考慮している、

H=HZZ+HX=J(i,j)ZiZj+hiXiH = H_{ZZ} + H_X = - J \sum_{(i,j)} Z_i Z_j + h \sum_{i} X_i

ここで、 J>0J > 0 は最近接スピンと i<ji < j との結合であり、 hh はグローバルな横磁場である。

時間発展演算子の一次トロッター分解により、初期状態からのスピンダイナミクスをシミュレートする、

exp(iHZZδt)=(i,j)exp(iJδtZiZj)=(i,j)RZiZj(2Jδt)exp(iHXδt)=iexp(ihδtXi)=iRXi(2hδt)\begin{aligned} \exp(-i H_{ZZ} \delta t) &= \prod_{(i,j)} \exp (i J \delta t Z_i Z_j) = \prod_{(i,j)} \mathrm{R}_{Z_i Z_j} ( - 2 J \delta t) \\ \exp(-i H_X \delta t) &= \prod_{i} \exp (-i h \delta t X_i ) = \prod_{i} \mathrm{R}_{X_i} ( 2 h \delta t) \end{aligned}

ここで、進化時間 TTT/δtT / \delta t トロッター・ステップに離散化され、 RZiZj(θJ)\mathrm{R}_{Z_i Z_j}(\theta_J) および RXi(θh)\mathrm{R}_{X_i}(\theta_h) はそれぞれ ZZZZXX の回転ゲートである。

彼らは、ヘビーヘックス接続を持つ127量子ビットのQuantum® Eagleプロセッサ( IBM )で実験を行い、すべての量子ビットに XX、結合マップのすべてのエッジに ZZZZ。 データ依存性」のため、 ZZZZ のすべての相互作用を同時に適用することはできないことに注意。 それゆえ、 カップリング・マップに色をつけて、レイヤーにグループ分けしているのだ。 レイヤー内のものは同じ色が割り当てられ、並行して適用できる。

さらに、実験を簡単にするため、 θJ=π/2\theta_J=-\pi /2 のケースに焦点を当てた。

この論文の斬新な貢献は、状態ベクトルシミュレーションを超える規模の量子回路を構築し、ノイズの多い量子コンピューター上で動作させ、信頼性の高い結果を引き出すことに成功したことである。 つまり、ノイジー量子コンピューターの有用性を実証したのである。 その際、ゼロノイズ外挿(ZNE)と確率的誤差増幅(PEA)を適用し、ノイズの多いデバイスからの誤差を軽減した。

それ以来、このような実験や回路を「ユーティリティ・スケール」と呼ぶことにした。

1.1 あなたの目標

このレッスンの目標は、ユーティリティ規模の回路を作り、Eagleプロセッサで動作させることです。 このノートブックで信頼できる結果を引き出すのは、この執筆時点ではPEAがQiskitの実験的な機能であることと、PEAでZNEを適用するにはかなりの時間がかかることもあって、この範囲を超えている。

具体的には、論文の図( 4b )に相当する回路を作り、走らせ、自分自身の「まねのできない」点をプロットすることが求められる。 ご覧のように、これは127量子ビット( ×\times )の60層(20トロッター・ステップ)回路で、 Z62\langle Z_{62} \rangle を観測可能としている。

image.png

大げさに聞こえるか? ご安心ください。 このコースの最後の3つのレッスンは、その足がかりとなる。 はじめに、 Z13\langle Z_{13} \rangle を観測可能な27量子ビット ×\times 6層(2トロッターステップ)回路を作り、偽デバイス上で動作させる小規模な実験を示す。

紹介は以上だ。 ユーティリティ・スケールの冒険に出かけよう!

import qiskit

qiskit.__version__

Output:

'2.0.2'
#!pip install qiskit_ibm_runtime
#!pip install qiskit_aer
import matplotlib.pyplot as plt
import numpy as np
import rustworkx as rx

from qiskit import QuantumCircuit, transpile
from qiskit.circuit import Parameter
from qiskit.circuit.library import YGate
from qiskit.quantum_info import SparsePauliOp
from qiskit_ibm_runtime import (
    QiskitRuntimeService,
    fake_provider,
    EstimatorV2 as Estimator,
)
from qiskit_aer import AerSimulator
service = QiskitRuntimeService()

2. 準備

2.1 RZZ(- π\pi /2) を構築する

まず、RZZゲートは一般に2つの CXCX ゲートを必要とする。

from qiskit.circuit.library import RZZGate

θ_h = Parameter("$\\theta_h$")
qc1 = QuantumCircuit(2)
qc1.append(RZZGate(θ_h), [0, 1])
qc1.decompose(reps=1).draw("mpl")

Output:

Output of the previous code cell

上述したように、この実験では、特定の角度(- π\pi / 2)を持つRZZゲートに焦点を当てる。 論文で示したように、 CXCX ゲート1つで実現できる。

qc2 = QuantumCircuit(2)

qc2.sdg([0, 1])
qc2.append(YGate().power(1 / 2), [1])
qc2.cx(0, 1)
qc2.append(YGate().power(1 / 2).adjoint(), [1])

qc2.draw("mpl")

Output:

Output of the previous code cell

今後の参考のため、この回路でゲートを定義する。

rzz = qc2.to_gate(label="RZZ")

新しく定義された rzz をランダムに使ってみよう。

qc3 = QuantumCircuit(3)
qc3.append(rzz, [0, 1])
qc3.append(rzz, [0, 2])
display(qc3.draw("mpl"))
# display(qc.decompose(reps=1).draw("mpl"))

Output:

Output of the previous code cell

これをさらに使用する前に、 -pi/2 と新たに定義した rzz または qc2 ゲートについて、 qc1 (RZZゲート)の論理的等価性を検証してみよう:

from qiskit.quantum_info import Operator

op1 = Operator(qc1.assign_parameters([-np.pi / 2]))
op2 = Operator(qc2)

op1.equiv(op2)

Output:

True

2.2 結合マップを色付けする

バックエンドのカップリング・マップにどのように色をつけるか、研究してみよう。 これは、 ZZZZ インタラクションをレイヤーにグループ化するために必要である。

まずはじめに、バックエンドのカップリングマップを視覚化してみよう。 現在の IBM 量子デバイスのカップリングマップはすべて重六角形である。

backend = service.least_busy(operational=True, simulator=False)

backend.coupling_map.draw()

Output:

Output of the previous code cell

カップリング・マップに色を付けるには、グラフや複雑なネットワークを扱うための Python パッケージである rustworkxを使う。 複数のカラーリング・アルゴリズムを提供するが、これらはすべて発見的であるため、最小カラーリングを見つけられる保証はない。

とはいえ、heavy-hexグラフはbipartiteなので、これらのグラフの最小彩色を見つけるはずの graph_bipartite_edge_colorをピックアップする。

def color_coupling_map(backend):
    graph = backend.coupling_map.graph
    undirected_graph = graph.to_undirected(multigraph=False)
    edge_color_map = rx.graph_bipartite_edge_color(undirected_graph)
    if edge_color_map is None:
        edge_color_map = rx.graph_greedy_edge_color(undirected_graph)
    # build a map from color to a list of edges
    edge_index_map = undirected_graph.edge_index_map()
    color_edges_map = {color: [] for color in edge_color_map.values()}
    for edge_index, color in edge_color_map.items():
        color_edges_map[color].append(
            (edge_index_map[edge_index][0], edge_index_map[edge_index][1])
        )
    return edge_color_map, color_edges_map

重六角形のグラフは3色で塗る。 上記のカップリング・マップについて確認してみよう。

edge_color_map, color_edges_map = color_coupling_map(backend)
print(
    f"{backend.name}, {backend.num_qubits}-qubit device, {len(color_edges_map.keys())} colors assigned."
)

Output:

ibm_strasbourg, 127-qubit device, 3 colors assigned.

そうだ!

お遊びで、rustworksの可視化機能を使って、得られたカラーリングにカップリング・マップをペイントしてみよう。

color_str_map = {0: "green", 1: "red", 2: "blue"}

undirected_graph = backend.coupling_map.graph.to_undirected(multigraph=False)
for i in undirected_graph.edge_indices():
    undirected_graph.get_edge_data_by_index(i)["color"] = color_str_map[
        edge_color_map[i]
    ]

rx.visualization.graphviz_draw(
    undirected_graph, method="neato", edge_attr_fn=lambda edge: {"color": edge["color"]}
)

Output:

Output of the previous code cell

3. 2D イジングモデルのトロッター化時間発展を解く。

2D イジング模型の時間発展について、実用新案回路を構成するルーチンを定義しよう。 このルーチンは、バックエンド、トロッターステップ数を示す整数、バリア挿入を制御するブール値の3つのパラメーターを取る。

def get_utility_circuit(backend, num_steps: int, barrier: bool = False):
    num_qubits = backend.num_qubits
    _, color_edges_map = color_coupling_map(backend)
    θ_h = Parameter("$\\theta_h$")
    qc = QuantumCircuit(num_qubits)

    for i in range(num_steps):
        qc.rx(θ_h, range(num_qubits))

        for _, edge_list in color_edges_map.items():
            for edge in edge_list:
                qc.append(rzz, edge)

        if barrier:
            qc.barrier()
    return qc

なお、構築した回路については、すでに手作業で量子ビットのマッピングとルーティングを行っている。 したがって、後で回路をトランスパイルする際、トランスパイラに量子ビットのマッピングやルーティングを依頼することはない (はずだ )。 すぐにおわかりになると思うが、最適化レベルを1、レイアウト方法を "trivial "として起動する。

次に、簡単なチェックのために、構成された回路の情報を取得する簡単なルーチンを定義する。

def get_circuit_info(qc: QuantumCircuit, reps: int = 0):
    qc0 = qc.decompose(reps=reps)
    return (
        f"{qc0.num_qubits} qubits × {qc0.depth(lambda x: x.operation.num_qubits == 2)} layers ({qc0.depth()}-depth)"
        + ",  "
        + f"""Gate breakdown: {", ".join([f"{k.upper()} {v}" for k, v in qc0.count_ops().items()])}"""
    )

これらのルーチンを行使しよう。 27 qubit ×\times 15層(5トロッターステップ)の回路が見えるはずです。 偽デバイスには28個のエッジがあるので、28*5個のエンタングルゲージがあるはずだ。

backend = fake_provider.FakeTorontoV2()
num_steps = 5
qc = get_utility_circuit(backend, num_steps, True)

display(qc.draw(output="mpl", fold=-1))
print(get_circuit_info(qc, reps=0))
print(get_circuit_info(qc, reps=1))

Output:

Output of the previous code cell
27 qubits × 15 layers (20-depth),  Gate breakdown: CIRCUIT-165 140, RX 135, BARRIER 5
27 qubits × 15 layers (60-depth),  Gate breakdown: SDG 280, UNITARY 280, CX 140, R 135, BARRIER 5

4. 27量子ビット版の問題を解く。

ここで、実用性実験の小規模バージョンを実証する。 Z13\langle Z_{13} \rangle を観測可能な27量子ビット ×\times 6層(2トロッターステップ)回路を構築し、 AerSimulator と偽デバイスの両方で実行する。

もちろん、マップ、最適化、実行、後処理からなる4段階のワークフロー「Qiskitパターン」に従う。 より具体的に言えば

  • 古典的な入力を量子計算にマップする。
  • 量子計算のための回路を最適化する。
  • プリミティブを使って回路を実行する。
  • 後処理を行い、古典的な形式で結果を返す。

以下では、小規模な実験用の回路を作るためのマップ・ステップを紹介する。 そして、 AerSimulator に対する最適化と実行のセットと、偽デバイスに対する最適化と実行のセットを用意する。 最後に、結果をプロットするポストプロセスのステップがある。

4.1 ステップ1: マップ

backend = fake_provider.FakeTorontoV2()  # a 27 qubit fake device.
num_steps = 2
qc = get_utility_circuit(backend, num_steps)
obs = SparsePauliOp.from_sparse_list(
    [("Z", [13], 1)], num_qubits=backend.num_qubits
)  # Falcon
angles = [
    0,
    0.1,
    0.2,
    0.3,
    0.4,
    0.5,
    0.6,
    0.7,
    0.8,
    1.0,
    np.pi / 2,
]  # We try 11 angles for theta_h.

4.2 ステップ2と3:最適化と実行(シミュレーター)

backend_sim = AerSimulator()
transpiled_qc_sim = transpile(
    qc, backend_sim, optimization_level=1, layout_method="trivial"
)
transpiled_obs_sim = obs.apply_layout(layout=transpiled_qc_sim.layout)

print(get_circuit_info(qc, reps=1))
print(get_circuit_info(transpiled_qc_sim, reps=1))

Output:

27 qubits × 6 layers (23-depth),  Gate breakdown: SDG 112, UNITARY 112, CX 56, R 54
27 qubits × 6 layers (16-depth),  Gate breakdown: U3 80, CX 56, R 54, U1 32, U 28

あるユーザーは、 2.3 GHzクアッドコアIntel Core i7 Processorを搭載した 32GB 3LPDDR4X RAMを搭載した MacBook Proを使用して次のセルを実行した macOS 14.5。 壁時間で 161ms。 ノートパソコンはそれぞれ微妙に異なる。

%%time
params = [[p] for p in angles]
estimator = Estimator(mode=backend_sim)
pub = (transpiled_qc_sim, transpiled_obs_sim, params)
result_sim = estimator.run([pub]).result()

Output:

CPU times: user 231 ms, sys: 186 ms, total: 417 ms
Wall time: 111 ms

4.3 ステップ2と3:最適化と実行(偽装デバイス)

backend_fake = fake_provider.FakeTorontoV2()
transpiled_qc_fake = transpile(
    qc, backend_fake, optimization_level=1, layout_method="trivial"
)
transpiled_obs_fake = obs.apply_layout(layout=transpiled_qc_fake.layout)

print(get_circuit_info(qc, reps=1))
print(get_circuit_info(transpiled_qc_fake, reps=1))

Output:

27 qubits × 6 layers (23-depth),  Gate breakdown: SDG 112, UNITARY 112, CX 56, R 54
27 qubits × 6 layers (49-depth),  Gate breakdown: SDG 324, U1 274, H 162, CX 56, U3 14

同じユーザーが上記と同じ環境で次のセルを実行したところ、ウォールタイムで 2min 19s。 偽デバイス上で回路を実行すると、ノイズの多いシミュレーションが呼び出され、厳密なシミュレーションよりもはるかに時間がかかる。 より大きな回路(27量子ビット ×\times 3トロッターステップの9層など)を偽デバイスで実行しないことをお勧めします。

%%time
params = [[p] for p in angles]
estimator = Estimator(mode=backend_fake)
pub = (transpiled_qc_fake, transpiled_obs_fake, params)
result_fake = estimator.run([pub]).result()

Output:

CPU times: user 4min 42s, sys: 9.35 s, total: 4min 51s
Wall time: 38.3 s

4.4 ステップ4: 後処理

正確なシミュレーションとノイズの多いシミュレーションの結果をプロットする。 FakeToronto、ノイズの深刻な影響を目の当たりにすることになる。

plt.plot(angles, result_fake[0].data.evs, "o", label="Fake Device")
plt.plot(angles, result_sim[0].data.evs, "o", label="AerSimulator")
plt.xlabel("$\\mathrm{R_x}$ angle $\\theta_h$")
plt.title("$\\langle Z_{13} \\rangle$")
plt.legend()
plt.show()

Output:

Output of the previous code cell

5. 127量子ビット版の問題を解く

冒頭で述べたように、ユーティリティ・スケールの実験を行うことがあなたの目標です。 Z62\langle Z_{62} \rangle、127量子ビット、60層(20トロッターステップ)の回路を作成し、実行します。 適切な場合は27qubit版のコードを使い、自分でやってみることをお勧めする。 しかし、その解決策はここにある。

解決策:

5.1 ステップ1: マップ

# backend_map = service.backend("ibm_brisbane")
backend_map = service.least_busy(operational=True, simulator=False)

num_steps = 20
qc = get_utility_circuit(backend_map, num_steps)
obs = SparsePauliOp.from_sparse_list(
    [("Z", [62], 1)], num_qubits=backend_map.num_qubits
)  # Eagle
angles = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 1.0, np.pi / 2]

5.2 ステップ2と3:最適化と実行

イーグル・プロセッサーのカップリング・マップには144本のエッジがある。

# backend = service.backend("ibm_brisbane")
backend = backend_map

transpiled_qc = transpile(qc, backend, optimization_level=1, layout_method="trivial")
transpiled_obs = obs.apply_layout(layout=transpiled_qc.layout)

print(get_circuit_info(qc, reps=1))
print(get_circuit_info(transpiled_qc))

Output:

156 qubits × 60 layers (221-depth),  Gate breakdown: SDG 7040, UNITARY 7040, CX 3520, R 3120
156 qubits × 60 layers (201-depth),  Gate breakdown: RZ 11933, SX 6240, CZ 3520
params = [[p] for p in angles]
estimator = Estimator(mode=backend)
pub = (transpiled_qc, transpiled_obs, params)
job = estimator.run([pub])

job_id = job.job_id()
print(f"job id={job_id}")

Output:

job id=d1479n6qf56g0081sxa0

5.3 後処理

ユーティリティ・ペーパーの図 4b に「緩和された」ポイントの値を示す。 これらの結果をプロットする。

result_paper = [
    1.0171,
    1.0044,
    0.9563,
    0.9602,
    0.8394,
    0.8120,
    0.5466,
    0.4556,
    0.1953,
    0.0141,
    0.0117,
]

# REPLACE WITH YOUR OWN JOB ID
job = service.job(job_id)

plt.plot(angles, job.result()[0].data.evs, "o", label=f"{job.backend().name}")
plt.plot(angles, result_paper, "o", label="Utility Paper")
plt.xlabel("$\\mathrm{R_x}$ angle $\\theta_h$")
plt.title("$\\langle Z_{62} \\rangle$")
plt.legend()
plt.show()

Output:

Output of the previous code cell

あなたの結果は、図 4b の "unmitigated "と同じようなものですか? それらは、装置や実験時の状態によって大きく異なる可能性がある。 結果そのものを気にすることはない。 私たちがチェックするのは、あなたが正しくコーディングしたかどうかです。 もしそうなら、おめでとう、あなたはユーティリティ時代のスタートラインに立ったのだ。

ユーティリティの論文にあるように、世界中の科学者たちは、ノイズがあっても意味のある結果を引き出すために多大な工夫を凝らしてきた。 この集団的努力の最終目標は、量子の優位性である。量子コンピューターが、産業界で利用されているいくつかの問題を、古典的なコンピューターよりも速く、より忠実に、より安価に解決できる状態である。 これは一度だけの出来事ではなく、量子の結果を古典的に再現するのに時間がかかるようになり、ある時点で量子のリードタイムが決定的に重要な意味を持つようになるのである。 量子力学的な優位性に関して、ひとつはっきりしていることがある。 このコースが、挑戦と楽しさに満ちたクエストに参加するきっかけになれば、これ以上の喜びはない。


参照

  • キム、Y、 エディンズ、A、 Anand, S. et al. フォールト・トレランスの前に量子コンピューティングの有用性を証明。 Nature 618, 500-505 (2023)。 https://doi.org/10.1038/s41586-023-06096-3
このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。