Skip to main content
IBM Quantum Platform

トランスパイラー

qiskit.transpiler


概要

注

回路のトランスパイレーション/コンパイルという概念についてすでに理解されている方は、次のセクションへ進んでください:

トランスパイレーションとは、与えられた入力回路を、特定の量子デバイスのトポロジーに合わせて書き換える、および/または量子システム上での実行に向けて回路を最適化するプロセスである。

ほとんどの回路は、特定のターゲットデバイスに対応できるよう一連の変換を経る必要があり、その結果として生じるノイズの影響を低減するために最適化される必要があります。 ハードウェアの制約に合わせて量子回路を書き換え、性能を最適化することは、決して簡単なことではない。 書き換えツールチェーンにおける論理の流れは、必ずしも直線的である必要はなく、多くの場合、反復的なサブループや条件分岐、その他の複雑な挙動を含むことがあります。 とはいえ、標準的なコンパイルの流れは、以下の構造に従います:

トランスパイレーション処理では、入力回路を受け取り、トランスパイレーションの各パスを適用した後、出力回路を生成します。

Qiskit は、トランスパイラ・スタック全体を通じて、ツリーベースのものではなく、回路のグラフベースの中間 DAGCircuit 表現(IR)を使用しています QuantumCircuit。 トランスパイラー・パイプラインとは、そのメソッド PassManager.run() が を受け取り、それを に変換し QuantumCircuitDAGCircuit 、そのIRを一連のパスに処理させた後、最終的に を QuantumCircuit 返す オブジェクト PassManager のことです。 パスとは、状態保持型オブジェクト内で回路に関する特性を計算・保存する「パス AnalysisPass」か PropertySet、特定の単一の目標を達成するためにIRを修正する「パス TransformationPass」のいずれかである。 パイプラインは「ステージ」に分割されていると考えてよく、各ステージは1つの大まかな変換を担当しています。

Qiskit は、関数 を使用して、デフォルトのトランスパイル・パイプライン・ビルダーを提供しています generate_preset_pass_manager()。 これにより、指定されたレベル( optimization_level 0 から 3 までの範囲)で、完全なトランスパイルを行うために適切に構成されたパイプラインが返されます。 極めて専門的なものを探しているのでない限り、ここが間違いなく最適な入り口となるでしょう。 トランスパイラによる変換の例は次のようになります:

from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService

# Any abstract circuit you want:
abstract = QuantumCircuit(2)
abstract.h(0)
abstract.cx(0, 1)

# Any method you like to retrieve the backend you want to run on:
backend = QiskitRuntimeService().backend("some-backend")

# Create the pass manager for the transpilation ...
pm = generate_preset_pass_manager(backend=backend)
# ... and use it (as many times as you like).
physical = pm.run(abstract)

フォールトトレランスに向けた初期の実験において、関数 および generate_preset_pass_manager() は、ターゲット基底がクリフォード+Tゲートで構成される場合、専用のトランスパイレーションパイプラインを呼び出します transpile() 。詳細については generate_preset_clifford_t_pass_manager() 、 を参照してください。 Clifford+Tパイプラインの詳細な設定を行う場合は、後者を使用することをお勧めします。 たとえば、 RZR_Z の合成精度は、 "unitary_synthesis_method" 内で設定することはできず、 generate_preset_pass_manager() のみを通じてグローバルに設定する必要があります "approximation_degree"。 しかし、この件 "rz_synthesis_config" に関してはその実態が明らか generate_preset_clifford_t_pass_manager() になっている。

例:

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import QFTGate
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import get_clifford_gate_names

# Any abstract circuit you want:
abstract = QuantumCircuit(4)
abstract.append(QFTGate(4), [0, 1, 2, 3])

# Use all Clifford+T basis gates
basis_gates = get_clifford_gate_names() + ["t", "tdg"]

# Create and run the pass manager
pm = generate_preset_pass_manager(basis_gates=basis_gates)
transpiled = pm.run(abstract)

ほとんどのケースでは、これだけで十分です。 とはいえ、Qiskitのトランスパイラ・インフラストラクチャはすべて、拡張性と設定の柔軟性に優れています。 このページの残りの部分では、トランスパイラ・スタックの低レベルな機能を活用する方法について詳しく説明します。


プリセット・パスマネージャー

この関数は、「プリセット・パス・マネージャー」を作成 generate_preset_pass_manager() します。 これらはすべて のインスタンスであるため PassManager、 を メソッド QuantumCircuitPassManager.run() に渡すことで使用されます。 具体的には、プリセット・パス・マネージャーはのインスタンスであり StagedPassManager、これにより、プリステージやポストステージのフックを含め、トランスパイラ処理の各段階をより詳細に設定できるようになります。

プリセット・パス・マネージャーには、最大6つの名前付きステージがあります。 これらを、実行順に以下にまとめました。より詳細な情報については、以下の各小見出しを参照してください。

init

アブストラクト回路の最適化、およびマルチ量子ビット演算を1量子ビット演算および2量子ビット演算に還元すること。 詳細については、「 初期化段階」 を参照してください。

layout

仮想量子ビットと物理量子ビットの初期マッピングを選択し、明示的なアンシラを含むように回路を展開してください。 この段階では、時に…が含まれることがある routing。 詳細については、「 レイアウト段階」 を参照してください。

routing

回路にゲートを挿入し、それがの接続制約を満たすようにします Target。 挿入されるゲートは、現時点ではターゲットのISAと一致している必要はないため、多くの場合、単なる swap 命令となります。 この段階は、前の layout 段階がその役割を果たしている場合には、省略されることがあります。 詳細については、「 ルーティング段階」 を参照してください。

translation

回路内のすべてのゲートを、のISAに一致するものに変換する Target。 詳細については、「 翻訳段階」 を参照してください。

optimization

低レベルで、ハードウェアを意識した最適化。 前の init 段階における抽象的な最適化とは異なり、この段階では物理的な回路に対して処理が行われる。 詳細については、「 最適化段階」 を参照してください。

scheduling

回路の壁掛け時計のタイミングを明確にするための指示 Delay を挿入してください。 これには、実時間タイミングの把握を前提とする、動的デカップリングなどのハードウェアを意識したオンライン誤差低減手法も含まれる場合がある。 詳細については、「 スケジューリング段階」 を参照してください。

プリセットのトランスパイラー・パイプラインは、. を設定することで、高レベルでも構成可能です optimization_level。 これは0から3までの整数(両端を含む)であり、ハードウェア向けに回路を最適化しようとする際に費やす相対的な労力を示しています。 レベル 0 では、不要な最適化はすべて無効化され、回路を実行可能にするために必要な変換のみが使用されます。 一方、レベル3では、あらゆる最適化手法が利用可能になりますが、その中にはコンパイル時間が非常に長くなるものもあります。 従来のコンパイラと同様、最適化レベル3が常に最良の結果をもたらすとは限りません。 Qiskitでは、コンパイル時間と期待される最適化の程度とのバランスを考慮し、デフォルトで最適化レベル2が設定されています。

最適化レベルは、特定のステージでデフォルトとしてどの実装が使用されるかに影響しますが、これは に明示的な引 <stage>_method="<choice>" 数を渡すことで上書きすることができます generate_preset_pass_manager()。

プリセットパイプラインの再現性

量子コンパイルでは、計算複雑度が非多項式であることが知られている問題を解くことがしばしばあり、そのため、グローバルな最適化を行うことは困難である。 このような場合、確率的アルゴリズムやヒューリスティックアルゴリズムの方が適していることが多い。 しかし、これによって再現性の問題が生じることになる。

