注釈
このページは docs/tutorials/how-to-getting-started-with-sampler.ipynb から生成されました。
Sampler primitive 入門¶
このチュートリアルでは、Qiskit Rumtime Sampler
primitiveを設定する方法、設定に使用できるさまざまなoption、およびsession内でprimitiveを効率的に呼び出す方法を説明します。
Primitives¶
Primitiveは、モジュール化されたアルゴリズムやアプリケーションを簡単に構築するためのコア関数です。
単にカウントを返す代わりに、より即座に意味のある情報を返すことができます。
さらに、IBM Quantumのハードウェアとソフトウェアの最新の進歩にアクセスするためのシームレスな方法を提供します。
Qiskit Runtimeの初期リリースには、次の2つのprimitiveが含まれています。
Sampler: 入力回路から準確率を生成する。
Estimator: 入力回路と観測量から期待値を計算する。
このチュートリアルでは、 Sampler
primitiveに焦点を当てます。Estimator primtive 入門 というチュートリアルは別にあります。
Sampler primitive を使う¶
Backend
の基底クラスと同様に、Qiskit Terraには Sampler
基底クラスが定義されており、ユーザーがすべての Sampler
実装と対話する方法を標準化します。これにより、基礎となる実装が異なっていても、期待値計算を行うためのシミュレーターやデバイスの選択を簡単に変更することができます。
このセクションでは、Qiskit Terraのデフォルトの実装であるローカルの状態ベクトル・シミュレーターを使用します。
1. 回路の作成¶
研究のための正確な量子状態でシステムを準備するために、少なくとも1つの量子回路が必要になります。すべての例に回路が含まれていますが、Qiskit を使用して独自の回路を作成することができます。 Qiskit を使用して回路を作成する方法については、回路の基本チュートリアル を参照してください。
[1]:
from qiskit.circuit.random import random_circuit
circuit = random_circuit(2, 2, seed=0, measure=True).decompose(reps=1)
display(circuit.draw("mpl"))

2. Samplerクラスの初期化¶
次のステップは、Sampler
クラスのインスタンスを作ることです。これは、Sampler
primitiveの仕様に準拠した どのような``Sampler`` クラスでも構いません。分かりやすくするため、Qiskit Terraの qiskit.primitives.Sampler
クラスを使用します。これは、 Statevector construct (すなわち代数シミュレーション) に基づいています。
[2]:
from qiskit.primitives import Sampler
sampler = Sampler()
3. Samplerの呼び出しおよび結果の取得¶
回路出力の準確率分散を推定するには、先ほど作成した Sampler
インスタンスの run()
メソッドを呼び出し、入力パラメータとして回路を渡します。このメソッドの呼び出しは非同期で、Job
オブジェクトを戻します。 このオブジェクトを使って job_id()
や status()
のような情報を問い合わせることができます。
[3]:
job = sampler.run(circuit)
print(f">>> Job ID: {job.job_id()}")
print(f">>> Job Status: {job.status()}")
>>> Job ID: 979495e7-7f0d-4b92-acbc-19da7dad864d
>>> Job Status: JobStatus.DONE
ジョブの result()
メソッドは、準確率分散とジョブのメタデータ双方を含む SamplerResult
を返します。
[4]:
result = job.result()
print(f">>> {result}")
print(f" > Quasi-distribution: {result.quasi_dists[0]}")
>>> SamplerResult(quasi_dists=[{0: 0.4999999999999999, 1: 0.0, 2: 0.4999999999999998, 3: 0.0}], metadata=[{}])
> Quasi-distribution: {0: 0.4999999999999999, 1: 0.0, 2: 0.4999999999999998, 3: 0.0}
このように、入力を変えて再度 run()
メソッドを呼び出し続けることができます。
[5]:
circuit = random_circuit(2, 2, seed=1, measure=True).decompose(reps=1)
job = sampler.run(circuit)
result = job.result()
display(circuit.draw("mpl"))
print(f">>> Quasi-distribution: {result.quasi_dists[0]}")

>>> Quasi-distribution: {0: 0.9999999999999991, 1: 6.580329297619248e-33, 2: 0.0, 3: 0.0}
run()
メソッドに複数の入力を提供することもできます。
[6]:
circuits = (
random_circuit(2, 2, seed=0, measure=True).decompose(reps=1),
random_circuit(2, 2, seed=1, measure=True).decompose(reps=1),
)
job = sampler.run(circuits)
result = job.result()
[display(cir.draw("mpl")) for cir in circuits]
print(f">>> Quasi-distribution: {result.quasi_dists}")


