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

動的回路の実行

パッケージ・バージョン

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

qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1

動的回路は、量子回路の実行中に Qubit を中間測定し、その測定結果に基づいて回路内で古典的な論理演算を実行できる強力なツールです。このプロセスは 古典フィードフォワード とも呼ばれます。動的回路を最大限に活用する方法の理解はまだ初期段階ですが、量子研究コミュニティはすでに以下のような多くのユースケースを特定しています。

ただし、動的回路によるこれらの改善はトレードオフを伴います。中間回路測定と古典演算は通常 2-Qubit ゲートよりも長い実行時間を必要とし、この時間の増加が回路深度の削減による利点を相殺する可能性があります。そのため、IBM Quantum® が動的回路の新バージョンをリリースするにあたり、中間回路測定の長さの削減が改善の焦点となっています。動的回路を使用する際のその他の制限については、Estimator または Sampler の機能互換性テーブルを参照してください。

OpenQASM 3 仕様ではいくつかの制御フロー構造が定義されていますが、Qiskit Runtime は現在、条件付き if 文のみをサポートしています。Qiskit SDK では、これは QuantumCircuitif_test メソッドに対応しています。このメソッドはコンテキスト・マネージャーを返し、通常は with 文で使用されます。このガイドでは、この条件文の使用方法を説明します。

備考

このガイドのコード例では、中間回路測定に標準の measure 命令を使用しています。しかし、バックエンドがサポートしている場合は、代わりに MidCircuitMeasure 命令を使用することをお勧めします。詳細については、中間回路測定セクションを参照してください。

動的回路をサポートするバックエンドの検索

アカウントがアクセスでき、動的回路をサポートするすべてのバックエンドを見つけるには、以下のようなコードを実行してください。この例では、ログイン認証情報を保存済みであることを前提としています。または、Qiskit Runtime サービス・アカウントを初期化する際に明示的に認証情報を指定することもできます。これにより、特定のインスタンスやプラン・タイプで利用可能なバックエンドを表示できます。

注意
  • アカウントで利用可能なバックエンドは、認証情報で指定されたインスタンスによって異なります。
  • 動的回路の新バージョンは現在、すべてのバックエンドのすべてのユーザーに利用可能です。詳細については、アナウンスを参照してください。
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# This cell is hidden from users. It hides all those "...instance was not set..." warnings.
import warnings

warnings.filterwarnings("ignore", message=".*Instance was not set*")
from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
dc_backends = service.backends(dynamic_circuits=True)
print(dc_backends)
[<IBMBackend('ibm_pittsburgh')>, <IBMBackend('ibm_kingston')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_boston')>]

中間回路測定

qiskit-ibm-runtime v0.43.0 より前は、measure が Qiskit における唯一の測定命令でした。しかし、中間回路測定は 最終 測定(回路の終わりで行われる測定)とは異なるチューニング要件を持っています。例えば、中間回路測定をチューニングする際には命令の継続時間を考慮する必要があります。継続時間が長いほど回路のノイズが増加するからです。最終測定の後には命令がないため、最終測定では命令の継続時間を考慮する必要はありません。

備考

MidCircuitMeasure 命令は、バックエンドの supported_instructions で報告される measure_2 命令にマッピングされます。ただし、measure_2 はすべてのバックエンドでサポートされているわけではありません。service.backends(filters=lambda b: "measure_2" in b.supported_instructions) を使用して、サポートするバックエンドを見つけてください。将来、新しい測定が追加される可能性がありますが、これは保証されていません。

MidCircuitMeasure メソッド

qiskit-ibm-runtime v0.43.0 では、MidCircuitMeasure 命令が導入されました。名前が示すように、これは IBM® QPU 上の中間回路測定に最適化された新しい測定命令です。中間回路測定に QuantumCircuit.measure を使用することもできますが、その設計上、MidCircuitMeasure は通常より良い選択です。例えば、QuantumCircuit.measure を使用する場合よりも回路へのオーバーヘッドが少なくなります。

from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime.circuit import MidCircuitMeasure

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)

circ = QuantumCircuit(2, 2)
circ.x(0)
circ.append(MidCircuitMeasure(), [0], [0])
# circ.measure([0], [0])
# circ.measure_all()
print(circ.draw(cregbundle=False))
┌───┐┌────────────┐
q_0: ┤ X ├┤0 ├
└───┘│ │
q_1: ─────┤ Measure_2 ├
│ │
c_0: ═════╡0 ╞
└────────────┘
c_1: ═══════════════════
重要な注意事項
  • 測定を使用するには、少なくとも 1 つの古典レジスターが必要です。
  • Sampler プリミティブは回路の測定を必要とします。Estimator プリミティブでは回路の測定を追加できますが、それらは無視されます。

Store

qiskit-ibm-runtime バージョン 0.47.0 以降では、store 命令を使用して、繰り返し使用される古典式の結果を保存できます。演算は自動的に並列化されるため、実行時のコード効率が大幅に向上します。

詳細については、古典フィードフォワードと制御フローガイドを参照してください。

備考

実際のバックエンドで store を使用して値を古典レジスターに保存する場合、その値は実行中にメモリ内にのみ保存され、ジョブの結果にはコピーまたは返されません。

例えば、以下のコードでは、実行中に tempcreg と同じ値を持ち、if_test は期待どおりに機能します。しかし、ジョブが終了した後、ジョブの結果に返される temp BitArray には creg の値が 含まれません。つまり、job.result()[0].data.temp0 になります。