プリセットのパスマネージャーには、ほぼ例外なく、確率論的かつヒューリスティックに基づくパスが含まれています。 コンパイル結果の再現性を確保する必要がある場合は、ジェネレータ関数の引数 seed_transpiler に既知の整数を渡してください。

Qiskit に組み込まれているすべてのプラグインは、分析結果を生成する際、また(もしあれば)ランダム化処理のシードが設定されている場合は、後でコンパイルを再現できるよう、決定論的な DAGCircuit 方法で を変更する必要があります。 これには制限があります:

  • 確率的要素を含むすべての組み込みパスは、ランダム化のシードを設定する手段を提供しなければならず、シードが設定された場合は、決定論的な出力の規則に従わなければならない。
  • 確率的要素を含まないすべての組み込みパスは、同一の入力に対して決定論的な出力を生成するという規則に従わなければならない。 効率化のためにキャッシュを保持することは許容されますが、同じ入力セットが与えられた場合、そのパスが複数回呼び出されても、パスの制御外の要因によって入力のいずれかがその場で変更されない限り、そのパスの戻り値は同一でなければなりません(例えば、プリセット・パス・マネージャーではデフォルト SessionEquivalenceLibrary で が を使用 BasisTranslator しており、等価性ライブラリに新しいエントリが追加された場合に異なる結果が得られるのはバグではありません)。 「出力」とは、パスが後の処理のために書き出すあらゆるものを指します。これには、パスからの明示的な値 return だけでなく、.内で後で利用されることを意図したプロパティも含まれます PropertySet。
  • 特定のマシン、特定のバージョンのQiskit、および固定された環境において、そのパスに利用可能なスレッド数がいくらであっても、そのパスの出力は決定論的であるべきです。 Qiskit に組み込まれている多くのパスはスレッドによる並行処理を採用しており、スレッド数によって動作が異なることは許容されていません。
  • 特定のシードに対するパスの出力は、基盤となる Python 環境の一部が変更された場合(依存パッケージの更新など)、あるいはシステムの数学ライブラリが変更された場合(BLASの異なる実装が利用可能になったなど)、必ずしも同一である必要はありません。
  • 特定のシードに対するパスの出力は、オペレーティングシステム間で必ずしも同一である必要はありません(ただし、通常、オペレーティングシステム間の差異の根本的な原因は、システムの数学ライブラリの実装にあります)。
  • 特定のシードに対する1回の処理の結果は、利用可能なCPU命令が異なる2台のマシン間で必ずしも同一である必要はありません。例えば、融合された乗算・加算命令と、2つの別々の浮動小数点乗算および加算命令とでは丸め特性が異なるなど、利用可能なCPU命令が異なる場合、コアとなる数学カーネルの実装が異なれば、異なる挙動を示す可能性があると考えられます。
  • ユーザーが明示的にこの動作を無効にしない限り、固定のシードに対する1回のパスにおける出力は、使用が許可されているスレッド数にかかわらず、常に同一でなければならない。 たとえば、プリセットのパスマネージャーでは、Sabreのレイアウトおよび配線手法は、デフォルトでは、スレッドが1つしか許可されていない場合でも、あるいはスレッド数が試行回数よりも多い場合でも、同じ数の試行を実行する必要があります。ただし、環境 QISKIT_SABRE_ALL_THREADS 変数を設定してスレッド数に依存するように明示的に指定することで、この動作を上書きすることができます。
  • 上記のルールはすべて、 Python のインタープリタセッション間で適用されます。これは、が明示的に設定 PYTHONHASHSEED されていない場合でも同様です。

一般的に、本製品のユーザーは、組み込みのQiskitパス(必要に応じてシードが設定されたもの)を任意の組み合わせで固定された入力に対して実行した後、すべてのメソッド DAGCircuit() の正確な出力が決定論的であると想定できる DAGCircuit はずです。 これには、順序について何ら保証をしていないメソッドの出力順序も含まれます。セマンティクスや正確な順序は信頼できませんが、固定された入力に対するその決定性は信頼できます。

トランスパイラ・パスの作成者は、トランスパイラ・パスを決定論的にする方法についての解説については、 「ランダム性と決定論」 を参照してください。

プリセットのステージ実装の選択

Qiskit には、上記の各段階に対応するいくつかの実装が含まれており、さらに別の「プラグイン」として追加でインストールすることも可能です。 ステージのどの実装を使用するかを制御するには、2つの関数のキーワード <stage>_method 引数にその名前を渡します(例:) translation_method="translator"。 ステージへのこのような外部プラグインの実装について詳しくは、を参照してください qiskit.transpiler.preset_passmanagers.plugin。

たとえば、最適化レベル 1 で、レイアウトには メソッド trivial を、配線には メソッド sabre を明示的に使用するプリセット・パス・マネージャーを生成するには、次のようにします

from qiskit.transpiler import generate_preset_pass_manager
from qiskit.providers.fake_provider import GenericBackendV2

# Whatever backend you like:
backend = GenericBackendV2(num_qubits=5)

pass_manager = generate_preset_pass_manager(
    optimization_level=1,
    backend=backend,
    layout_method="trivial",
    routing_method="sabre",
)
注

各ステージで利用可能な組み込みプラグインのセットは、Qiskitの公開APIの一部であり、すべての安定性保証の対象となります。 これには、そのメソッドがもたらす高レベルの論理的な影響も含まれます(例えば、 は常にSabreに由来するアルゴリズムを使用 routing_method="sabre" します)。 ただし、ステージ PassManager を表すこの構造の正確な内部構成は明らかではありません。マイナーバージョンごとにパスの順序が変わる場合や、新しいパスが導入される場合もあります。

各ステージにおいて、それが存在する場合、という名前のメソッドが最も変更されやすい "default" 。 Qiskitでは通常、メジャーバージョンの変更時にのみデフォルトメソッドのアルゴリズムを全面的に変更しますが、マイナーバージョンの変更の間には、ヒューリスティックのバランスを調整したり、デフォルトメソッドに新しいパスを追加したりする場合があります。

の出力は generate_preset_pass_manager() であるため StagedPassManager、作成後にパスマネージャーを変更して、完全にカスタマイズされたステージの実装を提供することも可能です。 たとえば、動的デカップリング(pass PadDynamicalDecoupling を使用)を用いてカスタムスケジューリングステージを実行し、さらにルーティングの前に初期の論理最適化を追加したい場合は、次のような処理を行います(前の例を基にしています):

import numpy as np
from qiskit.providers.fake_provider import GenericBackendV2
from qiskit.circuit import library as lib
from qiskit.transpiler import PassManager, generate_preset_pass_manager
from qiskit.transpiler.passes import (
    ALAPScheduleAnalysis,
    InverseCancellation,
    PadDynamicalDecoupling,
)

backend = GenericBackendV2(num_qubits=5)
dd_sequence = [lib.XGate(), lib.XGate()]
scheduling_pm = PassManager(
    [
        ALAPScheduleAnalysis(target=backend.target),
        PadDynamicalDecoupling(target=backend.target, dd_sequence=dd_sequence),
    ]
)
inverse_gate_list = [
    lib.CXGate(),
    lib.HGate(),
    (lib.RXGate(np.pi / 4), lib.RXGate(-np.pi / 4)),
    (lib.PhaseGate(np.pi / 4), lib.PhaseGate(-np.pi / 4)),
    (lib.TGate(), lib.TdgGate()),
]
logical_opt = PassManager([InverseCancellation(inverse_gate_list)])

pass_manager = generate_preset_pass_manager(optimization_level=0)
# Add pre-layout stage to run extra logical optimization
pass_manager.pre_layout = logical_opt
# Set scheduling stage to custom pass manager
pass_manager.scheduling = scheduling_pm

