Skip to main content
IBM Quantum Platform

QESEM: una funzione Qiskit di Qedma

Consulta la documentazione dell'API

  • Il codice presente in questa pagina è stato sviluppato tenendo conto dei seguenti requisiti. Si consiglia di utilizzare queste versioni o quelle più recenti.

    qiskit[all]~=2.5.0
    qiskit-ibm-runtime~=0.47.0
    
Nota

Le funzioni Qiskit sono una funzione sperimentale disponibile solo per gli utenti di IBM Quantum® Premium Plan, Flex Plan e On-Prem (tramite IBM Quantum Platform API) Plan. Sono in stato di anteprima e sono soggetti a modifiche.


Panoramica

Sebbene le unità di elaborazione quantistica siano notevolmente migliorate negli ultimi anni, gli errori dovuti al rumore e alle imperfezioni dell'hardware esistente rimangono una sfida centrale per gli sviluppatori di algoritmi quantistici. Man mano che il settore si avvicina a calcoli quantistici su scala industriale che non possono essere verificati in modo classico, le soluzioni per eliminare il rumore con una precisione garantita stanno diventando sempre più importanti. Per superare questa sfida, Qedma ha sviluppato Quantum Error Mitigation (QESEM), perfettamente integrato su IBM Quantum Platform come funzione Qiskit.

Con QESEM, gli utenti possono eseguire i propri circuiti quantistici su QPU soggette a rumore per ottenere risultati altamente accurati e privi di errori, con tempi di elaborazione della QPU estremamente efficienti, vicini ai limiti fondamentali. A tal fine, QESEM si avvale di una suite di metodi proprietari sviluppati da Qedma per la caratterizzazione e la riduzione degli errori. Le tecniche di riduzione degli errori comprendono l'ottimizzazione dei gate, la transpilazione sensibile al rumore, la soppressione degli errori (ES) e la mitigazione imparziale degli errori (EM). Grazie alla combinazione di questi metodi basati sulla caratterizzazione, gli utenti possono ottenere risultati affidabili e privi di errori per circuiti quantistici generici di grandi dimensioni, aprendo la strada ad applicazioni che altrimenti non sarebbero realizzabili.

Per una descrizione completa dei componenti sottostanti, nonché una dimostrazione su scala industriale, consultare il documento Reliable high-accuracy error mitigation for utility-scale quantum circuits (Mitigazione affidabile e altamente accurata degli errori per circuiti quantistici su scala industriale).


Descrizione

È possibile utilizzare la funzione QESEM di Qedma per stimare ed eseguire facilmente i circuiti con la soppressione e la mitigazione degli errori, ottenendo volumi di circuiti più grandi e precisioni più elevate. Per utilizzare il QESEM, si fornisce un circuito quantistico, una serie di osservabili da misurare, un obiettivo di precisione statistica per ogni osservabile e una QPU scelta. Prima di eseguire il circuito con la precisione desiderata, è possibile stimare il tempo richiesto dalla QPU in base a un calcolo analitico che non richiede l'esecuzione del circuito. Una volta soddisfatti della stima dei tempi di QPU, è possibile eseguire il circuito con QESEM.

Quando si esegue un circuito, QESEM esegue un protocollo di caratterizzazione del dispositivo su misura per il circuito, fornendo un modello di rumore affidabile per gli errori che si verificano nel circuito. Sulla base della caratterizzazione, QESEM implementa innanzitutto una transpilazione sensibile al rumore per mappare il circuito di input su un insieme di qubit e gate fisici, riducendo al minimo il rumore che influenza l'osservabile target. Questi includono i gate disponibili in modo nativo (CX/CZ sui dispositivi IBM® ), nonché gate aggiuntivi ottimizzati da QESEM, che formano il set di gate esteso di QESEM. QESEM esegue quindi una serie di circuiti ES ed EM basati sulla caratterizzazione sulla QPU e raccoglie i risultati delle misurazioni. Questi vengono poi sottoposti a post-elaborazione classica per fornire un valore atteso non distorto e una barra di errore per ciascun osservabile, in corrispondenza con l'accuratezza richiesta.

Panoramica di Qedma QESEM

È stato dimostrato che il QESEM è in grado di fornire risultati di alta precisione per una varietà di applicazioni quantistiche e sui più grandi volumi di circuiti oggi realizzabili. QESEM offre le seguenti funzionalità rivolte all'utente, dimostrate nella sezione dei benchmark che segue:

  • Accuratezza garantita: QESEM fornisce stime imparziali dei valori attesi delle grandezze osservabili. Il suo metodo EM è dotato di garanzie teoriche che, insieme alla caratterizzazione all'avanguardia di Qedma, assicurano che la mitigazione converga verso l'uscita del circuito privo di rumore fino alla precisione specificata dall'utente. A differenza di molti metodi EM euristici che sono soggetti a errori sistematici o distorsioni, l'accuratezza garantita di QESEM è essenziale per assicurare risultati affidabili nei circuiti quantistici generici e negli osservabili.
  • Scalabilità a QPU di grandi dimensioni: il tempo QPU di QESEM dipende dai volumi dei circuiti, ma è altrimenti indipendente dal numero di qubit. Qedma ha dimostrato QESEM sui più grandi dispositivi quantistici oggi disponibili, tra cui i dispositivi Eagle da 127 qubit e Heron da 133 qubit dell' IBM Quantum.
  • Indipendente dalle applicazioni: Il QESEM è stato dimostrato in diverse applicazioni, tra cui la simulazione hamiltoniana, VQE, QAOA e la stima dell'ampiezza. Gli utenti possono inserire qualsiasi circuito quantistico e osservabile da misurare e ottenere risultati precisi e privi di errori. Le uniche limitazioni sono dettate dalle specifiche hardware e dal tempo assegnato alla QPU, che determinano i volumi di circuito accessibili e le precisioni di uscita. Al contrario, molte soluzioni per la riduzione degli errori sono specifiche per l'applicazione o coinvolgono euristiche non controllate, rendendole inapplicabili a circuiti e applicazioni quantistiche generiche.
  • Set di gate esteso: QESEM supporta gate ad angolo frazionario e fornisce gate QEDMA ottimizzati ad angolo frazionario Rzz(θ)Rzz(\theta) sui dispositivi IBM Quantum Heron e Eagle. Questo set di gate esteso consente una compilazione più efficiente e sblocca volumi di circuiti fino a 2 volte superiori rispetto alla compilazione CX/CZ predefinita.
  • Osservabili multibase: QESEM supporta osservabili in ingresso composte da molte stringhe di Pauli non comunicanti, come gli hamiltoniani generici. La scelta delle basi di misura e l'ottimizzazione dell'allocazione delle risorse della QPU (scatti e circuiti) viene quindi eseguita automaticamente da QESEM per ridurre al minimo il tempo richiesto dalla QPU per la precisione richiesta. Questa ottimizzazione, che tiene conto delle fedeltà hardware e delle velocità di esecuzione, consente di eseguire circuiti più profondi e di ottenere precisioni più elevate.

