周期境界条件のための回路カッティング
使用時間の推定: 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 — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-addon-cutting qiskit-ibm-runtime
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_blocksとentangler 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)

回路カッティングを使用した結果の品質を検証するためには、理想的な結果を知る必要があります。現在選択されている回路は、ブルートフォースの古典シミュレーションを超えています。したがって、回路をクリフォードにするために、パラメータを慎重に固定します。
Rx gateの最初の2層にはパラメータ値を割り当て、最後の層には値を割り当てます。これにより、この回路の理想的な結果は(はqubitの数)になります。したがって、との期 待値(はqubitのインデックス)は、それぞれとになります。
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の利点を定量化するために、観測量との期待値を測定します。前述のように、理想的な期待値はそれぞれとです。
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)

長距離周期接続をカット
次に、トランスパイルされた回路の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です。したがって、サブ実験の総数はになります。
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
]
)