これで、ステージド・パスマネージャーが メソッド run() を介して実行されると、 layout ステージの前に パ logical_opt スマネージャーが呼び出され、その ステージ scheduling ではデフォルトのパスマネージャーの代わりに パ scheduling_pm スマネージャーが使用されるようになります。

プリセット・パス・マネージャー用にカスタムステージを構築する場合は、低レベルのヘルパー関数のいくつかが qiskit.transpiler.preset_passmanagers 役立つかもしれません。

初期化段階

関連資料

初期段階の説明

IBM Quantumガイドにおける「init」ステージについて、ユーザー向けに分かりやすく解説した内容。

このステージ init は、抽象回路に対する高レベルの論理最適化を行うとともに、複数量子ビット(3個以上)の演算を、1量子ビットおよび2量子ビットの演算の連鎖へと変換する役割を担っています。 これは最初のステージの実行であるため、その入力は完全に抽象化された回路です。 このステージ init は、ユーザー定義のゲートや、. などのすべての高レベルの抽象回路記述オブジェクトを処理できる必要があります AnnotatedOperation。

この init ステージの出力は、1クビットおよび2クビットの演算のみを含む抽象回路である。

ステージプラグインを作成する際、のエントリポイントは init です qiskit.transpiler.init。 組み込みプラグインは以下の通りです:

メソッド
サマリー
デフォルトマルチ量子ビット演算の組み込み型展開と抽象的な最適化。

組み込みプラグ default イン

最適化レベル 0 では、抽象的な最適化は行われません。 デフォルトのプラグインは、3個以上の量子ビットを含む操作について、それらの階層的なフィールド definition にアクセスすることで、単にそれらを「展開」するだけです。

最適化レベル 1 以上では、デフォルトのプラグインは、背中合わせに配置された 2 つの cx ゲートなど、隣接する逆ゲートの単純な相殺も行います。

最適化レベル 2 および 3 では、デフォルトのプラグインにより、より広範囲にわたる抽象的な最適化が有効になります。 こちらには以下の内容が含まれます:

  • 「仮想順列省略」(参照 ElidePermutations)とは、明示的な順列誘導演算を削除し、代わりに仮想量子ビットの再マッピングとして実現する手法である。
  • IRの交換構造を解析し、相殺可能なゲートのペアを特定する。
  • 分離可能な1量子ビット演算の系列として表すことができる2量子ビット演算の数値的分割。
  • 測定の直前に実行される、微小な角度のパウリ回転や対角演算など、知覚不可能な演算を除去すること。

レイアウト段階

関連資料

レイアウト段階の説明

IBM Quantumガイドにおける「レイアウト」ステージについて、ユーザー向けに分かりやすく解説した内容。

レイアウト段階では、入力回路の仮想量子ビットとターゲットのハードウェア量子ビットとの間の初期マッピングを行う役割を担っています。 これには、ターゲットと同じ数の量子ビットを持つように、明示的なアンシラを用いて入力回路を拡張すること、およびすべての演算をハードウェア量子ビットを用いて記述し直すことが含まれます。 他のツールキットや文献では、この問題を「配置」問題と呼んでいる場合もあります。

レイアウト段階では、パイプラインの において original_qubit_indices 、プロパティ と layout を設定する必要があります PropertySet。

注

レイアウト段階用のすべての組み込みプラグインは、または generate_preset_pass_manager() の initial_layout 引数を使用して明示的に選択されたレイアウトを優先します transpile()。

回路の任意の時点において、入力回路の現在アクティブな「仮想」量子ビットと、バックエンドのハードウェア量子ビットとの間の対応関係を特定することができます。 ハードウェア量子ビットは、ある時点では常に単一の仮想量子ビットしか表すことができませんが、その対応関係は回路の進行に伴い変化する可能性があります。 原則として、仮想量子ビットの状態の寿命を短縮することができれば、回路の実行中のある時点では一部の仮想量子ビットがマッピングされない場合がありますが、Qiskitに組み込まれているパイプラインでは、現時点ではこの機能は利用されていません。

入力回路からの仮想量子ビットが、バックエンドデバイスの接続マップ上のハードウェア量子ビットにどのようにマッピングされるかを示した図。

レイアウト段階では、回路全体を通じてターゲットの接続性が確保されていることや、すべての操作がターゲット上で直接実行可能であることを保証する責任を負いません。これらは、それぞれ配線段階および変換段階の責任となります。

初期レイアウトの選択は、出力回路の品質に影響を与える最も重要な要素の一つである。 レイアウト段階は、デフォルトのパイプラインにおいて、多くの場合、最も計算負荷の高い段階となります。レイアウト用のデフォルトプラグインでは、いくつかの異なるアルゴリズムを試すことさえあります(詳細は「 組み込みのデフォルトプラグイン 」で説明されています)。

レイアウト段階における理想的な状況とは、すべての操作が回路の接続制約を満たす「完璧な」レイアウトを見つけ出し、それ Target によって配線段階が不要になることです。 通常、任意の入力回路ではこれは不可能ですが、可能である場合には、このパス VF2Layout を利用して有効な初期レイアウトを見つけることができます。 複数の最適なレイアウトが見つかった場合、推定誤り率に基づく評価ヒューリスティックを用いて、どのレイアウトを採用するかを決定します。

すべての組み込みプラグインにおいて、引 generate_preset_pass_manager() 数を渡すと、個別の「選択」ロジックをスキップして、指定されたレイアウトがそのまま使用 initial_layout されます。 すべての組み込みプラグインは、アンシラの割り当てを含め、回路をデバイスの全幅に埋め込む処理も行います。

独自のレイアウトプラグインを作成する場合、レイアウト適用における「埋め込み」段階を自動化するために、これが generate_embed_passmanager() 役立つかもしれません。

ステージプラグインを作成する際、のエントリポイントは layout です qiskit.transpiler.layout。 組み込みプラグインは以下の通りです:

メソッド
サマリー
デフォルト最適化レベルが最高の場合、まず最適なレイアウトを探索し、その後、Sabre ベースのレイアウトと配線の統合処理を実行します。
高密度のバックエンドの中で(量子ビットの連結次数において)最も密な部分グラフを見つけ出し、それを初期量子ビットとして使用します。
平凡な仮想量子ビット 0 を物理量子ビット 0 に、以下同様にマッピングする。
サーベルQiskitの強化版Sabreレイアウトアルゴリズムを使用しています。

どの最適化レベルにおいても、デフォルトのレイアウト方法は ですが default、この段階の構造はレベルによって大きく異なります。

組み込みプラグ default イン

いくつかの異なるレイアウト技法を融合させたものです。

最適化レベル 0 では、単純なレイアウトが選択されます。

最適化レベルが 0 より大きい場合、2 段階のプロセスが実行されます:

  1. まず、 を使って「完璧な」レイアウトを見つけられるか試 VF2Layout してみてください。 同型評価関数への呼び出し回数の最大値は、最適化レベルが高くなるにつれて増加します。 巨大で複雑なターゲットの場合、たとえ完璧なレイアウトが存在したとしても、それを見つけられる保証はありませんが、最適化レベルが高くなるにつれてその可能性は高まります。
  2. 最適なレイアウトが見つからない場合は、 を使用して初期レイアウトを選択 SabreLayout し、最適化レベルの上昇に伴い、初期レイアウトの試行回数、スワップマップの試行回数、および順方向・逆方向の反復回数を増加させます。

さらに、最適化レベル 1 では、過去のバージョンとの下位互換性を確保するため、 VF2-based バージョンの前に、単純なレイアウトも試行します。

組み込みプラグ dense イン

