Skip to main content
IBM Quantum Platform

Serializzazione QPY

qiskit.qpy

QPY è un formato di serializzazione binaria per gli oggetti QuantumCircuit progettato per essere multipiattaforma, agnostico rispetto alla versione di Python e compatibile con il futuro. QPY dovrebbe essere utilizzato se si ha bisogno di un meccanismo per salvare o copiare tra i sistemi un oggetto QuantumCircuit che conservi l'intera struttura dell'oggetto Qiskit (ad eccezione degli attributi personalizzati definiti al di fuori del codice Qiskit). Questo differisce da altri formati di serializzazione come OpenQASM ( 2.0 o 3.0 ) che ha un modello di astrazione diverso e può comportare una perdita di informazioni contenute nel circuito originale (o non è in grado di rappresentare alcuni aspetti degli oggetti Qiskit) o il pickle di Python che conserva esattamente l'oggetto Qiskit, ma funziona solo per una singola versione di Qiskit (è anche potenzialmente insicuro ).


Utilizzo di base

L'uso di QPY è definito come semplice e rispecchia l'API utente dei serializzatori della libreria standard di Python, pickle e json. Ci sono 2 funzioni rivolte all'utente: qiskit.qpy.dump() e qiskit.qpy.load() che servono rispettivamente a scaricare i dati QPY in un oggetto file e a caricare i circuiti dai dati QPY in un oggetto file. Ad esempio:

from qiskit.circuit import QuantumCircuit
from qiskit import qpy

qc = QuantumCircuit(2, name='Bell', metadata={'test': True})
qc.h(0)
qc.cx(0, 1)
qc.measure_all()

with open('bell.qpy', 'wb') as fd:
    qpy.dump(qc, fd)

with open('bell.qpy', 'rb') as fd:
    new_qc = qpy.load(fd)[0]

La funzione qiskit.qpy.dump() consente di includere più circuiti in un unico file QPY:

with open('twenty_bells.qpy', 'wb') as fd:
    qpy.dump([qc] * 20, fd)

e poi caricare quel file restituirà un elenco con tutti i circuiti

with open('twenty_bells.qpy', 'rb') as fd:
    twenty_new_bells = qpy.load(fd)

documentazione API

load

qiskit.qpy.load(file_obj, metadata_deserializer=None, annotation_factories=None)

GitHub

Caricare un file binario QPY

Questa funzione viene utilizzata per caricare un file di programma QPY Qiskit serializzato e creare oggetti dal suo contenuto QuantumCircuit oggetti dal suo contenuto. Ad esempio:

from qiskit import qpy

with open('bell.qpy', 'rb') as fd:
    circuits = qpy.load(fd)

o con un file compresso gzip:

import gzip
from qiskit import qpy

with gzip.open('bell.qpy.gz', 'rb') as fd:
    circuits = qpy.load(fd)

che leggerà il contenuto del file qpy e restituirà un elenco di oggetti QuantumCircuit oggetti del file.

Parametri

  • file_obj (BinaryIO) – Un oggetto simile a un file che contiene i dati binari QPY di un circuito.
  • metadata_deserializer (type[JSONDecoder] | None) – Una classe JSONDecoder opzionale che verrà utilizzata per il parametro cls kwarg nella chiamata interna json.load utilizzata per deserializzare il payload JSON impiegato per l'attributo .metadata in tutti i programmi contenuti nel file QPY. Se non viene specificato, i metadati del circuito verranno analizzati come JSON tramite la funzione della libreria json.load() standard utilizzando la classe predefinita JSONDecoder .
  • annotation_factories (Mapping[str, Callable[[], annotation.QPYSerializer]] | None) – Mappatura degli spazi dei nomi alle funzioni che creano nuove istanze di annotation.QPUSerializer, per gestire il caricamento di oggetti personalizzati Annotation .

Risultati

L'elenco dei programmi Qiskit contenuti nei dati QPY. Viene sempre restituito un elenco, anche se c'è solo un programma nei dati QPY.

Aumenti

  • QiskitError - se file_obj non è un file QPY valido
  • TypeError - Quando viene caricato un tipo di dati non valido.
  • MissingOptionalLibraryError – Se la symengine libreria engine non è installata al momento del caricamento di un payload QPY versione 10, 11 o 12 che utilizza la codifica simbolica symengine e contiene ParameterExpression istanze.
  • QpyError - se viene caricato un tipo di dati noto ma non supportato.

Tipo di restituzione

[elenco] QPY_TIPI_SUPPORTATI

dump

qiskit.qpy.dump(programs, file_obj, metadata_serializer=None, use_symengine=False, version=17, annotation_factories=None)

GitHub

Scrivere i dati binari QPY in un file

Questa funzione serve a salvare un circuito in un file per utilizzarlo successivamente o trasferirlo tra le macchine. Il formato QPY è compatibile con le versioni precedenti e può essere caricato con le versioni future di Qiskit.

Ad esempio:

from qiskit.circuit import QuantumCircuit
from qiskit import qpy

qc = QuantumCircuit(2, name='Bell', metadata={'test': True})
qc.h(0)
qc.cx(0, 1)
qc.measure_all()

da qui è possibile scrivere i dati di qpy in un file:

with open('bell.qpy', 'wb') as fd:
    qpy.dump(qc, fd)

o un file compresso gzip:

import gzip

with gzip.open('bell.qpy.gz', 'wb') as fd:
    qpy.dump(qc, fd)

Che salverà il circuito serializzato di qpy nel file fornito.

Parametri

  • programs (list[QPY_SUPPORTED_TYPES] | QPY_SUPPORTED_TYPES) – Oggetto/i supportato/i da QPY da salvare nel file specificato come oggetto. QPY supporta QuantumCircuit.

  • file_obj (BinaryIO) – L'oggetto simile a un file su cui scrivere i dati QPY

  • metadata_serializer (type[JSONEncoder] | None) – Una classe JSONEncoder opzionale a cui verrà passato l’attributo .metadata di ciascun programma in programs e che verrà utilizzata come parametro cls kwarg nella chiamata a json.dump () per serializzare in formato JSON quel dizionario.

  • use_symengine (bool) – Questo flag non è più utilizzato dalle versioni di QPY supportate da questa funzione e non avrà alcun impatto sul payload QPY generato, se non quello di impostare un campo inutilizzato nell'intestazione del file QPY v13.

  • version (int) –

    La versione del formato QPY da emettere. Per impostazione predefinita, il formato supportato è l'ultimo di QPY_VERSIONtuttavia, per ragioni di compatibilità, se si ha bisogno di caricare il payload QPY generato con una versione precedente di Qiskit, si può anche selezionare una versione del formato QPY più vecchia fino alla versione minima supportata per l'esportazione, che può cambiare solo durante un rilascio della versione principale di Qiskit, per generare una versione del formato QPY più vecchia. È possibile accedere alla versione corrente di QPY e alla versione minima compatibile con qpy.QPY_VERSION e qpy.QPY_COMPATIBILITY_VERSION rispettivamente.

    Nota

    Se specificato con una versione precedente di QPY, le limitazioni e i potenziali bug derivanti dal formato QPY di quella versione persisteranno. Questo dovrebbe essere usato solo se è necessaria la compatibilità con il caricamento del payload con una versione precedente di Qiskit.

  • annotation_factories (Mapping[str, Callable[[], annotation.QPYSerializer]] | None) – Mappatura degli spazi dei nomi alle funzioni che creano nuove istanze di annotation.QPUSerializer, per gestire il salvataggio di oggetti personalizzati Annotation . La successiva chiamata a load() dovrà utilizzare oggetti serializzatori simili, in grado di interpretare il formato di output personalizzato di tali serializzatori.

Aumenti

  • TypeError - Quando viene immesso un tipo di dati non valido.
  • ValueError - Quando viene passato un numero di versione non supportato per l'argomento version .

get_qpy_version

qiskit.qpy.get_qpy_version(file_obj)

GitHub

Questa funzione identifica la versione QPY del file.

Questa funzione legge l'intestazione di file_obj e restituisce la versione in formato QPY. Non farà avanzare il cursore di file_obj. Se si utilizza questa funzione per una lettura successiva, come ad esempio per chiamare load()è possibile passare direttamente file_obj . Ad esempio:

from qiskit import qpy

qpy_version = qpy.get_qpy_version(qpy_file)
if qpy_version > 12:
    qpy.load(qpy_file)

Parametri

file_obj (BinaryIO) – Un oggetto simile a un file che contiene i dati binari QPY di un circuito.

Risultati

La versione QPY del file specificato.

Tipo di restituzione

int

Queste funzioni solleveranno una sottoclasse personalizzata di QiskitError se incontrano problemi durante la serializzazione o la deserializzazione.

QpyError

exception qiskit.qpy.QpyError(*message)

GitHub

Basi: QiskitError

Errori sollevati dal modulo qpy.

Impostare il messaggio di errore.

Quando viene impostata una versione QPY di destinazione inferiore al massimo per la serializzazione, ma l'oggetto da serializzare contiene caratteristiche che non possono essere rappresentate in quel formato, viene sollevata una sottoclasse di QpyError viene sollevata:

UnsupportedFeatureForVersion

exception qiskit.qpy.UnsupportedFeatureForVersion(feature, required, target)

GitHub

Basi: QpyError

Errore QPY generato quando la versione del dump di destinazione è troppo bassa per una caratteristica presente nell'oggetto da serializzare.

