Skip to main content
IBM Quantum Platform

実行者の例

  • このページのコードは、以下の要件に基づいて開発されました。 これらのバージョン以降のご利用をお勧めします。

    qiskit[all]~=2.4.0
    qiskit-ibm-runtime~=0.46.1
    samplomatic~=0.18.0
    

このセクションの例では、Executorプリミティブの一般的な使用方法をいくつか紹介します。 これらの例を実行する前に、 「QiskitExecutor のクイックスタート 」の手順に従ってください。


開始前に

samplexこのページにあるコード例の一部では、Samplomatic パッケージに含まれる を使用しています。 したがって、これらのコードブロックを実行する前に、次のコードブロックに示すように、Samplomaticをインストールする必要があります。 詳細については、 Samplomaticのドキュメントを参照してください。

pip install samplomatic

# For visualization support, include the visualization dependencies.
# pip install samplomatic[vis]

例:パラメータ化された回路

この例では、パラメータ付き回路アイテムの追加方法と、サンプレックス・アイテムの追加方法について説明します。 手順は以下の通りです:

  1. 回路の設定:ターゲット回路を生成し、トランスパイルします。
  2. サンプレックスの準備:ゲートと測定項目を注釈付きのボックスにまとめ、回路テンプレートとサンプレックスのペアを生成します。
  3. 実行:回路アイテムとサンプレックスアイテムを へ追加し、 QuantumProgram 両方を単一のジョブで実行します。

回路を組み立てる

3量子ビットのGHZ状態を準備し、量子ビットをパウリZ軸を中心に回転させ、計算基底で量子ビットを測定する。

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
import numpy as np
from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager

# Generate the circuit
circuit = QuantumCircuit(3)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.h(2)
circuit.cz(1, 2)
circuit.h(2)
circuit.rz(Parameter("theta"), 0)
circuit.rz(Parameter("phi"), 1)
circuit.rz(Parameter("lam"), 2)
circuit.measure_all()

バックエンドを指定し、QPUがサポートする命令のみを使用するように回路をトランスパイルします(これは命令セットアーキテクチャ(ISA)回路と呼ばれます)。

# Initialize the service and choose a backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Transpile the circuit to ISA
preset_pass_manager = generate_preset_pass_manager(
    backend=backend, optimization_level=3
)
isa_circuit = preset_pass_manager.run(circuit)

サンプレックスの準備をする

便利関数 generate_boxing_pass_manager とそのツイリングパラメータを使用して、2量子ビットゲートと測定をボックスにまとめ、ツイリング注釈を適用します。

boxing_pm = generate_boxing_pass_manager(
    # Add gate twirling
    enable_gates=True,
    # Add measurement twirling
    enable_measures=True,
)

boxed_circuit = boxing_pm.run(isa_circuit)

この build メソッドを使用して、テンプレート回路とサンプルを生成します。

# Build the template circuit and the samplex
template_circuit, samplex = build(boxed_circuit)

サーキットトレーニングを行う

Executorはオブジェクトを実行します QuantumProgram 。 それぞれ QuantumProgram に複数の項目を含めることができます。 この例では、実行用の回路項目とサンプレックス項目を追加します。 詳細については、 「Executorの入力と出力」 を参照してください。

まず、各アイテムの各設定についてショットを要求する 1024 、空のプログラムを初期化します。

# Generate a quantum program
program = QuantumProgram(shots=1024)

QuantumProgram回路項目を.に追加する。 この回路アイテムは、ISA回路と、そのパラメータ値10セットの2つの部分で構成されています。

# Append the circuit and the parameter values to the program
program.append_circuit_item(
    isa_circuit,
    circuit_arguments=np.random.rand(10, 3),  # 10 sets of parameter values
)

samplex 項目を、以下の引数とともに に QuantumProgram 追加してください:

  • テンプレート回路と、関数 build によって生成されたサンプレックス
  • 元の回路のパラメータ値の10組
  • 実行する無作為化の回数
# Append the template circuit and samplex as a samplex item
program.append_samplex_item(
    template_circuit,
    samplex=samplex,
    samplex_arguments={
        "parameter_values": np.random.rand(
            10, 3
        ),  # 10 sets of parameter values
    },
    shape=(2, 14, 10),
)

エグゼキュータ・ジョブを実行する

# initialize an Executor with default options
executor = Executor(mode=backend)

# Submit the job
job = executor.run(program)

# Retrieve the result
result = job.result()

各タスクの結果を取得します。

# Access the results of the classical register of task #0, the CircuitItem
result_0 = result[0]["meas"]

# Access the results of the classical register of task #1, the SamplexItem
result_1 = result[1]["meas"]

例:PECを実行する

