주 콘텐츠로 건너뛰기

Qiskit Runtime V2 프리미티브로 마이그레이션

경고

원래 프리미티브(V1 프리미티브), V1 SamplerV1 Estimatorqiskit-ibm-runtime 0.23에서 더 이상 사용되지 않습니다. 지원은 2024년 8월 15일에 제거되었습니다.

V1 프리미티브의 지원 중단으로 모든 코드는 V2 인터페이스를 사용하도록 마이그레이션해야 합니다. 이 가이드는 Qiskit Runtime V2 프리미티브(qiskit-ibm-runtime 0.21.0부터 사용 가능)에서 변경된 사항과 이유를 설명하고, 각 새 프리미티브를 자세히 설명하며, 레거시 프리미티브에서 V2 프리미티브로 코드를 마이그레이션하는 데 도움이 되는 예제를 제공합니다. 가이드의 예제는 모두 Qiskit Runtime 프리미티브를 사용하지만, 일반적으로 동일한 변경 사항이 다른 프리미티브 구현에도 적용됩니다. 오류 완화와 같은 Qiskit Runtime 고유 기능은 Qiskit Runtime에서만 제공됩니다.

Qiskit 참조 프리미티브(현재 statevector 프리미티브)의 변경 사항에 대한 정보는 Qiskit 1.0 기능 변경 페이지의 qiskit.primitives 섹션을 참조하세요. V2 프리미티브 참조 구현에 대해서는 StatevectorSamplerStatevectorEstimator를 참조하세요.

개요

프리미티브 V2는 Sampler와 Estimator 모두에 대한 새로운 기본 클래스(BaseSamplerV2BaseEstimatorV2)와 입출력에 대한 새로운 유형과 함께 도입되었습니다.

새 인터페이스를 사용하면 단일 회로와 여러 관측량(Estimator 사용 시) 및 해당 회로에 대한 매개변수 값 세트를 지정할 수 있으므로, 매개변수 값 세트와 관측량에 대한 스윕을 효율적으로 지정할 수 있습니다. 이전에는 결합할 데이터 크기에 맞추기 위해 동일한 회로를 여러 번 지정해야 했습니다. 또한 resilience_level(Estimator 사용 시)을 간단한 조절 수단으로 계속 사용할 수 있지만, V2 프리미티브는 개별 오류 완화/억제 방법을 켜거나 끌 수 있는 유연성을 제공하여 필요에 맞게 사용자 정의할 수 있습니다.

총 작업 실행 시간을 줄이기 위해, V2 프리미티브는 대상 QPU(양자 처리 장치)에서 지원하는 명령을 사용하는 회로와 관측량만 허용합니다. 이러한 회로와 관측량을 ISA(Instruction Set Architecture) 회로 및 관측량이라고 합니다. V2 프리미티브는 레이아웃, 라우팅, 변환 작업을 수행하지 않습니다. 회로 변환 지침은 트랜스파일레이션 문서를 참조하세요.

Sampler V2는 양자 회로 실행에서 출력 레지스터를 샘플링하는 핵심 작업에 집중하도록 간소화되었습니다. 가중치 없이 프로그램이 정의한 유형의 샘플을 반환합니다. 출력 데이터는 프로그램이 정의한 출력 레지스터 이름으로도 분리됩니다. 이 변경으로 고전적 제어 흐름이 있는 회로에 대한 향후 지원이 가능해집니다.

자세한 내용은 EstimatorV2 API 참조SamplerV2 API 참조를 확인하세요.

주요 변경 사항

Import

하위 호환성을 위해 V2 프리미티브를 명시적으로 import해야 합니다. import <primitive>V2 as <primitive> 형식의 지정은 필수는 아니지만, 코드를 V2로 전환하기 쉽게 만들어 줍니다.

경고

V1 프리미티브가 더 이상 지원되지 않으면, import <primitive>는 지정된 프리미티브의 V2 버전을 import하게 됩니다.

from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit_ibm_runtime import SamplerV2 as Sampler

입력과 출력

입력

SamplerV2EstimatorV2 모두 하나 이상의 프리미티브 통합 블록(PUB)을 입력으로 받습니다. 각 PUB는 하나의 회로와 해당 회로에 브로드캐스트되는 데이터를 포함하는 튜플로, 여러 관측량과 매개변수를 포함할 수 있습니다. 각 PUB는 하나의 결과를 반환합니다.

  • Sampler V2 PUB 형식: (<circuit>, <parameter values>, <shots>), 여기서 <parameter values><shots>는 선택 사항입니다.
  • Estimator V2 PUB 형식: (<circuit>, <observables>, <parameter values>, <precision>), 여기서 <parameter values><precision>은 선택 사항입니다. 관측량과 매개변수 값을 결합할 때 Numpy 브로드캐스팅 규칙이 사용됩니다.

