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

トランスパイラの最適化レベルを設定する

パッケージバージョン

このページのコードは、以下の要件を使用して開発されました。 これらのバージョン以降の使用を推奨します。

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

実際の量子デバイスはノイズやゲートエラーの影響を受けるため、回路の深さとゲート数を削減するように最適化することで、それらの回路の実行から得られる結果を大幅に改善できます。 generate_preset_pass_manager 関数には、必須の位置引数 optimization_level があり、トランスパイラが回路の最適化にどれだけの労力をかけるかを制御します。この引数には、0、1、2、3 のいずれかの整数を指定できます。 最適化レベルが高いほど、コンパイル時間が長くなる代わりに、より最適化された回路が生成されます。 次の表は、各設定で実行される最適化の内容を説明しています。

最適化レベル説明
0

最適化なし:主にハードウェア特性評価に使用

  • 基本的な変換のみ
  • レイアウト/ルーティング:TrivialLayout を使用し、仮想量子ビットと同じ物理量子ビット番号を選択し、SabreSwap を使用して動作するように SWAP を挿入
1

軽度の最適化:

  • レイアウト/ルーティング:まず TrivialLayout でレイアウトを試みます。追加の SWAP が必要な場合は、SabreSwap を使用して SWAP 数が最小となるレイアウトを見つけ、次に VF2LayoutPostLayout を使用してグラフ内の最適な量子ビットを選択します。
  • InverseCancellation
  • 1Q ゲートの最適化
2

中程度の最適化:

  • レイアウト/ルーティング:最適化レベル 1(trivial なし)+ より大きな探索深度と最適化関数の試行回数によるヒューリスティック最適化。TrivialLayout を使用しないため、物理量子ビット番号と仮想量子ビット番号を同じにしようとする試みは行われません。
  • CommutativeCancellation
3

高度な最適化:

  • 最適化レベル 2 + より大きな労力・試行回数でレイアウト/ルーティングをさらにヒューリスティック最適化
  • Cartan の KAK 分解 を使用した 2 量子ビットブロックの再合成
  • ユニタリ性を破るパス:
    • OptimizeSwapBeforeMeasure:SWAP を回避するために測定をリアレンジ
    • RemoveDiagonalGatesBeforeMeasure:測定結果に影響しない測定前のゲートを削除

最適化レベルの動作

2 量子ビットゲートは通常、最も大きなエラーの原因であるため、結果として得られる回路の 2 量子ビットゲート数を数えることで、トランスパイルの「ハードウェア効率」をおおよそ定量化できます。 ここでは、ランダムユニタリに SWAP ゲートが続く入力回路に対して、異なる最適化レベルを試してみます。

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
from qiskit import QuantumCircuit
from qiskit.circuit.library import UnitaryGate
from qiskit.quantum_info import Operator, random_unitary

UU = random_unitary(4, seed=12345)
rand_U = UnitaryGate(UU)

qc = QuantumCircuit(2)
qc.append(rand_U, range(2))
qc.swap(0, 1)
qc.draw("mpl", style="iqp")

Output of the previous code cell

例では FakeSherbrooke モックバックエンドを使用します。まず、最適化レベル 0 でトランスパイルしてみましょう。

from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()

pass_manager = generate_preset_pass_manager(
optimization_level=0, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)

Output of the previous code cell

トランスパイルされた回路には、2 量子ビット ECR ゲートが 6 つあります。

最適化レベル 1 で繰り返してみます:

from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()

pass_manager = generate_preset_pass_manager(
optimization_level=1, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)

Output of the previous code cell

トランスパイルされた回路にはまだ 6 つの ECR ゲートがありますが、1 量子ビットゲートの数が減少しています。

最適化レベル 2 で繰り返してみます:

pass_manager = generate_preset_pass_manager(
optimization_level=2, backend=backend, seed_transpiler=12345
)
qc_t2_exact = pass_manager.run(qc)
qc_t2_exact.draw("mpl", idle_wires=False)

Output of the previous code cell

最適化レベル 1 と同じ結果が得られます。最適化レベルを上げても、必ずしも違いが生まれるわけではないことに注意してください。

最適化レベル 3 で再度繰り返してみます:

pass_manager = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=12345
)
qc_t3_exact = pass_manager.run(qc)
qc_t3_exact.draw("mpl", idle_wires=False)

Output of the previous code cell

今度は ECR ゲートが 3 つだけになりました。これは、最適化レベル 3 では Qiskit が 2 量子ビットゲートのブロックを再合成しようとするためで、どんな 2 量子ビットゲートも最大 3 つの ECR ゲートで実装できます。approximation_degree を 1 未満の値に設定すると、さらに ECR ゲートを減らすことができます。これにより、トランスパイラはゲート分解に若干の誤差をもたらす可能性のある近似を行うことが許可されます(トランスパイルのよく使われるパラメーターを参照):

pass_manager = generate_preset_pass_manager(
optimization_level=3,
approximation_degree=0.99,
backend=backend,
seed_transpiler=12345,
)
qc_t3_approx = pass_manager.run(qc)
qc_t3_approx.draw("mpl", idle_wires=False)

Output of the previous code cell

この回路は ECR ゲートが 2 つだけですが、近似回路です。この回路の効果が正確な回路とどのように異なるかを理解するために、この回路が実装するユニタリ演算子と正確なユニタリとの間の忠実度(フィデリティ)を計算できます。計算を実行する前に、まず 127 量子ビットを含むトランスパイルされた回路を、アクティブな量子ビット(2 つ)のみを含む回路に縮小します。

import numpy as np

def trace_to_fidelity_2q(trace: float) -> float:
return (4.0 + trace * trace.conjugate()) / 20.0

# Reduce circuits down to 2 qubits so they are easy to simulate
qc_t3_exact_small = QuantumCircuit.from_instructions(qc_t3_exact)
qc_t3_approx_small = QuantumCircuit.from_instructions(qc_t3_approx)

# Compute the fidelity
exact_fid = trace_to_fidelity_2q(
np.trace(np.dot(Operator(qc_t3_exact_small).adjoint().data, UU))
)
approx_fid = trace_to_fidelity_2q(
np.trace(np.dot(Operator(qc_t3_approx_small).adjoint().data, UU))
)
print(
f"Synthesis fidelity\nExact: {exact_fid:.3f}\nApproximate: {approx_fid:.3f}"
)
Synthesis fidelity
Exact: 1.000+0.000j
Approximate: 0.992+0.000j

最適化レベルの調整は、ECR ゲートの数だけでなく、回路の他の側面にも変化をもたらす可能性があります。最適化レベルの設定がレイアウトにどのような変化を与えるかの例については、量子コンピューターの表現を参照してください。

次のステップ

おすすめ