実行者によるブロードキャスト
Executorプリミティブに渡されるデータは、ブロードキャストを通じてワークロードに柔軟性を持たせるため、さまざまな形式で配置することができます。 このガイドでは、Executorがブロードキャスティングのセマンティクスを使用して配列の入出力をどのように処理するかについて説明します。 これらの概念を理解することで、パラメータ値を効率的に確認したり、 複数の設定を組み合わせたり、返されるデータの形状を解釈したりするのに役立ちます。
このトピックの例は、単独では実行できません。 ここでは、適切な回路が定義されており、Samplomaticのパスマネージャーを使用してボックスや注釈が追加され、必要に応じてSamplomatic build の手法を用いて各コードブロック用のテンプレート回路とsamplexが取得されていることを前提としています。
クイックスタートの例
この例は、その基本的な考え方を示しています。 パラメトリック回路と、5種類の異なるパラメータ設定を作成します。 実行者は5つの構成すべてを実行し、構成ごとに整理されたデータを返す。各量子プログラム項目において、1つの古典レジスタにつき1つの結果が得られる。
このガイドの残りの部分では、この例を参照しながら、その仕組みや、Samplomatic を使ったランダム化や入力を含む、より複雑なスイープの作成方法について解説します。
import numpy as np
from qiskit.circuit import Parameter, QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from qiskit.transpiler import generate_preset_pass_manager
# A circuit with 2 parameters
# This circuit is used throughout the rest of this guide.
circuit = QuantumCircuit(4)
circuit.rx(Parameter("a"), 0)
circuit.rx(Parameter("b"), 1)
circuit.h(2)
circuit.cx(2, 3)
circuit.measure_all()
# 5 different parameter configurations (shape: 5 configurations × 2 parameters)
parameter_values = np.linspace(0, np.pi, 10).reshape(5, 2)
# Initialize the service and choose a backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Transpile to ISA circuit
preset_pass_manager = generate_preset_pass_manager(
backend=backend,
optimization_level=3,
)
isa_circuit = preset_pass_manager.run(circuit)
# This program is used throughout the rest of this guide.
program = QuantumProgram(shots=1024)
program.append_circuit_item(isa_circuit, circuit_arguments=parameter_values)
# initialize an Executor with default options
executor = Executor(mode=backend)
# Run and get results
result = executor.run(program).result()
# result is a list with one entry per program item
# result[0] is a dict mapping classical register names to data arrays
# Output bool arrays have shape (5, 1024, 4)
# 5 = number of parameter configurations
# 1024 = number of shots
# 4 = bits in the classical register
result[0]["meas"]内軸と外軸
放送は外因軸にのみ適用されます。 固有軸は、指定どおりに常に保持されます。
-
固有軸 (右端):データ型によって決定される。
(3,)たとえば、回路に 3つのパラメータがある場合、パラメータ値には3つの数値が必要となり、その結果、固有形状は となります。 -
外軸 (左端):スイープの寸法。 これらは、実行する構成の数を 指定します。
入力タイプ | 固有形状 | 完全な形状の例 |
|---|---|---|
| パラメータ値(パラメータ数:n) | (名詞) | (5, 3):5つの構成と3つのパラメータについて |
| スカラー入力(例:ノイズスケール) | () | (4,) 4つの構成について |
| オブザーバブル(該当する場合) | 状況による | オブザーバブルの型によって異なります |
例
4x3 の構成グリッド上で、2つのパラメータの値を変化させ、ノイズのスケール係数を調整しながらスキャンしたい回路を想定します:
import numpy as np
# Parameter values: 4 configurations along axis 0, intrinsic shape (2,)
# Full shape: (4, 1, 2) - the "1" allows broadcasting with noise_scale
parameter_values = np.array([
[[0.1, 0.2]],
[[0.3, 0.4]],
[[0.5, 0.6]],
[[0.7, 0.8]],
]) # shape (4, 1, 2)
# Noise scale: 3 configurations, intrinsic shape () (scalar)
# Full shape: (3,)
noise_scale = np.array([0.8, 1.0, 1.2]) # shape (3,)
# Extrinsic shapes: (4, 1) and (3,) → broadcast to (4, 3)
# Result: 12 total configurations in a 4×3 grid
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
"parameter_values": parameter_values,
"noise_scales.mod_ref1": noise_scale,
},
)形状は以下の通りです:
入力 | 完全な形状 | 外形 | 固有形状 |
|---|---|---|---|
parameter_values | (4, 1, 2) | (4, 1) | (2,) |
noise_scale | (3,) | (3,) | () |
| 放送 | なし | (4, 3) | なし |
出力配列の形状
出力配列も、外因的/内因的という同じパターンに従います:
- 外形: すべての入力の放送用形状に一致する
- 固有の形状: 出力タイプによって決定される
最も一般的な出力は、計測結果のビット列データであり、これは ブール値の配列としてフォーマットされます:
出力タイプ | 固有形状 | 説明 |
|---|---|---|
| 従来の登録データ | (num_shots, creg_size) | 測定データからのビット列 |
例
(4, 3)``(3,)外形 (4, 1) および を持つ入力を指定した場合、ブロードキャストされた外形は
となります。 以下のコードでは、1024ショットの回路と4ビットの古典的レジスタ( クイックスタートの例で定義されているもの)を使用しています:
# Input extrinsic shapes: (4, 1) and (3,) → (4, 3)
# Output for classical register "meas":
# extrinsic: (4, 3)
# intrinsic: (1024, 4) - shots × bits
# full shape: (4, 3, 1024, 4)
result = executor.run(program).result()
meas_data = result[0]["meas"] # result[0] for first program item
print(meas_data.shape) # (4, 3, 1024, 4)
# Access a specific configuration
config_2_1 = meas_data[2, 1, :, :] # shape (1024, 4)各構成では、量子プログラムで指定されたショット数をすべて実行します。 ショットは構成ごとに分けられていません。 たとえば、1024回のショットをリクエストし、10種類の構成がある場合、各構成で1024回のショットが実行されます(合計10,240回のショットが実行されます)。
無作為化とパラメータ shape
サンプレックスを使用する場合、外部形状の各要素は、独立した回路の実行に対応します Samplexは通常、各実行にランダム性(例えば、ゲートの回転など)を組み込むため、 明示的に複数のランダム化を要求しなくても、各要素は ランダムな実現値を受け取ることになります。
この shape パラメータを使用すると、アイテムの外形を拡張することができ、
実質的に、同じ構成を何度もランダム化することに対応する軸を追加することになります。 samplex_argumentsそれは、あなたの.に暗黙的に含まれる形状から
放送可能でなければならない。 が
の閾値を超える軸についてはshape、暗黙の形状に加えて、追加の独立したランダム化が列挙される。
明示的な無作為化軸がない
これを省略 shape する場合(または入力形状に合わせて設定する場合)、
入力構成ごとに1回ずつ実行されます。 各実行は依然としてsamplexによってランダム化されますが、
ランダムな実現値が1つしかない場合、複数のランダム化結果の平均化によるメリットは得られません。
twirling=Trueもし、のような単純なフラグでツイリングを有効にすることに慣れている場合は、
Executor では、後処理ルーチンが複数のランダム化による平均化の恩恵を受けられるようにするために、
引数を使用して複数のランダム化をshape明示的に要求する必要がある点に注意してください。 単一のランダム化(が省略された場合の shape デフォルト)では、
ランダムゲートが適用されますが、通常、ランダム化を行わずに基本回路を実行する場合と比べて
特に利点はありません。
次の例は、デフォルトの動作を示しています:
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
"parameter_values": np.random.rand(10, 2), # extrinsic (10,)
},
# shape defaults to (10,) - one randomized execution per config
)
# Output shape for "meas": (10, num_shots, creg_size)単一の無作為化軸
設定ごとに複数のランダム化を実行するには、形状に軸を追加して拡張してください。 たとえば、次のコードは、10種類のパラメータ設定それぞれについて、20回のランダム化を実行します:
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
"parameter_values": np.random.rand(10, 2), # extrinsic (10,)
},
shape=(20, 10), # 20 randomizations × 10 configurations
)
# Output shape for "meas": (20, 10, num_shots, creg_size)複数の無作為化軸
ランダム化を多次元グリッドとして整理することができます。 これは、構造化された 分析を行う際に役立ちます。例えば、無作為化を種類別に分類したり、統計処理のためにグループ分けしたりする場合などが挙げられます。
(2, 14, 10)ここでは、入力の外形 (10,) が要求された形にブロードキャストされ、
軸0と軸1は独立したランダム化によって埋められます。
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
"parameter_values": np.random.rand(10, 2), # extrinsic (10,)
},
# 2×14=28 randomizations per configuration, 10 configurations
# Or you could set shape=(28, 10) for the same effect
shape=(2, 14, 10),
)
# Output shape for "meas": (2, 14, 10, num_shots, creg_size)入力形状とどのように shape 相互作用するか
この shape パラメータは、入力となる外部形状からブロードキャスト可能でなければなりません。 これは、次のことを意味します:
shapesize-1 の寸法を持つ図形は、それに合わせて拡大することができます。shape入力する図形は、右端を揃えて配置する必要があります。- 入力寸法を超える軸は
shape、ランダム化を列挙します。
なお shape 、 size-1 の次元を含んでおり、
以下の表の最終行に示されているように、入力の次元に合わせて展開されることに注意してください。
例:
外因性の入力 | 形 | 結果 |
|---|---|---|
| (10,) | (10,) | 10種類の構成、それぞれ1回の無作為化 |
| (10,) | (5, 10) | 10種類の構成、それぞれ5つのランダム化 |
| (10,) | (2, 3, 10) | 10通りの構成、それぞれ2×3=6通りのランダム化 |
| (4, 1) | (4, 5) | 4つの構成、各構成につき5つのランダム化 |
| (4, 3) | (2, 4, 3) | 4×3=12通りの組み合わせ、それぞれに2つの無作為化 |
| (4, 3) | (2, 1, 3) | 4×3=12通りの組み合わせ、それぞれ2通りのランダム化(1が4に展開される) |
検索結果へ
ランダム化軸を使用すると、特定のランダム化とパラメータの組み合わせを指定することができます:
# Using shape=(2, 14, 10) with input extrinsic shape (10,), and
# 1024 shots and 4 classical registers.
result = executor.run(program).result()
meas_data = result[0]["meas"] # shape (2, 14, 10, 1024, 4)
# Get all shots for randomization (0, 7) and parameter config 3
specific = meas_data[0, 7, 3, :, :] # shape (1024, 4)
# Average over all randomizations for parameter config 5 on bit 2
averaged = meas_data[:, :, 5, :, 2].mean(axis=(0, 1))よくあるパターン
単一のパラメータを一括処理する
他のパラメータを固定したまま、あるパラメータを変化させるには、次のようなコードを使用します:
# Circuit has 2 parameters, sweep first one over 20 values
sweep_values = np.linspace(0, 2*np.pi, 20)
parameter_values = np.column_stack([
sweep_values,
np.full(20, 0.5),
]) # shape (20, 2)2D のグリッドスイープを作成する
3つのパラメータに基づいてグリッドを作成するには:
# Sweep param 0 over 10 values, param 1 over 8 values, param 2 fixed
p0 = np.linspace(0, np.pi, 10)[:, np.newaxis, np.newaxis] # (10, 1, 1)
p1 = np.linspace(0, np.pi, 8)[np.newaxis, :, np.newaxis] # (1, 8, 1)
p2 = np.array([[[0.5]]]) # (1, 1, 1)
parameter_values = np.broadcast_arrays(p0, p1, p2)
parameter_values = np.stack(parameter_values, axis=-1).squeeze() # (10, 8, 3)
# Extrinsic shape: (10, 8), intrinsic shape: (3,)複数の入力を組み合わせる
本質的な形状が異なる入力データを結合する際は、 size-1 の軸を使用して外的な寸法を揃えてください:
# 4 parameter configurations, 3 noise scales → 4×3 = 12 total configurations
parameter_values = np.random.rand(4, 1, 2) # extrinsic (4, 1), intrinsic (2,)
noise_scale = np.array([0.8, 1.0, 1.2]) # extrinsic (3,), intrinsic ()
# Broadcasted extrinsic shape: (4, 3)次のステップ
- 放送の概要を確認してください。
- 実行者の入力と出力を理解する。