Benchmark

QESEM è stato testato su un'ampia gamma di casi d'uso e applicazioni. I seguenti esempi possono aiutare a valutare quali tipi di carichi di lavoro è possibile eseguire con QESEM.

Una cifra di merito fondamentale per quantificare la durezza della mitigazione degli errori e della simulazione classica per un determinato circuito e osservabile è il volume attivo : il numero di porte CNOT che influenzano l'osservabile nel circuito. Il volume attivo dipende dalla profondità e dalla larghezza del circuito, dal peso dell'osservabile e dalla struttura del circuito, che determina il cono di luce dell'osservabile. Per ulteriori dettagli, si veda l'intervento del 2024 IBM Quantum Summit. Il QESEM fornisce un valore particolarmente elevato nel regime ad alto volume, fornendo risultati affidabili per circuiti e osservabili generici.

Volume attivo
Applicazione
Numero di qubit
Periferica
Descrizione del circuito
Accuratezza
Tempo totale
Utilizzo del tempo di esecuzione
Circuito VQE8Aquila ( r3 )21 strati totali, 9 basi di misura, 1D catena98%35 min14 min
Calciomercato Ising28Aquila ( r3 )3 strati unici x 3 passi, 2D topologia heavy-hex97%22 min4 min
Calciomercato Ising28Aquila ( r3 )3 strati unici x 8 passi, 2D topologia heavy-hex97%116 min23 min
Simulazione hamiltoniana trotterizzata40Aquila ( r3 )2 strati unici x 10 passi di Trotter, 1D catena97%3 ore25 min
Simulazione hamiltoniana trotterizzata119Aquila ( r3 )3 strati unici x 9 passi di Trotter, 2D topologia heavy-hex95%6.5 ore45 min
Calciomercato Ising136Airone ( r2 )3 strati unici x 15 passi, 2D topologia heavy-hex99%52 min9 min

