Skip to main content
IBM Quantum Platform

Migrazione da Sampler a Executor

Questa guida illustra come trasferire i carichi di lavoro di campionamento quantistico dalla primitiva " IBM Quantum® " alla primitiva "Executor".

Versione beta

La primitiva Executor fa parte del modello di esecuzione diretta. Tutti i componenti del modello di esecuzione diretta sono attualmente in versione beta e potrebbero non essere stabili. Ti invitiamo a provarle e a fornirci un feedback aprendo un ticket nei repository Samplomatic o qiskit-ibm-runtime su GitHub.


Dovresti migrare?

Non tutti dovrebbero passare da Sampler a Executor. Esistono molte differenze tra le primitive, ma le seguenti indicazioni possono aiutarti a decidere se procedere alla migrazione:

Passa a Executor se sei uno scienziato specializzato in informazione quantistica che conduce esperimenti su scala industriale e hai bisogno di un controllo dettagliato e riproducibile su tecniche quali il “Pauli twirling”, l’apprendimento e l’iniezione di modelli di rumore e i cambiamenti di base, oppure se hai bisogno di una delle funzionalità aggiuntive offerte da Executor.

Continua a utilizzare Sampler se desideri un'interfaccia semplice e di alto livello e vuoi che sia la primitiva a gestire per te la soppressione e la mitigazione degli errori.

Limiti e avvertenze

Poiché Executor e il modello di esecuzione diretta sono in fase beta, prima di decidere di effettuare la migrazione è bene tenere presente quanto segue:

  • Non è ancora disponibile il supporto per il simulatore : a differenza di Sampler, che dispone di un’ AerSamplerimplementazione per qiskit-aer la simulazione locale, attualmente non esiste un backend di simulazione per Executor. Simulatore Il supporto dovrebbe essere disponibile a breve. Nel frattempo, puoi comunque esaminare e testare il circuito modello in locale per verificare il corretto funzionamento del tuo flusso di lavoro prima di inviarlo all'hardware.
  • La presente guida riguarda esclusivamente Sampler, non Estimator. La migrazione da Estimator a Executor è notevolmente più complessa rispetto a quella da Sampler, poiché Estimator calcola i valori attesi anziché restituire campioni grezzi. Per riprodurre il comportamento di Estimator con Executor è necessaria un'ulteriore elaborazione successiva. Le funzioni di utilità che facilitano la migrazione da Estimator a Executor sono ancora in fase di sviluppo, pertanto questa guida descrive volutamente solo il flusso di lavoro di Sampler.

Differenze principali tra Executor e Sampler

Sia Sampler che Executor effettuano il campionamento dei registri di uscita dei circuiti quantistici, ma si rivolgono a utenti diversi:

  • Sampler è un'astrazione di alto livello. Presenta le seguenti caratteristiche:
    • È dotato di un sistema integrato di soppressione degli errori (disaccoppiamento dinamico e twirling).
    • Prende decisioni implicite al posto tuo.
    • È stato progettato in modo che gli sviluppatori di algoritmi possano concentrarsi sull'innovazione piuttosto che sui dati. conversione.
  • L'esecutore fa parte del modello di esecuzione diretta. Si differenzia da Sampler sotto molti aspetti e presenta le seguenti caratteristiche:
    • Non dispone di alcuna funzione integrata di soppressione o mitigazione degli errori. Si definisce invece l'intento progettuale sul lato client (utilizzando annotazioni del circuito e un samplex ), mentre la costosa generazione delle varianti del circuito viene trasferita al lato server.

    • Non prende alcuna decisione implicita. Segue alla lettera le tue indicazioni, garantendo pieno controllo e trasparenza.

    • Executor e Samplomatic offrono insieme funzionalità aggiuntive che Sampler non mette a disposizione, tra cui (a titolo esemplificativo ma non esaustivo) le seguenti:

      • Altri gruppi di rotazione: Samplomatic ti permette di scegliere quale gruppo di rotazione applicare per ogni casella, invece di limitarti all’unica strategia che Sampler applica automaticamente. Supporta inoltre gruppi di rotazione diversi da quelli di Pauli, come il gruppo di rotazione "local_c1" .
      • Misure con kernel e classificate insieme: l'impostazione QuantumProgram.meas_level = "both" (aggiunta in v0.48.0qiskit-ibm-runtime ) richiede che nei risultati siano presenti sia le misure classificate che quelle con kernel, anziché scegliere un unico tipo di misura per ogni processo.
      • Twirling per circuiti con porte frazionarie: Executor può applicare il twirling a circuiti che contengono porte frazionarie.
      • Mitigazione degli errori a granularità fine e modulabile: ad esempio, la scelta dei livelli del circuito su cui applicare la mitigazione e la regolazione dei livelli di rumore iniettati nel circuito.
      Note
      • Si prevede che le future nuove funzionalità vengano rilasciate prima su Executor e potrebbero non essere implementate su Sampler. Se per te è fondamentale poter accedere alle funzionalità più recenti, Executor è la scelta più a prova di futuro.
      • Il pacchetto base di Qiskit non fornisce ancora una classe base per la primitiva Executor (mentre la fornisce perSamplerV2).

