Lumaktaw sa pangunahing nilalaman

Mga Halimbawa ng Executor

Mga bersyon ng package

Ang code sa pahinang ito ay binuo gamit ang mga sumusunod na kinakailangan. Inirerekomenda naming gamitin ang mga bersyong ito o mas bago.

qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
samplomatic~=0.18.0
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime samplomatic

Ang mga halimbawa sa seksyong ito ay naglalarawan ng ilang karaniwang paraan ng paggamit ng Executor primitive. Bago patakbuhin ang mga halimbawang ito, sundin ang mga tagubilin sa I-install ang Qiskit at Executor quickstart.

Bago ka magsimula

Ang ilang mga halimbawa ng code sa pahinang ito ay gumagamit ng samplex, na bahagi ng Samplomatic package. Samakatuwid, bago patakbuhin ang mga code block na iyon, kailangan mong i-install ang Samplomatic, tulad ng ipinapakita sa sumusunod na code block. Para sa karagdagang impormasyon, tingnan ang dokumentasyon ng Samplomatic.

pip install samplomatic

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

Halimbawa: Parameterized circuit

Ipinapakita ng halimbawang ito kung paano magdagdag ng mga circuit item na may mga parameter, pati na rin kung paano magdagdag ng mga samplex item. Binubuo ito ng mga hakbang na ito:

  1. I-set up ang circuit: Bumuo at mag-transpile ng target circuit.
  2. Ihanda ang samplex: I-grupo ang mga gate at sukat sa mga annotated box at bumuo ng pares ng circuit template at samplex.
  3. Isabuhay: Magdagdag ng circuit item at samplex item sa isang QuantumProgram at sabay na patakbuhin ang dalawa sa isang trabaho.

I-set up ang circuit

Maghanda ng 3-qubit GHZ state, i-rotate ang mga qubit sa paligid ng Pauli-Z axis, at sukatin ang mga qubit sa computational basis.

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()

Tukuyin ang backend at i-transpile ang circuit upang gumamit lamang ng mga tagubilin na sinusuportahan ng QPU (tinutukoy bilang isang instruction set architecture (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)

Ihanda ang samplex

Gamitin ang convenience function na generate_boxing_pass_manager at ang mga twirling parameter nito upang i-grupo ang mga two-qubit gate at sukat sa mga box at mag-apply ng mga twirling annotation.

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)

Gamitin ang pamamaraan ng build upang bumuo ng template circuit at samplex.

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

Isabuhay ang mga circuit

Ang Executor ay nagpapatakbo ng mga bagay na QuantumProgram. Ang bawat QuantumProgram ay maaaring maglaman ng ilang mga item. Ang halimbawang ito ay nagdadagdag ng circuit item at samplex item para sa pagpapatakbo. Para sa buong detalye, tingnan ang Executor input and output.

Ang unang hakbang ay ang mag-initialize ng walang laman na programa, na humihiling ng 1024 shots para sa bawat configuration ng bawat item.

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

I-append ang circuit item sa QuantumProgram. Ang circuit item na ito ay binubuo ng dalawang bahagi - ang ISA circuit at 10 set ng mga halaga ng parameter nito.

# 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
)

I-append ang samplex item sa QuantumProgram gamit ang mga argumentong ito:

  • Ang template circuit at samplex na nabuo ng function na build
  • Sampung set ng mga halaga ng parameter para sa orihinal na circuit
  • Ang bilang ng mga randomization na isasagawa
# 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),
)

Patakbuhin ang Executor job

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

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

# Retrieve the result
result = job.result()

Kunin ang resulta para sa bawat task.

# 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"]

Halimbawa: Magsagawa ng PEC

Ipinapakita ng halimbawang ito kung paano gumamit ng samplex item upang magsagawa ng probabilistic error cancellation (PEC) para sa error mitigation.

Isaalang-alang ang isang mirror na bersyon ng isang circuit na may sampung qubit at dalawang natatanging layer ng mga CX gate. Narito ang mga pangunahing gawain:

Ang pipeline ay binubuo ng mga hakbang na ito:

  1. I-set up: Bumuo ng target circuit at i-grupo ang mga operasyon nito sa mga box.
  2. Matuto: Matutunan ang noise ng mga tagubilin na nais naming i-mitigate gamit ang PEC.
  3. Isabuhay: Patakbuhin ang circuit sa isang backend.
  4. Suriin: I-post-process at suriin ang mga resulta.

Para sa paghahambing, patatakbuhin namin ang mirrored circuit na ito nang dalawang beses. Minsan na may Pauli-twirling lamang na inilapat, at minsan na may PEC mitigation na inilapat.

tala

Ang paggamit para sa halimbawang ito ay humigit-kumulang 10 minuto sa isang Heron r2 processor.

I-set up ang circuit

Pumili ng backend at maghanda ng 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)

Output of the previous code cell

Pagsamahin ang circuit at ang inverse nito upang lumikha ng mirror circuit.

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

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

Output of the previous code cell

Magtakda ng ilang mga halaga ng parameter:

import numpy as np

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

Gamitin ang pass manager upang i-transpile ang circuit upang maging ISA circuit.

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

isa_circuit = preset_pass_manager.run(mirror_circuit)

Susunod, i-grupo ang mga gate at sukat sa mga annotated box. Maaari mo itong gawin nang manu-mano o gamitin ang function na generate_boxing_pass_manager mula sa Samplomatic para sa kaginhawahan. Ang unang circuit ay magkakaroon lamang ng twirling na inilapat kaya nangangailangan lamang ng annotation na Twirl. Ang ikalawang circuit ay patatakbuhin na may full PEC mitigation at nangangailangan ng parehong annotation na Twirl at 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)

Matutunan ang noise

Upang mabawasan ang bilang ng mga eksperimento sa noise learning, tukuyin ang mga natatanging tagubilin sa pangalawang circuit (ang isa na may mga box na annotated na may InjectNoise). Sa pagdefinisyon ng uniqueness, ang dalawang tagubilin ng box ay pantay kung ang parehong mga sumusunod ay totoo:

  • Ang kanilang nilalaman ay pantay, hanggang sa single-qubit na gate.
  • Ang kanilang Twirl annotation ay pantay (bawat iba pang annotation ay hindi pinapansin).

Ito ay humahantong sa tatlong natatanging tagubilin, katulad ng odd at even na gate box, at ang panghuling measurement box.

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

I-initialize ang isang NoiseLearnerV3, piliin ang mga parameter ng pagkatuto sa pamamagitan ng pagtatakda ng mga opsyon nito, at patakbuhin ang noise learning job.

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()

I-convert ang result sa bagay na kinakailangan ng samplex sa pamamagitan ng paggamit ng pamamaraan ng result.to_dict.

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

Isabuhay ang mga circuit

Ang Executor ay nagpapatakbo ng mga bagay na QuantumProgram. Ang bawat QuantumProgram ay maaaring maglaman ng ilang mga item, na idinaragdag sa programa. Ang bawat item ay isang gawain na isasagawa ng programa.

Mag-initialize ng walang laman na programa, humihiling ng 1000 shots para sa bawat configuration ng bawat item.

from qiskit_ibm_runtime.quantum_program import QuantumProgram

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

Susunod, i-build ang template circuit at samplex para sa mirror_circuit_twirl at i-append ang mga ito sa programa. Humiling din ng 900 randomization mula sa samplex. Nangangahulugan ito na ang samplex ay bumubuo ng 900 na set ng mga parameter, at ang bawat set ay isasagawa ng 1000 beses (ang bilang ng mga shot) sa QPU.

Ito ang unang gawain ng programa (resulta 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,),
)

Katulad nito, i-append ang template circuit at samplex na binuo para sa mirror_circuit_pec, humihiling ng 900 randomization. Ito ang pangalawang gawain ng programa (resulta 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,),
)

I-import ang Executor at mag-submit ng job.

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)

Suriin ang mga resulta

Sa wakas, i-post-process ang mga resulta upang matantya ang mga expectation value ng mga single-qubit Pauli-Z operator na kumikilos sa bawat isa sa sampung aktibong qubit (inaasahang halaga: 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.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)}")
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

Mga susunod na hakbang

Mga Rekomendasyon