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.4.0
qiskit-ibm-runtime~=0.46.1
Dispozitivele cuantice reale sunt supuse zgomotului și erorilor de poartă, astfel că optimizarea circuitelor pentru a le reduce adâncimea și numărul de poartă-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 poartă 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")
Backend-ul simulat FakeSherbrooke din qiskit_ibm_runtime este utilizat în aceste exemple, dar poți încerca pe orice backend real sau simulat compatibil cu Qiskit. Rezultatele tale pot fi diferite.
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 poartă-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 poartă-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.