メインコンテンツへスキップ
このプロジェクトはベータ版です。バグを見つけましたか?GitHub Issueを開く。質問やアイデアがありますか?Discussionsで質問する — フィードバックをお待ちしています!
このページの翻訳品質はいかがですか?

トランスパイラー向けに量子コンピューターを表現する

パッケージバージョン

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

qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0

抽象Circuitを特定のQPU(量子処理ユニット)上で実行可能なISA Circuitに変換するには、TranspilerがそのQPUに関する特定の情報を必要とします。この情報は2つの場所にあります。ジョブの送信先として計画しているBackendV2(またはレガシーのBackendV1)オブジェクトと、BackendのTarget属性です。

  • Target には、ネイティブ基底ゲート、量子ビット接続性、パルスやタイミング情報など、デバイスに関するすべての関連制約が含まれています。

  • Backend はデフォルトで Target を持ち、InstructionScheduleMap などの追加情報を含み、量子回路ジョブを送信するためのインターフェースを提供します。

また、特定のユースケースがある場合や、この情報がトランスパイラーによるより最適化された回路の生成に役立つと考える場合は、トランスパイラーが使用する情報を明示的に提供することもできます。

特定のハードウェアに対してトランスパイラーが最適な回路を生成する精度は、Target または Backend が保持する制約情報の量に依存します。

備考

基礎となるトランスパイルアルゴリズムの多くは確率的であるため、より良い回路が必ずしも見つかるとは限りません。

このページでは、QPU 情報をトランスパイラーに渡す例をいくつか示します。

デフォルト設定​

Transpilerの最も単純な使用方法は、BackendまたはTargetを提供することで、すべてのQPU情報を提供することです。Transpilerの動作をよりよく理解するために、以下のように回路を構築し、異なる情報を使ってトランスパイルしてみましょう。

必要なライブラリをインポートし、QPUをインスタンス化します。 抽象回路を特定のプロセッサ上で実行可能なISA回路に変換するには、Transpilerがそのプロセッサに関する特定の情報を必要とします。通常、この情報はTranspilerに提供されるBackendまたはTargetに格納されており、それ以上の情報は必要ありません。ただし、特定のユースケースがある場合や、この情報がTranspilerがより最適化された回路を生成するのに役立つと思われる場合は、Transpilerが使用する情報を明示的に提供することもできます。

このトピックでは、トランスパイラーに情報を渡す例をいくつか紹介します。

備考

これらの例では、qiskit_ibm_runtimeのFakeSherbrookeモックBackendのtargetを使用しています。ただし、Qiskit互換の任意の実機または模擬Backendで試すこともできます。結果は異なる場合があります。

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()
target = backend.target

サンプル回路には、Qiskit の回路ライブラリから efficient_su2 のインスタンスを使用します。

from qiskit.circuit.library import efficient_su2

qc = efficient_su2(12, entanglement="circular", reps=1)

qc.draw("mpl")

Output of the previous code cell

この例では、デフォルト設定を使用して backend の target にトランスパイルします。これにより、回路をバックエンドで実行できる回路に変換するために必要なすべての情報が提供されます。

from qiskit.transpiler import generate_preset_pass_manager

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=target, seed_transpiler=12345
)
qc_t_target = pass_manager.run(qc)
qc_t_target.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

この例は、このトピックの後続のセクションで、カップリングマップと基底ゲートが最適な回路構築のためにトランスパイラーに渡すべき重要な情報であることを示すために使用されます。QPU は通常、タイミングやスケジューリングなど、渡されなかった他の情報についてはデフォルト設定を選択できます。

カップリングマップ​

カップリングマップは、どの量子ビットが接続されており、したがってそれらの間に 2 量子ビットゲートが存在するかを示すグラフです。このグラフが方向性を持つ場合があり、その場合 2 量子ビットゲートは一方向にしか作用できません。ただし、トランスパイラーは追加の 1 量子ビットゲートを加えることでゲートの方向を常に反転できます。抽象的な量子回路は、接続性が限られていても、量子情報を移動させるための SWAP ゲートを導入することで、常にこのグラフ上に表現できます。

抽象回路の量子ビットを 仮想量子ビット、カップリングマップ上の量子ビットを 物理量子ビット と呼びます。トランスパイラーは仮想量子ビットと物理量子ビットの間のマッピングを提供します。トランスパイルの最初のステップの一つである レイアウト ステージがこのマッピングを実行します。

備考

ルーティングステージはデフォルトでは、実際の量子ビットを選択する レイアウト ステージと一体化していますが、このトピックでは簡略化のため別々のステージとして扱います。ルーティングとレイアウトの組み合わせは 量子ビットマッピング と呼ばれます。これらのステージの詳細については、トランスパイラーステージのトピックを参照してください。

coupling_map キーワード引数を渡して、トランスパイラーへの影響を確認します:

coupling_map = target.build_coupling_map()