Parametri

  • feature (str) – una descrizione dell'elemento problematico.
  • required (int) – la versione minima di QPY che sarebbe necessaria per rappresentare questa caratteristica.
  • target (int) – la versione di QPY utilizzata nella serializzazione.

qiskit.qpy.QPY_VERSION

La versione attuale del formato QPY a partire da questa release. Questo è il valore predefinito dell'argomento della parola chiave version su qpy.dump() e anche il limite superiore dei valori accettati per lo stesso argomento. Questo è anche il limite superiore delle versioni supportate da qpy.load().

Tipo

int

qiskit.qpy.QPY_COMPATIBILITY_VERSION

L'attuale versione minima di compatibilità del formato QPY. Questa è la versione minima che qpy.dump() accetta l'argomento della parola chiave version . qpy.load() sarà in grado di caricare tutte le versioni di formato rilasciate di QPY (fino a QPY_VERSION).

Tipo

int


Compatibilità QPY

Il formato QPY è stato progettato per essere compatibile con il futuro. Questo significa che dovreste essere in grado di caricare un QPY con una versione di Qiskit più recente di quella che lo ha generato. Tuttavia, il caricamento di un file QPY con una versione precedente di Qiskit non è supportato e potrebbe non funzionare.

Per esempio, se si è generato un file QPY usando qiskit-terra 0.18.1 si può caricare quel file QPY con qiskit-terra 0.19.0 e un ipotetico qiskit-terra 0.29.0. Tuttavia, il caricamento del file QPY con 0.18.0 non è supportato e potrebbe non funzionare.

Si noti che i metadati dei circuiti e gli oggetti personalizzati Annotation vengono serializzati e deserializzati tramite classi fornite dall'utente, poiché gli oggetti stessi sono interamente personalizzabili dall'utente; pertanto, la compatibilità in avanti e all'indietro di questi elementi è limitata da ciò che l'utente fornisce.

Se una funzionalità che viene caricata è deprecata nella corrispondente release di qiskit, QPY solleverà un messaggio di errore QPYLoadingDeprecatedFeatureWarning che informa del periodo di deprezzamento e di come la funzionalità sarà gestita internamente.

QPYLoadingDeprecatedFeatureWarning

exception qiskit.qpy.QPYLoadingDeprecatedFeatureWarning

GitHub

Basi: QiskitWarning

Avviso di deprezzamento visibile per le funzioni QPY che vengono caricate senza un punto stabile nello stack delle chiamate.

Nota

Nelle versioni di Qiskit precedenti alla 1.2.4, l'argomento use_symengine=True di qpy.dump() poteva causare problemi di retrocompatibilità se c'erano ParameterExpression oggetti da serializzare. In particolare:

  • Quando la versione di Qiskit da caricare è 1.2.4 o superiore, i file QPY generati con qualsiasi versione di Qiskit >= 0.46.0 possono essere caricati. Se per generare i file è stata utilizzata una versione di Qiskit compresa tra 0.45.0 e 0.45.3 e l'argomento non predefinito use_symengine=True è stato dato a qpy.dump()il file può essere letto solo se la versione di symengine utilizzata nell'ambiente generatore era della serie 0.11 o 0.13, ma se l'ambiente è stato creato durante la finestra di supporto di Qiskit 0.45, è probabile che sia stato utilizzato symengine==0.9.2 .
  • Quando la versione di Qiskit da caricare è compresa tra 0.46.0 e 1.2.2, il file può essere letto solo se la versione di symengine installata nell'ambiente di caricamento corrisponde alla versione utilizzata nell'ambiente di generazione.

Per recuperare un file QPY che fallisce con errori relativi alla versione symengine durante una chiamata a qpy.load()si tenta prima di tutto di utilizzare Qiskit >= 1.2.4 per caricare il file. Se questo fallisce ancora, è probabile che sia stato usato Qiskit 0.45.x per generare il file con use_symengine=True. In questo caso, utilizzare Qiskit 0.45.3 con symengine==0.9.2 per caricare il file e poi riesportarlo in QPY impostando use_symengine=False. Il file risultante può essere caricato da qualsiasi versione successiva di Qiskit.

Nota

A partire dalla versione di Qiskit 2.0.0, che ha rimosso il modulo Pulse dalla libreria, QPY fornisce un supporto limitato per il caricamento di payload che includono dati relativi agli impulsi. Se si carica un payload ScheduleBlock , viene sollevata un'eccezione QpyError verrà sollevata un'eccezione. Caricando un payload per un circuito che contiene porte a impulsi, il circuito di uscita conterrà istruzioni personalizzate senza dati di calibrazione allegati per ogni porta a impulsi, lasciandole indefinite.

Cronologia delle versioni del formato QPY

Se si intende caricare un file QPY tra diverse versioni di Qiskit, è utile sapere quali versioni erano disponibili in una determinata release. Poiché il QPY è compatibile con le versioni precedenti ma non con quelle successive, è necessario assicurarsi che una determinata versione del formato QPY sia stata rilasciata nella release con cui si sta chiamando load() con. La seguente tabella elenca le versioni di QPY supportate in ogni release di Qiskit (e di qiskit-terra prima di Qiskit 1.0.0 ) a partire dall'introduzione di QPY in qiskit-terra 0.18.0.

Qiskit (qiskit-terra per < 1.0.0 ) versione
dump() formato/i versioni di output
load() versione massima supportata (le versioni di formato più vecchie possono sempre essere lette)
2.5.213, 14, 15, 16, 1717
2.5.113, 14, 15, 16, 1717
2.5.013, 14, 15, 16, 1717
2.4.113, 14, 15, 16, 1717
2.4.013, 14, 15, 16, 1717
2.3.113, 14, 15, 16, 1717
2.3.013, 14, 15, 16, 1717
2.2.213, 14, 15, 1616
2.2.113, 14, 15, 1616
2.2.013, 14, 15, 1616
2.1.213, 14, 15, 1616
2.1.113, 14, 15, 1616
2.1.013, 14, 1515
2.0.213, 1414
2.0.113, 1414
2.0.013, 1414
1.4.310, 11, 12, 1313
1.4.210, 11, 12, 1313
1.4.110, 11, 12, 1313
1.4.010, 11, 12, 1313
1.3.310, 11, 12, 1313
1.3.210, 11, 12, 1313
1.3.110, 11, 12, 1313
1.3.010, 11, 12, 1313
1.2.410, 11, 1212
1.2.3 (strattonato)10, 11, 1212
1.2.210, 11, 1212
1.2.110, 11, 1212
1.2.010, 11, 1212
1.1.010, 11, 1212
1.0.210, 1111
1.0.110, 1111
1.0.010, 1111
0.46.11010
0.45.31010
0.45.21010
0.45.11010
0.45.01010
0.25.399
0.25.299
0.25.199
0.24.288
0.24.177
0.24.077
0.23.366
0.23.266
0.23.166
0.23.066
0.22.455
0.22.355
0.22.255
0.22.155
0.22.055
0.21.255
0.21.155
0.21.055
0.20.244
0.20.144
0.20.044
0.19.244
0.19.133
0.19.022
0.18.311
0.18.211
0.18.111
0.18.011

Formato QPY

Il formato di serializzazione QPY è un formato di serializzazione binaria multipiattaforma portatile per gli oggetti di QuantumCircuit oggetti in Qiskit. Il formato di base dei file è il seguente:

Un file QPY (o un oggetto di memoria) inizia sempre con la seguente stringa di 6 byte UTF8 : QISKIT che è immediatamente seguita dall'intestazione generale del file. Il contenuto dell'intestazione del file, definito come struttura C, è il seguente:

struct {
    uint8_t qpy_version;
    uint8_t qiskit_major_version;
    uint8_t qiskit_minor_version;
    uint8_t qiskit_patch_version;
    uint64_t num_circuits;
}

A partire da V10, viene aggiunto un nuovo campo alla struct header del file per rappresentare lo schema di codifica utilizzato per le espressioni simboliche:

struct {
    uint8_t qpy_version;
    uint8_t qiskit_major_version;
    uint8_t qiskit_minor_version;
    uint8_t qiskit_patch_version;
    uint64_t num_circuits;
    char symbolic_encoding;
}

Da V16 in poi, la struttura di intestazione del file è immediatamente seguita da una tabella di avvio del circuito contenente gli offset dei byte di ciascun payload del circuito nel file. Nella tabella di avvio del circuito ci sono num_circuits voci, ognuna delle quali è del tipo uint64_t. In tutte le versioni precedenti, l'intestazione del file è immediatamente seguita dai payload del circuito in sequenza, senza alcun padding intermedio.

Tutti i valori utilizzano l'ordine dei byte di rete [1] (big-endian) per garantire la compatibilità multipiattaforma. L'eccezione a questa regola riguarda le versioni del formato QPY <= 17, in cui la codifica dei numeri interi e dei numeri in virgola mobile è INSTRUCTION_PARAM di tipo little-endian.

Ogni singolo circuito è composto dalle seguenti parti, in ordine dall'alto verso il basso:

HEADER
METADATA
REGISTERS
ANNOTATION_HEADER
STANDALONE_VARS
CUSTOM_DEFINITIONS
INSTRUCTIONS

Modificato nella versione QPY: 15 ANNOTATION_HEADER è stato aggiunto tra REGISTERS e STANDALONE_VARS.

Modificato nella versione QPY: 12 STANDALONE_VARS è stato aggiunto tra REGISTERS e CUSTOM_DEFINITIONS.