Mappatura concettuale

La tabella seguente illustra la corrispondenza tra i concetti di Sampler e quelli di Executor.

Concetto
Campionatore
Esecutore
Importafrom qiskit_ibm_runtime import SamplerV2from qiskit_ibm_runtime import Executor
InputElenco dei PUB (tuple)Un insieme di QuantumProgram QuantumProgramItem oggetti
Circuito e parametri(circuit, params, shots) tuplaprogram.append_circuit_item(circuit, circuit_arguments=...)
Girare su se stessiTwirlingOptionsEsplicito tramite riquadri annotati e un samplex (append_samplex_item)
Esegui chiamatasampler.run([pub, ...])executor.run(program)
Tipo di risultatoPrimitiveResult di SamplerPubResultQuantumProgramResult (iterabile)
Accedi ai datiresult[0].data.<register> (BitArray)result[0]["<register>"] (np.ndarray)
Gestire il rumoreOpzioni integrateDevono essere compilati manualmente (annotazioni, samplex, ecc. NoiseLearnerV3)

Panoramica delle fasi della migrazione

  1. Installa Samplomatic.
  2. Modifica le importazioni.
  3. Sostituisci le tuple " PUB ".
  4. Modifica il modo in cui vengono espressi i tiri.
  5. Modifica le altre opzioni secondo necessità.
  6. Aggiornare il comando run .
  7. Aggiornamento dell'analisi dei risultati.
  8. Annulla la rotazione.

Passo 1. Installa i pacchetti necessari

Executor e il modello di esecuzione diretta richiedono il pacchetto samplomatic :

pip install qiskit qiskit-ibm-runtime samplomatic

# For visualization support:
# pip install samplomatic[vis]
Note sulla versione
  • qiskit-ibm-runtime v0.48.0 è consigliato perché aggiunge l'opzione meas_level = "both" e il gruppo di rotazione local_c1 .
  • qiskit >= 2.3.0 è obbligatorio.
  • samplomatic >= 0.18.0 è obbligatorio.

Passo 2. Modifica le importazioni

Esempio:

from qiskit_ibm_runtime import SamplerV2 as Sampler

Esecutore testamentario:

from qiskit_ibm_runtime import Executor, QuantumProgram

Passo 3. Sostituisci le tuple " PUB " con un QuantumProgram

Quando si utilizza Executor, invece di passare un elenco di tuple (PUB), si crea un e QuantumProgram vi si aggiungono gli elementi.

A QuantumProgram accetta articoli per circuiti e articoli Samplex :

  • append_circuit_item: Aggiunge un CircuitItem, che è un circuito e (facoltativamente) i relativi valori dei parametri. Viene eseguito così com'è, senza alcuna randomizzazione.

    Utilizza questa opzione quando desideri semplicemente campionare un circuito, esattamente come farebbe Sampler con un “ PUB ” privo di twirling; ad esempio, quando invii un semplice lavoro di campionamento, oppure quando hai già incluso manualmente tutte le varianti desiderate.

  • append_samplex_item: Aggiunge un samplexItem, ovvero un circuito modello più un samplex che genera insiemi di parametri casuali sul lato server.

    Utilizza questa opzione quando desideri che il contenuto del circuito venga generato in modo casuale. Il caso principale riguarda il twirling (gate o misurazione) o l'iniezione di rumore. Questa funzionalità sostituisce la funzione "twirling" integrata in Sampler.

Un singolo QuantumProgram può accettare entrambi i tipi di elementi; ogni elemento aggiunto viene eseguito come attività indipendente e genera una propria voce nei risultati. In generale, usa append_circuit_item quando il tuo circuito non deve essere randomizzato. Altrimenti, usa append_samplex_item.

Le sezioni seguenti illustrano, una dopo l'altra: i circuiti parametrizzati che utilizzano append_circuit_iteme la migrazione del twirling tramite append_samplex_item.

Negli esempi di codice che seguono, si riferisce isa_circuit al circuito che è stato transpilato per conformarsi all'architettura del set di istruzioni (ISA) del backend di destinazione. Questo contiene isa_circuit due parametri.

Fase 3a. Migrazione dei circuiti parametrizzati

Con Sampler, i valori dei parametri sono il secondo elemento della tupla PUB. Con Executor, passali come circuit_arguments a append_circuit_item.

Esempio:

params = np.random.rand(10, circuit.num_parameters)  # 10 parameter sets
pubs = (isa_circuit, params)