La precisione viene misurata rispetto al valore ideale dell'osservabile: OidealϵOideal\frac{\langle O \rangle_{ideal} - \epsilon}{\langle O \rangle_{ideal}}, dove ' ϵ\epsilon ' è la precisione assoluta dell'attenuazione (impostata dall'input dell'utente) e Oideal\langle O \rangle_{ideal} è l'osservabile al circuito senza rumore. 'Runtime usage' misura l'uso del benchmark in modalità batch (somma dell'uso dei singoli lavori), mentre 'total time' misura l'uso in modalità sessione (experiment wall time), che include tempi classici e di comunicazione aggiuntivi. QESEM è disponibile per l'esecuzione in entrambe le modalità, in modo che gli utenti possano sfruttare al meglio le risorse disponibili.

I circuiti Ising a 28 qubit simulano il Quasicristallo a tempo discreto studiato da Shinjo et al. (cfr arXiv 2403.16718 e Q2B24 Tokyo ) su tre anelli connessi di ibm_kawasaki. I parametri del circuito presi in considerazione sono (θx,θz)=(0.9π,0)(\theta_x, \theta_z) = (0.9 \pi, 0), con uno stato iniziale ferromagnetico ψ0=0n| \psi_0 \rangle = | 0 \rangle ^{\otimes n}. L'osservabile misurato è il valore assoluto della magnetizzazione M=128i=027ZiM = |\frac{1}{28} \sum_{i=0}^{27} \langle Z_i \rangle|. L'esperimento di Kicked Ising su scala utility è stato eseguito sui 136 migliori qubit di ibm_fez; questo particolare benchmark è stato eseguito all'angolo di Clifford (θx,θz)=(π,0)(\theta_x, \theta_z) = (\pi, 0), al quale il volume attivo cresce lentamente con la profondità del circuito, il che, insieme all'elevata fedeltà del dispositivo, consente di ottenere un'elevata precisione con un breve tempo di esecuzione.

I circuiti di simulazione hamiltoniana trotterizzata sono per un modello Ising a campo trasverso con angoli frazionari: (θzz,θx)=(π/4,π/8)(\theta_{zz}, \theta_x) = (\pi / 4, \pi /8) e (θzz,θx)=(π/6,π/8)(\theta_{zz}, \theta_x) = (\pi / 6, \pi / 8) corrispondenti (vedi Q2B24 Tokyo ). Il circuito utility-scale è stato eseguito sui 119 migliori qubit di ibm_brisbane, mentre l'esperimento a 40 qubit è stato eseguito sulla migliore catena disponibile. L'accuratezza è riportata per la magnetizzazione; risultati di alta precisione sono stati ottenuti anche per osservabili di peso superiore.

Il circuito VQE è stato sviluppato insieme ai ricercatori del Center for Quantum Technology and Applications del Deutsches Elektronen-Synchrotron (DESY). L'osservabile target in questo caso era un'hamiltoniana costituita da un gran numero di stringhe di Pauli non comunicanti, sottolineando le prestazioni ottimizzate di QESEM per le osservabili multi-base. La mitigazione è stata applicata a un'ipotesi di ottimizzazione classica; sebbene questi risultati siano ancora inediti, si otterranno risultati della stessa qualità per circuiti diversi con proprietà strutturali simili.


Introduzione

Autenticati utilizzando la tua chiave API IBM Quantum Platform e seleziona la funzione QESEM Qiskit come segue. (Questo frammento di codice presuppone che tu abbia già salvato il tuo account nell'ambiente locale.)

import qiskit
from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# verify that you have access to the function
catalog.list()
# load the function
qesem_function = catalog.load("qedma/qesem")

Esempi

Esempio di lavoro di stima dei tempi

Il processo di stima del tempo è utile per stimare il tempo di elaborazione richiesto dalla QPU per un dato pub e backend_name. backend_name può anche essere impostato su qualsiasi backend del simulatore; ad esempio, fake_fez.

QESEM utilizza un metodo EM quasi-probabilistico basato sulla caratterizzazione. Questo metodo comporta un sovraccarico di tempo della QPU che varia approssimativamente secondo la seguente relazione:

TQPU=aeαIFVaϵ2+bT_{QPU} = a \frac{e^{\alpha IF\cdot V_a}}{\epsilon^2} + b

Dove VaV_a è il volume attivo del circuito, ϵ\epsilon è la precisione desiderata e IFIF è l’infedeltà dei gate nativi.

Si noti che "estimate_time_only": "empirical" impiega alcuni minuti di tempo QPU per stimare il tempo necessario per l'esecuzione del processo (se il backend è un dispositivo reale; se invece si tratta di un simulatore, non viene utilizzato alcun tempo QPU). Di solito ci vogliono circa 5 minuti, ma non più di 10 minuti. Se l'infedeltà varia drasticamente tra l'operazione di stima empirica dei tempi e quella di mitigazione, anche il tempo di elaborazione della QPU subirà una variazione drastica.

Per iniziare, provate questo esempio di base per stimare il tempo necessario alla QPU per eseguire QESEM per un dato pub:

backend_name = "fake_fez"

circ = qiskit.QuantumCircuit(5)
circ.cx(0, 1)
circ.cx(2, 3)
circ.cx(1, 2)
circ.cx(3, 4)

avg_magnetization = qiskit.quantum_info.SparsePauliOp.from_sparse_list(
    [("Z", [q], 1 / 5) for q in range(5)], num_qubits=5
)
other_observable = qiskit.quantum_info.SparsePauliOp.from_sparse_list(
    [("ZZ", [0, 1], 1.0), ("XZ", [1, 4], 0.5)], num_qubits=5
)

time_estimation_job = qesem_function.run(
    pubs=[(circ, [avg_magnetization, other_observable])],
    options={
        "estimate_time_only": "empirical",
    },
    backend_name=backend_name,  # example: "fake_fez", "ibm_fez"
)
time_estimate_result = (
    time_estimation_job.result()
)  # a list of results per pub (circuit)

Il seguente frammento di codice illustra come recuperare diverse metriche di esecuzione dal processo di stima dei tempi (estimate_time_only è impostato):

pub_result = time_estimate_result[0]

print(
    f"The estimated QPU time for mitigation for this PUB is: {pub_result.metadata['time_estimation_sec']}"
)
print(
    f"The QPU time that this time estimation job took is (here it is 0 because we used fake_fez): {pub_result.metadata['total_qpu_time']}"
)
print(
    f"Gates fidelity measured during the experiment: {pub_result.metadata['gate_fidelities']}"
)
print(f"Total shots: {pub_result.metadata['total_shots']}")
print(f"Resource usage breakdown: {pub_result.metadata['resource_usage']}")

Output:

The estimated QPU time for mitigation for this PUB is: 300
The QPU time that this time estimation job took is (here it is 0 because we used fake_fez): 0
Gates fidelity measured during the experiment: {'CZ': 0.9951354916722668, 'ID1Q': 0.9991246627329172}
Total shots: 220000
Resource usage breakdown: {'RUNNING: MAPPING': {'CPU_TIME': 33.6066133165732, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU_TIME': 184.53575124032795, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: WAITING_FOR_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: EXECUTING_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: POST_PROCESSING': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}}

Quando è abilitata la stima empirica dei tempi, QESEM esegue un numero limitato di circuiti per fornire una stima più accurata dei tempi della QPU. I risultati relativi alla mitigazione ottenuti da questi circuiti sono disponibili nel empirical_estimation_mitigation_results campo del lavoro.

Poiché questi risultati derivano da un campione limitato di circuiti, sono notevolmente meno accurati rispetto ai risultati finali ottenuti dall'analisi completa di mitigazione QESEM. Tuttavia, quando il circuito è di piccole dimensioni o la precisione richiesta è bassa, la mitigazione effettuata durante la stima empirica dei tempi potrebbe essere sufficiente per raggiungere la precisione desiderata, e potrebbe non essere necessario eseguire l'intero processo di mitigazione.

Il empirical_estimation_mitigation_results campo è un elenco di PrimitiveResult oggetti per ciascun parametro di input. Se il circuito non è parametrizzato, la lista avrà lunghezza 1.

empirical_estimation_mitigation_results = time_estimate_result[0].metadata[
    "empirical_estimation_mitigation_results"
][0]  # a list per parameter
print("Partial results for the observables:")

print(
    f"    Mitigated expectation values: {empirical_estimation_mitigation_results.data.evs}"
)
print(
    f"    Mitigated error bars: {empirical_estimation_mitigation_results.data.stds}"
)
print(
    f"    Number of shots used for mitigation: {empirical_estimation_mitigation_results.metadata['mitigation_shots']}"
)
transpiled_circ = empirical_estimation_mitigation_results.metadata[
    "transpiled_circ"
]
print(f"    Qubit mapping: {transpiled_circ['qubit_maps']}")
print(
    f"    Number of measurement bases: {transpiled_circ['num_measurement_bases']}\n"
)

# results per obs
emp_obs_results = empirical_estimation_mitigation_results.metadata["results"][
    0
]
# print(f"Results for each observable: {results}")
print("Results for each observable:")

for i, (obs_array, result_dict) in enumerate(emp_obs_results):
    # obs_array, result_dict = results
    print(f"Observable {i+1}: {obs_array}")
    print(
        f"    QESEM mitigated value: {result_dict['qesem']['value']} \u00b1 {result_dict['qesem']['error_bar']}"
    )

Output:

Partial results for the observables:
    Mitigated expectation values: [1.00347302 1.00693905]
    Mitigated error bars: [0.00304061 0.00714276]
    Number of shots used for mitigation: 180000
    Qubit mapping: [[[0, 136], [1, 143], [2, 142], [3, 141], [4, 140]]]
    Number of measurement bases: 2

Results for each observable:
Observable 1: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
    QESEM mitigated value: 1.003473015776871 ± 0.0030406128032204015
Observable 2: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
    QESEM mitigated value: 1.0069390542613554 ± 0.0071427606736885925

Esempio di attività di mitigazione QESEM

L'esempio seguente esegue un lavoro QESEM:

sample_job = qesem_function.run(
    pubs=[(circ, [avg_magnetization, other_observable])],
    backend_name=backend_name,  # example: "ibm_fez"
    # options = {
    #     "estimate_time_only": "empirical",
    #     "default_precision": 0.2,  # Default precision is applied to all pubs that don't have a precision specified, see API reference for more details
    #     "max_execution_time": 3600,  # You can specify a maximum QPU time in seconds, see API reference for more details
    #     "transpilation_level": "standard",  # "minimal_with_layout_opt" for minimal transpilation, see API reference for more details
    #     "parallel_execution": True,  # True for parallel execution, see API reference for more details
    # },
)

Per una descrizione dettagliata di ciascun campo di immissione e di ciascuna opzione, consultare la guida di riferimento dell'API QESEM.

È possibile utilizzare le API Qiskit Serverless già note per controllare lo stato del carico di lavoro di Qiskit Function o per restituire i risultati:

# Print the ID so you can use it later, if necessary
print(sample_job.job_id)
print(sample_job.status())
sample_result = sample_job.result()

Output:

3ac6b2df-15b0-4dc0-8f48-cf14bd20a1c8
DONE

Il seguente frammento di codice mostra come recuperare i risultati delle misure di mitigazione e le metriche di esecuzione. Questi contengono dati essenziali che consentono di comprendere più a fondo in che modo i diversi parametri influenzano l'esecuzione del QESEM. Potrebbe inoltre rivelarsi utile quando si redige un articolo basato sulla propria ricerca.

for pub_idx, pub_result in enumerate(
    sample_result
):  # each element in the list is a result for a different pub, here we sent only one pub
    print(f"\nPUB {pub_idx}:")
    print(
        f"  The QPU time that this job took is (here it is 0 because we used fake_fez): {pub_result.metadata['total_qpu_time']}"
    )
    print(
        f"  Gates fidelity measured during the experiment: {pub_result.metadata['gate_fidelities']}"
    )
    print(f"  Total shots: {pub_result.metadata['total_shots']}")
    print(
        f"  Number of shots used for mitigation: {pub_result.metadata['mitigation_shots']}"
    )
    print(
        f"  Resource usage breakdown: {pub_result.metadata['resource_usage']}"
    )

Output:


PUB 0:
  The QPU time that this job took is (here it is 0 because we used fake_fez): 0.0
  Gates fidelity measured during the experiment: {'CZ': 0.9953704216147041, 'ID1Q': 0.9991834123567518}
  Total shots: 446000
  Number of shots used for mitigation: 194000
  Resource usage breakdown: {'RUNNING: MAPPING': {'CPU_TIME': 32.52745003718883, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU_TIME': 257.850521848537, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: WAITING_FOR_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: EXECUTING_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: POST_PROCESSING': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}}

In metadata["results"], i risultati vengono raggruppati prima per istanza di circuito e poi per grandezza osservabile.

print("Full QESEM mitigation results:")

for pub_idx, pub_result in enumerate(sample_result):
    print(f"\nPUB {pub_idx}:")

    print(f"  Mitigated expectation values: {pub_result.data.evs}")
    print(f"  Mitigated error bars: {pub_result.data.stds}")
    noisy_results = pub_result.metadata.get("noisy_results")
    print(f"  Unmitigated expectation values: {noisy_results.evs}")
    print(f"  Unmitigated error bars: {noisy_results.stds}")

    print("  Transpiled circuits:")
    for circ_idx, transpiled_circ in enumerate(
        pub_result.metadata["transpiled_circs"]
    ):
        print(f"    Circuit {circ_idx}:")
        # print(f"      Circuit: \n {transpiled_circ['circuit']}") # not printing it because it's long but you can see the transpiled circuit itself
        print(f"      Qubit mapping: {transpiled_circ['qubit_maps']}")
        print(
            f"      Measurement bases: {transpiled_circ['num_measurement_bases']}"
        )

    print("  Results for each observable:")
    for circ_idx, circ_results in enumerate(pub_result.metadata["results"]):
        print(f"    Circuit {circ_idx}:")
        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):
            print(f"      Observable {obs_idx}: {obs_array}")
            print(
                f"        QESEM mitigated value: {result_dict['qesem']['value']} ± {result_dict['qesem']['error_bar']}"
            )
            print(
                f"        Unmitigated value: {result_dict['unmitigated']['value']} ± {result_dict['unmitigated']['error_bar']}"
            )

Output:

Full QESEM mitigation results:

PUB 0:
  Mitigated expectation values: [1.00648343 1.00636289]
  Mitigated error bars: [0.00253812 0.00693586]
  Unmitigated expectation values: [0.98031429 0.96357143]
  Unmitigated error bars: [0.00124128 0.00578812]
  Transpiled circuits:
    Circuit 0:
      Qubit mapping: [[[0, 140], [1, 141], [2, 142], [3, 143], [4, 136]]]
      Measurement bases: 2
  Results for each observable:
    Circuit 0:
      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
        QESEM mitigated value: 1.0064834305181962 ± 0.002538119914534849
        Unmitigated value: 0.9803142857142859 ± 0.0012412835813609938
      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
        QESEM mitigated value: 1.0063628870614818 ± 0.006935859820870656
        Unmitigated value: 0.9635714285714285 ± 0.005788121870526659

Ripartizione dei risultati principali:

  • mitigated: il valore atteso del QESEM completamente mitigato.
  • unmitigated: il risultato grezzo relativo al rumore fisico senza mitigazione degli errori.

Risultati dell'estrapolazione euristica QESEM

In un'esecuzione standard del QESEM con un singolo precision galleggiante, i risultati includono anche punti di scalatura del rumore disponibili automaticamente, utilizzati per l'euristica del QESEM. Questi punti vengono calcolati senza ricorrere a risorse QPU aggiuntive.

La scala 1.0 rappresenta il livello di rumore del dispositivo fisico con mitigazione della lettura (REM), mentre la scala 2.0 corrisponde al punto complementare con amplificazione del rumore, anch’esso con REM. Questi punti vengono utilizzati per ottenere il qesem_heuristic risultato.

  • qesem_heuristic: una stima in stile ZNE calcolata sulla base dei dati disponibili, corretti in funzione del rumore. Attualmente, questo metodo utilizza l'estrapolazione esponenziale.
  • noise_scaling.results_with_REM: valori attesi a diverse scale di rumore, tutti con mitigazione della lettura (REM).

Un dettaglio sottile ma importante è che il risultato della scala 1.0 non coincide con il unmitigated risultato. Entrambi corrispondono al livello di rumore del dispositivo fisico, ma il punto di scala 1.0 tiene conto della mitigazione del rumore di lettura, mentre unmitigated no.

print("QESEM heuristic results:")

for pub_idx, pub_result in enumerate(sample_result):
    print(f"\nPUB {pub_idx}:")
    for circ_idx, circ_results in enumerate(pub_result.metadata["results"]):
        print(f"  Circuit {circ_idx}:")
        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):
            print(f"    Observable {obs_idx}: {obs_array}")
            qesem_heuristic = result_dict["qesem_heuristic"][0]
            print("      QESEM heuristic:")
            print(
                f"        Value: {qesem_heuristic['value']} ± {qesem_heuristic['error_bar']}"
            )
            print(
                f"        Extrapolation: {qesem_heuristic['extrapolation']}"
            )
            print(
                f"        Scale factors: {qesem_heuristic['scale_factors']}"
            )
            noise_scaling = result_dict["noise_scaling"]
            print("      Noise scaling results:")
            print(
                f"        Scaling method: {noise_scaling['scaling_method']}"
            )
            print("        Results with Readout mitigation (REM):")
            for rem_result in sorted(
                (
                    item
                    for item in noise_scaling["results_with_REM"]
                    if item["scale"] != 0.0
                ),
                key=lambda item: item["scale"],
            ):
                print(
                    f"          Scale factor {rem_result['scale']}: {rem_result['value']} ± {rem_result['error_bar']}"
                )