C'è un payload di circuito per ogni circuito (il cui numero totale è dettato da num_circuits nell'intestazione del file). Non c'è padding tra i circuiti nei dati.

Versione 17

La versione 17 aggiunge il supporto per la serializzazione e la deserializzazione PauliEvolutionGate di SparseObservable oggetti contenenti uno o più operatori.

Modifiche a PAULI_EVOLUTION

Il formato di PAULI_EVOLUTION rimane invariato, ma viene aggiornato il formato degli operatori che seguono immediatamente il gate di evoluzione compresso. Anziché gli elementi operator_count definiti dal formato SPARSE_PAULI_OP_LIST_ELEM, il payload specifica ora il tipo di ciascun operatore per tenere conto sia degli operatori di tipo SparsePauliOp che di quelli di tipo SparseObservable.

Il nuovo payload che segue PAULI_EVOLUTION ora contiene esattamente operator_count sequenze composte da un bool ("!?") seguito dall'operatore. Se il valore booleano è True, l'operatore è un SparseObservable e viene interpretato secondo il nuovo formato SPARSE_OBSERVABLE (vedi sotto). FalseIn tal caso, l'operatore è un SparsePauliOp e viene interpretato secondo il formato SPARSE_PAULI_OP_LIST_ELEM esistente.

Nuovo SPARSE_OBSERVABLE

Il formato SPARSE_OBSERVABLE rappresenta un'istanza di un SparseObservable, definita da

struct {
  uint32_t num_qubits;
  uint64_t coeff_data_len;
  uint64_t bitterm_data_len;
  uint64_t inds_data_len;
  uint64_t bounds_data_len;
}

seguito immediatamente dal numero di qubit e quindi dagli array di dati dei coefficienti, dei termini binari, degli indici e dei confini dell'osservabile. Il formato specifica il numero di byte occupati da ciascun array. Il numero di elementi può essere calcolato dividendo il numero di byte per la dimensione di ciascun elemento.

  • Ogni coefficiente è memorizzato come due elementi consecutivi "!d", prima la parte reale e poi quella immaginaria.
  • Gli elementi del termine bit sono di tipo “!"H" e rappresenta il valore " u8 " del SparseObservable.BitTerm
  • Gli elementi dell'indice sono di tipo "!I”.
  • Gli elementi dei confini sono di tipo "!Q”.

Versione 16

La versione 16 aggiunge al formato del file QPY una tabella di inizio circuito. Serve come indice degli offset dei byte di ciascun payload del circuito nel file. La motivazione di questa modifica è quella di consentire un caricamento più efficiente dei circuiti utilizzando il multi-threading in una futura implementazione di Rust del deserializzatore QPY.

Modifiche alla DURATA

È stata aggiunta una nuova variante alla codifica esistente del tipo DURATION per i picosecondi. La codifica è la seguente e si aggiunge alle varianti precedentemente supportate.

Classe Qiskit
Codice tipo
Payload
pspUno double value.

Versione 15

La versione 15 aggiunge il concetto di annotazioni personalizzate al formato del payload. QPY stesso non specifica come le annotazioni vengano serializzate o deserializzate, poiché si tratta di oggetti utente personalizzati. Tuttavia, il formato collabora con i sub-serializzatori.

La versione 15 aggiunge il campo ANNOTATION_HEADER tra i campi STANDALONE_VARS e CUSTOM_DEFINITIONS nel livello superiore del payload di un singolo circuito. Modifica l'interpretazione di un campo della struttura INSTRUCTION in modo compatibile con l'ABI e aggiunge un trailer INSTRUCTION_ANNOTATIONS a INSTRUCTION , che è presente a condizione di un bit impostato nel payload INSTRUCTION .

Nuovo ANNOTATION_HEADER

Il campo ANNOTATION_HEADER è un carico utile di dimensioni variabili nell'intestazione. Inizia con un'istanza di ANNOTATION_HEADER_STATIC, che è la struct del C:

struct ANNOTATION_HEADER_STATIC {
    uint32_t num_namespaces;
}

Questo è immediatamente seguito da num_namespaces istanze del payload di ANNOTATION_STATE . L'ordine di questi è importante e deve essere mantenuto durante il processo di deserializzazione, poiché i successivi payload di INSTRUCTION_ANNOTATION vi indicizzeranno.

Il payload di ANNOTATION_STATE inizia con la struttura C fissa:

struct ANNOTATION_STATE_HEADER {
    uint32_t namespace_size;
    uint64_t state_size;
}

Questa intestazione è immediatamente seguita da namespace_size byte di testo codificato in UTF-8, che comprende lo spazio dei nomi. Questi byte sono immediatamente seguiti da state_size byte di dati arbitrari. Il formato di questo payload di "stato" non è definito dal QPY. È invece responsabilità di un oggetto esterno associato allo spazio dei nomi memorizzato. Il formato non detta come produrre questi oggetti; poiché le annotazioni sono interamente personalizzate, l'utente deve fornire i metodi di serializzazione e deserializzazione.

Modifiche alle ISTRUZIONI

La struct INSTRUCTION è stata modificata in modo compatibile con l'ABI rispetto alla sua precedente definizione nella versione 9. La nuova struct è la struct C (ricordate che non c'è padding tra i campi, né alla fine della struct):

struct INSTRUCTION {
    uint16_t name_size;
    uint16_t label_size;
    uint16_t num_parameters;
    uint32_t num_qargs;
    uint32_t num_cargs;
    uint8_t extras_key;
    uint16_t conditional_reg_name_size;
    int64_t conditional_value;
    uint32_t num_ctrl_qubits;
    uint32_t ctrl_state;
}

dove il campo uint8_t extras_key sostituisce il precedente uint8_t conditional_key. La differenza è puramente interpretativa. I due bit inferiori del byte vengono ancora interpretati come definizione della condizione e del suo tipo. Il bit alto del byte è ora un flag, che indica se un campo INSTRUCTION_ANNOTATIONS_HEADER è presente (se il bit è impostato) nei dati di coda della struttura INSTRUCTION .

Il payload di un'istruzione completa appare nel flusso di dati, compresi gli oggetti di coda e senza byte di padding tra gli elementi, come:

struct INSTRUCTION;
uint8_t name[name_size];
uint8_t label[label_size];
uint8_t register[conditional_reg_name_size]; (1)
struct INSTRUCTION_PARAM;                    (2)
struct INSTRUCTION_ARG[num_qargs];
struct INSTRUCTION_ARG[num_cargs];
struct INSTRUCTION_PARAM[num_parameters];
INSTRUCTION_ANNOTATIONS;                     (3)

Si applicano le seguenti note:

  1. se i due bit bassi di extras_key hanno il valore 2, che indica che la condizione è una EXPRESSION, la conditional_reg_name_size è sempre zero.
  2. questo campo è presente se e solo se i due bit bassi di extras_key hanno il valore 2, indicando che la condizione è un EXPRESSION.
  3. questo campo è presente se e solo se il bit alto di extras_key è impostato. Questo campo ha una dimensione variabile; vedere Nuove istruzioni_annotazioni.

Nuove ISTRUZIONI_ANNOTAZIONI

Il payload di INSTRUCTION_ANNOTATIONS inizia con la struttura C:

struct INSTRUCTION_ANNOTATIONS_HEADER {
    uint32_t num_annotations;
}

Questo payload è immediatamente seguito da num_annotations istanze del payload INSTRUCTION_ANNOTATION , di dimensioni variabili.

Il payload di INSRTUCTION_ANNOTATION è definito dalla seguente struttura C, più un numero di byte di coda pari a payload_size, chiamato ANNOTATION_PAYLOAD.

struct INSTRUCTION_ANNOTATION {
    uint32_t namespace_index;
    uint32_t payload_size;
}

namespace_index è un indice intero nell'elenco degli oggetti ANNOTATION_NAMESPACE definiti nella cartella ANNOTATION_HEADER. Lo spazio dei nomi della serializzazione per un'annotazione è la stringa codificata in UTF-8 nel relativo payload.

Il formato dell'oggetto ANNOTATION_PAYLOAD non è specificato da QPY. È definito da un oggetto di serializzazione esterno associato allo spazio dei nomi a cui fa riferimento il namespace_index e al suo stato di serializzazione associato nell'ANNOTATION_HEADER.

Cambiamenti all'interno dell' PARAM_EXPR_ELEM_V13

La struttura in sé rimane invariata. Tuttavia, per un PARAM_EXPR_ELEM_V13 che rappresenta una ParameterExpression.subs() chiamata (con op_code = 15, e quindi lhs_type = 'p' e rhs_type = 'n'), il MAPPING finale ora mappa le chiavi dei byte grezzi degli Parameter UUID ai valori sostituiti. In precedenza (nelle versioni 13 e 14 di QPY), questa mappatura memorizzava i nomi dei parametri come chiavi.

Versione 14

La versione 14 aggiunge un nuovo tipo di base DURATION, il supporto per altre classi Type classi Float e Duratione un nuovo tipo di nodo di espressione Stretch.

DURATA

Un Duration è codificato da un singolo byte ASCII char che codifica il tipo di tipo, seguito da un payload che varia a seconda del tipo. I codici definiti sono:

Classe Qiskit
Codice tipo
Payload
dttUno unsigned long long value.
nsnUno double value.
usuUno double value.
msmUno double value.
ssUno double value.

Modifiche a EXPR_VAR_DECLARATION

