トラ ンスパイラの最適化レベルを設定する
パッケージバージョン
このページのコードは、以下の要件を使用して開発されました。 これらのバージョン以降の使用を推奨します。
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
実際の量子デバイスはノイズやゲートエラーの影響を受けるため、回路の深さとゲート数を削減するように最適化することで、それらの回路の実行から得られる結果を大幅に改善できます。
generate_preset_pass_manager 関数には、必須の位置引数 optimization_level があり、トランスパイラが回路の最適化にどれだけの労力をかけるかを制御します。この引数には、0、1、2、3 のいずれかの整数を指定できます。
最適化レベルが高いほど、コンパイル時間が長くなる代わりに、より最適化された回路が生成されます。
次の表は、各設定で実行される最適化の内容を説明しています。
| 最適化レベル | 説明 |
|---|---|
| 0 | 最適化なし:主にハードウェア特性評価に使用
|
| 1 | 軽度の最適化:
|
| 2 | 中程度の最適化:
|
| 3 | 高度な最適化:
|
最適化レベルの動作
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")
例では 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)
トランスパイルされた回路には、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)
トランスパイルされた回路にはまだ 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)
最適化レベル 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)
今度は 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)
この回路は 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 ゲートの数だけでなく、回路の他の側面にも変化をもたらす可能性があります。最適化レベルの設定がレイアウトにどのような変化を与えるかの例については、量子コンピューターの表現を参照してください。
次のステップ
generate_preset_passmanager関数の詳細については、トランスパイルのデフォルト設定と構成オプション トピックから始めてください。- トランスパイラのステージ トピックでトランスパイルの学習を続けてください。
- トランスパイラ設定の比較 ガイドを試してみてください。
- 繰り返し符号の構築 チュートリアルを試してみてください。
- Transpile API ドキュメント を参照してください。