Sari la conținutul principal

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 optimizareDescriere
0

Fără optimizare: utilizat de obicei pentru caracterizarea hardware-ului

  • Traducere de bază
  • Layout/Rutare: TrivialLayout, care selectează aceleași numere de Qubit fizic ca și virtual și inserează SWAP-uri pentru a funcționa (folosind SabreSwap)
1

Optimizare ușoară:

  • Layout/Rutare: Layout-ul este încercat mai întâi cu TrivialLayout. Dacă sunt necesare SWAP-uri suplimentare, se găsește un layout cu un număr minim de SWAP-uri folosind SabreSwap, apoi se utilizează VF2LayoutPostLayout pentru a selecta cei mai buni Qubiți din graf.
  • InverseCancellation
  • Optimizarea Gate-urilor cu 1 Qubit
2

Optimizare medie:

  • Layout/Rutare: Nivelul de optimizare 1 (fără trivial) + euristic optimizat cu adâncime de căutare mai mare și mai multe încercări ale funcției de optimizare. Deoarece TrivialLayout nu este utilizat, nu se încearcă să se folosească aceleași numere de Qubit fizic și virtual.
  • CommutativeCancellation
3

Optimizare ridicată:

  • Nivelul de optimizare 2 + euristic optimizat suplimentar pe layout/rutare cu mai mult efort/încercări
  • Resinteză a blocurilor cu doi Qubiți folosind Descompunerea KAK a lui Cartan.
  • Pași care întrerup unitaritatea:
    • OptimizeSwapBeforeMeasure: Mută măsurătorile pentru a evita SWAP-urile
    • RemoveDiagonalGatesBeforeMeasure: Elimină Gate-urile dinaintea măsurătorilor care nu ar afecta rezultatele măsurătorilor

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

Output of the previous code cell

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)

Output of the previous code cell

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)

Output of the previous code cell

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)

Output of the previous code cell

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)

Output of the previous code cell

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)

Output of the previous code cell

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

Recomandări