Il tipo EXPR_VAR_DECLARATION è ora utilizzato per rappresentare sia variabili Var variabili autonome che Stretch identificatori. Per supportare questa modifica, il codice del tipo di utilizzo ha due nuove voci possibili, oltre a quelle esistenti:

Codice tipo
Significato
AUn tratto di capture per il circuito.
OUn tratto dichiarato a livello locale del circuito.

Modifiche a EXPRESSION

Il codice del tipo EXPRESSION ha una nuova voce possibile, s, che corrisponde a expr.Stretch nodi.

Classe Qiskit
Codice tipo
Payload
Elementi figlio
StretchsUno unsigned short var_index0

Modifiche a EXPR_TYPE

La tabella seguente mostra le nuove classi di tipi aggiunte nella versione:

Classe Qiskit
Codice tipo
Payload
FloatfNessuno.
DurationdNessuno.

Modifiche a EXPR_VALUE

Il sistema di tipi dell'espressione classica supporta ora nuovi tipi di codifica per i letterali di valore, oltre alle codifiche esistenti per int e bool. Le nuove codifiche dei tipi di valore sono riportate di seguito:

Python tipo
Codice tipo
Payload
floatfUno double value.
DurationtUno DURATION.

Versione 13

La versione 13 ha aggiunto una rappresentazione di serializzazione nativa di Qiskit per ParameterExpression. Le versioni precedenti di QPY utilizzavano o symengine``sympy per serializzare l'espressione simbolica sottostante. A partire dalla versione 13, QPY rappresenta ora la sequenza di chiamate API utilizzate per creare il file ParameterExpression.

La modifica principale nel formato di serializzazione riguarda il payload PARAMETER_EXPR. I expr_size byte che seguono l'intestazione contengono ora un array di PARAM_EXPR_ELEM_V13 strutture. L'intenzione è che questo array venga letto una struttura alla volta, dove ogni struttura descrive una delle chiamate da effettuare per ricostruire il ParameterExpression.

PARAM_EXPR_ELEM_V13

Il formato della struct è definito come:

struct {
    unsigned char op_code;
    char lhs_type;
    char lhs[16];
    char rhs_type;
    char rhs[16];
} PARAM_EXPR_ELEM_V13;

Il op_code campo viene utilizzato per definire l'operazione aggiunta al ParameterExpression. Il valore può essere:

op_code
0__add__()
1__sub__()
2__mul__()
3__truediv__()
4__pow__()
5sin()
6cos()
7tan()
8arcsin()
9arccos()
10exp()
11log()
12sign()
13gradient()
14conjugate()
15subs()
16abs()
17arctan()
255NULL

Il valore NULL di 255 viene utilizzato solo per riempire il campo del codice op per le voci che non sono operazioni vere e proprie, ma indicano definizioni ricorsive. I campi lhs_type e rhs_type sono utilizzati per descrivere i tipi di operando e possono essere uno dei seguenti caratteri codificati UTF-8 :

Valore
Tipo
nNone
pParameter
ffloat
ccomplex
iint
sInizio della definizione ricorsiva ParameterExpression
eFine della definizione ricorsiva ParameterExpression
usostituzione

Se il valore del tipo è f, c, o i, le larghezze dei campi corrispondenti lhs o rhs sono di 128 bit ciascuna. Nel caso dei numeri in virgola mobile, il valore letterale viene codificato come numero di tipo double con riempimento a zeri, mentre i numeri complessi vengono codificati come parte reale seguita dalla parte immaginaria, occupando 64 bit ciascuno. Per i, il valore viene codificato come un intero con segno a 64 bit, con riempimento a zeri fino a raggiungere la larghezza totale di 128 bit. n viene utilizzato per rappresentare un None e in genere non viene utilizzato direttamente, poiché indica un argomento che non viene utilizzato. Infatti, p il dato è l'UUID corrispondente a Parameter [...], che può essere individuato nella mappa dei simboli descritta nel payload map_elements esterno PARAMETER_EXPR. ParameterExpressionSe il valore del tipo è s , ciò segna l'inizio di una nuova sezione ricorsiva per un elemento annidato. Ad esempio, nel frammento di codice seguente è presente un elemento interno expr contenuto in final_expr, che costituisce un'espressione annidata:

from qiskit.circuit import Parameter

x = Parameter("x")
y = Parameter("y")
z = Parameter("z")

expr = (x + y) / 2
final_expr = z**2 + expr