추가로 다음과 같은 변경 사항이 있습니다:

  • Estimator V2는 기대값 추정의 목표 정밀도를 지정하는 precision 인수가 run() 메서드에 추가되었습니다.
  • Sampler V2는 run() 메서드에 shots 인수가 있습니다.
예제

run()에서 precision을 사용하는 Estimator V2 예제:

# Estimate expectation values for two PUBs, both with 0.05 precision.
estimator.run([(circuit1, obs_array1), (circuit2, obs_array_2)], precision=0.05)

run()에서 shots를 사용하는 Sampler V2 예제:

# Sample two circuits at 128 shots each.
sampler.run([circuit1, circuit2], shots=128)

# Sample two circuits at different amounts of shots.
# The "None"s are necessary as placeholders
# for the lack of parameter values in this example.
sampler.run([
(circuit1, None, 123),
(circuit2, None, 456),
])

출력

출력은 이제 PubResult 형식입니다. PubResult는 단일 PUB 실행에서 생성된 데이터와 메타데이터입니다.

  • Estimator V2는 계속해서 기대값을 반환합니다.

  • Estimator V2 PubResult의 data 부분에는 기대값과 표준 오차(stds)가 모두 포함됩니다. V1은 메타데이터에서 분산을 반환했습니다.

  • Sampler V2는 V1 인터페이스의 유사 확률 분포 대신 비트 문자열 형태의 샷별 측정값을 반환합니다. 비트 문자열은 측정된 순서를 유지하면서 측정 결과를 보여줍니다.

  • Sampler V2에는 마이그레이션을 돕기 위한 get_counts()와 같은 편의 메서드가 있습니다.

  • Sampler V2 결과 객체는 동적 회로와의 호환성을 위해 입력 회로의 고전 레지스터 이름으로 데이터를 구성합니다. 기본적으로 고전 레지스터 이름은 다음 예제와 같이 meas입니다. 회로를 정의할 때 기본이 아닌 이름으로 하나 이상의 고전 레지스터를 생성한 경우, 해당 이름을 사용하여 결과를 가져옵니다. <circuit_name>.cregs를 실행하여 고전 레지스터 이름을 찾을 수 있습니다. 예: qc.cregs.

    # Define a quantum circuit with 2 qubits
    circuit = QuantumCircuit(2)
    circuit.h(0)
    circuit.cx(0, 1)
    circuit.measure_all()
    circuit.draw()
            ┌───┐      ░ ┌─┐
    q_0: ┤ H ├──■───░─┤M├───
    └───┘┌─┴─┐ ░ └╥┘┌─┐
    q_1: ─────┤ X ├─░──╫─┤M├
    └───┘ ░ ║ └╥┘
    meas: 2/══════════════╩══╩═
    0 1

Estimator 예제 (입력과 출력)

# Estimator V1: Execute 1 circuit with 4 observables
job = estimator_v1.run([circuit] * 4, [obs1, obs2, obs3, obs4])
evs = job.result().values

# Estimator V2: Execute 1 circuit with 4 observables
job = estimator_v2.run([(circuit, [obs1, obs2, obs3, obs4])])
evs = job.result()[0].data.evs

Sampler 예제 (입력과 출력)

  # Sampler V1: Execute 1 circuit with 3 parameter sets
job = sampler_v1.run([circuit] * 3, [vals1, vals2, vals3])
dists = job.result().quasi_dists

# Sampler V2: Executing 1 circuit with 3 parameter sets
job = sampler_v2.run([(circuit, [vals1, vals2, vals3])])
counts = job.result()[0].data.meas.get_counts()

다른 출력 레지스터를 사용하는 예제

from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler

alpha = ClassicalRegister(5, "alpha")
beta = ClassicalRegister(7, "beta")
qreg = QuantumRegister(12)

circuit = QuantumCircuit(qreg, alpha, beta)
circuit.h(0)
circuit.measure(qreg[:5], alpha)
circuit.measure(qreg[5:], beta)

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=12)
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)