「pass DenseLayout 」を使用してレイアウトを選択します。 このパスでは、対象の完全接続グラフの中から、最も密度の高い連結部分グラフを特定します。ここで「最も密度が高い」とは、利用可能な接続数が最も多いハードウェア量子ビットが優先されることを意味します。 仮想量子ビットとハードウェア量子ビットのマッピングは、最高次数の仮想量子ビットを最高次数のハードウェア量子ビットに割り当てることで完了する。

これは初期レイアウトを選択するための比較的安価なヒューリスティックですが、通常、Sabreベースの手法に比べて出力品質がはるかに劣ります。 デフォルトのレイアウトプラグインは、によって選択された初期マッピングを初期レイアウトの一つ DenseLayout として使用し、Sabreアルゴリズムの初期値として設定します。

組み込みプラグ trivial イン

「pass TrivialLayout 」を使用してレイアウトを選択します。 これは最も単純な割り当て方法で、各仮想量子ビットが同じインデックスを持つハードウェア量子ビットに割り当てられます。つまり、仮想量子ビット 0 はハードウェア量子ビット 0 にマッピングされ、以下同様です。

この手法は、ハードウェア特性評価実験において最も有用です。こうした実験では、入力される「抽象的な」回路はデバイス上で既にフル幅となっており、その動作は物理的な動作に対応しており、トランスパイラは単に物理的な回路の作成を形式化するために呼び出されるに過ぎません QuantumCircuit。

組み込みプラグ sabre イン

を使用して初期レイアウトを選択 SabreLayout します。この際、Qiskitの改良版 Sabre配線アルゴリズムをサブルーチンとして用い、候補となる回路を順方向および逆方向の両方でスワップマップします。

要約すると、 オリジナルのSabreアルゴリズムのレイアウトコンポーネントは、最初に任意の初期レイアウトを選択し、その後、回路に対して配線処理を実行し、回路を反転させ、その反転した回路に対して、前回の「最終」仮想-ハードウェア割り当てを初期状態として配線処理を実行することで、そのレイアウトを「改善」しようと試みる。 設定された最適化レベルによって、この往復処理を何回繰り返すか、および試すランダムな初期レイアウトの数が決まります。

0 以外の最適化レベルにおけるデフォルトのステージとの主な違いは、このプラグインが Sabre ベースのアルゴリズムのみを実行する点です。 この手法は、完璧なレイアウトを見つけようとはせず、また、ありきたりなレイアウトを試みることもない。

ルーティング段階

関連資料

ルーティング段階の説明

『 IBM Quantum』ガイドにおけるルーティング段階について、ユーザー向けに分かりやすく解説した内容。

ルーティング段階では、回路の仮想接続グラフがターゲットのハードウェア接続グラフと互換性があることを確認します。 簡単に言えば、ルーティング段階では、回路内のすべての2量子ビットゲートが、対象のISAにおいて定義された2量子ビット演算を持つハードウェア量子ビットに確実にマッピングされるようにします。 他のツールキットや文献では、この問題を「マッピング」問題や「スワップマッピング」問題と呼んでいる場合もあります。

ルーティングアルゴリズムは通常、回路にゲ swap ートを挿入し、回路の実行過程において量子ビットの仮想-ハードウェアマッピングを変更することで、これを実現します。

配線段階では、回路内のすべてのゲートが対象のISAに対して有効であることを保証する必要はありません。 たとえば、ルーティングプラグインは、たとえその回路に が Target 含まれていなくても、回路内にリテラルゲ swap ートを残すことがあります SwapGate。 ただし、回路内でゲートが適用される任意のハードウェア量子ビットのペアについて Target 、その回路には少なくとも1つの2量子ビットゲートが定義されていなければならない。

ルーティングが行われた場合 PropertySet 、ルーティング段階では、の および final_layout プロパティ virtual_permutation_layout を設定しなければならない。

Qiskit の組み込みルーティングステージはすべて、ルーティング後に VF2PostLayout pass を実行します。 エラー率の低い量子ビットが見つかった場合、これにより初期レイアウトが再割り当てされる可能性があります。 このパスは、 デフォルトのレイアウトプラグインが使用するクラス VF2Layout と非常によく似ていますが、一点異なるのは、ターゲットトポロジーの中に、回路トポロジーと一致する等形誘導部分グラフが少なくとも1つ存在することを保証できるという点 VF2PostLayout です。

注

Qiskitに組み込まれているルーティングプラグインは、概して、定義済みの2量子ビットリンクを持つすべての量子ビットのペアについて、その2つの量子ビットに対して定義された普遍的なゲートセットが存在することを前提としています。 ハードウェアが必ずしもこれを遵守する必要はありません(たとえば、定義されている2量子ビットゲートが のみである場合 swap、 のようなエンタングルメント操作は実現 cx できません)が、Qiskitでは現時点ではこの可能性を考慮していません。

注

挿入に必要なスワップの最小回数を求める問題は、非多項式時間問題であることが知られている。 つまり、これを試みるには莫大なコストがかかるため、Qiskitに組み込まれているアルゴリズムの多くは確率的であり、コンパイルごとに結果に大きなばらつきが見られることがあります。 再現性を確保したい場合は、の引 seed_transpiler 数をまたは generate_preset_pass_manager() に設定してください transpile()。

ステージプラグインを作成する際、のエントリポイントは routing です qiskit.transpiler.routing。 組み込みプラグインは以下の通りです:

メソッド
サマリー
デフォルトQiskitが選択したデフォルトのルーティング方法を使用します。
サーベルデフォルト。 Qiskitの改良版Sabreルーティングアルゴリズムを使用して、マップを入れ替えます。
なしルーティングを無効にする。 ルーティングが必要な場合、エラーを発生させます。
基本1回につき1つの操作をルーティングするための、貪欲なスワップ挿入。
予見ゲートを実行可能にするスワップを見つけるための、ヒューリスティックな剪定を伴う幅優先探索。

組み込みプラグ default イン

ルーティングには、Qiskitが選択したデフォルトの手法を使用します。 Qiskit 2.0 の時点では、選択されるアルゴリズムは組み込みの Sabre プラグインと同じですが、実際には、通常、 組み込みのデフォルトのレイアウトステージプラグインが Sabre ベースの配線アルゴリズムを実行し、配線ステージは. を実行するためにのみ使用されます VF2PostLayout。

組み込みプラグ none イン

ルーティングを完全に無効にするために使用されるダミープラグインです。 これは、ハードウェア構成の実験や、部分コンパイルの特定の特殊なケースにおいて、時折役立つことがあります。

組み込みプラグ basic イン

貪欲 BasisSwap なスワップ挿入アルゴリズムを使用します。 これは概念的には非常に単純です。位相順序に従って各操作について、デバイス上でその接続を実行可能にするために必要な最短経路のスワップを挿入します。

最適化レベルは、配線後の初期レイアウトを改善するためにそのステップ VF2PostLayout が行う処理量にのみ影響します。

この方法では、通常、出力品質が低くなります。

組み込みプラグ lookahead イン

ルーティングには、このアルゴリズム LookaheadSwap を使用します。 これは本質的に、スワップネットワークを生成するための幅優先探索であり、探索対象のツリーは各深さにおいて、少数のスワップ候補に絞り込まれていきます。

このアルゴリズムは、 「sabre」プラグインのヒューリスティック basic と似ていますが、各スワップが浅い深さにおいて及ぼす以下の影響も考慮している点が異なります。

最適化レベルは、探索深度、深度ごとの剪定量、および初期レイアウトの事後最適化を行う VF2PostLayout ためにが処理する作業量に影響を与えます。

実際には、 「sabre」プラグインは数桁も高速に動作し、より高品質な出力を生成します。

組み込みプラグ sabre イン

