Esegui Circuit dinamici
Versioni dei pacchetti
Il codice in questa pagina è stato sviluppato con i seguenti requisiti. Ti consigliamo di utilizzare queste versioni o versioni più recenti.
qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
I Circuit dinamici sono strumenti potenti con cui puoi misurare i qubit nel mezzo dell'esecuzione di un Circuit quantistico e poi eseguire operazioni di logica classica all'interno del Circuit, in base al risultato di quelle misurazioni mid-circuit. Questo processo è anche noto come feedforward classico. Sebbene questi siano ancora i primi passi per capire come sfruttare al meglio i Circuit dinamici, la comunità di ricerca quantistica ha già identificato una serie di casi d'uso, come i seguenti:
- Preparazione efficiente dello stato quantistico, come lo stato GHZ, lo stato W (per ulteriori informazioni sullo stato W, consulta anche "State preparation by shallow circuits using feed forward"), e un'ampia classe di matrix product states
- Entanglement a lungo raggio efficiente tra qubit sullo stesso chip usando Circuit superficiali
- Campionamento efficiente di Circuit simili a IQP
Questi miglioramenti apportati dai Circuit dinamici, tuttavia, comportano dei compromessi. Le misurazioni mid-circuit e le operazioni classiche hanno tipicamente tempi di esecuzione più lunghi rispetto ai Gate a due Qubit, e questo aumento del tempo potrebbe annullare i benefici della riduzione della profondità del Circuit. Pertanto, la riduzione della durata della misurazione mid-circuit è un'area di miglioramento su cui IBM Quantum® si concentra con il rilascio della nuova versione dei Circuit dinamici. Per altre restrizioni quando si usano i Circuit dinamici, consulta la tabella di compatibilità delle funzionalità di Estimator o Sampler.
La specifica OpenQASM 3 definisce una serie di strutture di flusso di controllo, ma Qiskit Runtime attualmente supporta solo l'istruzione condizionale if. In Qiskit SDK, questo corrisponde al metodo if_test su QuantumCircuit. Questo metodo restituisce un context manager e viene tipicamente usato in un'istruzione with. Questa guida descrive come usare questa istruzione condizionale.
Gli esempi di codice in questa guida usano l'istruzione di misurazione standard per le misurazioni mid-circuit. Tuttavia, si raccomanda di usare invece l'istruzione MidCircuitMeasure, se il Backend la supporta. Consulta la sezione Misurazioni mid-circuit per i dettagli.
Trova i Backend che supportano i Circuit dinamici
Per trovare tutti i Backend a cui il tuo account può accedere e che supportano i Circuit dinamici, esegui codice come il seguente. Questo esempio presuppone che tu abbia salvato le tue credenziali di accesso. Potresti anche specificare esplicitamente le credenziali quando inizializzi il tuo account del servizio Qiskit Runtime. Questo ti permetterebbe di visualizzare i Backend disponibili su un'istanza o tipo di piano specifico, ad esempio.
- I Backend disponibili per l'account dipendono dall'istanza specificata nelle credenziali.
- La nuova versione dei Circuit dinamici è ora disponibile per tutti gli utenti su tutti i Backend. Consulta l'annuncio per ulteriori dettagli.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# This cell is hidden from users. It hides all those "...instance was not set..." warnings.
import warnings
warnings.filterwarnings("ignore", message=".*Instance was not set*")
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
dc_backends = service.backends(dynamic_circuits=True)
print(dc_backends)
[<IBMBackend('ibm_pittsburgh')>, <IBMBackend('ibm_kingston')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_boston')>]
Misurazioni mid-circuit
Prima di qiskit-ibm-runtime v0.43.0, measure era l'unica istruzione di misurazione in Qiskit. Le misurazioni mid-circuit, tuttavia, hanno requisiti di tuning diversi rispetto alle misurazioni terminali (misurazioni che avvengono alla fine di un Circuit). Ad esempio, è necessario considerare la durata dell'istruzione durante il tuning di una misurazione mid-circuit perché le istruzioni più lunghe causano Circuit più rumorosi. Non è necessario considerare la durata dell'istruzione per le misurazioni terminali perché non ci sono istruzioni dopo le misurazioni terminali.
L'istruzione MidCircuitMeasure mappa all'istruzione measure_2 riportata nelle supported_instructions del Backend. Tuttavia, measure_2 non è supportata su tutti i Backend. Usa service.backends(filters=lambda b: "measure_2" in b.supported_instructions) per trovare i Backend che la supportano. In futuro potrebbero essere aggiunte nuove misurazioni, ma ciò non è garantito.
Metodo MidCircuitMeasure
In qiskit-ibm-runtime v0.43.0, è stata introdotta l'istruzione MidCircuitMeasure. Come suggerisce il nome, è una nuova istruzione di misurazione ottimizzata per le misurazioni mid-circuit su QPU IBM®. Sebbene tu possa usare QuantumCircuit.measure per una misurazione mid-circuit, a causa del suo design, MidCircuitMeasure è tipicamente una scelta migliore. Ad esempio, aggiunge meno overhead al tuo Circuit rispetto all'uso di QuantumCircuit.measure.
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime.circuit import MidCircuitMeasure
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)
circ = QuantumCircuit(2, 2)
circ.x(0)
circ.append(MidCircuitMeasure(), [0], [0])
# circ.measure([0], [0])
# circ.measure_all()
print(circ.draw(cregbundle=False))
┌───┐┌────────────┐
q_0: ┤ X ├┤0 ├
└───┘│ │
q_1: ─────┤ Measure_2 ├
│ │
c_0: ═════╡0 ╞
└────────────┘
c_1: ═══════════════════
- Deve esserci almeno un registro classico per poter usare le misurazioni.
- La primitiva Sampler richiede le misurazioni del Circuit. Puoi aggiungere misurazioni del Circuit con la primitiva Estimator, ma vengono ignorate.
Store
Con qiskit-ibm-runtime versione 0.47.0 o successiva, puoi usare l'istruzione store per salvare il risultato di un'espressione classica, se quell'espressione verrà usata ripetutamente. Le operazioni vengono parallelizzate automaticamente, rendendo il tuo codice significativamente più efficiente in fase di esecuzione.
Per ulteriori informazioni, consulta la guida Feedforward classico e flusso di controllo.
Quando usi store per salvare un valore in un registro classico su un Backend reale, quel valore viene salvato solo in memoria durante l'esecuzione e non viene copiato o restituito nel risultato del job.
Ad esempio, nel codice seguente, temp ha lo stesso valore di creg durante l'esecuzione, e l'if_test funziona come previsto. Ma dopo il completamento del job, il BitArray di temp restituito nel risultato del job non contiene il valore di creg. Ovvero, job.result()[0].data.temp è 0.
creg = ClassicalRegister(3, "c")
temp = ClassicalRegister(3, "temp")
...
qc.store(temp, creg)
with circuit.if_test((temp, 0b001)):
...
Esempio completo
Il codice seguente crea ed esegue un Circuit dinamico sull'hardware IBM®.
from qiskit_ibm_runtime import SamplerV2, QiskitRuntimeService
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.transpiler import generate_preset_pass_manager
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)
# Create a dynamic circuit
qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
qc = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits
qc.h(q0)
qc.measure(q0, c0)
with qc.if_test((c0, 1)):
qc.x(q0)
qc.measure(q0, c0)
# Convert to an ISA circuit for the given backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
# Generate samplers for backend targets
sampler = SamplerV2(backend)
# Submit jobs
sampler_job = sampler.run([isa_circuit])
result = sampler_job.result()
print(
f">>> {' Job ID:':<10} {sampler_job.job_id()} ({sampler_job.status()})"
)
>>> Job ID: d88cakp789is7391vq0g (DONE)
Limitazioni di Qiskit Runtime
Tieni presente i seguenti vincoli quando esegui Circuit dinamici in Qiskit Runtime.
-
A causa della memoria fisica limitata sull'elettronica di controllo, c'è anche un limite al numero di istruzioni
ife alla dimensione dei loro operandi. Questo limite è una funzione del numero di broadcast e del numero di bit trasmessi in un job (non in un Circuit).Quando si elabora una condizione
if, i dati di misurazione devono essere trasferiti alla logica di controllo per effettuare quella valutazione. Un broadcast è un trasferimento di dati classici unici, e i bit trasmessi sono il numero di bit classici trasferiti. Considera quanto segue:c0 = ClassicalRegister(3)c1 = ClassicalRegister(5)...with circuit.if_test((c0, 1)) ...with circuit.if_test((c0, 3)) ...with circuit.if_test((c1[2], 1)) ...Nel precedente esempio di codice, i primi due oggetti
if_testsuc0sono considerati un broadcast perché il contenuto dic0non è cambiato e quindi non deve essere ritrasmesso. L'if_testsuc1è un secondo broadcast. Il primo trasmette tutti e tre i bit inc0e il secondo trasmette solo un bit, per un totale di quattro bit trasmessi.Attualmente, se si trasmettono 60 bit ogni volta, il job può avere circa 300 broadcast. Se si trasmette solo un bit ogni volta, tuttavia, il job può avere 2400 broadcast.
-
L'operando usato in un'istruzione
if_testdeve essere di 32 o meno bit. Quindi, se stai confrontando un interoClassicalRegister, la dimensione di quelClassicalRegisterdeve essere di 32 o meno bit. Se stai confrontando solo un singolo bit da unClassicalRegister, tuttavia, quelClassicalRegisterpuò essere di qualsiasi dimensione (poiché l'operando è solo un bit).Ad esempio, il blocco di codice "Non valido" non funziona perché
crè più di 32 bit. Puoi, tuttavia, usare un registro classico più largo di 32 bit se stai testando solo un bit, come mostrato nel blocco di codice "Valido".- Non valido
- Valido
cr = ClassicalRegister(50)qr = QuantumRegister(50)circuit = QuantumCircuit(qr, cr)...circ.measure(qr, cr)with circ.if_test((cr, 15)):...cr = ClassicalRegister(50)qr = QuantumRegister(50)circuit = QuantumCircuit(qr, cr)...circ.measure(qr, cr)with circ.if_test((cr[5], 1)):... -
I condizionali annidati non sono consentiti. Ad esempio, il seguente blocco di codice non funzionerà perché ha un
if_testall'interno di un altroif_test:- Non valido
- Valido
c1 = ClassicalRegister(1, "c1")c2 = ClassicalRegister(2, "c2")...with circ.if_test((c1, 1)):with circ.if_test(c2, 1)):...cr = ClassicalRegister(2)...with circuit.if_test((cr, 0b11)):... -
Non è supportato avere
reseto misurazioni all'interno dei condizionali. -
Le operazioni aritmetiche non sono supportate.
-
Consulta la tabella delle funzionalità OpenQASM 3 per determinare quali funzionalità OpenQASM 3 sono supportate su Qiskit e Qiskit Runtime.
-
Quando OpenQASM 3 (invece di
QuantumCircuit) è usato come formato di input per passare Circuit alle primitive Qiskit Runtime, sono supportate solo le istruzioni che possono essere caricate in Qiskit. Le operazioni classiche, ad esempio, non sono supportate perché non possono essere caricate in Qiskit. Consulta Importa un programma OpenQASM 3 in Qiskit per ulteriori informazioni. -
Le istruzioni
for,whileeswitchnon sono supportate.
Usa i Circuit dinamici con Estimator
Poiché Estimator non supporta i Circuit dinamici, puoi usare Sampler e costruire i tuoi Circuit di misurazione.
Per replicare il comportamento di Estimator, segui questo processo:
- Raggruppa i termini di tutti gli osservabili in una partizione. Questo può essere fatto usando l'API
PauliList, ad esempio.notaPuoi usare l'attributo primitivo
BitArrayper calcolare i valori di aspettazione degli osservabili forniti. - Esegui un Circuit di cambio di base per partizione (qualunque cambio di base debba essere fatto per ogni partizione). Consulta il modulo
measurement_basesdel componente aggiuntivo Measurement bases per ulteriori informazioni. Per ulteriori informazioni, consulta la documentazione del pacchetto Qiskit addon utilities. - Somma i risultati per ogni partizione.
Restrizioni
Consulta qualsiasi tabella di compatibilità delle funzionalità per capire le restrizioni quando si usano i Circuit dinamici. Nota che la compatibilità delle funzionalità non dipende dalla primitiva.
Passi successivi
- Scopri come implementare il decoupling dinamico accurato usando stretch.
- Consulta la guida feedforward classico e flusso di controllo.
- Usa la visualizzazione della pianificazione del Circuit per eseguire il debug e ottimizzare i tuoi Circuit dinamici.
- Non tutte le funzioni sono compatibili con i Circuit dinamici. Controlla la sezione di compatibilità delle funzionalità per Sampler o Executor per i dettagli.