Output:

QESEM heuristic results:

PUB 0:
  Circuit 0:
    Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
      QESEM heuristic:
        Value: 1.0008161638888535 ± 0.0038859458884403964
        Extrapolation: exponential
        Scale factors: [1.0, 2.0]
      Noise scaling results:
        Scaling method: QESEM
        Results with Readout mitigation (REM):
          Scale factor 1.0: 0.9918395459270772 ± 0.0012565417579355634
          Scale factor 2.0: 0.982943441922748 ± 0.0028919278067695018
    Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
      QESEM heuristic:
        Value: 0.9960853148925298 ± 0.013811635038961175
        Extrapolation: exponential
        Scale factors: [1.0, 2.0]
      Noise scaling results:
        Scaling method: QESEM
        Results with Readout mitigation (REM):
          Scale factor 1.0: 0.9902860583785115 ± 0.005921236914723409
          Scale factor 2.0: 0.984520565414274 ± 0.006909522262347639
Note

Gli esempi che seguono si concentrano su input e risultati specifici per ciascuna funzionalità, pertanto non riportano ogni volta tutte le metriche di esecuzione. I metadati di primo livello mostrati in precedenza, quali tempo_totale_qpu, gate_fidelities, numero_totale_di_tiri, misure di mitigazione e utilizzo_delle_risorse, sono disponibili anche per questi lavori.