ルーティングには、このアルゴリズム SabreSwap を使用します。 ここでは、 Qiskitが改良を加えたオリジナルのSabreルーティングアルゴリズムを使用しています。

このルーティングアルゴリズムは、スレッドによる並列処理で実行され、ルーティングに関するいくつかの異なる可能性を検討した上で、挿入されるスワップの数を最小化するものを選択します。

最適化レベルは、フルルーティングにおいて試行される異なる乱数シードの数、および初期レイアウトのポスト最適化 VF2PostLayout に要する作業量に影響を与えます。

これはほぼ例外なく最も高性能な組み込みプラグインであり、ルーティングが必要なあらゆる場面でQiskitがデフォルトで使用しているものです。

翻訳段階

関連資料

翻訳段階の説明

『 IBM Quantum』ガイドにおける翻訳段階について、ユーザー向けに分かりやすく解説した内容です。

翻訳段階では、回路内のすべてのゲートを、対象のISAでサポートされているゲートに書き換える役割を担っています。 たとえば、ハードウェア量子ビット 0 と 1 に対して が要求 cx されたものの、ISA にそれらの量子ビットに対する 演算 cz しか含まれていない場合、変換段階では、 および cz 利用可能な 1 量子ビットゲートを用いて ゲ cx ートを表現する方法を見つけなければならない。

最適化段階に入る前に、翻訳段階が呼び出されます。 最適化プラグイン(Qiskitの組み込みプラグインを含む)は、最適化ループが非ISAゲートを含む回路を返した場合、その最適化ループの後に「修正」段階として変換段階を使用することもあります。 後者の状況は比較的よく見られる。最適化ループは、「2量子ビットゲートの数」といった特性の最小化のみを目的としており、その出力は局所的に同等のゲートで表される。これにより、変換段階では、目標とする最適化特性に影響を与えることなく、その出力を容易に書き換えることができる。 これにより、2つの段階間の関心の分離が容易になります。 最適化プラグインによっては、出力の基準がより厳格な場合があるため、翻訳段階の後にこの作業を行う必要がなくなる可能性があります。

ステージプラグインを作成する際、のエントリポイントは translation です qiskit.transpiler.translation。 組み込みプラグインは以下の通りです:

メソッド
サマリー
デフォルトQiskitが選択したデフォルトの変換方法を使用します。
変換プログラム既知の同値関係を用いて、ゲートをターゲット基底へ記号的に変換すること。
合成1クビットゲートおよび2クビットゲートの各実行を行列表現にまとめ、そこから再合成を行う。

組み込みプラグ default イン

翻訳には、Qiskitが選択したデフォルトの方法を使用してください。 Qiskit 2.0 の時点では、これは組み込みのトランスレータプラグインと同じですが、 2.x シリーズにおいて、選択されるアルゴリズムが、すべてのターゲットに対して、あるいは特定のクラスのターゲットに対してのみ、変更される可能性があります。

組み込みプラグ synthesis イン

同じ量子ビット上のゲートの連鎖を行列形式にまとめ、その後、 UnitarySynthesis パス(構成済みの unitary_synthesis_method)を使用して再合成します。 これは、最適化レベルが高い場合、最適化ループそのものと大部分が類似しています。

行列を用いた翻訳は、通常、行列を使用しない翻訳よりも計算コストが高くなりますが、原則として翻訳の品質は向上する可能性があります。 実際には、これには対象のISAに合わせた合成アルゴリズムが必要となるため、この手法は他の手法に比べて汎用性が低い。 Qiskitにすでに実装されている合成ルーチンと一致する単純なISAを対象とした場合、より高品質な結果が得られる可能性があります。

この方法を使用する場合、最適化ループは必要なくなる可能性があります。

このプラグインでは、最適化レベルは影響しません。

組み込みプラグ translator イン

このアルゴリズム BasisTranslator を用いて、ゲートを対象基底へと記号的に変換します。 大まかに言えば、これは回路から要求されたゲートの集合から始まり、所定の( EquivalenceLibrary 通常は SessionEquivalenceLibrary)規則を用いてISAへと導いていく。

これがデフォルトの翻訳方法です。

このプラグインでは、最適化レベルは影響しません。

最適化段階

関連資料

最適化段階の説明

『 IBM Quantum』ガイドにおける最適化段階について、ユーザー向けに分かりやすく解説した内容。

最適化段階では、ハードウェアを意識した低レベルの最適化が行われます。 init ステージとは異なり、このステージへの入力はすでに ISA 互換となっている回路であるため、特定の ISA に合わせて低レベルの最適化プラグインをカスタマイズすることができます。

最適化プラグインに対する要件は、ISAでサポートされている回路を受け入れ、ISAでサポートされている回路を返すこと以外には、ほとんどありません。 最適化プラグインには、多くの場合、のようなループが含まれており DoWhileController、設定された変換ステージが修正パイプラインとして組み込まれていることもあります。

Qiskitに組み込まれている最適化プラグインは汎用性が高く、エラー訂正機能のないデバイス向けの現実のISAsのほとんどにうまく適用できます。 組み込みプラグインは、連続的にパラメータ化可能な単一量子ビットゲートを一切持たないISAにはあまり適していません。

ステージプラグインを作成する際、のエントリポイントは optimization です qiskit.transpiler.optimization。 組み込みプラグインは以下の通りです:

メソッド
サマリー
デフォルトデフォルトの最適化処理のセット。 これは、最適化レベルによって大きく異なります。

組み込みプラグ default イン

これは、最適化のレベルによって大きく異なります。

このパイプラインの詳細は、Qiskitのバージョンによって変更される場合があります。 その大まかな原則については、以下に説明します。

最適化レベル 0 では、ステージは空です。

最適化レベル1では、このステージは、単一量子ビットゲートの連続した実行に対して行列ベースの再合成を行い、2量子ビットゲートが連続して現れる場合には、非常に単純な記号的な逆キャンセルを行います。 これは、回路のサイズと深さが確定するまでループを繰り返します。

最適化レベル 2 では、レベル 1 の最適化に加え、ループ内でゲート群の交換解析が行われ、キャンセルの対象となり得るゲートの範囲が拡大されます。 ループに入る前に、1クビットゲートと2クビットゲートの両方のゲート列に対して、単一の行列ベースの再合成が行われる。

最適化レベル 3 では、2 量子ビット行列ベースの再合成が最適化ループ内で実行されます。 最適化ループの条件では、出力が変動する場合にも複数回の実行を試み、その中から最小値となる点を選択します。これは、行列ベースの再合成が具体的なゲート数に関して比較的不安定であるため、必要な処理です。

最適化レベル3は、大規模な回路の場合、通常、非常にコストがかかります。

スケジューリング段階

関連資料

回路のスケジューリング

スケジューリングの概念に関する入門レベルの解説。

スケジューリング段階では、要求があった場合、量子ビットのアイドル期間を明示的に示すための明示的な指示 Delay を挿入する役割を担う。 プラグインは、必要に応じて、動的なデカップリングシーケンスの挿入など、ウォールタイムに依存する変換を行うことを選択できます。

スケジューリング段階への入力は、ISA互換の回路である。 スケジューリング段階の出力も、ISA互換の回路でなければならず、必要に応じて、ハードウェアのタイミング情報を満たす明示的な命令 Delay を含んでいる必要がある。

スケジューリング段階では、パイプラインの 内の プロパティ node_start_time を設定する必要があります PropertySet。

ステージプラグインを作成する際、のエントリポイントは scheduling です qiskit.transpiler.scheduling。 組み込みプラグインは以下の通りです:

メソッド
サマリー
デフォルトスケジューリングを行わずに、タイミング整合制約を満たそうとする。
alap回路のスケジュールを立て、各工程をできるだけ遅く行うようにする。
ASAP回路のスケジュールを立て、作業はできるだけ早い時期に行うようにしてください。

組み込みプラグ default イン

回路にすでに明示的なタイミングが指定された命令が含まれていない限り、何も行わない。 回路内に明示的にタイミングが指定された操作がある場合は、これらのタイミングがアライメントやその他のハードウェア制約を満たすよう、追加のパディングを挿入してください。

組み込みプラグ alap イン

すべての操作について、「できるだけ遅く」という戦略を用いて、明示的にスケジュールを設定してください。 ここでは、ゲートをどこに配置するかを決定するために、このアルゴリズム ALAPScheduleAnalysis を使用しています。

組み込みプラグ asap イン

すべての操作について、「できるだけ早く」という戦略を用いて明示的にスケジュールを設定してください。 ここでは、ゲートをどこに配置するかを決定するために、このアルゴリズム ASAPScheduleAnalysis を使用しています。


カスタムパスマネージャー

プリセットのパスマネージャを変更するだけでなく、入力回路を変換するための完全にカスタマイズされたパイプラインを構築するためのパスマネージャを作成することも可能です。 これを行うには、このクラ StagedPassManager スを直接使用できます。 任意のステージ名を定義し、そこにインスタンス PassManager を設定することができます。 たとえば、次のコードは、2つのステージ( と init ) StagedPassManager を持つ新しい を作成します translation。

from qiskit.transpiler.passes import (
    UnitarySynthesis,
    Collect2qBlocks,
    ConsolidateBlocks,
    UnitarySynthesis,
    Unroll3qOrMore,
)
from qiskit.transpiler import PassManager, StagedPassManager

basis_gates = ["rx", "ry", "rxx"]
init = PassManager([UnitarySynthesis(basis_gates, min_qubits=3), Unroll3qOrMore()])
translate = PassManager(
    [
        Collect2qBlocks(),
        ConsolidateBlocks(basis_gates=basis_gates),
        UnitarySynthesis(basis_gates),
    ]
)

staged_pm = StagedPassManager(
    stages=["init", "translation"], init=init, translation=translate
)

. に配置できるステージの数に制限はありません StagedPassManager。 各ステージは、Qiskitのプリセットパイプラインで使用されているステージと一致している必要はありません。

Stageジェネレータの関数は、カスタムインスタンス StagedPassManager の構築に役立つ場合があります。 これらは、多くの段階で共通して使用される機能を提供するパスマネージャーを生成します。 たとえば、レイアウトパス Layout から選択された初期 を、指定されたターゲットデバイスに「埋め込む」 PassManager ために を生成 generate_embed_passmanager() します。


カスタムトランスパイラ・パスの作成

Qiskitは、カスタムや特殊なトランスパイラ・パスによって機能を拡張できるよう設計されています。

トランスパイラーのパスには2種類あります。1つは「解析」パス(AnalysisPass)で、回路を読み取り、グローバルな解析プロパティを に書き込みます PropertySet。もう1つは「変換」パス(TransformationPass)で、をその DAGCircuit 場で変更するか、新しい を返します DAGCircuit。 これまで、Qiskit ではこれら 2 つのタイプを厳密に区別しようとしてきました。 しかし、現代のQiskitでは、すべてを分割しようとするよりも TransformationPass、分析と修正の両方を1つのスタンドアロンにまとめることがむしろ一般的です。 もしそのパスが純粋に分析に基づいている場合でも、. を使用するのは適切です AnalysisPass。

パスの著作者に関する一般原則

を修正したり、新しいものを作成したりしたい場合は DAGCircuit、を作成する必要があります TransformationPass。 に書き込むだけで PropertySet 、を変更したくない場合は DAGCircuit、を記述する必要があります AnalysisPass。 両方を行いたい場合は、. と記述してください TransformationPass。 どちらの場合も、必須のメソッドは だけであり BasePass.run()、これがパスの中心となる部分です。 これは、単一の引数(を除く self)を受け入れるはずです dag: DAGCircuit。 もし a であれば TranspilerPass、a を返す必要があります( DAGCircuit その場で変更された場合は、入力そのものを返すことも可能です)。一方、a であれば AnalysisPass、 を返す必要があります None。

パスに初期化子が含まれている場合は、. を呼び出す必要があります super().__init__()。

通常、パスは初期化子 Target として を受け入れるようになっており、これはコンパイル対象の量子ハードウェアを記述するものです。 個別の結合マップや基本ゲートのリストといった「大まかな」制約を受け入れることは推奨されません。 の方が、一般的な異種ハードウェアをより正確に表現 Target しています。

パイプライン PassManager の実行中に、パスのメソッド run() が呼び出された際、属性にアクセスして self.property_set 、トランスパイルの現在の PropertySet 状態を取得することができます。 このデータに対しては、その場で読み書きを行う必要があります。 パスには、読み書きを行うプロパティセット内の属性(ある場合)が、どのようなものであるかを明確に記述する必要があります。

ランダム性と決定論

量子コンパイルでは、グローバル最適化では解決が困難な問題を解くことがよくあります。 このような場合、確率的アルゴリズムやヒューリスティックアルゴリズムの方が適していることが多い。 しかし、これによって再現性の問題が生じることになる。

組み込みのQiskitパスが従わなければならないのと同じ厳密なルールセットの下で、カスタムパスが決定論的であるという正式な要件は存在しません。 ただし、ご自身の実験ではこれらのルールを遵守されることを強くお勧めします。科学は再現性によって成り立っており、以前に観察された挙動を再現できない場合、デバッグ作業は悪夢のようなものになります。

トランスパイラ・パスを記述する際、順序の正確な意味論が完全に規定されていない場合でも、またパスは特定の順序に依存すべきではないとしても、以下の(代表的なものであり、網羅的ではない)例が決定論的であることを前提とすることができます:

  • 順序ノードは、. で見つかります DAGCircuit.op_nodes()。 対照的に、デフォルト topological_op_nodes() では、ノードの削除・挿入の順序に全く影響されない順序キーが含まれているため、たとえ構築順序が異なっていても、同じデータフローを持つ同じノードの集合が指定されていれば、完全に決定論的である。
  • 順序エッジは、. において現れます DAGCircuit.edges()。
  • 実行結果が返される順序 DAGCircuit.collect_2q_runs()、および実行内のノードが処理される正確な順序。
  • predecessors()、 bfs_successors()、などといった順序非特異な手法において、ノードが検出される順序。

一般的に、 同じ回路の変更をすべて、まったく同じ順序で行うことが求められます。 たとえば、ノードを追加、縮小、または削除する場合、これらの変更は決定論的な順序で行われなければならず、置換対象も決定論的に指定されなければならない。