sampler = Sampler(backend)
job = sampler.run([isa_circuit])
result = job.result()
# Get results for the first (and only) PUB
pub_result = result[0]
print(f" >> Counts for the alpha output register: {pub_result.data.alpha.get_counts()}")
print(f" >> Counts for the beta output register: {pub_result.data.beta.get_counts()}")

옵션

V2 프리미티브에서 옵션은 다음과 같은 방식으로 다르게 지정됩니다:

  • SamplerV2EstimatorV2는 이제 별도의 옵션 클래스를 가집니다. 프리미티브 초기화 중 또는 이후에 사용 가능한 옵션을 확인하고 옵션 값을 업데이트할 수 있습니다.
  • set_options() 메서드 대신, V2 프리미티브 옵션에는 options 속성에 변경 사항을 적용하는 update() 메서드가 있습니다.
  • 옵션에 대한 값을 지정하지 않으면 Unset이라는 특수 값이 부여되고 서버 기본값이 사용됩니다.
  • V2 프리미티브의 경우 options 속성은 dataclass Python 유형입니다. 내장 asdict 메서드를 사용하여 딕셔너리로 변환할 수 있습니다.

사용 가능한 옵션 목록은 API 참조를 확인하세요.

from dataclasses import asdict
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator

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

# Setting options during primitive initialization
estimator = Estimator(backend, options={"resilience_level": 2})

# Setting options after primitive initialization
# This uses auto complete.
estimator.options.default_shots = 4000
# This does bulk update.
estimator.options.update(default_shots=4000, resilience_level=2)

# Print the dictionary format.
# Server defaults are used for unset options.
print(asdict(estimator.options))
from dataclasses import asdict
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as Sampler

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

# Setting options during primitive initialization
sampler = Sampler(backend, options={"default_shots": 4096})

# Setting options after primitive initialization
# This uses auto complete.
sampler.options.dynamical_decoupling.enable = True
# Turn on gate twirling. Requires qiskit_ibm_runtime 0.23.0 or later.
sampler.options.twirling.enable_gates = True

# This does bulk update. The value for default_shots is overridden if you specify shots with run() or in the PUB.
sampler.options.update(default_shots=1024, dynamical_decoupling={"sequence_type": "XpXm"})

# Print the dictionary format.
# Server defaults are used for unset options.
print(asdict(sampler.options))

오류 완화 및 억제

  • Sampler V2는 후처리 없이 샘플을 반환하므로 resilience level을 지원하지 않습니다.

  • Sampler V2는 optimization_level을 지원하지 않습니다.

  • Estimator V2는 2024년 9월 30일경에 optimization_level 지원을 중단합니다.

  • Estimator V2는 resilience level 3을 지원하지 않습니다. 이는 V1 Estimator의 resilience level 3이 확률적 오류 상쇄(PEC)를 사용하기 때문이며, PEC는 지수적 처리 시간을 대가로 편향 없는 결과를 제공하는 것으로 입증되었습니다. Level 3은 이러한 트레이드오프에 주의를 기울이기 위해 제거되었습니다. 그러나 pec_mitigation 옵션을 지정하여 PEC를 오류 완화 방법으로 계속 사용할 수 있습니다.

  • Estimator V2는 다음 표에 설명된 대로 resilience_level 0-2를 지원합니다. 이러한 옵션은 V1 대응 옵션보다 더 고급입니다. 개별 오류 완화/억제 방법을 명시적으로 켜거나 끌 수도 있습니다.

    Level 1Level 2
    Measurement twirlingMeasurement twirling
    Readout error mitigationReadout error mitigation
    ZNE
from dataclasses import asdict
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator

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

# Setting options during primitive initialization
estimator = Estimator(backend)

# Set resilience_level to 0
estimator.options.resilience_level = 0

# Turn on measurement error mitigation
estimator.options.resilience.measure_mitigation = True
from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(backend)
# Turn on dynamical decoupling with sequence XpXm.
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XpXm"

print(f">> dynamical decoupling sequence to use: {sampler.options.dynamical_decoupling.sequence_type}")

트랜스파일레이션

V2 프리미티브는 특정 백엔드의 명령어 세트 아키텍처(ISA)를 준수하는 회로만 지원합니다. 프리미티브가 레이아웃, 라우팅 및 변환 작업을 수행하지 않으므로, V1의 해당 트랜스파일레이션 옵션은 지원되지 않습니다.

작업 상태

V2 프리미티브에는 BasePrimitiveJob에서 상속하는 새로운 RuntimeJobV2 클래스가 있습니다. 이 새 클래스의 status() 메서드는 Qiskit의 JobStatus 열거형 대신 문자열을 반환합니다. 자세한 내용은 RuntimeJobV2 API 참조를 확인하세요.

