Executor 예제
패키지 버전
이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다. 이 버전 이상을 사용하는 것을 권장합니다.
qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.21.0
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime samplomatic
이 섹션의 예제들은 Executor 프리미티브를 사용하는 몇 가지 일반적인 방법을 보여줍니다. 이 예제들을 실행하기 전에 Qiskit 설치 및 Executor 퀵스타트의 지침을 따르세요.
시작하기 전에
이 페이지의 일부 코드 예제는 Samplomatic 패키지의 일부인 samplex를 사용합니다. 따라서 해당 코드 블록을 실행하기 전에 다음 코드 블록에 표시된 대로 Samplomatic을 설치해야 합니다. 자세한 내용은 Samplomatic 문서를 참조하세요.
pip install samplomatic
# For visualization support, include the visualization dependencies.
# pip install samplomatic[vis]
예제: 파라미터화된 circuit
이 예제는 파라미터가 있는 circuit 항목을 추가하는 방법과 samplex 항목을 추가하는 방법을 보여줍니다. 다음 단계로 구성됩니다:
- circuit 설정: 대상 circuit을 생성하고 트랜스파일합니다.
- samplex 준비: 게이트와 측정을 주석이 달린 박스로 그룹화하고 circuit 템플릿과 samplex 쌍을 생성합니다.
- 실행:
QuantumProgram에 circuit 항목과 samplex 항목을 추가하고 단일 작업으로 둘 다 실행합니다.
circuit 설정
3-qubit GHZ 상태를 준비하고, qubit들을 Pauli-Z 축 주위로 회전시키고, 계산 기저에서 qubit들을 측정합니다.
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가 지원하는 명령어만 사용하도록 circuit을 트랜스파일합니다 (명령어 집합 아키텍처 (ISA) circuit이라고 함).
# 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)
samplex 준비
generate_boxing_pass_manager 편의 함수와 그 twirling 파라미터를 사용하여 2-qubit 게이트와 측정을 박스로 그룹화하고 twirling 주석을 적용합니다.
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 메서드를 사용하여 템플릿 circuit과 samplex를 생성합니다.
# Build the template circuit and the samplex
template_circuit, samplex = build(boxed_circuit)
circuit 실행
Executor는 QuantumProgram 객체를 실행합니다. 각 QuantumProgram은 여러 항목을 포함할 수 있습니다. 이 예제는 실행을 위해 Circuit 항목과 samplex 항목을 추가합니다. 자세한 내용은 Executor 입력 및 출력을 참조하세요.
첫 번째 단계는 빈 프로그램을 초기화하고, 각 항목의 각 구성에 대해 1024 shots을 요청하는 것입니다.
# Generate a quantum program
program = QuantumProgram(shots=1024)
QuantumProgram에 circuit 항목을 추가합니다. 이 circuit 항목은 두 부분으로 구성됩니다 - ISA circuit과 10세트의 파라미터 값.
# 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함수로 생성된 템플릿 circuit과 samplex- 원래 circuit의 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),
)
Executor 작업 실행
# 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개의 qubit과 두 개의 고유한 CX 게이트 레이어를 가진 circuit의 미러 버전을 고려해 보세요. 다음이 주요 작업입니다:
- twirling을 적용하여 circuit을 실행합니다.
- 논문 "Probabilistic error cancellation with sparse Pauli-Lindblad models on noisy quantum processors"에서와 같이 PEC 완화를 적용하여 circuit을 실행합니다.
파이프라인은 다음 단계로 구성됩니다:
- 설정: 대상 circuit을 생성하고 그 연산들을 박스로 그룹화합니다.
- 학습: PEC로 완화하려는 명령어의 노이즈를 학습합니다.
- 실행: 백엔드에서 circuit을 실행합니다.
- 분석: 결과를 후처리하고 분석합니다.
비교를 위해 이 미러 circuit을 두 번 실행합니다. 한 번은 Pauli-twirling만 적용하고, 한 번은 PEC 완화를 적용합니다.
이 예제의 사용량은 Heron r2 프로세서에서 약 10분입니다.
circuit 설정
백엔드를 선택하고 10-qubit circuit을 준비합니다.
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)
circuit과 그 역을 결합하여 미러 circuit을 만듭니다.
mirror_circuit = circuit.compose(circuit.inverse())
mirror_circuit.measure_all()
mirror_circuit.draw("mpl", scale=0.35, fold=100)
일부 파라미터 값을 설정합니다:
import numpy as np
parameter_values = np.random.rand(mirror_circuit.num_parameters)
패스 매니저를 사용하여 circuit을 ISA circuit으로 트랜스파일합니다.
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 함수를 편의상 사용할 수 있습니다. 첫 번째 circuit은 twirling만 적용되므로 Twirl 주석만 필요합니다. 두 번째 circuit은 전체 PEC 완화로 실행되며 Twirl과 InjectNoise 주석이 모두 필요합니다.
# 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)
노이즈 학습
노이즈 학습 실험의 수를 최소화하기 위해 두 번째 circuit (InjectNoise로 주석이 달린 박스가 있는 것)의 고유한 명령어를 식별합니다. 고유성을 정의할 때, 두 박스 명령어는 다음 두 가지가 모두 참인 경우 동일합니다:
- 내용이 단일 qubit 게이트까지 동일합니다.
Twirl주석이 동일합니다 (다른 모든 주석은 무시됩니다).
이로 인해 홀수 및 짝수 게이트 박스와 최종 측정 박스의 세 가지 고유한 명령어가 생성됩니다.
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 메서드를 사용하여 result를 samplex가 필요로 하는 객체로 변환합니다.
noise_maps = learner_result.to_dict(
instructions=unique_box_instructions, require_refs=False
)
circuit 실행
Executor는 QuantumProgram 객체를 실행합니다. 각 QuantumProgram은 프로그램에 추가되는 여러 항목을 포함할 수 있습니다. 각 항목은 프로그램이 수행할 작업입니다.
빈 프로그램을 초기화하고 각 항목의 각 구성에 대해 1000 shots을 요청합니다.
from qiskit_ibm_runtime.quantum_program import QuantumProgram
# Initialize an empty QuantumProgram
program = QuantumProgram(shots=1000)
다음으로 mirror_circuit_twirl에 대한 템플릿 circuit과 samplex를 빌드하고 프로그램에 추가합니다. 또한 samplex에서 900번의 랜덤화를 요청합니다. 이는 samplex가 900세트의 파라미터를 생성하고 각 세트가 QPU에서 1000번 (shots 수) 실행된다는 의미입니다.
이것이 프로그램의 첫 번째 작업 (결과 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에 대한 템플릿 circuit과 samplex를 추가하고 900번의 랜덤화를 요청합니다. 이것이 프로그램의 두 번째 작업 (결과 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}")
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)
결과 분석
마지막으로 10개의 활성 qubit 각각에 작용하는 단일 qubit Pauli-Z 연산자의 기댓값 (기대값: 1.0)을 추정하기 위해 결과를 후처리합니다.
# 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)}")
Qubit 0 -> 0.71
Qubit 1 -> 0.72
Qubit 2 -> 0.7
Qubit 3 -> 0.68
Qubit 4 -> 0.65
Qubit 5 -> 0.64
Qubit 6 -> 0.62
Qubit 7 -> 0.66
Qubit 8 -> 0.69
Qubit 9 -> 0.75
# 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)}")
Qubit 0 -> 0.98
Qubit 1 -> 1.0
Qubit 2 -> 0.99
Qubit 3 -> 0.97
Qubit 4 -> 0.97
Qubit 5 -> 0.97
Qubit 6 -> 0.96
Qubit 7 -> 0.97
Qubit 8 -> 0.97
Qubit 9 -> 0.98
다음 단계
- 브로드캐스팅 개요를 검토합니다.
- Executor 옵션 사용 방법을 알아봅니다.
- directed execution model을 이해합니다.
- Samplomatic 문서를 검토합니다.
- directed execution model을 사용할 때 다양한 오류 완화 기술을 결합하는 방법을 Probabilistic error cancellation with shaded lightcones 튜토리얼에서 알아봅니다.