プリミティブ
qiskit.primitives
プリミティブは、プリミティブ・ユニファイド・ブロック(PUB)と呼ばれる入力ユニットが、効率的に出力を生成するために量子リソースを必要とする、より大規模なアプリケーションで使用される計算ビルディングブロックである。
現在、プリミティブには2つのタイプがあり、その抽象化された最新のバージョンは次のように定義されている。 BaseSamplerV2 と BaseEstimatorV2. サンプラーは、量子回路(またはパラメータ化された回路上の値のスイープ)を受け入れ、その古典的な出力レジスタからサンプリングする役割を担っている。 推定器は、回路と観測値(またはその掃引)の組み合わせを受け入れ、観測値の期待値を推定する。
Qiskitは、これらの抽象化された各機能のリファレンス実装を StatevectorSampler および StatevectorEstimator クラスで参照実装を提供しています。
サンプラーと推定量の抽象化の初期バージョンは次のように定義される BaseSamplerV1 と BaseEstimatorV1. これらのインターフェイスは、 run メソッドとは異なる、柔軟性に欠ける入出力フォーマットに従っており、実際のところ、その大部分は以下に置き換えられている。 BaseSamplerV2 そして BaseEstimatorV2. しかし、後方互換性のために、元の抽象的なインターフェイス定義は保持されている。 V1 と V2 の違いについての詳細は、このページの移行セクションをご覧ください。
EstimatorV2 の概要
BaseEstimatorV2 は、与えられた量子回路と観測値の組み合わせの期待値を推定するプリミティブである。
構築後、推定器はパブ(Primitive Unified Bloc)のリストで run() メソッドを呼び出すことで使用される。 各パブには3つの値が含まれており、これらの値を合計することで、エスティメータが完了する計算単位が定義される:
- 単一の
QuantumCircuit(パラメータ化される可能性のある)関数であり、その最終状態を と定義する - つ以上の観測値(
ObservablesArrayLikeを含む。Pauli,SparsePauliOpstr)があり、どの期待値を推定するかを指定する - 回路をバインドするためのパラメータ値セットのコレクション、 。
を返します。 BasePrimitiveJob オブジェクトを返します。 result() メソッドを呼び出すと、各パブの期待値推定値とメタデータが返されます:
パブの観測値とパラメータ値の部分は、標準的なブロードキャストルールが適用される任意の次元の配列値であることができ、その結果、各パブの推定結果も一般的に配列値である。 詳しくはこちらをご覧ください。
以下は推定値の使用例である。
from qiskit.primitives import StatevectorEstimator as Estimator
from qiskit.circuit.library import RealAmplitudes
from qiskit.quantum_info import SparsePauliOp
psi1 = RealAmplitudes(num_qubits=2, reps=2)
psi2 = RealAmplitudes(num_qubits=2, reps=3)
H1 = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)])
H2 = SparsePauliOp.from_list([("IZ", 1)])
H3 = SparsePauliOp.from_list([("ZI", 1), ("ZZ", 1)])
theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 1, 2, 3, 5, 8, 13]
theta3 = [1, 2, 3, 4, 5, 6]
estimator = Estimator()
# calculate [ <psi1(theta1)|H1|psi1(theta1)> ]
job = estimator.run([(psi1, H1, [theta1])])
job_result = job.result() # It will block until the job finishes.
print(f"The primitive-job finished with result {job_result}")
# calculate [ [<psi1(theta1)|H1|psi1(theta1)>,
# <psi1(theta3)|H3|psi1(theta3)>],
# [<psi2(theta2)|H2|psi2(theta2)>] ]
job2 = estimator.run(
[
(psi1, [H1, H3], [theta1, theta3]),
(psi2, H2, theta2)
],
precision=0.01
)
job_result = job2.result()
print(f"The primitive-job finished with result {job_result}")SamplerV2 の概要
BaseSamplerV2 は量子回路の出力をサンプリングするプリミティブである。
構築後、サンプラーはその run() メソッドを呼び出すことで使用される。 各パブには、サンプラーが完了する計算単位を定義する値が含まれている:
- 単一の
QuantumCircuitパラメータ化されていることもある。 - 回路がパラメトリックである場合にバインドするコレクション・パラメータ値セット。
- オプションとして、サンプリングするショット数(設定されていない場合は、ランメソッドで決定される)。
sampler を実行すると オブジェクト BasePrimitiveJob が返され、そのメソッド を呼び出すと、各 pub に対する result() 出力サンプルとメタデータが得られます。
サンプラーの使用例を紹介しよう。
from qiskit.primitives import StatevectorSampler as Sampler
from qiskit import QuantumCircuit
from qiskit.circuit.library import RealAmplitudes
# create a Bell circuit
bell = QuantumCircuit(2)
bell.h(0)
bell.cx(0, 1)
bell.measure_all()
# create two parameterized circuits
pqc = RealAmplitudes(num_qubits=2, reps=2)
pqc.measure_all()
pqc2 = RealAmplitudes(num_qubits=2, reps=3)
pqc2.measure_all()
theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 2, 3, 4, 5, 6, 7]
# initialization of the sampler
sampler = Sampler()
# collect 128 shots from the Bell circuit
job = sampler.run([bell], shots=128)
job_result = job.result()
print(f"The primitive-job finished with result {job_result}")
# run a sampler job on the parameterized circuits
job2 = sampler.run([(pqc, theta1), (pqc2, theta2)])
job_result = job2.result()
print(f"The primitive-job finished with result {job_result}")EstimatorV1 の概要
Qiskitには現在、レガシーな EstimatorV1 インターフェイスの実装はありません。 しかし BaseEstimatorV1 からの抽象インターフェース定義は、外部実装との後方互換性を提供するために、まだパッケージの一部である。
EstimatorV1 の実装は、空のパラメータセットで初期化される。 BaseEstimatorV1 は、 .run() メソッドで以下のパラメータを指定して呼び出すことができる:
- 量子回路 ( ): (パラメータ化された)量子回路のリスト(オブジェクトのリスト)。
QuantumCircuitオブジェクトのリスト)。 - observables ( ): オブジェクトのリスト。
SparsePauliOpオブジェクトのリストです。 - パラメータ値 ( ): 量子回路のパラメータに束縛される値の集合のリスト(浮動小数点数のリスト)。
このメソッドは オブジェクト JobV1 を返す必要があります。 この関数を呼び出すと、期待値のリストに加え、推定値の信頼区間 qiskit.providers.JobV1.result() などのオプションのメタデータが返されます。
以下は、 EstimatorV1 の実装例である。 Qiskitには現在、レガシーな EstimatorV1 インターフェイスの実装がないことに注意してください。
# This is a fictional import path.
# There are currently no EstimatorV1 implementations in Qiskit.
from estimator_v1_location import EstimatorV1
from qiskit.circuit.library import RealAmplitudes
from qiskit.quantum_info import SparsePauliOp
psi1 = RealAmplitudes(num_qubits=2, reps=2)
psi2 = RealAmplitudes(num_qubits=2, reps=3)
H1 = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)])
H2 = SparsePauliOp.from_list([("IZ", 1)])
H3 = SparsePauliOp.from_list([("ZI", 1), ("ZZ", 1)])
theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 1, 2, 3, 5, 8, 13]
theta3 = [1, 2, 3, 4, 5, 6]
estimator = EstimatorV1()
# calculate [ <psi1(theta1)|H1|psi1(theta1)> ]
job = estimator.run([psi1], [H1], [theta1])
job_result = job.result() # It will block until the job finishes.
print(f"The primitive-job finished with result {job_result}")
# calculate [ <psi1(theta1)|H1|psi1(theta1)>,
# <psi2(theta2)|H2|psi2(theta2)>,
# <psi1(theta3)|H3|psi1(theta3)> ]
job2 = estimator.run(
[psi1, psi2, psi1],
[H1, H2, H3],
[theta1, theta2, theta3]
)
job_result = job2.result()
print(f"The primitive-job finished with result {job_result}")SamplerV1 の概要
Qiskitには現在、レガシーな SamplerV1 インターフェイスの実装はありません。 しかし BaseSamplerV1 からの抽象インターフェース定義は、外部実装との後方互換性を提供するために、まだパッケージの一部である。
サンプラークラスは、量子回路からビット列の確率または準確率を計算する。
SamplerV1 は空のパラメータセットで初期化される。 BaseSamplerV1 の実装は、 .run() メソッドで以下のパラメータを指定して呼び出すことができる:
- quantum circuits ( ): (パラメータ化された)量子回路のリスト。 (オブジェクトのリスト
QuantumCircuitオブジェクトのリスト) - parameter values ( ): 量子回路のパラメータに束縛されるパラメータ値のセットのリスト。 (フロートのリストのリスト)
.run() は JobV1 オブジェクトを返します。 呼び出し qiskit.providers.JobV1.result() を呼び出すと SamplerResult オブジェクトが生成され、ビット列の確率または準確率と、サンプルのエラーバーのようなオプションのメタデータが含まれる。
以下は、 SamplerV1 の実装例である。 Qiskitには現在、レガシーな SamplerV1 インターフェイスの実装がないことに注意してください。
# This is a fictional import path.
# There are currently no SamplerV1 implementations in Qiskit.
from sampler_v1_location import Sampler
from qiskit import QuantumCircuit
from qiskit.circuit.library import RealAmplitudes
# a Bell circuit
bell = QuantumCircuit(2)
bell.h(0)
bell.cx(0, 1)
bell.measure_all()
# two parameterized circuits
pqc = RealAmplitudes(num_qubits=2, reps=2)
pqc.measure_all()
pqc2 = RealAmplitudes(num_qubits=2, reps=3)
pqc2.measure_all()
theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 2, 3, 4, 5, 6, 7]
# initialization of the sampler
sampler = SamplerV1()
# Sampler runs a job on the Bell circuit
job = sampler.run(
circuits=[bell], parameter_values=[[]], parameters=[[]]
)
job_result = job.result()
print([q.binary_probabilities() for q in job_result.quasi_dists])
# Sampler runs a job on the parameterized circuits
job2 = sampler.run(
circuits=[pqc, pqc2],
parameter_values=[theta1, theta2],
parameters=[pqc.parameters, pqc2.parameters])
job_result = job2.result()
print([q.binary_probabilities() for q in job_result.quasi_dists])プリミティブからの移行 V1 から V2 へ
Primitives V1 と V2 のAPIにおける形式的な違いは、プリミティブの実装が継承する基底クラスにあり、これらはすべてページの下部に一覧表示されています。 ただし、概念的なレベルでは、 V1 から V2: へ移行する際に留意すべき、いくつかの重要な違いがあります
-
V2 プリミティブはベクトル化された入力を好み、単一の回路をベクトル値(またはより一般的には配列値)の仕様でグループ化することができる。 各グループはプリミティブ・ユニファイド・ブロック(パブ)と呼ばれ、各パブは独自の結果を得る。 例えば、見積もりでは次のような違いを比較することができる:
# Favoured V2 pattern. There is only one pub here, but there could be more. job = estimator_v2.run([(circuit, [obs1, obs2, obs3, obs4])]) evs = job.result()[0].data.evs # V1 equivalent, where the same circuit must be provided four times. job = estimator_v1.run([circuit] * 4, [obs1, obs2, obs3, obs4]) evs = job.result().values上記の例では、簡潔にするために示していないが、回路はパラメトリックにすることができ、観測値の配列に対してパラメータ値の配列がブロードキャストされる。 サンプラーも同様だが、観測値がない:
# Favoured V2 pattern. There is only one pub here, but there could be more. job = sampler_v2.run([(circuit, [vals1, vals2, vals3])]) samples = job.result()[0].data # V1 equivalent, where the same circuit must be provided three times. sampler_v1.run([circuit] * 3, [vals1, vals2, vals3]) quasi_dists = job.result().quasi_dists -
V2 サンプラーは、古典的な結果のサンプルを、それらが測定されたショット順を保持したまま返す。 これは、代わりに古典的な結果に対する分布の推定である準確率分布を出力する V1 サンプラーとは対照的である。 さらに、 V2 サンプラーの結果オブジェクトは、入力回路の古典的なレジスタ名でデータを整理するため、ダイナミック回路との自然な互換性が得られる。
V2 インタフェースにおける準確率分布の最も近い類似は
get_counts()メソッドである。 しかし、実用的な規模の実験(100量子ビット以上)では、同じビット列を2回測定する可能性は小さく、辞書形式でカウントをビニングすることは、通常、効率的なデータ処理戦略にはならないことを強調する。circuit = QuantumCircuit(QuantumRegister(2, "qreg"), ClassicalRegister(2, "alpha")) circuit.h(0) circuit.cx(0, 1) circuit.measure([0, 1], [0, 1]) # V1 sampler usage result = sampler_v1.run([circuit]).result() quasi_dist = result.quasi_dists[0] # V2 sampler usage result = sampler_v2.run([circuit]).result() # these are the bit values from the alpha register, over all shots bitvals = result[0].data.alpha # we can use it to generate a Counts mapping, which is similar to a quasi prob distribution counts = bitvals.get_counts() # which can in turn be converted to the V1 type through normalization quasi_dist = QuasiDistribution({outcome: freq / shots for outcome, freq in counts.items()}) -
V2 のプリミティブは、すべての量子システムに内在する確率的性質に起因するサンプリング・オーバーヘッドという概念を、単なるオプションからAPIそのものへと組み込みました。 サンプラーにとって、これは
shots引run()数がシグネチャの一部となったことを意味します。さらに、各パブリックメソッドは `` に対して独自の値を指定することができ、その値はメソッドshotsに渡された値よりも優先されます。 この推定関数には、プリミティブ実装が期待値の推定値として目指すべき誤差範囲を指定する、同様のprecision引数があります。この概念は V1 プリミティブのAPIには存在しないが、 V1 プリミティブのすべての実装には、オプションのどこかに関連する設定がある。
# Sample two circuits at 128 shots each. sampler_v2.run([circuit1, circuit2], shots=128) # Sample two circuits at different amounts of shots. The "None"s are necessary as placeholders # for the lack of parameter values in this example. sampler_v2.run([(circuit1, None, 123), (circuit2, None, 456)]) # Estimate expectation values for two pubs, both with 0.05 precision. estimator_v2.run([(circuit1, obs_array1), (circuit2, obs_array_2)], precision=0.05)
プリミティブ API
パラメータ V2
ParameterLike | ユニオン型を表す |
BindingsArray( [データ、形状] ) | . に対するパラメータ qiskit.QuantumCircuitバインディングの値セットを保存します。 |
BindingsArrayLike | 別名 `Mapping[ParameterLike |
見積もりツール V2
BaseEstimatorV2() | EstimatorV2 実装のための基本クラス。 |
StatevectorEstimator(*[, default_precision,...] ) | のシンプルな実装。 BaseEstimatorV2 を実装した。 |
BackendEstimatorV2(*, backend[, options] ) | 提供された量子回路と観測値の組み合わせに対する期待値を評価する。 |
EstimatorPub(回路、観測可能量[、……] ) | 任意の推定子プリミティブ用のプリミティブ統一ブロック。 |
ObservablesArray(観測可能量[、量子ビット数、...] ) | ある Estimator 原始関数に対するエルミート観測量のND配列。 |
ObservableLike | ユニオン型を表す |
EstimatorPubLike | 別名 EstimatorPub |
ObservablesArrayLike | 別名 `ObservableLike |
サンプラー V2
BaseSamplerV2() | SamplerV2 実装のための基本クラス。 |
StatevectorSampler(*[, default_shots, seed] ) | 完全な状態ベクトル・シミュレーションを使った BaseSamplerV2 完全な状態ベクトルシミュレーションを使用した |
BackendSamplerV2(*, backend[, options] ) | 提供された量子回路のビット列を評価する |
SamplerPub(回路[, パラメータ値,...] ) | サンプラー用のPub(Primitive Unified Bloc)。 |
SamplerPubLike | 別名 SamplerPub |
結果 V2
BitArray(array, num_bits) | ビット値の配列を格納する。 |
DataBin(♪*[, shape] ) | 単一のパブからの主なデータ返却は、 PubResult. |
PrimitiveResult(pub_results[, metadata] ) | 複数のパブの結果とグローバルなメタデータを格納するコンテナ。 |
PubResult(データ[、メタデータ] ) | 単一のパブ(プリミティブ統一ブロック)に対する結果オブジェクト。 |
SamplerPubResult(データ[、メタデータ] ) | サンプラー・パブの結果 |
BasePrimitiveJob(job_id, **kwargs) | プリミティブジョブの抽象ベースクラス。 |
PrimitiveJob(function, ˶*args, ˶**kwargs) | Qiskitのプリミティブの参照実装からジョブへのハンドル。 |
見積もりツール V1
BaseEstimatorV1[(オプション)] | EstimatorV1 実装のための基本クラス。 |
EstimatorResult(値、メタデータ) | エスティメーターの結果 V1. |
サンプラー V1
BaseSamplerV1[(オプション)] | サンプラー V1 基本クラス |
SamplerResult(quasi_dists, metadata) | サンプラーの結果 V1. |