Per motivi di concisione, alcune variabili degli esempi precedenti, tra cui il backend, gli osservabili e i parametri del circuito di base, vengono riutilizzate di seguito.

Note

Tutti gli esempi riportati di seguito possono essere eseguiti anche con una stima empirica del tempo. Per abilitarla, passare <code>"estimate_time_only": "empirico"</code> nelle opzioni della funzione.

Esempio di circuito parametrizzato

Molti algoritmi valutano lo stesso circuito con diversi valori dei parametri. L'invio del circuito parametrizzato come unico processo QESEM consente a QESEM di condividere la caratterizzazione e la calibrazione tra le diverse istanze del circuito, il che può ridurre il sovraccarico in termini di tempo di elaborazione della QPU rispetto all'esecuzione di processi separati.

Per inviare un circuito parametrizzato è necessario utilizzare il "minimal_with_layout_opt" livello di transpilazione. I circuiti inviati a questo livello dovrebbero già essere espressi utilizzando i gate di base del backend, a seconda del backend stesso. A questo livello, QESEM mantiene la struttura inviata il più vicina possibile al circuito di input, rispetta le barriere durante la stratificazione (raggruppando le operazioni in strati di porte parallele a due qubit) e gestisce comunque automaticamente la mappatura hardware su qubit ad alta fedeltà e la connettività dei dispositivi.

