Impostare il livello di ottimizzazione del transpiler
Versioni dei pacchetti
Il codice in questa pagina è stato sviluppato con i seguenti requisiti. Si consiglia di usare queste versioni o versioni più recenti.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
I dispositivi quantistici reali sono soggetti a rumore ed errori nei gate, quindi ottimizzare i circuiti per ridurne la profondità e il numero di gate può migliorare significativamente i risultati ottenuti dall'esecuzione di quei circuiti.
La funzione generate_preset_pass_manager ha un argomento posizionale obbligatorio, optimization_level, che controlla quanto impegno il transpiler dedica all'ottimizzazione dei circuiti. Questo argomento può essere un intero con uno dei valori 0, 1, 2 o 3.
Livelli di ottimizzazione più alti generano circuiti più ottimizzati a scapito di tempi di compilazione più lunghi.
La tabella seguente illustra le ottimizzazioni eseguite con ciascuna impostazione.
| Livello di ottimizzazione | Descrizione |
|---|---|
| 0 | Nessuna ottimizzazione: tipicamente usato per la caratterizzazione dell'hardware
|
| 1 | Ottimizzazione leggera:
|
| 2 | Ottimizzazione media:
|
| 3 | Ottimizzazione elevata:
|
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 trasposizione 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 — 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")
Useremo il backend mock FakeSherbrooke nei nostri esempi. 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)
Il circuito trasposto 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)
Il circuito trasposto 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)
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)
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)
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 prima il circuito trasposto, 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​
- Per saperne di più sulla funzione
generate_preset_passmanager, inizia con l'argomento Impostazioni predefinite e opzioni di configurazione della trasposizione. - Continua ad apprendere sulla trasposizione con l'argomento Fasi del transpiler.
- Prova la guida Confronta le impostazioni del transpiler.
- Prova il tutorial Costruisci codici a ripetizione.
- Consulta la documentazione API di Transpile.