pass_manager = generate_preset_pass_manager(
optimization_level=0, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv0 = pass_manager.run(qc)
qc_t_cm_lv0.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

上記に示すように、いくつかの SWAP ゲートが挿入されています(それぞれ 3 つの CX ゲートで構成されています)。これは現在のデバイスでは多くのエラーを引き起こします。実際の量子ビットトポロジー上でどの量子ビットが選択されているかを確認するには、Qiskit Visualizations の plot_circuit_layout を使用します:

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv0, backend, view="physical")

Output of the previous code cell

これにより、仮想量子ビット 0〜11 が物理量子ビット 0〜11 の直線上にそのままマッピングされたことがわかります。ルーティングが必要な場合に VF2Layout を使用するデフォルト(optimization_level=1)に戻りましょう。

pass_manager = generate_preset_pass_manager(
optimization_level=1, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv1 = pass_manager.run(qc)
qc_t_cm_lv1.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

SWAP ゲートが挿入されなくなり、選択された物理量子ビットは target クラスを使用した場合と同じになりました。

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv1, backend, view="physical")

Output of the previous code cell

レイアウトがリング状になりました。このレイアウトは回路の接続性を尊重しているため、SWAP ゲートが存在せず、実行に対してはるかに優れた回路が得られます。

サポートされている命令​

すべての量子コンピューターは限られた命令セットをサポートしています。回路内のすべてのゲートは、このセットの要素に変換する必要があります。このセットは、任意の量子演算をそれらのゲートに分解できることを意味する、ユニバーサル・ゲートセットを提供する単一量子ビットおよび2量子ビットのゲートで構成される必要があります。これはBasisTranslatorによって行われ、basis_gatesをトランスパイラーへのキーワード引数として指定することで、この情報を提供できます。

basis_gates = list(target.operation_names)
print(basis_gates)
['id', 'delay', 'reset', 'if_else', 'for_loop', 'x', 'rz', 'ecr', 'switch_case', 'measure', 'sx']

FakeSherbrookeのデフォルトの単一量子ビットゲートはrz、x、sxであり、デフォルトの2量子ビットゲートはecr(エコー付きクロス・レゾナンス)です。CXゲートはecrゲートから構成されるため、一部のQPUではecrが2量子ビットの基底ゲートとして指定される一方、他のQPUではcxがデフォルトになります。ecrゲートはcxゲートの_もつれ生成_部分です。制御ゲートに加えて、delayおよびmeasurement命令もあります。

備考

QPU にはデフォルトの基底ゲートがありますが、命令を提供するかパルスゲートを追加する限り(カスタムトランスパイラーパスの作成を参照)、任意のゲートを選択できます。デフォルトの基底ゲートは QPU でキャリブレーションが行われたゲートであるため、追加の命令/パルスゲートを提供する必要はありません。たとえば、一部の QPU では cx がデフォルトの 2 量子ビットゲートであり、他の QPU では ecr です。詳細については、ネイティブゲートと演算の一覧を参照してください。

pass_manager = generate_preset_pass_manager(
optimization_level=1,
coupling_map=coupling_map,
basis_gates=basis_gates,
seed_transpiler=12345,
)
qc_t_cm_bg = pass_manager.run(qc)
qc_t_cm_bg.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

CXGate オブジェクトが ecr ゲートと 1 量子ビット基底ゲートに分解されたことに注目してください。

デバイスエラーレート​

Target クラスには、デバイス上の演算のエラーレートに関する情報を含めることができます。 例えば、以下のコードは量子ビット 1 と 0 の間のエコーされたクロスレゾナンス(ECR)ゲートのプロパティを取得します(ECR ゲートは方向性があることに注意してください):

target["ecr"][(1, 0)]
InstructionProperties(duration=5.333333333333332e-07, error=0.007494257741828603)

出力にはゲートの持続時間(秒単位)とエラーレートが表示されます。エラー情報をトランスパイラーに渡すには、上記の basis_gates と coupling_map を使ってターゲットモデルを構築し、バックエンド FakeSherbrooke からのエラー値を設定します。

from qiskit.transpiler import Target
from qiskit.circuit.controlflow import IfElseOp, SwitchCaseOp, ForLoopOp

err_targ = Target.from_configuration(
basis_gates=basis_gates,
coupling_map=coupling_map,
num_qubits=target.num_qubits,
custom_name_mapping={
"if_else": IfElseOp,
"switch_case": SwitchCaseOp,
"for_loop": ForLoopOp,
},
)

for i, (op, qargs) in enumerate(target.instructions):
if op.name in basis_gates:
err_targ[op.name][qargs] = target.instruction_properties(i)

新しいターゲット err_targ をターゲットとしてトランスパイルします:

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=err_targ, seed_transpiler=12345
)
qc_t_cm_bg_et = pass_manager.run(qc)
qc_t_cm_bg_et.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

ターゲットにエラー情報が含まれているため、VF2PostLayout パスが使用する最適な量子ビットを見つけようとし、結果として同じ物理量子ビットを使用した元々見つかったものと同じ回路が得られます。

次のステップ​