これを確実にするためのヒントとしては、次のようなものがあります:

  • ハッシュベースのコンテナを反復処理する際は、細心の注意を払ってください。 Python に対する反復処理は、ハッシュシードのランダム化により非決定論的 set となります。 Rust では、標準ライブラリのハッシュベースのコンテナ(デフォルトのハッシュ関数を持つ hashbrown ものも含む)に対する反復処理は、非決定論的です。

    注

    Python の反復処理は決定 dict は 論的であり、削除が行われていない場合は挿入順であることが保証され、削除が行われた場合でも、その順序は任意ではあるが依然として決定論的である。

    Python において、を作成 set してからそれを反復処理する必要がある場合は、代わりに、すべての値が dict None である を使用することを検討してください。 を単に set メンバーシップの検証にのみ使用しても、何の問題もありません。

    Rust では、それぞれ および HashMap の IndexSet 代わりに および indexmap その構造体 IndexMap と を使用してください HashSet。これらは、 Python の と同様の決定論的反復の性質を持っています dict。

  • パスに確率的な要素が含まれる場合は、必ず 入力 seed を受け入れるようにし、それが整数として指定された場合は出力を純粋なものにしてください。 通常、これはシードを保存し、各呼び出しの開始時にこのシードから新しい pRNG をインスタンス化することを意味します BasePass.run()。

  • スレッド並列処理を使用する場合は、出力が、スレッドが処理を実行する順序や部分的な結果を返す順序に依存しないように注意してください。 たとえば、スレッドプールに処理を分散させ、最後に結果を集約する場合は、出力が入力と同じ順序になるようにしてください。 Python では、次のような関数がこれを保証 concurrent.futures.ThreadPoolExecutor.map() しています。 同様に、Rustにおいても、並列イテレータ rayonは入力と同じ順序で出力を収集します。

    「このイテレータの各要素に関数を適用し、ある指標を最小化するものを選択する」といった並列の「削減」は、指標に縮退性が存在する場合、通常、スレッド間の非決定性に非常に影響を受けやすいことに注意してください。 たとえば、イテレータ内の2つの項目が、異なる出力を生成するものの、比較キーが同じである場合、スレッド環境においてどちらが選択されるかは決定論的ではありません。 これを回避するには、決定論的なタイブレーク処理を適用して同値を解消します。例えば、入力を列挙し、その順序番号をタイブレークのキーとして使用することで、2つの項目が同じスコアとなった場合でも、より早い入力に対応する方が確実に選択されるようにします。


量子コンピュータの表現

特定のバックエンド QuantumCircuit 向けにコンパイルを行うためには、トランスパイラは、そのバックエンドの制約、命令セット、量子ビットの特性などを含む、そのバックエンドに特化した表現を必要とし、それによって効果的なコンパイルと最適化が可能となります。 このクラ BackendV2 スは、バックエンドへのクエリやバックエンドとのやり取りを行うためのインターフェースを定義していますが、その適用範囲はトランスパイラの要件にとどまらず、ジョブの送信管理や、場合によってはリモートサービスとの連携なども含んでいます。 トランスパイラーが必要とする具体的な情報は、この Target クラスによって記述されています

たとえば、単純なオブジェクト Target を構築するには、そのオブジェクトがサポートする命令の説明を繰り返し追加していくことができます:

from qiskit.circuit import Parameter, Measure
from qiskit.transpiler import Target, InstructionProperties
from qiskit.circuit.library import UGate, RZGate, RXGate, RYGate, CXGate, CZGate

