Japanese
言語
English
Japanese
Spanish

注釈

このページは docs/tutorials/how-to-getting-started-with-estimator.ipynb から生成されました。

Estimator primitive 入門

このチュートリアルでは、Qiskit Rumtime Estimator primitiveを設定する方法、設定に使用できるさまざまなoption、およびsession内でprimitiveを効率的に呼び出す方法を説明します。

プリミティブ

Primitiveは、モジュール化されたアルゴリズムやアプリケーションを簡単に構築するためのコア関数です。

単にカウントを返す代わりに、より即座に意味のある情報を返すことができます。

さらに、IBM Quantumのハードウェアとソフトウェアの最新の進歩にアクセスするためのシームレスな方法を提供します。

Qiskit Runtimeの初期リリースには、次の2つのprimitiveが含まれています。

Sampler: 入力回路から準確率を生成する。

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"))
../_images/tutorials_how-to-getting-started-with-estimator_10_0.png

2. 測定する観測量の作成

You will also need at least one observable to measure. Observables represent physical properties of a quantum system (such as energy or spin), and allow said properties to be measured (such as their expectation values) for a given state of our system. For simplicity, you can use the SparsePauliOp class in Qiskit to define them, as illustrated in the following example.

[2]:
from qiskit.quantum_info import SparsePauliOp

observable = SparsePauliOp("XZ")
print(f">>> Observable: {observable.paulis}")
>>> Observable: ['XZ']

3. Estimatorクラスの初期化

次のステップは、Estimator クラスのインスタンスを作ることです。これは、Estimator primitiveの仕様に準拠した どのような``Estimator`` クラスでも構いません。分かりやすくするため、Qiskit Terraの qiskit.primitives.Estimator クラスを使用します。これは、 Statevector construct (すなわち代数シミュレーション) に基づいています。

[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]}")
../_images/tutorials_how-to-getting-started-with-estimator_23_0.png
>>> 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()}")
../_images/tutorials_how-to-getting-started-with-estimator_25_0.png
../_images/tutorials_how-to-getting-started-with-estimator_25_1.png
>>> 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]}")
../_images/tutorials_how-to-getting-started-with-estimator_27_0.png
>>> 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}")
../_images/tutorials_how-to-getting-started-with-estimator_35_0.png
>>> Observable: ['XZ']

3. Qiskit Runtime Estimator の初期化

ここでは、Qiskit Runtimeの Estimator の実装を使用するため、 qiskit.primitives.Estimator の代わりに qiskit_ibm_runtime.Estimator のインスタンスを初期化します。

Estimator を初期化する場合は、 session パラメータを使用して、先に選択したバックエンドをターゲット・デバイス (またはシミュレーター) として渡す必要があります。 これにより、バックエンドのセッションが自動的に開きます。セッションについては、後のセクションで詳しく説明します。

[11]:
from qiskit_ibm_runtime import Estimator

estimator = Estimator(session=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 クラスを使用して、さまざまなオプションを指定できます。

以下の例では、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(session=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(session=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 `` を使用して、エラーの抑止と軽減を構成します。

Estimatoroptimization_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(session=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 パラメーターを使用して設定できます。

タイムアウト値を指定しない場合、最初のジョブの最大実行時間に設定されます。これは次のうち小さい方の値です。

この制限時間に達すると、セッションは永久にクローズされます。

セッションには 対話的 タイムアウト値もあります。 そのウィンドウ内に待ち行列に入ったセッション・ジョブがない場合、セッションは一時的に無効化され、通常のジョブ選択が再開されます。 この対話的タイムアウト値はシステムによって設定され、上書きすることはできません。

セッション内での 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"))
../_images/tutorials_how-to-getting-started-with-estimator_69_0.png

以下の例では、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 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 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 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.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 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.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 SoftwareVersion
qiskit-terra0.22.2
qiskit-aer0.11.0
qiskit-ibmq-provider0.19.2
qiskit-nature0.5.0
System information
Python version3.8.1
Python compilerClang 11.0.3 (clang-1103.0.32.62)
Python builddefault, Jul 15 2020 18:48:27
OSDarwin
CPUs8
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.