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

プリミティブの概要

パッケージバージョン

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

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
新しい実行モデル(現在ベータリリース)

新しい実行モデルのベータリリースが利用可能になりました。指向型実行モデルは、エラー緩和ワークフローをカスタマイズする際の柔軟性を高めます。詳細については、指向型実行モデルガイドを参照してください。

Qiskitがプリミティブを導入した理由

古典コンピューターの黎明期、開発者がCPUレジスタを直接操作しなければならなかったように、QPUへの初期インターフェースは制御エレクトロニクスからの生データをそのまま返すだけのものでした。 QPUが研究室にあり、研究者だけが直接アクセスできた頃は、これは大きな問題ではありませんでした。 しかし、多くの開発者がそのような生データを0と1に変換する方法を知っているべきではないと認識し、Qiskitはクラウド上のQPUにアクセスするための最初の抽象化としてbackend.runを導入しました。これにより、開発者は使い慣れたデータ形式で操作し、より大きな目標に集中できるようになりました。

QPUへのアクセスがより広まり、より多くの量子アルゴリズムが開発されるにつれて、 より高レベルな抽象化の必要性が再び生じました。これに応えるため、Qiskitは プリミティブインターフェースを導入しました。これは量子アルゴリズム開発における2つのコアタスクに最適化されています: 期待値推定(Estimator)と回路サンプリング(Sampler)です。目標は、 開発者がデータ変換よりもイノベーションに集中できるようにすることです。プリミティブインターフェースはbackend.runインターフェースに取って代わります。Samplerbackend.runで提供されていたのと同じ直接的なハードウェアアクセスを提供するためです。

プリミティブとは何か?

コンピューティングシステムは複数の抽象化レイヤーの上に構築されています。抽象化により、手元のタスクに関連する特定の詳細レベルに集中できます。ハードウェアに近づくほど、必要な抽象化のレベルは低くなります(例えば、CPUの命令レベルでデータを移動または操作する必要があるかもしれません)。実行したいタスクが複雑になるほど、抽象化のレベルは高くなります(例えば、代数計算を実行するためにプログラミングライブラリを使用するかもしれません)。

この文脈において、プリミティブとは最小の処理命令であり、与えられた抽象化レベルで有用なものを作成できる最も単純な構成要素です。

量子コンピューティングの最近の進歩により、より高い抽象化レベルで作業する必要性が高まっています。 この分野が大規模な量子処理ユニット(QPU)やより複雑なワークフローに向かうにつれて、焦点は個々の量子ビット信号との対話から、必要なタスクを実行するシステムとして量子デバイスを見ることへとシフトします。

量子コンピューターの最も一般的な2つのタスクは、量子状態のサンプリングと期待値の計算です。 これらのタスクがQiskitプリミティブ、EstimatorSamplerの設計を動機づけました。

  • Estimatorは量子回路によって準備された状態に関するオブザーバブルの期待値を計算します。
  • Samplerは量子回路の実行から出力レジスタをサンプリングします。

端的に言えば、Qiskitプリミティブが導入した計算モデルは、量子プログラミングを今日の古典プログラミングに一歩近づけるものです。ハードウェアの詳細よりも、達成しようとしている結果に焦点を当てることができます。

プリミティブの定義と実装

Qiskitプリミティブには2種類あります:基底クラスとその実装です。Qiskitプリミティブは、Qiskit SDK(qiskit.primitivesモジュール内)に含まれるオープンソースのプリミティブ基底クラスによって定義されています。プロバイダー(Qiskit Runtimeなど)はこれらの基底クラスを使用して、独自のSamplerおよびEstimatorの実装を派生させることができます。ほとんどのユーザーは基底プリミティブではなく、プロバイダーの実装を使用します。

基底クラス

BaseEstimatorV2およびBaseSamplerV2 — プリミティブを実装するための共通インターフェースを定義する抽象基底クラスです。qiskit.primitivesモジュール内の他のすべてのクラスはこれらの基底クラスを継承します。特定のプロバイダー向けに独自のプリミティブベースの実行モデルを作成することに興味がある開発者はこれらを使用してください。これらのクラスは、高度にカスタマイズされた処理を行いたいが、既存のプリミティブ実装が自分のニーズに対して単純すぎると感じる方にも役立つかもしれません。一般ユーザーは基底クラスを直接使用しません。

実装

以下はプリミティブ基底クラスの実装です:

  • Qiskit Runtimeプリミティブ(EstimatorV2およびSamplerV2)は、クラウドベースのサービスとして、より高度な実装(例えばエラー緩和を含む)を提供します。この基底プリミティブの実装は、IBM Quantum®ハードウェアへのアクセスに使用されます。IBM Qiskit Runtimeを通じてアクセスします。

  • StatevectorEstimatorおよびStatevectorSampler — Qiskitに組み込まれたシミュレーターを使用するプリミティブのリファレンス実装です。Qiskitのquantum_infoモジュールで構築されており、理想的な状態ベクトルシミュレーションに基づく結果を生成します。Qiskitを通じてアクセスします。

  • BackendEstimatorV2およびBackendSamplerV2 — これらのクラスを使用して、任意の量子コンピューティングリソースをプリミティブに「ラップ」できます。これにより、まだプリミティブベースのインターフェースを持っていないプロバイダーに対してプリミティブスタイルのコードを記述できます。これらのクラスは通常のSamplerやEstimatorと同様に使用できますが、実行する量子コンピューターを選択するための追加のbackend引数で初期化する必要があります。Qiskitを使用してアクセスします。

