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

周期境界条件のための回路カッティング

使用時間の推定: Eagleプロセッサで2分(注: これは推定値です。実際の実行時間は異なる場合があります。)

背景

このノートブックでは、隣接するすべてのqubitペア間、最初と最後のqubitを含む、2qubit演算を持つ周期的なqubitチェーンのシミュレーションを検討します。周期的チェーンは、Isingモデルや分子シミュレーションなどの物理学や化学の問題でよく見られます。

現在のIBM Quantum®デバイスは平面的です。最初と最後のqubitが隣接している場合、トポロジー上に直接いくつかの周期的チェーンを埋め込むことが可能です。しかし、十分に大きな問題の場合、最初と最後のqubitが遠く離れている可能性があり、これら2つのqubit間の2qubit演算には多くのSWAP gateが必要になります。このような周期境界問題はこの論文で研究されています。

このノートブックでは、回路カッティングを使用して、最初と最後のqubitが隣接していないユーティリティスケールの周期的チェーン問題に対処する方法を示します。この長距離接続をカットすることで、回路の複数のインスタンスを実行し、いくらかの古典的な後処理を行うコストで、余分なSWAP gateを回避できます。要約すると、カッティングを組み込むことで、長距離2qubit演算を論理的に計算できます。言い換えれば、このアプローチは結合マップの接続性を効果的に増加させ、結果としてSWAP gateの数を削減します。

カットには2つのタイプがあることに注意してください - 回路のワイヤをカットする(wire cuttingと呼ばれる)、または2qubit gateを複数の1qubit演算に置き換える(gate cuttingと呼ばれる)。このノートブックでは、gate cuttingに焦点を当てます。gate cuttingの詳細については、qiskit-addon-cutting説明資料および対応する参考文献を参照してください。wire cuttingの詳細については、期待値推定のためのワイヤカッティングチュートリアル、またはqiskit-addon-cuttingのチュートリアルを参照してください。

