動的回路を実行する
動的回路は、量子回路の実行途中で量子ビットを測定し、その測定結果に基づいて回路内で古典的な論理演算を実行できる強力なツールです。 このプロセスは、 古典的フィードフォワードとも呼ばれる。 ダイナミック回路を最大限に活用する方法についてはまだ研究の初期段階にあるものの、量子研究コミュニティではすでに、以下のような数多くの活用事例が特定されています:
- GHZ状態やW状態 (W状態の詳細については、 「フィードフォワードを用いた浅い回路による状態準備」 も参照)、および広範な行列積状態など、効率的な量子状態の準備
- 浅い回路を用いた、同一チップ上の量子ビット間における効率的な長距離エンタングルメント
- IQP型回路の効率的なサンプリング
しかし、ダイナミック回路によってもたらされるこうした改善には、トレードオフが伴います。 回路途中での測定や古典的な演算は、通常、2量子ビットゲートよりも実行時間が長くなる傾向があり、この時間の増加によって、回路の深さを減らすことによるメリットが相殺されてしまう可能性がある。 したがって、 IBM Quantum® 新しいバージョンの動的回路をリリースするにあたり、回路中間測定の長さを短縮することは、改善の重点分野となる。 動的回路を使用する際のその他の制限事項については、「 Estimator」 または「 Sampler」 機能の互換性表を参照してください。
OpenQASM 3の仕様では、いくつかの制御フロー構造が定義されていますが、 IBM Quantum Compute Serviceでは現在、条件分岐 if 文のみがサポートされています。 Qiskit SDK では、これは QuantumCircuit の if_test メソッドに相当します。 このメソッドはコンテキストマネージャー を返し、通常は ステートメント with 内で使用されます。 このガイドでは、この条件文の使用方法について説明します。
このガイドのコード例では、回路の途中での測定に標準的な測定命令を使用しています。 ただし、バックエンドが対応している場合は、代わりに の MidCircuitMeasure 指示を使用することをお勧めします。 詳細については、「回路中間測定」のセクションを参照してください。
このページのコードは、以下の要件に基づいて開発されました。 これらのバージョン以降のご利用をお勧めします。
qiskit[all]~=2.5.1 qiskit-ibm-runtime~=0.47.0
動的回路をサポートするバックエンドを検索する
自分のアカウントからアクセス可能で、動的サーキットをサポートしているすべてのバックエンドを確認するには、次のようなコードを実行してください。 この例では、 ログイン情報が保存されていることを前提としています。 また、 IBM Quantum Compute Service アカウントを初期化する際に、 認証情報を明示的に指定することも可能です。 これにより、例えば、特定のインスタンスやプランタイプで利用可能なバックエンドを確認できるようになります。
- そのアカウントで利用可能なバックエンドは、認証情報で指定されたインスタンスによって異なります。
- ダイナミック回路の新バージョンが、すべてのバックエンドにおいて全ユーザー向けに利用可能になりました。 詳細については、 お知らせをご覧ください。
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
dc_backends = service.backends(dynamic_circuits=True)
print(dc_backends)Output:
[<IBMBackend('ibm_pittsburgh')>, <IBMBackend('ibm_boston')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_kingston')>]
回路の途中での測定
v0.43.0 qiskit-ibm-runtime が登場する前は、 measure これが Qiskit における唯一の測定命令でした。 しかし、回路中間での測定は、 端子測定(回路の末端で行われる測定)とは異なる調整要件があります。 例えば、回路の測定を調整する際には、命令の実行時間を考慮する必要があります。なぜなら、命令が長くなると回路のノイズが増加するからです。 末端測定の後は命令がないため、末端測定における命令の実行時間は考慮する必要はありません。
この MidCircuitMeasure 命令は、バックエンドの supported_instructions. に報告された命令 measure_2 に対応します。 ただし、すべてのバックエンド measure_2 でサポートされているわけではありません。 を使用して service.backends(filters=lambda b: "measure_2" in b.supported_instructions) 、それをサポートしているバックエンドを検索してください。 今後、新たな測定項目が追加される可能性がありますが、その保証はありません。
MidCircuitMeasureメソッド
v0.43.0 qiskit-ibm-runtime において、この 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))Output:
┌───┐┌────────────┐
q_0: ┤ X ├┤0 ├
└───┘│ │
q_1: ─────┤ Measure_2 ├
│ │
c_0: ═════╡0 ╞
└────────────┘
c_1: ═══════════════════
- 測定機能を使用するには、少なくとも1つのクラシック・レジスタが必要です。
- 「Sampler」プリミティブでは、回路の測定が必要です。 「Estimator」プリミティブを使用して回路の測定値を追加することはできますが、それらは無視されます。
Store
0.47.0 以降のバージョンでは qiskit-ibm-runtime 、ある式を繰り返し使用する場合は、`` store 命令を使用してその式の計算結果を保存することができます。 処理は自動的に並列化されるため、実行時のコードの効率が大幅に向上します。
詳細については、「 古典的なフィードフォワードおよび制御フロー ガイド」を参照してください。
実バックエンド上で を使用して store 古典的なレジスタに値を保存する場合、その値は実行中にメモリに保存されるだけであり、ジョブ結果にはコピーされたり返されたりすることはありません。
たとえば、次のコードでは、 temp 実行時に と creg の値は同じになり、 は if_test 期待どおりに動作します。 cregしかし、ジョブが終了した後、ジョブ結果として返される BitArray には temp 、の値が含まれていません。 0つまり、 は job.result()[0].data.temp である。
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()})"
)Output:
>>> Job ID: d9mq9qnurbec73e67acg (DONE)
量子コンピューティングの限界
Quantum Compute で動的回路を実行する際は、以下の制約事項に注意してください。
-
制御電子機器の物理メモリ容量には限りがあるため、命令
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)) ...前のコード例では、の
if_test最初の2つのc0オブジェクトは1つのブロードキャストと見なされます。これは、の内容がc0変更されていないため、再ブロードキャストする必要がないからです。 このif_test放送c1は再放送です。 1つ目は3ビットすべてをブロードキャストしc0、2つ目は1ビットのみをブロードキャストするため、合計で4ビットがブロードキャストされることになる。現在、1回につき60ビットをブロードキャストする場合、このジョブでは約300回のブロードキャストが可能となります。 しかし、毎回1ビットずつ送信する場合、そのジョブでは2400回の送信が必要になります。
-
if_teststatementで使用されるオペランドは、32ビット以下でなければなりません。 したがって、全体を比較する場合、そのサイズは32ClassicalRegister``ClassicalRegisterビット以下でなければなりません。 ただし、1つのビットだけを比較する場合、ClassicalRegisterそのビットはどのようなClassicalRegister長さでも構いません(オペランドが1ビットのみであるため)。たとえば、「Not valid」というコードブロックは、が32ビットを超
crえているため動作しません。 ただし、「Valid」のコードブロックに示されているように、1ビットのみをテストする場合は、32ビットより広い古典的なレジスタを使用することも可能です。cr = ClassicalRegister(50) qr = QuantumRegister(50) circuit = QuantumCircuit(qr, cr) ... circ.measure(qr, cr) with circ.if_test((cr, 15)): ...cr = ClassicalRegister(50) qr = QuantumRegister(50) circuit = QuantumCircuit(qr, cr) ... circ.measure(qr, cr) with circ.if_test((cr[5], 1)): ... -
入れ子になった条件文は使用できません。 たとえば、次のコードブロックは、
が別のif_testの中に含まif_testれているため、動作しません:c1 = ClassicalRegister(1, "c1") c2 = ClassicalRegister(2, "c2") ... with circ.if_test((c1, 1)): with circ.if_test(c2, 1)): ...cr = ClassicalRegister(2) ... with circuit.if_test((cr, 0b11)): ... -
条件文内に
orやmeasurementsresetを含めることはサポートされていません。 -
算術演算はサポートされていません。
-
「 OpenQASM 3」の機能一覧表を参照し、QiskitおよびQuantum Computeでどの OpenQASM 3機能がサポートされているかを確認してください。
-
IBM Quantum プリミティブに回路を渡す際の入力形式として OpenQASM 3(他の形式ではなく
QuantumCircuit)を使用する場合、Qiskitに読み込める命令のみがサポートされます。 たとえば、従来の演算は、Qiskit に読み込むことができないため、サポートされていません。 詳細については、「 OpenQASM 3のプログラムをQiskitにインポートする」 を参照してください。 -
,
while, およびswitchforコマンドはサポートされていません。
Estimator で動的回路を使用する
Estimatorは動的回路に対応していないため、代わりに Sampler を使用して、独自の測定回路を構築することができます。
Estimatorの動作を再現するには、以下の手順に従ってください:
- すべての観測可能変数の項を1つのパーティションにまとめる。 例えば、 API
PauliListを使用することで実現できます。NoteBitArrayprimitive 属性を使用すると、指定された観測量の期待値を計算できます。 - パーティションごとに1つの基底変換回路を実行する(各パーティションに対して必要な基底変換を行う)。 詳細については、「Measurement bases
measurement_basesモジュール 」アドオンユーティリティを参照してください。 詳細については、Qiskit addon utilities パッケージのドキュメントを参照してください。 - 各パーティションの結果を足し合わせます。
制約事項
動的回路を使用する際の制限事項を確認するには、機能互換性表を参照してください。 なお、機能の互換性はプリミティブに依存しないことに注意してください。
次のステップ
- stretch を使用して、正確な動的デカップリングを実装する方法について学びましょう。
- 従来のフィードフォワードおよび制御フロー のガイドを確認してください。
- 回路スケジュールの可視化機能を活用して、動的回路のデバッグと最適化を行ってください。
- すべての関数が動的回路と互換性があるわけではありません。 詳細については、「 Sampler」 の機能互換性に関するセクションをご確認ください。