Vai al contenuto principale
Questo progetto è in fase beta. Hai trovato un bug? Apri una issue su GitHub. Hai una domanda o un'idea? Chiedi su GitHub Discussions — apprezziamo il tuo feedback!
Com'è la qualità della traduzione su questa pagina?

Impostare il livello di ottimizzazione del transpiler

Versioni dei pacchetti

Il codice in questa pagina è stato sviluppato utilizzando i seguenti requisiti. Consigliamo di utilizzare queste versioni o versioni più recenti.

qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0

I dispositivi quantistici reali sono soggetti a rumore ed errori dei Gate, quindi ottimizzare i Circuit per ridurne la profondità e il numero di Gate può migliorare significativamente i risultati ottenuti dall'esecuzione di tali Circuit. La funzione generate_preset_pass_manager ha un argomento posizionale obbligatorio, optimization_level, che controlla quanto sforzo il Transpiler dedica all'ottimizzazione dei Circuit. Questo argomento può essere un intero che assume uno dei valori 0, 1, 2 o 3. Livelli di ottimizzazione più alti generano Circuit più ottimizzati a scapito di tempi di compilazione più lunghi. La tabella seguente spiega le ottimizzazioni eseguite con ciascuna impostazione.

Livello di ottimizzazioneDescrizione
0

Nessuna ottimizzazione: tipicamente usato per la caratterizzazione dell'hardware

  • Traduzione di base
  • Layout/Routing: TrivialLayout, che seleziona gli stessi numeri di qubit fisici come virtuali e inserisce SWAP per farlo funzionare (usando SabreSwap)
1

Ottimizzazione leggera:

  • Layout/Routing: il layout viene prima tentato con TrivialLayout. Se sono richiesti SWAP aggiuntivi, viene trovato un layout con un numero minimo di SWAP usando SabreSwap, poi si usa VF2LayoutPostLayout per cercare di selezionare i migliori qubit nel grafo.
  • InverseCancellation
  • Ottimizzazione dei gate a 1 qubit
2

Ottimizzazione media:

  • Layout/Routing: livello di ottimizzazione 1 (senza trivial) + euristico ottimizzato con maggiore profondità di ricerca e tentativi della funzione di ottimizzazione. Poiché TrivialLayout non viene usato, non si cerca di usare gli stessi numeri di qubit fisici e virtuali.
  • CommutativeCancellation
3

Ottimizzazione elevata:

  • Livello di ottimizzazione 2 + euristico ulteriormente ottimizzato su layout/routing con maggiore impegno/tentativi
  • Risintesi di blocchi a due qubit usando la decomposizione KAK di Cartan.
  • Passate che interrompono l'unitarietà:
    • OptimizeSwapBeforeMeasure: sposta le misurazioni per evitare SWAP
    • RemoveDiagonalGatesBeforeMeasure: rimuove i gate prima delle misurazioni che non influenzerebbero i risultati

Il livello di ottimizzazione in azione​

Poiché i gate a due qubit sono tipicamente la principale fonte di errori, possiamo quantificare approssimativamente l'"efficienza hardware" della transpilazione contando il numero di gate a due qubit nel circuito risultante. Qui proveremo i diversi livelli di ottimizzazione su un circuito d'ingresso composto da un unitario casuale seguito da un gate SWAP.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
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 della cella di codice precedente

nota

Il backend mock FakeSherbrooke di qiskit_ibm_runtime viene usato in questi esempi, ma puoi provarlo su qualsiasi backend reale o finto compatibile con Qiskit. I tuoi risultati potrebbero essere diversi.

Prima di tutto, trasponiamo usando il livello di ottimizzazione 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 della cella di codice precedente

Il circuito transpilato ha sei gate ECR a due qubit.

Ripetiamo per il livello di ottimizzazione 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 della cella di codice precedente

Il circuito transpilato ha ancora sei gate ECR, ma il numero di gate a qubit singolo si è ridotto.

Ripetiamo per il livello di ottimizzazione 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 della cella di codice precedente

Questo produce gli stessi risultati del livello di ottimizzazione 1. Nota che aumentare il livello di ottimizzazione non sempre fa la differenza.

Ripetiamo ancora, con il livello di ottimizzazione 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 della cella di codice precedente

Ora ci sono solo tre gate ECR. Otteniamo questo risultato perché al livello di ottimizzazione 3, Qiskit tenta di ri-sintetizzare blocchi di gate a due qubit, e qualsiasi gate a due qubit può essere implementato usando al massimo tre gate ECR. Possiamo ottenere ancora meno gate ECR se impostiamo approximation_degree a un valore inferiore a 1, consentendo al transpiler di fare approssimazioni che potrebbero introdurre qualche errore nella decomposizione del gate (vedi Parametri comunemente usati per la trasposizione):

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 della cella di codice precedente

Questo circuito ha solo due gate ECR, ma è un circuito approssimato. Per capire in che misura il suo effetto differisce dal circuito esatto, possiamo calcolare la fedeltà tra l'operatore unitario implementato da questo circuito e l'unitario esatto. Prima di eseguire il calcolo, riduciamo il circuito transpilato, che contiene 127 qubit, a un circuito che contiene solo i qubit attivi, che sono due.

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

Regolare il livello di ottimizzazione può cambiare anche altri aspetti del circuito, non solo il numero di gate ECR. Per esempi di come l'impostazione del livello di ottimizzazione cambia il layout, vedi Rappresentare i computer quantistici.

Passi successivi​

Raccomandazioni