Quando s si incontra, ciò indica che, fino a quando non vengono e` struct is reached, the next structs are used for a recursive definition. For both ``s specificati e i tipi e, i valori dei dati non vengono utilizzati e sono sempre impostati a 0. Il valore di u tipo viene utilizzato per rappresentare una chiamata di sostituzione. Questo viene utilizzato solo per lhs_type ed è sempre abbinato a un rhs_type di n. Il valore del dato corrisponde alla dimensione in byte di una mappatura, codificata in formato MAPPING, dei Parameter nomi e dei relativi valori per la subs() chiamata. I dati di mappatura seguono immediatamente la struttura, e la struttura successiva inizia subito dopo i dati di mappatura.

Versione 12

La versione 12 aggiunge il supporto per:

  • circuiti contenenti variabili che possiedono memoria expr.Var variabili.

Modifiche all'HEADER

La struttura HEADER per un singolo circuito ha aggiunto tre uint32_t conteggi delle variabili in ingresso, catturate e dichiarate localmente nel circuito. Il nuovo modulo si presenta come:

struct {
    uint16_t name_size;
    char global_phase_type;
    uint16_t global_phase_size;
    uint32_t num_qubits;
    uint32_t num_clbits;
    uint64_t metadata_size;
    uint32_t num_registers;
    uint64_t num_instructions;
    uint32_t num_vars;
} HEADER_V12;

La struct HEADER_V12 è seguita immediatamente dalle stesse informazioni su nome, fase globale, metadati e registri della versione V2 dell'intestazione. Subito dopo i registri si trova num_vars istanze di EXPR_VAR_STANDALONE che definiscono le variabili di questo circuito. Successivamente, i dati continuano con le definizioni e le istruzioni personalizzate come nelle versioni precedenti di QPY.

EXPR_VAR_DECLARATION

Un EXPR_VAR_DECLARATION definisce un'istanza expr.Var che è indipendente; cioè, rappresenta una locazione di memoria autonoma piuttosto che avvolgere un oggetto Clbit o ClassicalRegister. Il carico utile è una struttura C:

struct {
    char uuid_bytes[16];
    char usage;
    uint16_t name_size;
}

che è immediatamente seguito da un payload EXPR_TYPE e poi da name_size byte di dati stringa di codifica UTF-8 contenenti il nome della variabile.

Il codice del tipo di utilizzo char assume i seguenti valori:

Codice tipo
Significato
IUna variabile input del circuito.
CUna variabile capture del circuito.
LUna variabile dichiarata localmente al circuito.

Modifiche a EXPR_VAR

La variabile EXPR_VAR ha acquisito un nuovo codice di tipo e un nuovo payload, oltre a quelli preesistenti:

Python classe
Codice tipo
Payload
UUIDUUno uint32_t indice della variabile nella serie di variabili EXPR_VAR_STANDALONE scritte immediatamente dopo l'intestazione del circuito.

In particolare, questo nuovo codice di tipo indicizza le variabili predefinite dall'intestazione del circuito, anziché ridefinire la variabile in ogni punto in cui viene utilizzata.

Modifiche a EXPRESSION

Il codice del tipo EXPRESSION ha una nuova voce possibile, i, che corrisponde a expr.Index nodi.

Classe Qiskit
Codice tipo
Payload
Elementi figlio
IndexiNessun carico utile aggiuntivo. I figli sono l'obiettivo e l'indice, in quest'ordine.2

Versione 11

La versione 11 è identica alla versione 10, ad eccezione di quanto segue. Innanzitutto, i nomi nei blocchi CUSTOM_INSTRUCTION hanno un suffisso della forma "_{uuid_hex}" dove uuid_hex è una stringa esadecimale UUID come quella restituita da UUID.hex. Ad esempio: "b3ecab5b4d6a4eb6bc2b2dbf18d83e1e". In secondo luogo, aggiunge il supporto per AnnotatedOperation gli oggetti. L'operazione di base di un'operazione annotata viene memorizzata tramite il blocco INSTRUCTION, e viene aggiunto un valore 'a'``is added to indicate that the custom instruction is an annotated operation. The list of modifiers are stored as instruction parameters using INSTRUCTION_PARAM, with an additional value ``'m' aggiuntivo type per indicare che il parametro è di tipo Modifier. Ogni modificatore viene memorizzato utilizzando la struttura MODIFIER.

Modificatore

Questo rappresenta Modifier

struct {
    char type;
    uint32_t num_ctrl_qubits;
    uint32_t ctrl_state;
    double power;
}

Questo è sufficiente per memorizzare i diversi tipi di modificatori necessari per la serializzazione degli oggetti di tipo AnnotatedOperation. Il campo type può assumere il valore 'i', 'c' o 'p', a indicare rispettivamente se il modificatore è un modificatore inverso, un modificatore di controllo o un modificatore di potenza. Nel secondo caso, i campi num_ctrl_qubits e ctrl_state specificano la logica di controllo dell'operazione di base, mentre nel terzo caso il campo power rappresenta la potenza dell'operazione di base.

Versione 10

La versione 10 aggiunge il supporto per:

  • Serializzazione nativa di Symengine per oggetti di tipo ParameterExpression e per le espressioni simboliche nei blocchi di pianificazione di Pulse.
  • nuovi campi nella TranspileLayout classe aggiunti nella versione 0.45.0 di Qiskit.

Il campo symbolic_encoding viene aggiunto all'intestazione del file e viene introdotto un nuovo tipo di codifica char, mappato a ogni libreria simbolica come segue: p si riferisce alla codifica sympy e e si riferisce alla codifica symengine.

Modifiche a FILE_HEADER

Il contenuto di FILE_HEADER dopo V10 è definito come una struct C come:

struct {
    uint8_t qpy_version;
    uint8_t qiskit_major_version;
    uint8_t qiskit_minor_version;
    uint8_t qiskit_patch_version;
    uint64_t num_circuits;
    char symbolic_encoding;
} FILE_HEADER_V10;

Modifiche al LAYOUT

La struttura LAYOUT viene aggiornata con un campo aggiuntivo input_qubit_count . Con la versione 10 la struttura LAYOUT è ora:

struct {
    char exists;
    int32_t initial_layout_size;
    int32_t input_mapping_size;
    int32_t final_layout_size;
    uint32_t extra_registers;
    int32_t input_qubit_count;
}

Il resto dei dati di layout successivi alla LAYOUT struttura è rappresentato come nelle versioni precedenti. Se input qubit_count è < 0, ciò indica che sia _input_qubit_count che _output_qubit_list nell'oggetto TranspileLayout sono None.

Versione 9

La versione 9 aggiunge il supporto per i nodi Expr e i loro nodi associati Types.

Espressione

Un Expr è rappresentato da un flusso di dati a larghezza variabile. Un nodo stesso è rappresentato da (in ordine nel flusso di byte):

  1. un discriminatore di codice di tipo a un byte;
  2. un oggetto EXPR_TYPE;
  3. un carico utile aggiuntivo specifico per il codice del tipo;
  4. un numero di payload EXPRESSION figlio specifico del codice del tipo (il numero di questi è implicito nel codice del tipo e non viene memorizzato esplicitamente).

Ciascuna di esse è descritta nella tabella seguente:

Classe Qiskit
Codice tipo
Payload
Elementi figlio
VarxUno EXPR_VAR.0
ValuevUno EXPR_VALUE.0
CastcUno _Bool che corrisponde al valore di implicit.1
UnaryuUno uint8_t con lo stesso valore numerico dell'elemento Unary.Op.1
BinarybUno uint8_t con lo stesso valore numerico dell'elemento Binary.Op.2

EXPR_TYPE

A Type è codificato da un singolo byte ASCII char che codifica il tipo di tipo, seguito da un payload che varia a seconda del tipo. I codici definiti sono:

Classe Qiskit
Codice tipo
Payload
BoolbNessuno.
UintuUno uint32_t width.

EXPR_VAR

Rappresenta una variabile di runtime di un Var nodo. Si tratta di un codice di tipo, seguito da un carico utile specifico del codice di tipo:

Python classe
Codice tipo
Payload
ClbitCUno uint32_t index che è l'indice del Clbit nel circuito contenente.
ClassicalRegisterRUn uint16_t reg_name_size, seguito da altrettanti byte di UTF-8 stringa di dati del nome del registro.

EXPR_VALORE

Rappresenta un oggetto letterale nel sistema di tipi classico, come un intero. Attualmente esistono pochissimi letterali di questo tipo. Questi sono codificati come un codice di tipo, seguito da un carico utile specifico del codice di tipo.

Python tipo
Codice tipo
Payload
boolbUno _Bool value.
intiUno uint8_t num_bytes, seguito dal numero intero codificato in tanti byte (ordine di rete) in una rappresentazione a complemento di due.

Modifiche alle ISTRUZIONI

Per supportare l'uso dei Expr nodi nei campi IfElseOp.condition, WhileLoopOp.condition e SwitchCaseOp.target, la struttura INSTRUCTION viene modificata in modo compatibile con l'ABI rispetto alla sua definizione precedente. La nuova struttura è la struttura C:

struct {
    uint16_t name_size;
    uint16_t label_size;
    uint16_t num_parameters;
    uint32_t num_qargs;
    uint32_t num_cargs;
    uint8_t conditional_key;
    uint16_t conditional_reg_name_size;
    int64_t conditional_value;
    uint32_t num_ctrl_qubits;
    uint32_t ctrl_state;
}

dove l'unica modifica è che una voce uint8_t conditional_key ha sostituito _Bool has_conditional. Questo nuovo conditional_key assume i seguenti valori numerici, con questi effetti:

Valore
Effetti
0L'istruzione ha il campo .condition impostato su None. I campi conditional_reg_name_size e conditional_value devono essere ignorati.
1L'istruzione ha il suo campo .condition impostato su una 2-tupla di a Clbit o a ClassicalRegistere un intero di valore conditional_value. Il payload di INSTRUCTION, compresi i dati di coda, viene analizzato esattamente come nelle versioni di QPY inferiori alla 8.
2L'istruzione ha il suo campo .condition impostato su un Expr nodo. I campi conditional_reg_name_size e conditional_value devono essere ignorati. I dati che seguono la struct sono seguiti (come nelle versioni QPY inferiori alla 9) da name_size byte di dati stringa UTF-8 per il nome della classe e label_size byte di dati stringa UTF-8 per l'eventuale etichetta. Poi, c'è una INSTRUCTION_PARAM, che conterrà un'ESPRESSIONE. Dopodiché, il parsing continua con le strutture INSTRUCTION_ARG, come nelle versioni precedenti di QPY.

Modifiche a INSTRUCTION_PARAM

È stato aggiunto un nuovo codice di tipo x che definisce un parametro EXPRESSION.

Versione 8

La versione 8 aggiunge il supporto per la gestione di un valore TranspileLayout memorizzato nell'attributo QuantumCircuit.layout . Nella versione 8, subito dopo il blocco delle calibrazioni alla fine del carico utile del circuito, è ora presente la LAYOUT struttura. Questa struttura descrive le dimensioni dei tre attributi di una TranspileLayout classe.

Layout

struct {
    char exists;
    int32_t initial_layout_size;
    int32_t input_mapping_size;
    int32_t final_layout_size;
    uint32_t extra_registers;
}

Se uno qualsiasi dei valori firmati è -1 , significa che l'attributo corrispondente è None.

Subito dopo la struttura LAYOUT struct c'è una struttura REGISTERS dedicata extra_registers alle definizioni di registri indipendenti (in particolare nel formato introdotto nella versione 4 ) che non sono presenti nel circuito. Ci sono initial_layout_size poi delle INITIAL_LAYOUT_BIT strutture per definire TranspileLayout.initial_layout l'attributo.

BIT_LAYOUT_INIZIALE

struct {
    int32_t index;
    int32_t register_size;
}

Dove un valore di -1 indica None (cioè nessun registro è associato al bit). Dopo ogni struttura INITIAL_LAYOUT_BIT c'è register_size byte per una stringa codificata utf8 per il nome del registro.

Dopo il layout iniziale c'è input_mapping_size array di uint32_t interi che rappresentano le posizioni dei bit fisici del layout iniziale. Ciò consente di costruire un elenco di bit virtuali in cui l'indice dell'array è la posizione di mappatura dell'ingresso.

Infine, c'è un array di numeri interi final_layout_size uint32_t . Ogni elemento è un indice nell'attributo qubits del circuito, che consente di costruire una mappatura dalla posizione iniziale del qubit alla posizione di uscita alla fine del circuito.

Versione 7

La versione 7 aggiunge il supporto per l'istruzione Reference e la serializzazione di un programma ScheduleBlock mantenendo il riferimento alle subroutine:

from qiskit import pulse
from qiskit import qpy

with pulse.build() as schedule:
    pulse.reference("cr45p", "q0", "q1")
    pulse.reference("x", "q0")
    pulse.reference("cr45p", "q0", "q1")

with open('template_ecr.qpy', 'wb') as fd:
    qpy.dump(schedule, fd)

Il modello di dati convenzionale SCHEDULE_BLOCK viene mantenuto, ma nella versione 7 è immediatamente seguito da un blocco extra MAPPING utf8 byte che rappresenta i dati delle subroutine di riferimento.

Al gruppo SCHEDULE_BLOCK_INSTRUCTIONS è stato aggiunto un nuovo tipo di carattere chiave per l'istruzione Reference .

  • y: Reference istruzione

Al gruppo SCHEDULE_BLOCK_OPERANDS viene aggiunto un nuovo tipo di carattere chiave per gli operandi dell'istruzione Reference , che è una tupla di stringhe, ad esempio ( “cr45p”, “q0”, “q1” ).

  • o: stringa (stringa dell'operando)

Si noti che questa è la stessa codifica della stringa incorporata Python; tuttavia, la codifica standard dei valori in QPY utilizza il tipo di carattere s per i dati delle stringhe, il che è in conflitto con SymbolicPulse nell'ambito degli operandi delle istruzioni pulse. Un carattere di tipo speciale o è riservato ai dati di stringa che compaiono negli operandi delle istruzioni a impulsi.

Inoltre, la versione 7 aggiunge due nuove chiavi di tipo alla struct INSTRUCTION\PARM. "d" è seguito da nessun dato e rappresenta il valore letterale CASE_DEFAULT per il supporto delle dichiarazioni di commutazione. "R" rappresenta un ClassicalRegister o Clbited è seguito dallo stesso formato della descrizione del registro o del bit classico utilizzato nel primo elemento della condizione di un campo INSTRUCTION.

Versione 6

La versione 6 aggiunge il supporto per ScalableSymbolicPulse. Questi oggetti vengono salvati e letti come oggetti SymbolicPulse e il nome della classe viene aggiunto ai dati per gestire correttamente la selezione della classe.

SymbolicPulse inizia ora con l'intestazione SYMBOLIC_PULSE_V2 :

struct {
    uint16_t class_name_size;
    uint16_t type_size;
    uint16_t envelope_size;
    uint16_t constraints_size;
    uint16_t valid_amp_conditions_size;
    _bool amp_limited;
}

L'unica modifica rispetto alla versione 5 è l'aggiunta di class_name_size. L'intestazione è seguita immediatamente da class_name_size utf8 byte con il nome della classe. Attualmente sono supportati sia SymbolicPulse che ScalableSymbolicPulse. Il resto dei dati è identico alla versione 5.

Versione 5

La versione 5 si differenzia dalla versione 4 per l'aggiunta del supporto per ScheduleBlock e per la modifica di due payload: il payload dei metadati INSTRUCTION e il blocco CUSTOM_INSTRUCTION. Questi dispongono ora di nuovi campi per tenere meglio conto degli ControlledGate oggetti presenti in un circuito. Inoltre, viene definito un nuovo payload MAP_ITEM per implementare il blocco MAPPING.

Nota

Il supporto per la rappresentazione delle sequenze di impulsi e delle calibrazioni personalizzate è stato rimosso in Qiskit v2.0. Durante il caricamento dei payload QPY, questi campi dati vengono ora ignorati o generano un errore quando si utilizza Qiskit per la deserializzazione.

In QPY versione 5 e successive,

struct {
    char type;
}

segue immediatamente il blocco di intestazione del file per rappresentare il tipo di programma memorizzato nel file.

  • Quando type==c, QuantumCircuit il carico utile segue
  • Quando type==s, segue il payload di ScheduleBlock
Nota

Non è possibile riunire programmi diversi nello stesso file. È necessario creare file diversi per i vari tipi di programma. È possibile salvare più oggetti dello stesso tipo in un unico file.

SCHEDULE_BLOCK

ScheduleBlock è supportato per la prima volta nella versione 5 di QPY. In questo modo è possibile salvare i programmi ad impulsi nel formato binario QPY come segue:

from qiskit import pulse, qpy

with pulse.build() as schedule:
    pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0))

with open('schedule.qpy', 'wb') as fd:
    qpy.dump(schedule, fd)

with open('schedule.qpy', 'rb') as fd:
    new_schedule = qpy.load(fd)[0]

Si noti che il circuito e il blocco di programmazione sono serializzati e deserializzati attraverso la stessa interfaccia QPY. Il tipo di dati in ingresso viene analizzato implicitamente e non è necessaria alcuna opzione aggiuntiva per salvare il blocco di pianificazione.

SCHEDULE_BLOCK_HEADER

ScheduleBlock il blocco inizia con la seguente intestazione:

struct {
    uint16_t name_size;
    uint64_t metadata_size;
    uint16_t num_element;
}

che è immediatamente seguito da name_size utf8 byte del nome del programma previsionale e da metadata_size utf8 byte del dizionario di metadati serializzato JSON allegato al programma previsionale.

PROGRAMMA_BLOCCO_ALLINEAMENTI

Quindi, il contesto di allineamento del blocco del programma previsionale inizia con char che rappresenta il tipo di contesto supportato, seguito dal blocco SEQUENCE che rappresenta i parametri associati al contesto di allineamento AlignmentKind._context_params. Il tipo di contesto char è mappato a ciascuna sottoclasse di allineamento come segue:

  • l: AlignLeft
  • r: AlignRight
  • s: AlignSequential
  • e: AlignEquispaced

Si noti che il contesto AlignFunc non è supportato a causa della funzione di callback memorizzata nei parametri del contesto.

PROGRAMMA_BLOCCO_ISTRUZIONI

Questo blocco di allineamento è seguito da elementi di blocco della lunghezza di num_element che possono essere costituiti da blocchi di programma e istruzioni di programma annidati. Ogni istruzione del programma inizia con char che rappresenta il tipo di istruzione, seguito dal blocco SEQUENCE che rappresenta l'istruzione operands. Si noti che la struttura dei dati di pulse Instruction è unificata in modo che l'istanza possa essere determinata in modo univoco dalla classe e da una tupla di operandi. La mappatura del tipo char alla sottoclasse di istruzioni è definita come segue:

  • a: Acquire istruzione
  • p: Play istruzione
  • d: Delay istruzione
  • f: SetFrequency istruzione
  • g: ShiftFrequency istruzione
  • q: SetPhase istruzione
  • r: ShiftPhase istruzione
  • b: RelativeBarrier istruzione
  • t: TimeBlockade istruzione
  • y: istruzione Reference (novità della versione 0.7 )

SCHEDULE_BLOCK_OPERANDS

Gli operandi di queste istanze possono essere serializzati attraverso il meccanismo di serializzazione dei valori standard di QPY, ma ci sono tipi di oggetti speciali che appaiono solo negli operandi del programma. Poiché gli operandi sono serializzati come SEQUENCE, ogni elemento deve essere impacchettato con la struct INSTRUCTION_PARAM pack, dove ogni payload inizia con un blocco di intestazione costituito dai char type e uint64_t size. Gli oggetti speciali iniziano con la seguente chiave di tipo:

  • c: Channel
  • w: Waveform
  • s: SymbolicPulse
  • o: stringa (operando stringa, nuovo nella versione 0.7 )

Canale

Il blocco di canali inizia con il sottotipo di canale char che mappa i dati di un oggetto nella sottoclasse Channel . La mappatura è definita come segue:

  • d: DriveChannel
  • c: ControlChannel
  • m: MeasureChannel
  • a: AcquireChannel
  • e: MemorySlot
  • r: RegisterSlot

La chiave è immediatamente seguita dall'indice del canale serializzato come INSTRUCTION_PARAM.

Forma d'onda

Il blocco della forma d'onda inizia con l'intestazione WAVEFORM:

struct {
    double epsilon;
    uint32_t data_size;
    _bool amp_limited;
}

che è seguito da data_size byte di binario complesso ndarray generato da numpy.save. Questo rappresenta il complesso di punti dati del QI riprodotti su un dispositivo quantistico. name viene salvato dopo i campioni nella struttura INSTRUCTION_PARAM pack, che può essere una stringa o None.

SymbolicPulse

SymbolicPulse inizia con l'intestazione SYMBOLIC_PULSE:

struct {
    uint16_t type_size;
    uint16_t envelope_size;
    uint16_t constraints_size;
    uint16_t valid_amp_conditions_size;
    _bool amp_limited;
}

che è seguito da type_size utf8 byte di SymbolicPulse.pulse_type stringa che rappresenta una classe di forma d'onda, come "gaussiana" o “GaussianSquare”. Quindi, envelope_size, constraints_size, valid_amp_conditions_size utf8 byte di espressioni simboliche serializzate vengono generati rispettivamente per SymbolicPulse.envelope, SymbolicPulse.constraints, e SymbolicPulse.valid_amp_conditions. Poiché la rappresentazione in stringa di queste espressioni è solitamente lunga, il binario dell'espressione è generato dal modulo zlib di python con compressione dei dati.

Per specificare in modo univoco un'istanza di impulso, è necessario memorizzare anche i parametri associati, che consistono in duration e nel resto dei parametri come dizionario. I parametri del dizionario vengono prima scaricati nella forma MAPPING e poi duration viene scaricato con la struttura pack INSTRUCTION_PARAM. Infine, name viene salvato anche con la struct del pacchetto INSTRUCTION_PARAM, che può essere una stringa o None.

associazione

MAPPING è una rappresentazione per un oggetto di mappatura arbitrario. Si tratta di una SEQUENZA a lunghezza fissa di coppie chiave-valore rappresentate dal payload di MAP_ITEM.

Un MAP_ITEM inizia con un'intestazione definita come:

struct {
    uint16_t key_size;
    char type;
    uint16_t size;
}

che è immediatamente seguito dai key_size utf8 byte che rappresentano la chiave del dizionario in stringa e size utf8 byte di dati di oggetti arbitrari di QPY serializzabili type.

CALIBRAZIONI DEL CIRCUITO

Il blocco CIRCUIT_CALIBRATIONS è un dizionario per definire le calibrazioni degli impulsi del set di istruzioni personalizzate. Questo blocco inizia con la seguente intestazione CALIBRATION:

struct {
    uint16_t num_cals;
}

che è seguito dalla lunghezza num_cals delle voci di calibrazione, ognuna delle quali inizia con l'intestazione CALIBRATION_DEF:

struct {
    uint16_t name_size;
    uint16_t num_qubits;
    uint16_t num_params;
    char type;
}

L'intestazione della definizione di calibrazione è seguita da name_size utf8 byte del nome del gate, num_qubits lunghezza degli interi che rappresentano una sequenza di qubit e num_params lunghezza del payload INSTRUCTION_PARAM per i parametri associati all'istruzione personalizzata. type indica la classe del programma di impulsi che è, in linea di principio, ScheduleBlock o Schedule. A partire dalla versione 5 di QPY, è supportato solo il payload ScheduleBlock . Infine, il payload SCHEDULE_BLOCK viene confezionato per ogni voce CALIBRATION_DEF.

Istruzione

Il blocco INSTRUCTION è stato modificato per aggiungere due nuovi campi num_ctrl_qubits e ctrl_state , utilizzati per modellare gli ControlledGate.num_ctrl_qubits attributi e ControlledGate.ctrl_state . Il nuovo formato della struttura che contiene il payload è il seguente:

struct {
    uint16_t name_size;
    uint16_t label_size;
    uint16_t num_parameters;
    uint32_t num_qargs;
    uint32_t num_cargs;
    _Bool has_conditional;
    uint16_t conditional_reg_name_size;
    int64_t conditional_value;
    uint32_t num_ctrl_qubits;
    uint32_t ctrl_state;
}

Il resto del payload dell'istruzione è lo stesso. Per i dettagli sul carico utile completo, consultare le ISTRUZIONI.

ISTRUZIONI PERSONALIZZATE

Il blocco CUSTOM_INSTRUCTION nella versione 5 di QPY aggiunge un nuovo campo base_gate_size utilizzato per definire la dimensione dell'oggetto qiskit.circuit.Instruction memorizzato nell'attributo ControlledGate.base_gate di un oggetto personalizzato ControlledGate . Con questa modifica, il blocco di metadati CUSTOM_INSTRUCTION diventa:

struct {
    uint16_t name_size;
    char type;
    uint32_t num_qubits;
    uint32_t num_clbits;
    _Bool custom_definition;
    uint64_t size;
    uint32_t num_ctrl_qubits;
    uint32_t ctrl_state;
    uint64_t base_gate_size
}

Subito dopo la struct CUSTOM_INSTRUCTION c'è il nome codificato utf8 di dimensione name_size.

Se custom_definition è True , ciò significa che i byte immediatamente successivi size contengono i dati di un circuito QPY che possono essere utilizzati per la definizione personalizzata di quella porta. Se custom_definition è False , allora l'istruzione può essere considerata opaca (cioè senza definizione). Il type campo determina quale tipo di oggetto verrà creato con la definizione personalizzata. Se è 'g' sarà un Gate oggetto, 'i' sarà un Instruction oggetto.

A seguire, i successivi base_gate_size byte contengono il payload di INSTRUCTION per ControlledGate.base_gate.

ControlledGateInoltre, viene aggiunto 'c' un valore aggiuntivo per type che serve a indicare che l'istruzione personalizzata è di tipo personalizzato.

Versione 4

La versione 4 è identica alla versione 3, tranne che per l'aggiunta di 2 nuove stringhe di tipo alla struct INSTRUCTION_PARAM, z per rappresentare None (che è codificato come nessun dato), q per rappresentare un di interi (che è codificato come un RANGE), e per rappresentare un (che è codificato come un circuito QPY) QuantumCircuit (che è codificato come circuito QPY), r per rappresentare un range di interi (che è codificato come RANGE ) e t per rappresentare un sequence (che è codificato come definito da SEQUENCE ). Inoltre, la versione 4 cambia il tipo di array di mappatura degli indici dei registri da uint32_t a int64_t. Se i valori di uno qualsiasi degli elementi della matrice sono negativi, rappresentano un bit di registro non presente nel circuito.

Anche il formato dell'intestazione REGISTERS è stato aggiornato in modo che

struct {
    char type;
    _Bool standalone;
    uint32_t size;
    uint16_t name_size;
    _bool in_circuit;
}

che aggiunge solo il campo in_circuit che rappresenta se il registro fa parte o meno del circuito.

RANGE

Un RANGE è una rappresentazione di un oggetto range . Si definisce come:

struct {
    int64_t start;
    int64_t stop;
    int64_t step;
}

SEQUENZA

Una SEQUENZA è una rappresentazione di un oggetto sequenza arbitrario. Poiché le sequenze sono solo contenitori a lunghezza fissa di oggetti python arbitrari, il loro QPY non può rappresentare completamente alcuna sequenza, ma finché il contenuto di una sequenza è costituito da altri tipi di QPY serializzabili per il payload INSTRUCTION_PARAM, l'oggetto `sequenza' può essere serializzato.