>>> Quasi-distribution: [{0: 0.4999999999999999, 1: 0.0, 2: 0.4999999999999998, 3: 0.0}, {0: 0.9999999999999991, 1: 6.580329297619248e-33, 2: 0.0, 3: 0.0}]
もしくはパラメーター化された回路を使用します。
[7]:
from qiskit.circuit.library import RealAmplitudes
circuit = RealAmplitudes(num_qubits=2, reps=2).decompose(reps=1)
circuit.measure_all()
parameter_values = [0, 1, 2, 3, 4, 5]
job = sampler.run(circuit, parameter_values)
result = job.result()
display(circuit.draw("mpl"))
print(f">>> Parameter values: {parameter_values}")
print(f">>> Quasi-distribution: {result.quasi_dists[0]}")

>>> Parameter values: [0, 1, 2, 3, 4, 5]
>>> Quasi-distribution: {0: 0.17158451004815306, 1: 0.0041370682135240654, 2: 0.20402129418492707, 3: 0.6202571275533961}
Qiskit Runtime Samplerの使用¶
このセクションでは、Qiskit Runtimeの Sampler
primitiveの実装方法について説明します。
1. アカウントの初期化¶
QisKit Runtimeの Sampler
はマネージドサービスなので、まずアカウントを初期化する必要があります。 すると、期待値を計算するために使用するシミュレーターや実際のバックエンドを選択できるようになります。
まだアカウントを設定していない場合は、 getting started guide の手順に従ってください。
[8]:
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService(channel="ibm_quantum")
backend = service.backend("ibmq_qasm_simulator")
2. 回路の作成¶
前のセクションと同様に、Sampler
primitive への入力として少なくとも1つの回路が必要です。
[9]:
from qiskit.circuit.random import random_circuit
circuit = random_circuit(2, 2, seed=0, measure=True).decompose(reps=1)
display(circuit.draw("mpl"))

