Ikumpara ang mga setting ng transpiler
Package versions
Ang code sa pahinang ito ay ginawa gamit ang mga sumusunod na kinakailangan. Inirerekomenda naming gamitin ang mga bersyong ito o mas bago pa.
qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
Ang iba't ibang setting ng transpiler ay nagbibigay ng iba't ibang uri ng optimization sa circuit, kadalasan sa kapinsalaan ng mas matagal na classical processing time. Itinuturo ng gabay na ito ang buong proseso ng paglikha, pag-transpile, at pagsumite ng mga circuit para ipakita kung paano subukin ang performance ng iba't ibang setting.
Tandaan na ang parehong setting ay maaaring mapabuti ang mga resulta ng isang circuit habang hinahadlangan ang isa pa. Siguraduhing suriin ang mga resultang transpiled na circuit bago patakbuhin sa tunay na hardware.
I-set up at gumawa ng sample na circuit​
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# Create circuit to test transpiler on
from qiskit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.circuit.library import grover_operator, DiagonalGate
# Use Statevector object to calculate the ideal output
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_histogram
from qiskit.transpiler import PassManager
from qiskit.circuit.library import XGate
from qiskit.quantum_info import hellinger_fidelity
Gumawa ng maliit na circuit para subukan ng transpiler na i-optimize. Sa halimbawang ito, gagawa ng circuit na nagsasagawa ng Grover's algorithm na may oracle na nagmamarka sa estado na 111. Susunod, i-simulate ang ideal na distribusyon (ang inaasahan mong masusukat kung pinatakbo mo ito sa isang perpektong quantum computer nang walang katapusang beses) para sa paghahambing sa ibang pagkakataon.
oracle = DiagonalGate([1] * 7 + [-1])
qc = QuantumCircuit(3)
qc.h([0, 1, 2])
qc = qc.compose(grover_operator(oracle))
qc.draw(output="mpl", style="iqp")
ideal_distribution = Statevector.from_instruction(qc).probabilities_dict()
plot_histogram(ideal_distribution)
I-transpile​
Susunod, i-transpile ang mga circuit para sa QPU. Ikukumpara mo ang performance ng transpiler na ang optimization_level ay nakatakda sa 0 (pinakamababa) laban sa 3 (pinakamataas). Ang pinakamababang antas ng optimization ay gumagawa lamang ng pinakamaliit na kinakailangan para mapatakbo ang circuit sa device; imi-map nito ang mga circuit qubit sa mga device qubit at nagdadagdag ng mga swap gate para payagan ang lahat ng two-qubit na operasyon. Ang pinakamataas na antas ng optimization ay mas matalino at gumagamit ng maraming paraan para bawasan ang kabuuang bilang ng gate. Dahil ang mga multi-qubit na gate ay may mataas na error rate at ang mga qubit ay nagiging decoherent sa paglipas ng panahon, ang mas maikling mga circuit ay dapat magbigay ng mas magandang resulta.
Gumagamit ang halimbawang ito ng IBM Quantum® hardware, ngunit maaari mo itong subukan sa anumang Qiskit-compatible na QPU. Maaaring mag-iba ang iyong mga resulta.
Ang sumusunod na cell ay nagta-transpile ng qc para sa parehong halaga ng optimization_level, nagpi-print ng bilang ng mga two-qubit na gate, at nagdadagdag ng mga transpiled na circuit sa isang listahan. Ang ilan sa mga algorithm ng transpiler ay randomized, kaya nagtatakda ito ng seed para sa reproducibility.
# Use Qiskit Runtime to run jobs on hardware
from qiskit_ibm_runtime import (
QiskitRuntimeService,
SamplerV2 as Sampler,
)
# Select the backend with the fewest number of jobs in the queue
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
backend.name
'ibm_marrakesh'
# Need to add measurements to the circuit
qc.measure_all()
# Find the correct two-qubit gate
twoQ_gates = set(["ecr", "cz", "cx"])
for gate in backend.basis_gates:
if gate in twoQ_gates:
twoQ_gate = gate
circuits = []
for optimization_level in [0, 3]:
pm = generate_preset_pass_manager(
optimization_level, backend=backend, seed_transpiler=0
)
t_qc = pm.run(qc)
print(
f"Two-qubit gates (optimization_level={optimization_level}): ",
t_qc.count_ops()[twoQ_gate],
)
circuits.append(t_qc)
Two-qubit gates (optimization_level=0): 21
Two-qubit gates (optimization_level=3): 12
Dahil ang mga CNOT ay karaniwang may mataas na error rate, ang circuit na na-transpile gamit ang optimization_level=3 ay dapat na mas mahusay na magsagawa.
Isa pang paraan para mapabuti ang performance ay sa pamamagitan ng dynamical decoupling, sa pamamagitan ng paglalagay ng sequence ng mga gate sa mga idle na qubit. Nagkakansela ito ng ilang hindi gustong interaksyon sa kapaligiran. Ang sumusunod na cell ay nagdadagdag ng dynamic decoupling sa circuit na na-transpile gamit ang optimization_level=3 at idinadagdag ito sa listahan.
from qiskit_ibm_runtime.transpiler.passes.scheduling import (
ASAPScheduleAnalysis,
PadDynamicalDecoupling,
)
# Get gate durations so the transpiler knows how long each operation takes
durations = backend.target.durations()
# This is the sequence we'll apply to idling qubits
dd_sequence = [XGate(), XGate()]
# Run scheduling and dynamic decoupling passes on circuit
pm = PassManager(
[
ASAPScheduleAnalysis(durations),
PadDynamicalDecoupling(durations, dd_sequence),
]
)
circ_dd = pm.run(circuits[1])
# Add this new circuit to our list
circuits.append(circ_dd)
circ_dd.draw(output="mpl", style="iqp", idle_wires=False)
Isagawa ang circuit​
Sa puntong ito, mayroon kang listahan ng mga circuit na na-transpile gamit ang iba't ibang setting. Susunod, patakbuhin ang mga circuit na ito gamit ang Sampler primitive at itago ang mga resulta sa result.
sampler = Sampler(backend)
job = sampler.run(
[(circuit) for circuit in circuits], # sample all three circuits
shots=8000,
)
result = job.result()
Tingnan ang mga resulta​
Sa wakas, i-plot ang mga resulta mula sa mga pagpapatakbo ng device laban sa ideal na distribusyon. Makikita mo na ang mga resulta na may optimization_level=3 ay mas malapit sa ideal na distribusyon dahil sa mas mababang bilang ng gate, at ang optimization_level=3 + dd ay mas lalong malapit dahil sa dynamical decoupling.
binary_prob = [
{
k: v / res.data.meas.num_shots
for k, v in res.data.meas.get_counts().items()
}
for res in result
]
plot_histogram(
binary_prob + [ideal_distribution],
bar_labels=False,
legend=[
"optimization_level=0",
"optimization_level=3",
"optimization_level=3 + dd",
"ideal distribution",
],
)
Maaari mo itong kumpirmahin sa pamamagitan ng pagkukuwenta ng Hellinger fidelity sa pagitan ng bawat set ng resulta at ng ideal na distribusyon (mas mataas ay mas mabuti, at ang 1 ay perpektong fidelity).
for prob in binary_prob:
print(f"{hellinger_fidelity(prob, ideal_distribution):.3f}")
0.985
0.989
0.988
Mga susunod na hakbang​
-
Tuklasin ang ilang advanced na resources sa transpilation, tulad ng:
-
I-browse ang mga available na tutorials.