job = estimator.run(...)

# check if a job is still running
print(f"Job {job.job_id()} is still running: {job.status() == "RUNNING"}")

Estimator V2로 마이그레이션하는 단계

  1. from qiskit_ibm_runtime import Estimatorfrom qiskit_ibm_runtime import EstimatorV2 as Estimator로 교체하세요.

  2. V2 프리미티브에서 Options 클래스를 사용하지 않으므로 모든 from qiskit_ibm_runtime import Options 문을 제거하세요. 대신 EstimatorV2 클래스를 초기화할 때 딕셔너리로 옵션을 전달하거나(예: estimator = Estimator(backend, options={“dynamical_decoupling”: {“enable”: True}})), 초기화 후에 설정할 수 있습니다:

    estimator = Estimator(backend)
    estimator.options.dynamical_decoupling.enable = True
  3. 모든 지원 옵션을 검토하고 그에 따라 업데이트하세요.

  4. 실행하려는 각 회로를 관측량 및 매개변수 값과 함께 튜플(PUB)로 그룹화하세요. 예를 들어, circuit1observable1parameter_set1로 실행하려면 (circuit1, observable1, parameter_set1)을 사용하세요.

  5. 외적을 적용하려면 관측량 또는 매개변수 세트의 배열을 재구성해야 할 수 있습니다. 예를 들어, 형상 (4, 1)의 관측량 배열과 형상 (1, 6)의 매개변수 세트 배열은 (4, 6) 기대값 결과를 제공합니다. 자세한 내용은 Numpy 브로드캐스팅 규칙을 참조하세요.

  6. 해당 특정 PUB에 대해 원하는 precision을 선택적으로 지정할 수 있습니다.

  7. PUB 목록을 전달하도록 estimator run() 메서드를 업데이트하세요. 예: run([(circuit1, observable1, parameter_set1)]). 여기서 선택적으로 precision을 지정할 수 있으며, 이는 모든 PUB에 적용됩니다.

  8. Estimator V2 작업 결과는 PUB별로 그룹화됩니다. 인덱싱하여 각 PUB의 기대값과 표준 오차를 확인할 수 있습니다. 예:

pub_result = job.result()[0]
print(f">>> Expectation values: {pub_result.data.evs}")
print(f">>> Standard errors: {pub_result.data.stds}")

Estimator 전체 예제

단일 실험 실행

Estimator를 사용하여 단일 회로-관측량 쌍의 기대값을 결정합니다.

import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import SparsePauliOp, random_hermitian
from qiskit_ibm_runtime import EstimatorV2 as Estimator, QiskitRuntimeService

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

n_qubits = 127

mat = np.real(random_hermitian(n_qubits, seed=1234))
circuit = IQP(mat)
observable = SparsePauliOp("Z" * n_qubits)

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)

job = estimator.run([(isa_circuit, isa_observable)])
result = job.result()

print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")

단일 작업에서 여러 실험 실행

Estimator를 사용하여 여러 회로-관측량 쌍의 기대값을 결정합니다.

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

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)

n_qubits = 3
rng = np.random.default_rng()
mats = [np.real(random_hermitian(n_qubits, seed=rng)) for _ in range(3)]
circuits = [IQP(mat) for mat in mats]
observables = [
SparsePauliOp("X" * n_qubits),
SparsePauliOp("Y" * n_qubits),
SparsePauliOp("Z" * n_qubits),
]

isa_circuits = pm.run(circuits)
isa_observables = [ob.apply_layout(isa_circuits[0].layout) for ob in observables]

estimator = Estimator(backend)
job = estimator.run([(isa_circuits[0], isa_observables[0]),(isa_circuits[1], isa_observables[1]),(isa_circuits[2], isa_observables[2])])
job_result = job.result()
for idx in range(len(job_result)):
pub_result = job_result[idx]
print(f">>> Expectation values for PUB {idx}: {pub_result.data.evs}")
print(f">>> Standard errors for PUB {idx}: {pub_result.data.stds}")

매개변수화된 회로 실행

Estimator를 사용하여 매개변수 값을 활용해 회로 재사용성을 높이면서 단일 작업에서 여러 실험을 실행합니다. 다음 예제에서 1단계와 2단계는 V1과 V2가 동일합니다.

import numpy as np

from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService

# Step 1: Map classical inputs to a quantum problem

theta = Parameter("θ")

chsh_circuit = QuantumCircuit(2)
chsh_circuit.h(0)
chsh_circuit.cx(0, 1)
chsh_circuit.ry(theta, 0)

number_of_phases = 21
phases = np.linspace(0, 2 * np.pi, number_of_phases)
individual_phases = [[ph] for ph in phases]

ZZ = SparsePauliOp.from_list([("ZZ", 1)])
ZX = SparsePauliOp.from_list([("ZX", 1)])
XZ = SparsePauliOp.from_list([("XZ", 1)])
XX = SparsePauliOp.from_list([("XX", 1)])
ops = [ZZ, ZX, XZ, XX]

# Step 2: Optimize problem for quantum execution.

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

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
chsh_isa_circuit = pm.run(chsh_circuit)
isa_observables = [operator.apply_layout(chsh_isa_circuit.layout) for operator in ops]

from qiskit_ibm_runtime import EstimatorV2 as Estimator

# Step 3: Execute using Qiskit primitives.

# Reshape observable array for broadcasting
reshaped_ops = np.fromiter(isa_observables, dtype=object)
reshaped_ops = reshaped_ops.reshape((4, 1))

estimator = Estimator(backend, options={"default_shots": int(1e4)})
job = estimator.run([(chsh_isa_circuit, reshaped_ops, individual_phases)])
# Get results for the first (and only) PUB
pub_result = job.result()[0]
print(f">>> Expectation values: {pub_result.data.evs}")
print(f">>> Standard errors: {pub_result.data.stds}")
print(f">>> Metadata: {pub_result.metadata}")

세션 및 고급 옵션 사용

QPU에서 회로 성능을 최적화하기 위해 세션과 고급 옵션을 살펴봅니다.

주의

다음 코드 블록은 세션을 사용하므로 Open Plan 사용자에게 오류를 반환합니다. Open Plan의 워크로드는 작업 모드 또는 배치 모드에서만 실행할 수 있습니다.

import numpy as np
from qiskit.circuit.library import IQP
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp, random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, Session, EstimatorV2 as Estimator

n_qubits = 127

rng = np.random.default_rng(1234)
mat = np.real(random_hermitian(n_qubits, seed=rng))
circuit = IQP(mat)
mat = np.real(random_hermitian(n_qubits, seed=rng))
another_circuit = IQP(mat)
observable = SparsePauliOp("X" * n_qubits)
another_observable = SparsePauliOp("Y" * n_qubits)

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
another_isa_circuit = pm.run(another_circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
another_isa_observable = another_observable.apply_layout(another_isa_circuit.layout)

service = QiskitRuntimeService()

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

with Session(backend=backend) as session:
estimator = Estimator()

estimator.options.resilience_level = 1

job = estimator.run([(isa_circuit, isa_observable)])
another_job = estimator.run([(another_isa_circuit, another_isa_observable)])
result = job.result()
another_result = another_job.result()

# first job
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")

# second job
print(f" > Another Expectation value: {another_result[0].data.evs}")
print(f" > More Metadata: {another_result[0].metadata}")

Sampler V2로 마이그레이션하는 단계

  1. from qiskit_ibm_runtime import Samplerfrom qiskit_ibm_runtime import SamplerV2 as Sampler로 교체하세요.
  2. V2 프리미티브에서 Options 클래스를 사용하지 않으므로 모든 from qiskit_ibm_runtime import Options 문을 제거하세요. 대신 SamplerV2 클래스를 초기화할 때 딕셔너리로 옵션을 전달하거나(예: sampler = Sampler(backend, options={“default_shots”: 1024})), 초기화 후에 설정할 수 있습니다:
    sampler = Sampler(backend)
    sampler.options.default_shots = 1024
  3. 모든 지원 옵션을 검토하고 그에 따라 업데이트하세요.
  4. 실행하려는 각 회로를 매개변수 값과 함께 튜플(PUB)로 그룹화하세요. 예를 들어, circuit1parameter_set1로 실행하려면 (circuit1, parameter_set1)을 사용하세요. 해당 특정 PUB에 대해 원하는 shots를 선택적으로 지정할 수 있습니다.
  5. PUB 목록을 전달하도록 sampler run() 메서드를 업데이트하세요. 예: run([(circuit1, parameter_set1)]). 여기서 선택적으로 shots를 지정할 수 있으며, 이는 모든 PUB에 적용됩니다.
  6. Sampler V2 작업 결과는 PUB별로 그룹화됩니다. 인덱싱하여 각 PUB의 출력 데이터를 확인할 수 있습니다. Sampler V2는 가중치 없는 샘플을 반환하지만, 결과 클래스에는 대신 카운트를 가져올 수 있는 편의 메서드가 있습니다. 예:
pub_result = job.result()[0]
print(f">>> Counts: {pub_result.data.meas.get_counts()}")
print(f">>> Per-shot measurement: {pub_result.data.meas.get_counts()}")
참고

결과를 가져오려면 고전 레지스터 이름이 필요합니다. 기본적으로 measure_all()을 사용하면 meas라는 이름이 지정됩니다. 회로를 정의할 때 기본이 아닌 이름으로 하나 이상의 고전 레지스터를 생성한 경우, 해당 이름을 사용하여 결과를 가져옵니다. <circuit_name>.cregs를 실행하여 고전 레지스터 이름을 찾을 수 있습니다. 예: qc.cregs.

Sampler 전체 예제

단일 실험 실행

Sampler를 사용하여 단일 회로의 카운트 또는 유사 확률 분포를 결정합니다.

import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

service = QiskitRuntimeService()

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

n_qubits = 127

mat = np.real(random_hermitian(n_qubits, seed=1234))
circuit = IQP(mat)
circuit.measure_all()

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)