3. Qiskit Runtime Sampler の初期化¶
ここでは、Qiskit Runtimeの Sampler
の実装を使用するため、 qiskit.primitives.Sampler
の代わりに qiskit_ibm_runtime.Sampler
のインスタンスを初期化します。
Sampler
を初期化する場合、backend
パラメータを使用して、先に選択したバックエンドをターゲットデバイス (またはシミュレーター) として渡す必要があります。
[10]:
from qiskit_ibm_runtime import Sampler
sampler = Sampler(backend=backend)
4. Samplerの呼び出しおよび結果の取得¶
その後、 run()
メソッドを呼び出して、入力回路と観測量の期待値を計算することができます。
[11]:
job = sampler.run(circuit)
print(f">>> Job ID: {job.job_id()}")
print(f">>> Job Status: {job.status()}")
>>> Job ID: cdkrk4qan60ka16e6v0g
>>> Job Status: JobStatus.RUNNING
[12]:
result = job.result()
print(f">>> {result}")
print(f" > Quasi-distribution: {result.quasi_dists[0]}")
print(f" > Metadata: {result.metadata[0]}")
>>> SamplerResult(quasi_dists=[{2: 0.49275, 0: 0.50725}], metadata=[{'header_metadata': {}, 'shots': 4000}])
> Quasi-distribution: {2: 0.49275, 0: 0.50725}
> Metadata: {'header_metadata': {}, 'shots': 4000}
オプション¶
primitiveには、さまざまなカテゴリーにグループ化された数々のオプションが用意されています。resilience_level
などの一般的に使用されるオプションは、最初のレベルにあります。
Options クラスを使用して、さまざまなオプションを指定できます。
以下の例では、Options
クラスのインスタンスを作成します。 optimization_level
は最初のレベルのオプションで、入力パラメーターとして渡すことができます。 実行環境に関連するオプションは environment
パラメーターを使用して渡されます。
[13]:
from qiskit_ibm_runtime import Options
options = Options(optimization_level=3, environment={"log_level": "INFO"})
Options
は自動補完をサポートします。Options
クラスのインスタンスを作成したら、自動補完を使用して利用可能なオプションを確認できます。 カテゴリーを選択した場合は、再び自動補完を使用して、そのカテゴリーの下で利用可能なオプションを確認できます。
[14]:
from qiskit_ibm_runtime import Options
options = Options()
options.resilience_level = 1
options.execution.shots = 2048
Sampler
クラスのインスタンスを作成する場合、作成したばかりの options
を渡すことができます。 これらのオプションは run()
を使って計算を行うときに適用されます。
[15]:
sampler = Sampler(backend=backend, options=options)
result = sampler.run(circuit).result()
print(f">>> Metadata: {result.metadata[0]}")
>>> Metadata: {'header_metadata': {}, 'shots': 2048, 'readout_mitigation_overhead': 1.0, 'readout_mitigation_time': 0.028210751246660948}
run()
メソッドでオプションを渡すこともできます。 これにより、 Sampler
インスタンスを作成するときに指定したオプションを、特定の実行のために上書きします。
ほとんどのユーザーはジョブ・レベルでのオプションのみ上書きするので、 カテゴリーを指定する必要はありません。 例えば、execution={"shots": 1024}
(これも有効です) の代わりに shots=1024
を指定します 。
[16]:
sampler = Sampler(backend=backend, options=options)
result = sampler.run(circuit, shots=1024).result()
print(f">>> Metadata: {result.metadata[0]}")
>>> Metadata: {'header_metadata': {}, 'shots': 1024, 'readout_mitigation_overhead': 1.0, 'readout_mitigation_time': 0.002864845097064972}
エラーの抑止と軽減¶
optimization_level
および ``resilience_level `` を使用して、エラーの抑止と軽減を構成します。
Sampler
は optimization_level
0-3 と resilience_level
0-1 をサポートしています。
[17]:
from qiskit_ibm_runtime import Options
# optimization_level=3 adds dynamical decoupling
# resilience_level=1 adds readout error mitigation
options = Options(optimization_level=3, resilience_level=1)
[18]:
sampler = Sampler(backend=backend, options=options)
result = sampler.run(circuit).result()
print(f">>> Quasi-distribution: {result.quasi_dists[0]}")
print(f">>> Metadata: {result.metadata[0]}")
>>> Quasi-distribution: {0: 0.50175, 2: 0.49825}
>>> Metadata: {'header_metadata': {}, 'shots': 4000, 'readout_mitigation_overhead': 1.0, 'readout_mitigation_time': 0.04642554186284542}
セッション¶
Qiskit Runtime セッション は、量子コンピューターの反復呼び出しの集合をグループ化することができます。セッションは、プログラムの最初のジョブがセッション内で開始したときに開始されます。セッションが有効であれば、セッション内の後続のジョブは反復アルゴリズム内の人為的な遅延を最小化するようスケジューラーによって優先順位が付けられます。トランスパイルされた回路のように、セッション内で使用されるデータも、不要なオーバーヘッドを避けるためにキャッシュされます。
セッションの時間¶
セッションが開始されると、セッション・タイムアウトの最大値が割り当てられます。この値は max_time
パラメーターを使用して設定できます。
タイムアウト値を指定しない場合、最初のジョブの最大実行時間に設定されます。これは次のうち小さい方の値です。
システム制限(`Qiskit Runtime ジョブの最大実行時間は何ですか? <https://qiskit.org/documentation/partners/qiskit_ibm_runtime/faqs/max_execution_time.html>`__を参照してください)
プログラムによって定義された
max_execution_time
。
この制限時間に達すると、セッションは永久にクローズされます。
セッションには 対話的 タイムアウト値もあります。 そのウィンドウ内に待ち行列に入ったセッション・ジョブがない場合、セッションは一時的に無効化され、通常のジョブ選択が再開されます。 この対話的タイムアウト値はシステムによって設定され、上書きすることはできません。
セッション内での Sampler.run の呼び出し¶
自動的にセッションを開閉するコンテキスト・マネージャー (with ...:
) を使って、Qiskit Runtimeセッションを作成できます。セッション内で Sampler.run
を1回以上呼び出すことができます。
[19]:
from qiskit_ibm_runtime import Session, Estimator
with Session(backend=backend, max_time="1h"):
sampler = Sampler()
result = sampler.run(circuit).result()
print(f">>> Quasi-distribution from the first run: {result.quasi_dists[0]}")
result = sampler.run(circuit).result()
print(f">>> Quasi-distribution from the second run: {result.quasi_dists[0]}")
>>> Quasi-distribution from the first run: {0: 0.498, 2: 0.502}
>>> Quasi-distribution from the second run: {0: 0.498, 2: 0.502}
セッション内での複数primitiveの呼び出し¶
セッション内は単一のprimitive関数に限定されていません。このセクションでは、複数のprimitiveを使用する例を示します。
最初に、Estimator
primitiveのための回路と観測量を用意します。
[20]:
from qiskit.circuit.random import random_circuit
from qiskit.quantum_info import SparsePauliOp
estimator_circuit = random_circuit(2, 2, seed=0).decompose(reps=1)
display(estimator_circuit.draw("mpl"))
observable = SparsePauliOp("XZ")
print(f">>> Observable: {observable.paulis}")

