トランスパイラ最適化レベルを設定する
このページのコードは、以下の要件に基づいて開発された。 これらのバージョンまたは新しいバージョンの使用をお勧めします。
qiskit[all]~=2.5.1 qiskit-ibm-runtime~=0.47.0
実際の量子デバイスはノイズやゲートエラーの影響を受けるため、回路の深さやゲート数を減らすように最適化することで、それらの回路を実行して得られる結果を大幅に改善することができる。
この関数には、1つの位置引数が必要である。 generate_preset_pass_manageroptimization_level この関数は、トランスパイラが回路の最適化に費やす労力を制御する。 この引数には、0、1、2、3のいずれかの値をとる整数を指定する。
最適化レベルを上げると、コンパイル時間が長くなる代わりに、より最適化された回路が生成される。
次の表は、各設定で実行される最適化について説明しています。
最適化レベル | 説明 |
|---|---|
| 0 | 最適化なし:通常、ハードウェアの特性評価に使用
|
| 1 | 光の最適化:
|
| 2 | 中庸の最適化:
|
| 3 | 高い最適化:
|
最適化レベルの実践
通常、2量子ビットゲートは最も重大なエラーの原因となるため、結果として得られる回路内の2量子ビットゲートの数を数えることで、トランスパイルの「ハードウェア効率」をおおよそ定量化することができる。 ここでは、ランダムなユニタリーにSWAPゲートが続く入力回路で、さまざまな最適化レベルを試してみる。
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:
これらの例では の FakeSherbrooke``qiskit_ibm_runtime モックバックエンドを使用していますが、Qiskitと互換性のある実在のバックエンドや模擬バックエンドであれば、どれでも試すことができます。 実際の結果は異なる場合があります。
まず、最適化レベル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:
トランスパイルド回路には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:
トランスパイルド回路は依然として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:
これは最適化レベル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:
現在、ECRゲートは3つしかない。 最適化レベル3では、Qiskitは2量子ビットのゲート・ブロックを再合成しようとするため、この結果が得られる。 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:
この回路には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}"
)Output:
Synthesis fidelity
Exact: 1.000+0.000j
Approximate: 0.992+0.000j
最適化レベルを調整すると、ECRゲートの数だけでなく、回路の他の側面にも影響が及ぶことがあります。 最適化レベルの設定がレイアウトにどのような影響を与えるかについては、 「量子コンピュータの表現」を参照してください。
次のステップ
generate_preset_passmanager機能の詳細については、 トランスピレーションのデフォルト設定と構成オプションのトピックから始めてください。- Transpilerステージのトピックでトランスピレーションの学習を続けてください。
- トランスパイラ設定の比較ガイドをお試しください。
- チュートリアルの Build repetition codesをお試しください。
- Transpile API ドキュメントを参照してください。