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

プリミティブを使ってみる

新しい実行モデル(ベータリリース)

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

備考

このドキュメントではQiskit Runtimeのプリミティブを使用しており、IBM®のバックエンドを利用できます。ただし、代わりにバックエンドプリミティブを使用することで、任意のプロバイダーでプリミティブを実行できます。また、リファレンスプリミティブを使用してローカルの状態ベクトルシミュレーター上で実行することも可能です。詳細については、Qiskitプリミティブによる厳密なシミュレーションを参照してください。

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime

このトピックの手順では、プリミティブのセットアップ方法、設定に使用できるオプションの確認、およびプログラム内での呼び出し方法について説明します。

フラクショナルゲートの使用

新しくサポートされたフラクショナルゲートを使用するには、QiskitRuntimeServiceインスタンスからバックエンドを要求する際にuse_fractional_gates=Trueを設定します。例えば:

service = QiskitRuntimeService()
fractional_gate_backend = service.least_busy(use_fractional_gates=True)

これは実験的な機能であり、将来変更される可能性があることに注意してください。

パッケージのバージョン

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

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

Estimatorを使ってみる

1. アカウントの初期化

Qiskit Runtime EstimatorはマネージドサービスであるためEstimatorはマネージドサービスであるため、まずアカウントを初期化する必要があります。その後、期待値の計算に使用するQPUを選択できます。

アカウントをまだ持っていない場合は、インストールとセットアップのトピックの手順に従ってください。

from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)

print(backend.name)
ibm_torino

2. Circuit(回路)とオブザーバブルの作成

Estimatorプリミティブへの入力として、少なくとも1つのCircuitと1つのオブザーバブルが必要です。

from qiskit.circuit.library import qaoa_ansatz
from qiskit.quantum_info import SparsePauliOp

entanglement = [tuple(edge) for edge in backend.coupling_map.get_edges()]
observable = SparsePauliOp.from_sparse_list(
[("ZZ", [i, j], 0.5) for i, j in entanglement],
num_qubits=backend.num_qubits,
)
circuit = qaoa_ansatz(observable, reps=2)
# the circuit is parametrized, so we will define the parameter values for execution
param_values = [0.1, 0.2, 0.3, 0.4]

print(f">>> Observable: {observable.paulis}")
>>> Observable: ['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...', ...]

CircuitとオブザーバブルはQPUがサポートする命令のみを使用するように変換する必要があります(*命令セットアーキテクチャ(ISA)*回路と呼ばれます)。これにはTranspilerを使用します。

from qiskit.transpiler import generate_preset_pass_manager

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
print(f">>> Circuit ops (ISA): {isa_circuit.count_ops()}")
>>> Circuit ops (ISA): OrderedDict([('rz', 3826), ('sx', 1601), ('cz', 968)])

3. Qiskit Runtime Estimatorの初期化

Estimatorを初期化する際は、modeパラメーターを使用して実行モードを指定します。指定できる値は、バッチ、セッション、ジョブ実行モードに対してそれぞれbatchsession、またはbackendオブジェクトです。詳細については、Qiskit Runtime実行モードの概要を参照してください。

from qiskit_ibm_runtime import EstimatorV2 as Estimator

estimator = Estimator(mode=backend)

4. Estimatorの呼び出しと結果の取得

次に、run()メソッドを呼び出して、入力されたCircuitとオブザーバブルの期待値を計算します。Circuit、オブザーバブル、およびオプションのパラメーター値セットは、プリミティブ統合ブロック(PUB)タプルとして入力されます。

job = estimator.run([(isa_circuit, isa_observable, param_values)])
print(f">>> Job ID: {job.job_id()}")
print(f">>> Job Status: {job.status()}")
>>> Job ID: d5k96c4jt3vs73ds5smg
>>> Job Status: QUEUED
result = job.result()
print(f">>> {result}")
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")
>>> PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(), dtype=float64>), stds=np.ndarray(<shape=(), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(), dtype=float64>)), metadata={'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': False, 'enable_measure': True, 'num_randomizations': 'auto', 'shots_per_randomization': 'auto', 'interleave_randomizations': True, 'strategy': 'active-accum'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': False, 'pec_mitigation': False}, 'version': 2})
> Expectation value: 25.8930784649363
> Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}

Samplerを使ってみる

1. アカウントの初期化

Qiskit Runtime SamplerはマネージドサービスであるためSamplerはマネージドサービスであるため、まずアカウントを初期化する必要があります。その後、期待値の計算に使用するQPUを選択できます。

アカウントをまだセットアップしていない場合は、インストールとセットアップのトピックの手順に従ってください。

from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)

2. Circuitの作成

Samplerプリミティブへの入力として、少なくとも1つのCircuitが必要です。

