Vai al contenuto principale

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:

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.

nota

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.

Note
  • 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.

nota

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: ═══════════════════
Note importanti
  • 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.

nota

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 if e 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_test su c0 sono considerati un broadcast perché il contenuto di c0 non è cambiato e quindi non deve essere ritrasmesso. L'if_test su c1 è un secondo broadcast. Il primo trasmette tutti e tre i bit in c0 e 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_test deve essere di 32 o meno bit. Quindi, se stai confrontando un intero ClassicalRegister, la dimensione di quel ClassicalRegister deve essere di 32 o meno bit. Se stai confrontando solo un singolo bit da un ClassicalRegister, tuttavia, quel ClassicalRegister può 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".

    cr = ClassicalRegister(50)
    qr = QuantumRegister(50)
    circuit = QuantumCircuit(qr, cr)
    ...
    circ.measure(qr, cr)
    with circ.if_test((cr, 15)):
    ...
  • I condizionali annidati non sono consentiti. Ad esempio, il seguente blocco di codice non funzionerà perché ha un if_test all'interno di un altro if_test:

    c1 = ClassicalRegister(1, "c1")
    c2 = ClassicalRegister(2, "c2")
    ...
    with circ.if_test((c1, 1)):
    with circ.if_test(c2, 1)):
    ...
  • Non è supportato avere reset o 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, while e switch non 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:

  1. Raggruppa i termini di tutti gli osservabili in una partizione. Questo può essere fatto usando l'API PauliList, ad esempio.
    nota

    Puoi usare l'attributo primitivo BitArray per calcolare i valori di aspettazione degli osservabili forniti.

  2. Esegui un Circuit di cambio di base per partizione (qualunque cambio di base debba essere fatto per ogni partizione). Consulta il modulo measurement_bases del componente aggiuntivo Measurement bases per ulteriori informazioni. Per ulteriori informazioni, consulta la documentazione del pacchetto Qiskit addon utilities.
  3. 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

Raccomandazioni