Il parametro di un'istruzione di sequenza inizia con un'intestazione definita come:

struct {
    uint64_t size;
}

seguito da size elementi che sono payload di INSTRUCTION_PARAM, dove ognuno di questi definisce un elemento della sequenza. L'oggetto sequenza sarà digitato nel tipo corretto, ad esempio tuple, in seguito.

Versione 3

La versione 3 del formato QPY è identica alla versione 2, tranne per il fatto che definisce un formato struct per rappresentare un PauliEvolutionGate in modo nativo in QPY. A tal fine, la struttura CUSTOM_DEFINITIONS ora supporta un nuovo valore 'p' di tipo per rappresentare un PauliEvolutionGate. Alle voci delle tabelle delle istruzioni personalizzate viene assegnato un nome univoco generato che inizia con la stringa "###PauliEvolutionGate_" seguita da una stringa UUID. Questo nome di gate è riservato in QPY e, se si dispone di un oggetto personalizzato Instruction con un set di definizioni che include quel prefisso, verrà generato un errore. Se è di tipo 'p' , il payload dei dati è definito come segue:

PAULI_EVOLUZIONE

Questo rappresenta il livello più alto PauliEvolutionGate

struct {
    uint64_t operator_count;
    _Bool standalone_op;
    char time_type;
    uint64_t time_size;
    uint64_t synthesis_size;
}