In pratica, ciò significa che prima dell'invio è necessario trasporre i circuiti nelle porte di base del backend di destinazione. Di seguito è riportato un semplice esempio di trasposizione di un gate di base.

Attualmente QESEM supporta un solo osservabile per ogni set di parametri. Le due righe di parametri riportate di seguito sono associate ai due osservabili: la prima riga viene misurata con avg_magnetization, mentre la seconda riga viene misurata con other_observable.

# Transpile to the backend basis gates only. With minimal_with_layout_opt, QESEM handles hardware mapping/connectivity and observable layout internally.
from qiskit_ibm_runtime.fake_provider import FakeFez

backend = FakeFez()
basis = backend.operation_names
print(basis)

param0 = qiskit.circuit.Parameter("param0")
param1 = qiskit.circuit.Parameter("param1")
parametrized_circ = qiskit.QuantumCircuit(5)
parametrized_circ.rx(param0, 0)
parametrized_circ.rx(param1, 1)
parametrized_circ.cx(0, 1)
parametrized_circ.cx(2, 3)
parametrized_circ.cx(1, 2)
parametrized_circ.cx(3, 4)

parametrized_circ = qiskit.transpile(
    parametrized_circ, basis_gates=basis, optimization_level=1
)
parametrized_parameter_values = [[0.5, 0.1], [0.0, 0.6]]
parametrized_observables = [avg_magnetization, other_observable]

parametrized_job = qesem_function.run(
    pubs=[
        (
            parametrized_circ,
            parametrized_observables,
            parametrized_parameter_values,
            0.1,
        )
    ],
    backend_name=backend_name,
    options={
        "max_execution_time": 300,
        "transpilation_level": "minimal_with_layout_opt",
    },
)
print(parametrized_job.job_id)
print(parametrized_job.status())

Output:

d1b0e29b-196c-4896-aec6-44a268ebd874
DONE
parametrized_result = parametrized_job.result()
print("Parameterized circuit QESEM results:")

for pub_idx, pub_result in enumerate(parametrized_result):
    print(f"\nPUB {pub_idx}:")
    print(f"  Mitigated expectation values: {pub_result.data.evs}")
    print(f"  Mitigated error bars: {pub_result.data.stds}")
    noisy_results = pub_result.metadata["noisy_results"]
    print(f"  Unmitigated expectation values: {noisy_results.evs}")
    print(f"  Unmitigated error bars: {noisy_results.stds}")
    print("  Results for each parameter value:")
    for param_idx, param_results in enumerate(pub_result.metadata["results"]):
        print(
            f"    Parameter set {param_idx}: {parametrized_parameter_values[param_idx]}"
        )
        for obs_idx, (obs_array, result_dict) in enumerate(param_results):
            print(f"      Observable {obs_idx}: {obs_array}")
            print(
                f"        QESEM mitigated value: {result_dict['qesem']['value']} ± {result_dict['qesem']['error_bar']}"
            )
            print(
                f"        Unmitigated value: {result_dict['unmitigated']['value']} ± {result_dict['unmitigated']['error_bar']}"
            )

Output:

Parameterized circuit QESEM results:

PUB 0:
  Mitigated expectation values: [0.92392021 0.82517653]
  Mitigated error bars: [0.00565281 0.00616016]
  Unmitigated expectation values: [0.9028     0.78771429]
  Unmitigated error bars: [0.00335142 0.00925413]
  Results for each parameter value:
    Parameter set 0: [0.5, 0.1]
      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
        QESEM mitigated value: 0.923920210615709 ± 0.005652811570890183
        Unmitigated value: 0.9028 ± 0.0033514176105045447
    Parameter set 1: [0.0, 0.6]
      Observable 0: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
        QESEM mitigated value: 0.8251765289285893 ± 0.006160161743353999
        Unmitigated value: 0.7877142857142858 ± 0.009254130564027902

Esempio con più pub

L'esecuzione multi-pub è utile quando si desidera eseguire diversi circuiti correlati in un unico processo QESEM. Come nel caso dell'esecuzione parametrizzata, ciò può ridurre il sovraccarico, poiché QESEM è in grado di condividere la caratterizzazione e la calibrazione tra le diverse istanze del circuito, anziché ripeterle in processi separati.

Ciò risulta particolarmente utile per i circuiti con una struttura a livelli condivisi, come i carichi di lavoro di tipo Trotter, in cui circuiti diversi riutilizzano gli stessi livelli univoci. In tal caso, eseguirle contemporaneamente può ridurre i costi di caratterizzazione rispetto a sessioni QESEM indipendenti.