sampler = Sampler(backend)
job = sampler.run([isa_circuit])
result = job.result()

단일 작업에서 여러 실험 실행

Sampler를 사용하여 하나의 작업에서 여러 회로의 카운트 또는 유사 확률 분포를 결정합니다.

import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler

service = QiskitRuntimeService()

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

n_qubits = 127

rng = np.random.default_rng()
mats = [np.real(random_hermitian(n_qubits, seed=rng)) for _ in range(3)]
circuits = [IQP(mat) for mat in mats]
for circuit in circuits:
circuit.measure_all()

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuits = pm.run(circuits)

sampler = Sampler(backend)
job = sampler.run(isa_circuits)
result = job.result()

for idx, pub_result in enumerate(result):
print(f" > Counts for pub {idx}: {pub_result.data.meas.get_counts()}")

매개변수화된 회로 실행

매개변수 값을 활용해 회로 재사용성을 높이면서 단일 작업에서 여러 실험을 실행합니다.

import numpy as np
from qiskit.circuit.library import RealAmplitudes
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService

# Step 1: Map classical inputs to a quantum problem
num_qubits = 127
circuit = RealAmplitudes(num_qubits=num_qubits, reps=2)
circuit.measure_all()

# Define three sets of parameters for the circuit
rng = np.random.default_rng(1234)
parameter_values = [
rng.uniform(-np.pi, np.pi, size=circuit.num_parameters) for _ in range(3)
]

# Step 2: Optimize problem for quantum execution.

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

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)

# Step 3: Execute using Qiskit primitives.

from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(backend)
job = sampler.run([(isa_circuit, parameter_values)])
result = job.result()
# Get results for the first (and only) PUB
pub_result = result[0]
# Get counts from the classical register "meas".
print(f" >> Counts for the meas output register: {pub_result.data.meas.get_counts()}")

세션 및 고급 옵션 사용

QPU에서 회로 성능을 최적화하기 위해 세션과 고급 옵션을 살펴봅니다.

주의

다음 코드 블록은 세션을 사용하므로 Open Plan 사용자에게 오류를 반환합니다. Open Plan의 워크로드는 작업 모드 또는 배치 모드에서만 실행할 수 있습니다.

import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler, Session

n_qubits = 127

rng = np.random.default_rng(1234)
mat = np.real(random_hermitian(n_qubits, seed=rng))
circuit = IQP(mat)
circuit.measure_all()
mat = np.real(random_hermitian(n_qubits, seed=rng))
another_circuit = IQP(mat)
another_circuit.measure_all()

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
another_isa_circuit = pm.run(another_circuit)

service = QiskitRuntimeService()

# Turn on dynamical decoupling with sequence XpXm.
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XpXm"

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

with Session(backend=backend) as session:
sampler = Sampler()
job = sampler.run([isa_circuit])
another_job = sampler.run([another_isa_circuit])
result = job.result()
another_result = another_job.result()

# first job
print(f" > Counts for job 1: {result[0].data.meas.get_counts()}")

# second job
print(f" > Counts for job 2: {another_result[0].data.meas.get_counts()}")

다음 단계

권장 사항