A questi seguono immediatamente gli operator_count elementi definiti dal payload SPARSE_PAULI_OP_LIST_ELEM. A seguire abbiamo time_size i byte che rappresentano l'attributo time . Se standalone_op è True , allora deve esserci un solo operatore. La codifica di questi byte è determinata dal valore di time_type. I valori possibili di time_type sono 'f', 'p', e 'e'. Se time_type è 'f' un doppio, 'p' definisce un Parameter oggetto rappresentato da un PARAMETER, e definisce un ParameterExpression oggetto (che non è un Parameter) rappresentato da un PARAMETER_EXPR. Segue poi il dato synthesis_size in byte, ovvero un payload JSON codificato con il formato " utf8 " che rappresenta la EvolutionSynthesis classe utilizzata dal gate.

SPARSE_PAULI_OP_LIST_ELEM

Questo rappresenta un esempio di SparsePauliOp.

struct {
    uint32_t pauli_op_size;
}

seguito immediatamente da pauli_op_size byte contenenti dati in formato.npy [2] che rappresentano il SparsePauliOp.

La versione 3 del formato QPY definisce anche un formato struct per rappresentare un ParameterVectorElement come sottoclasse distinta da un Parameter. Questo aggiunge un nuovo tipo di parametro char 'v' per rappresentare un valore ParameterVectorElement che ora è supportato come valore di tipo stringa per un INSTRUCTION\_PARAM. I valori di questi parametri sono definiti di seguito come PARAMETER_VECTOR_ELEMENT.

PARAMETRO_VETTORE_ELEMENTO

Un PARAMETER_VECTOR_ELEMENT rappresenta un ParameterVectorElement oggetto contenente i dati relativi a un INSTRUCTION_PARAM. Il contenuto di PARAMETER_VECTOR_ELEMENT è definito come segue:

struct {
    uint16_t vector_name_size;
    uint64_t vector_size;
    char uuid[16];
    uint64_t index;
}

che è immediatamente seguito da vector_name_size utf8 byte che rappresenta il nome del vettore del parametro.

PARAMETRO_ESPRESSIONE

Inoltre, poiché la versione v3 del formato QPY distingue tra a Parameter e ParameterVectorElement , il payload per a ParameterExpression deve essere aggiornato per distinguere tra i due tipi. Di seguito è riportato il formato modificato del payload, che è sostanzialmente identico a quello delle Versioni 1 e 2, ma presenta solo una modifica alla map_elements struttura per includere un campo di tipo simbolo.

Un PARAMETER_EXPR rappresenta un ParameterExpression oggetto che contiene i dati relativi a un INSTRUCTION_PARAM. Il contenuto di un PARAMETER_EXPR è definito come segue:

struct {
    uint64_t map_elements;
    uint64_t expr_size;
}

Subito dopo l'intestazione c'è expr_size byte di dati utf8 contenenti la stringa di espressione, che è la sigla dell'espressione per l'espressione del parametro. Segue una mappa di simboli che contiene gli elementi map_elements con il formato

struct {
    char symbol_type;
    char type;
    uint64_t size;
}

La symbol_type chiave determina il tipo di payload della rappresentazione simbolica dell'elemento. Se è p , rappresenta un Parameter , e se è v , rappresenta un ParameterVectorElement. La struttura dell'elemento "map" è immediatamente seguita dal payload della chiave "symbol map"; se symbol_type è p , allora è immediatamente seguita da un oggetto PARAMETER (sia la struttura che i byte del nom utf8 ), mentre se symbol_type è v , allora la struttura è immediatamente seguita da PARAMETER_VECTOR_ELEMENT (sia la struttura che i byte del nom utf8 ). A size ciò seguono byte per i dati del simbolo. Il formato dei dati dipende dal valore di type. Se type è p allora rappresenta un Parameter e la dimensione sarà 0; il valore sarà semplicemente uguale alla chiave. Allo stesso modo, se è v``type , allora rappresenta un ParameterVectorElement e la dimensione sarà 0, poiché il valore sarà semplicemente uguale alla chiave. Se type è f , allora rappresenta un numero in virgola mobile a doppia precisione. Se type è c , rappresenta un numero complesso a doppia precisione, rappresentato dal tipo COMPLEX. Infine, se il tipo è i , rappresenta un numero intero che è un int64_t.

Versione 2