I lavori che prevedono la pubblicazione su più testate richiedono "transpilation_level": "minimal_with_layout_opt". Come nell'esempio parametrizzato, prima dell'invio i circuiti devono essere transpilati nei gate di base del backend di destinazione. QESEM gestisce quindi internamente la connettività dei dispositivi, il layout e la mappatura ai qubit ad alta fedeltà.

Ogni PUB riportato di seguito contiene un circuito e gli stessi due osservabili utilizzati in precedenza nel notebook, quindi il risultato restituito PrimitiveResult contiene un PubResult per ogni circuito di input.

L'esempio riportato di seguito utilizza due semplici circuiti di Trotter con lo stesso schema di strati: circ_a presenta uno strato di Trotter, mentre circ_b ripete lo stesso schema di strati due volte. In questo modo la struttura condivisa risulta esplicita.

def make_trotter_circuit(num_qubits, num_layers, zz_angle=0.2, x_angle=0.1):
    trotter_circ = qiskit.QuantumCircuit(num_qubits)
    for _ in range(num_layers):
        for q in range(num_qubits):
            trotter_circ.rx(x_angle, q)
        trotter_circ.barrier()
        for q in range(0, num_qubits - 1, 2):
            trotter_circ.rzz(zz_angle, q, q + 1)
        trotter_circ.barrier()
        for q in range(1, num_qubits - 1, 2):
            trotter_circ.rzz(zz_angle, q, q + 1)
        trotter_circ.barrier()
    return trotter_circ


circ_a = make_trotter_circuit(num_qubits=5, num_layers=1)
circ_b = make_trotter_circuit(num_qubits=5, num_layers=2)
multi_pubs = [
    (
        qiskit.transpile(qci, basis_gates=basis, optimization_level=1),
        [avg_magnetization, other_observable],
    )
    for qci in [circ_a, circ_b]
]

multi_circ_job = qesem_function.run(
    pubs=multi_pubs,
    backend_name=backend_name,
    options={
        "max_execution_time": 300,
        "transpilation_level": "minimal_with_layout_opt",
        "default_precision": 0.1,
    },
)
print(multi_circ_job.job_id)
print(multi_circ_job.status())

Output:

e34565b8-7262-4133-a120-de42ce624a99
DONE
multi_circ_result = multi_circ_job.result()
print("Multi-pub QESEM results:")

for pub_idx, pub_result in enumerate(multi_circ_result):
    print(f"\nPUB {pub_idx}:")
    print(f"  Mitigated expectation values: {pub_result.data.evs}")
    print(f"  Mitigated error bars: {pub_result.data.stds}")
    noisy_results = pub_result.metadata["noisy_results"]
    print(f"  Unmitigated expectation values: {noisy_results.evs}")
    print(f"  Unmitigated error bars: {noisy_results.stds}")
    print("  Results for each observable:")
    for circ_idx, circ_results in enumerate(pub_result.metadata["results"]):
        print(f"    Circuit {circ_idx}:")
        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):
            print(f"      Observable {obs_idx}: {obs_array}")
            print(
                f"        QESEM mitigated value: {result_dict['qesem']['value']} ± {result_dict['qesem']['error_bar']}"
            )
            print(
                f"        Unmitigated value: {result_dict['unmitigated']['value']} ± {result_dict['unmitigated']['error_bar']}"
            )

Output:

Multi-pub QESEM results:

PUB 0:
  Mitigated expectation values: [0.99502406 1.02209332]
  Mitigated error bars: [0.00483819 0.00707488]
  Unmitigated expectation values: [0.96934286 0.97271429]
  Unmitigated error bars: [0.00124855 0.00617294]
  Results for each observable:
    Circuit 0:
      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
        QESEM mitigated value: 0.9950240647925642 ± 0.004838188086259301
        Unmitigated value: 0.9693428571428573 ± 0.0012485470362492692
      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
        QESEM mitigated value: 1.0220933230604674 ± 0.007074884384355636
        Unmitigated value: 0.9727142857142859 ± 0.006172939375512439

PUB 1:
  Mitigated expectation values: [0.98850017 1.02555188]
  Mitigated error bars: [0.0077912  0.01672652]
  Unmitigated expectation values: [0.93682857 0.95371429]
  Unmitigated error bars: [0.00156245 0.00665735]
  Results for each observable:
    Circuit 0:
      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
        QESEM mitigated value: 0.988500171577252 ± 0.007791203181151346
        Unmitigated value: 0.9368285714285716 ± 0.001562451883089579
      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
        QESEM mitigated value: 1.02555188098689 ± 0.016726524388086233
        Unmitigated value: 0.9537142857142858 ± 0.006657345655544263

Esempio di regolazione dell'errore quasi-probabilistica (QET)

Il Quasi-probabilistic Error Tuning (QET) richiede i valori attesi a determinati fattori di scala del rumore. Ciò risulta utile per studi personalizzati sul ridimensionamento del rumore e per i flussi di lavoro di estrapolazione a rumore zero. La scala 1.0 indica il livello fisico di rumore; i valori compresi tra 0.0 e 1.0 riducono parzialmente il rumore, mentre i valori superiori 1.0 a lo amplificano.

Per utilizzare QET con la funzione Qiskit, passare un dizionario come parametro " PUB " (precisione). Il dizionario associa a ciascuna scala di rumore richiesta la relativa precisione target. I risultati relativi al fattore di scala restituiti vengono memorizzati in noise_scaling.results_with_REM e includono la mitigazione della lettura. Il punto di scala 1.0 non è quindi identico al valore non corretto, poiché 1.0 il primo tiene conto della correzione di lettura mentre unmitigated il secondo no.