>>> Observable: ['XZ']
以下の例では、Sampler
クラスと Estimator
クラスのインスタンスを両方作成し、セッション内で run()
メソッドを呼び出す方法を示しています。
[21]:
from qiskit_ibm_runtime import Session, Sampler, Estimator
with Session(backend=backend):
sampler = Sampler()
estimator = Estimator()
result = sampler.run(circuit).result()
print(f">>> Quasi Distribution from the sampler job: {result.quasi_dists[0]}")
result = estimator.run(estimator_circuit, observable).result()
print(f">>> Expectation value from the estimator job: {result.values[0]}")
>>> Quasi Distribution from the sampler job: {2: 0.50025, 0: 0.49975}
>>> Expectation value from the estimator job: 0.848
呼び出しは非同期にすることもできます。別のジョブを送信する前に、前のジョブの結果を待つ必要はありません。
[23]:
from qiskit_ibm_runtime import Session, Sampler, Estimator
with Session(backend=backend):
sampler = Sampler()
estimator = Estimator()
sampler_job = sampler.run(circuit)
estimator_job = estimator.run(estimator_circuit, observable)
print(
f">>> Quasi Distribution from the sampler job: {sampler_job.result().quasi_dists[0]}"
)
print(
f">>> Expectation value from the estimator job: {estimator_job.result().values[0]}"
)
>>> Quasi Distribution from the sampler job: {2: 0.508, 0: 0.492}
>>> Expectation value from the estimator job: 0.8495
まとめ¶
以下は、Qiskit Runtime primitive、オプション、そしてセッションを簡単にまとめたものです。
[25]:
from qiskit_ibm_runtime import (
QiskitRuntimeService,
Session,
Sampler,
Estimator,
Options,
)
# 1. Initialize account
service = QiskitRuntimeService(channel="ibm_quantum")
# 2. Specify options, such as enabling error mitigation
options = Options(resilience_level=1)
# 3. Select a backend.
backend = service.backend("ibmq_qasm_simulator")
# 4. Create a session
with Session(backend=backend):
# 5. Create primitive instances
sampler = Sampler(options=options)
estimator = Estimator(options=options)
# 6. Submit jobs
sampler_job = sampler.run(circuit)
estimator_job = estimator.run(estimator_circuit, observable)
# 7. Get results
print(
f">>> Quasi Distribution from the sampler job: {sampler_job.result().quasi_dists[0]}"
)
print(
f">>> Expectation value from the estimator job: {estimator_job.result().values[0]}"
)
>>> Quasi Distribution from the sampler job: {0: 0.50125, 2: 0.49875}
>>> Expectation value from the estimator job: 0.8475
参考資料¶
Sampler
メソッドの詳細は、 ``Sampler API reference <https://qiskit.org/documentation/partners/qiskit_ibm_runtime/stubs/qiskit_ibm_runtime.Sampler.html#qiskit_ibm_runtime.Sampler>`__ を参照してください。
そして利用可能なすべてのオプションは、Options API reference に記載されています。
[26]:
import qiskit_ibm_runtime
qiskit_ibm_runtime.version.get_version_info()
[26]:
'0.8.0'
[27]:
from qiskit.tools.jupyter import *
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
qiskit-terra | 0.22.2 |
qiskit-aer | 0.11.0 |
qiskit-ibmq-provider | 0.19.2 |
qiskit-nature | 0.5.0 |
System information | |
Python version | 3.8.1 |
Python compiler | Clang 11.0.3 (clang-1103.0.32.62) |
Python build | default, Jul 15 2020 18:48:27 |
OS | Darwin |
CPUs | 8 |
Memory (Gb) | 16.0 |
Mon Nov 07 21:10:31 2022 EST |
This code is a part of Qiskit
© Copyright IBM 2017, 2022.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.