creg = ClassicalRegister(3, "c")
temp = ClassicalRegister(3, "temp")
...
qc.store(temp, creg)
with circuit.if_test((temp, 0b001)):
...

完全な例

以下のコードは IBM® ハードウェア上で動的回路を作成して実行します。

from qiskit_ibm_runtime import SamplerV2, QiskitRuntimeService
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.transpiler import generate_preset_pass_manager

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)

# Create a dynamic circuit

qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
qc = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits

qc.h(q0)
qc.measure(q0, c0)
with qc.if_test((c0, 1)):
qc.x(q0)
qc.measure(q0, c0)

# Convert to an ISA circuit for the given backend

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)

# Generate samplers for backend targets
sampler = SamplerV2(backend)

# Submit jobs
sampler_job = sampler.run([isa_circuit])
result = sampler_job.result()

print(
f">>> {' Job ID:':<10} {sampler_job.job_id()} ({sampler_job.status()})"
)
>>> Job ID: d88cakp789is7391vq0g (DONE)

Qiskit Runtime の制限

Qiskit Runtime で動的回路を実行する際は、以下の制約に注意してください。

  • 制御エレクトロニクスの物理メモリが限られているため、if 文の数とそのオペランドのサイズにも制限があります。この制限は、ジョブ(回路ではなく)内のブロードキャスト数とブロードキャストされたビット数の関数です。

    if 条件を処理するとき、その評価を行うために測定データを制御ロジックに転送する必要があります。ブロードキャストとは一意の古典データの転送であり、ブロードキャストされたビットとは転送される古典ビットの数です。以下を考えてみてください。

    c0 = ClassicalRegister(3)
    c1 = ClassicalRegister(5)
    ...
    with circuit.if_test((c0, 1)) ...
    with circuit.if_test((c0, 3)) ...
    with circuit.if_test((c1[2], 1)) ...

    前のコード例では、c0 に対する最初の 2 つの if_test オブジェクトは、c0 の内容が変化していないため、再ブロードキャストする必要がなく、1 つのブロードキャストと見なされます。c1 に対する if_test は 2 番目のブロードキャストです。最初のブロードキャストは c0 の 3 ビットすべてをブロードキャストし、2 番目は 1 ビットのみをブロードキャストするため、合計で 4 つのブロードキャストされたビットになります。

    現在、毎回 60 ビットをブロードキャストする場合、ジョブには約 300 のブロードキャストが含まれます。しかし、毎回 1 ビットのみをブロードキャストする場合、ジョブには 2400 のブロードキャストが含まれます。

  • if_test 文で使用されるオペランドは 32 ビット以下でなければなりません。したがって、ClassicalRegister 全体と比較している場合、その ClassicalRegister のサイズは 32 ビット以下でなければなりません。ただし、ClassicalRegister の単一ビットのみと比較している場合、その ClassicalRegister は任意のサイズにすることができます(オペランドが 1 ビットのみであるため)。

    例えば、cr が 32 ビットを超えているため、「Not valid」コード・ブロックは機能しません。しかし、「Valid」コード・ブロックに示されているように、1 ビットのみをテストする場合は 32 ビットより広い古典レジスターを使用できます。

    cr = ClassicalRegister(50)
    qr = QuantumRegister(50)
    circuit = QuantumCircuit(qr, cr)
    ...
    circ.measure(qr, cr)
    with circ.if_test((cr, 15)):
    ...
  • ネストされた条件文は許可されていません。例えば、次のコード・ブロックは if_test の中に別の if_test があるため機能しません。

    c1 = ClassicalRegister(1, "c1")
    c2 = ClassicalRegister(2, "c2")
    ...
    with circ.if_test((c1, 1)):
    with circ.if_test(c2, 1)):
    ...
  • 条件文内の reset または測定はサポートされていません。

  • 算術演算はサポートされていません。

  • Qiskit と Qiskit Runtime でサポートされている OpenQASM 3 機能を確認するには、OpenQASM 3 機能テーブルを参照してください。

  • OpenQASM 3(QuantumCircuit の代わり)が Qiskit Runtime プリミティブに回路を渡すための入力形式として使用される場合、Qiskit にロードできる命令のみがサポートされます。古典演算は、例えば Qiskit にロードできないためサポートされていません。詳細については、OpenQASM 3 プログラムを Qiskit にインポートするを参照してください。

  • forwhile、および switch 命令はサポートされていません。

Estimator での動的回路の使用

Estimator は動的回路をサポートしていないため、Sampler を使用して独自の測定回路を構築できます。

Estimator の動作を再現するには、以下のプロセスに従ってください。

  1. すべてのオブザーバブルの項をパーティションにグループ化します。これは例えば PauliList API を使用して行うことができます。
    備考

    BitArray プリミティブ属性を使用して、提供されたオブザーバブルの期待値を計算できます。

  2. パーティションごとに 1 つの基底変換回路を実行します(各パーティションに対して行う必要のある基底変換)。詳細については、Measurement bases アドオン・ユーティリティの measurement_bases モジュールを参照してください。Qiskit addon utilities パッケージのドキュメントもご覧ください。
  3. 各パーティションの結果を合計して戻します。

制限

動的回路を使用する際の制限を理解するには、機能互換性テーブルを確認してください。機能の互換性はプリミティブに依存しないことに注意してください。

次のステップ

おすすめ