Quando viene richiesta una scala, QESEM restituisce anche la scala complementare intorno a 1.0 senza un utilizzo aggiuntivo della QPU. 0.7``1.5Ad esempio, la richiesta di 0.5 può restituire anche, e la richiesta di 1.3 può restituire anche. La precisione della scala complementare non è garantita.

noise_scale_precision = {0.5: 0.15, 1.3: 0.2}

qet_job = qesem_function.run(
    pubs=[
        (
            circ,
            [avg_magnetization, other_observable],
            None,
            noise_scale_precision,
        )
    ],
    backend_name=backend_name,
    options={"max_execution_time": 300},
)
print(qet_job.job_id)
print(qet_job.status())

Output:

8195fa58-f037-4651-8715-36ce1cdc5521
DONE
qet_result = qet_job.result()
print("QET noise-scaling results:")

for pub_idx, pub_result in enumerate(qet_result):
    print(f"\nPUB {pub_idx}:")
    noisy_results = pub_result.metadata["noisy_results"]
    print(f"  Unmitigated expectation values: {noisy_results.evs}")
    print(f"  Unmitigated error bars: {noisy_results.stds}")
    print("  Results for each observable:")
    for circ_idx, circ_results in enumerate(pub_result.metadata["results"]):
        print(f"    Circuit {circ_idx}:")
        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):
            print(f"      Observable {obs_idx}: {obs_array}")
            noise_scaling = result_dict["noise_scaling"]
            print(
                f"        Scaling method: {noise_scaling['scaling_method']}"
            )
            print("        Results with Readout mitigation (REM):")
            for rem_result in sorted(
                (
                    item
                    for item in noise_scaling["results_with_REM"]
                    if item["scale"] != 0.0
                ),
                key=lambda item: item["scale"],
            ):
                print(
                    f"          Scale factor {rem_result['scale']}: {rem_result['value']} ± {rem_result['error_bar']}"
                )

Output:

QET noise-scaling results:

PUB 0:
  Unmitigated expectation values: [0.97822857 0.96171429]
  Unmitigated error bars: [0.00123812 0.00672958]
  Results for each observable:
    Circuit 0:
      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
        Scaling method: QESEM
        Results with Readout mitigation (REM):
          Scale factor 0.5: 0.9938730340199383 ± 0.0032116907357568275
          Scale factor 0.7: 0.9963976191853445 ± 0.00036300258869586616
          Scale factor 1.0: 0.9898115079506586 ± 0.0012525947426560995
          Scale factor 1.3: 0.9864667065580341 ± 0.002633221613518526
          Scale factor 1.5: 0.9838755527197551 ± 0.002948417797996015
      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
        Scaling method: QESEM
        Results with Readout mitigation (REM):
          Scale factor 0.5: 1.0006538544450332 ± 0.002121742014777343
          Scale factor 0.7: 1.0004159801523036 ± 0.0021671375357823794
          Scale factor 1.0: 0.9898058846339917 ± 0.00690183710903159
          Scale factor 1.3: 0.9948946719997267 ± 0.002146532859610311
          Scale factor 1.5: 0.9927220368192772 ± 0.0020875057190323882

Recupera i messaggi di errore

Se lo stato del carico di lavoro è ERROR, utilizzare job.result() per recuperare il messaggio di errore come segue:

# Get the result and truncate for readability
result = sample_job.result()
result_str = str(result)
max_length = 500  # Adjust this value as necessary

if len(result_str) > max_length:
    truncated = (
        result_str[:max_length]
        + f"... (truncated {len(result_str) - max_length} characters)"
    )
else:
    truncated = result_str

print(truncated)

Output:

PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(2,), dtype=float64>), stds=np.ndarray(<shape=(2,), dtype=float64>), shape=(2,)), metadata={'gate_fidelities': {'CZ': 0.9979444718552628, 'ID1Q': 0.9991994239814883}, 'total_shots': 498600, 'mitigation_shots': 223400, 'transpiled_circs': [{'circuit': 'OPENQASM 3.0;\ninclude "stdgates.inc";\nbit[76] c0;\nqubit[76] q0;\nrx(0) q0[54];\nrx(0) q0[59];\nrx(0) q0[75];\nrz(pi/2) q0[54];\nrz(pi/2) q0[59];\nrz(pi/2) q0[75];\nrx(pi/2) q0[54];\nr... (truncated 3771 characters)

Ottenere supporto

Il team di supporto Qedma è qui per aiutarvi! Se riscontrate problemi o avete domande sull'utilizzo della funzione Qiskit di QESEM, non esitate a contattarci. Il nostro personale di assistenza, competente e cordiale, è pronto ad assistervi in caso di dubbi tecnici o richieste di informazioni.

Potete inviarci un'e-mail all'indirizzo [email protected] per ricevere assistenza. Si prega di includere quanti più dettagli possibili sul problema riscontrato per aiutarci a fornire una risposta rapida e accurata. Potete anche contattare il vostro rappresentante Qedma POC dedicato via e-mail o telefono.

Per aiutarci ad assistervi in modo più efficiente, vi preghiamo di fornire le seguenti informazioni quando ci contattate:

  • Una descrizione dettagliata del problema
  • L'ID lavoro
  • Eventuali messaggi o codici di errore rilevanti

Ci impegniamo a fornirvi un'assistenza rapida ed efficace per assicurarvi la migliore esperienza possibile con la nostra funzione Qiskit.

Siamo sempre alla ricerca di modi per migliorare il nostro prodotto e accogliamo con piacere i vostri suggerimenti! Se avete idee su come migliorare i nostri servizi o funzionalità che vorreste vedere implementate, inviateci i vostri suggerimenti all'indirizzo [email protected].


Passi successivi

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