Setează nivelul de optimizare al Transpiler-ului
Versiuni de pachete
Codul de pe această pagină a fost dezvoltat folosind următoarele cerințe. Recomandăm să folosești aceste versiuni sau unele mai noi.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
Dispozitivele cuantice reale sunt supuse zgomotului și erorilor de Gate, astfel c ă optimizarea circuitelor pentru a le reduce adâncimea și numărul de Gate-uri poate îmbunătăți semnificativ rezultatele obținute prin executarea acelor circuite.
Funcția generate_preset_pass_manager are un argument pozițional obligatoriu, optimization_level, care controlează cât efort investește Transpiler-ul în optimizarea circuitelor. Acest argument poate fi un număr întreg cu una dintre valorile 0, 1, 2 sau 3.
Nivelurile de optimizare mai ridicate generează circuite mai optimizate, cu prețul unor timpi de compilare mai lungi.
Tabelul următor explică optimizările efectuate pentru fiecare setare.
| Nivel de optimizare | Descriere |
|---|---|
| 0 | Fără optimizare: utilizat de obicei pentru caracterizarea hardware-ului
|
| 1 | Optimizare ușoară:
|
| 2 | Optimizare medie:
|
| 3 | Optimizare ridicată:
|
Nivelul de optimizare în acțiune
Deoarece Gate-urile cu doi Qubiți sunt de obicei cea mai semnificativă sursă de erori, putem cuantifica aproximativ „eficiența hardware" a transpilării numărând Gate-urile cu doi Qubiți din circuitul rezultat. Aici, vom încerca diferitele niveluri de optimizare pe un circuit de intrare format dintr-un unitar aleatoriu urmat de un Gate SWAP.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
from qiskit import QuantumCircuit
from qiskit.circuit.library import UnitaryGate
from qiskit.quantum_info import Operator, random_unitary
UU = random_unitary(4, seed=12345)
rand_U = UnitaryGate(UU)
qc = QuantumCircuit(2)
qc.append(rand_U, range(2))
qc.swap(0, 1)
qc.draw("mpl", style="iqp")
Vom folosi Backend-ul simulat FakeSherbrooke în exemplele noastre. Mai întâi, să transpilăm folosind nivelul de optimizare 0.
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke
backend = FakeSherbrooke()
pass_manager = generate_preset_pass_manager(
optimization_level=0, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)
Circuitul transpilat are șase Gate-uri ECR cu doi Qubiți.
Repetă pentru nivelul de optimizare 1:
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke
backend = FakeSherbrooke()
pass_manager = generate_preset_pass_manager(
optimization_level=1, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)
Circuitul transpilat are în continuare șase Gate-uri ECR, dar numărul Gate-urilor cu un singur Qubit s-a redus.
Repetă pentru nivelul de optimizare 2:
pass_manager = generate_preset_pass_manager(
optimization_level=2, backend=backend, seed_transpiler=12345
)
qc_t2_exact = pass_manager.run(qc)
qc_t2_exact.draw("mpl", idle_wires=False)
Aceasta produce aceleași rezultate ca nivelul de optimizare 1. Reține că mărirea nivelului de optimizare nu face întotdeauna o diferență.
Repetă din nou, cu nivelul de optimizare 3:
pass_manager = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=12345
)
qc_t3_exact = pass_manager.run(qc)
qc_t3_exact.draw("mpl", idle_wires=False)
Acum există doar trei Gate-uri ECR. Obținem acest rezultat deoarece la nivelul de optimizare 3, Qiskit încearcă să resintetizeze blocurile cu doi Qubiți de Gate-uri, iar orice Gate cu doi Qubiți poate fi implementat folosind cel mult trei Gate-uri ECR. Putem obține și mai puține Gate-uri ECR dacă setăm approximation_degree la o valoare mai mică decât 1, permițând Transpiler-ului să facă aproximări care pot introduce o eroare în descompunerea Gate-urilor (vezi Parametri frecvent utilizați pentru transpilare):
pass_manager = generate_preset_pass_manager(
optimization_level=3,
approximation_degree=0.99,
backend=backend,
seed_transpiler=12345,
)
qc_t3_approx = pass_manager.run(qc)
qc_t3_approx.draw("mpl", idle_wires=False)
Acest Circuit are doar două Gate-uri ECR, dar este un circuit aproximativ. Pentru a înțelege cum diferă efectul său față de circuitul exact, putem calcula fidelitatea dintre operatorul unitar pe care îl implementează acest circuit și unitarul exact. Înainte de a efectua calculul, reducem mai întâi circuitul transpilat, care conține 127 de Qubiți, la un circuit care conține doar Qubiții activi, dintre care sunt doi.
import numpy as np
def trace_to_fidelity_2q(trace: float) -> float:
return (4.0 + trace * trace.conjugate()) / 20.0
# Reduce circuits down to 2 qubits so they are easy to simulate
qc_t3_exact_small = QuantumCircuit.from_instructions(qc_t3_exact)
qc_t3_approx_small = QuantumCircuit.from_instructions(qc_t3_approx)
# Compute the fidelity
exact_fid = trace_to_fidelity_2q(
np.trace(np.dot(Operator(qc_t3_exact_small).adjoint().data, UU))
)
approx_fid = trace_to_fidelity_2q(
np.trace(np.dot(Operator(qc_t3_approx_small).adjoint().data, UU))
)
print(
f"Synthesis fidelity\nExact: {exact_fid:.3f}\nApproximate: {approx_fid:.3f}"
)
Synthesis fidelity
Exact: 1.000+0.000j
Approximate: 0.992+0.000j
Ajustarea nivelului de optimizare poate schimba și alte aspecte ale circuitului, nu doar numărul de Gate-uri ECR. Pentru exemple despre cum setarea nivelului de optimizare schimbă layout-ul, vezi Reprezentarea calculatoarelor cuantice.
Pași următori
- Pentru a afla mai multe despre funcția
generate_preset_passmanager, începe cu subiectul Setări implicite și opțiuni de configurare pentru transpilare. - Continuă să înveți despre transpilare cu subiectul Etapele Transpiler-ului.
- Încearcă ghidul Compară setările Transpiler-ului.
- Încearcă tutorialul Construiește coduri de repetiție.
- Vezi documentația API pentru Transpilare.