Esecutore

program = QuantumProgram(shots=1024)
program.append_circuit_item(
    isa_circuit,
    circuit_arguments=np.random.rand(10, circuit.num_parameters),  # 10 sets
)

# CircuitItem result shape: (parameter_sets, shots, register_bits) -> (10, 1024, 2)
result_0 = result[0]["meas"]

Fase 3b. Migrazione delle rotazioni integrate verso annotazioni esplicite

Questo è il cambiamento più significativo. Sampler esegue il twirling al posto tuo utilizzando le opzioni disponibili. Con Executor, si dichiara esplicitamente tale intenzione utilizzando caselle annotate e un samplex (di Samplomatic ).

Esempio (rotazione tramite le opzioni):

sampler = Sampler(mode=backend)
sampler.options.twirling.enable_gates = True
sampler.options.twirling.enable_measure = True

Esecutore (giro con scatole e un samplex):

from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager

# 1. Group gates and measurements into annotated boxes with twirling annotations
boxes_pm = generate_boxing_pass_manager(
    enable_gates=True,     # gate twirling
    enable_measures=True,  # measurement twirling
)
boxed_circuit = boxes_pm.run(isa_circuit)

# 2. Build the (template circuit, samplex) pair.
#    The template circuit's single-qubit gates are replaced by parameterized gates;
#    the samplex encodes how to generate the randomized parameters at runtime.
template_circuit, samplex = build(boxed_circuit)

# 3. Append as a samplex item, specifying the number of randomizations
program = QuantumProgram(shots=1024)
program.append_samplex_item(
    template_circuit,
    samplex=samplex,
    samplex_arguments={
        "parameter_values": np.random.rand(10, 2),  # original circuit params
    },
    shape=(28, 10),  # 28 randomizations x 10 parameter sets
)

Poiché il circuito modello e il samplex vengono generati sul lato client, è possibile esaminarli e campionarli localmente per verificare l'output prima di inviare qualsiasi cosa all' hardware.

Verifica: testare il circuito modello in locale

È possibile estrarre valori casuali dal samplex e associarli al circuito modello per verificare che il samplex stia generando i valori dei parametri previsti. I valori dei parametri restituiti da samplex.sample sono direttamente compatibili con i parametri del circuito modello.

# Check which inputs the samplex requires (for the twirling example above,
# this is just the original circuit's parameter values).
print(samplex.inputs())

# Bind the required inputs, then draw a few randomizations locally.
inputs = samplex.inputs().bind(
    parameter_values=np.random.rand(2),  # one set of the original circuit's params
)
outputs = samplex.sample(inputs, num_randomizations=3)

# Assign one randomization's parameter values to the template circuit and inspect it.
bound_template = template_circuit.assign_parameters(outputs["parameter_values"][0])
bound_template.draw("mpl", idle_wires=False)

Per approfondire, è possibile verificare che ogni randomizzazione sia logicamente equivalente al circuito originale, ad esempio convertendo entrambi in oggetti Operator e confrontando le loro implementazioni unitarie (dopo aver tenuto conto delle outputs["measurement_flips.<register>"] correzioni che annullano l’effetto della rotazione da misurazione), oppure confrontando i valori attesi ottenuti da un’esecuzione locale StatevectorSampler o da StatevectorEstimator un’esecuzione. Per una guida completa, consulta la guida agli ingressi e alle uscite di Samplomatic Samplex.

Passo 4. Modifica le modalità di richiesta delle riprese

Sposta le immagini dall' PUB a a QuantumProgram(shots=...). In Executor, si shots applica all'intero processo. Invia più lavori se hai bisogno di un numero diverso di scatti.

Esempio:

# Run — shots are passed to run()
sampler = Sampler(mode=backend)
job = sampler.run([(isa_circuit, None, 25)])

Esecutore testamentario:

# Build a QuantumProgram — shots are on the program
program = QuantumProgram(shots=25)
program.append_circuit_item(isa_circuit)

Passo 5. Aggiornare le opzioni secondo necessità

Le opzioni disponibili per Executor sono meno numerose rispetto a quelle di Sampler, poiché le impostazioni relative alla mitigazione degli errori si trovano ora nelle annotazioni e in samplex anziché nelle opzioni.

Esiste inoltre una differenza strutturale relativa alla posizione in cui si trovano le impostazioni.

  • Con Sampler, tutto, comprese le impostazioni che influenzano la post-elaborazione dei risultati, viene configurato nelle opzioni della primitiva o nel file “ PUB ”.

  • Con Executor, le impostazioni che influenzano il modo in cui i risultati del lavoro vengono definiti e sottoposti a post-elaborazione vengono configurate su QuantumProgram, non su ExecutorOptions.

Esempi:

Campionatore
Esecutore
shotsQuantumProgram(shots=...)
meas_typeQuantumProgram(meas_level=...)

ExecutorOptions contiene solo impostazioni di esecuzione e di ambiente di livello inferiore che non modificano la struttura dei dati restituiti. Comprende tre gruppi di primo livello:

In particolare, le opzioni dynamical_decoupling e twirling sono presenti in Sampler ma non in Executor. Tali valori delle opzioni vengono invece espressi attraverso il modello di esecuzione diretta.

Esempio:

from qiskit_ibm_runtime import Executor, ExecutorOptions

options = ExecutorOptions(
    environment={"log_level": "INFO"},
    execution={"init_qubits": True},
)
# or mutate after construction:
options = ExecutorOptions()
options.environment.log_level = "INFO"
options.execution.init_qubits = True

executor = Executor(mode=backend, options=options)

Fase 6. Aggiorna il comando run

L'input di un processo Executor è il programma, anziché i PUB.

Esempio:

# Submit a job
sampler.run([(isa_circuit, parameter_values)])

Esecutore testamentario:

# Submit a job
executor.run(program)

Passo 7. Modifica le modalità di visualizzazione dei risultati

In Executor, i risultati sono array di tipo NumPy, non BitArray oggetti. Utilizza la stringa del nome come indice (result[0]["meas"]) e ottieni un np.ndarray come risultato. Non è necessario ricordare il percorso dell'attributo .data.<register> .

Per passare da Sampler a Executor, sostituire result[i].data.<reg> (BitArray) con result[i]["<reg>"] (np.ndarray), quindi riscrivere le operazioni di post-elaborazione get_countsbasate su - come operazioni NumPy.

Attività
Campionatore
Esecutore
Recupera i dati di registrazioneresult[0].data.measresult[0]["meas"]
Tipo di datiBitArraynp.ndarray
Dizionario dei conteggiresult[0].data.meas.get_counts()Elaborare manualmente l'array
Registri multipliresult[0].data.<name> per registroresult[0]["<name>"] per registro
CircuitItem forma dell'array-(parameter_sets, shots, register_bits)
SamplexItem forma dell'array-(randomizations, parameter_sets, shots, register_bits)
Annulla la rotazione della misurazioneAutomaticoresult[i]["measurement_flips.<name>"] + XOR
Note

Sampler's BitArray offre strumenti di supporto (get_counts, slice_bits, slice_shots, expectation_values, e maschere post-selezione). Executor restituisce array " NumPy " non elaborati, in modo da poter eseguire questa post-elaborazione con le operazioni standard di " NumPy ".

Passaggio 8. Gestione dei risultati alterati (correzioni di bit invertiti)

Quando si applica la rotazione delle misurazioni tramite un SamplexItem, Executor restituisce le misurazioni grezze (rotate) insieme alle correzioni di inversione di bit necessarie per annullare la rotazione. È necessario applicarle manualmente; non viene corretta nulla in modo automatico.

Quando si utilizza Executor, annullare esplicitamente il twirling utilizzando le correzioni measurement_flips.<reg> e un'operazione XOR, come illustrato nell'esempio seguente:

# SamplexItem result shape: (randomizations, parameter_sets, shots, register_bits)
result_1 = result[1]["meas"]                       # example: (28, 10, 1024, 2)

# Bit-flip corrections to undo measurement twirling
flips_1 = result[1]["measurement_flips.meas"]      # example: (28, 10, 1, 2)

# Undo the twirling through classical XOR (broadcasts over the shots axis)
unflipped_result_1 = result_1 ^ flips_1

In Sampler non esiste un'operazione equivalente, poiché il programma annulla automaticamente l'effetto "twirling".


Esempio completo: migrazione di un processo di campionamento di base

Campionatore

import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler

# 1. Account + backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# 2. Circuit
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.measure_all()

# 3. Transpile to ISA
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)

# 4. Run — shots are passed to run()
sampler = Sampler(mode=backend)
job = sampler.run([(isa_circuit,)], shots=25)
result = job.result()

# 5. Access results: a BitArray keyed by register name
counts = result[0].data.meas.get_counts()

Esecutore

import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram

# 1. Account + backend (unchanged)
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# 2. Circuit (unchanged)
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.measure_all()

# 3. Transpile to ISA (unchanged)
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)

# 4. Build a QuantumProgram — shots are on the program
program = QuantumProgram(shots=25)
program.append_circuit_item(isa_circuit)

# 5. Run
executor = Executor(mode=backend)
job = executor.run(program)
result = job.result()

# 6. Access results: a plain np.ndarray keyed by register name
#    shape = (shots, register_bits)
meas = result[0]["meas"]

Passi successivi

Questa pagina è stata utile?
Segnala un bug, un errore di battitura o richiedi contenuti su GitHub.