La versione 2 del formato QPY è identica alla versione 1, tranne che per la sezione HEADER, leggermente diversa. Per i dettagli sul resto del formato del payload, si rimanda alla sezione Versione 1.

INTESTAZIONE

Il contenuto di HEADER è definito come una struct C:

struct {
    uint16_t name_size;
    char global_phase_type;
    uint16_t global_phase_size;
    uint32_t num_qubits;
    uint32_t num_clbits;
    uint64_t metadata_size;
    uint32_t num_registers;
    uint64_t num_instructions;
}

A name_size questo seguono immediatamente byte di dati in formato utf8, corrispondenti al nome del circuito. A questi seguono immediatamente global_phase_size i byte che rappresentano la fase globale. Il contenuto di tali dati è determinato dal valore di global_phase_type. Se il dato è 'f' un numero in virgola mobile e ha la dimensione di un double. Se 'p' definisce un Parameter oggetto rappresentato da una struttura PARAM (vedi sotto), e definisce un ParameterExpression oggetto (che non è un Parameter) rappresentato da una struttura PARAM_EXPR (vedi sotto).

Versione 1

INTESTAZIONE

Il contenuto di HEADER, definito come struttura C, è il seguente:

struct {
    uint16_t name_size;
    double global_phase;
    uint32_t num_qubits;
    uint32_t num_clbits;
    uint64_t metadata_size;
    uint32_t num_registers;
    uint64_t num_instructions;
}

Questo è immediatamente seguito da name_size byte di dati utf8 per il nome del circuito.

Metadati

Il campo METADATA è una stringa JSON codificata da UTF8. Dopo aver letto l'HEADER (che ha una dimensione fissa all'inizio del file QPY) e la stringa name , si legge il numero di byte metadata_size e si analizza il JSON per ottenere i metadati del circuito.

Registri

Il contenuto di REGISTER è un numero di oggetti REGISTER. Se num_registers è > 0, dopo la lettura di METADATA si legge il numero di strutture REGISTER definite come:

struct {
    char type;
    _Bool standalone;
    uint32_t size;
    uint16_t name_size;
}

type può essere 'q' o 'c'.

Subito dopo la struct REGISTER si trova il nome del registro codificato utf8 di dimensione name_size. Dopo i name utf8 byte c'è un array di int64_t valori di dimensione size che contiene una mappa dell'indice del registro con l'indice del qubit del circuito. Ad esempio, il valore dell'elemento dell'array 0’s è l'indice della posizione di register[0]nell'elenco dei qubit del circuito contenente.

Nota

Prima della versione 4 di QPY il tipo di elementi dell'array era uint32_t. Questo è stato modificato per abilitare i valori negativi che rappresentano i bit dell'array non presenti nel circuito

Il booleano standalone determina se il registro è stato costruito come registro autonomo aggiunto al circuito o se è stato creato a partire da bit esistenti. Un registro è considerato autonomo se ha dei bit costruiti esclusivamente come parte di esso, ad esempio:

qr = QuantumRegister(2)
qc = QuantumCircuit(qr)

il registro qr sarebbe un registro indipendente. Mentre qualcosa come:

bits = [Qubit(), Qubit()]
qr2 = QuantumRegister(bits=bits)
qc = QuantumCircuit(qr2)

qr2 avrebbe standalone impostato su False.

DEFINIZIONI PERSONALIZZATE

Questa sezione specifica le definizioni personalizzate per qualsiasi istruzione del circuito.

I contenuti di CUSTOM_DEFINITION_HEADER sono definiti come:

struct {
    uint64_t size;
}

Se la dimensione è maggiore di 0, significa che il circuito contiene istruzioni personalizzate. Ogni istruzione personalizzata viene definita con un blocco CUSTOM_INSTRUCTION definito come:

struct {
    uint16_t name_size;
    char type;
    uint32_t num_qubits;
    uint32_t num_clbits;
    _Bool custom_definition;
    uint64_t size;
}

Subito dopo la struct CUSTOM_INSTRUCTION c'è il nome codificato utf8 di dimensione name_size.

Se custom_definition è True , ciò significa che i byte immediatamente successivi size contengono i dati di un circuito QPY che possono essere utilizzati per la definizione personalizzata di quella porta. Se custom_definition è False , allora l'istruzione può essere considerata opaca (cioè senza definizione). Il type campo determina quale tipo di oggetto verrà creato con la definizione personalizzata. Se è 'g' sarà un Gate oggetto, 'i' sarà un Instruction oggetto.

ISTRUZIONI

Il contenuto di INSTRUCTIONS è un elenco di oggetti metadati INSTRUCTION

struct {
    uint16_t name_size;
    uint16_t label_size;
    uint16_t num_parameters;
    uint32_t num_qargs;
    uint32_t num_cargs;
    _Bool has_conditional;
    uint16_t conditional_reg_name_size;
    int64_t conditional_value;
}

Questo oggetto di metadati è immediatamente seguito da name_size byte di utf8 byte per l'oggetto name. name è il nome della classe Qiskit per la classe Istruzione, se è definita in Qiskit. Altrimenti si torna al nome dell'istruzione personalizzata. Dopo i byte name ci sono label_size byte di dati utf8 per l'etichetta, se è stata impostata nell'istruzione. Dopo i byte di etichetta, se has_conditional è True , ci sono conditional_reg_name_size byte di dati utf8 per il nome del registro condizionale. Nel caso di condizioni a singolo bit classico, i dati del nome del registro utf8 saranno preceduti da un carattere nullo “x00” e poi da un intero della stringa utf8 che rappresenta l'indice del bit classico nel circuito su cui si trova la condizione.

Questa è immediatamente seguita dalle strutture INSTRUCTION_ARG per l'elenco degli argomenti di quell'istruzione. Questi sono nell'ordine di tutti gli argomenti quantistici (ci sono num_qargs di questi) seguiti da tutti gli argomenti classici (num_cargs di questi).

Il contenuto di ogni INSTRUCTION_ARG è:

struct {
    char type;
    uint32_t index;
}

type può essere 'q' o 'c'.

Dopo tutti gli argomenti di un'istruzione, i parametri sono specificati con le strutture num_parameters INSTRUCTION_PARAM.

Il contenuto di ogni INSTRUCTION_PARAM è:

struct {
    char type;
    uint64_t size;
}

Dopo ogni INSTRUCTION_PARAM, i byte successivi size rappresentano i dati del parametro. Il type campo può essere 'i', 'f', 'p', 'e', 's', 'c' o 'n' , che ne determinano il formato. Se 'i' è un numero intero, 'f' è un numero in virgola mobile, 's' se è una stringa (codificata come utf8 ), 'c' è un numero complesso e i dati sono rappresentati dal formato della struttura nella sezione PARAMETER_EXPR. 'p' definisce un Parameter oggetto rappresentato da una struttura PARAMETER, e definisce un ParameterExpression oggetto (che non è un Parameter) rappresentato da una struttura PARAMETER_EXPR (nel formato QPY versione 3 il formato è leggermente modificato, vedi: PARAMETER_EXPR ), 'n' rappresenta un oggetto proveniente da numpy (un ndarray o un tipo numpy), il che significa che i dati sono in formato.npy [2], e nella versione 3 'v' di QPY rappresenta un ParameterVectorElement rappresentato da una struttura PARAMETER_VECTOR_ELEMENT.

Parametro

Un PARAMETRO rappresenta un Parameter oggetto contenente i dati relativi a un INSTRUCTION_PARAM. Il contenuto del PARAMETRO è definito come segue:

struct {
    uint16_t name_size;
    char uuid[16];
}

che è immediatamente seguito da name_size utf8 byte che rappresentano il nome del parametro.

PARAMETRO_ESPRESSIONE

Un PARAMETER_EXPR rappresenta un ParameterExpression oggetto che contiene i dati relativi a un INSTRUCTION_PARAM. Il contenuto di un PARAMETER_EXPR è definito come segue:

I dati di PARAMETER\EXPR iniziano con un'intestazione:

struct {
    uint64_t map_elements;
    uint64_t expr_size;
}

Subito dopo l'intestazione c'è expr_size byte di dati utf8 contenenti la stringa di espressione, che è la sigla dell'espressione per l'espressione del parametro. Segue una mappa di simboli che contiene gli elementi map_elements con il formato

struct {
    char type;
    uint64_t size;
}

A PARAMETER cui segue immediatamente l’oggetto (sia i byte relativi alla struttura che quelli relativi al nom utf8 ) corrispondente alla chiave della mappa dei simboli. A size ciò seguono byte per i dati del simbolo. Il formato dei dati dipende dal valore di type. Se type è p , allora rappresenta un Parameter e la dimensione sarà 0; il valore sarà semplicemente uguale alla chiave. Se type è f , allora rappresenta un numero in virgola mobile a doppia precisione. Se type è c , rappresenta un numero complesso a doppia precisione, rappresentato dal tipo COMPLEX. Infine, se il tipo è i , rappresenta un numero intero che è un int64_t.

Complesso

Quando si rappresenta un valore complesso a doppia precisione in QPY si utilizza la seguente struttura:

struct {
    double real;
    double imag;
}

corrisponde alla rappresentazione interna in C del tipo complesso di Python. [3]


Riferimenti

[1 ]

https://tools.ietf.org/html/rfc1700

[2] (1,2 )

https://numpy.org/doc/stable/reference/generated/numpy.lib.format.html

[3 ]

https://docs.python.org/3/c-api/complex.html# c.Py_complex

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