target = Target(num_qubits=3)
target.add_instruction(CXGate(), {(0, 1): InstructionProperties(error=.0001, duration=5e-7)})
target.add_instruction(
    UGate(Parameter('theta'), Parameter('phi'), Parameter('lam')),
    {
        (0,): InstructionProperties(error=.00001, duration=5e-8),
        (1,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RZGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RYGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RXGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    CZGate(),
    {
        (1, 2): InstructionProperties(error=.0001, duration=5e-7),
        (2, 0): InstructionProperties(error=.0001, duration=5e-7)
    }
)
target.add_instruction(
    Measure(),
    {
        (0,): InstructionProperties(error=.001, duration=5e-5),
        (1,): InstructionProperties(error=.002, duration=6e-5),
        (2,): InstructionProperties(error=.2, duration=5e-7)
    }
)
print(target)
Target
Number of qubits: 3
Instructions:
    cx
        (0, 1):
            Duration: 5e-07 sec.
            Error Rate: 0.0001
    u
        (0,):
            Duration: 5e-08 sec.
            Error Rate: 1e-05
        (1,):
            Duration: 6e-08 sec.
            Error Rate: 2e-05
    rz
        (1,):
            Duration: 5e-08 sec.
            Error Rate: 1e-05
        (2,):
            Duration: 6e-08 sec.
            Error Rate: 2e-05
    ry
        (1,):
            Duration: 5e-08 sec.
            Error Rate: 1e-05
        (2,):
            Duration: 6e-08 sec.
            Error Rate: 2e-05
    rx
        (1,):
            Duration: 5e-08 sec.
            Error Rate: 1e-05
        (2,):
            Duration: 6e-08 sec.
            Error Rate: 2e-05
    cz
        (1, 2):
            Duration: 5e-07 sec.
            Error Rate: 0.0001
        (2, 0):
            Duration: 5e-07 sec.
            Error Rate: 0.0001
    measure
        (0,):
            Duration: 5e-05 sec.
            Error Rate: 0.001
        (1,):
            Duration: 6e-05 sec.
            Error Rate: 0.002
        (2,):
            Duration: 5e-07 sec.
            Error Rate: 0.2

これは、量子ビット0と1 CXGate の間、量子ビット0と1 UGate 上、 RZGate、 RXGate、および量子ビット1と2 RYGate 上、量子ビット1と2 CZGate の間、量子ビット2と0の間、ならびにすべての量子ビット Measure 上で、それぞれをサポートする3量子ビットのバックエンドを表 Target しています。

また、. からの情報の特定のサブセットを表すための専用のデータ構造も存在します Target。 例えば、このクラ CouplingMap スは、バックエンドの接続制約を有向グラフとして表現することのみを目的として使用されます。 カップリングマップは、 メソッド TargetTarget.build_coupling_map() を使用して から生成することができます。 これらのデータ構造は、通常、Target class よりも前に存在していましたが、まだ class Target インスタンスとネイティブに連携できない一部のトランスパイラ・パスや、最新の BackendV2 interface を使用していないバックエンドを扱う際にも、依然として使用されています。

たとえば、上記の Target 3キュービットの例 CouplingMap について、その状態を可視化したい場合:

from qiskit.circuit import Parameter, Measure
from qiskit.transpiler import Target, InstructionProperties
from qiskit.circuit.library import UGate, RZGate, RXGate, RYGate, CXGate, CZGate

target = Target(num_qubits=3)
target.add_instruction(CXGate(), {(0, 1): InstructionProperties(error=.0001, duration=5e-7)})
target.add_instruction(
    UGate(Parameter('theta'), Parameter('phi'), Parameter('lam')),
    {
        (0,): InstructionProperties(error=.00001, duration=5e-8),
        (1,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RZGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RYGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RXGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    CZGate(),
    {
        (1, 2): InstructionProperties(error=.0001, duration=5e-7),
        (2, 0): InstructionProperties(error=.0001, duration=5e-7)
    }
)
target.add_instruction(
    Measure(),
    {
        (0,): InstructionProperties(error=.001, duration=5e-5),
        (1,): InstructionProperties(error=.002, duration=6e-5),
        (2,): InstructionProperties(error=.2, duration=5e-7)
    }
)

target.build_coupling_map().draw()

これは、および CXGate のサポート対象クビットを組み合わせた Target ものの、グローバルな接続性を示しています CZGate。 個々の接続状況を確認するには、操作名を以下に指定します CouplingMap.build_coupling_map():

from qiskit.circuit import Parameter, Measure
from qiskit.transpiler import Target, InstructionProperties
from qiskit.circuit.library import UGate, RZGate, RXGate, RYGate, CXGate, CZGate

target = Target(num_qubits=3)
target.add_instruction(CXGate(), {(0, 1): InstructionProperties(error=.0001, duration=5e-7)})
target.add_instruction(
    UGate(Parameter('theta'), Parameter('phi'), Parameter('lam')),
    {
        (0,): InstructionProperties(error=.00001, duration=5e-8),
        (1,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RZGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RYGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RXGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    CZGate(),
    {
        (1, 2): InstructionProperties(error=.0001, duration=5e-7),
        (2, 0): InstructionProperties(error=.0001, duration=5e-7)
    }
)
target.add_instruction(
    Measure(),
    {
        (0,): InstructionProperties(error=.001, duration=5e-5),
        (1,): InstructionProperties(error=.002, duration=6e-5),
        (2,): InstructionProperties(error=.2, duration=5e-7)
    }
)

target.build_coupling_map('cx').draw()
from qiskit.circuit import Parameter, Measure
from qiskit.transpiler import Target, InstructionProperties
from qiskit.circuit.library import UGate, RZGate, RXGate, RYGate, CXGate, CZGate

target = Target(num_qubits=3)
target.add_instruction(CXGate(), {(0, 1): InstructionProperties(error=.0001, duration=5e-7)})
target.add_instruction(
    UGate(Parameter('theta'), Parameter('phi'), Parameter('lam')),
    {
        (0,): InstructionProperties(error=.00001, duration=5e-8),
        (1,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RZGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RYGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    RXGate(Parameter('theta')),
    {
        (1,): InstructionProperties(error=.00001, duration=5e-8),
        (2,): InstructionProperties(error=.00002, duration=6e-8)
    }
)
target.add_instruction(
    CZGate(),
    {
        (1, 2): InstructionProperties(error=.0001, duration=5e-7),
        (2, 0): InstructionProperties(error=.0001, duration=5e-7)
    }
)
target.add_instruction(
    Measure(),
    {
        (0,): InstructionProperties(error=.001, duration=5e-5),
        (1,): InstructionProperties(error=.002, duration=6e-5),
        (2,): InstructionProperties(error=.2, duration=5e-7)
    }
)

target.build_coupling_map('cz').draw()

回路のスケジューリング

関連資料

スケジューリング段階

プリセット・パス・マネージャーのスケジューリング段階を設定する方法。

回路がターゲット基底に変換され、デバイスにマッピングされ、最適化された後、オプションとして、回路内のすべてのアイドル時間を考慮に入れるためにスケジューリング段階を適用することができます。 大まかに言えば、スケジューリングとは、命令の実行と実行の合間にクビットがアイドル状態になる時間を考慮して、回路に遅延を挿入することだと考えることができます。 例えば、次のような回路から考えてみましょう:

前述の回路を示す図。

その後、set scheduling_method を使用して、そのオブジェクト transpile() に対して call を実行できます:

from qiskit import QuantumCircuit, transpile
from qiskit.providers.fake_provider import GenericBackendV2

backend = GenericBackendV2(5)

ghz = QuantumCircuit(5)
ghz.h(0)
ghz.cx(0,range(1,5))

circ = transpile(ghz, backend, scheduling_method="asap")
circ.draw(output='mpl')
前のコードによって出力された回路図。

ここでわかるように、トランスパイラーは各量子ビットのアイドル時間を考慮した命令 Delay を挿入しています。 回路のタイミングをよりよく把握するために、次の関数 timeline.draw() を使って検討することもできます:

回路タイムライン描画機能からの出力。

回路のスケジューリングには、解析と制約マッピングという2つの段階があり、その後にパディング処理が行われます。 最初のステップでは、 や ALAPSchedulingAnalysis などのスケジューリング解析パスを実行する必要があります。 ASAPSchedulingAnalysis これにより、回路が解析され、プロパティセットに含まれるスケジューリングアルゴリズム( の場合は「可能な限り遅く」、 ALAPSchedulingAnalysis の場合は「可能な限り早く」 ASAPSchedulingAnalysis)を用いて、回路内の各命令の開始時刻が記録されます。 回路の初期スケジューリングが完了したら、アライメント制約など、ターゲットバックエンドにおけるタイミング制約を考慮するために、追加のパスを実行することができます。 これは通常、ConstrainedReschedule pass を使用して行われ、これにより、プロパティセットで設定されたスケジューリングが、ターゲットバックエンドの制約に合わせて調整されます。 すべてのスケジューリングおよび調整・再スケジューリングが完了すると、や PadDelay などのパディングパスが実行 PadDynamicalDecoupling され、命令が回路に挿入されることで、スケジューリングが完了する。


トランスパイラー API

ハードウェアの詳細

コラム「 1 」
コラム「 2 」
Target( [説明, 量子ビット数, dt,...] )この Target オブジェクトの目的は、特定のバックエンドの制約をQiskitのコンパイラに通知し、コンパイラが入力回路を、デバイス上で正常に動作し、かつ最適化された形にコンパイルできるようにすることです。
InstructionProperties( [所要時間、エラー] )ゲート実装の特性を表したもの。
WrapAngleRegistry()角度ラッピング関数のレジストリ

パスマネージャーの定義

コラム「 1 」
コラム「 2 」
StagedPassManager( [ステージ] )個々のステージから構成されるパスマネージャーパイプライン。
PassManager( [passes, max_iteration] )トランスパイル処理中のパス群およびそのスケジューリングを管理するマネージャー。
PassManagerConfig( [initial_layout,...] )パスマネージャーの設定。
PassManagerCliffordTConfig( [initial_layout,...] )Clifford+T トランスパイレーション用の Pass Manager の設定。
generate_preset_pass_manager([...])プリセットを生成する PassManager
generate_preset_clifford_t_pass_manager([...])Clifford+T のプリセットを生成する StagedPassManager。
generate_preset_pbc_pass_manager([...])PBCのプリセットを生成します StagedPassManager。

レイアウトとトポロジー

コラム「 1 」
コラム「 2 」
Layout( [input_dict] )レイアウトを表す双方向ディクショナリ。
CouplingMap( [結合リスト, 説明] )固定結合を指定する有向グラフ。
TranspileLayout(initial_layout,...[,...] )トランスパイラーからの出力回路のレイアウト属性。

スケジューリング

コラム「 1 」
コラム「 2 」
InstructionDurations( [instruction_durations, dt] )スケジューリングに必要な指示の所要時間を提供するヘルパークラス。

要旨パス

コラム「 1 」
コラム「 2 」
TransformationPass(*args, **kwargs)変換パス:プロパティセットではなく、DAGを変更する。
AnalysisPass(*args, **kwargs)分析パス:DAGではなく、プロパティセットを変更する。

例外

TranspilerError

exception qiskit.transpiler.TranspilerError(*message)

GitHub

ベース: TranspilerAccessError

トランスパイレーション中に発生した例外。

エラーメッセージを設定します。

TranspilerAccessError

exception qiskit.transpiler.TranspilerAccessError(*message)

GitHub

ベース: PassManagerError

非推奨:トランスパイラ・パスでアクセスエラーが発生しました。

エラーメッセージを設定します。

CouplingError

exception qiskit.transpiler.CouplingError(*msg)

GitHub

ベース: QiskitError

カップリンググラフオブジェクトによって発生するエラーの基底クラス。

エラーメッセージを設定します。

LayoutError

exception qiskit.transpiler.LayoutError(*msg)

GitHub

ベース: QiskitError

レイアウトオブジェクトによって発生したエラー。

エラーメッセージを設定します。

CircuitTooWideForTarget

exception qiskit.transpiler.CircuitTooWideForTarget(*message)

GitHub

ベース: TranspilerError

回路の幅がターゲットに対して広すぎる場合、エラーが発生します。

エラーメッセージを設定します。

InvalidLayoutError

exception qiskit.transpiler.InvalidLayoutError(*message)

GitHub

ベース: TranspilerError

ユーザーが指定したレイアウトが無効な場合、エラーが発生します。

エラーメッセージを設定します。

最適化指標

コラム「 1 」
コラム「 2 」
OptimizationMetric(*値)トランスパイル時に考慮される最適化指標。
このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。