Qiskitプリミティブの利点

プリミティブを使用することで、Qiskitユーザーはすべての詳細を明示的に管理することなく、特定のQPU向けに量子コードを記述できます。また、追加の抽象化レイヤーにより、特定のプロバイダーの高度なハードウェア機能にアクセスしやすくなる場合があります。例えば、Qiskit Runtimeプリミティブを使用すると、エラー緩和や抑制の最新の進歩を、プリミティブのresilience_levelなどのオプションを切り替えるだけで活用できます。これらのテクニックを独自に実装する必要はありません。

ハードウェアプロバイダーにとって、プリミティブをネイティブに実装することは、高度なポストプロセッシングテクニックなどのハードウェア機能に「すぐに使える」形でアクセスできる方法をユーザーに提供できることを意味します。これにより、ユーザーがハードウェアの最高の機能から恩恵を受けやすくなります。

プリミティブの詳細

前述のとおり、すべてのプリミティブは基底クラスから作成されます。したがって、同じ一般的な構造と使用方法を持ちます。例えば、すべてのEstimatorプリミティブへの入力フォーマットは同じです。ただし、それぞれを独自にする実装の違いがあります。

備考

ほとんどのユーザーはQiskit Runtimeプリミティブを使用するため、このセクションの残りの例はQiskit Runtimeプリミティブに基づいています。

Estimator

Estimatorプリミティブは、量子回路によって準備された状態に関して、1つまたは複数のオブザーバブルの期待値を計算します。回路はパラメーター化できますが、その場合はパラメーター値もプリミティブへの入力として提供する必要があります。

入力はPUBの配列です。各PUBのフォーマットは次のとおりです:

(<単一回路>, <1つまたは複数のオブザーバブル>, <省略可能な1つまたは複数のパラメーター値>, <省略可能な精度>),

ここで省略可能なパラメーター値はリストまたは単一のパラメーターにできます。異なるEstimatorの実装はさまざまな設定オプションをサポートします。入力に測定が含まれている場合、それらは無視されます。

出力はPubResultで、ペアごとに計算された期待値とその標準誤差がPubResult形式で含まれます。各PubResultにはデータとメタデータの両方が含まれます。

EstimatorはNumPyのブロードキャストルールに従って、プリミティブの入出力トピックで説明されているようにオブザーバブルとパラメーター値の要素を組み合わせます。

例:

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
# This cell is hidden from users, it creates the circuits and observables to run

from qiskit_ibm_runtime import EstimatorV2, SamplerV2, QiskitRuntimeService
from qiskit.circuit.random import random_circuit
from qiskit.circuit import Parameter
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
import numpy as np

service = QiskitRuntimeService()
backend = service.least_busy()
phi = Parameter("phi")

circuit1 = random_circuit(10, 5, seed=12345)
circuit1.rzz(phi, 1, 2)
observable1 = SparsePauliOp.from_sparse_list(
[("ZXYZ", [1, 2, 3, 4], 1)], num_qubits=10
)
param_values1 = np.random.uniform(size=5).T

circuit2 = random_circuit(10, 5, seed=12345)
circuit2.rzz(phi, 1, 2)
observable2 = SparsePauliOp.from_sparse_list(
[("XZYX", [1, 2, 3, 4], 1)], num_qubits=10
)
param_values2 = np.random.uniform(size=5).T

shots1 = 164
shots2 = 1024

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
circuit1 = pm.run(circuit1)
circuit2 = pm.run(circuit2)
observable1 = observable1.apply_layout(circuit1.layout)
observable2 = observable2.apply_layout(circuit2.layout)
estimator = EstimatorV2(mode=backend)
estimator_job = estimator.run(
[
(circuit1, observable1, param_values1),
(circuit2, observable2, param_values2),
]
)

Sampler

Samplerのコアタスクは、1つまたは複数の量子回路の実行から出力レジスタをサンプリングすることです。入力回路はパラメーター化できますが、その場合はパラメーター値もプリミティブへの入力として提供する必要があります。

入力は1つまたは複数のPUBで、フォーマットは次のとおりです:

(<単一回路>, <省略可能な1つまたは複数のパラメーター値>, <省略可能なショット数>),

ここで複数のパラメーター値アイテムを指定でき、各アイテムは選択した回路に応じて配列または単一のパラメーターにできます。また、入力には測定が含まれている必要があります。

出力はカウントまたはショットごとの測定値で、重みなしのPubResultオブジェクトとして返されます。ただし結果クラスには、カウントなどの重み付きサンプルを返すメソッドがあります。詳細はプリミティブの入出力を参照してください。

例:

# This cell is hidden from users, add measurement instructions to circuits
circuit1.measure_active()
circuit2.measure_active()
sampler = SamplerV2(mode=backend)
sampler_job = sampler.run(
[
(circuit1, param_values1, shots1),
(circuit2, param_values2, shots2),
]
)

次のステップ

おすすめ