この例では、samplex アイテムを使用して、誤差低減のための確率的誤差相殺( PEC )を行う方法を示します。

10個の量子ビットと2つの異なる層からなるCXゲートを持つ回路の対称配置について考えてみよう。 主な業務内容は以下の通りです:

このパイプラインは、以下のステップで構成されています:

  1. 設定:対象回路を生成し、その演算をボックスにグループ化する。
  2. 学習:PECを用いて低減したい指令のノイズを学習します。
  3. 実行:バックエンド上で回路を実行する。
  4. 分析:結果の後処理と分析を行う。

比較のために、このミラー回路を2回実行します。 1回目はパウリ回転のみを適用した場合、もう1回はPEC緩和を適用した場合。

Note

この例の処理時間は、Heron r2 プロセッサ上で約10分です。

回路を組み立てる

バックエンドを選択し、10キュービットの回路を準備してください。

from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.transpiler import generate_preset_pass_manager
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic import build

# Initialize the service and choose a backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Prepare a circuit

num_qubits = 10
num_layers = 10

qubits = list(range(num_qubits))
circuit = QuantumCircuit(num_qubits)

for layer_idx in range(num_layers):
    circuit.rx(Parameter(f"theta_{layer_idx}"), qubits)
    for i in range(num_qubits // 2):
        circuit.cz(qubits[2 * i], qubits[2 * i + 1])

    circuit.rx(Parameter(f"phi_{layer_idx}"), qubits)
    for i in range(num_qubits // 2 - 1):
        circuit.cz(qubits[2 * i] + 1, qubits[2 * i + 1] + 1)

circuit.draw("mpl", scale=0.35, fold=100)

Output:

Output of the previous code cell

回路とその逆回路を組み合わせると、鏡像回路が得られます。

mirror_circuit = circuit.compose(circuit.inverse())
mirror_circuit.measure_all()

mirror_circuit.draw("mpl", scale=0.35, fold=100)

Output:

Output of the previous code cell

いくつかのパラメータ値を設定します:

import numpy as np

parameter_values = np.random.rand(mirror_circuit.num_parameters)

パスマネージャーを使用して、回路をトランスパイルし、ISA回路に変換します。

preset_pass_manager = generate_preset_pass_manager(
    backend=backend,
    optimization_level=3,
)

isa_circuit = preset_pass_manager.run(mirror_circuit)

次に、ゲートと測定値を注釈付きボックスにグループ化します。 手動で行うこともできますが、より手軽に処理したい場合は、Samplomaticの関数 generate_boxing_pass_manager を利用することもできます。 最初の回路には回転処理のみが適用されるため、必要なのは 注釈のみです Twirl 。 2番目のループは、PECの緩和策をすべて適用して実行され、および InjectNoise の両 Twirl 方の注釈が必要です。

# Pass manager used to create twirled-annotated boxes.
boxing_pm = generate_boxing_pass_manager(
    enable_gates=True,
    enable_measures=True,
)

mirror_circuit_twirl = boxing_pm.run(isa_circuit)

# Pass manager used to create a new boxed circuit with
# both Twirl and InjectNoise annotations.
boxing_pm = generate_boxing_pass_manager(
    enable_gates=True,
    enable_measures=True,
    inject_noise_targets="gates",  # no measurement mitigation
    inject_noise_strategy="uniform_modification",
)

mirror_circuit_pec = boxing_pm.run(isa_circuit)

ノイズについて学ぶ

InjectNoiseノイズ学習の実験回数を最小限に抑えるため、2番目の回路(に注釈が付けられたボックスがある回路)に含まれる固有の命令を特定してください。 一意性を定義するにあたり、以下の2つの条件の両方が満たされる場合、2つのボックス命令は等しいとみなされます:

  • 1量子ビットゲートに至るまで、その内容は同等です。
  • それらの Twirl 注釈は等しい(それ以外の注釈はすべて無視される)。

これにより、3つの独自の指示、すなわち「奇数・偶数ゲートボックス」と「最終測定ボックス」が導き出されます。

from samplomatic.utils import find_unique_box_instructions

unique_box_instructions = find_unique_box_instructions(
    mirror_circuit_pec.data
)
assert len(unique_box_instructions) == 3

NoiseLearnerV3を初期化し、オプションを設定して学習パラメータを選択し、ノイズ学習ジョブを実行します。

from qiskit_ibm_runtime.noise_learner_v3 import NoiseLearnerV3

learner = NoiseLearnerV3(backend)

learner.options.shots_per_randomization = 128
learner.options.num_randomizations = 32
learner.options.layer_pair_depths = [0, 1, 2, 4, 16, 32]

learner_job = learner.run(unique_box_instructions)

learner_job.job_id()
learner_result = learner_job.result()

メソッド result.to_dict を使用して、samplexが必要とするオブジェクトに変換 result します。

noise_maps = learner_result.to_dict(
    instructions=unique_box_instructions, require_refs=False
)

サーキットトレーニングを行う

Executor オブジェクトを実行します QuantumProgram 。 それぞれ QuantumProgram には複数の項目を含めることができ、それらはプログラムに追加されます。 各項目は、プログラムが実行すべきタスクです。

空のプログラムを初期化し、各項目の各設定についてショットを要求 1000 します。

from qiskit_ibm_runtime.quantum_program import QuantumProgram

# Initialize an empty QuantumProgram
program = QuantumProgram(shots=1000)

次に、テンプレート回路とsamplexを作成し、 mirror_circuit_twirl それらをプログラムに追加してください。 また、samplex からランダム化データも要求 900 してください。 つまり、このサンプレックスはパラメータのセットを生成 900 し、各セットはQPU上で(ショット数に相当する)回実行 1000 されます。

これがこのプログラムの最初のタスクです(結果 0)。

template_twirl, samplex_twirl = build(mirror_circuit_twirl)

program.append_samplex_item(
    template_twirl,
    samplex=samplex_twirl,
    samplex_arguments={"parameter_values": parameter_values},
    shape=(900,),
)

mirror_circuit_pec同様に、のために作成されたテンプレート回路とsamplexを追加し、ランダム化を要求 900 します。 これはこのプログラムの2番目のタスクです(結果1)。

template_pec, samplex_pec = build(mirror_circuit_pec)

program.append_samplex_item(
    template_pec,
    samplex=samplex_pec,
    samplex_arguments={
        "parameter_values": parameter_values,
        "pauli_lindblad_maps": noise_maps,
        "noise_scales": {
            ref: -1.0 for ref in noise_maps
        },  # Set the scales to -1 for PEC
    },
    shape=(900,),
)

ジョブをインポート Executor して送信します。

from qiskit_ibm_runtime.executor import Executor

executor = Executor(backend)
executor_job = executor.run(program)

executor_job.job_id()

executor_results = executor_job.result()
executor_results

twirl_result = executor_results[0]

print(f"Twirl result keys:\n {list(twirl_result.keys())}\n")
print(f"Shape of results: {twirl_result['meas'].shape}")

pec_result = executor_results[1]

print(f"PEC result keys:\n {list(pec_result.keys())}\n")
print(f"Shape of results: {pec_result['meas'].shape}")

Output:

Twirl result keys:
 ['meas', 'measurement_flips.meas']

Shape of results: (900, 1000, 10)
PEC result keys:
 ['meas', 'measurement_flips.meas', 'pauli_signs']

Shape of results: (900, 1000, 10)

結果を分析する

1.0最後に、結果の後処理を行い、10個のアクティブな量子ビットのそれぞれに作用する単一量子ビットのパウリZ演算子の期待値を推定する(期待値:)。

# Undo measurement twirling
twirl_result_unflipped = (
    twirl_result["meas"] ^ twirl_result["measurement_flips.meas"]
)

# Calculate the expectation values of single-qubit Z operators
exp_vals = 1 - 2 * twirl_result_unflipped.mean(axis=1).mean(axis=0)

for qubit, val in enumerate(exp_vals):
    print(f"Qubit {qubit} -> {np.round(val, 2)}")

Output:

Qubit 0 -> 0.77
Qubit 1 -> 0.76
Qubit 2 -> 0.66
Qubit 3 -> 0.71
Qubit 4 -> 0.69
Qubit 5 -> 0.67
Qubit 6 -> 0.62
Qubit 7 -> 0.59
Qubit 8 -> 0.62
Qubit 9 -> 0.68
# Undo measurement twirling
pec_result_unflipped = (
    pec_result["meas"] ^ pec_result["measurement_flips.meas"]
)

# Calculate the signs for PEC mitigation
signs = np.prod((-1) ** pec_result["pauli_signs"], axis=-1)
signs = signs.reshape((signs.shape[0], 1))

# Calculate the expectation values of single-qubit Z operators as required by
# PEC mitigation
exp_vals = 1 - (2 * pec_result_unflipped.mean(axis=1) * signs).mean(axis=0)

for qubit, val in enumerate(exp_vals):
    print(f"Qubit {qubit} -> {np.round(val, 2)}")

Output:

Qubit 0 -> 0.98
Qubit 1 -> 0.99
Qubit 2 -> 0.96
Qubit 3 -> 0.98
Qubit 4 -> 0.98
Qubit 5 -> 0.98
Qubit 6 -> 0.98
Qubit 7 -> 0.95
Qubit 8 -> 0.95
Qubit 9 -> 0.94

次のステップ

推奨事項
このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。