import numpy as np
from qiskit.circuit.library import efficient_su2

circuit = efficient_su2(127, entanglement="linear")
circuit.measure_all()
# The circuit is parametrized, so we will define the parameter values for execution
param_values = np.random.rand(circuit.num_parameters)

TranspilerでISA回路を取得します。

from qiskit.transpiler import generate_preset_pass_manager

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
print(f">>> Circuit ops (ISA): {isa_circuit.count_ops()}")
>>> Circuit ops (ISA): OrderedDict([('sx', 3089), ('rz', 3036), ('cz', 1092), ('measure', 127), ('barrier', 1)])

3. Qiskit Runtime Samplerの初期化

Samplerを初期化する際は、modeパラメーターを使用して実行モードを指定します。指定できる値は、バッチ、セッション、ジョブ実行モードに対してそれぞれbatchsession、またはbackendオブジェクトです。詳細については、Qiskit Runtime実行モードの概要を参照してください。なお、オープンプランのユーザーはセッションジョブを送信できません。

from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(mode=backend)

4. Samplerの呼び出しと結果の取得

次に、run()メソッドを呼び出して出力を生成します。Circuitおよびオプションのパラメーター値セットは、プリミティブ統合ブロック(PUB)タプルとして入力されます。

job = sampler.run([(isa_circuit, param_values)])
print(f">>> Job ID: {job.job_id()}")
print(f">>> Job Status: {job.status()}")
>>> Job ID: d5k96rsjt3vs73ds5tig
>>> Job Status: QUEUED
result = job.result()

# Get results for the first (and only) PUB
pub_result = result[0]
print(
f"First ten results for the 'meas' output register: {pub_result.data.meas.get_bitstrings()[:10]}"
)
First ten results for the 'meas' output register: ['0101001101010000011001110001011000010010001100001000100110011111011110000010110001101000110011101010000100011011000110101111000', '0100111000000100110001100100000101111000111001101000110111101110110010010100001101001111001010011101010000010011000110000010001', '0101111101111111010011010101000000110100000010000010011101100011100011001100000100100001000101000000100001010101010011001101100', '1100110101111111001110010000010100101010101010001000001100100110011111010000000010001000110111010000010101100000100000110111001', '0010000001111001111010100100010111101000101000100000101100001000011100000100011010110110100011100110001001110110111101010011000', '0101110000001000100100010010100100111000010100000000010010000000010110010010000110000001110110010100000111001110100100111101100', '0100011111101001000111110011011101101101110101110001010111011101111110011101001000000001110000011110000101010000001010000100000', '0001010101011000110100000100111111100001011000111110000011000111001101010000010001001100000110000000100000110101010010101110010', '0100011010001110011110000110100101100100101001001111010100100101010100010000000010100000101010110010000000001000010101011111110', '0000011000000111000001000101111111110110101100110000001100010010011101011100001010000100011010001010001101000000000000010001001']

バックエンドプリミティブを使ってみる

プロバイダー固有のプリミティブとは異なり、バックエンドプリミティブは汎用的な実装であり、Backendインターフェースを実装している限り、任意のbackendオブジェクトで使用できます。

一部のプロバイダーはプリミティブをネイティブに実装しています。詳細については、Qiskit Ecosystemページを参照してください。

例:BackendEstimator

from qiskit.primitives import BackendEstimatorV2
from <some_qiskit_provider> import QiskitProvider

provider = QiskitProvider()
backend = provider.get_backend('backend_name')
estimator = BackendEstimatorV2(backend)

例:BackendSampler

from qiskit.primitives import BackendSamplerV2
from <some_qiskit_provider> import QiskitProvider

provider = QiskitProvider()
backend = provider.get_backend('backend_name')
sampler = BackendSamplerV2(backend)

バックエンドプリミティブとRuntimeプリミティブの共通点と相違点

  • qiskit.primitives.BackendSamplerV2およびqiskit.primitives.BackendEstimatorV2への入出力は、Qiskit Runtimeのプリミティブと同じPUB形式に従います。詳細については、プリミティブの入力と出力を参照してください。 ただし、返されるメタデータのフィールドには差異がある場合があります。

  • qiskit.primitives.BackendEstimatorV2クラスは、測定エラーやゲートエラーの緩和実装をデフォルトでは提供していません。これは、バックエンドプリミティブがユーザーのマシン上でローカルに実行されるように設計されているためです。

  • qiskit.primitives.BackendSamplerV2クラスは、memoryオプションをサポートするバックエンドを必要とします。

  • バックエンドプリミティブのインターフェースは、Runtimeの実装とは異なるカスタムのSamplerV2およびEstimatorV2Optionsを公開しています。

次のステップ

推奨事項