要件

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

  • Qiskit SDK v1.2以降(pip install qiskit
  • Qiskit Runtime v0.3以降(pip install qiskit-ibm-runtime
  • Circuit cutting Qiskit addon v.9.0以降(pip install qiskit-addon-cutting

セットアップ

# Added by doQumentation — installs packages not in the Binder environment
%pip install -q qiskit-addon-cutting
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import (
BasisTranslator,
Optimize1qGatesDecomposition,
)
from qiskit.circuit.equivalence_library import (
SessionEquivalenceLibrary as sel,
)
from qiskit.converters import circuit_to_dag, dag_to_circuit
from qiskit.result import sampled_expectation_value
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.circuit.library import TwoLocal

from qiskit_addon_cutting import (
cut_gates,
generate_cutting_experiments,
reconstruct_expectation_values,
)

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2, SamplerOptions, Batch

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

ここでは、TwoLocal回路を生成し、いくつかの観測量を定義します。

  • 入力: 回路を作成するためのパラメータ
  • 出力: 抽象回路と観測量

entangler mapの最後と最初のqubit間に周期的接続を持つ、TwoLocal回路のためのハードウェア効率的なentangler mapを考えます。この長距離相互作用は、transpilation中に余分なSWAP gateを引き起こし、回路の深さを増加させる可能性があります。

バックエンドと初期レイアウトを選択

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

このノートブックでは、127qubit IBM Quantumデバイスのトポロジーにおける最長の1Dチェーンである109qubitの周期的1Dチェーンを考えます。127qubitデバイス上に109qubitの周期的チェーンを、最初と最後のqubitが余分なSWAP gateを組み込むことなく隣接するように配置することは不可能です。

init_layout = [
13,
12,
11,
10,
9,
8,
7,
6,
5,
4,
3,
2,
1,
0,
14,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
36,
51,
50,
49,
48,
47,
46,
45,
44,
43,
42,
41,
40,
39,
38,
37,
52,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
74,
89,
88,
87,
86,
85,
84,
83,
82,
81,
80,
79,
78,
77,
76,
75,
90,
94,
95,
96,
97,
98,
99,
100,
101,
102,
103,
104,
105,
106,
107,
108,
112,
126,
125,
124,
123,
122,
121,
120,
119,
118,
117,
116,
115,
114,
113,
]

# the number of qubits in the circuit is governed by the length of the initial layout
num_qubits = len(init_layout)
num_qubits
109

TwoLocal回路のentangler mapを構築

coupling_map = [(i, i + 1) for i in range(0, len(init_layout) - 1)]
coupling_map.append(
(len(init_layout) - 1, 0)
) # adding in the periodic connectivity

TwoLocal回路は、rotation_blocksentangler mapの繰り返しを複数回許可します。この場合、繰り返しの回数は、カットする必要がある周期的gateの数を決定します。サンプリングオーバーヘッドはカットの数に対して指数関数的に増加するため(詳細については期待値推定のためのワイヤカッティングチュートリアルを参照)、このノートブックでは繰り返しの回数を2に固定します。

num_reps = 2
entangler_map = []

for even_edge in coupling_map[0 : len(coupling_map) : 2]:
entangler_map.append(even_edge)

for odd_edge in coupling_map[1 : len(coupling_map) : 2]:
entangler_map.append(odd_edge)
ansatz = TwoLocal(
num_qubits=num_qubits,
rotation_blocks="rx",
entanglement_blocks="cx",
entanglement=entangler_map,
reps=num_reps,
).decompose()
ansatz.draw("mpl", fold=-1)

Output of the previous code cell

回路カッティングを使用した結果の品質を検証するためには、理想的な結果を知る必要があります。現在選択されている回路は、ブルートフォースの古典シミュレーションを超えています。したがって、回路をクリフォードにするために、パラメータを慎重に固定します。

Rx gateの最初の2層にはパラメータ値00を割り当て、最後の層には値π\piを割り当てます。これにより、この回路の理想的な結果は1n|1\rangle^{\otimes n}nnはqubitの数)になります。したがって、Zi\langle Z_i \rangleZiZi+1\langle Z_i Z_{i+1} \rangleの期待値(iiはqubitのインデックス)は、それぞれ1-1+1+1になります。

params_last_layer = [np.pi] * ansatz.num_qubits
params = [0] * (ansatz.num_parameters - ansatz.num_qubits)
params.extend(params_last_layer)

ansatz.assign_parameters(params, inplace=True)

観測量を選択

gate cuttingの利点を定量化するために、観測量1ni=1nZi\frac{1}{n}\sum_{i=1}^n \langle Z_i \rangle1n1i=1n1ZiZi+1\frac{1}{n-1}\sum_{i=1}^{n-1} \langle Z_i Z_{i+1} \rangleの期待値を測定します。前述のように、理想的な期待値はそれぞれ1-1+1+1です。

observables = []

for i in range(num_qubits):
obs = "I" * (i) + "Z" + "I" * (num_qubits - i - 1)
observables.append(obs)

for i in range(num_qubits):
if i == num_qubits - 1:
obs = "Z" + "I" * (num_qubits - 2) + "Z"
else:
obs = "I" * i + "ZZ" + "I" * (num_qubits - i - 2)
observables.append(obs)

observables = SparsePauliOp(observables)
paulis = observables.paulis
coeffs = observables.coeffs

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

  • 入力: 抽象回路と観測量
  • 出力: 長距離gateをカットすることによって生成されたターゲット回路と観測量

回路をトランスパイル

回路はこの段階でトランスパイルすることも、カット後にトランスパイルすることもできます。カット後にトランスパイルする場合、サンプリングオーバーヘッドによって生成された各サブ実験をトランスパイルする必要があります。したがって、トランスパイルのオーバーヘッドを削減するために、この段階でトランスパイルする方が賢明です。

ただし、ネイティブハードウェア接続でこの段階でトランスパイルを行うと、transpilerは周期的な2qubit演算を配置するために複数のSWAP gateを追加し、回路カッティングの利点を不明瞭にします。この問題を回避するために、カットする必要がある正確なgateを知っているという事実を活用できます。具体的には、離れたqubit間に仮想接続を追加して仮想結合マップを作成し、これらの周期的な2qubit gateに対応できます。これにより、余分なSWAP gateを組み込むことなく、この段階で回路をトランスパイルできることが保証されます。

coupling_map = backend.configuration().coupling_map

# create a virtual coupling map with long range connectivity
virtual_coupling_map = coupling_map.copy()
virtual_coupling_map.append([init_layout[-1], init_layout[0]])
virtual_coupling_map.append([init_layout[0], init_layout[-1]])
pm_virtual = generate_preset_pass_manager(
optimization_level=1,
coupling_map=virtual_coupling_map,
initial_layout=init_layout,
basis_gates=backend.configuration().basis_gates,
)

virtual_mapped_circuit = pm_virtual.run(ansatz)
virtual_mapped_circuit.draw("mpl", fold=-1, idle_wires=False)

Output of the previous code cell

長距離周期接続をカット

次に、トランスパイルされた回路のgateをカットします。カットする必要がある2qubit gateは、レイアウトの最後と最初のqubitを接続するものであることに注意してください。

# Find the indices of the distant gates
cut_indices = [
i
for i, instruction in enumerate(virtual_mapped_circuit.data)
if {virtual_mapped_circuit.find_bit(q)[0] for q in instruction.qubits}
== {init_layout[-1], init_layout[0]}
]

トランスパイルされた回路のレイアウトを観測量に適用します。

trans_observables = observables.apply_layout(virtual_mapped_circuit.layout)

最後に、異なる測定と準備基底をサンプリングすることによって、サブ実験が生成されます。

qpd_circuit, bases = cut_gates(virtual_mapped_circuit, cut_indices)
subexperiments, coefficients = generate_cutting_experiments(
circuits=qpd_circuit,
observables=trans_observables.paulis,
num_samples=np.inf,
)

長距離相互作用をカットすると、測定と準備基底が異なる回路の複数のサンプルの実行につながることに注意してください。これについての詳細は、Constructing a virtual two-qubit gate by sampling single-qubit operationsおよびCutting circuits with multiple two-qubit unitariesで確認できます。

カットする必要がある周期的gateの数は、上でnum_repsとして定義されたTwoLocalレイヤーの繰り返し回数に等しくなります。gate cuttingのサンプリングオーバーヘッドは6です。したがって、サブ実験の総数は6num_reps6^{num\_reps}になります。

print(f"Number of subexperiments is {len(subexperiments)} = 6**{num_reps}")
Number of subexperiments is 36 = 6**2

サブ実験をトランスパイル

この時点で、サブ実験には、basis gate setに含まれていない一部の1qubit gateを含む回路が含まれています。これは、カットされたqubitが異なる基底で測定され、これに使用される回転gateが必ずしもbasis gate setに属していないためです。たとえば、X基底での測定は、通常のZ基底での測定の前にHadamard gateを適用することを意味します。しかし、Hadamardはbasis gate setの一部ではありません。

サブ実験の各回路に対して全体のトランスパイルプロセスを適用する代わりに、特定のトランスパイルパスを使用できます。利用可能なすべてのトランスパイルパスの詳細な説明については、このドキュメントを参照してください。

これらの回路のすべてのgateがbasis gate setに属することを保証するために、BasisTranslatorを適用し、次にOptimize1qGatesDecompositionパスを適用します。これら2つのパスを使用する方が、全体のトランスパイルプロセスよりも高速です。なぜなら、ルーティングや初期レイアウトの選択などの他のステップは再度実行されないためです。

pass_ = PassManager(
[Optimize1qGatesDecomposition(basis=backend.configuration().basis_gates)]
)

subexperiments = pass_.run(
[
dag_to_circuit(
BasisTranslator(sel, target_basis=backend.basis_gates).run(
circuit_to_dag(circ)
)
)
for circ in subexperiments
]
)

ステップ3: Qiskit primitivesを使用して実行

  • 入力: ターゲット回路
  • 出力: 準確率分布

カットされた回路の実行にはSamplerV2 primitiveを使用します。dynamical decouplingtwirlingを無効にして、結果で得られる改善が、このタイプの回路に対するgate cuttingの効果的な適用のみによるものになるようにします。

options = SamplerOptions()
options.default_shots = 10000
options.dynamical_decoupling.enable = False
options.twirling.enable_gates = False
options.twirling.enable_measure = False

次に、バッチモードを使用してジョブを送信します。

with Batch(backend=backend) as batch:
sampler = SamplerV2(options=options)
cut_job = sampler.run(subexperiments)

print(f"Job ID {cut_job.job_id()}")
Job ID cwxf7wq60bqg008pvt8g
result = cut_job.result()

ステップ4: 後処理して望ましい古典的形式で結果を返す

  • 入力: 準確率分布
  • 出力: 再構成された期待値
reconstructed_expvals = reconstruct_expectation_values(
result,
coefficients,
paulis,
)

次に、重み1と重み2のZ型観測量の平均を計算します。

cut_weight_1 = np.mean(reconstructed_expvals[:num_qubits])
cut_weight_2 = np.mean(reconstructed_expvals[num_qubits:])

print(f"Average of weight-1 expectation values is {cut_weight_1}")
print(f"Average of weight-2 expectation values is {cut_weight_2}")
Average of weight-1 expectation values is -0.741733944954063
Average of weight-2 expectation values is 0.6968862385320495

クロス検証: カットなしの期待値を取得

回路カッティング技術の利点をカットなしと比較して検証することは有用です。ここでは、回路をカットせずに期待値を計算します。このようなカットなしの回路は、最初と最後のqubit間の2qubit演算を実装するために必要な多数のSWAP gateに悩まされることに注意してください。SamplerV2を介して確率分布を取得した後、sampled_expectation_value関数を使用してカットなし回路の期待値を取得します。これにより、すべてのインスタンスでprimitiveの均質な使用が可能になります。ただし、期待値を直接計算するためにEstimatorV2も使用できたことに注意してください。

if ansatz.num_clbits == 0:
ansatz.measure_all()

pm_uncut = generate_preset_pass_manager(
optimization_level=1, backend=backend, initial_layout=init_layout
)

transpiled_circuit = pm_uncut.run(ansatz)
sampler = SamplerV2(mode=backend, options=options)
uncut_job = sampler.run([transpiled_circuit])
uncut_job_id = uncut_job.job_id()
print(f"The job id for the uncut clifford circuit is {uncut_job_id}")
The job id for the uncut clifford circuit is cwxfads2ac5g008jhe7g
uncut_result = uncut_job.result()[0]
uncut_counts = uncut_result.data.meas.get_counts()

次に、カットなしですべての重み1と重み2のZ型観測量の平均期待値を計算します。

uncut_expvals = [
sampled_expectation_value(uncut_counts, obs) for obs in paulis
]

uncut_weight_1 = np.mean(uncut_expvals[:num_qubits])
uncut_weight_2 = np.mean(uncut_expvals[num_qubits:])

print(f"Average of weight-1 expectation values is {uncut_weight_1}")
print(f"Average of weight-2 expectation values is {uncut_weight_2}")
Average of weight-1 expectation values is -0.32494128440366965
Average of weight-2 expectation values is 0.32340917431192656

可視化

周期的チェーン回路にgate cuttingを使用した場合の重み1と重み2の観測量に対する改善を可視化しましょう。

mpl.rcParams.update(mpl.rcParamsDefault)

fig = plt.subplots(figsize=(12, 8), dpi=200)
width = 0.25
labels = ["Weight-1", "Weight-2"]
x = np.arange(len(labels))

ideal = [-1, 1]
cut = [cut_weight_1, cut_weight_2]
uncut = [uncut_weight_1, uncut_weight_2]

br1 = np.arange(len(ideal))
br2 = [x + width for x in br1]
br3 = [x + width for x in br2]

plt.bar(
br1, ideal, width=width, edgecolor="k", label="Ideal", color="#4589ff"
)
plt.bar(br2, cut, width=width, edgecolor="k", label="Cut", color="#a56eff")
plt.bar(
br3, uncut, width=width, edgecolor="k", label="Uncut", color="#009d9a"
)

plt.axhline(y=0, color="k", linestyle="-")

plt.xticks([r + width for r in range(len(ideal))], labels, fontsize=14)
plt.yticks(fontsize=14)

plt.legend(fontsize=14)
plt.show()

Output of the previous code cell

まとめ

要約すると、109qubitの周期的1Dチェーンに対する重み1と重み2のZ型観測量の平均期待値を計算しました。そのために、以下を行いました。

  • 1Dチェーンの最初と最後のqubit間に長距離接続を追加することによって仮想結合マップを作成し、回路をトランスパイルしました。
    • この段階でのトランスパイルにより、カット後に各サブ実験を個別にトランスパイルするオーバーヘッドを回避できました。
    • 仮想結合マップを使用することで、最初と最後のqubit間の2qubit演算のための余分なSWAP gateを回避できました。
  • gate cuttingを介してトランスパイルされた回路から長距離接続を削除しました。
  • 適切なトランスパイルパスを適用することによって、カットされた回路をbasis gate setに変換しました。
  • SamplerV2 primitiveを使用して、IBM Quantumデバイスでカットされた回路を実行しました。
  • カットされた回路の結果を再構成することによって期待値を取得しました。

推論

結果から、重み1のZ\langle Z \rangleと重み2のZZ\langle ZZ \rangle型観測量の平均が、周期的gateをカットすることによって大幅に改善されたことがわかります。この研究には、誤差抑制または緩和技術は含まれていないことに注意してください。観察された改善は、この問題に対するgate cuttingの適切な使用のみによるものです。緩和および抑制技術を使用することで、結果をさらに改善できた可能性があります。

この研究は、計算のパフォーマンスを向上させるためにgate cuttingを効果的に使用する例を示しています。

チュートリアルのアンケート

このチュートリアルに関するフィードバックを提供するために、この短いアンケートにご協力ください。皆様のご意見は、コンテンツの提供とユーザーエクスペリエンスの向上に役立ちます。

アンケートへのリンク