注釈
このページは docs/tutorials/how-to-getting-started-with-estimator.ipynb から生成されました。
Estimator primitive 入門¶
このチュートリアルでは、Qiskit Rumtime Estimator
primitiveを設定する方法、設定に使用できるさまざまなoption、およびsession内でprimitiveを効率的に呼び出す方法を説明します。
プリミティブ¶
Primitives are core functions that make it easier to build modular algorithms and applications.
Qiskit Runtimeの初期リリースには、次の2つのprimitiveが含まれています。
Sampler: Generates quasi-probability distribution from input circuits.
Estimator: 入力回路と観測量から期待値を計算する。
このチュートリアルでは、 Estimator
primitiveに焦点を当てます。Sampler primtive 入門 というチュートリアルは別にあります。
Estimator primitive を使う¶
Backend
の基底クラスと同様に、Qiskit Terraには Estimator
基底クラスが定義されており、ユーザーがすべての Estimator
実装と対話する方法を標準化します。これにより、基礎となる実装が異なっていても、期待値計算を行うためのシミュレーターやデバイスの選択を簡単に変更することができます。
このセクションでは、Qiskit Terraのデフォルトの実装であるローカルの状態ベクトル・シミュレーターを使用します。
1. 回路の作成¶
基本的な期待値計算のためには、研究のための正確な量子状態でシステムを準備するために、少なくとも1つの量子回路が必要になります. すべての例に回路が含まれていますが、Qiskit を使用して独自の回路を作成することができます。 Qiskit を使用して回路を作成する方法については、回路の基本チュートリアル を参照してください。
[1]:
from qiskit.circuit.random import random_circuit
circuit = random_circuit(2, 2, seed=0).decompose(reps=1)
display(circuit.draw("mpl"))

2. 測定する観測量の作成¶
少なくとも測定する1つの観測量も必要です。観測量は量子系の物理的特性 (エネルギーやスピンなど) を表し、系の与えられた状態について前記特性を測定 (期待値など) できるようにします。単純化するために、以下の例に示すように、Qiskitの `SparsePauliOp クラス <https://qiskit.org/documentation/stubs/qiskit.quantum_info.SparsePauliOp.html#qiskit.quantum_info.SparsePauliOp>`__を使用してそれらを定義することができます。
[2]:
from qiskit.quantum_info import SparsePauliOp
observable = SparsePauliOp("XZ")
print(f">>> Observable: {observable.paulis}")
>>> Observable: ['XZ']
3. Estimatorクラスの初期化¶
The next step is to create an instance of an Estimator
class, which can be any of the subclasses that comply with the base specification. For simplicity, we will use Qiskit Terra’s qiskit.primitives.Estimator
class, based on the Statevector construct (algebraic simulation).
[3]:
from qiskit.primitives import Estimator
estimator = Estimator()
4. Estimatorの呼び出しおよび結果の取得¶
期待値を計算するには、先ほど作成した Estimator
インスタンスの run()
メソッドを呼び出し、入力パラメータとして回路と観測量を渡します。このメソッドの呼び出しは非同期で、Job
オブジェクトを戻します。 このオブジェクトを使って job_id()
や status()
のような情報を問い合わせることができます。
[4]:
job = estimator.run(circuit, observable)
print(f">>> Job ID: {job.job_id()}")
print(f">>> Job Status: {job.status()}")
>>> Job ID: 85a54b84-7ce2-49f8-b614-cc39ef8eafcc
>>> Job Status: JobStatus.DONE
ジョブの result()
メソッドは、期待値とジョブのメタデータ双方を含む EstimatorResult
を返します。
[5]:
result = job.result()
print(f">>> {result}")
print(f" > Expectation value: {result.values[0]}")
>>> EstimatorResult(values=array([0.85347811]), metadata=[{}])
> Expectation value: 0.8534781134132173
このように、入力を変えて再度 run()
メソッドを起動し続けることができます。
[6]:
circuit = random_circuit(2, 2, seed=1).decompose(reps=1)
observable = SparsePauliOp("IY")
job = estimator.run(circuit, observable)
result = job.result()
display(circuit.draw("mpl"))
print(f">>> Observable: {observable.paulis}")
print(f">>> Expectation value: {result.values[0]}")

>>> Observable: ['IY']
>>> Expectation value: -1.582539029327245e-16
run()
メソッドに複数の入力を提供することもできます。
[7]:
circuits = (
random_circuit(2, 2, seed=0).decompose(reps=1),
random_circuit(2, 2, seed=1).decompose(reps=1),
)
observables = (
SparsePauliOp("XZ"),
SparsePauliOp("IY"),
)
job = estimator.run(circuits, observables)
result = job.result()
[display(cir.draw("mpl")) for cir in circuits]
print(f">>> Observables: {[obs.paulis for obs in observables]}")
print(f">>> Expectation values: {result.values.tolist()}")


>>> Observables: [PauliList(['XZ']), PauliList(['IY'])]
>>> Expectation values: [0.8534781134132173, -1.582539029327245e-16]
もしくはパラメーター化された回路を使用します。
[8]:
from qiskit.circuit.library import RealAmplitudes
circuit = RealAmplitudes(num_qubits=2, reps=2).decompose(reps=1)
observable = SparsePauliOp("ZI")
parameter_values = [0, 1, 2, 3, 4, 5]
job = estimator.run(circuit, observable, parameter_values)
result = job.result()
display(circuit.draw("mpl"))
print(f">>> Observable: {observable.paulis}")
print(f">>> Parameter values: {parameter_values}")
print(f">>> Expectation value: {result.values[0]}")

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

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

以下の例では、Sampler
クラスと Estimator
クラスのインスタンスを両方作成し、セッション内で run()
メソッドを呼び出す方法を示しています。
[22]:
from qiskit_ibm_runtime import Session, Sampler, Estimator
with Session(backend=backend):
sampler = Sampler()
estimator = Estimator()
result = sampler.run(sampler_circuit).result()
print(f">>> Quasi-probability distribution from the sampler job: {result.quasi_dists[0]}")
result = estimator.run(circuit, observable).result()
print(f">>> Expectation value from the estimator job: {result.values[0]}")
>>> Quasi-probability distribution from the sampler job: {2: 0.50125, 0: 0.49875}
>>> Expectation value from the estimator job: 0.8525
呼び出しは非同期にすることもできます。別のジョブを送信する前に、前のジョブの結果を待つ必要はありません。
[23]:
from qiskit_ibm_runtime import Session, Sampler, Estimator
with Session(backend=backend):
sampler = Sampler()
estimator = Estimator()
sampler_job = sampler.run(sampler_circuit)
estimator_job = estimator.run(circuit, observable)
print(
f">>> Quasi-probability 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-probability distribution from the sampler job: {2: 0.49025, 0: 0.50975}
>>> Expectation value from the estimator job: 0.8475
まとめ¶
以下は、Qiskit Runtime primitive、オプション、そしてセッションを簡単にまとめたものです。
[24]:
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(sampler_circuit)
estimator_job = estimator.run(circuit, observable)
# 7. Get results
print(
f">>> Quasi-probability 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-probability distribution from the sampler job: {0: 0.49575, 2: 0.50425}
>>> Expectation value from the estimator job: 0.8315
参考資料¶
Estimator
メソッドの詳細は、 Estimator API reference を参照してください。
そして利用可能なすべてのオプションは、Options API reference に記載されています。
[25]:
import qiskit_ibm_runtime
qiskit_ibm_runtime.version.get_version_info()
[25]:
'0.8.0'
[26]:
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:11:54 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.